Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve type flow #89

Merged
merged 2 commits into from
Apr 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 19 additions & 3 deletions init/data/test-tables.sql
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,23 @@ CREATE TABLE users

CREATE TABLE "identity-test"
(
always_generated Integer NOT NULL GENERATED ALWAYS AS IDENTITY (INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1),
default_generated Integer NOT NULL GENERATED BY DEFAULT AS IDENTITY (INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1),
name Character varying(250) NOT NULL primary key
always_generated Integer NOT NULL GENERATED ALWAYS AS IDENTITY (INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1),
default_generated Integer NOT NULL GENERATED BY DEFAULT AS IDENTITY (INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1),
name Character varying(250) NOT NULL primary key
);

create domain short_text as text
constraint short_text_check check (length(VALUE) <= 55);

create table flaff
(
code short_text not null,
another_code varchar(20) not null,
some_number integer not null,
specifier short_text not null,
parentSpecifier short_text,
constraint flaff_pk primary key (code, another_code, some_number, specifier),
constraint flaff_parent_fk foreign key (code, another_code, some_number, parentSpecifier) references flaff
);


Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/**
* File has been automatically generated by `typo`.
*
* IF YOU CHANGE THIS FILE YOUR CHANGES WILL BE OVERWRITTEN.
*/
package adventureworks
package public

import adventureworks.Text
import anorm.Column
import anorm.ParameterMetaData
import anorm.ToStatement
import play.api.libs.json.Reads
import play.api.libs.json.Writes
import typo.dsl.Bijection

/** Domain `public.short_text`
* Constraint: CHECK ((length(VALUE) <= 55))
*/
case class ShortText(value: String)
object ShortText {
implicit lazy val arrayColumn: Column[Array[ShortText]] = Column.columnToArray(column, implicitly)
implicit lazy val arrayToStatement: ToStatement[Array[ShortText]] = ToStatement.arrayToParameter(ParameterMetaData.StringParameterMetaData).contramap(_.map(_.value))
implicit lazy val bijection: Bijection[ShortText, String] = Bijection[ShortText, String](_.value)(ShortText.apply)
implicit lazy val column: Column[ShortText] = Column.columnToString.map(ShortText.apply)
implicit lazy val ordering: Ordering[ShortText] = Ordering.by(_.value)
implicit lazy val parameterMetadata: ParameterMetaData[ShortText] = new ParameterMetaData[ShortText] {
override def sqlType: String = ParameterMetaData.StringParameterMetaData.sqlType
override def jdbcType: Int = ParameterMetaData.StringParameterMetaData.jdbcType
}
implicit lazy val reads: Reads[ShortText] = Reads.StringReads.map(ShortText.apply)
implicit lazy val text: Text[ShortText] = new Text[ShortText] {
override def unsafeEncode(v: ShortText, sb: StringBuilder) = Text.stringInstance.unsafeEncode(v.value, sb)
override def unsafeArrayEncode(v: ShortText, sb: StringBuilder) = Text.stringInstance.unsafeArrayEncode(v.value, sb)
}
implicit lazy val toStatement: ToStatement[ShortText] = ToStatement.stringToStatement.contramap(_.value)
implicit lazy val writes: Writes[ShortText] = Writes.StringWrites.contramap(_.value)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/**
* File has been automatically generated by `typo`.
*
* IF YOU CHANGE THIS FILE YOUR CHANGES WILL BE OVERWRITTEN.
*/
package adventureworks
package public
package flaff

import adventureworks.public.ShortText
import typo.dsl.SqlExpr.FieldLikeNoHkt
import typo.dsl.SqlExpr.IdField
import typo.dsl.SqlExpr.OptField
import typo.dsl.Structure.Relation

trait FlaffFields[Row] {
val code: IdField[ShortText, Row]
val anotherCode: IdField[/* max 20 chars */ String, Row]
val someNumber: IdField[Int, Row]
val specifier: IdField[ShortText, Row]
val parentspecifier: OptField[ShortText, Row]
}

object FlaffFields {
val structure: Relation[FlaffFields, FlaffRow, FlaffRow] =
new Impl(None, identity, (_, x) => x)

private final class Impl[Row](val prefix: Option[String], val extract: Row => FlaffRow, val merge: (Row, FlaffRow) => Row)
extends Relation[FlaffFields, FlaffRow, Row] {

override val fields: FlaffFields[Row] = new FlaffFields[Row] {
override val code = new IdField[ShortText, Row](prefix, "code", None, Some("text"))(x => extract(x).code, (row, value) => merge(row, extract(row).copy(code = value)))
override val anotherCode = new IdField[/* max 20 chars */ String, Row](prefix, "another_code", None, None)(x => extract(x).anotherCode, (row, value) => merge(row, extract(row).copy(anotherCode = value)))
override val someNumber = new IdField[Int, Row](prefix, "some_number", None, Some("int4"))(x => extract(x).someNumber, (row, value) => merge(row, extract(row).copy(someNumber = value)))
override val specifier = new IdField[ShortText, Row](prefix, "specifier", None, Some("text"))(x => extract(x).specifier, (row, value) => merge(row, extract(row).copy(specifier = value)))
override val parentspecifier = new OptField[ShortText, Row](prefix, "parentspecifier", None, Some("text"))(x => extract(x).parentspecifier, (row, value) => merge(row, extract(row).copy(parentspecifier = value)))
}

override val columns: List[FieldLikeNoHkt[?, Row]] =
List[FieldLikeNoHkt[?, Row]](fields.code, fields.anotherCode, fields.someNumber, fields.specifier, fields.parentspecifier)

override def copy[NewRow](prefix: Option[String], extract: NewRow => FlaffRow, merge: (NewRow, FlaffRow) => NewRow): Impl[NewRow] =
new Impl(prefix, extract, merge)
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/**
* File has been automatically generated by `typo`.
*
* IF YOU CHANGE THIS FILE YOUR CHANGES WILL BE OVERWRITTEN.
*/
package adventureworks
package public
package flaff

import adventureworks.public.ShortText
import play.api.libs.json.JsObject
import play.api.libs.json.JsResult
import play.api.libs.json.JsValue
import play.api.libs.json.OWrites
import play.api.libs.json.Reads
import play.api.libs.json.Writes
import scala.collection.immutable.ListMap
import scala.util.Try

/** Type for the composite primary key of table `public.flaff` */
case class FlaffId(code: ShortText, anotherCode: /* max 20 chars */ String, someNumber: Int, specifier: ShortText)
object FlaffId {
implicit lazy val ordering: Ordering[FlaffId] = Ordering.by(x => (x.code, x.anotherCode, x.someNumber, x.specifier))
implicit lazy val reads: Reads[FlaffId] = Reads[FlaffId](json => JsResult.fromTry(
Try(
FlaffId(
code = json.\("code").as(ShortText.reads),
anotherCode = json.\("another_code").as(Reads.StringReads),
someNumber = json.\("some_number").as(Reads.IntReads),
specifier = json.\("specifier").as(ShortText.reads)
)
)
),
)
implicit lazy val writes: OWrites[FlaffId] = OWrites[FlaffId](o =>
new JsObject(ListMap[String, JsValue](
"code" -> ShortText.writes.writes(o.code),
"another_code" -> Writes.StringWrites.writes(o.anotherCode),
"some_number" -> Writes.IntWrites.writes(o.someNumber),
"specifier" -> ShortText.writes.writes(o.specifier)
))
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/**
* File has been automatically generated by `typo`.
*
* IF YOU CHANGE THIS FILE YOUR CHANGES WILL BE OVERWRITTEN.
*/
package adventureworks
package public
package flaff

import java.sql.Connection
import typo.dsl.DeleteBuilder
import typo.dsl.SelectBuilder
import typo.dsl.UpdateBuilder

trait FlaffRepo {
def delete(compositeId: FlaffId)(implicit c: Connection): Boolean
def delete: DeleteBuilder[FlaffFields, FlaffRow]
def insert(unsaved: FlaffRow)(implicit c: Connection): FlaffRow
def insertStreaming(unsaved: Iterator[FlaffRow], batchSize: Int)(implicit c: Connection): Long
def select: SelectBuilder[FlaffFields, FlaffRow]
def selectAll(implicit c: Connection): List[FlaffRow]
def selectById(compositeId: FlaffId)(implicit c: Connection): Option[FlaffRow]
def update(row: FlaffRow)(implicit c: Connection): Boolean
def update: UpdateBuilder[FlaffFields, FlaffRow]
def upsert(unsaved: FlaffRow)(implicit c: Connection): FlaffRow
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/**
* File has been automatically generated by `typo`.
*
* IF YOU CHANGE THIS FILE YOUR CHANGES WILL BE OVERWRITTEN.
*/
package adventureworks
package public
package flaff

import adventureworks.public.ShortText
import adventureworks.streamingInsert
import anorm.ParameterValue
import anorm.SqlStringInterpolation
import anorm.ToStatement
import java.sql.Connection
import typo.dsl.DeleteBuilder
import typo.dsl.SelectBuilder
import typo.dsl.SelectBuilderSql
import typo.dsl.UpdateBuilder

class FlaffRepoImpl extends FlaffRepo {
override def delete(compositeId: FlaffId)(implicit c: Connection): Boolean = {
SQL"""delete from public.flaff where "code" = ${ParameterValue(compositeId.code, null, ShortText.toStatement)} AND "another_code" = ${ParameterValue(compositeId.anotherCode, null, ToStatement.stringToStatement)} AND "some_number" = ${ParameterValue(compositeId.someNumber, null, ToStatement.intToStatement)} AND "specifier" = ${ParameterValue(compositeId.specifier, null, ShortText.toStatement)}""".executeUpdate() > 0
}
override def delete: DeleteBuilder[FlaffFields, FlaffRow] = {
DeleteBuilder("public.flaff", FlaffFields.structure)
}
override def insert(unsaved: FlaffRow)(implicit c: Connection): FlaffRow = {
SQL"""insert into public.flaff("code", "another_code", "some_number", "specifier", "parentspecifier")
values (${ParameterValue(unsaved.code, null, ShortText.toStatement)}::text, ${ParameterValue(unsaved.anotherCode, null, ToStatement.stringToStatement)}, ${ParameterValue(unsaved.someNumber, null, ToStatement.intToStatement)}::int4, ${ParameterValue(unsaved.specifier, null, ShortText.toStatement)}::text, ${ParameterValue(unsaved.parentspecifier, null, ToStatement.optionToStatement(ShortText.toStatement, ShortText.parameterMetadata))}::text)
returning "code", "another_code", "some_number", "specifier", "parentspecifier"
"""
.executeInsert(FlaffRow.rowParser(1).single)

}
override def insertStreaming(unsaved: Iterator[FlaffRow], batchSize: Int)(implicit c: Connection): Long = {
streamingInsert(s"""COPY public.flaff("code", "another_code", "some_number", "specifier", "parentspecifier") FROM STDIN""", batchSize, unsaved)(FlaffRow.text, c)
}
override def select: SelectBuilder[FlaffFields, FlaffRow] = {
SelectBuilderSql("public.flaff", FlaffFields.structure, FlaffRow.rowParser)
}
override def selectAll(implicit c: Connection): List[FlaffRow] = {
SQL"""select "code", "another_code", "some_number", "specifier", "parentspecifier"
from public.flaff
""".as(FlaffRow.rowParser(1).*)
}
override def selectById(compositeId: FlaffId)(implicit c: Connection): Option[FlaffRow] = {
SQL"""select "code", "another_code", "some_number", "specifier", "parentspecifier"
from public.flaff
where "code" = ${ParameterValue(compositeId.code, null, ShortText.toStatement)} AND "another_code" = ${ParameterValue(compositeId.anotherCode, null, ToStatement.stringToStatement)} AND "some_number" = ${ParameterValue(compositeId.someNumber, null, ToStatement.intToStatement)} AND "specifier" = ${ParameterValue(compositeId.specifier, null, ShortText.toStatement)}
""".as(FlaffRow.rowParser(1).singleOpt)
}
override def update(row: FlaffRow)(implicit c: Connection): Boolean = {
val compositeId = row.compositeId
SQL"""update public.flaff
set "parentspecifier" = ${ParameterValue(row.parentspecifier, null, ToStatement.optionToStatement(ShortText.toStatement, ShortText.parameterMetadata))}::text
where "code" = ${ParameterValue(compositeId.code, null, ShortText.toStatement)} AND "another_code" = ${ParameterValue(compositeId.anotherCode, null, ToStatement.stringToStatement)} AND "some_number" = ${ParameterValue(compositeId.someNumber, null, ToStatement.intToStatement)} AND "specifier" = ${ParameterValue(compositeId.specifier, null, ShortText.toStatement)}
""".executeUpdate() > 0
}
override def update: UpdateBuilder[FlaffFields, FlaffRow] = {
UpdateBuilder("public.flaff", FlaffFields.structure, FlaffRow.rowParser)
}
override def upsert(unsaved: FlaffRow)(implicit c: Connection): FlaffRow = {
SQL"""insert into public.flaff("code", "another_code", "some_number", "specifier", "parentspecifier")
values (
${ParameterValue(unsaved.code, null, ShortText.toStatement)}::text,
${ParameterValue(unsaved.anotherCode, null, ToStatement.stringToStatement)},
${ParameterValue(unsaved.someNumber, null, ToStatement.intToStatement)}::int4,
${ParameterValue(unsaved.specifier, null, ShortText.toStatement)}::text,
${ParameterValue(unsaved.parentspecifier, null, ToStatement.optionToStatement(ShortText.toStatement, ShortText.parameterMetadata))}::text
)
on conflict ("code", "another_code", "some_number", "specifier")
do update set
"parentspecifier" = EXCLUDED."parentspecifier"
returning "code", "another_code", "some_number", "specifier", "parentspecifier"
"""
.executeInsert(FlaffRow.rowParser(1).single)

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/**
* File has been automatically generated by `typo`.
*
* IF YOU CHANGE THIS FILE YOUR CHANGES WILL BE OVERWRITTEN.
*/
package adventureworks
package public
package flaff

import java.sql.Connection
import scala.annotation.nowarn
import typo.dsl.DeleteBuilder
import typo.dsl.DeleteBuilder.DeleteBuilderMock
import typo.dsl.DeleteParams
import typo.dsl.SelectBuilder
import typo.dsl.SelectBuilderMock
import typo.dsl.SelectParams
import typo.dsl.UpdateBuilder
import typo.dsl.UpdateBuilder.UpdateBuilderMock
import typo.dsl.UpdateParams

class FlaffRepoMock(map: scala.collection.mutable.Map[FlaffId, FlaffRow] = scala.collection.mutable.Map.empty) extends FlaffRepo {
override def delete(compositeId: FlaffId)(implicit c: Connection): Boolean = {
map.remove(compositeId).isDefined
}
override def delete: DeleteBuilder[FlaffFields, FlaffRow] = {
DeleteBuilderMock(DeleteParams.empty, FlaffFields.structure.fields, map)
}
override def insert(unsaved: FlaffRow)(implicit c: Connection): FlaffRow = {
val _ = if (map.contains(unsaved.compositeId))
sys.error(s"id ${unsaved.compositeId} already exists")
else
map.put(unsaved.compositeId, unsaved)

unsaved
}
override def insertStreaming(unsaved: Iterator[FlaffRow], batchSize: Int)(implicit c: Connection): Long = {
unsaved.foreach { row =>
map += (row.compositeId -> row)
}
unsaved.size.toLong
}
override def select: SelectBuilder[FlaffFields, FlaffRow] = {
SelectBuilderMock(FlaffFields.structure, () => map.values.toList, SelectParams.empty)
}
override def selectAll(implicit c: Connection): List[FlaffRow] = {
map.values.toList
}
override def selectById(compositeId: FlaffId)(implicit c: Connection): Option[FlaffRow] = {
map.get(compositeId)
}
override def update(row: FlaffRow)(implicit c: Connection): Boolean = {
map.get(row.compositeId) match {
case Some(`row`) => false
case Some(_) =>
map.put(row.compositeId, row): @nowarn
true
case None => false
}
}
override def update: UpdateBuilder[FlaffFields, FlaffRow] = {
UpdateBuilderMock(UpdateParams.empty, FlaffFields.structure.fields, map)
}
override def upsert(unsaved: FlaffRow)(implicit c: Connection): FlaffRow = {
map.put(unsaved.compositeId, unsaved): @nowarn
unsaved
}
}
Loading
Loading