From 9fc2f65e9a0add789fddf6400ba3c29f7a3928f0 Mon Sep 17 00:00:00 2001 From: Mark Karavashkin <148395262+mark-kar@users.noreply.github.com> Date: Sat, 11 May 2024 12:20:55 +0300 Subject: [PATCH] Branch 0.8 (#16) * refactor: split PredOp into PredicateBinary and PredicateUnary * fit: collection values * refactor: delete Syms * fit: between and not between demo * review fixes * review fixes --------- Co-authored-by: m.karavashkin --- README.md | 13 +- build.sbt | 3 + .../rafafrdz/criteria4s/core/PredOp.scala | 103 ----------- .../rafafrdz/criteria4s/core/Predicate.scala | 168 ++++++++++++++++++ .../github/rafafrdz/criteria4s/core/Ref.scala | 51 +++--- .../rafafrdz/criteria4s/core/Show.scala | 12 ++ .../github/rafafrdz/criteria4s/core/Sym.scala | 25 --- .../rafafrdz/criteria4s/core/package.scala | 26 +-- .../criteria4s/extensions/predicates.scala | 79 +++++--- .../criteria4s/functions/package.scala | 17 +- .../criteria4s/functions/predicates.scala | 131 +++++++++----- .../criteria4s/instances/package.scala | 7 - .../criteria4s/examples/ArraysExample.scala | 30 ++++ .../criteria4s/examples/BetweenExample.scala | 21 +++ .../criteria4s/examples/Example3.scala | 4 +- .../criteria4s/examples/Example4.scala | 4 +- .../examples/FilterByUserExample.scala | 2 +- .../examples/datastores/MySQL.scala | 5 +- .../examples/datastores/Postgres.scala | 11 +- .../examples/datastores/WeirdDatastore.scala | 15 +- project/Dependencies.scala | 6 + .../github/rafafrdz/criteria4s/sql/SQL.scala | 9 +- 22 files changed, 465 insertions(+), 277 deletions(-) delete mode 100644 core/src/main/scala/io/github/rafafrdz/criteria4s/core/PredOp.scala create mode 100644 core/src/main/scala/io/github/rafafrdz/criteria4s/core/Predicate.scala create mode 100644 core/src/main/scala/io/github/rafafrdz/criteria4s/core/Show.scala delete mode 100644 core/src/main/scala/io/github/rafafrdz/criteria4s/core/Sym.scala create mode 100644 examples/src/main/scala/io/github/rafafrdz/criteria4s/examples/ArraysExample.scala create mode 100644 examples/src/main/scala/io/github/rafafrdz/criteria4s/examples/BetweenExample.scala diff --git a/README.md b/README.md index 820ec5a..434d657 100644 --- a/README.md +++ b/README.md @@ -11,17 +11,20 @@ extensible to support any kind of data stores. The formal definition of the Criteria4s' type-classes (expressions) is as follows: ```text -Criteria := ConjOp Criteria Criteria | PredOp Ref Ref | Value +Criteria := Conjuction Criteria Criteria | Predicate | Value +Predicate := UnaryPred Ref | BinaryPred Ref Ref Ref := Value | Col -ConjOp := AND | OR -PredOp := EQ | NEQ | GT | LT | GEQ | LEQ | IN | LIKE | IS_NULL | IS_NOT_NULL ... +Conjuction := AND | OR +UnaryPred := IS_NULL | IS_NOT_NULL ... +BinaryPred := EQ | NEQ | GT | LT | GEQ | LEQ | IN | LIKE ... ``` Where: - `Criteria` is the main expression of the DSL - `ConjOp` is the conjunction operator expression -- `PredOp` is the predicate operator expression +- `UnaryPredOp` is the unary predicate operator expression +- `BinaryPredOp` is the binary predicate operator expression - `Ref` is a reference to a value or a column - `Value` is a value expression of a certain type `T` - `Col` is a column expression @@ -105,4 +108,4 @@ Or maybe we can use the Criteria DSL inline: ``` You can find more examples in -the [`criteria4s-examples`](./examples/src/main/scala/io/github/rafafrdz/criteria/examples) module. +the [`criteria4s-examples`](./examples/src/main/scala/io/github/rafafrdz/criteria4s/examples) module. diff --git a/build.sbt b/build.sbt index 1bc7d5d..f9cba17 100644 --- a/build.sbt +++ b/build.sbt @@ -1,3 +1,5 @@ +import Dependencies.ProjectOps + lazy val criteria4s: Project = project .in(file(".")) @@ -28,3 +30,4 @@ lazy val examples: Project = name := "criteria4s-examples" ) .dependsOn(core, sql) + .withKindProjector diff --git a/core/src/main/scala/io/github/rafafrdz/criteria4s/core/PredOp.scala b/core/src/main/scala/io/github/rafafrdz/criteria4s/core/PredOp.scala deleted file mode 100644 index f6efe2d..0000000 --- a/core/src/main/scala/io/github/rafafrdz/criteria4s/core/PredOp.scala +++ /dev/null @@ -1,103 +0,0 @@ -package io.github.rafafrdz.criteria4s.core - -import io.github.rafafrdz.criteria4s.core.Criteria._ -import io.github.rafafrdz.criteria4s.instances.builder.{Builder1, Builder2} - -trait PredOp[T <: CriteriaTag] { - def eval(cr1: Ref[T], cr2: Ref[T]): Criteria[T] -} - -object PredOp { - - trait GT[T <: CriteriaTag] extends PredOp[T] - - trait LT[T <: CriteriaTag] extends PredOp[T] - - trait EQ[T <: CriteriaTag] extends PredOp[T] - - trait NEQ[T <: CriteriaTag] extends PredOp[T] - - trait GEQ[T <: CriteriaTag] extends PredOp[T] - - trait LEQ[T <: CriteriaTag] extends PredOp[T] - - trait LIKE[T <: CriteriaTag] extends PredOp[T] - - trait IN[T <: CriteriaTag] extends PredOp[T] - - trait NOTIN[T <: CriteriaTag] extends PredOp[T] - - trait ISNULL[T <: CriteriaTag] extends PredOp[T] - - trait ISNOTNULL[T <: CriteriaTag] extends PredOp[T] - - trait BETWEEN[T <: CriteriaTag] extends PredOp[T] - - trait NOTBETWEEN[T <: CriteriaTag] extends PredOp[T] - - implicit val gtBuilder: Builder2[GT] = new Builder2[GT] { - override def build[T <: CriteriaTag](F: (String, String) => String): GT[T] = - (cr1: Ref[T], cr2: Ref[T]) => pure(F(cr1.ref.value, cr2.ref.value)) - } - - implicit val ltBuilder: Builder2[LT] = new Builder2[LT] { - override def build[T <: CriteriaTag](F: (String, String) => String): LT[T] = - (cr1: Ref[T], cr2: Ref[T]) => pure(F(cr1.ref.value, cr2.ref.value)) - } - - implicit val eqBuilder: Builder2[EQ] = new Builder2[EQ] { - override def build[T <: CriteriaTag](F: (String, String) => String): EQ[T] = - (cr1: Ref[T], cr2: Ref[T]) => pure(F(cr1.ref.value, cr2.ref.value)) - } - - implicit val neqBuilder: Builder2[NEQ] = new Builder2[NEQ] { - override def build[T <: CriteriaTag](F: (String, String) => String): NEQ[T] = - (cr1: Ref[T], cr2: Ref[T]) => pure(F(cr1.ref.value, cr2.ref.value)) - } - - implicit val geqBuilder: Builder2[GEQ] = new Builder2[GEQ] { - override def build[T <: CriteriaTag](F: (String, String) => String): GEQ[T] = - (cr1: Ref[T], cr2: Ref[T]) => pure(F(cr1.ref.value, cr2.ref.value)) - } - - implicit val leqBuilder: Builder2[LEQ] = new Builder2[LEQ] { - override def build[T <: CriteriaTag](F: (String, String) => String): LEQ[T] = - (cr1: Ref[T], cr2: Ref[T]) => pure(F(cr1.ref.value, cr2.ref.value)) - } - - implicit val likeBuilder: Builder2[LIKE] = new Builder2[LIKE] { - override def build[T <: CriteriaTag](F: (String, String) => String): LIKE[T] = - (cr1: Ref[T], cr2: Ref[T]) => pure(F(cr1.ref.value, cr2.ref.value)) - } - - implicit val inBuilder: Builder2[IN] = new Builder2[IN] { - override def build[T <: CriteriaTag](F: (String, String) => String): IN[T] = - (cr1: Ref[T], cr2: Ref[T]) => pure(F(cr1.ref.value, cr2.ref.value)) - } - - implicit val notinBuilder: Builder2[NOTIN] = new Builder2[NOTIN] { - override def build[T <: CriteriaTag](F: (String, String) => String): NOTIN[T] = - (cr1: Ref[T], cr2: Ref[T]) => pure(F(cr1.ref.value, cr2.ref.value)) - } - - implicit val isnullBuilder: Builder1[ISNULL] = new Builder1[ISNULL] { - override def build[T <: CriteriaTag](F: String => String): ISNULL[T] = - (cr1: Ref[T], _: Ref[T]) => pure(F(cr1.ref.value)) - } - - implicit val isnotnullBuilder: Builder1[ISNOTNULL] = new Builder1[ISNOTNULL] { - override def build[T <: CriteriaTag](F: String => String): ISNOTNULL[T] = - (cr1: Ref[T], _: Ref[T]) => pure(F(cr1.ref.value)) - } - - implicit val betweenBuilder: Builder2[BETWEEN] = new Builder2[BETWEEN] { - override def build[T <: CriteriaTag](F: (String, String) => String): BETWEEN[T] = - (cr1: Ref[T], cr2: Ref[T]) => pure(F(cr1.ref.value, cr2.ref.value)) - } - - implicit val notbetweenBuilder: Builder2[NOTBETWEEN] = new Builder2[NOTBETWEEN] { - override def build[T <: CriteriaTag](F: (String, String) => String): NOTBETWEEN[T] = - (cr1: Ref[T], cr2: Ref[T]) => pure(F(cr1.ref.value, cr2.ref.value)) - } - -} diff --git a/core/src/main/scala/io/github/rafafrdz/criteria4s/core/Predicate.scala b/core/src/main/scala/io/github/rafafrdz/criteria4s/core/Predicate.scala new file mode 100644 index 0000000..ffc423d --- /dev/null +++ b/core/src/main/scala/io/github/rafafrdz/criteria4s/core/Predicate.scala @@ -0,0 +1,168 @@ +package io.github.rafafrdz.criteria4s.core + +import io.github.rafafrdz.criteria4s.core.Criteria._ +import io.github.rafafrdz.criteria4s.instances.builder.{Builder1, Builder2} + +sealed trait Predicate[T <: CriteriaTag] + +trait PredicateUnary[T <: CriteriaTag] extends Predicate[T] { + def eval[V](ref: Ref[T, V])(implicit show: Show[V, T]): Criteria[T] +} + +trait PredicateBinary[T <: CriteriaTag] extends Predicate[T] { + def eval[L, R](cr1: Ref[T, L], cr2: Ref[T, R])(implicit + showL: Show[L, T], + showR: Show[R, T] + ): Criteria[T] +} + +object PredicateUnary { + trait ISNULL[T <: CriteriaTag] extends PredicateUnary[T] + + trait ISNOTNULL[T <: CriteriaTag] extends PredicateUnary[T] + + implicit val isNullBuilder: Builder1[ISNULL] = new Builder1[ISNULL] { + override def build[T <: CriteriaTag](F: String => String): ISNULL[T] = new ISNULL[T] { + override def eval[V](ref: Ref[T, V])(implicit show: Show[V, T]): Criteria[T] = pure( + F(ref.asString) + ) + } + } + + implicit val isNotNullBuilder: Builder1[ISNOTNULL] = new Builder1[ISNOTNULL] { + override def build[T <: CriteriaTag](F: String => String): ISNOTNULL[T] = new ISNOTNULL[T] { + override def eval[V](ref: Ref[T, V])(implicit show: Show[V, T]): Criteria[T] = pure( + F(ref.asString) + ) + } + } +} + +object PredicateBinary { + + trait GT[T <: CriteriaTag] extends PredicateBinary[T] + + trait LT[T <: CriteriaTag] extends PredicateBinary[T] + + trait EQ[T <: CriteriaTag] extends PredicateBinary[T] + + trait NEQ[T <: CriteriaTag] extends PredicateBinary[T] + + trait GEQ[T <: CriteriaTag] extends PredicateBinary[T] + + trait LEQ[T <: CriteriaTag] extends PredicateBinary[T] + + trait LIKE[T <: CriteriaTag] extends PredicateBinary[T] + + trait IN[T <: CriteriaTag] extends PredicateBinary[T] + + trait NOTIN[T <: CriteriaTag] extends PredicateBinary[T] + + trait BETWEEN[T <: CriteriaTag] extends PredicateBinary[T] + + trait NOTBETWEEN[T <: CriteriaTag] extends PredicateBinary[T] + + implicit val gtBuilder: Builder2[GT] = new Builder2[GT] { + override def build[T <: CriteriaTag]( + F: (String, String) => String + ): GT[T] = new GT[T] { + override def eval[L, R](cr1: Ref[T, L], cr2: Ref[T, R])(implicit + showL: Show[L, T], + showR: Show[R, T] + ): Criteria[T] = pure(F(cr1.asString, cr2.asString)) + } + } + + implicit val ltBuilder: Builder2[LT] = new Builder2[LT] { + override def build[T <: CriteriaTag](F: (String, String) => String): LT[T] = new LT[T] { + override def eval[L, R](cr1: Ref[T, L], cr2: Ref[T, R])(implicit + showL: Show[L, T], + showR: Show[R, T] + ): Criteria[T] = pure(F(cr1.asString, cr2.asString)) + } + } + + implicit val eqBuilder: Builder2[EQ] = new Builder2[EQ] { + override def build[T <: CriteriaTag](F: (String, String) => String): EQ[T] = new EQ[T] { + override def eval[L, R](cr1: Ref[T, L], cr2: Ref[T, R])(implicit + showL: Show[L, T], + showR: Show[R, T] + ): Criteria[T] = pure(F(cr1.asString, cr2.asString)) + } + } + + implicit val neqBuilder: Builder2[NEQ] = new Builder2[NEQ] { + override def build[T <: CriteriaTag](F: (String, String) => String): NEQ[T] = new NEQ[T] { + override def eval[L, R](cr1: Ref[T, L], cr2: Ref[T, R])(implicit + showL: Show[L, T], + showR: Show[R, T] + ): Criteria[T] = pure(F(cr1.asString, cr2.asString)) + } + } + + implicit val geqBuilder: Builder2[GEQ] = new Builder2[GEQ] { + override def build[T <: CriteriaTag](F: (String, String) => String): GEQ[T] = new GEQ[T] { + override def eval[L, R](cr1: Ref[T, L], cr2: Ref[T, R])(implicit + showL: Show[L, T], + showR: Show[R, T] + ): Criteria[T] = pure(F(cr1.asString, cr2.asString)) + } + } + + implicit val leqBuilder: Builder2[LEQ] = new Builder2[LEQ] { + override def build[T <: CriteriaTag](F: (String, String) => String): LEQ[T] = new LEQ[T] { + override def eval[L, R](cr1: Ref[T, L], cr2: Ref[T, R])(implicit + showL: Show[L, T], + showR: Show[R, T] + ): Criteria[T] = pure(F(cr1.asString, cr2.asString)) + } + } + + implicit val likeBuilder: Builder2[LIKE] = new Builder2[LIKE] { + override def build[T <: CriteriaTag](F: (String, String) => String): LIKE[T] = new LIKE[T] { + override def eval[L, R](cr1: Ref[T, L], cr2: Ref[T, R])(implicit + showL: Show[L, T], + showR: Show[R, T] + ): Criteria[T] = pure(F(cr1.asString, cr2.asString)) + } + } + + implicit val inBuilder: Builder2[IN] = new Builder2[IN] { + override def build[T <: CriteriaTag](F: (String, String) => String): IN[T] = new IN[T] { + override def eval[L, R](cr1: Ref[T, L], cr2: Ref[T, R])(implicit + showL: Show[L, T], + showR: Show[R, T] + ): Criteria[T] = pure(F(cr1.asString, cr2.asString)) + } + } + + implicit val notinBuilder: Builder2[NOTIN] = new Builder2[NOTIN] { + override def build[T <: CriteriaTag](F: (String, String) => String): NOTIN[T] = + new NOTIN[T] { + override def eval[L, R](cr1: Ref[T, L], cr2: Ref[T, R])(implicit + showL: Show[L, T], + showR: Show[R, T] + ): Criteria[T] = pure(F(cr1.asString, cr2.asString)) + } + } + + implicit val betweenBuilder: Builder2[BETWEEN] = new Builder2[BETWEEN] { + override def build[T <: CriteriaTag](F: (String, String) => String): BETWEEN[T] = + new BETWEEN[T] { + override def eval[L, R](cr1: Ref[T, L], cr2: Ref[T, R])(implicit + showL: Show[L, T], + showR: Show[R, T] + ): Criteria[T] = pure(F(cr1.asString, cr2.asString)) + } + } + + implicit val notbetweenBuilder: Builder2[NOTBETWEEN] = new Builder2[NOTBETWEEN] { + override def build[T <: CriteriaTag](F: (String, String) => String): NOTBETWEEN[T] = + new NOTBETWEEN[T] { + override def eval[L, R](cr1: Ref[T, L], cr2: Ref[T, R])(implicit + showL: Show[L, T], + showR: Show[R, T] + ): Criteria[T] = pure(F(cr1.asString, cr2.asString)) + } + } +} diff --git a/core/src/main/scala/io/github/rafafrdz/criteria4s/core/Ref.scala b/core/src/main/scala/io/github/rafafrdz/criteria4s/core/Ref.scala index 8e7b961..741b439 100644 --- a/core/src/main/scala/io/github/rafafrdz/criteria4s/core/Ref.scala +++ b/core/src/main/scala/io/github/rafafrdz/criteria4s/core/Ref.scala @@ -1,43 +1,38 @@ package io.github.rafafrdz.criteria4s.core -sealed trait Ref[D <: CriteriaTag] { - def ref: Criteria[D] - - override def toString: String = ref.value +sealed trait Ref[D <: CriteriaTag, V] { + def asString(implicit show: Show[V, D]): String } object Ref { - trait Value[+V, D <: CriteriaTag] extends Ref[D] - - trait Collection[V, D <: CriteriaTag] extends Value[Seq[V], D] - - trait Col[D <: CriteriaTag] extends Ref[D] - - trait Bool[D <: CriteriaTag] extends Value[Boolean, D] with Criteria[D] { - self => - - override def value: String = ref.value + trait Value[D <: CriteriaTag, V] extends Ref[D, V] + trait Collection[D <: CriteriaTag, V] extends Ref[D, Seq[V]] + trait Col[D <: CriteriaTag] extends Ref[D, Column] + trait Bool[D <: CriteriaTag] extends Value[D, Boolean] with Criteria[D] + trait Range[D <: CriteriaTag, V] extends Ref[D, (V, V)] - override def toString: String = value - } + private[criteria4s] def nothing[T <: CriteriaTag]: Value[T, Nothing] = + (_: Show[Nothing, T]) => "" - private[criteria4s] def nothing[T <: CriteriaTag]: Value[Nothing, T] = - new Value[Nothing, T] { - override def ref: Criteria[T] = Criteria.pure("") - } - private[criteria4s] def value[V, D <: CriteriaTag](v: V): Value[V, D] = - new Value[V, D] { - override def ref: Criteria[D] = Criteria.pure(v.toString) - } + private[criteria4s] def value[V, D <: CriteriaTag](v: V): Value[D, V] = + (show: Show[V, D]) => show.show(v) - private[criteria4s] def col[D <: CriteriaTag](v: String): Col[D] = new Col[D] { - override def ref: Criteria[D] = Criteria.pure(v) - } + private[criteria4s] def col[D <: CriteriaTag](v: Column): Col[D] = + (show: Show[Column, D]) => show.show(v) private[criteria4s] def bool[D <: CriteriaTag](v: Boolean): Bool[D] = new Bool[D] { - override def ref: Criteria[D] = Criteria.pure(v.toString) + override def value: String = v.toString + override def asString(implicit show: Show[Boolean, D]): String = v.toString } + private[criteria4s] def array[V, D <: CriteriaTag](vs: V*): Collection[D, V] = + (show: Show[Seq[V], D]) => show.show(vs) + + private[criteria4s] def range[V, D <: CriteriaTag](left: V, right: V): Range[D, V] = + (show: Show[(V, V), D]) => show.show((left, right)) + } + +case class Column(colName: String) extends AnyVal diff --git a/core/src/main/scala/io/github/rafafrdz/criteria4s/core/Show.scala b/core/src/main/scala/io/github/rafafrdz/criteria4s/core/Show.scala new file mode 100644 index 0000000..0edecde --- /dev/null +++ b/core/src/main/scala/io/github/rafafrdz/criteria4s/core/Show.scala @@ -0,0 +1,12 @@ +package io.github.rafafrdz.criteria4s.core + +trait Show[-V, D <: CriteriaTag] { + def show(v: V): String +} + +object Show { + def create[V, D <: CriteriaTag](f: V => String): Show[V, D] = (v: V) => f(v) + + implicit def defaultStringShow[D <: CriteriaTag]: Show[String, D] = identity + implicit def defaultIntShow[V <: AnyVal, D <: CriteriaTag]: Show[V, D] = create(_.toString) +} diff --git a/core/src/main/scala/io/github/rafafrdz/criteria4s/core/Sym.scala b/core/src/main/scala/io/github/rafafrdz/criteria4s/core/Sym.scala deleted file mode 100644 index 1ae376c..0000000 --- a/core/src/main/scala/io/github/rafafrdz/criteria4s/core/Sym.scala +++ /dev/null @@ -1,25 +0,0 @@ -package io.github.rafafrdz.criteria4s.core - -import io.github.rafafrdz.criteria4s.core.Criteria.CriteriaTag -import io.github.rafafrdz.criteria4s.core.Ref.{Bool, Col, Value} - -trait Sym[T <: CriteriaTag] { - def value[V](v: Value[V, T]): Value[V, T] = v - def bool(v: Bool[T]): Bool[T] = v - def col(c: Col[T]): Col[T] = c -} -object Sym { - - private[criteria4s] def sym[T <: CriteriaTag]( - C: String => String, - V: String => String - ): Sym[T] = new Sym[T] { - - override def value[V](v: Value[V, T]): Value[V, T] = - new Value[V, T] { - override def ref: Criteria[T] = Criteria.pure(V(v.ref.value)) - } - - override def col(c: Col[T]): Col[T] = Ref.col(C(c.ref.value)) - } -} diff --git a/core/src/main/scala/io/github/rafafrdz/criteria4s/core/package.scala b/core/src/main/scala/io/github/rafafrdz/criteria4s/core/package.scala index 8320bfe..61bcc33 100644 --- a/core/src/main/scala/io/github/rafafrdz/criteria4s/core/package.scala +++ b/core/src/main/scala/io/github/rafafrdz/criteria4s/core/package.scala @@ -8,30 +8,30 @@ package object core { type OR[T <: CriteriaTag] = ConjOp.OR[T] - type GT[T <: CriteriaTag] = PredOp.GT[T] + type GT[T <: CriteriaTag] = PredicateBinary.GT[T] - type LT[T <: CriteriaTag] = PredOp.LT[T] + type LT[T <: CriteriaTag] = PredicateBinary.LT[T] - type EQ[T <: CriteriaTag] = PredOp.EQ[T] + type EQ[T <: CriteriaTag] = PredicateBinary.EQ[T] - type NEQ[T <: CriteriaTag] = PredOp.NEQ[T] + type NEQ[T <: CriteriaTag] = PredicateBinary.NEQ[T] - type GEQ[T <: CriteriaTag] = PredOp.GEQ[T] + type GEQ[T <: CriteriaTag] = PredicateBinary.GEQ[T] - type LEQ[T <: CriteriaTag] = PredOp.LEQ[T] + type LEQ[T <: CriteriaTag] = PredicateBinary.LEQ[T] - type LIKE[T <: CriteriaTag] = PredOp.LIKE[T] + type LIKE[T <: CriteriaTag] = PredicateBinary.LIKE[T] - type IN[T <: CriteriaTag] = PredOp.IN[T] + type IN[T <: CriteriaTag] = PredicateBinary.IN[T] - type NOTIN[T <: CriteriaTag] = PredOp.NOTIN[T] + type NOTIN[T <: CriteriaTag] = PredicateBinary.NOTIN[T] - type ISNULL[T <: CriteriaTag] = PredOp.ISNULL[T] + type ISNULL[T <: CriteriaTag] = PredicateUnary.ISNULL[T] - type ISNOTNULL[T <: CriteriaTag] = PredOp.ISNOTNULL[T] + type ISNOTNULL[T <: CriteriaTag] = PredicateUnary.ISNOTNULL[T] - type BETWEEN[T <: CriteriaTag] = PredOp.BETWEEN[T] + type BETWEEN[T <: CriteriaTag] = PredicateBinary.BETWEEN[T] - type NOTBETWEEN[T <: CriteriaTag] = PredOp.NOTBETWEEN[T] + type NOTBETWEEN[T <: CriteriaTag] = PredicateBinary.NOTBETWEEN[T] } diff --git a/core/src/main/scala/io/github/rafafrdz/criteria4s/extensions/predicates.scala b/core/src/main/scala/io/github/rafafrdz/criteria4s/extensions/predicates.scala index 9cf70e5..4875738 100644 --- a/core/src/main/scala/io/github/rafafrdz/criteria4s/extensions/predicates.scala +++ b/core/src/main/scala/io/github/rafafrdz/criteria4s/extensions/predicates.scala @@ -1,38 +1,63 @@ package io.github.rafafrdz.criteria4s.extensions import io.github.rafafrdz.criteria4s.core.Criteria.CriteriaTag -import io.github.rafafrdz.criteria4s.core.PredOp._ -import io.github.rafafrdz.criteria4s.core.{Criteria, Ref} +import io.github.rafafrdz.criteria4s.core.PredicateBinary._ +import io.github.rafafrdz.criteria4s.core.PredicateUnary._ +import io.github.rafafrdz.criteria4s.core.Ref.Collection +import io.github.rafafrdz.criteria4s.core.{Criteria, Ref, Show} import io.github.rafafrdz.criteria4s.{functions => F} trait predicates { - implicit class CriteriaPredImplicit[T <: CriteriaTag](c: Ref[T]) { - def lt(other: Ref[T])(implicit H: LT[T]): Criteria[T] = F.lt(c, other) - def gt(other: Ref[T])(implicit H: GT[T]): Criteria[T] = F.gt(c, other) - def leq(other: Ref[T])(implicit H: LEQ[T]): Criteria[T] = F.leq(c, other) - - def geq(other: Ref[T])(implicit H: GEQ[T]): Criteria[T] = F.geq(c, other) - - def ===(other: Ref[T])(implicit H: EQ[T]): Criteria[T] = F.===(c, other) - - def =!=(other: Ref[T])(implicit H: NEQ[T]): Criteria[T] = F.=!=(c, other) - - def like(other: Ref[T])(implicit H: LIKE[T]): Criteria[T] = F.like(c, other) - - def in(other: Ref[T])(implicit H: IN[T]): Criteria[T] = F.in(c, other) - - def notin(other: Ref[T])(implicit H: NOTIN[T]): Criteria[T] = F.notin(c, other) - - def isNull(implicit H: ISNULL[T]): Criteria[T] = F.isNull(c) - - def isNotNull(implicit H: ISNOTNULL[T]): Criteria[T] = F.isNotNull(c) - - def between(other: Ref[T])(implicit H: BETWEEN[T]): Criteria[T] = F.between(c, other) - - def notBetween(other: Ref[T])(implicit H: NOTBETWEEN[T]): Criteria[T] = + implicit class CriteriaPredImplicit[T <: CriteriaTag, L](c: Ref[T, L]) { + def lt[R]( + other: Ref[T, R] + )(implicit H: LT[T], showL: Show[L, T], showR: Show[R, T]): Criteria[T] = F.lt(c, other) + def gt[R]( + other: Ref[T, R] + )(implicit H: GT[T], showL: Show[L, T], showR: Show[R, T]): Criteria[T] = F.gt(c, other) + def leq[R]( + other: Ref[T, R] + )(implicit H: LEQ[T], showL: Show[L, T], showR: Show[R, T]): Criteria[T] = F.leq(c, other) + + def geq[R]( + other: Ref[T, R] + )(implicit H: GEQ[T], showL: Show[L, T], showR: Show[R, T]): Criteria[T] = F.geq(c, other) + + def ===[R]( + other: Ref[T, R] + )(implicit H: EQ[T], showL: Show[L, T], showR: Show[R, T]): Criteria[T] = F.===(c, other) + + def =!=[R]( + other: Ref[T, R] + )(implicit H: NEQ[T], showL: Show[L, T], showR: Show[R, T]): Criteria[T] = F.=!=(c, other) + + def like[R]( + other: Ref[T, R] + )(implicit H: LIKE[T], showL: Show[L, T], showR: Show[R, T]): Criteria[T] = F.like(c, other) + + def in[R]( + other: Collection[T, R] + )(implicit H: IN[T], showL: Show[L, T], showR: Show[Seq[R], T]): Criteria[T] = F.in(c, other) + + def notIn[R]( + other: Collection[T, R] + )(implicit H: NOTIN[T], showL: Show[L, T], showR: Show[Seq[R], T]): Criteria[T] = + F.notIn(c, other) + + def isNull(implicit H: ISNULL[T], show: Show[L, T]): Criteria[T] = F.isNull(c) + + def isNotNull(implicit H: ISNOTNULL[T], show: Show[L, T]): Criteria[T] = F.isNotNull(c) + + def between[R]( + other: Ref.Range[T, R] + )(implicit H: BETWEEN[T], showL: Show[L, T], showR: Show[(R, R), T]): Criteria[T] = + F.between(c, other) + + def notBetween[R]( + other: Ref.Range[T, R] + )(implicit H: NOTBETWEEN[T], showL: Show[L, T], showR: Show[(R, R), T]): Criteria[T] = F.notBetween(c, other) - } } diff --git a/core/src/main/scala/io/github/rafafrdz/criteria4s/functions/package.scala b/core/src/main/scala/io/github/rafafrdz/criteria4s/functions/package.scala index 72267c5..593e6bd 100644 --- a/core/src/main/scala/io/github/rafafrdz/criteria4s/functions/package.scala +++ b/core/src/main/scala/io/github/rafafrdz/criteria4s/functions/package.scala @@ -5,13 +5,22 @@ import io.github.rafafrdz.criteria4s.core._ package object functions extends predicates with conjunctions { - def pred[T <: CriteriaTag, H <: PredOp[T]](cr1: Ref[T], cr2: Ref[T])( - implicit H: H + def predBinary[T <: CriteriaTag, H <: PredicateBinary[T], L, R](cr1: Ref[T, L], cr2: Ref[T, R])( + implicit + H: H, + showL: Show[L, T], + showR: Show[R, T] ): Criteria[T] = H.eval(cr1, cr2) - def cond[T <: CriteriaTag, H <: ConjOp[T]](cr1: Criteria[T], cr2: Criteria[T])( - implicit H: H + def predUnary[T <: CriteriaTag, H <: PredicateUnary[T], V](ref: Ref[T, V])(implicit + H: H, + show: Show[V, T] + ): Criteria[T] = + H.eval(ref) + + def cond[T <: CriteriaTag, H <: ConjOp[T]](cr1: Criteria[T], cr2: Criteria[T])(implicit + H: H ): Criteria[T] = H.eval(cr1, cr2) diff --git a/core/src/main/scala/io/github/rafafrdz/criteria4s/functions/predicates.scala b/core/src/main/scala/io/github/rafafrdz/criteria4s/functions/predicates.scala index 1ec9ae7..9ad9b44 100644 --- a/core/src/main/scala/io/github/rafafrdz/criteria4s/functions/predicates.scala +++ b/core/src/main/scala/io/github/rafafrdz/criteria4s/functions/predicates.scala @@ -1,73 +1,112 @@ package io.github.rafafrdz.criteria4s.functions import io.github.rafafrdz.criteria4s.core.Criteria.CriteriaTag -import io.github.rafafrdz.criteria4s.core.PredOp._ -import io.github.rafafrdz.criteria4s.core.Ref.{Bool, Col, Value} -import io.github.rafafrdz.criteria4s.core.{Criteria, Ref, Sym} +import io.github.rafafrdz.criteria4s.core.PredicateBinary._ +import io.github.rafafrdz.criteria4s.core.PredicateUnary._ +import io.github.rafafrdz.criteria4s.core.Ref.{Bool, Col, Collection, Value} +import io.github.rafafrdz.criteria4s.core.{Column, Criteria, Ref, Show} private[functions] trait predicates { - def lit[T <: CriteriaTag: Sym, V](v: V): Value[V, T] = - implicitly[Sym[T]].value[V](Ref.value(v)) + def lit[T <: CriteriaTag, V](v: V): Value[T, V] = + Ref.value(v) - def bool[T <: CriteriaTag: Sym](v: Boolean): Bool[T] = - implicitly[Sym[T]].bool(Ref.bool(v)) + def bool[T <: CriteriaTag](v: Boolean): Bool[T] = + Ref.bool(v) - private[criteria4s] def __[T <: CriteriaTag]: Value[Nothing, T] = Ref.nothing[T] + private[criteria4s] def __[T <: CriteriaTag]: Value[T, Nothing] = Ref.nothing[T] - def col[T <: CriteriaTag: Sym](ref: String): Col[T] = implicitly[Sym[T]].col(Ref.col(ref)) + def col[T <: CriteriaTag](ref: String): Col[T] = Ref.col(Column(ref)) -// private def array_[T <: CriteriaTag: ARRAY](values: Criteria[T]*): Criteria[T] = pred[T, ARRAY[T]](values: _*) -// -// def array[T <: CriteriaTag: ARRAY, V](values: V*): Criteria[T] = array_(values.map(lit[T, V]): _*) -// - def lt[T <: CriteriaTag: LT](cr1: Ref[T], cr2: Ref[T]): Criteria[T] = - pred[T, LT[T]](cr1, cr2) + def array[T <: CriteriaTag, V](vs: V*): Collection[T, V] = Ref.array(vs: _*) - def gt[T <: CriteriaTag: GT](cr1: Ref[T], cr2: Ref[T]): Criteria[T] = - pred[T, GT[T]](cr1, cr2) + def range[T <: CriteriaTag, V](left: V, right: V): Ref.Range[T, V] = Ref.range(left, right) - def ===[T <: CriteriaTag: EQ](cr1: Ref[T], cr2: Ref[T]): Criteria[T] = - pred[T, EQ[T]](cr1, cr2) - - def =!=[T <: CriteriaTag: NEQ](cr1: Ref[T], cr2: Ref[T]): Criteria[T] = - pred[T, NEQ[T]](cr1, cr2) + def lt[T <: CriteriaTag: LT, L, R](cr1: Ref[T, L], cr2: Ref[T, R])(implicit + showL: Show[L, T], + showR: Show[R, T] + ): Criteria[T] = + predBinary[T, LT[T], L, R](cr1, cr2) - def neq[T <: CriteriaTag: NEQ](cr1: Ref[T], cr2: Ref[T]): Criteria[T] = - pred[T, NEQ[T]](cr1, cr2) + def gt[T <: CriteriaTag: GT, L, R](cr1: Ref[T, L], cr2: Ref[T, R])(implicit + showL: Show[L, T], + showR: Show[R, T] + ): Criteria[T] = + predBinary[T, GT[T], L, R](cr1, cr2) - def geq[T <: CriteriaTag: GEQ](cr1: Ref[T], cr2: Ref[T]): Criteria[T] = - pred[T, GEQ[T]](cr1, cr2) + def ===[T <: CriteriaTag: EQ, L, R](cr1: Ref[T, L], cr2: Ref[T, R])(implicit + showL: Show[L, T], + showR: Show[R, T] + ): Criteria[T] = + predBinary[T, EQ[T], L, R](cr1, cr2) - def leq[T <: CriteriaTag: LEQ](cr1: Ref[T], cr2: Ref[T]): Criteria[T] = - pred[T, LEQ[T]](cr1, cr2) + def =!=[T <: CriteriaTag: NEQ, L, R](cr1: Ref[T, L], cr2: Ref[T, R])(implicit + showL: Show[L, T], + showR: Show[R, T] + ): Criteria[T] = + predBinary[T, NEQ[T], L, R](cr1, cr2) - def like[T <: CriteriaTag: LIKE](cr1: Ref[T], cr2: Ref[T]): Criteria[T] = - pred[T, LIKE[T]](cr1, cr2) + def neq[T <: CriteriaTag: NEQ, L, R](cr1: Ref[T, L], cr2: Ref[T, R])(implicit + showL: Show[L, T], + showR: Show[R, T] + ): Criteria[T] = + predBinary[T, NEQ[T], L, R](cr1, cr2) - def in[T <: CriteriaTag: IN](cr1: Ref[T], cr2: Ref[T]): Criteria[T] = - pred[T, IN[T]](cr1, cr2) + def geq[T <: CriteriaTag: GEQ, L, R](cr1: Ref[T, L], cr2: Ref[T, R])(implicit + showL: Show[L, T], + showR: Show[R, T] + ): Criteria[T] = + predBinary[T, GEQ[T], L, R](cr1, cr2) - def notin[T <: CriteriaTag: NOTIN](cr1: Ref[T], cr2: Ref[T]): Criteria[T] = - pred[T, NOTIN[T]](cr1, cr2) + def leq[T <: CriteriaTag: LEQ, L, R](cr1: Ref[T, L], cr2: Ref[T, R])(implicit + showL: Show[L, T], + showR: Show[R, T] + ): Criteria[T] = + predBinary[T, LEQ[T], L, R](cr1, cr2) - def isNull[T <: CriteriaTag: ISNULL](cr1: Ref[T]): Criteria[T] = - pred[T, ISNULL[T]](cr1, __) + def like[T <: CriteriaTag: LIKE, L, R](cr1: Ref[T, L], cr2: Ref[T, R])(implicit + showL: Show[L, T], + showR: Show[R, T] + ): Criteria[T] = + predBinary[T, LIKE[T], L, R](cr1, cr2) - def isNotNull[T <: CriteriaTag: ISNOTNULL](cr1: Ref[T]): Criteria[T] = - pred[T, ISNOTNULL[T]](cr1, __) + def in[T <: CriteriaTag: IN, L, R](cr1: Ref[T, L], cr2: Ref[T, R])(implicit + showL: Show[L, T], + showR: Show[R, T] + ): Criteria[T] = + predBinary[T, IN[T], L, R](cr1, cr2) - def between[T <: CriteriaTag: BETWEEN]( - cr1: Ref[T], - cr2: Ref[T] + def notIn[T <: CriteriaTag: NOTIN, L, R](cr1: Ref[T, L], cr2: Ref[T, R])(implicit + showL: Show[L, T], + showR: Show[R, T] ): Criteria[T] = - pred[T, BETWEEN[T]](cr1, cr2) + predBinary[T, NOTIN[T], L, R](cr1, cr2) - def notBetween[T <: CriteriaTag: NOTBETWEEN]( - cr1: Ref[T], - cr2: Ref[T] + def isNull[T <: CriteriaTag: ISNULL, V](cr1: Ref[T, V])(implicit show: Show[V, T]): Criteria[T] = + predUnary[T, ISNULL[T], V](cr1) + + def isNotNull[T <: CriteriaTag: ISNOTNULL, V](cr1: Ref[T, V])(implicit + show: Show[V, T] + ): Criteria[T] = + predUnary[T, ISNOTNULL[T], V](cr1) + + def between[T <: CriteriaTag: BETWEEN, L, R]( + cr1: Ref[T, L], + cr2: Ref[T, R] + )(implicit + showL: Show[L, T], + showR: Show[R, T] + ): Criteria[T] = + predBinary[T, BETWEEN[T], L, R](cr1, cr2) + + def notBetween[T <: CriteriaTag: NOTBETWEEN, L, R]( + cr1: Ref[T, L], + cr2: Ref[T, R] + )(implicit + showL: Show[L, T], + showR: Show[R, T] ): Criteria[T] = - pred[T, NOTBETWEEN[T]](cr1, cr2) + predBinary[T, NOTBETWEEN[T], L, R](cr1, cr2) } object predicates extends predicates diff --git a/core/src/main/scala/io/github/rafafrdz/criteria4s/instances/package.scala b/core/src/main/scala/io/github/rafafrdz/criteria4s/instances/package.scala index 0ba2226..7887a15 100644 --- a/core/src/main/scala/io/github/rafafrdz/criteria4s/instances/package.scala +++ b/core/src/main/scala/io/github/rafafrdz/criteria4s/instances/package.scala @@ -1,16 +1,9 @@ package io.github.rafafrdz.criteria4s import io.github.rafafrdz.criteria4s.core.Criteria.CriteriaTag -import io.github.rafafrdz.criteria4s.core.Sym import io.github.rafafrdz.criteria4s.instances.builder.{Builder1, Builder2} package object instances { - def sym0[T <: CriteriaTag]: Sym[T] = sym1(v => v) - - def sym1[T <: CriteriaTag](symF: String => String): Sym[T] = sym(symF, symF) - def sym[T <: CriteriaTag](colF: String => String, valueF: String => String): Sym[T] = - Sym.sym(colF, valueF) - def build[T <: CriteriaTag, H[_ <: CriteriaTag]](F: (String, String) => String)(implicit BH: Builder2[H] ): H[T] = diff --git a/examples/src/main/scala/io/github/rafafrdz/criteria4s/examples/ArraysExample.scala b/examples/src/main/scala/io/github/rafafrdz/criteria4s/examples/ArraysExample.scala new file mode 100644 index 0000000..b4b9865 --- /dev/null +++ b/examples/src/main/scala/io/github/rafafrdz/criteria4s/examples/ArraysExample.scala @@ -0,0 +1,30 @@ +package io.github.rafafrdz.criteria4s.examples + +import io.github.rafafrdz.criteria4s.core._ +import io.github.rafafrdz.criteria4s.examples.datastores.{Postgres, WeirdDatastore} +import io.github.rafafrdz.criteria4s.functions._ + +object ArraysExample extends App { + val aIsNull: Criteria[Postgres] = isNull(col("a")) + def aIsNullAlgebra[ + T <: CriteriaTag: ISNULL: Show[Column, *] + ]: Criteria[T] = isNull(col("a")) + + val numberInArray: Criteria[Postgres] = in(col("a"), array(1, 2, 3)) + def numberInArrayAlgebra[T <: CriteriaTag: IN: Show[Column, *]: Show[Seq[Int], *]]: Criteria[T] = + in(col("a"), array(1, 2, 3)) + + val combined: Criteria[Postgres] = or(aIsNull, numberInArray) + val moreCombined: Criteria[Postgres] = or(combined, ===(col("b"), lit(10))) + + println(aIsNull) + println(aIsNullAlgebra[Postgres]) + println(aIsNullAlgebra[WeirdDatastore]) + + println(numberInArray) + println(numberInArrayAlgebra[Postgres]) + println(numberInArrayAlgebra[WeirdDatastore]) + + println(combined) + println(moreCombined) +} diff --git a/examples/src/main/scala/io/github/rafafrdz/criteria4s/examples/BetweenExample.scala b/examples/src/main/scala/io/github/rafafrdz/criteria4s/examples/BetweenExample.scala new file mode 100644 index 0000000..c8dd466 --- /dev/null +++ b/examples/src/main/scala/io/github/rafafrdz/criteria4s/examples/BetweenExample.scala @@ -0,0 +1,21 @@ +package io.github.rafafrdz.criteria4s.examples + +import io.github.rafafrdz.criteria4s.core._ +import io.github.rafafrdz.criteria4s.examples.datastores.{Postgres, WeirdDatastore} +import io.github.rafafrdz.criteria4s.extensions._ +import io.github.rafafrdz.criteria4s.functions._ + +object BetweenExample extends App { + val simpleBetween: Criteria[Postgres] = col[Postgres]("a").between(range(1, 10)) + val simpleNotBetween: Criteria[Postgres] = col[Postgres]("b").notBetween(range("A", "Z")) + + def taglessFinalBetweenExample[ + T <: CriteriaTag: BETWEEN: Show[Column, *]: Show[(Int, Int), *] + ]: Criteria[T] = + col[T]("column") between range(100, 150) + + println(simpleBetween) + println(simpleNotBetween) + println(taglessFinalBetweenExample[Postgres]) + println(taglessFinalBetweenExample[WeirdDatastore]) +} diff --git a/examples/src/main/scala/io/github/rafafrdz/criteria4s/examples/Example3.scala b/examples/src/main/scala/io/github/rafafrdz/criteria4s/examples/Example3.scala index 23aa084..b316b6c 100644 --- a/examples/src/main/scala/io/github/rafafrdz/criteria4s/examples/Example3.scala +++ b/examples/src/main/scala/io/github/rafafrdz/criteria4s/examples/Example3.scala @@ -6,10 +6,10 @@ import io.github.rafafrdz.criteria4s.functions._ object Example3 extends App { - def example1[T <: CriteriaTag: LT: AND: OR: Sym]: Criteria[T] = + def example1[T <: CriteriaTag: LT: AND: OR : Show[Column, *]]: Criteria[T] = or(and(lt(col("a"), lit(3)), lt(col("b"), lit(4))), bool(true)) - def example2[T <: CriteriaTag: LT: AND: OR: GEQ: ISNULL: NEQ: Sym]: Criteria[T] = + def example2[T <: CriteriaTag: LT: AND: OR: GEQ: ISNULL: NEQ: Show[Column, *]]: Criteria[T] = or( and( lt(col("col1"), lit(3)), diff --git a/examples/src/main/scala/io/github/rafafrdz/criteria4s/examples/Example4.scala b/examples/src/main/scala/io/github/rafafrdz/criteria4s/examples/Example4.scala index efc9b35..702bffa 100644 --- a/examples/src/main/scala/io/github/rafafrdz/criteria4s/examples/Example4.scala +++ b/examples/src/main/scala/io/github/rafafrdz/criteria4s/examples/Example4.scala @@ -7,12 +7,12 @@ import io.github.rafafrdz.criteria4s.functions._ object Example4 extends App { - def expr[T <: CriteriaTag: LEQ: EQ: AND: OR: Sym]: Criteria[T] = + def expr[T <: CriteriaTag: LEQ: EQ: AND: OR: Show[Column, *]]: Criteria[T] = (col[T]("a") leq lit(3)) and (col[T]("b") leq lit(4)) or (col[T]("c") === lit("c")) - def inlineExpr[T <: CriteriaTag: LEQ: EQ: AND: OR: Sym]: Criteria[T] = + def inlineExpr[T <: CriteriaTag: LEQ: EQ: AND: OR: Show[Column, *]]: Criteria[T] = (col[T]("a") leq lit(3)) and (col[T]("b") leq lit(4)) or (col[T]("c") === lit("c")) println { diff --git a/examples/src/main/scala/io/github/rafafrdz/criteria4s/examples/FilterByUserExample.scala b/examples/src/main/scala/io/github/rafafrdz/criteria4s/examples/FilterByUserExample.scala index bfc852a..6db102a 100644 --- a/examples/src/main/scala/io/github/rafafrdz/criteria4s/examples/FilterByUserExample.scala +++ b/examples/src/main/scala/io/github/rafafrdz/criteria4s/examples/FilterByUserExample.scala @@ -9,7 +9,7 @@ import java.util.UUID object FilterByUserExample extends App { - def expr[T <: CriteriaTag: EQ: Sym](fieldName: String, id: UUID): Criteria[T] = + def expr[T <: CriteriaTag: EQ: Show[Column, *]](fieldName: String, id: UUID): Criteria[T] = col[T](fieldName) === lit(id.toString) println { diff --git a/examples/src/main/scala/io/github/rafafrdz/criteria4s/examples/datastores/MySQL.scala b/examples/src/main/scala/io/github/rafafrdz/criteria4s/examples/datastores/MySQL.scala index 2a81108..7551426 100644 --- a/examples/src/main/scala/io/github/rafafrdz/criteria4s/examples/datastores/MySQL.scala +++ b/examples/src/main/scala/io/github/rafafrdz/criteria4s/examples/datastores/MySQL.scala @@ -1,6 +1,7 @@ package io.github.rafafrdz.criteria4s.examples.datastores -import io.github.rafafrdz.criteria4s.core.PredOp._ +import io.github.rafafrdz.criteria4s.core.PredicateBinary._ +import io.github.rafafrdz.criteria4s.core.{Column, Show} import io.github.rafafrdz.criteria4s.instances._ import io.github.rafafrdz.criteria4s.sql._ @@ -12,6 +13,8 @@ object MySQL extends SQLExpr[MySQL] { * That's not the right symbol for MySQL but it's just an example of how to override the default * implementation */ + implicit val showColumn: Show[Column, MySQL] = Show.create(_.colName) + implicit override val leqPred: LEQ[MySQL] = build[MySQL, LEQ](predExpr("<<<")) } diff --git a/examples/src/main/scala/io/github/rafafrdz/criteria4s/examples/datastores/Postgres.scala b/examples/src/main/scala/io/github/rafafrdz/criteria4s/examples/datastores/Postgres.scala index f56f18d..a57c06c 100644 --- a/examples/src/main/scala/io/github/rafafrdz/criteria4s/examples/datastores/Postgres.scala +++ b/examples/src/main/scala/io/github/rafafrdz/criteria4s/examples/datastores/Postgres.scala @@ -1,7 +1,6 @@ package io.github.rafafrdz.criteria4s.examples.datastores -import io.github.rafafrdz.criteria4s.core._ -import io.github.rafafrdz.criteria4s.instances._ +import io.github.rafafrdz.criteria4s.core.{Column, Show} import io.github.rafafrdz.criteria4s.sql.{SQL, _} trait Postgres extends SQL @@ -12,7 +11,9 @@ object Postgres extends SQLExpr[Postgres] { * default implementation */ - val C: String => String = s => s"`$s`" - val V: String => String = s => s"'$s'" - override implicit val symRef: Sym[Postgres] = sym[Postgres](C, V) + implicit val showColumn: Show[Column, Postgres] = Show.create(col => s"'${col.colName}'") + implicit def showSeq[T](implicit show: Show[T, Postgres]): Show[Seq[T], Postgres] = + Show.create(_.map(show.show).mkString("(", ", ", ")")) + implicit def betweenShow[T](implicit show: Show[T, Postgres]): Show[(T, T), Postgres] = + Show.create { case (l, r) => s"${show.show(l)} TO ${show.show(r)}" } } diff --git a/examples/src/main/scala/io/github/rafafrdz/criteria4s/examples/datastores/WeirdDatastore.scala b/examples/src/main/scala/io/github/rafafrdz/criteria4s/examples/datastores/WeirdDatastore.scala index fcbbf6c..0775588 100644 --- a/examples/src/main/scala/io/github/rafafrdz/criteria4s/examples/datastores/WeirdDatastore.scala +++ b/examples/src/main/scala/io/github/rafafrdz/criteria4s/examples/datastores/WeirdDatastore.scala @@ -2,8 +2,9 @@ package io.github.rafafrdz.criteria4s.examples.datastores import io.github.rafafrdz.criteria4s.core.ConjOp._ import io.github.rafafrdz.criteria4s.core.Criteria.CriteriaTag -import io.github.rafafrdz.criteria4s.core.PredOp._ -import io.github.rafafrdz.criteria4s.core.Sym +import io.github.rafafrdz.criteria4s.core.PredicateBinary._ +import io.github.rafafrdz.criteria4s.core.PredicateUnary._ +import io.github.rafafrdz.criteria4s.core.{Column, Show} import io.github.rafafrdz.criteria4s.instances._ trait WeirdDatastore extends CriteriaTag @@ -16,6 +17,14 @@ object WeirdDatastore { private def wope1(symbol: String)(left: String): String = s"""{left: $left, opt: $symbol }""".stripMargin + implicit def showSeq[V](implicit show: Show[V, WeirdDatastore]): Show[Seq[V], WeirdDatastore] = + Show.create(_.map(show.show).mkString("[", ", ", "]")) + + implicit def showRange[V](implicit show: Show[V, WeirdDatastore]): Show[(V, V), WeirdDatastore] = + Show.create { case (l, r) => s"[${show.show(l)}, ${show.show(r)}]" } + + implicit val showColumn: Show[Column, WeirdDatastore] = Show.create(_.colName) + implicit val ltPred: LT[WeirdDatastore] = build[WeirdDatastore, LT](wope("<")) implicit val gtPred: GT[WeirdDatastore] = build[WeirdDatastore, GT](wope(">")) @@ -49,6 +58,4 @@ object WeirdDatastore { implicit val notbetweenPred: NOTBETWEEN[WeirdDatastore] = build[WeirdDatastore, NOTBETWEEN](wope("NOT BETWEEN")) - implicit val symRef: Sym[WeirdDatastore] = sym0[WeirdDatastore] - } diff --git a/project/Dependencies.scala b/project/Dependencies.scala index 1edb07a..6ff9dd8 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -2,4 +2,10 @@ import sbt._ object Dependencies { lazy val munit = "org.scalameta" %% "munit" % "0.7.29" + + implicit class ProjectOps(val prj: Project) extends AnyVal { + def withKindProjector: Project = prj.settings( + addCompilerPlugin("org.typelevel" % "kind-projector" % "0.13.2" cross CrossVersion.full) + ) + } } diff --git a/sql/src/main/scala/io/github/rafafrdz/criteria4s/sql/SQL.scala b/sql/src/main/scala/io/github/rafafrdz/criteria4s/sql/SQL.scala index b5d47f7..8607ff2 100644 --- a/sql/src/main/scala/io/github/rafafrdz/criteria4s/sql/SQL.scala +++ b/sql/src/main/scala/io/github/rafafrdz/criteria4s/sql/SQL.scala @@ -1,8 +1,9 @@ package io.github.rafafrdz.criteria4s.sql import io.github.rafafrdz.criteria4s.core.ConjOp._ -import io.github.rafafrdz.criteria4s.core.PredOp._ -import io.github.rafafrdz.criteria4s.core.{CriteriaTag, Sym} +import io.github.rafafrdz.criteria4s.core.PredicateBinary._ +import io.github.rafafrdz.criteria4s.core.PredicateUnary._ +import io.github.rafafrdz.criteria4s.core.{Column, CriteriaTag, Show} import io.github.rafafrdz.criteria4s.instances._ trait SQL extends CriteriaTag @@ -13,6 +14,8 @@ object SQL { private def opExpr(symbol: String)(a: String, b: String): String = s"($a) $symbol ($b)" private def predExpr1(symbol: String)(a: String): String = s"$a $symbol" + implicit val showColumn: Show[Column, SQL] = Show.create(col => s"'${col.colName}'") + trait SQLExpr[T <: SQL] { protected def predExpr(symbol: String)(a: String, b: String): String = @@ -20,8 +23,6 @@ object SQL { protected def opExpr(symbol: String)(a: String, b: String): String = SQL.opExpr(symbol)(a, b) protected def predExpr1(symbol: String)(a: String): String = SQL.predExpr1(symbol)(a) - implicit val symRef: Sym[T] = sym[T](v => v, c => s"'$c'") - implicit val ltPred: LT[T] = build[T, LT](predExpr("<")) implicit val gtPred: GT[T] = build[T, GT](predExpr(">"))