diff --git a/jOOQ-scala/src/main/scala/org/jooq/scala/Conversions.scala b/jOOQ-scala/src/main/scala/org/jooq/scala/Conversions.scala index 3d6fdbcd0d..a2458f72f7 100644 --- a/jOOQ-scala/src/main/scala/org/jooq/scala/Conversions.scala +++ b/jOOQ-scala/src/main/scala/org/jooq/scala/Conversions.scala @@ -77,20 +77,155 @@ import org.jooq.impl.Factory._ */ object Conversions { + // ------------------------------------------------------------------------- + // Traits + // ------------------------------------------------------------------------- + + /** + * A Scala-esque representation of {@link org.jooq.Field}, adding overloaded + * operators for common jOOQ operations to arbitrary fields + */ + trait SAnyField[T] extends QueryPartInternal { + + // String operations + // ----------------- + + def ||(value : String) : Field[String] + def ||(value : Field[_]) : Field[String] + + // Comparison predicates + // --------------------- + + def ===(value : T) : Condition + def ===(value : Field[T]) : Condition + + def !==(value : T) : Condition + def !==(value : Field[T]) : Condition + + def <>(value : T) : Condition + def <>(value : Field[T]) : Condition + + def >(value : T) : Condition + def >(value : Field[T]) : Condition + + def >=(value : T) : Condition + def >=(value : Field[T]) : Condition + + def <(value : T) : Condition + def <(value : Field[T]) : Condition + + def <=(value : T) : Condition + def <=(value : Field[T]) : Condition + + def <=>(value : T) : Condition + def <=>(value : Field[T]) : Condition + } + + /** + * A Scala-esque representation of {@link org.jooq.Field}, adding overloaded + * operators for common jOOQ operations to numeric fields + */ + trait SNumberField[T <: Number] extends SAnyField[T] { + + // Arithmetic operations + // --------------------- + + def +(value : Number) : Field[T] + def +(value : Field[_ <: Number]) : Field[T] + + def -(value : Number) : Field[T] + def -(value : Field[_ <: Number]) : Field[T] + + def *(value : Number) : Field[T] + def *(value : Field[_ <: Number]) : Field[T] + + def /(value : Number) : Field[T] + def /(value : Field[_ <: Number]) : Field[T] + + def %(value : Number) : Field[T] + def %(value : Field[_ <: Number]) : Field[T] + + // Bitwise operations + // ------------------ + + def unary_~ : Field[T] + + def &(value : T) : Field[T] + def &(value : Field[T]) : Field[T] + + def |(value : T) : Field[T] + def |(value : Field[T]) : Field[T] + + def ^(value : T) : Field[T] + def ^(value : Field[T]) : Field[T] + + def <<(value : T) : Field[T] + def <<(value : Field[T]) : Field[T] + + def >>(value : T) : Field[T] + def >>(value : Field[T]) : Field[T] + } + + // ------------------------------------------------------------------------ + // Trait implementations + // ------------------------------------------------------------------------ + /** * A Scala-esque representation of {@link org.jooq.Field}, implementing - * overloaded operators for common jOOQ operations + * overloaded operators for common jOOQ operations to arbitrary fields */ - case class JFieldWrapper[T](val underlying: Field[T]) + abstract class AnyFieldBase[T](val underlying: Field[T]) extends CustomField[T] (underlying.getName(), underlying.getDataType()) - with SField[T] { - // ------------------------------------------------------------------------ + with SAnyField[T] { + // QueryPart API - // ------------------------------------------------------------------------ + // ------------- def toSQL(context : RenderContext) = underlying.toSQL(context) def bind (context : BindContext) = underlying.bind(context) + // String operations + // ----------------- + + def ||(value : String) = underlying.concat(value) + def ||(value : Field[_]) = underlying.concat(value) + + // Comparison predicates + // --------------------- + + def ===(value : T) = underlying.equal(value) + def ===(value : Field[T]) = underlying.equal(value) + + def !==(value : T) = underlying.notEqual(value) + def !==(value : Field[T]) = underlying.notEqual(value) + + def <>(value : T) = underlying.notEqual(value) + def <>(value : Field[T]) = underlying.notEqual(value) + + def >(value : T) = underlying.greaterThan(value) + def >(value : Field[T]) = underlying.greaterThan(value) + + def >=(value : T) = underlying.greaterOrEqual(value) + def >=(value : Field[T]) = underlying.greaterOrEqual(value) + + def <(value : T) = underlying.lessThan(value) + def <(value : Field[T]) = underlying.lessThan(value) + + def <=(value : T) = underlying.lessOrEqual(value) + def <=(value : Field[T]) = underlying.lessOrEqual(value) + + def <=>(value : T) = underlying.isNotDistinctFrom(value) + def <=>(value : Field[T]) = underlying.isNotDistinctFrom(value) + } + + /** + * A Scala-esque representation of {@link org.jooq.Field}, implementing + * overloaded operators for common jOOQ operations to numeric fields + */ + abstract class NumberFieldBase[T <: Number](override val underlying: Field[T]) + extends AnyFieldBase[T] (underlying) + with SNumberField[T] { + // ------------------------------------------------------------------------ // Arithmetic operations // ------------------------------------------------------------------------ @@ -110,98 +245,54 @@ object Conversions { def %(value : Number) = underlying.mod(value) def %(value : Field[_ <: Number]) = underlying.mod(value) + // ------------------------------------------------------------------------- + // Bitwise operations + // ------------------------------------------------------------------------- - def ||(value : String) = underlying.concat(value) - //def ||(value : Field[_]) : underlying.concat(value) + def unary_~ = bitNot(underlying) - // ------------------------------------------------------------------------ - // Comparison predicates - // ------------------------------------------------------------------------ + def &(value : T) = bitAnd(underlying, value) + def &(value : Field[T]) = bitAnd(underlying, value) - def ===(value : T) : Condition = underlying.equal(value) - def ===(value : Field[T]) : Condition = underlying.equal(value) + def |(value : T) = bitOr (underlying, value) + def |(value : Field[T]) = bitOr (underlying, value) - def !==(value : T) : Condition = underlying.notEqual(value) - def !==(value : Field[T]) : Condition = underlying.notEqual(value) + def ^(value : T) = bitXor(underlying, value) + def ^(value : Field[T]) = bitXor(underlying, value) - def <>(value : T) : Condition = underlying.notEqual(value) - def <>(value : Field[T]) : Condition = underlying.notEqual(value) + def <<(value : T) = shl(underlying, value) + def <<(value : Field[T]) = shl(underlying, value) - def >(value : T) : Condition = underlying.greaterThan(value) - def >(value : Field[T]) : Condition = underlying.greaterThan(value) - - def >=(value : T) : Condition = underlying.greaterOrEqual(value) - def >=(value : Field[T]) : Condition = underlying.greaterOrEqual(value) - - def <(value : T) : Condition = underlying.lessThan(value) - def <(value : Field[T]) : Condition = underlying.lessThan(value) - - def <=(value : T) : Condition = underlying.lessOrEqual(value) - def <=(value : Field[T]) : Condition = underlying.lessOrEqual(value) - - def <=>(value : T) : Condition = underlying.isNotDistinctFrom(value) - def <=>(value : Field[T]) : Condition = underlying.isNotDistinctFrom(value) + def >>(value : T) = shr(underlying, value) + def >>(value : Field[T]) = shr(underlying, value) } + // ------------------------------------------------------------------------ + // Implicit conversions + // ------------------------------------------------------------------------ + /** - * A Scala-esque representation of {@link org.jooq.Field}, adding overloaded - * operators for common jOOQ operations + * A Scala-esque representation of {@link org.jooq.Field}, implementing + * overloaded operators for common jOOQ operations to arbitrary fields */ - trait SField[T] extends QueryPartInternal { + case class AnyFieldWrapper[T] (override val underlying: Field[T]) + extends AnyFieldBase[T] (underlying) {} - // ------------------------------------------------------------------------ - // Arithmetic operations - // ------------------------------------------------------------------------ + /** + * A Scala-esque representation of {@link org.jooq.Field}, implementing + * overloaded operators for common jOOQ operations to numeric fields + */ + case class NumberFieldWrapper[T <: Number](override val underlying: Field[T]) + extends NumberFieldBase[T] (underlying) {} - def +(value : Number) : Field[T] - def +(value : Field[_ <: Number]) : Field[T] - - def -(value : Number) : Field[T] - def -(value : Field[_ <: Number]) : Field[T] - - def *(value : Number) : Field[T] - def *(value : Field[_ <: Number]) : Field[T] - - def /(value : Number) : Field[T] - def /(value : Field[_ <: Number]) : Field[T] - - def %(value : Number) : Field[T] - def %(value : Field[_ <: Number]) : Field[T] - - def ||(value : String) : Field[String] - //def ||(value : Field[_]) : Field[String] - - // ------------------------------------------------------------------------ - // Comparison predicates - // ------------------------------------------------------------------------ - - def ===(value : T) : Condition - def ===(value : Field[T]) : Condition - - def !==(value : T) : Condition - def !==(value : Field[T]) : Condition - - def <>(value : T) : Condition - def <>(value : Field[T]) : Condition - - def >(value : T) : Condition - def >(value : Field[T]) : Condition - - def >=(value : T) : Condition - def >=(value : Field[T]) : Condition - - def <(value : T) : Condition - def <(value : Field[T]) : Condition - - def <=(value : T) : Condition - def <=(value : Field[T]) : Condition - - def <=>(value : T) : Condition - def <=>(value : Field[T]) : Condition + implicit def asSNumberField[T <: Number](f : Field[T]): SNumberField[T] = f match { + case AnyFieldWrapper(f) => f + case NumberFieldWrapper(f) => f + case _ => new NumberFieldWrapper(f) } - implicit def asScalaField[T](f : Field[T]): SField[T] = f match { - case JFieldWrapper(f) => f - case _ => new JFieldWrapper(f) + implicit def asSAnyField[T](f : Field[T]): SAnyField[T] = f match { + case AnyFieldWrapper(f) => f + case _ => new AnyFieldWrapper(f) } } diff --git a/jOOQ-scala/src/test/scala/org/jooq/scala/test/ArithmeticExpressionTest.scala b/jOOQ-scala/src/test/scala/org/jooq/scala/test/ArithmeticExpressionTest.scala index ab21b7751c..c35098d7d9 100644 --- a/jOOQ-scala/src/test/scala/org/jooq/scala/test/ArithmeticExpressionTest.scala +++ b/jOOQ-scala/src/test/scala/org/jooq/scala/test/ArithmeticExpressionTest.scala @@ -4,11 +4,9 @@ import collection.JavaConversions._ import org.scalatest.FunSuite import org.jooq._ import org.jooq.impl._ +import org.jooq.impl.Factory._ import org.jooq.scala.example.h2.Tables._ import org.jooq.scala.Conversions._ -import org.jooq.conf.Settings -import javax.xml.bind.JAXB -import org.jooq.conf.SettingsTools class ArithmeticExpressionTest extends FunSuite { @@ -42,4 +40,40 @@ class ArithmeticExpressionTest extends FunSuite { assert("(t_book.id + (t_book.author_id * 2))" == combined1.toString(), combined1.toString()) assert("((t_book.id * t_book.author_id) + 2)" == combined2.toString(), combined2.toString()) } -} \ No newline at end of file + + test("concat") { + val cat1 = T_BOOK.TITLE || T_BOOK.TITLE + val cat2 = T_BOOK.TITLE || " part 2" + val cat3 = T_BOOK.TITLE || " part 2" || " and 3" + + assert("(t_book.title || t_book.title)" == cat1.toString(), cat1.toString()) + assert("(t_book.title || ' part 2')" == cat2.toString(), cat2.toString()) + assert("((t_book.title || ' part 2') || ' and 3')" == cat3.toString(), cat3.toString()) + } + + test("bitwise") { + val and1 = T_BOOK.ID & T_BOOK.AUTHOR_ID + val and2 = T_BOOK.ID & 1 + val or1 = T_BOOK.ID | T_BOOK.AUTHOR_ID + val or2 = T_BOOK.ID | 1 + val xor1 = T_BOOK.ID ^ T_BOOK.AUTHOR_ID + val xor2 = T_BOOK.ID ^ 1 + val shl1 = T_BOOK.ID << T_BOOK.AUTHOR_ID + val shl2 = T_BOOK.ID << 1 + val shr1 = T_BOOK.ID >> T_BOOK.AUTHOR_ID + val shr2 = T_BOOK.ID >> 1 + val not1 = ~T_BOOK.ID + + assert("(t_book.id & t_book.author_id)" == and1.toString(), and1.toString()) + assert("(t_book.id & 1)" == and2.toString(), and2.toString()) + assert("(t_book.id | t_book.author_id)" == or1.toString(), or1.toString()) + assert("(t_book.id | 1)" == or2.toString(), or2.toString()) + assert("(t_book.id ^ t_book.author_id)" == xor1.toString(), xor1.toString()) + assert("(t_book.id ^ 1)" == xor2.toString(), xor2.toString()) + assert("(t_book.id << t_book.author_id)" == shl1.toString(), shl1.toString()) + assert("(t_book.id << 1)" == shl2.toString(), shl2.toString()) + assert("(t_book.id >> t_book.author_id)" == shr1.toString(), shr1.toString()) + assert("(t_book.id >> 1)" == shr2.toString(), shr2.toString()) + assert("~(t_book.id)" == not1.toString(), not1.toString()) + } +}