Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/ajozwik/sbt-protoquill-crud-generic
https://github.com/ajozwik/sbt-protoquill-crud-generic
Last synced: about 2 months ago
JSON representation
- Host: GitHub
- URL: https://github.com/ajozwik/sbt-protoquill-crud-generic
- Owner: ajozwik
- License: mit
- Created: 2023-04-27T14:20:27.000Z (over 1 year ago)
- Default Branch: master
- Last Pushed: 2024-01-19T21:06:48.000Z (12 months ago)
- Last Synced: 2024-01-19T22:27:34.161Z (12 months ago)
- Language: Scala
- Size: 145 KB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# sbt-protoquill-crud-generic
Library of generic CRUD operation for [protoquill](https://github.com/zio/zio-protoquill) library. Only dynamic queries are supported.
[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.github.ajozwik/sbt-protoquill-crud-generic/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.github.ajozwik/sbt-protoquill-crud-generic)
[![Scala CI](https://github.com/ajozwik/sbt-protoquill-crud-generic/actions/workflows/ci.yml/badge.svg)](https://github.com/ajozwik/sbt-protoquill-crud-generic/actions/workflows/ci.yml)
[![Coverage Status](https://coveralls.io/repos/github/ajozwik/sbt-protoquill-crud-generic/badge.svg?branch=master)](https://coveralls.io/github/ajozwik/sbt-protoquill-crud-generic?branch=master)
[![codecov](https://codecov.io/gh/ajozwik/sbt-protoquill-crud-generic/branch/master/graph/badge.svg?token=ZGHJ344TLO)](https://codecov.io/gh/ajozwik/sbt-protoquill-crud-generic)To activate the plugins add to project/plugins.sbt:
```scala
addSbtPlugin("com.github.ajozwik" % "sbt-protoquill-crud-generic" % quillGenericVersion)
```
And to build.sbt
```scala
enablePlugins(QuillRepositoryPlugin)
```For simple usage you need to add:
```scala
generateTryRepositories += RepositoryDescription(
"pl.jozwik.example.model.Person", // model object
"pl.jozwik.example.model.PersonId", // model key
"pl.jozwik.example.monad.repository.PersonRepositoryGen", // repository implementation
true, // generated id , false for not generated id
Option("pl.jozwik.example.monad.impl.MyPersonRepository[Dialect, Naming, C]") // custom trait repository implementation or domain trait, or None
)
```where:
```sql
CREATE TABLE IF NOT EXISTS PERSON
(
ID INT NOT NULL,
FIRST_NAME VARCHAR(50) NOT NULL,
LAST_NAME VARCHAR(20) NOT NULL,
BIRTH_DATE DATE,
ADDRESS_ID INT DEFAULT NULL
)```
[Person.scala](/src/sbt-test/all/all/common/src/main/scala/pl/jozwik/example/domain/model/Person.scala)
```scala
package pl.jozwik.example.domain.modelimport java.time.LocalDate
import pl.jozwik.quillgeneric.repository.WithId
object PersonId {
val empty: PersonId = PersonId(0)
}final case class PersonId(value: Int) extends AnyVal
final case class Person(id: PersonId, firstName: String, lastName: String, birthDate: LocalDate, addressId: Option[AddressId] = None) extends WithId[PersonId]
```
[PersonRepository.scala](/src/sbt-test/all/all/common/src/main/scala/pl/jozwik/example/domain/repository/PersonRepository.scala)
```scala
trait PersonRepository[F[_], UP] extends RepositoryWithGeneratedId[F, PersonId, Person, UP] {def count: F[Long]
def searchByFirstName(name: String)(offset: Int, limit: Int): F[Seq[Person]]
def maxBirthDate: F[Option[LocalDate]]
def youngerThan(date: LocalDate)(offset: Int, limit: Int): F[Seq[Person]]
}
```[MyPersonRepository.scala](/src/sbt-test/all/all/monad/src/main/scala/pl/jozwik/example/monad/impl/PersonRepositoryImpl.scala) for scala.util.Try Monad
```scala
package pl.jozwik.example.monad.implimport io.getquill.*
import io.getquill.context.sql.idiom.SqlIdiom
import io.getquill.extras.LocalDateOps
import pl.jozwik.quillgeneric.monad.*
import pl.jozwik.example.domain.model.{ Person, PersonId }
import pl.jozwik.example.domain.repository.PersonRepositoryimport java.time.LocalDate
import scala.util.Try
trait PersonRepositoryImpl[+Dialect <: SqlIdiom, +Naming <: NamingStrategy, C <: TryJdbcContextWithDateQuotes[Dialect, Naming]]
extends TryJdbcRepositoryWithGeneratedId[PersonId, Person, C, Dialect, Naming]
with PersonRepository[Try, Long] {
import context.*
def searchByFirstName(name: String)(offset: Int, limit: Int): Try[Seq[Person]] = {
val q = quoteQuery.filter(_.firstName == lift(name)).filter(_.lastName != lift("")).drop(lift(offset)).take(lift(limit))
Try { run(q) }
}def maxBirthDate: Try[Option[LocalDate]] = {
val r = quoteQuery.map(p => p.birthDate)
Try { run(r.max) }
}def youngerThan(date: LocalDate)(offset: Int, limit: Int): Try[Seq[Person]] = {
val q = quoteQuery.filter(_.birthDate > lift(date)).drop(lift(offset)).take(lift(limit))
Try { run(q) }
}def count: Try[Long] =
val q = quoteQuery.size
Try { run(q) }}
```
Auto generated class will look like:
```scala
//------------------------------------------------------------------------------
//
// This code was generated from a template.
//
// Manual changes to this file may cause unexpected behavior in your application.
// Manual changes to this file will be overwritten if the code is regenerated.
//
//------------------------------------------------------------------------------
package pl.jozwik.example.monad.repositoryimport io.getquill.*
import io.getquill.context.sql.idiom.SqlIdiom
import pl.jozwik.example.domain.model.Person
import pl.jozwik.example.domain.model.PersonId
import pl.jozwik.example.monad.impl.PersonRepositoryImpl
import scala.util.Try
import pl.jozwik.quillgeneric.monad.*
import cats.implicits.*final class PersonRepositoryGen[+Dialect <: SqlIdiom, +Naming <: NamingStrategy, C <: TryJdbcContextWithDateQuotes[Dialect, Naming]](
protected val context: C)(
implicit meta: SchemaMeta[Person]
) extends PersonRepositoryImpl[Dialect, Naming, C] {import context.*
protected def quoteQuery = quote {
query[Person]
}protected inline def find(id: PersonId): Quoted[EntityQuery[Person]] = quote {
quoteQuery.filter(_.id == lift(id))
}override def all: Try[Seq[Person]] =
for {
all <- Try {run(quoteQuery)}
} yield {
all
}override def create(entity: Person, generateId: Boolean = true): Try[PersonId] =
Try {if (generateId) {
run(quoteQuery.insertValue(lift(entity)).returningGenerated(_.id))
} else {
run(quoteQuery.insertValue(lift(entity)).returning(_.id))
}}override def createOrUpdate(entity: Person, generateId: Boolean = true): Try[PersonId] = {
inTransaction {
for {
el <- Try {run(find(entity.id).updateValue(lift(entity)))}
id <- el match
case 0 =>
create(entity, generateId)
case _ =>
pure(entity.id)
} yield {
id
}
}
}override def read(id: PersonId): Try[Option[Person]] =
for {
seq <- Try {run(find(id))}
} yield {
seq.headOption
}override def update(entity: Person): Try[Long] =
Try {run(find(entity.id).updateValue(lift(entity)))}override def delete(id: PersonId): Try[Long] =
Try {run(find(id).delete)}override def deleteAll(): Try[Long] =
Try {run(quoteQuery.delete)}}
```
See [build.sbt](/src/sbt-test/all/all/build.sbt) for custom example of usage.To initialize object for sql model:
```sql
CREATE TABLE IF NOT EXISTS PERSON3
(
ID INT NOT NULL AUTO_INCREMENT,
FIRST_NAME VARCHAR(50) NOT NULL,
LAST_NAME VARCHAR(20) NOT NULL,
DOB DATE,
ADDRESS_ID INT DEFAULT NULL
)
```use:
```scala
val ctx = new H2JdbcContext(Literal, "h2")
implicit val meta: SchemaMeta[Person] = schemaMeta[Person]("Person3", columns => columns.birthDate -> "dob")
val repository = new PersonRepositoryGen(ctx)
```Config file for this example is:
[application.conf](/src/sbt-test/all/all/common/src/test/resources/application.conf)