Skip to content

Commit

Permalink
Branch 0.8 (#16)
Browse files Browse the repository at this point in the history
* 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 <[email protected]>
mark-kar and m.karavashkin authored May 11, 2024
1 parent c2bd751 commit 9fc2f65
Showing 22 changed files with 465 additions and 277 deletions.
13 changes: 8 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -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<Boolean>
Criteria := Conjuction Criteria Criteria | Predicate | Value<Boolean>
Predicate := UnaryPred Ref | BinaryPred Ref Ref
Ref := Value<T> | 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<T>` 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.
3 changes: 3 additions & 0 deletions build.sbt
Original file line number Diff line number Diff line change
@@ -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
103 changes: 0 additions & 103 deletions core/src/main/scala/io/github/rafafrdz/criteria4s/core/PredOp.scala

This file was deleted.

168 changes: 168 additions & 0 deletions core/src/main/scala/io/github/rafafrdz/criteria4s/core/Predicate.scala
Original file line number Diff line number Diff line change
@@ -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))
}
}
}
51 changes: 23 additions & 28 deletions core/src/main/scala/io/github/rafafrdz/criteria4s/core/Ref.scala
Original file line number Diff line number Diff line change
@@ -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
12 changes: 12 additions & 0 deletions core/src/main/scala/io/github/rafafrdz/criteria4s/core/Show.scala
Original file line number Diff line number Diff line change
@@ -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)
}
25 changes: 0 additions & 25 deletions core/src/main/scala/io/github/rafafrdz/criteria4s/core/Sym.scala

This file was deleted.

Original file line number Diff line number Diff line change
@@ -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]

}
Original file line number Diff line number Diff line change
@@ -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)

}

}
Original file line number Diff line number Diff line change
@@ -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)

Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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] =
Original file line number Diff line number Diff line change
@@ -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)
}
Original file line number Diff line number Diff line change
@@ -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])
}
Original file line number Diff line number Diff line change
@@ -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)),
Original file line number Diff line number Diff line change
@@ -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 {
Original file line number Diff line number Diff line change
@@ -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 {
Original file line number Diff line number Diff line change
@@ -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("<<<"))

}
Original file line number Diff line number Diff line change
@@ -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)}" }
}
Original file line number Diff line number Diff line change
@@ -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]

}
6 changes: 6 additions & 0 deletions project/Dependencies.scala
Original file line number Diff line number Diff line change
@@ -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)
)
}
}
Original file line number Diff line number Diff line change
@@ -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,15 +14,15 @@ 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 =
SQL.predExpr(symbol)(a, b)
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(">"))

0 comments on commit 9fc2f65

Please sign in to comment.