Skip to content

Commit

Permalink
Refactor documentation (#33)
Browse files Browse the repository at this point in the history
In this PR we refactor de **README** file and add some doc files in
order to clarify the use of criteria4s:
- Defining criteria expressions
- Evaluating criteria expressions using:
  - PostgreSQL dialect (non-official)
  - MongoDB dialect
  - MySQL dialect (non-official)
  - Custom dialect
  • Loading branch information
rafafrdz authored Aug 13, 2024
1 parent 9301c8f commit d9319c0
Show file tree
Hide file tree
Showing 6 changed files with 374 additions and 37 deletions.
110 changes: 73 additions & 37 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,30 +37,43 @@ To use dsl of Criteria4s, you need to add the following dependency to your proje

- Core library: [criteria4s-core](https://central.sonatype.com/artifact/io.github.rafafrdz/criteria4s-core_2.13)
- SQL implementation: [criteria4s-sql](https://central.sonatype.com/artifact/io.github.rafafrdz/criteria4s-sql_2.13)
- MongoDB dialect
implementation: [criteria4s-mongodb](https://central.sonatype.com/artifact/io.github.rafafrdz/criteria4s-mongodb_2.13)

**SBT**

```scala
libraryDependencies += "io.github.rafafrdz" %% "criteria4s-core" % "<version>" // Core library
libraryDependencies += "io.github.rafafrdz" %% "criteria4s-sql" % "<version>" // SQL implementation
libraryDependencies += "io.github.rafafrdz" %% "criteria4s-mongodb" % "<version>" // MongoDB implementation

```

**Maven**

```xml
<!-- Core library -->
<dependency>
<groupId>io.github.rafafrdz</groupId>
<artifactId>criteria4s-core_2.13</artifactId>
<version>0.8.0</version>
</dependency>

<!-- SQL implementation -->
<dependency>
<groupId>io.github.rafafrdz</groupId>
<artifactId>criteria4s-core_2.13</artifactId>
<version>0.8.0</version>
</dependency>
<dependencies>
<dependency>
<groupId>io.github.rafafrdz</groupId>
<artifactId>criteria4s-core_2.13</artifactId>
<version>0.8.2</version>
</dependency>

<!-- SQL implementation -->
<dependency>
<groupId>io.github.rafafrdz</groupId>
<artifactId>criteria4s-core_2.13</artifactId>
<version>0.8.2</version>
</dependency>

<!-- MongoDB implementation -->
<dependency>
<groupId>io.github.rafafrdz</groupId>
<artifactId>criteria4s-mongodb_2.13</artifactId>
<version>0.8.2</version>
</dependency>
</dependencies>
```

> [!IMPORTANT]
Expand All @@ -70,52 +83,75 @@ libraryDependencies += "io.github.rafafrdz" %% "criteria4s-sql" % "<version>" //

Criteria4s is extensible to support any kind of data stores. Currently, it supports the following **dialects**:

| Dialect | Package | Example |
|-------------|:-------------------------------------------------------------------------------------------|:--------|
| SQL | [sql](./sql/src/main/scala/io/github/rafafrdz/criteria4s/dialect/sql) | - |
| MongoDB | [mongodb](./mongodb/src/main/scala/io/github/rafafrdz/criteria4s/dialect/mongodb) | - |
| PostgresSQL | [postgresql](./postgresql/src/main/scala/io/github/rafafrdz/criteria4s/dialect/postgresql) | - |
| Dialect | Package |
|-------------|:-------------------------------------------------------------------------------------------|
| SQL | [sql](./sql/src/main/scala/io/github/rafafrdz/criteria4s/dialect/sql) |
| MongoDB | [mongodb](./mongodb/src/main/scala/io/github/rafafrdz/criteria4s/dialect/mongodb) |
| PostgresSQL | [postgresql](./postgresql/src/main/scala/io/github/rafafrdz/criteria4s/dialect/postgresql) |

## Examples

Here, we will show some examples of how to use the Criteria DSL.
Here, we will show some examples of how to use the Criteria DSL. You can find more examples in
the [`criteria4s-examples`](./examples/src/main/scala/io/github/rafafrdz/criteria4s/examples) module.

### Imports

First, we need to import the Criteria4s DSL and the SQL dialect:

```scala
import io.github.rafafrdz.criteria4s.core._
import io.github.rafafrdz.criteria4s.examples.datastores._
import io.github.rafafrdz.criteria4s.extensions._
import io.github.rafafrdz.criteria4s.functions._
```

def ageCriteria[T <: CriteriaTag : GT : LT : AND : Sym]: Criteria[T] =
(col[T]("age") gt lit(18)) and (col[T]("age") lt lit(65))
### Defining Criteria Expressions

def expr[T <: CriteriaTag : LEQ : EQ : AND : OR : Sym]: Criteria[T] =
(col[T]("a") leq lit(3)) and (col[T]("b") leq lit(4)) or (col[T]("c") === lit("c"))
We can define criteria expressions in a polymorphic way by using the Criteria DSL. You can find more definitions
examples
in the [`Defining Criteria Expressions`](./doc/defining-criteria-expressions.md) document.

def expr2[T <: CriteriaTag : EQ : Sym](fieldName: String, id: UUID): Criteria[T] =
col[T](fieldName) === lit(id.toString)
```scala
def expr[T <: CriteriaTag : LEQ : EQ : AND : OR : Show[Column, *]]: Criteria[T] =
(col[T]("field1") leq lit(3)) and (col[T]("field2") leq lit(4)) or (col[T]("field3") === lit("c"))
```

And then we can use the `ageCriteria`, `expr` and `expr2` functions to generate criteria expressions for different
datastores:
#### Case of use

```scala
ageCriteria[WeirdDatastore]
// res: {left: {left: age, opt: >, right: 18 }, opt: AND, right: {left: age, opt: <, right: 65 } }

expr[MySQL]
// res: ((a <<< '3') AND (b <<< '4')) OR (c = 'c')
def ageCriteria[T <: CriteriaTag : GT : LT : AND : Show[Column, *]]: Criteria[T] =
(col[T]("age") gt lit(18)) and (col[T]("age") lt lit(65))

expr2[Postgres]("USER_ID", UUID.randomUUID())
// res: `USER_ID` = '07715cee-5d87-427d-99a7-cc03f2b5ef4a'
def refCriteria[T <: CriteriaTag : EQ : Show[Column, *]](fieldName: String, id: UUID): Criteria[T] =
col[T](fieldName) === lit(id.toString)
```

### Evaluating Criteria Expressions

And then we can use those expressions defined belows in order to generate criteria expressions for different
datastores by importing the corresponding dialects. You can find evaluation examples for some different dialects in the
following documents:

- [PostgreSQL Dialect](./doc/postgresql-dialect-evaluating.md)
- [MongoDB Dialect](./doc/mongodb-dialect-evaluating.md)
- [MySQL Dialect](./doc/mysql-dialect-evaluating.md)
- [Custom Dialect](./doc/custom-dialect-evaluating.md)

### Inline Criteria DSL

Or maybe we can use the Criteria DSL inline:

```scala
(col[WeirdDatastore]("a") leq lit(3)) and (col[WeirdDatastore]("b") leq lit(4)) or (col[WeirdDatastore]("c") === lit("c"))
// res: {left: {left: {left: a, opt: <=, right: 3 }, opt: AND, right: {left: b, opt: <=, right: 4 } }, opt: OR, right: {left: c, opt: =, right: c } }
(col[PostgreSQL]("field1") leq lit(3)) and (col[PostgreSQL]("field2") leq lit(4)) or (col[PostgreSQL]("field3") === lit("c"))
// res: (('field1' <= 3) AND ('field2' <= 4)) OR ('field3' = c)
```

You can find more examples in
the [`criteria4s-examples`](./examples/src/main/scala/io/github/rafafrdz/criteria4s/examples) module.
```scala
(col[MongoDB]("field1") leq lit(3)) and (col[MongoDB]("field2") leq lit(4)) or (col[MongoDB]("field3") === lit("c"))
// res: {$or: [{$and: [{"field1": {$lte: 3}}, {"field2": {$lte: 4}}]}, {"field3": {$eq: c}}]}
```

```scala
(col[WeirdDatastore]("field1") leq lit(3)) and (col[WeirdDatastore]("field2") leq lit(4)) or (col[WeirdDatastore]("field3") === lit("c"))
// res: {left: {left: {left: field1, opt: <=, right: 3 }, opt: AND, right: {left: field2, opt: <=, right: 4 } }, opt: OR, right: {left: field3, opt: =, right: c } }
```
63 changes: 63 additions & 0 deletions doc/custom-dialect-evaluating.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# Custom Dialect

The `WeirdDatastore` dialect using in this document is an own-implemented dialect for a custom or "weird" datastore.
The examples provided illustrate what the output would look like if a `WeirdDatastore` dialect needs be implemented.
The results are intentionally generated using weird expressions to highlight the differences that occur when applying
the same criteria expression across different dialects.

The `WeirdDatastore` dialect implementation is located in the [WeirdDatastore.scala](../examples/src/main/scala/io/github/rafafrdz/criteria4s/examples/datastores/WeirdDatastore.scala) file.

For these examples we will use the defined expressions in
the [Defining Criteria Expressions](defining-criteria-expressions.md) document.

```scala
expr[WeirdDatastore]
// res: {left: {left: {left: field1, opt: <=, right: 3 }, opt: AND, right: {left: field2, opt: <=, right: 4 } }, opt: OR, right: {left: field3, opt: =, right: c } }
```

## Case of use

```scala
ageCriteria[WeirdDatastore]
// res: {left: {left: age, opt: >, right: 18 }, opt: AND, right: {left: age, opt: <, right: 65 } }
```

```scala
refCriteria[WeirdDatastore]("id", UUID.randomUUID())
// res: {left: id, opt: =, right: dfacb848-6d39-404b-9e6b-f8cbc1f52918 }
```

### Using `IS NULL` expression

```scala
isNullExpr[WeirdDatastore]("field")
// res: {left: field, opt: IS NULL }
```

### Using `NOT` expression

```scala
notExpr[WeirdDatastore]("field")
// res: {left: {left: {left: field, opt: >, right: 2 }, opt: NOT }, opt: AND, right: {left: field, opt: <=, right: 10 } }
```

### Using `BETWEEN` expression

```scala
betweenExpr[WeirdDatastore]("field")
// res: {left: field, opt: BETWEEN, right: [100, 150] }
```

### Using `ARRAY` expression

```scala
arrayExpr[WeirdDatastore]("field")
// res: {left: field, opt: IN, right: [1, 2, 3] }
```

### Using `LIKE` expression

```scala
likeExpr[WeirdDatastore]("field")
// res: {left: field, opt: LIKE, right: a% }
```
53 changes: 53 additions & 0 deletions doc/defining-criteria-expressions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Defining Criteria Expressions

We can define criteria expressions in a polymorphic way by using the Criteria DSL:

```scala
def expr[T <: CriteriaTag : LEQ : EQ : AND : OR : Show[Column, *]]: Criteria[T] =
(col[T]("field1") leq lit(3)) and (col[T]("field2") leq lit(4)) or (col[T]("field3") === lit("c"))
```

## Case of use

```scala
def ageCriteria[T <: CriteriaTag : GT : LT : AND : Show[Column, *]]: Criteria[T] =
(col[T]("age") gt lit(18)) and (col[T]("age") lt lit(65))

def refCriteria[T <: CriteriaTag : EQ : Show[Column, *]](fieldName: String, id: UUID): Criteria[T] =
col[T](fieldName) === lit(id.toString)
```

### Using `IS NULL` expression

```scala
def isNullExpr[T <: CriteriaTag : ISNULL : Show[Column, *]](fieldName: String): Criteria[T] =
col[T](fieldName).isNull
```

### Using `NOT` expression

```scala
def notExpr[T <: CriteriaTag : NOT : GT : LEQ : AND : Show[Column, *] : Show[(Int, Int), *]](fieldName: String): Criteria[T] =
not(col[T](fieldName) gt lit(2)) && (col[T](fieldName) leq lit(10))
```

### Using `BETWEEN` expression

```scala
def betweenExpr[T <: CriteriaTag : BETWEEN : Show[Column, *] : Show[(Int, Int), *]](fieldName: String): Criteria[T] =
col[T](fieldName) between range(100, 150)
```

### Using `ARRAY` expression

```scala
def arrayExpr[T <: CriteriaTag : IN : Show[Column, *] : Show[Seq[Int], *]](fieldName: String): Criteria[T] =
col[T](fieldName) in array(1, 2, 3)
```

### Using `LIKE` expression

```scala
def likeExpr[T <: CriteriaTag : LIKE : Show[Column, *]](fieldName: String): Criteria[T] =
col[T](fieldName) like lit("a%")
```
59 changes: 59 additions & 0 deletions doc/mongodb-dialect-evaluating.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# MongoDB Dialect

The `MongoDB` dialect is available. The examples provided illustrate what the output look like using the MongoDB
dialect.

For these examples we will use the defined expressions in
the [Defining Criteria Expressions](defining-criteria-expressions.md) document.

```scala
expr[MongoDB]
// res: {$or: [{$and: [{"field1": {$lte: 3}}, {"field2": {$lte: 4}}]}, {"field3": {$eq: c}}]}
```

## Case of use

```scala
ageCriteria[MongoDB]
// res: {$and: [{"age": {$gt: 18}}, {"age": {$lt: 65}}]}
```

```scala
refCriteria[MongoDB]("id", UUID.randomUUID())
// res: {"id": {$eq: d0ba6ea7-4cff-44e4-b612-ebe12242bd18}}
```

### Using `IS NULL` expression

```scala
isNullExpr[MongoDB]("field")
// res: {"field": null}
```

### Using `NOT` expression

```scala
notExpr[MongoDB]("field")
// res: {$and: [{"field": {$not: {$gt: 2}}}, {"field": {$lte: 10}}]}
```

### Using `BETWEEN` expression

```scala
betweenExpr[MongoDB]("field")
// res: {"field": { $gte: 100, $lt: 150 }}
```

### Using `ARRAY` expression

```scala
arrayExpr[MongoDB]("field")
// res: {"field": {$in: [1, 2, 3]}}
```

### Using `LIKE` expression

```scala
likeExpr[MongoDB]("field")
// res: {"field": {$regex: \a%\}}
```
Loading

0 comments on commit d9319c0

Please sign in to comment.