diff --git a/init/data/test-tables.sql b/init/data/test-tables.sql index 4ed763979..ecdf073a7 100644 --- a/init/data/test-tables.sql +++ b/init/data/test-tables.sql @@ -253,4 +253,23 @@ create table "table-with-generated-columns" WHEN name = 'a' THEN 'a-name' ELSE 'some-name' END) STORED -) \ No newline at end of file +); + + +CREATE TABLE issue142 +( + tabellkode TEXT NOT NULL , + CONSTRAINT tabell_pk PRIMARY KEY (tabellkode) +); + +CREATE TABLE issue142_2 +( + tabellkode TEXT NOT NULL, + CONSTRAINT tabell2_pk PRIMARY KEY (tabellkode), + CONSTRAINT tabell2_tabell_fk FOREIGN KEY (tabellkode) REFERENCES issue142 (tabellkode) +); + +INSERT INTO issue142 (tabellkode) +VALUES ('aa'), + ('bb') +; diff --git a/typo-scripts/src/scala/scripts/GeneratedAdventureWorks.scala b/typo-scripts/src/scala/scripts/GeneratedAdventureWorks.scala index ae5a7dfe4..0c66b6252 100644 --- a/typo-scripts/src/scala/scripts/GeneratedAdventureWorks.scala +++ b/typo-scripts/src/scala/scripts/GeneratedAdventureWorks.scala @@ -30,12 +30,13 @@ object GeneratedAdventureWorks { val selector = Selector.ExcludePostgresInternal val typoLogger = TypoLogger.Console val metadb = Await.result(MetaDb.fromDb(typoLogger, ds, selector, schemaMode = SchemaMode.MultiSchema), Duration.Inf) + val openEnumSelector = Selector.relationNames("title", "title_domain", "issue142") val relationNameToOpenEnum = Await.result( OpenEnum.find( ds, typoLogger, Selector.All, - openEnumSelector = Selector.relationNames("title", "title_domain"), + openEnumSelector = openEnumSelector, metaDb = metadb ), Duration.Inf @@ -58,7 +59,7 @@ object GeneratedAdventureWorks { case (_, "firstname") => "adventureworks.userdefined.FirstName" case ("sales.creditcard", "creditcardid") => "adventureworks.userdefined.CustomCreditcardId" }, - openEnums = Selector.relationNames("title", "title_domain"), + openEnums = openEnumSelector, generateMockRepos = !Selector.relationNames("purchaseorderdetail"), enablePrimaryKeyType = !Selector.relationNames("billofmaterials"), enableTestInserts = Selector.All, diff --git a/typo-tester-anorm/generated-and-checked-in/adventureworks/public/issue142/Issue142Fields.scala b/typo-tester-anorm/generated-and-checked-in/adventureworks/public/issue142/Issue142Fields.scala new file mode 100644 index 000000000..58be7bed0 --- /dev/null +++ b/typo-tester-anorm/generated-and-checked-in/adventureworks/public/issue142/Issue142Fields.scala @@ -0,0 +1,37 @@ +/** + * File has been automatically generated by `typo`. + * + * IF YOU CHANGE THIS FILE YOUR CHANGES WILL BE OVERWRITTEN. + */ +package adventureworks +package public +package issue142 + +import typo.dsl.Path +import typo.dsl.SqlExpr.FieldLikeNoHkt +import typo.dsl.SqlExpr.IdField +import typo.dsl.Structure.Relation + +trait Issue142Fields { + def tabellkode: IdField[Issue142Id, Issue142Row] +} + +object Issue142Fields { + lazy val structure: Relation[Issue142Fields, Issue142Row] = + new Impl(Nil) + + private final class Impl(val _path: List[Path]) + extends Relation[Issue142Fields, Issue142Row] { + + override lazy val fields: Issue142Fields = new Issue142Fields { + override def tabellkode = IdField[Issue142Id, Issue142Row](_path, "tabellkode", None, None, x => x.tabellkode, (row, value) => row.copy(tabellkode = value)) + } + + override lazy val columns: List[FieldLikeNoHkt[?, Issue142Row]] = + List[FieldLikeNoHkt[?, Issue142Row]](fields.tabellkode) + + override def copy(path: List[Path]): Impl = + new Impl(path) + } + +} diff --git a/typo-tester-anorm/generated-and-checked-in/adventureworks/public/issue142/Issue142Id.scala b/typo-tester-anorm/generated-and-checked-in/adventureworks/public/issue142/Issue142Id.scala new file mode 100644 index 000000000..c486a4436 --- /dev/null +++ b/typo-tester-anorm/generated-and-checked-in/adventureworks/public/issue142/Issue142Id.scala @@ -0,0 +1,48 @@ +/** + * File has been automatically generated by `typo`. + * + * IF YOU CHANGE THIS FILE YOUR CHANGES WILL BE OVERWRITTEN. + */ +package adventureworks +package public +package issue142 + +import anorm.Column +import anorm.ParameterMetaData +import anorm.ToStatement +import java.sql.Types +import play.api.libs.json.JsValue +import play.api.libs.json.Reads +import play.api.libs.json.Writes + +/** Type for the primary key of table `public.issue142`. It has some known values: + * - aa + * - bb + */ +sealed abstract class Issue142Id(val value: String) + +object Issue142Id { + def apply(underlying: String): Issue142Id = + ByName.getOrElse(underlying, Unknown(underlying)) + case object aa extends Issue142Id("aa") + case object bb extends Issue142Id("bb") + case class Unknown(override val value: String) extends Issue142Id(value) + val All: List[Issue142Id] = List(aa, bb) + val ByName: Map[String, Issue142Id] = All.map(x => (x.value, x)).toMap + + implicit lazy val arrayColumn: Column[Array[Issue142Id]] = Column.columnToArray[String](Column.columnToString, implicitly).map(_.map(Issue142Id.apply)) + implicit lazy val arrayToStatement: ToStatement[Array[Issue142Id]] = ToStatement.arrayToParameter(ParameterMetaData.StringParameterMetaData).contramap(_.map(_.value)) + implicit lazy val column: Column[Issue142Id] = Column.columnToString.map(Issue142Id.apply) + implicit lazy val ordering: Ordering[Issue142Id] = Ordering.by(_.value) + implicit lazy val parameterMetadata: ParameterMetaData[Issue142Id] = new ParameterMetaData[Issue142Id] { + override def sqlType: String = "text" + override def jdbcType: Int = Types.OTHER + } + implicit lazy val reads: Reads[Issue142Id] = Reads[Issue142Id]{(value: JsValue) => value.validate(Reads.StringReads).map(Issue142Id.apply)} + implicit lazy val text: Text[Issue142Id] = new Text[Issue142Id] { + override def unsafeEncode(v: Issue142Id, sb: StringBuilder) = Text.stringInstance.unsafeEncode(v.value, sb) + override def unsafeArrayEncode(v: Issue142Id, sb: StringBuilder) = Text.stringInstance.unsafeArrayEncode(v.value, sb) + } + implicit lazy val toStatement: ToStatement[Issue142Id] = ToStatement.stringToStatement.contramap(_.value) + implicit lazy val writes: Writes[Issue142Id] = Writes[Issue142Id](value => Writes.StringWrites.writes(value.value)) +} diff --git a/typo-tester-anorm/generated-and-checked-in/adventureworks/public/issue142/Issue142Repo.scala b/typo-tester-anorm/generated-and-checked-in/adventureworks/public/issue142/Issue142Repo.scala new file mode 100644 index 000000000..27d2ef4b4 --- /dev/null +++ b/typo-tester-anorm/generated-and-checked-in/adventureworks/public/issue142/Issue142Repo.scala @@ -0,0 +1,31 @@ +/** + * File has been automatically generated by `typo`. + * + * IF YOU CHANGE THIS FILE YOUR CHANGES WILL BE OVERWRITTEN. + */ +package adventureworks +package public +package issue142 + +import java.sql.Connection +import typo.dsl.DeleteBuilder +import typo.dsl.SelectBuilder +import typo.dsl.UpdateBuilder + +trait Issue142Repo { + def delete: DeleteBuilder[Issue142Fields, Issue142Row] + def deleteById(tabellkode: Issue142Id)(implicit c: Connection): Boolean + def deleteByIds(tabellkodes: Array[Issue142Id])(implicit c: Connection): Int + def insert(unsaved: Issue142Row)(implicit c: Connection): Issue142Row + def insertStreaming(unsaved: Iterator[Issue142Row], batchSize: Int = 10000)(implicit c: Connection): Long + def select: SelectBuilder[Issue142Fields, Issue142Row] + def selectAll(implicit c: Connection): List[Issue142Row] + def selectById(tabellkode: Issue142Id)(implicit c: Connection): Option[Issue142Row] + def selectByIds(tabellkodes: Array[Issue142Id])(implicit c: Connection): List[Issue142Row] + def selectByIdsTracked(tabellkodes: Array[Issue142Id])(implicit c: Connection): Map[Issue142Id, Issue142Row] + def update: UpdateBuilder[Issue142Fields, Issue142Row] + def upsert(unsaved: Issue142Row)(implicit c: Connection): Issue142Row + def upsertBatch(unsaved: Iterable[Issue142Row])(implicit c: Connection): List[Issue142Row] + /* NOTE: this functionality is not safe if you use auto-commit mode! it runs 3 SQL statements */ + def upsertStreaming(unsaved: Iterator[Issue142Row], batchSize: Int = 10000)(implicit c: Connection): Int +} diff --git a/typo-tester-anorm/generated-and-checked-in/adventureworks/public/issue142/Issue142RepoImpl.scala b/typo-tester-anorm/generated-and-checked-in/adventureworks/public/issue142/Issue142RepoImpl.scala new file mode 100644 index 000000000..9ea04cec6 --- /dev/null +++ b/typo-tester-anorm/generated-and-checked-in/adventureworks/public/issue142/Issue142RepoImpl.scala @@ -0,0 +1,118 @@ +/** + * File has been automatically generated by `typo`. + * + * IF YOU CHANGE THIS FILE YOUR CHANGES WILL BE OVERWRITTEN. + */ +package adventureworks +package public +package issue142 + +import anorm.BatchSql +import anorm.NamedParameter +import anorm.ParameterValue +import anorm.SqlStringInterpolation +import java.sql.Connection +import scala.annotation.nowarn +import typo.dsl.DeleteBuilder +import typo.dsl.SelectBuilder +import typo.dsl.SelectBuilderSql +import typo.dsl.UpdateBuilder + +class Issue142RepoImpl extends Issue142Repo { + override def delete: DeleteBuilder[Issue142Fields, Issue142Row] = { + DeleteBuilder(""""public"."issue142"""", Issue142Fields.structure) + } + override def deleteById(tabellkode: Issue142Id)(implicit c: Connection): Boolean = { + SQL"""delete from "public"."issue142" where "tabellkode" = ${ParameterValue(tabellkode, null, Issue142Id.toStatement)}""".executeUpdate() > 0 + } + override def deleteByIds(tabellkodes: Array[Issue142Id])(implicit c: Connection): Int = { + SQL"""delete + from "public"."issue142" + where "tabellkode" = ANY(${tabellkodes}) + """.executeUpdate() + + } + override def insert(unsaved: Issue142Row)(implicit c: Connection): Issue142Row = { + SQL"""insert into "public"."issue142"("tabellkode") + values (${ParameterValue(unsaved.tabellkode, null, Issue142Id.toStatement)}) + returning "tabellkode" + """ + .executeInsert(Issue142Row.rowParser(1).single) + + } + override def insertStreaming(unsaved: Iterator[Issue142Row], batchSize: Int = 10000)(implicit c: Connection): Long = { + streamingInsert(s"""COPY "public"."issue142"("tabellkode") FROM STDIN""", batchSize, unsaved)(Issue142Row.text, c) + } + override def select: SelectBuilder[Issue142Fields, Issue142Row] = { + SelectBuilderSql(""""public"."issue142"""", Issue142Fields.structure, Issue142Row.rowParser) + } + override def selectAll(implicit c: Connection): List[Issue142Row] = { + SQL"""select "tabellkode" + from "public"."issue142" + """.as(Issue142Row.rowParser(1).*) + } + override def selectById(tabellkode: Issue142Id)(implicit c: Connection): Option[Issue142Row] = { + SQL"""select "tabellkode" + from "public"."issue142" + where "tabellkode" = ${ParameterValue(tabellkode, null, Issue142Id.toStatement)} + """.as(Issue142Row.rowParser(1).singleOpt) + } + override def selectByIds(tabellkodes: Array[Issue142Id])(implicit c: Connection): List[Issue142Row] = { + SQL"""select "tabellkode" + from "public"."issue142" + where "tabellkode" = ANY(${tabellkodes}) + """.as(Issue142Row.rowParser(1).*) + + } + override def selectByIdsTracked(tabellkodes: Array[Issue142Id])(implicit c: Connection): Map[Issue142Id, Issue142Row] = { + val byId = selectByIds(tabellkodes).view.map(x => (x.tabellkode, x)).toMap + tabellkodes.view.flatMap(id => byId.get(id).map(x => (id, x))).toMap + } + override def update: UpdateBuilder[Issue142Fields, Issue142Row] = { + UpdateBuilder(""""public"."issue142"""", Issue142Fields.structure, Issue142Row.rowParser) + } + override def upsert(unsaved: Issue142Row)(implicit c: Connection): Issue142Row = { + SQL"""insert into "public"."issue142"("tabellkode") + values ( + ${ParameterValue(unsaved.tabellkode, null, Issue142Id.toStatement)} + ) + on conflict ("tabellkode") + do nothing + returning "tabellkode" + """ + .executeInsert(Issue142Row.rowParser(1).single) + + } + override def upsertBatch(unsaved: Iterable[Issue142Row])(implicit c: Connection): List[Issue142Row] = { + def toNamedParameter(row: Issue142Row): List[NamedParameter] = List( + NamedParameter("tabellkode", ParameterValue(row.tabellkode, null, Issue142Id.toStatement)) + ) + unsaved.toList match { + case Nil => Nil + case head :: rest => + new anorm.adventureworks.ExecuteReturningSyntax.Ops( + BatchSql( + s"""insert into "public"."issue142"("tabellkode") + values ({tabellkode}) + on conflict ("tabellkode") + do nothing + returning "tabellkode" + """, + toNamedParameter(head), + rest.map(toNamedParameter)* + ) + ).executeReturning(Issue142Row.rowParser(1).*) + } + } + /* NOTE: this functionality is not safe if you use auto-commit mode! it runs 3 SQL statements */ + override def upsertStreaming(unsaved: Iterator[Issue142Row], batchSize: Int = 10000)(implicit c: Connection): Int = { + SQL"""create temporary table issue142_TEMP (like "public"."issue142") on commit drop""".execute(): @nowarn + streamingInsert(s"""copy issue142_TEMP("tabellkode") from stdin""", batchSize, unsaved)(Issue142Row.text, c): @nowarn + SQL"""insert into "public"."issue142"("tabellkode") + select * from issue142_TEMP + on conflict ("tabellkode") + do nothing + ; + drop table issue142_TEMP;""".executeUpdate() + } +} diff --git a/typo-tester-anorm/generated-and-checked-in/adventureworks/public/issue142/Issue142RepoMock.scala b/typo-tester-anorm/generated-and-checked-in/adventureworks/public/issue142/Issue142RepoMock.scala new file mode 100644 index 000000000..d4befe005 --- /dev/null +++ b/typo-tester-anorm/generated-and-checked-in/adventureworks/public/issue142/Issue142RepoMock.scala @@ -0,0 +1,82 @@ +/** + * File has been automatically generated by `typo`. + * + * IF YOU CHANGE THIS FILE YOUR CHANGES WILL BE OVERWRITTEN. + */ +package adventureworks +package public +package issue142 + +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 Issue142RepoMock(map: scala.collection.mutable.Map[Issue142Id, Issue142Row] = scala.collection.mutable.Map.empty) extends Issue142Repo { + override def delete: DeleteBuilder[Issue142Fields, Issue142Row] = { + DeleteBuilderMock(DeleteParams.empty, Issue142Fields.structure, map) + } + override def deleteById(tabellkode: Issue142Id)(implicit c: Connection): Boolean = { + map.remove(tabellkode).isDefined + } + override def deleteByIds(tabellkodes: Array[Issue142Id])(implicit c: Connection): Int = { + tabellkodes.map(id => map.remove(id)).count(_.isDefined) + } + override def insert(unsaved: Issue142Row)(implicit c: Connection): Issue142Row = { + val _ = if (map.contains(unsaved.tabellkode)) + sys.error(s"id ${unsaved.tabellkode} already exists") + else + map.put(unsaved.tabellkode, unsaved) + + unsaved + } + override def insertStreaming(unsaved: Iterator[Issue142Row], batchSize: Int = 10000)(implicit c: Connection): Long = { + unsaved.foreach { row => + map += (row.tabellkode -> row) + } + unsaved.size.toLong + } + override def select: SelectBuilder[Issue142Fields, Issue142Row] = { + SelectBuilderMock(Issue142Fields.structure, () => map.values.toList, SelectParams.empty) + } + override def selectAll(implicit c: Connection): List[Issue142Row] = { + map.values.toList + } + override def selectById(tabellkode: Issue142Id)(implicit c: Connection): Option[Issue142Row] = { + map.get(tabellkode) + } + override def selectByIds(tabellkodes: Array[Issue142Id])(implicit c: Connection): List[Issue142Row] = { + tabellkodes.flatMap(map.get).toList + } + override def selectByIdsTracked(tabellkodes: Array[Issue142Id])(implicit c: Connection): Map[Issue142Id, Issue142Row] = { + val byId = selectByIds(tabellkodes).view.map(x => (x.tabellkode, x)).toMap + tabellkodes.view.flatMap(id => byId.get(id).map(x => (id, x))).toMap + } + override def update: UpdateBuilder[Issue142Fields, Issue142Row] = { + UpdateBuilderMock(UpdateParams.empty, Issue142Fields.structure, map) + } + override def upsert(unsaved: Issue142Row)(implicit c: Connection): Issue142Row = { + map.put(unsaved.tabellkode, unsaved): @nowarn + unsaved + } + override def upsertBatch(unsaved: Iterable[Issue142Row])(implicit c: Connection): List[Issue142Row] = { + unsaved.map { row => + map += (row.tabellkode -> row) + row + }.toList + } + /* NOTE: this functionality is not safe if you use auto-commit mode! it runs 3 SQL statements */ + override def upsertStreaming(unsaved: Iterator[Issue142Row], batchSize: Int = 10000)(implicit c: Connection): Int = { + unsaved.foreach { row => + map += (row.tabellkode -> row) + } + unsaved.size + } +} diff --git a/typo-tester-anorm/generated-and-checked-in/adventureworks/public/issue142/Issue142Row.scala b/typo-tester-anorm/generated-and-checked-in/adventureworks/public/issue142/Issue142Row.scala new file mode 100644 index 000000000..0d0f58bd9 --- /dev/null +++ b/typo-tester-anorm/generated-and-checked-in/adventureworks/public/issue142/Issue142Row.scala @@ -0,0 +1,52 @@ +/** + * File has been automatically generated by `typo`. + * + * IF YOU CHANGE THIS FILE YOUR CHANGES WILL BE OVERWRITTEN. + */ +package adventureworks +package public +package issue142 + +import anorm.RowParser +import anorm.Success +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 scala.collection.immutable.ListMap +import scala.util.Try + +/** Table: public.issue142 + Primary key: tabellkode */ +case class Issue142Row( + tabellkode: Issue142Id +){ + val id = tabellkode + } + +object Issue142Row { + implicit lazy val reads: Reads[Issue142Row] = Reads[Issue142Row](json => JsResult.fromTry( + Try( + Issue142Row( + tabellkode = json.\("tabellkode").as(Issue142Id.reads) + ) + ) + ), + ) + def rowParser(idx: Int): RowParser[Issue142Row] = RowParser[Issue142Row] { row => + Success( + Issue142Row( + tabellkode = row(idx + 0)(Issue142Id.column) + ) + ) + } + implicit lazy val text: Text[Issue142Row] = Text.instance[Issue142Row]{ (row, sb) => + Issue142Id.text.unsafeEncode(row.tabellkode, sb) + } + implicit lazy val writes: OWrites[Issue142Row] = OWrites[Issue142Row](o => + new JsObject(ListMap[String, JsValue]( + "tabellkode" -> Issue142Id.writes.writes(o.tabellkode) + )) + ) +} diff --git a/typo-tester-anorm/generated-and-checked-in/adventureworks/public/issue142_2/Issue1422Fields.scala b/typo-tester-anorm/generated-and-checked-in/adventureworks/public/issue142_2/Issue1422Fields.scala new file mode 100644 index 000000000..59f3f3ce5 --- /dev/null +++ b/typo-tester-anorm/generated-and-checked-in/adventureworks/public/issue142_2/Issue1422Fields.scala @@ -0,0 +1,44 @@ +/** + * File has been automatically generated by `typo`. + * + * IF YOU CHANGE THIS FILE YOUR CHANGES WILL BE OVERWRITTEN. + */ +package adventureworks +package public +package issue142_2 + +import adventureworks.public.issue142.Issue142Fields +import adventureworks.public.issue142.Issue142Id +import adventureworks.public.issue142.Issue142Row +import typo.dsl.ForeignKey +import typo.dsl.Path +import typo.dsl.SqlExpr.FieldLikeNoHkt +import typo.dsl.SqlExpr.IdField +import typo.dsl.Structure.Relation + +trait Issue1422Fields { + def tabellkode: IdField[Issue142Id, Issue1422Row] + def fkIssue142: ForeignKey[Issue142Fields, Issue142Row] = + ForeignKey[Issue142Fields, Issue142Row]("public.tabell2_tabell_fk", Nil) + .withColumnPair(tabellkode, _.tabellkode) +} + +object Issue1422Fields { + lazy val structure: Relation[Issue1422Fields, Issue1422Row] = + new Impl(Nil) + + private final class Impl(val _path: List[Path]) + extends Relation[Issue1422Fields, Issue1422Row] { + + override lazy val fields: Issue1422Fields = new Issue1422Fields { + override def tabellkode = IdField[Issue142Id, Issue1422Row](_path, "tabellkode", None, None, x => x.tabellkode, (row, value) => row.copy(tabellkode = value)) + } + + override lazy val columns: List[FieldLikeNoHkt[?, Issue1422Row]] = + List[FieldLikeNoHkt[?, Issue1422Row]](fields.tabellkode) + + override def copy(path: List[Path]): Impl = + new Impl(path) + } + +} diff --git a/typo-tester-anorm/generated-and-checked-in/adventureworks/public/issue142_2/Issue1422Repo.scala b/typo-tester-anorm/generated-and-checked-in/adventureworks/public/issue142_2/Issue1422Repo.scala new file mode 100644 index 000000000..b77f7b39e --- /dev/null +++ b/typo-tester-anorm/generated-and-checked-in/adventureworks/public/issue142_2/Issue1422Repo.scala @@ -0,0 +1,32 @@ +/** + * File has been automatically generated by `typo`. + * + * IF YOU CHANGE THIS FILE YOUR CHANGES WILL BE OVERWRITTEN. + */ +package adventureworks +package public +package issue142_2 + +import adventureworks.public.issue142.Issue142Id +import java.sql.Connection +import typo.dsl.DeleteBuilder +import typo.dsl.SelectBuilder +import typo.dsl.UpdateBuilder + +trait Issue1422Repo { + def delete: DeleteBuilder[Issue1422Fields, Issue1422Row] + def deleteById(tabellkode: Issue142Id)(implicit c: Connection): Boolean + def deleteByIds(tabellkodes: Array[Issue142Id])(implicit c: Connection): Int + def insert(unsaved: Issue1422Row)(implicit c: Connection): Issue1422Row + def insertStreaming(unsaved: Iterator[Issue1422Row], batchSize: Int = 10000)(implicit c: Connection): Long + def select: SelectBuilder[Issue1422Fields, Issue1422Row] + def selectAll(implicit c: Connection): List[Issue1422Row] + def selectById(tabellkode: Issue142Id)(implicit c: Connection): Option[Issue1422Row] + def selectByIds(tabellkodes: Array[Issue142Id])(implicit c: Connection): List[Issue1422Row] + def selectByIdsTracked(tabellkodes: Array[Issue142Id])(implicit c: Connection): Map[Issue142Id, Issue1422Row] + def update: UpdateBuilder[Issue1422Fields, Issue1422Row] + def upsert(unsaved: Issue1422Row)(implicit c: Connection): Issue1422Row + def upsertBatch(unsaved: Iterable[Issue1422Row])(implicit c: Connection): List[Issue1422Row] + /* NOTE: this functionality is not safe if you use auto-commit mode! it runs 3 SQL statements */ + def upsertStreaming(unsaved: Iterator[Issue1422Row], batchSize: Int = 10000)(implicit c: Connection): Int +} diff --git a/typo-tester-anorm/generated-and-checked-in/adventureworks/public/issue142_2/Issue1422RepoImpl.scala b/typo-tester-anorm/generated-and-checked-in/adventureworks/public/issue142_2/Issue1422RepoImpl.scala new file mode 100644 index 000000000..dc5941c12 --- /dev/null +++ b/typo-tester-anorm/generated-and-checked-in/adventureworks/public/issue142_2/Issue1422RepoImpl.scala @@ -0,0 +1,119 @@ +/** + * File has been automatically generated by `typo`. + * + * IF YOU CHANGE THIS FILE YOUR CHANGES WILL BE OVERWRITTEN. + */ +package adventureworks +package public +package issue142_2 + +import adventureworks.public.issue142.Issue142Id +import anorm.BatchSql +import anorm.NamedParameter +import anorm.ParameterValue +import anorm.SqlStringInterpolation +import java.sql.Connection +import scala.annotation.nowarn +import typo.dsl.DeleteBuilder +import typo.dsl.SelectBuilder +import typo.dsl.SelectBuilderSql +import typo.dsl.UpdateBuilder + +class Issue1422RepoImpl extends Issue1422Repo { + override def delete: DeleteBuilder[Issue1422Fields, Issue1422Row] = { + DeleteBuilder(""""public"."issue142_2"""", Issue1422Fields.structure) + } + override def deleteById(tabellkode: Issue142Id)(implicit c: Connection): Boolean = { + SQL"""delete from "public"."issue142_2" where "tabellkode" = ${ParameterValue(tabellkode, null, Issue142Id.toStatement)}""".executeUpdate() > 0 + } + override def deleteByIds(tabellkodes: Array[Issue142Id])(implicit c: Connection): Int = { + SQL"""delete + from "public"."issue142_2" + where "tabellkode" = ANY(${tabellkodes}) + """.executeUpdate() + + } + override def insert(unsaved: Issue1422Row)(implicit c: Connection): Issue1422Row = { + SQL"""insert into "public"."issue142_2"("tabellkode") + values (${ParameterValue(unsaved.tabellkode, null, Issue142Id.toStatement)}) + returning "tabellkode" + """ + .executeInsert(Issue1422Row.rowParser(1).single) + + } + override def insertStreaming(unsaved: Iterator[Issue1422Row], batchSize: Int = 10000)(implicit c: Connection): Long = { + streamingInsert(s"""COPY "public"."issue142_2"("tabellkode") FROM STDIN""", batchSize, unsaved)(Issue1422Row.text, c) + } + override def select: SelectBuilder[Issue1422Fields, Issue1422Row] = { + SelectBuilderSql(""""public"."issue142_2"""", Issue1422Fields.structure, Issue1422Row.rowParser) + } + override def selectAll(implicit c: Connection): List[Issue1422Row] = { + SQL"""select "tabellkode" + from "public"."issue142_2" + """.as(Issue1422Row.rowParser(1).*) + } + override def selectById(tabellkode: Issue142Id)(implicit c: Connection): Option[Issue1422Row] = { + SQL"""select "tabellkode" + from "public"."issue142_2" + where "tabellkode" = ${ParameterValue(tabellkode, null, Issue142Id.toStatement)} + """.as(Issue1422Row.rowParser(1).singleOpt) + } + override def selectByIds(tabellkodes: Array[Issue142Id])(implicit c: Connection): List[Issue1422Row] = { + SQL"""select "tabellkode" + from "public"."issue142_2" + where "tabellkode" = ANY(${tabellkodes}) + """.as(Issue1422Row.rowParser(1).*) + + } + override def selectByIdsTracked(tabellkodes: Array[Issue142Id])(implicit c: Connection): Map[Issue142Id, Issue1422Row] = { + val byId = selectByIds(tabellkodes).view.map(x => (x.tabellkode, x)).toMap + tabellkodes.view.flatMap(id => byId.get(id).map(x => (id, x))).toMap + } + override def update: UpdateBuilder[Issue1422Fields, Issue1422Row] = { + UpdateBuilder(""""public"."issue142_2"""", Issue1422Fields.structure, Issue1422Row.rowParser) + } + override def upsert(unsaved: Issue1422Row)(implicit c: Connection): Issue1422Row = { + SQL"""insert into "public"."issue142_2"("tabellkode") + values ( + ${ParameterValue(unsaved.tabellkode, null, Issue142Id.toStatement)} + ) + on conflict ("tabellkode") + do nothing + returning "tabellkode" + """ + .executeInsert(Issue1422Row.rowParser(1).single) + + } + override def upsertBatch(unsaved: Iterable[Issue1422Row])(implicit c: Connection): List[Issue1422Row] = { + def toNamedParameter(row: Issue1422Row): List[NamedParameter] = List( + NamedParameter("tabellkode", ParameterValue(row.tabellkode, null, Issue142Id.toStatement)) + ) + unsaved.toList match { + case Nil => Nil + case head :: rest => + new anorm.adventureworks.ExecuteReturningSyntax.Ops( + BatchSql( + s"""insert into "public"."issue142_2"("tabellkode") + values ({tabellkode}) + on conflict ("tabellkode") + do nothing + returning "tabellkode" + """, + toNamedParameter(head), + rest.map(toNamedParameter)* + ) + ).executeReturning(Issue1422Row.rowParser(1).*) + } + } + /* NOTE: this functionality is not safe if you use auto-commit mode! it runs 3 SQL statements */ + override def upsertStreaming(unsaved: Iterator[Issue1422Row], batchSize: Int = 10000)(implicit c: Connection): Int = { + SQL"""create temporary table issue142_2_TEMP (like "public"."issue142_2") on commit drop""".execute(): @nowarn + streamingInsert(s"""copy issue142_2_TEMP("tabellkode") from stdin""", batchSize, unsaved)(Issue1422Row.text, c): @nowarn + SQL"""insert into "public"."issue142_2"("tabellkode") + select * from issue142_2_TEMP + on conflict ("tabellkode") + do nothing + ; + drop table issue142_2_TEMP;""".executeUpdate() + } +} diff --git a/typo-tester-anorm/generated-and-checked-in/adventureworks/public/issue142_2/Issue1422RepoMock.scala b/typo-tester-anorm/generated-and-checked-in/adventureworks/public/issue142_2/Issue1422RepoMock.scala new file mode 100644 index 000000000..e73d14fab --- /dev/null +++ b/typo-tester-anorm/generated-and-checked-in/adventureworks/public/issue142_2/Issue1422RepoMock.scala @@ -0,0 +1,83 @@ +/** + * File has been automatically generated by `typo`. + * + * IF YOU CHANGE THIS FILE YOUR CHANGES WILL BE OVERWRITTEN. + */ +package adventureworks +package public +package issue142_2 + +import adventureworks.public.issue142.Issue142Id +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 Issue1422RepoMock(map: scala.collection.mutable.Map[Issue142Id, Issue1422Row] = scala.collection.mutable.Map.empty) extends Issue1422Repo { + override def delete: DeleteBuilder[Issue1422Fields, Issue1422Row] = { + DeleteBuilderMock(DeleteParams.empty, Issue1422Fields.structure, map) + } + override def deleteById(tabellkode: Issue142Id)(implicit c: Connection): Boolean = { + map.remove(tabellkode).isDefined + } + override def deleteByIds(tabellkodes: Array[Issue142Id])(implicit c: Connection): Int = { + tabellkodes.map(id => map.remove(id)).count(_.isDefined) + } + override def insert(unsaved: Issue1422Row)(implicit c: Connection): Issue1422Row = { + val _ = if (map.contains(unsaved.tabellkode)) + sys.error(s"id ${unsaved.tabellkode} already exists") + else + map.put(unsaved.tabellkode, unsaved) + + unsaved + } + override def insertStreaming(unsaved: Iterator[Issue1422Row], batchSize: Int = 10000)(implicit c: Connection): Long = { + unsaved.foreach { row => + map += (row.tabellkode -> row) + } + unsaved.size.toLong + } + override def select: SelectBuilder[Issue1422Fields, Issue1422Row] = { + SelectBuilderMock(Issue1422Fields.structure, () => map.values.toList, SelectParams.empty) + } + override def selectAll(implicit c: Connection): List[Issue1422Row] = { + map.values.toList + } + override def selectById(tabellkode: Issue142Id)(implicit c: Connection): Option[Issue1422Row] = { + map.get(tabellkode) + } + override def selectByIds(tabellkodes: Array[Issue142Id])(implicit c: Connection): List[Issue1422Row] = { + tabellkodes.flatMap(map.get).toList + } + override def selectByIdsTracked(tabellkodes: Array[Issue142Id])(implicit c: Connection): Map[Issue142Id, Issue1422Row] = { + val byId = selectByIds(tabellkodes).view.map(x => (x.tabellkode, x)).toMap + tabellkodes.view.flatMap(id => byId.get(id).map(x => (id, x))).toMap + } + override def update: UpdateBuilder[Issue1422Fields, Issue1422Row] = { + UpdateBuilderMock(UpdateParams.empty, Issue1422Fields.structure, map) + } + override def upsert(unsaved: Issue1422Row)(implicit c: Connection): Issue1422Row = { + map.put(unsaved.tabellkode, unsaved): @nowarn + unsaved + } + override def upsertBatch(unsaved: Iterable[Issue1422Row])(implicit c: Connection): List[Issue1422Row] = { + unsaved.map { row => + map += (row.tabellkode -> row) + row + }.toList + } + /* NOTE: this functionality is not safe if you use auto-commit mode! it runs 3 SQL statements */ + override def upsertStreaming(unsaved: Iterator[Issue1422Row], batchSize: Int = 10000)(implicit c: Connection): Int = { + unsaved.foreach { row => + map += (row.tabellkode -> row) + } + unsaved.size + } +} diff --git a/typo-tester-anorm/generated-and-checked-in/adventureworks/public/issue142_2/Issue1422Row.scala b/typo-tester-anorm/generated-and-checked-in/adventureworks/public/issue142_2/Issue1422Row.scala new file mode 100644 index 000000000..de1baffd3 --- /dev/null +++ b/typo-tester-anorm/generated-and-checked-in/adventureworks/public/issue142_2/Issue1422Row.scala @@ -0,0 +1,54 @@ +/** + * File has been automatically generated by `typo`. + * + * IF YOU CHANGE THIS FILE YOUR CHANGES WILL BE OVERWRITTEN. + */ +package adventureworks +package public +package issue142_2 + +import adventureworks.public.issue142.Issue142Id +import anorm.RowParser +import anorm.Success +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 scala.collection.immutable.ListMap +import scala.util.Try + +/** Table: public.issue142_2 + Primary key: tabellkode */ +case class Issue1422Row( + /** Points to [[issue142.Issue142Row.tabellkode]] */ + tabellkode: Issue142Id +){ + val id = tabellkode + } + +object Issue1422Row { + implicit lazy val reads: Reads[Issue1422Row] = Reads[Issue1422Row](json => JsResult.fromTry( + Try( + Issue1422Row( + tabellkode = json.\("tabellkode").as(Issue142Id.reads) + ) + ) + ), + ) + def rowParser(idx: Int): RowParser[Issue1422Row] = RowParser[Issue1422Row] { row => + Success( + Issue1422Row( + tabellkode = row(idx + 0)(Issue142Id.column) + ) + ) + } + implicit lazy val text: Text[Issue1422Row] = Text.instance[Issue1422Row]{ (row, sb) => + Issue142Id.text.unsafeEncode(row.tabellkode, sb) + } + implicit lazy val writes: OWrites[Issue1422Row] = OWrites[Issue1422Row](o => + new JsObject(ListMap[String, JsValue]( + "tabellkode" -> Issue142Id.writes.writes(o.tabellkode) + )) + ) +} diff --git a/typo-tester-anorm/generated-and-checked-in/adventureworks/testInsert.scala b/typo-tester-anorm/generated-and-checked-in/adventureworks/testInsert.scala index 29e8a454a..4523188d3 100644 --- a/typo-tester-anorm/generated-and-checked-in/adventureworks/testInsert.scala +++ b/typo-tester-anorm/generated-and-checked-in/adventureworks/testInsert.scala @@ -204,6 +204,11 @@ import adventureworks.public.identity_test.IdentityTestId import adventureworks.public.identity_test.IdentityTestRepoImpl import adventureworks.public.identity_test.IdentityTestRow import adventureworks.public.identity_test.IdentityTestRowUnsaved +import adventureworks.public.issue142.Issue142Id +import adventureworks.public.issue142.Issue142RepoImpl +import adventureworks.public.issue142.Issue142Row +import adventureworks.public.issue142_2.Issue1422RepoImpl +import adventureworks.public.issue142_2.Issue1422Row import adventureworks.public.pgtest.PgtestRepoImpl import adventureworks.public.pgtest.PgtestRow import adventureworks.public.pgtestnull.PgtestnullRepoImpl @@ -643,6 +648,8 @@ class TestInsert(random: Random, domainInsert: TestDomainInsert) { parentspecifier: Option[ShortText] = None )(implicit c: Connection): FlaffRow = (new FlaffRepoImpl).insert(new FlaffRow(code = code, anotherCode = anotherCode, someNumber = someNumber, specifier = specifier, parentspecifier = parentspecifier)) def publicIdentityTest(name: IdentityTestId, defaultGenerated: Defaulted[Int] = Defaulted.UseDefault)(implicit c: Connection): IdentityTestRow = (new IdentityTestRepoImpl).insert(new IdentityTestRowUnsaved(name = name, defaultGenerated = defaultGenerated)) + def publicIssue142(tabellkode: Issue142Id = Issue142Id(random.alphanumeric.take(20).mkString))(implicit c: Connection): Issue142Row = (new Issue142RepoImpl).insert(new Issue142Row(tabellkode = tabellkode)) + def publicIssue1422(tabellkode: Issue142Id = Issue142Id.All(random.nextInt(2)))(implicit c: Connection): Issue1422Row = (new Issue1422RepoImpl).insert(new Issue1422Row(tabellkode = tabellkode)) def publicPgtest(box: TypoBox, bytea: TypoBytea, circle: TypoCircle, diff --git a/typo-tester-doobie/generated-and-checked-in/adventureworks/public/issue142/Issue142Fields.scala b/typo-tester-doobie/generated-and-checked-in/adventureworks/public/issue142/Issue142Fields.scala new file mode 100644 index 000000000..58be7bed0 --- /dev/null +++ b/typo-tester-doobie/generated-and-checked-in/adventureworks/public/issue142/Issue142Fields.scala @@ -0,0 +1,37 @@ +/** + * File has been automatically generated by `typo`. + * + * IF YOU CHANGE THIS FILE YOUR CHANGES WILL BE OVERWRITTEN. + */ +package adventureworks +package public +package issue142 + +import typo.dsl.Path +import typo.dsl.SqlExpr.FieldLikeNoHkt +import typo.dsl.SqlExpr.IdField +import typo.dsl.Structure.Relation + +trait Issue142Fields { + def tabellkode: IdField[Issue142Id, Issue142Row] +} + +object Issue142Fields { + lazy val structure: Relation[Issue142Fields, Issue142Row] = + new Impl(Nil) + + private final class Impl(val _path: List[Path]) + extends Relation[Issue142Fields, Issue142Row] { + + override lazy val fields: Issue142Fields = new Issue142Fields { + override def tabellkode = IdField[Issue142Id, Issue142Row](_path, "tabellkode", None, None, x => x.tabellkode, (row, value) => row.copy(tabellkode = value)) + } + + override lazy val columns: List[FieldLikeNoHkt[?, Issue142Row]] = + List[FieldLikeNoHkt[?, Issue142Row]](fields.tabellkode) + + override def copy(path: List[Path]): Impl = + new Impl(path) + } + +} diff --git a/typo-tester-doobie/generated-and-checked-in/adventureworks/public/issue142/Issue142Id.scala b/typo-tester-doobie/generated-and-checked-in/adventureworks/public/issue142/Issue142Id.scala new file mode 100644 index 000000000..3aba85975 --- /dev/null +++ b/typo-tester-doobie/generated-and-checked-in/adventureworks/public/issue142/Issue142Id.scala @@ -0,0 +1,47 @@ +/** + * File has been automatically generated by `typo`. + * + * IF YOU CHANGE THIS FILE YOUR CHANGES WILL BE OVERWRITTEN. + */ +package adventureworks +package public +package issue142 + +import doobie.postgres.Text +import doobie.util.Get +import doobie.util.Put +import doobie.util.Read +import doobie.util.Write +import doobie.util.meta.Meta +import io.circe.Decoder +import io.circe.Encoder + +/** Type for the primary key of table `public.issue142`. It has some known values: + * - aa + * - bb + */ +sealed abstract class Issue142Id(val value: String) + +object Issue142Id { + def apply(underlying: String): Issue142Id = + ByName.getOrElse(underlying, Unknown(underlying)) + case object aa extends Issue142Id("aa") + case object bb extends Issue142Id("bb") + case class Unknown(override val value: String) extends Issue142Id(value) + val All: List[Issue142Id] = List(aa, bb) + val ByName: Map[String, Issue142Id] = All.map(x => (x.value, x)).toMap + + implicit lazy val arrayGet: Get[Array[Issue142Id]] = adventureworks.StringArrayMeta.get.map(_.map(Issue142Id.apply)) + implicit lazy val arrayPut: Put[Array[Issue142Id]] = adventureworks.StringArrayMeta.put.contramap(_.map(_.value)) + implicit lazy val decoder: Decoder[Issue142Id] = Decoder.decodeString.map(Issue142Id.apply) + implicit lazy val encoder: Encoder[Issue142Id] = Encoder.encodeString.contramap(_.value) + implicit lazy val get: Get[Issue142Id] = Meta.StringMeta.get.map(Issue142Id.apply) + implicit lazy val ordering: Ordering[Issue142Id] = Ordering.by(_.value) + implicit lazy val put: Put[Issue142Id] = Meta.StringMeta.put.contramap(_.value) + implicit lazy val read: Read[Issue142Id] = Read.fromGet(get) + implicit lazy val text: Text[Issue142Id] = new Text[Issue142Id] { + override def unsafeEncode(v: Issue142Id, sb: StringBuilder) = Text.stringInstance.unsafeEncode(v.value, sb) + override def unsafeArrayEncode(v: Issue142Id, sb: StringBuilder) = Text.stringInstance.unsafeArrayEncode(v.value, sb) + } + implicit lazy val write: Write[Issue142Id] = Write.fromPut(put) +} diff --git a/typo-tester-doobie/generated-and-checked-in/adventureworks/public/issue142/Issue142Repo.scala b/typo-tester-doobie/generated-and-checked-in/adventureworks/public/issue142/Issue142Repo.scala new file mode 100644 index 000000000..c4b1b63a1 --- /dev/null +++ b/typo-tester-doobie/generated-and-checked-in/adventureworks/public/issue142/Issue142Repo.scala @@ -0,0 +1,32 @@ +/** + * File has been automatically generated by `typo`. + * + * IF YOU CHANGE THIS FILE YOUR CHANGES WILL BE OVERWRITTEN. + */ +package adventureworks +package public +package issue142 + +import doobie.free.connection.ConnectionIO +import fs2.Stream +import typo.dsl.DeleteBuilder +import typo.dsl.SelectBuilder +import typo.dsl.UpdateBuilder + +trait Issue142Repo { + def delete: DeleteBuilder[Issue142Fields, Issue142Row] + def deleteById(tabellkode: Issue142Id): ConnectionIO[Boolean] + def deleteByIds(tabellkodes: Array[Issue142Id]): ConnectionIO[Int] + def insert(unsaved: Issue142Row): ConnectionIO[Issue142Row] + def insertStreaming(unsaved: Stream[ConnectionIO, Issue142Row], batchSize: Int = 10000): ConnectionIO[Long] + def select: SelectBuilder[Issue142Fields, Issue142Row] + def selectAll: Stream[ConnectionIO, Issue142Row] + def selectById(tabellkode: Issue142Id): ConnectionIO[Option[Issue142Row]] + def selectByIds(tabellkodes: Array[Issue142Id]): Stream[ConnectionIO, Issue142Row] + def selectByIdsTracked(tabellkodes: Array[Issue142Id]): ConnectionIO[Map[Issue142Id, Issue142Row]] + def update: UpdateBuilder[Issue142Fields, Issue142Row] + def upsert(unsaved: Issue142Row): ConnectionIO[Issue142Row] + def upsertBatch(unsaved: List[Issue142Row]): Stream[ConnectionIO, Issue142Row] + /* NOTE: this functionality is not safe if you use auto-commit mode! it runs 3 SQL statements */ + def upsertStreaming(unsaved: Stream[ConnectionIO, Issue142Row], batchSize: Int = 10000): ConnectionIO[Int] +} diff --git a/typo-tester-doobie/generated-and-checked-in/adventureworks/public/issue142/Issue142RepoImpl.scala b/typo-tester-doobie/generated-and-checked-in/adventureworks/public/issue142/Issue142RepoImpl.scala new file mode 100644 index 000000000..ecd3db505 --- /dev/null +++ b/typo-tester-doobie/generated-and-checked-in/adventureworks/public/issue142/Issue142RepoImpl.scala @@ -0,0 +1,96 @@ +/** + * File has been automatically generated by `typo`. + * + * IF YOU CHANGE THIS FILE YOUR CHANGES WILL BE OVERWRITTEN. + */ +package adventureworks +package public +package issue142 + +import cats.instances.list.catsStdInstancesForList +import doobie.free.connection.ConnectionIO +import doobie.postgres.syntax.FragmentOps +import doobie.syntax.SqlInterpolator.SingleFragment.fromWrite +import doobie.syntax.string.toSqlInterpolator +import doobie.util.Write +import doobie.util.update.Update +import fs2.Stream +import typo.dsl.DeleteBuilder +import typo.dsl.SelectBuilder +import typo.dsl.SelectBuilderSql +import typo.dsl.UpdateBuilder + +class Issue142RepoImpl extends Issue142Repo { + override def delete: DeleteBuilder[Issue142Fields, Issue142Row] = { + DeleteBuilder(""""public"."issue142"""", Issue142Fields.structure) + } + override def deleteById(tabellkode: Issue142Id): ConnectionIO[Boolean] = { + sql"""delete from "public"."issue142" where "tabellkode" = ${fromWrite(tabellkode)(Write.fromPut(Issue142Id.put))}""".update.run.map(_ > 0) + } + override def deleteByIds(tabellkodes: Array[Issue142Id]): ConnectionIO[Int] = { + sql"""delete from "public"."issue142" where "tabellkode" = ANY(${tabellkodes})""".update.run + } + override def insert(unsaved: Issue142Row): ConnectionIO[Issue142Row] = { + sql"""insert into "public"."issue142"("tabellkode") + values (${fromWrite(unsaved.tabellkode)(Write.fromPut(Issue142Id.put))}) + returning "tabellkode" + """.query(using Issue142Row.read).unique + } + override def insertStreaming(unsaved: Stream[ConnectionIO, Issue142Row], batchSize: Int = 10000): ConnectionIO[Long] = { + new FragmentOps(sql"""COPY "public"."issue142"("tabellkode") FROM STDIN""").copyIn(unsaved, batchSize)(using Issue142Row.text) + } + override def select: SelectBuilder[Issue142Fields, Issue142Row] = { + SelectBuilderSql(""""public"."issue142"""", Issue142Fields.structure, Issue142Row.read) + } + override def selectAll: Stream[ConnectionIO, Issue142Row] = { + sql"""select "tabellkode" from "public"."issue142"""".query(using Issue142Row.read).stream + } + override def selectById(tabellkode: Issue142Id): ConnectionIO[Option[Issue142Row]] = { + sql"""select "tabellkode" from "public"."issue142" where "tabellkode" = ${fromWrite(tabellkode)(Write.fromPut(Issue142Id.put))}""".query(using Issue142Row.read).option + } + override def selectByIds(tabellkodes: Array[Issue142Id]): Stream[ConnectionIO, Issue142Row] = { + sql"""select "tabellkode" from "public"."issue142" where "tabellkode" = ANY(${tabellkodes})""".query(using Issue142Row.read).stream + } + override def selectByIdsTracked(tabellkodes: Array[Issue142Id]): ConnectionIO[Map[Issue142Id, Issue142Row]] = { + selectByIds(tabellkodes).compile.toList.map { rows => + val byId = rows.view.map(x => (x.tabellkode, x)).toMap + tabellkodes.view.flatMap(id => byId.get(id).map(x => (id, x))).toMap + } + } + override def update: UpdateBuilder[Issue142Fields, Issue142Row] = { + UpdateBuilder(""""public"."issue142"""", Issue142Fields.structure, Issue142Row.read) + } + override def upsert(unsaved: Issue142Row): ConnectionIO[Issue142Row] = { + sql"""insert into "public"."issue142"("tabellkode") + values ( + ${fromWrite(unsaved.tabellkode)(Write.fromPut(Issue142Id.put))} + ) + on conflict ("tabellkode") + do nothing + returning "tabellkode" + """.query(using Issue142Row.read).unique + } + override def upsertBatch(unsaved: List[Issue142Row]): Stream[ConnectionIO, Issue142Row] = { + Update[Issue142Row]( + s"""insert into "public"."issue142"("tabellkode") + values (?) + on conflict ("tabellkode") + do nothing + returning "tabellkode"""" + )(using Issue142Row.write) + .updateManyWithGeneratedKeys[Issue142Row]("tabellkode")(unsaved)(using catsStdInstancesForList, Issue142Row.read) + } + /* NOTE: this functionality is not safe if you use auto-commit mode! it runs 3 SQL statements */ + override def upsertStreaming(unsaved: Stream[ConnectionIO, Issue142Row], batchSize: Int = 10000): ConnectionIO[Int] = { + for { + _ <- sql"""create temporary table issue142_TEMP (like "public"."issue142") on commit drop""".update.run + _ <- new FragmentOps(sql"""copy issue142_TEMP("tabellkode") from stdin""").copyIn(unsaved, batchSize)(using Issue142Row.text) + res <- sql"""insert into "public"."issue142"("tabellkode") + select * from issue142_TEMP + on conflict ("tabellkode") + do nothing + ; + drop table issue142_TEMP;""".update.run + } yield res + } +} diff --git a/typo-tester-doobie/generated-and-checked-in/adventureworks/public/issue142/Issue142RepoMock.scala b/typo-tester-doobie/generated-and-checked-in/adventureworks/public/issue142/Issue142RepoMock.scala new file mode 100644 index 000000000..4a1445678 --- /dev/null +++ b/typo-tester-doobie/generated-and-checked-in/adventureworks/public/issue142/Issue142RepoMock.scala @@ -0,0 +1,100 @@ +/** + * File has been automatically generated by `typo`. + * + * IF YOU CHANGE THIS FILE YOUR CHANGES WILL BE OVERWRITTEN. + */ +package adventureworks +package public +package issue142 + +import doobie.free.connection.ConnectionIO +import doobie.free.connection.delay +import fs2.Stream +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 Issue142RepoMock(map: scala.collection.mutable.Map[Issue142Id, Issue142Row] = scala.collection.mutable.Map.empty) extends Issue142Repo { + override def delete: DeleteBuilder[Issue142Fields, Issue142Row] = { + DeleteBuilderMock(DeleteParams.empty, Issue142Fields.structure, map) + } + override def deleteById(tabellkode: Issue142Id): ConnectionIO[Boolean] = { + delay(map.remove(tabellkode).isDefined) + } + override def deleteByIds(tabellkodes: Array[Issue142Id]): ConnectionIO[Int] = { + delay(tabellkodes.map(id => map.remove(id)).count(_.isDefined)) + } + override def insert(unsaved: Issue142Row): ConnectionIO[Issue142Row] = { + delay { + val _ = if (map.contains(unsaved.tabellkode)) + sys.error(s"id ${unsaved.tabellkode} already exists") + else + map.put(unsaved.tabellkode, unsaved) + + unsaved + } + } + override def insertStreaming(unsaved: Stream[ConnectionIO, Issue142Row], batchSize: Int = 10000): ConnectionIO[Long] = { + unsaved.compile.toList.map { rows => + var num = 0L + rows.foreach { row => + map += (row.tabellkode -> row) + num += 1 + } + num + } + } + override def select: SelectBuilder[Issue142Fields, Issue142Row] = { + SelectBuilderMock(Issue142Fields.structure, delay(map.values.toList), SelectParams.empty) + } + override def selectAll: Stream[ConnectionIO, Issue142Row] = { + Stream.emits(map.values.toList) + } + override def selectById(tabellkode: Issue142Id): ConnectionIO[Option[Issue142Row]] = { + delay(map.get(tabellkode)) + } + override def selectByIds(tabellkodes: Array[Issue142Id]): Stream[ConnectionIO, Issue142Row] = { + Stream.emits(tabellkodes.flatMap(map.get).toList) + } + override def selectByIdsTracked(tabellkodes: Array[Issue142Id]): ConnectionIO[Map[Issue142Id, Issue142Row]] = { + selectByIds(tabellkodes).compile.toList.map { rows => + val byId = rows.view.map(x => (x.tabellkode, x)).toMap + tabellkodes.view.flatMap(id => byId.get(id).map(x => (id, x))).toMap + } + } + override def update: UpdateBuilder[Issue142Fields, Issue142Row] = { + UpdateBuilderMock(UpdateParams.empty, Issue142Fields.structure, map) + } + override def upsert(unsaved: Issue142Row): ConnectionIO[Issue142Row] = { + delay { + map.put(unsaved.tabellkode, unsaved): @nowarn + unsaved + } + } + override def upsertBatch(unsaved: List[Issue142Row]): Stream[ConnectionIO, Issue142Row] = { + Stream.emits { + unsaved.map { row => + map += (row.tabellkode -> row) + row + } + } + } + /* NOTE: this functionality is not safe if you use auto-commit mode! it runs 3 SQL statements */ + override def upsertStreaming(unsaved: Stream[ConnectionIO, Issue142Row], batchSize: Int = 10000): ConnectionIO[Int] = { + unsaved.compile.toList.map { rows => + var num = 0 + rows.foreach { row => + map += (row.tabellkode -> row) + num += 1 + } + num + } + } +} diff --git a/typo-tester-doobie/generated-and-checked-in/adventureworks/public/issue142/Issue142Row.scala b/typo-tester-doobie/generated-and-checked-in/adventureworks/public/issue142/Issue142Row.scala new file mode 100644 index 000000000..79b4e2100 --- /dev/null +++ b/typo-tester-doobie/generated-and-checked-in/adventureworks/public/issue142/Issue142Row.scala @@ -0,0 +1,50 @@ +/** + * File has been automatically generated by `typo`. + * + * IF YOU CHANGE THIS FILE YOUR CHANGES WILL BE OVERWRITTEN. + */ +package adventureworks +package public +package issue142 + +import doobie.enumerated.Nullability +import doobie.postgres.Text +import doobie.util.Read +import doobie.util.Write +import io.circe.Decoder +import io.circe.Encoder +import java.sql.ResultSet + +/** Table: public.issue142 + Primary key: tabellkode */ +case class Issue142Row( + tabellkode: Issue142Id +){ + val id = tabellkode + } + +object Issue142Row { + implicit lazy val decoder: Decoder[Issue142Row] = Decoder.forProduct1[Issue142Row, Issue142Id]("tabellkode")(Issue142Row.apply)(Issue142Id.decoder) + implicit lazy val encoder: Encoder[Issue142Row] = Encoder.forProduct1[Issue142Row, Issue142Id]("tabellkode")(x => (x.tabellkode))(Issue142Id.encoder) + implicit lazy val read: Read[Issue142Row] = new Read[Issue142Row]( + gets = List( + (Issue142Id.get, Nullability.NoNulls) + ), + unsafeGet = (rs: ResultSet, i: Int) => Issue142Row( + tabellkode = Issue142Id.get.unsafeGetNonNullable(rs, i + 0) + ) + ) + implicit lazy val text: Text[Issue142Row] = Text.instance[Issue142Row]{ (row, sb) => + Issue142Id.text.unsafeEncode(row.tabellkode, sb) + } + implicit lazy val write: Write[Issue142Row] = new Write[Issue142Row]( + puts = List((Issue142Id.put, Nullability.NoNulls)), + toList = x => List(x.tabellkode), + unsafeSet = (rs, i, a) => { + Issue142Id.put.unsafeSetNonNullable(rs, i + 0, a.tabellkode) + }, + unsafeUpdate = (ps, i, a) => { + Issue142Id.put.unsafeUpdateNonNullable(ps, i + 0, a.tabellkode) + } + ) +} diff --git a/typo-tester-doobie/generated-and-checked-in/adventureworks/public/issue142_2/Issue1422Fields.scala b/typo-tester-doobie/generated-and-checked-in/adventureworks/public/issue142_2/Issue1422Fields.scala new file mode 100644 index 000000000..59f3f3ce5 --- /dev/null +++ b/typo-tester-doobie/generated-and-checked-in/adventureworks/public/issue142_2/Issue1422Fields.scala @@ -0,0 +1,44 @@ +/** + * File has been automatically generated by `typo`. + * + * IF YOU CHANGE THIS FILE YOUR CHANGES WILL BE OVERWRITTEN. + */ +package adventureworks +package public +package issue142_2 + +import adventureworks.public.issue142.Issue142Fields +import adventureworks.public.issue142.Issue142Id +import adventureworks.public.issue142.Issue142Row +import typo.dsl.ForeignKey +import typo.dsl.Path +import typo.dsl.SqlExpr.FieldLikeNoHkt +import typo.dsl.SqlExpr.IdField +import typo.dsl.Structure.Relation + +trait Issue1422Fields { + def tabellkode: IdField[Issue142Id, Issue1422Row] + def fkIssue142: ForeignKey[Issue142Fields, Issue142Row] = + ForeignKey[Issue142Fields, Issue142Row]("public.tabell2_tabell_fk", Nil) + .withColumnPair(tabellkode, _.tabellkode) +} + +object Issue1422Fields { + lazy val structure: Relation[Issue1422Fields, Issue1422Row] = + new Impl(Nil) + + private final class Impl(val _path: List[Path]) + extends Relation[Issue1422Fields, Issue1422Row] { + + override lazy val fields: Issue1422Fields = new Issue1422Fields { + override def tabellkode = IdField[Issue142Id, Issue1422Row](_path, "tabellkode", None, None, x => x.tabellkode, (row, value) => row.copy(tabellkode = value)) + } + + override lazy val columns: List[FieldLikeNoHkt[?, Issue1422Row]] = + List[FieldLikeNoHkt[?, Issue1422Row]](fields.tabellkode) + + override def copy(path: List[Path]): Impl = + new Impl(path) + } + +} diff --git a/typo-tester-doobie/generated-and-checked-in/adventureworks/public/issue142_2/Issue1422Repo.scala b/typo-tester-doobie/generated-and-checked-in/adventureworks/public/issue142_2/Issue1422Repo.scala new file mode 100644 index 000000000..d2df75d4a --- /dev/null +++ b/typo-tester-doobie/generated-and-checked-in/adventureworks/public/issue142_2/Issue1422Repo.scala @@ -0,0 +1,33 @@ +/** + * File has been automatically generated by `typo`. + * + * IF YOU CHANGE THIS FILE YOUR CHANGES WILL BE OVERWRITTEN. + */ +package adventureworks +package public +package issue142_2 + +import adventureworks.public.issue142.Issue142Id +import doobie.free.connection.ConnectionIO +import fs2.Stream +import typo.dsl.DeleteBuilder +import typo.dsl.SelectBuilder +import typo.dsl.UpdateBuilder + +trait Issue1422Repo { + def delete: DeleteBuilder[Issue1422Fields, Issue1422Row] + def deleteById(tabellkode: Issue142Id): ConnectionIO[Boolean] + def deleteByIds(tabellkodes: Array[Issue142Id]): ConnectionIO[Int] + def insert(unsaved: Issue1422Row): ConnectionIO[Issue1422Row] + def insertStreaming(unsaved: Stream[ConnectionIO, Issue1422Row], batchSize: Int = 10000): ConnectionIO[Long] + def select: SelectBuilder[Issue1422Fields, Issue1422Row] + def selectAll: Stream[ConnectionIO, Issue1422Row] + def selectById(tabellkode: Issue142Id): ConnectionIO[Option[Issue1422Row]] + def selectByIds(tabellkodes: Array[Issue142Id]): Stream[ConnectionIO, Issue1422Row] + def selectByIdsTracked(tabellkodes: Array[Issue142Id]): ConnectionIO[Map[Issue142Id, Issue1422Row]] + def update: UpdateBuilder[Issue1422Fields, Issue1422Row] + def upsert(unsaved: Issue1422Row): ConnectionIO[Issue1422Row] + def upsertBatch(unsaved: List[Issue1422Row]): Stream[ConnectionIO, Issue1422Row] + /* NOTE: this functionality is not safe if you use auto-commit mode! it runs 3 SQL statements */ + def upsertStreaming(unsaved: Stream[ConnectionIO, Issue1422Row], batchSize: Int = 10000): ConnectionIO[Int] +} diff --git a/typo-tester-doobie/generated-and-checked-in/adventureworks/public/issue142_2/Issue1422RepoImpl.scala b/typo-tester-doobie/generated-and-checked-in/adventureworks/public/issue142_2/Issue1422RepoImpl.scala new file mode 100644 index 000000000..a5b8ae0eb --- /dev/null +++ b/typo-tester-doobie/generated-and-checked-in/adventureworks/public/issue142_2/Issue1422RepoImpl.scala @@ -0,0 +1,97 @@ +/** + * File has been automatically generated by `typo`. + * + * IF YOU CHANGE THIS FILE YOUR CHANGES WILL BE OVERWRITTEN. + */ +package adventureworks +package public +package issue142_2 + +import adventureworks.public.issue142.Issue142Id +import cats.instances.list.catsStdInstancesForList +import doobie.free.connection.ConnectionIO +import doobie.postgres.syntax.FragmentOps +import doobie.syntax.SqlInterpolator.SingleFragment.fromWrite +import doobie.syntax.string.toSqlInterpolator +import doobie.util.Write +import doobie.util.update.Update +import fs2.Stream +import typo.dsl.DeleteBuilder +import typo.dsl.SelectBuilder +import typo.dsl.SelectBuilderSql +import typo.dsl.UpdateBuilder + +class Issue1422RepoImpl extends Issue1422Repo { + override def delete: DeleteBuilder[Issue1422Fields, Issue1422Row] = { + DeleteBuilder(""""public"."issue142_2"""", Issue1422Fields.structure) + } + override def deleteById(tabellkode: Issue142Id): ConnectionIO[Boolean] = { + sql"""delete from "public"."issue142_2" where "tabellkode" = ${fromWrite(tabellkode)(Write.fromPut(Issue142Id.put))}""".update.run.map(_ > 0) + } + override def deleteByIds(tabellkodes: Array[Issue142Id]): ConnectionIO[Int] = { + sql"""delete from "public"."issue142_2" where "tabellkode" = ANY(${tabellkodes})""".update.run + } + override def insert(unsaved: Issue1422Row): ConnectionIO[Issue1422Row] = { + sql"""insert into "public"."issue142_2"("tabellkode") + values (${fromWrite(unsaved.tabellkode)(Write.fromPut(Issue142Id.put))}) + returning "tabellkode" + """.query(using Issue1422Row.read).unique + } + override def insertStreaming(unsaved: Stream[ConnectionIO, Issue1422Row], batchSize: Int = 10000): ConnectionIO[Long] = { + new FragmentOps(sql"""COPY "public"."issue142_2"("tabellkode") FROM STDIN""").copyIn(unsaved, batchSize)(using Issue1422Row.text) + } + override def select: SelectBuilder[Issue1422Fields, Issue1422Row] = { + SelectBuilderSql(""""public"."issue142_2"""", Issue1422Fields.structure, Issue1422Row.read) + } + override def selectAll: Stream[ConnectionIO, Issue1422Row] = { + sql"""select "tabellkode" from "public"."issue142_2"""".query(using Issue1422Row.read).stream + } + override def selectById(tabellkode: Issue142Id): ConnectionIO[Option[Issue1422Row]] = { + sql"""select "tabellkode" from "public"."issue142_2" where "tabellkode" = ${fromWrite(tabellkode)(Write.fromPut(Issue142Id.put))}""".query(using Issue1422Row.read).option + } + override def selectByIds(tabellkodes: Array[Issue142Id]): Stream[ConnectionIO, Issue1422Row] = { + sql"""select "tabellkode" from "public"."issue142_2" where "tabellkode" = ANY(${tabellkodes})""".query(using Issue1422Row.read).stream + } + override def selectByIdsTracked(tabellkodes: Array[Issue142Id]): ConnectionIO[Map[Issue142Id, Issue1422Row]] = { + selectByIds(tabellkodes).compile.toList.map { rows => + val byId = rows.view.map(x => (x.tabellkode, x)).toMap + tabellkodes.view.flatMap(id => byId.get(id).map(x => (id, x))).toMap + } + } + override def update: UpdateBuilder[Issue1422Fields, Issue1422Row] = { + UpdateBuilder(""""public"."issue142_2"""", Issue1422Fields.structure, Issue1422Row.read) + } + override def upsert(unsaved: Issue1422Row): ConnectionIO[Issue1422Row] = { + sql"""insert into "public"."issue142_2"("tabellkode") + values ( + ${fromWrite(unsaved.tabellkode)(Write.fromPut(Issue142Id.put))} + ) + on conflict ("tabellkode") + do nothing + returning "tabellkode" + """.query(using Issue1422Row.read).unique + } + override def upsertBatch(unsaved: List[Issue1422Row]): Stream[ConnectionIO, Issue1422Row] = { + Update[Issue1422Row]( + s"""insert into "public"."issue142_2"("tabellkode") + values (?) + on conflict ("tabellkode") + do nothing + returning "tabellkode"""" + )(using Issue1422Row.write) + .updateManyWithGeneratedKeys[Issue1422Row]("tabellkode")(unsaved)(using catsStdInstancesForList, Issue1422Row.read) + } + /* NOTE: this functionality is not safe if you use auto-commit mode! it runs 3 SQL statements */ + override def upsertStreaming(unsaved: Stream[ConnectionIO, Issue1422Row], batchSize: Int = 10000): ConnectionIO[Int] = { + for { + _ <- sql"""create temporary table issue142_2_TEMP (like "public"."issue142_2") on commit drop""".update.run + _ <- new FragmentOps(sql"""copy issue142_2_TEMP("tabellkode") from stdin""").copyIn(unsaved, batchSize)(using Issue1422Row.text) + res <- sql"""insert into "public"."issue142_2"("tabellkode") + select * from issue142_2_TEMP + on conflict ("tabellkode") + do nothing + ; + drop table issue142_2_TEMP;""".update.run + } yield res + } +} diff --git a/typo-tester-doobie/generated-and-checked-in/adventureworks/public/issue142_2/Issue1422RepoMock.scala b/typo-tester-doobie/generated-and-checked-in/adventureworks/public/issue142_2/Issue1422RepoMock.scala new file mode 100644 index 000000000..14c55a8e3 --- /dev/null +++ b/typo-tester-doobie/generated-and-checked-in/adventureworks/public/issue142_2/Issue1422RepoMock.scala @@ -0,0 +1,101 @@ +/** + * File has been automatically generated by `typo`. + * + * IF YOU CHANGE THIS FILE YOUR CHANGES WILL BE OVERWRITTEN. + */ +package adventureworks +package public +package issue142_2 + +import adventureworks.public.issue142.Issue142Id +import doobie.free.connection.ConnectionIO +import doobie.free.connection.delay +import fs2.Stream +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 Issue1422RepoMock(map: scala.collection.mutable.Map[Issue142Id, Issue1422Row] = scala.collection.mutable.Map.empty) extends Issue1422Repo { + override def delete: DeleteBuilder[Issue1422Fields, Issue1422Row] = { + DeleteBuilderMock(DeleteParams.empty, Issue1422Fields.structure, map) + } + override def deleteById(tabellkode: Issue142Id): ConnectionIO[Boolean] = { + delay(map.remove(tabellkode).isDefined) + } + override def deleteByIds(tabellkodes: Array[Issue142Id]): ConnectionIO[Int] = { + delay(tabellkodes.map(id => map.remove(id)).count(_.isDefined)) + } + override def insert(unsaved: Issue1422Row): ConnectionIO[Issue1422Row] = { + delay { + val _ = if (map.contains(unsaved.tabellkode)) + sys.error(s"id ${unsaved.tabellkode} already exists") + else + map.put(unsaved.tabellkode, unsaved) + + unsaved + } + } + override def insertStreaming(unsaved: Stream[ConnectionIO, Issue1422Row], batchSize: Int = 10000): ConnectionIO[Long] = { + unsaved.compile.toList.map { rows => + var num = 0L + rows.foreach { row => + map += (row.tabellkode -> row) + num += 1 + } + num + } + } + override def select: SelectBuilder[Issue1422Fields, Issue1422Row] = { + SelectBuilderMock(Issue1422Fields.structure, delay(map.values.toList), SelectParams.empty) + } + override def selectAll: Stream[ConnectionIO, Issue1422Row] = { + Stream.emits(map.values.toList) + } + override def selectById(tabellkode: Issue142Id): ConnectionIO[Option[Issue1422Row]] = { + delay(map.get(tabellkode)) + } + override def selectByIds(tabellkodes: Array[Issue142Id]): Stream[ConnectionIO, Issue1422Row] = { + Stream.emits(tabellkodes.flatMap(map.get).toList) + } + override def selectByIdsTracked(tabellkodes: Array[Issue142Id]): ConnectionIO[Map[Issue142Id, Issue1422Row]] = { + selectByIds(tabellkodes).compile.toList.map { rows => + val byId = rows.view.map(x => (x.tabellkode, x)).toMap + tabellkodes.view.flatMap(id => byId.get(id).map(x => (id, x))).toMap + } + } + override def update: UpdateBuilder[Issue1422Fields, Issue1422Row] = { + UpdateBuilderMock(UpdateParams.empty, Issue1422Fields.structure, map) + } + override def upsert(unsaved: Issue1422Row): ConnectionIO[Issue1422Row] = { + delay { + map.put(unsaved.tabellkode, unsaved): @nowarn + unsaved + } + } + override def upsertBatch(unsaved: List[Issue1422Row]): Stream[ConnectionIO, Issue1422Row] = { + Stream.emits { + unsaved.map { row => + map += (row.tabellkode -> row) + row + } + } + } + /* NOTE: this functionality is not safe if you use auto-commit mode! it runs 3 SQL statements */ + override def upsertStreaming(unsaved: Stream[ConnectionIO, Issue1422Row], batchSize: Int = 10000): ConnectionIO[Int] = { + unsaved.compile.toList.map { rows => + var num = 0 + rows.foreach { row => + map += (row.tabellkode -> row) + num += 1 + } + num + } + } +} diff --git a/typo-tester-doobie/generated-and-checked-in/adventureworks/public/issue142_2/Issue1422Row.scala b/typo-tester-doobie/generated-and-checked-in/adventureworks/public/issue142_2/Issue1422Row.scala new file mode 100644 index 000000000..2c9618784 --- /dev/null +++ b/typo-tester-doobie/generated-and-checked-in/adventureworks/public/issue142_2/Issue1422Row.scala @@ -0,0 +1,52 @@ +/** + * File has been automatically generated by `typo`. + * + * IF YOU CHANGE THIS FILE YOUR CHANGES WILL BE OVERWRITTEN. + */ +package adventureworks +package public +package issue142_2 + +import adventureworks.public.issue142.Issue142Id +import doobie.enumerated.Nullability +import doobie.postgres.Text +import doobie.util.Read +import doobie.util.Write +import io.circe.Decoder +import io.circe.Encoder +import java.sql.ResultSet + +/** Table: public.issue142_2 + Primary key: tabellkode */ +case class Issue1422Row( + /** Points to [[issue142.Issue142Row.tabellkode]] */ + tabellkode: Issue142Id +){ + val id = tabellkode + } + +object Issue1422Row { + implicit lazy val decoder: Decoder[Issue1422Row] = Decoder.forProduct1[Issue1422Row, Issue142Id]("tabellkode")(Issue1422Row.apply)(Issue142Id.decoder) + implicit lazy val encoder: Encoder[Issue1422Row] = Encoder.forProduct1[Issue1422Row, Issue142Id]("tabellkode")(x => (x.tabellkode))(Issue142Id.encoder) + implicit lazy val read: Read[Issue1422Row] = new Read[Issue1422Row]( + gets = List( + (Issue142Id.get, Nullability.NoNulls) + ), + unsafeGet = (rs: ResultSet, i: Int) => Issue1422Row( + tabellkode = Issue142Id.get.unsafeGetNonNullable(rs, i + 0) + ) + ) + implicit lazy val text: Text[Issue1422Row] = Text.instance[Issue1422Row]{ (row, sb) => + Issue142Id.text.unsafeEncode(row.tabellkode, sb) + } + implicit lazy val write: Write[Issue1422Row] = new Write[Issue1422Row]( + puts = List((Issue142Id.put, Nullability.NoNulls)), + toList = x => List(x.tabellkode), + unsafeSet = (rs, i, a) => { + Issue142Id.put.unsafeSetNonNullable(rs, i + 0, a.tabellkode) + }, + unsafeUpdate = (ps, i, a) => { + Issue142Id.put.unsafeUpdateNonNullable(ps, i + 0, a.tabellkode) + } + ) +} diff --git a/typo-tester-doobie/generated-and-checked-in/adventureworks/testInsert.scala b/typo-tester-doobie/generated-and-checked-in/adventureworks/testInsert.scala index 7f0e5f34b..f945b9864 100644 --- a/typo-tester-doobie/generated-and-checked-in/adventureworks/testInsert.scala +++ b/typo-tester-doobie/generated-and-checked-in/adventureworks/testInsert.scala @@ -204,6 +204,11 @@ import adventureworks.public.identity_test.IdentityTestId import adventureworks.public.identity_test.IdentityTestRepoImpl import adventureworks.public.identity_test.IdentityTestRow import adventureworks.public.identity_test.IdentityTestRowUnsaved +import adventureworks.public.issue142.Issue142Id +import adventureworks.public.issue142.Issue142RepoImpl +import adventureworks.public.issue142.Issue142Row +import adventureworks.public.issue142_2.Issue1422RepoImpl +import adventureworks.public.issue142_2.Issue1422Row import adventureworks.public.pgtest.PgtestRepoImpl import adventureworks.public.pgtest.PgtestRow import adventureworks.public.pgtestnull.PgtestnullRepoImpl @@ -643,6 +648,8 @@ class TestInsert(random: Random, domainInsert: TestDomainInsert) { parentspecifier: Option[ShortText] = None ): ConnectionIO[FlaffRow] = (new FlaffRepoImpl).insert(new FlaffRow(code = code, anotherCode = anotherCode, someNumber = someNumber, specifier = specifier, parentspecifier = parentspecifier)) def publicIdentityTest(name: IdentityTestId, defaultGenerated: Defaulted[Int] = Defaulted.UseDefault): ConnectionIO[IdentityTestRow] = (new IdentityTestRepoImpl).insert(new IdentityTestRowUnsaved(name = name, defaultGenerated = defaultGenerated)) + def publicIssue142(tabellkode: Issue142Id = Issue142Id(random.alphanumeric.take(20).mkString)): ConnectionIO[Issue142Row] = (new Issue142RepoImpl).insert(new Issue142Row(tabellkode = tabellkode)) + def publicIssue1422(tabellkode: Issue142Id = Issue142Id.All(random.nextInt(2))): ConnectionIO[Issue1422Row] = (new Issue1422RepoImpl).insert(new Issue1422Row(tabellkode = tabellkode)) def publicPgtest(box: TypoBox, bytea: TypoBytea, circle: TypoCircle, diff --git a/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/issue142/Issue142Fields.scala b/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/issue142/Issue142Fields.scala new file mode 100644 index 000000000..58be7bed0 --- /dev/null +++ b/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/issue142/Issue142Fields.scala @@ -0,0 +1,37 @@ +/** + * File has been automatically generated by `typo`. + * + * IF YOU CHANGE THIS FILE YOUR CHANGES WILL BE OVERWRITTEN. + */ +package adventureworks +package public +package issue142 + +import typo.dsl.Path +import typo.dsl.SqlExpr.FieldLikeNoHkt +import typo.dsl.SqlExpr.IdField +import typo.dsl.Structure.Relation + +trait Issue142Fields { + def tabellkode: IdField[Issue142Id, Issue142Row] +} + +object Issue142Fields { + lazy val structure: Relation[Issue142Fields, Issue142Row] = + new Impl(Nil) + + private final class Impl(val _path: List[Path]) + extends Relation[Issue142Fields, Issue142Row] { + + override lazy val fields: Issue142Fields = new Issue142Fields { + override def tabellkode = IdField[Issue142Id, Issue142Row](_path, "tabellkode", None, None, x => x.tabellkode, (row, value) => row.copy(tabellkode = value)) + } + + override lazy val columns: List[FieldLikeNoHkt[?, Issue142Row]] = + List[FieldLikeNoHkt[?, Issue142Row]](fields.tabellkode) + + override def copy(path: List[Path]): Impl = + new Impl(path) + } + +} diff --git a/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/issue142/Issue142Id.scala b/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/issue142/Issue142Id.scala new file mode 100644 index 000000000..4e536fa47 --- /dev/null +++ b/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/issue142/Issue142Id.scala @@ -0,0 +1,47 @@ +/** + * File has been automatically generated by `typo`. + * + * IF YOU CHANGE THIS FILE YOUR CHANGES WILL BE OVERWRITTEN. + */ +package adventureworks +package public +package issue142 + +import java.sql.Types +import typo.dsl.PGType +import zio.jdbc.JdbcDecoder +import zio.jdbc.JdbcEncoder +import zio.jdbc.SqlFragment.Setter +import zio.json.JsonDecoder +import zio.json.JsonEncoder + +/** Type for the primary key of table `public.issue142`. It has some known values: + * - aa + * - bb + */ +sealed abstract class Issue142Id(val value: String) + +object Issue142Id { + def apply(underlying: String): Issue142Id = + ByName.getOrElse(underlying, Unknown(underlying)) + case object aa extends Issue142Id("aa") + case object bb extends Issue142Id("bb") + case class Unknown(override val value: String) extends Issue142Id(value) + val All: List[Issue142Id] = List(aa, bb) + val ByName: Map[String, Issue142Id] = All.map(x => (x.value, x)).toMap + + implicit lazy val arrayJdbcDecoder: JdbcDecoder[Array[Issue142Id]] = adventureworks.StringArrayDecoder.map(a => if (a == null) null else a.map(apply)) + implicit lazy val arrayJdbcEncoder: JdbcEncoder[Array[Issue142Id]] = JdbcEncoder.singleParamEncoder(using arraySetter) + implicit lazy val arraySetter: Setter[Array[Issue142Id]] = adventureworks.StringArraySetter.contramap(_.map(_.value)) + implicit lazy val jdbcDecoder: JdbcDecoder[Issue142Id] = JdbcDecoder.stringDecoder.map(Issue142Id.apply) + implicit lazy val jdbcEncoder: JdbcEncoder[Issue142Id] = JdbcEncoder.stringEncoder.contramap(_.value) + implicit lazy val jsonDecoder: JsonDecoder[Issue142Id] = JsonDecoder.string.map(Issue142Id.apply) + implicit lazy val jsonEncoder: JsonEncoder[Issue142Id] = JsonEncoder.string.contramap(_.value) + implicit lazy val ordering: Ordering[Issue142Id] = Ordering.by(_.value) + implicit lazy val pgType: PGType[Issue142Id] = PGType.instance[Issue142Id]("text", Types.OTHER) + implicit lazy val setter: Setter[Issue142Id] = Setter.stringSetter.contramap(_.value) + implicit lazy val text: Text[Issue142Id] = new Text[Issue142Id] { + override def unsafeEncode(v: Issue142Id, sb: StringBuilder) = Text.stringInstance.unsafeEncode(v.value, sb) + override def unsafeArrayEncode(v: Issue142Id, sb: StringBuilder) = Text.stringInstance.unsafeArrayEncode(v.value, sb) + } +} diff --git a/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/issue142/Issue142Repo.scala b/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/issue142/Issue142Repo.scala new file mode 100644 index 000000000..0ba885692 --- /dev/null +++ b/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/issue142/Issue142Repo.scala @@ -0,0 +1,34 @@ +/** + * File has been automatically generated by `typo`. + * + * IF YOU CHANGE THIS FILE YOUR CHANGES WILL BE OVERWRITTEN. + */ +package adventureworks +package public +package issue142 + +import typo.dsl.DeleteBuilder +import typo.dsl.SelectBuilder +import typo.dsl.UpdateBuilder +import zio.ZIO +import zio.jdbc.UpdateResult +import zio.jdbc.ZConnection +import zio.stream.ZStream + +trait Issue142Repo { + def delete: DeleteBuilder[Issue142Fields, Issue142Row] + def deleteById(tabellkode: Issue142Id): ZIO[ZConnection, Throwable, Boolean] + def deleteByIds(tabellkodes: Array[Issue142Id]): ZIO[ZConnection, Throwable, Long] + def insert(unsaved: Issue142Row): ZIO[ZConnection, Throwable, Issue142Row] + def insertStreaming(unsaved: ZStream[ZConnection, Throwable, Issue142Row], batchSize: Int = 10000): ZIO[ZConnection, Throwable, Long] + def select: SelectBuilder[Issue142Fields, Issue142Row] + def selectAll: ZStream[ZConnection, Throwable, Issue142Row] + def selectById(tabellkode: Issue142Id): ZIO[ZConnection, Throwable, Option[Issue142Row]] + def selectByIds(tabellkodes: Array[Issue142Id]): ZStream[ZConnection, Throwable, Issue142Row] + def selectByIdsTracked(tabellkodes: Array[Issue142Id]): ZIO[ZConnection, Throwable, Map[Issue142Id, Issue142Row]] + def update: UpdateBuilder[Issue142Fields, Issue142Row] + def upsert(unsaved: Issue142Row): ZIO[ZConnection, Throwable, UpdateResult[Issue142Row]] + // Not implementable for zio-jdbc: upsertBatch + /* NOTE: this functionality is not safe if you use auto-commit mode! it runs 3 SQL statements */ + def upsertStreaming(unsaved: ZStream[ZConnection, Throwable, Issue142Row], batchSize: Int = 10000): ZIO[ZConnection, Throwable, Long] +} diff --git a/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/issue142/Issue142RepoImpl.scala b/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/issue142/Issue142RepoImpl.scala new file mode 100644 index 000000000..07d9e34cd --- /dev/null +++ b/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/issue142/Issue142RepoImpl.scala @@ -0,0 +1,82 @@ +/** + * File has been automatically generated by `typo`. + * + * IF YOU CHANGE THIS FILE YOUR CHANGES WILL BE OVERWRITTEN. + */ +package adventureworks +package public +package issue142 + +import typo.dsl.DeleteBuilder +import typo.dsl.SelectBuilder +import typo.dsl.SelectBuilderSql +import typo.dsl.UpdateBuilder +import zio.ZIO +import zio.jdbc.SqlFragment.Segment +import zio.jdbc.UpdateResult +import zio.jdbc.ZConnection +import zio.jdbc.sqlInterpolator +import zio.stream.ZStream + +class Issue142RepoImpl extends Issue142Repo { + override def delete: DeleteBuilder[Issue142Fields, Issue142Row] = { + DeleteBuilder(""""public"."issue142"""", Issue142Fields.structure) + } + override def deleteById(tabellkode: Issue142Id): ZIO[ZConnection, Throwable, Boolean] = { + sql"""delete from "public"."issue142" where "tabellkode" = ${Segment.paramSegment(tabellkode)(Issue142Id.setter)}""".delete.map(_ > 0) + } + override def deleteByIds(tabellkodes: Array[Issue142Id]): ZIO[ZConnection, Throwable, Long] = { + sql"""delete from "public"."issue142" where "tabellkode" = ANY(${tabellkodes})""".delete + } + override def insert(unsaved: Issue142Row): ZIO[ZConnection, Throwable, Issue142Row] = { + sql"""insert into "public"."issue142"("tabellkode") + values (${Segment.paramSegment(unsaved.tabellkode)(Issue142Id.setter)}) + returning "tabellkode" + """.insertReturning(using Issue142Row.jdbcDecoder).map(_.updatedKeys.head) + } + override def insertStreaming(unsaved: ZStream[ZConnection, Throwable, Issue142Row], batchSize: Int = 10000): ZIO[ZConnection, Throwable, Long] = { + streamingInsert(s"""COPY "public"."issue142"("tabellkode") FROM STDIN""", batchSize, unsaved)(Issue142Row.text) + } + override def select: SelectBuilder[Issue142Fields, Issue142Row] = { + SelectBuilderSql(""""public"."issue142"""", Issue142Fields.structure, Issue142Row.jdbcDecoder) + } + override def selectAll: ZStream[ZConnection, Throwable, Issue142Row] = { + sql"""select "tabellkode" from "public"."issue142"""".query(using Issue142Row.jdbcDecoder).selectStream() + } + override def selectById(tabellkode: Issue142Id): ZIO[ZConnection, Throwable, Option[Issue142Row]] = { + sql"""select "tabellkode" from "public"."issue142" where "tabellkode" = ${Segment.paramSegment(tabellkode)(Issue142Id.setter)}""".query(using Issue142Row.jdbcDecoder).selectOne + } + override def selectByIds(tabellkodes: Array[Issue142Id]): ZStream[ZConnection, Throwable, Issue142Row] = { + sql"""select "tabellkode" from "public"."issue142" where "tabellkode" = ANY(${Segment.paramSegment(tabellkodes)(Issue142Id.arraySetter)})""".query(using Issue142Row.jdbcDecoder).selectStream() + } + override def selectByIdsTracked(tabellkodes: Array[Issue142Id]): ZIO[ZConnection, Throwable, Map[Issue142Id, Issue142Row]] = { + selectByIds(tabellkodes).runCollect.map { rows => + val byId = rows.view.map(x => (x.tabellkode, x)).toMap + tabellkodes.view.flatMap(id => byId.get(id).map(x => (id, x))).toMap + } + } + override def update: UpdateBuilder[Issue142Fields, Issue142Row] = { + UpdateBuilder(""""public"."issue142"""", Issue142Fields.structure, Issue142Row.jdbcDecoder) + } + override def upsert(unsaved: Issue142Row): ZIO[ZConnection, Throwable, UpdateResult[Issue142Row]] = { + sql"""insert into "public"."issue142"("tabellkode") + values ( + ${Segment.paramSegment(unsaved.tabellkode)(Issue142Id.setter)} + ) + on conflict ("tabellkode") + do nothing + returning "tabellkode"""".insertReturning(using Issue142Row.jdbcDecoder) + } + /* NOTE: this functionality is not safe if you use auto-commit mode! it runs 3 SQL statements */ + override def upsertStreaming(unsaved: ZStream[ZConnection, Throwable, Issue142Row], batchSize: Int = 10000): ZIO[ZConnection, Throwable, Long] = { + val created = sql"""create temporary table issue142_TEMP (like "public"."issue142") on commit drop""".execute + val copied = streamingInsert(s"""copy issue142_TEMP("tabellkode") from stdin""", batchSize, unsaved)(Issue142Row.text) + val merged = sql"""insert into "public"."issue142"("tabellkode") + select * from issue142_TEMP + on conflict ("tabellkode") + do nothing + ; + drop table issue142_TEMP;""".update + created *> copied *> merged + } +} diff --git a/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/issue142/Issue142RepoMock.scala b/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/issue142/Issue142RepoMock.scala new file mode 100644 index 000000000..cb29761ab --- /dev/null +++ b/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/issue142/Issue142RepoMock.scala @@ -0,0 +1,91 @@ +/** + * File has been automatically generated by `typo`. + * + * IF YOU CHANGE THIS FILE YOUR CHANGES WILL BE OVERWRITTEN. + */ +package adventureworks +package public +package issue142 + +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 +import zio.Chunk +import zio.ZIO +import zio.jdbc.UpdateResult +import zio.jdbc.ZConnection +import zio.stream.ZStream + +class Issue142RepoMock(map: scala.collection.mutable.Map[Issue142Id, Issue142Row] = scala.collection.mutable.Map.empty) extends Issue142Repo { + override def delete: DeleteBuilder[Issue142Fields, Issue142Row] = { + DeleteBuilderMock(DeleteParams.empty, Issue142Fields.structure, map) + } + override def deleteById(tabellkode: Issue142Id): ZIO[ZConnection, Throwable, Boolean] = { + ZIO.succeed(map.remove(tabellkode).isDefined) + } + override def deleteByIds(tabellkodes: Array[Issue142Id]): ZIO[ZConnection, Throwable, Long] = { + ZIO.succeed(tabellkodes.map(id => map.remove(id)).count(_.isDefined).toLong) + } + override def insert(unsaved: Issue142Row): ZIO[ZConnection, Throwable, Issue142Row] = { + ZIO.succeed { + val _ = + if (map.contains(unsaved.tabellkode)) + sys.error(s"id ${unsaved.tabellkode} already exists") + else + map.put(unsaved.tabellkode, unsaved) + + unsaved + } + } + override def insertStreaming(unsaved: ZStream[ZConnection, Throwable, Issue142Row], batchSize: Int = 10000): ZIO[ZConnection, Throwable, Long] = { + unsaved.scanZIO(0L) { case (acc, row) => + ZIO.succeed { + map += (row.tabellkode -> row) + acc + 1 + } + }.runLast.map(_.getOrElse(0L)) + } + override def select: SelectBuilder[Issue142Fields, Issue142Row] = { + SelectBuilderMock(Issue142Fields.structure, ZIO.succeed(Chunk.fromIterable(map.values)), SelectParams.empty) + } + override def selectAll: ZStream[ZConnection, Throwable, Issue142Row] = { + ZStream.fromIterable(map.values) + } + override def selectById(tabellkode: Issue142Id): ZIO[ZConnection, Throwable, Option[Issue142Row]] = { + ZIO.succeed(map.get(tabellkode)) + } + override def selectByIds(tabellkodes: Array[Issue142Id]): ZStream[ZConnection, Throwable, Issue142Row] = { + ZStream.fromIterable(tabellkodes.flatMap(map.get)) + } + override def selectByIdsTracked(tabellkodes: Array[Issue142Id]): ZIO[ZConnection, Throwable, Map[Issue142Id, Issue142Row]] = { + selectByIds(tabellkodes).runCollect.map { rows => + val byId = rows.view.map(x => (x.tabellkode, x)).toMap + tabellkodes.view.flatMap(id => byId.get(id).map(x => (id, x))).toMap + } + } + override def update: UpdateBuilder[Issue142Fields, Issue142Row] = { + UpdateBuilderMock(UpdateParams.empty, Issue142Fields.structure, map) + } + override def upsert(unsaved: Issue142Row): ZIO[ZConnection, Throwable, UpdateResult[Issue142Row]] = { + ZIO.succeed { + map.put(unsaved.tabellkode, unsaved): @nowarn + UpdateResult(1, Chunk.single(unsaved)) + } + } + /* NOTE: this functionality is not safe if you use auto-commit mode! it runs 3 SQL statements */ + override def upsertStreaming(unsaved: ZStream[ZConnection, Throwable, Issue142Row], batchSize: Int = 10000): ZIO[ZConnection, Throwable, Long] = { + unsaved.scanZIO(0L) { case (acc, row) => + ZIO.succeed { + map += (row.tabellkode -> row) + acc + 1 + } + }.runLast.map(_.getOrElse(0L)) + } +} diff --git a/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/issue142/Issue142Row.scala b/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/issue142/Issue142Row.scala new file mode 100644 index 000000000..983ac5ca3 --- /dev/null +++ b/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/issue142/Issue142Row.scala @@ -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 issue142 + +import zio.jdbc.JdbcDecoder +import zio.json.JsonDecoder +import zio.json.JsonEncoder +import zio.json.ast.Json +import zio.json.internal.Write + +/** Table: public.issue142 + Primary key: tabellkode */ +case class Issue142Row( + tabellkode: Issue142Id +){ + val id = tabellkode + } + +object Issue142Row { + implicit lazy val jdbcDecoder: JdbcDecoder[Issue142Row] = Issue142Id.jdbcDecoder.map(v => Issue142Row(tabellkode = v)) + implicit lazy val jsonDecoder: JsonDecoder[Issue142Row] = JsonDecoder[Json.Obj].mapOrFail { jsonObj => + val tabellkode = jsonObj.get("tabellkode").toRight("Missing field 'tabellkode'").flatMap(_.as(Issue142Id.jsonDecoder)) + if (tabellkode.isRight) + Right(Issue142Row(tabellkode = tabellkode.toOption.get)) + else Left(List[Either[String, Any]](tabellkode).flatMap(_.left.toOption).mkString(", ")) + } + implicit lazy val jsonEncoder: JsonEncoder[Issue142Row] = new JsonEncoder[Issue142Row] { + override def unsafeEncode(a: Issue142Row, indent: Option[Int], out: Write): Unit = { + out.write("{") + out.write(""""tabellkode":""") + Issue142Id.jsonEncoder.unsafeEncode(a.tabellkode, indent, out) + out.write("}") + } + } + implicit lazy val text: Text[Issue142Row] = Text.instance[Issue142Row]{ (row, sb) => + Issue142Id.text.unsafeEncode(row.tabellkode, sb) + } +} diff --git a/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/issue142_2/Issue1422Fields.scala b/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/issue142_2/Issue1422Fields.scala new file mode 100644 index 000000000..59f3f3ce5 --- /dev/null +++ b/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/issue142_2/Issue1422Fields.scala @@ -0,0 +1,44 @@ +/** + * File has been automatically generated by `typo`. + * + * IF YOU CHANGE THIS FILE YOUR CHANGES WILL BE OVERWRITTEN. + */ +package adventureworks +package public +package issue142_2 + +import adventureworks.public.issue142.Issue142Fields +import adventureworks.public.issue142.Issue142Id +import adventureworks.public.issue142.Issue142Row +import typo.dsl.ForeignKey +import typo.dsl.Path +import typo.dsl.SqlExpr.FieldLikeNoHkt +import typo.dsl.SqlExpr.IdField +import typo.dsl.Structure.Relation + +trait Issue1422Fields { + def tabellkode: IdField[Issue142Id, Issue1422Row] + def fkIssue142: ForeignKey[Issue142Fields, Issue142Row] = + ForeignKey[Issue142Fields, Issue142Row]("public.tabell2_tabell_fk", Nil) + .withColumnPair(tabellkode, _.tabellkode) +} + +object Issue1422Fields { + lazy val structure: Relation[Issue1422Fields, Issue1422Row] = + new Impl(Nil) + + private final class Impl(val _path: List[Path]) + extends Relation[Issue1422Fields, Issue1422Row] { + + override lazy val fields: Issue1422Fields = new Issue1422Fields { + override def tabellkode = IdField[Issue142Id, Issue1422Row](_path, "tabellkode", None, None, x => x.tabellkode, (row, value) => row.copy(tabellkode = value)) + } + + override lazy val columns: List[FieldLikeNoHkt[?, Issue1422Row]] = + List[FieldLikeNoHkt[?, Issue1422Row]](fields.tabellkode) + + override def copy(path: List[Path]): Impl = + new Impl(path) + } + +} diff --git a/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/issue142_2/Issue1422Repo.scala b/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/issue142_2/Issue1422Repo.scala new file mode 100644 index 000000000..405029036 --- /dev/null +++ b/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/issue142_2/Issue1422Repo.scala @@ -0,0 +1,35 @@ +/** + * File has been automatically generated by `typo`. + * + * IF YOU CHANGE THIS FILE YOUR CHANGES WILL BE OVERWRITTEN. + */ +package adventureworks +package public +package issue142_2 + +import adventureworks.public.issue142.Issue142Id +import typo.dsl.DeleteBuilder +import typo.dsl.SelectBuilder +import typo.dsl.UpdateBuilder +import zio.ZIO +import zio.jdbc.UpdateResult +import zio.jdbc.ZConnection +import zio.stream.ZStream + +trait Issue1422Repo { + def delete: DeleteBuilder[Issue1422Fields, Issue1422Row] + def deleteById(tabellkode: Issue142Id): ZIO[ZConnection, Throwable, Boolean] + def deleteByIds(tabellkodes: Array[Issue142Id]): ZIO[ZConnection, Throwable, Long] + def insert(unsaved: Issue1422Row): ZIO[ZConnection, Throwable, Issue1422Row] + def insertStreaming(unsaved: ZStream[ZConnection, Throwable, Issue1422Row], batchSize: Int = 10000): ZIO[ZConnection, Throwable, Long] + def select: SelectBuilder[Issue1422Fields, Issue1422Row] + def selectAll: ZStream[ZConnection, Throwable, Issue1422Row] + def selectById(tabellkode: Issue142Id): ZIO[ZConnection, Throwable, Option[Issue1422Row]] + def selectByIds(tabellkodes: Array[Issue142Id]): ZStream[ZConnection, Throwable, Issue1422Row] + def selectByIdsTracked(tabellkodes: Array[Issue142Id]): ZIO[ZConnection, Throwable, Map[Issue142Id, Issue1422Row]] + def update: UpdateBuilder[Issue1422Fields, Issue1422Row] + def upsert(unsaved: Issue1422Row): ZIO[ZConnection, Throwable, UpdateResult[Issue1422Row]] + // Not implementable for zio-jdbc: upsertBatch + /* NOTE: this functionality is not safe if you use auto-commit mode! it runs 3 SQL statements */ + def upsertStreaming(unsaved: ZStream[ZConnection, Throwable, Issue1422Row], batchSize: Int = 10000): ZIO[ZConnection, Throwable, Long] +} diff --git a/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/issue142_2/Issue1422RepoImpl.scala b/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/issue142_2/Issue1422RepoImpl.scala new file mode 100644 index 000000000..88d88fdb6 --- /dev/null +++ b/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/issue142_2/Issue1422RepoImpl.scala @@ -0,0 +1,83 @@ +/** + * File has been automatically generated by `typo`. + * + * IF YOU CHANGE THIS FILE YOUR CHANGES WILL BE OVERWRITTEN. + */ +package adventureworks +package public +package issue142_2 + +import adventureworks.public.issue142.Issue142Id +import typo.dsl.DeleteBuilder +import typo.dsl.SelectBuilder +import typo.dsl.SelectBuilderSql +import typo.dsl.UpdateBuilder +import zio.ZIO +import zio.jdbc.SqlFragment.Segment +import zio.jdbc.UpdateResult +import zio.jdbc.ZConnection +import zio.jdbc.sqlInterpolator +import zio.stream.ZStream + +class Issue1422RepoImpl extends Issue1422Repo { + override def delete: DeleteBuilder[Issue1422Fields, Issue1422Row] = { + DeleteBuilder(""""public"."issue142_2"""", Issue1422Fields.structure) + } + override def deleteById(tabellkode: Issue142Id): ZIO[ZConnection, Throwable, Boolean] = { + sql"""delete from "public"."issue142_2" where "tabellkode" = ${Segment.paramSegment(tabellkode)(Issue142Id.setter)}""".delete.map(_ > 0) + } + override def deleteByIds(tabellkodes: Array[Issue142Id]): ZIO[ZConnection, Throwable, Long] = { + sql"""delete from "public"."issue142_2" where "tabellkode" = ANY(${tabellkodes})""".delete + } + override def insert(unsaved: Issue1422Row): ZIO[ZConnection, Throwable, Issue1422Row] = { + sql"""insert into "public"."issue142_2"("tabellkode") + values (${Segment.paramSegment(unsaved.tabellkode)(Issue142Id.setter)}) + returning "tabellkode" + """.insertReturning(using Issue1422Row.jdbcDecoder).map(_.updatedKeys.head) + } + override def insertStreaming(unsaved: ZStream[ZConnection, Throwable, Issue1422Row], batchSize: Int = 10000): ZIO[ZConnection, Throwable, Long] = { + streamingInsert(s"""COPY "public"."issue142_2"("tabellkode") FROM STDIN""", batchSize, unsaved)(Issue1422Row.text) + } + override def select: SelectBuilder[Issue1422Fields, Issue1422Row] = { + SelectBuilderSql(""""public"."issue142_2"""", Issue1422Fields.structure, Issue1422Row.jdbcDecoder) + } + override def selectAll: ZStream[ZConnection, Throwable, Issue1422Row] = { + sql"""select "tabellkode" from "public"."issue142_2"""".query(using Issue1422Row.jdbcDecoder).selectStream() + } + override def selectById(tabellkode: Issue142Id): ZIO[ZConnection, Throwable, Option[Issue1422Row]] = { + sql"""select "tabellkode" from "public"."issue142_2" where "tabellkode" = ${Segment.paramSegment(tabellkode)(Issue142Id.setter)}""".query(using Issue1422Row.jdbcDecoder).selectOne + } + override def selectByIds(tabellkodes: Array[Issue142Id]): ZStream[ZConnection, Throwable, Issue1422Row] = { + sql"""select "tabellkode" from "public"."issue142_2" where "tabellkode" = ANY(${Segment.paramSegment(tabellkodes)(Issue142Id.arraySetter)})""".query(using Issue1422Row.jdbcDecoder).selectStream() + } + override def selectByIdsTracked(tabellkodes: Array[Issue142Id]): ZIO[ZConnection, Throwable, Map[Issue142Id, Issue1422Row]] = { + selectByIds(tabellkodes).runCollect.map { rows => + val byId = rows.view.map(x => (x.tabellkode, x)).toMap + tabellkodes.view.flatMap(id => byId.get(id).map(x => (id, x))).toMap + } + } + override def update: UpdateBuilder[Issue1422Fields, Issue1422Row] = { + UpdateBuilder(""""public"."issue142_2"""", Issue1422Fields.structure, Issue1422Row.jdbcDecoder) + } + override def upsert(unsaved: Issue1422Row): ZIO[ZConnection, Throwable, UpdateResult[Issue1422Row]] = { + sql"""insert into "public"."issue142_2"("tabellkode") + values ( + ${Segment.paramSegment(unsaved.tabellkode)(Issue142Id.setter)} + ) + on conflict ("tabellkode") + do nothing + returning "tabellkode"""".insertReturning(using Issue1422Row.jdbcDecoder) + } + /* NOTE: this functionality is not safe if you use auto-commit mode! it runs 3 SQL statements */ + override def upsertStreaming(unsaved: ZStream[ZConnection, Throwable, Issue1422Row], batchSize: Int = 10000): ZIO[ZConnection, Throwable, Long] = { + val created = sql"""create temporary table issue142_2_TEMP (like "public"."issue142_2") on commit drop""".execute + val copied = streamingInsert(s"""copy issue142_2_TEMP("tabellkode") from stdin""", batchSize, unsaved)(Issue1422Row.text) + val merged = sql"""insert into "public"."issue142_2"("tabellkode") + select * from issue142_2_TEMP + on conflict ("tabellkode") + do nothing + ; + drop table issue142_2_TEMP;""".update + created *> copied *> merged + } +} diff --git a/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/issue142_2/Issue1422RepoMock.scala b/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/issue142_2/Issue1422RepoMock.scala new file mode 100644 index 000000000..7717f408d --- /dev/null +++ b/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/issue142_2/Issue1422RepoMock.scala @@ -0,0 +1,92 @@ +/** + * File has been automatically generated by `typo`. + * + * IF YOU CHANGE THIS FILE YOUR CHANGES WILL BE OVERWRITTEN. + */ +package adventureworks +package public +package issue142_2 + +import adventureworks.public.issue142.Issue142Id +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 +import zio.Chunk +import zio.ZIO +import zio.jdbc.UpdateResult +import zio.jdbc.ZConnection +import zio.stream.ZStream + +class Issue1422RepoMock(map: scala.collection.mutable.Map[Issue142Id, Issue1422Row] = scala.collection.mutable.Map.empty) extends Issue1422Repo { + override def delete: DeleteBuilder[Issue1422Fields, Issue1422Row] = { + DeleteBuilderMock(DeleteParams.empty, Issue1422Fields.structure, map) + } + override def deleteById(tabellkode: Issue142Id): ZIO[ZConnection, Throwable, Boolean] = { + ZIO.succeed(map.remove(tabellkode).isDefined) + } + override def deleteByIds(tabellkodes: Array[Issue142Id]): ZIO[ZConnection, Throwable, Long] = { + ZIO.succeed(tabellkodes.map(id => map.remove(id)).count(_.isDefined).toLong) + } + override def insert(unsaved: Issue1422Row): ZIO[ZConnection, Throwable, Issue1422Row] = { + ZIO.succeed { + val _ = + if (map.contains(unsaved.tabellkode)) + sys.error(s"id ${unsaved.tabellkode} already exists") + else + map.put(unsaved.tabellkode, unsaved) + + unsaved + } + } + override def insertStreaming(unsaved: ZStream[ZConnection, Throwable, Issue1422Row], batchSize: Int = 10000): ZIO[ZConnection, Throwable, Long] = { + unsaved.scanZIO(0L) { case (acc, row) => + ZIO.succeed { + map += (row.tabellkode -> row) + acc + 1 + } + }.runLast.map(_.getOrElse(0L)) + } + override def select: SelectBuilder[Issue1422Fields, Issue1422Row] = { + SelectBuilderMock(Issue1422Fields.structure, ZIO.succeed(Chunk.fromIterable(map.values)), SelectParams.empty) + } + override def selectAll: ZStream[ZConnection, Throwable, Issue1422Row] = { + ZStream.fromIterable(map.values) + } + override def selectById(tabellkode: Issue142Id): ZIO[ZConnection, Throwable, Option[Issue1422Row]] = { + ZIO.succeed(map.get(tabellkode)) + } + override def selectByIds(tabellkodes: Array[Issue142Id]): ZStream[ZConnection, Throwable, Issue1422Row] = { + ZStream.fromIterable(tabellkodes.flatMap(map.get)) + } + override def selectByIdsTracked(tabellkodes: Array[Issue142Id]): ZIO[ZConnection, Throwable, Map[Issue142Id, Issue1422Row]] = { + selectByIds(tabellkodes).runCollect.map { rows => + val byId = rows.view.map(x => (x.tabellkode, x)).toMap + tabellkodes.view.flatMap(id => byId.get(id).map(x => (id, x))).toMap + } + } + override def update: UpdateBuilder[Issue1422Fields, Issue1422Row] = { + UpdateBuilderMock(UpdateParams.empty, Issue1422Fields.structure, map) + } + override def upsert(unsaved: Issue1422Row): ZIO[ZConnection, Throwable, UpdateResult[Issue1422Row]] = { + ZIO.succeed { + map.put(unsaved.tabellkode, unsaved): @nowarn + UpdateResult(1, Chunk.single(unsaved)) + } + } + /* NOTE: this functionality is not safe if you use auto-commit mode! it runs 3 SQL statements */ + override def upsertStreaming(unsaved: ZStream[ZConnection, Throwable, Issue1422Row], batchSize: Int = 10000): ZIO[ZConnection, Throwable, Long] = { + unsaved.scanZIO(0L) { case (acc, row) => + ZIO.succeed { + map += (row.tabellkode -> row) + acc + 1 + } + }.runLast.map(_.getOrElse(0L)) + } +} diff --git a/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/issue142_2/Issue1422Row.scala b/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/issue142_2/Issue1422Row.scala new file mode 100644 index 000000000..c5bb5fd80 --- /dev/null +++ b/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/issue142_2/Issue1422Row.scala @@ -0,0 +1,45 @@ +/** + * File has been automatically generated by `typo`. + * + * IF YOU CHANGE THIS FILE YOUR CHANGES WILL BE OVERWRITTEN. + */ +package adventureworks +package public +package issue142_2 + +import adventureworks.public.issue142.Issue142Id +import zio.jdbc.JdbcDecoder +import zio.json.JsonDecoder +import zio.json.JsonEncoder +import zio.json.ast.Json +import zio.json.internal.Write + +/** Table: public.issue142_2 + Primary key: tabellkode */ +case class Issue1422Row( + /** Points to [[issue142.Issue142Row.tabellkode]] */ + tabellkode: Issue142Id +){ + val id = tabellkode + } + +object Issue1422Row { + implicit lazy val jdbcDecoder: JdbcDecoder[Issue1422Row] = Issue142Id.jdbcDecoder.map(v => Issue1422Row(tabellkode = v)) + implicit lazy val jsonDecoder: JsonDecoder[Issue1422Row] = JsonDecoder[Json.Obj].mapOrFail { jsonObj => + val tabellkode = jsonObj.get("tabellkode").toRight("Missing field 'tabellkode'").flatMap(_.as(Issue142Id.jsonDecoder)) + if (tabellkode.isRight) + Right(Issue1422Row(tabellkode = tabellkode.toOption.get)) + else Left(List[Either[String, Any]](tabellkode).flatMap(_.left.toOption).mkString(", ")) + } + implicit lazy val jsonEncoder: JsonEncoder[Issue1422Row] = new JsonEncoder[Issue1422Row] { + override def unsafeEncode(a: Issue1422Row, indent: Option[Int], out: Write): Unit = { + out.write("{") + out.write(""""tabellkode":""") + Issue142Id.jsonEncoder.unsafeEncode(a.tabellkode, indent, out) + out.write("}") + } + } + implicit lazy val text: Text[Issue1422Row] = Text.instance[Issue1422Row]{ (row, sb) => + Issue142Id.text.unsafeEncode(row.tabellkode, sb) + } +} diff --git a/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/testInsert.scala b/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/testInsert.scala index e255a307c..cbf4631cb 100644 --- a/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/testInsert.scala +++ b/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/testInsert.scala @@ -204,6 +204,11 @@ import adventureworks.public.identity_test.IdentityTestId import adventureworks.public.identity_test.IdentityTestRepoImpl import adventureworks.public.identity_test.IdentityTestRow import adventureworks.public.identity_test.IdentityTestRowUnsaved +import adventureworks.public.issue142.Issue142Id +import adventureworks.public.issue142.Issue142RepoImpl +import adventureworks.public.issue142.Issue142Row +import adventureworks.public.issue142_2.Issue1422RepoImpl +import adventureworks.public.issue142_2.Issue1422Row import adventureworks.public.pgtest.PgtestRepoImpl import adventureworks.public.pgtest.PgtestRow import adventureworks.public.pgtestnull.PgtestnullRepoImpl @@ -644,6 +649,8 @@ class TestInsert(random: Random, domainInsert: TestDomainInsert) { parentspecifier: Option[ShortText] = None ): ZIO[ZConnection, Throwable, FlaffRow] = (new FlaffRepoImpl).insert(new FlaffRow(code = code, anotherCode = anotherCode, someNumber = someNumber, specifier = specifier, parentspecifier = parentspecifier)) def publicIdentityTest(name: IdentityTestId, defaultGenerated: Defaulted[Int] = Defaulted.UseDefault): ZIO[ZConnection, Throwable, IdentityTestRow] = (new IdentityTestRepoImpl).insert(new IdentityTestRowUnsaved(name = name, defaultGenerated = defaultGenerated)) + def publicIssue142(tabellkode: Issue142Id = Issue142Id(random.alphanumeric.take(20).mkString)): ZIO[ZConnection, Throwable, Issue142Row] = (new Issue142RepoImpl).insert(new Issue142Row(tabellkode = tabellkode)) + def publicIssue1422(tabellkode: Issue142Id = Issue142Id.All(random.nextInt(2))): ZIO[ZConnection, Throwable, Issue1422Row] = (new Issue1422RepoImpl).insert(new Issue1422Row(tabellkode = tabellkode)) def publicPgtest(box: TypoBox, bytea: TypoBytea, circle: TypoCircle, diff --git a/typo/src/scala/typo/internal/ComputedTestInserts.scala b/typo/src/scala/typo/internal/ComputedTestInserts.scala index 7c9cf9377..7f3af1607 100644 --- a/typo/src/scala/typo/internal/ComputedTestInserts.scala +++ b/typo/src/scala/typo/internal/ComputedTestInserts.scala @@ -48,7 +48,7 @@ object ComputedTestInserts { case tpe if tableUnaryId.exists(_.tpe == tpe) => tableUnaryId.get match { case x: IdComputed.UnaryNormal => go(x.underlying, x.col.dbCol.tpe, None).map(default => code"${x.tpe}($default)") - case x: IdComputed.UnaryInherited => go(x.underlying, x.col.dbCol.tpe, None).map(default => code"${x.tpe}($default)") + case x: IdComputed.UnaryInherited => go(x.underlying, x.col.dbCol.tpe, None) case x: IdComputed.UnaryNoIdType => go(x.underlying, x.col.dbCol.tpe, None) case x: IdComputed.UnaryOpenEnum => go(x.underlying, x.col.dbCol.tpe, None).map(default => code"${x.tpe}($default)") case _: IdComputed.UnaryUserSpecified => None