diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000000..58e448cce2 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,321 @@ +# Typo - Type-Safe PostgreSQL Code Generator for Scala + +## Project Overview + +Typo is a PostgreSQL-specific code generator that creates type-safe Scala code from database schemas. It follows a "SQL is King" philosophy, generating strongly-typed database access code that works with popular Scala database libraries (Anorm, Doobie, ZIO-JDBC). + +## Architecture + +### Core Components +- **`typo/`** - Main code generator with database introspection and code generation +- **`typo-dsl-*`** - DSL implementations for different database libraries +- **`typo-runtime-*`** - Runtime support libraries for generated code +- **`typo-tester-*`** - Test projects demonstrating generated code usage + +### Key Philosophy +- SQL files are first-class citizens (stored in dedicated `.sql` files) +- Type safety propagates through foreign key relationships +- Generates idiomatic Scala code for each supported database library +- PostgreSQL-specific optimizations and type support + +## Build System - Bleep + +This project uses **Bleep** (https://github.com/oyvindberg/bleep) as the build tool: + +### Common Commands +```bash +# Compile all projects +bleep compile + +# Run tests +bleep test + +# Run specific test project +bleep test typo-tester-anorm + +# Run code generation scripts +bleep run GeneratedAdventureWorks +bleep run GeneratedAdventureWorks -- --watch # Watch mode for SQL files + +# Cross-compile for different Scala versions +bleep compile @jvm212 # Scala 2.12 +bleep compile @jvm213 # Scala 2.13 +bleep compile @jvm3 # Scala 3.3 +``` + +### Key Scripts (defined in bleep.yaml) +- **`GeneratedAdventureWorks`** - Main code generation from AdventureWorks DB +- **`GeneratedSources`** - Generate Typo's internal code from database +- **`GenHardcodedFiles`** - Generate test fixtures without database +- **`GenerateDocumentation`** - Generate documentation using mdoc + +## Development Environment + +### Database Setup +```bash +# Start PostgreSQL with test data +docker-compose up -d + +# Database runs on localhost:6432 +# Database: Adventureworks +# User: postgres +# Password: password +``` + +### Generated Code Structure +- **Row Classes** - Case classes mirroring table structure +- **ID Types** - Strongly-typed primary keys (e.g., `UserId(value: Long)`) +- **Repository Interfaces** - Complete CRUD operations +- **Unsaved Row Types** - For insertions with default handling +- **SQL DSL** - Type-safe query building (optional) + +## Code Generation Process + +### Main Generation Script (scripts/GeneratedAdventureWorks.scala) +```scala +// Basic setup +val options = typo.Options( + pkg = "adventureworks", + dbLib = typo.DbLib.Anorm, + jsonLib = typo.JsonLib.PlayJson, + enablePrimaryKeyType = true, + enableTestInserts = true +) + +// Generate code +typo.generate(options, db, sqlFiles, folder) +``` + +### Key Configuration Options +- `pkg` - Base package name +- `dbLib` - Database library (Anorm, Doobie, ZioJdbc) +- `jsonLib` - JSON library (PlayJson, Circe, ZioJson) +- `enablePrimaryKeyType` - Generate type-safe ID types +- `enableTestInserts` - Generate test data helpers +- `enableDsl` - Generate SQL DSL +- `generateMockRepos` - Generate mock implementations + +### Type Overrides +```scala +// Custom type mappings +TypeOverride.relation { + case (_, "firstname") => "adventureworks.userdefined.FirstName" + case ("sales.creditcard", "creditcardid") => "adventureworks.userdefined.CustomCreditcardId" +} + +// Nullability overrides +NullabilityOverride.relation { + case (_, "column_name") => Nullability.NoNulls +} +``` + +## Testing + +### Test Structure +- **Unit Tests** - Individual repository methods +- **Integration Tests** - Real database operations +- **DSL Tests** - Type-safe query DSL +- **Snapshot Tests** - Generated SQL verification + +### TestInsert Pattern +```scala +// Generated test data factory +val testInsert = new TestInsert(new Random(0), DomainInsert) +val productCategory = testInsert.productionProductcategory() +val product = testInsert.productionProduct(productcategory = productCategory.productcategoryid) +``` + +### Running Tests +```bash +# All tests (transactional, rolled back) +bleep test + +# Specific test class +bleep test --only DepartmentTest + +# Watch mode +bleep test --watch +``` + +## SQL Files Integration + +### SQL File Syntax +```sql +-- Parameters: :param_name:type! (required), :param_name:type? (optional) +SELECT p.productid, p.name as product_name! +FROM production.product p +WHERE p.productcategory = :category_id:adventureworks.production.productcategory.ProductcategoryId! +``` + +### Type Annotations +- `!` suffix - Column is non-null +- `?` suffix - Parameter is optional +- Custom types reference generated types + +## Key Features + +### Type Safety +- **Type Flow** - Foreign key relationships propagate specific types +- **ID Types** - Prevents mixing different entity IDs +- **Nullability Inference** - Comprehensive null-safety analysis +- **Custom Types** - Support for PostgreSQL domains, enums, arrays + +### SQL DSL Example +```scala +// Type-safe query building +val query = select + .from(person) + .join(address) + .on(person.addressid, address.addressid) + .where(person.firstname.like("John%")) + .orderBy(person.lastname.asc) + .limit(10) +``` + +### Generated Repository Methods +```scala +// CRUD operations +def insert(unsaved: PersonRowUnsaved): PersonRow +def update(row: PersonRow): Boolean +def delete(id: PersonId): Boolean +def selectAll: List[PersonRow] +def selectById(id: PersonId): Option[PersonRow] +``` + +## Development Workflow + +### Making Changes +1. **Code Generation Changes** - Modify scripts in `scripts/` +2. **Core Changes** - Edit `typo/` source code +3. **Test Changes** - Update test files in `typo-tester-*` +4. **Documentation** - Update files in `site-in/` + +### Regenerating Code +```bash +# Watch for SQL file changes and regenerate +bleep run GeneratedAdventureWorks -- --watch + +# Regenerate test fixtures +bleep run GenHardcodedFiles + +# Regenerate documentation +bleep run GenerateDocumentation +``` + +### Testing Changes +```bash +# Test specific database library +bleep test typo-tester-anorm +bleep test typo-tester-doobie +bleep test typo-tester-zio-jdbc + +# Test core functionality +bleep test typo +``` + +## Documentation + +### Building Documentation Site +```bash +cd site +npm install +npm run build +npm run serve +``` + +### Documentation Structure +- **`site-in/`** - Source markdown files +- **`site/`** - Generated Docusaurus site +- **Type Safety** - Documentation on type system features +- **Customization** - Guides for customizing generation +- **Patterns** - Common usage patterns + +## Common Tasks + +### Adding New Database Library Support +1. Create `typo-dsl-newlib` module +2. Create `typo-runtime-newlib` module +3. Add to `DbLib` enum in core +4. Implement code generation templates +5. Add test project `typo-tester-newlib` + +### Adding New PostgreSQL Type Support +1. Add to `PgType` enum +2. Update type mapping in `ScalaType` +3. Add runtime support if needed +4. Update tests and documentation + +### Debugging Generated Code +- Generated code is in `generated-and-checked-in/` directories +- Use `--watch` mode to see changes in real-time +- Check `bleep.yaml` for script configurations +- Use database introspection tools to verify schema + +## Troubleshooting + +### Common Issues +- **Database Connection** - Ensure PostgreSQL is running on port 6432 +- **Generated Code Compilation** - Check type overrides and nullability settings +- **SQL File Syntax** - Verify parameter syntax and type annotations +- **Bleep Issues** - Check `bleep.yaml` syntax and script configurations + +### Debug Commands +```bash +# Check database connection +psql -h localhost -p 6432 -U postgres -d Adventureworks + +# Verify generated code +find . -name "generated-and-checked-in" -type d + +# Check Bleep configuration +bleep projects --json +``` + +This project represents a sophisticated approach to type-safe database access in Scala, with comprehensive tooling and extensive test coverage. + +## Development Workflow + +When working on Typo issues, follow this workflow: + +1. **Create Test Case**: Add a minimal reproduction SQL file in `init/data/issueNNN.sql` +2. **Update Install Script**: Add the SQL file to `init/install.sh` +3. **Restart Database**: Run `docker-compose down && docker-compose up -d` +4. **Generate Code**: Run `bleep generate-adventureworks` to generate test code +5. **Trace Issue**: Examine generated code to understand the problem +6. **Commit Test Setup**: Always commit the test setup before making changes +7. **Implement Fix**: Make necessary code changes +8. **Format Code**: Always run `bleep fmt` before testing +9. **Run Tests**: Always run `bleep test` before committing +10. **Commit Fix**: Commit with descriptive message referencing the issue + +### Debugging and Development Approach + +**General Problem-Solving Process**: +1. **Create Minimal Reproduction**: Add minimal test case to `init/data/issueNNN.sql` +2. **Set up Test Environment**: Update `init/install.sh`, restart database, regenerate code +3. **Understand the Issue**: Trace through generated code to identify root cause +4. **Test-Driven Development**: + - Add debug logging to capture relevant data + - Create comprehensive test suite covering edge cases + - Use static test data based on debug output + - Implement fix and verify all tests pass +5. **Code Quality**: Always run `bleep fmt` and `bleep test` before committing +6. **Commit**: Clear commit message referencing the issue number + +**Debug Techniques**: +- **Temporary Logging**: Add `println` statements to capture runtime data +- **Static Analysis**: Read generated code to understand behavior +- **Test Coverage**: Create tests for various scenarios (different names, ordering, edge cases) +- **Incremental Testing**: Verify each component works in isolation + +**Code Generation Issues**: +- **Schema Analysis**: Use database introspection to understand relationships +- **AST Manipulation**: Modify code generation trees (`sc.Code`, `sc.Type`, etc.) +- **Template Generation**: Update generation logic in core modules +- **Verification**: Check generated code produces expected output + +**Testing Strategy**: +- **Unit Tests**: Test individual components in isolation +- **Integration Tests**: Test full generation pipeline +- **Regression Tests**: Ensure fixes don't break existing functionality +- **Edge Case Coverage**: Test boundary conditions and unusual schemas diff --git a/init/data/issue148.sql b/init/data/issue148.sql new file mode 100644 index 0000000000..bf6d08b971 --- /dev/null +++ b/init/data/issue148.sql @@ -0,0 +1,23 @@ +-- Issue #148: Fix FK column mapping +-- https://github.com/oyvindberg/typo/issues/148 + +CREATE TABLE test_organisasjon ( + organisasjonskode text NOT NULL, + PRIMARY KEY (organisasjonskode) +); + +CREATE TABLE test_utdanningstilbud ( + organisasjonskode text NOT NULL, + utdanningsmulighet_kode text NOT NULL, + PRIMARY KEY (organisasjonskode, utdanningsmulighet_kode), + FOREIGN KEY (organisasjonskode) REFERENCES test_organisasjon (organisasjonskode) +); + +CREATE TABLE test_sak_soknadsalternativ ( + organisasjonskode_saksbehandler text NOT NULL, + utdanningsmulighet_kode text NOT NULL, + organisasjonskode_tilbyder text NOT NULL, + PRIMARY KEY (organisasjonskode_saksbehandler, utdanningsmulighet_kode), + FOREIGN KEY (organisasjonskode_tilbyder, utdanningsmulighet_kode) + REFERENCES test_utdanningstilbud (organisasjonskode, utdanningsmulighet_kode) +); \ No newline at end of file diff --git a/init/install.sh b/init/install.sh index 3f58004319..e87d36257c 100755 --- a/init/install.sh +++ b/init/install.sh @@ -11,3 +11,4 @@ psql -d Adventureworks < /docker-entrypoint-initdb.d/data/install.sql # this should have had a database by itself, but let's be lazy for now psql -d Adventureworks < /docker-entrypoint-initdb.d/data/test-tables.sql +psql -d Adventureworks < /docker-entrypoint-initdb.d/data/issue148.sql diff --git a/tests/src/scala/typo/internal/FkAnalysisTest.scala b/tests/src/scala/typo/internal/FkAnalysisTest.scala new file mode 100644 index 0000000000..20b2fd5eb1 --- /dev/null +++ b/tests/src/scala/typo/internal/FkAnalysisTest.scala @@ -0,0 +1,215 @@ +package typo.internal + +import typo.{NonEmptyList, Nullability, db, sc} +import typo.internal.analysis.* +import org.scalatest.funsuite.AnyFunSuite +import org.scalatest.matchers.should.Matchers + +import scala.annotation.nowarn + +class FkAnalysisTest extends AnyFunSuite with Matchers { + + test("FK column mapping for issue #148 - different column names") { + // Based on debug output: test_utdanningstilbud FK with different column names + // FK: (organisasjonskode_tilbyder, utdanningsmulighet_kode) -> (organisasjonskode, utdanningsmulighet_kode) + + val thisFkCols = NonEmptyList(db.ColName("organisasjonskode_tilbyder"), List(db.ColName("utdanningsmulighet_kode"))) + val thisFkOtherCols = NonEmptyList(db.ColName("organisasjonskode"), List(db.ColName("utdanningsmulighet_kode"))) + + val organisasjonskodeCol = createComputedColumn("organisasjonskode", "organisasjonskode") + val utdanningsmulighetKodeCol = createComputedColumn("utdanningsmulighetKode", "utdanningsmulighet_kode") + + val utdanningsmulighetKodeThisCol = createComputedColumn("utdanningsmulighetKode", "utdanningsmulighet_kode") + + val originalOtherIdCols = NonEmptyList(organisasjonskodeCol, List(utdanningsmulighetKodeCol)) + val thisColumns = List(utdanningsmulighetKodeThisCol) + + val fk = db.ForeignKey( + cols = thisFkCols, + otherTable = db.RelationName(Some("public"), "test_utdanningstilbud"), + otherCols = thisFkOtherCols, + constraintName = db.RelationName(Some("public"), "test_sak_soknadsalternativ_organisasjonskode_tilbyder_utda_fkey") + ) + + val candidateFk = FkAnalysis.CandidateFk( + thisFk = fk, + otherTable = null, + otherId = IdComputed.Composite( + originalOtherIdCols, + createQualifiedType("TestUtdanningstilbudId"), + createIdent("testUtdanningstilbudId") + ) + ) + + val colsFromFk = FkAnalysis.ColsFromFk(candidateFk.otherId, thisColumns, candidateFk) + + val expr = colsFromFk.expr + assert(expr.size == 1): @nowarn + assert(expr.keys.head.value == "utdanningsmulighetKode"): @nowarn + + // The key fix: should map to utdanningsmulighetKode, not organisasjonskode + val expectedExpr = s"${colsFromFk.param.name.value}.utdanningsmulighetKode" + assert(expr.values.head.render.asString == expectedExpr) + } + + test("FK column mapping for both columns - different column names") { + // Test case where both columns are mapped (organisasjonskodeTilbyder, utdanningsmulighetKode) + + val thisFkCols = NonEmptyList(db.ColName("organisasjonskode_tilbyder"), List(db.ColName("utdanningsmulighet_kode"))) + val thisFkOtherCols = NonEmptyList(db.ColName("organisasjonskode"), List(db.ColName("utdanningsmulighet_kode"))) + + val organisasjonskodeCol = createComputedColumn("organisasjonskode", "organisasjonskode") + val utdanningsmulighetKodeCol = createComputedColumn("utdanningsmulighetKode", "utdanningsmulighet_kode") + + val organisasjonskodeTilbyderCol = createComputedColumn("organisasjonskodeTilbyder", "organisasjonskode_tilbyder") + val utdanningsmulighetKodeThisCol = createComputedColumn("utdanningsmulighetKode", "utdanningsmulighet_kode") + + val originalOtherIdCols = NonEmptyList(organisasjonskodeCol, List(utdanningsmulighetKodeCol)) + val thisColumns = List(organisasjonskodeTilbyderCol, utdanningsmulighetKodeThisCol) + + val fk = db.ForeignKey( + cols = thisFkCols, + otherTable = db.RelationName(Some("public"), "test_utdanningstilbud"), + otherCols = thisFkOtherCols, + constraintName = db.RelationName(Some("public"), "test_sak_soknadsalternativ_organisasjonskode_tilbyder_utda_fkey") + ) + + val candidateFk = FkAnalysis.CandidateFk( + thisFk = fk, + otherTable = null, + otherId = IdComputed.Composite( + originalOtherIdCols, + createQualifiedType("TestUtdanningstilbudId"), + createIdent("testUtdanningstilbudId") + ) + ) + + val colsFromFk = FkAnalysis.ColsFromFk(candidateFk.otherId, thisColumns, candidateFk) + + val expr = colsFromFk.expr + assert(expr.size == 2): @nowarn + + // Both columns should map correctly + assert(expr(createIdent("organisasjonskodeTilbyder")).render.asString == s"${colsFromFk.param.name.value}.organisasjonskode"): @nowarn + assert(expr(createIdent("utdanningsmulighetKode")).render.asString == s"${colsFromFk.param.name.value}.utdanningsmulighetKode") + } + + test("FK column mapping for identical column names") { + // Test case from specialofferproduct - columns have same names + // FK: (specialofferid, productid) -> (specialofferid, productid) + + val thisFkCols = NonEmptyList(db.ColName("specialofferid"), List(db.ColName("productid"))) + val thisFkOtherCols = NonEmptyList(db.ColName("specialofferid"), List(db.ColName("productid"))) + + val specialofferidCol = createComputedColumn("specialofferid", "specialofferid") + val productidCol = createComputedColumn("productid", "productid") + + val specialofferidThisCol = createComputedColumn("specialofferid", "specialofferid") + val productidThisCol = createComputedColumn("productid", "productid") + + val originalOtherIdCols = NonEmptyList(specialofferidCol, List(productidCol)) + val thisColumns = List(specialofferidThisCol, productidThisCol) + + val fk = db.ForeignKey( + cols = thisFkCols, + otherTable = db.RelationName(Some("sales"), "specialofferproduct"), + otherCols = thisFkOtherCols, + constraintName = db.RelationName(Some("sales"), "FK_SalesOrderDetail_SpecialOfferProduct_SpecialOfferIDProductID") + ) + + val candidateFk = FkAnalysis.CandidateFk( + thisFk = fk, + otherTable = null, + otherId = IdComputed.Composite( + originalOtherIdCols, + createQualifiedType("SpecialofferproductId"), + createIdent("specialofferproductId") + ) + ) + + val colsFromFk = FkAnalysis.ColsFromFk(candidateFk.otherId, thisColumns, candidateFk) + + val expr = colsFromFk.expr + assert(expr.size == 2): @nowarn + + // Should map correctly even with identical names + assert(expr(createIdent("specialofferid")).render.asString == s"${colsFromFk.param.name.value}.specialofferid"): @nowarn + assert(expr(createIdent("productid")).render.asString == s"${colsFromFk.param.name.value}.productid") + } + + test("FK column mapping with reordered columns") { + // Test case where FK columns are in different order than PK columns + + val thisFkCols = NonEmptyList(db.ColName("col_b"), List(db.ColName("col_a"))) + val thisFkOtherCols = NonEmptyList(db.ColName("pk_b"), List(db.ColName("pk_a"))) + + val pkACol = createComputedColumn("pkA", "pk_a") + val pkBCol = createComputedColumn("pkB", "pk_b") + + val colAThisCol = createComputedColumn("colA", "col_a") + val colBThisCol = createComputedColumn("colB", "col_b") + + // Other table has PK in (pk_a, pk_b) order + val originalOtherIdCols = NonEmptyList(pkACol, List(pkBCol)) + // This table has FK in (col_b, col_a) order + val thisColumns = List(colBThisCol, colAThisCol) + + val fk = db.ForeignKey( + cols = thisFkCols, + otherTable = db.RelationName(Some("public"), "other_table"), + otherCols = thisFkOtherCols, + constraintName = db.RelationName(Some("public"), "fk_reordered") + ) + + val candidateFk = FkAnalysis.CandidateFk( + thisFk = fk, + otherTable = null, + otherId = IdComputed.Composite( + originalOtherIdCols, + createQualifiedType("OtherTableId"), + createIdent("otherTableId") + ) + ) + + val colsFromFk = FkAnalysis.ColsFromFk(candidateFk.otherId, thisColumns, candidateFk) + + val expr = colsFromFk.expr + assert(expr.size == 2): @nowarn + + // Should map correctly despite reordering + assert(expr(createIdent("colB")).render.asString == s"${colsFromFk.param.name.value}.pkB"): @nowarn + assert(expr(createIdent("colA")).render.asString == s"${colsFromFk.param.name.value}.pkA") + } + + // Helper methods for creating test objects + private def createComputedColumn(name: String, dbName: String): ComputedColumn = { + ComputedColumn( + pointsTo = List.empty, + name = createIdent(name), + tpe = createQualifiedType("String"), + dbCol = createDbCol(dbName) + ) + } + + private def createIdent(name: String): sc.Ident = { + sc.Ident(name) + } + + private def createQualifiedType(name: String): sc.Type.Qualified = { + sc.Type.Qualified(sc.QIdent(List(sc.Ident(name)))) + } + + private def createDbCol(name: String): db.Col = { + db.Col( + parsedName = ParsedName(db.ColName(name), db.ColName(name), None, None), + tpe = db.Type.Text, + udtName = None, + nullability = Nullability.NoNulls, + columnDefault = None, + maybeGenerated = None, + comment = None, + constraints = Nil, + jsonDescription = typo.internal.DebugJson.Empty + ) + } +} diff --git a/typo-tester-anorm/generated-and-checked-in/adventureworks/public/test_organisasjon/TestOrganisasjonFields.scala b/typo-tester-anorm/generated-and-checked-in/adventureworks/public/test_organisasjon/TestOrganisasjonFields.scala new file mode 100644 index 0000000000..e6198a24cb --- /dev/null +++ b/typo-tester-anorm/generated-and-checked-in/adventureworks/public/test_organisasjon/TestOrganisasjonFields.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 test_organisasjon + +import typo.dsl.Path +import typo.dsl.SqlExpr.FieldLikeNoHkt +import typo.dsl.SqlExpr.IdField +import typo.dsl.Structure.Relation + +trait TestOrganisasjonFields { + def organisasjonskode: IdField[TestOrganisasjonId, TestOrganisasjonRow] +} + +object TestOrganisasjonFields { + lazy val structure: Relation[TestOrganisasjonFields, TestOrganisasjonRow] = + new Impl(Nil) + + private final class Impl(val _path: List[Path]) + extends Relation[TestOrganisasjonFields, TestOrganisasjonRow] { + + override lazy val fields: TestOrganisasjonFields = new TestOrganisasjonFields { + override def organisasjonskode = IdField[TestOrganisasjonId, TestOrganisasjonRow](_path, "organisasjonskode", None, None, x => x.organisasjonskode, (row, value) => row.copy(organisasjonskode = value)) + } + + override lazy val columns: List[FieldLikeNoHkt[?, TestOrganisasjonRow]] = + List[FieldLikeNoHkt[?, TestOrganisasjonRow]](fields.organisasjonskode) + + override def copy(path: List[Path]): Impl = + new Impl(path) + } + +} diff --git a/typo-tester-anorm/generated-and-checked-in/adventureworks/public/test_organisasjon/TestOrganisasjonId.scala b/typo-tester-anorm/generated-and-checked-in/adventureworks/public/test_organisasjon/TestOrganisasjonId.scala new file mode 100644 index 0000000000..9c522a5f9a --- /dev/null +++ b/typo-tester-anorm/generated-and-checked-in/adventureworks/public/test_organisasjon/TestOrganisasjonId.scala @@ -0,0 +1,36 @@ +/** + * File has been automatically generated by `typo`. + * + * IF YOU CHANGE THIS FILE YOUR CHANGES WILL BE OVERWRITTEN. + */ +package adventureworks +package public +package test_organisasjon + +import anorm.Column +import anorm.ParameterMetaData +import anorm.ToStatement +import play.api.libs.json.Reads +import play.api.libs.json.Writes +import typo.dsl.Bijection + +/** Type for the primary key of table `public.test_organisasjon` */ +case class TestOrganisasjonId(value: String) extends AnyVal +object TestOrganisasjonId { + implicit lazy val arrayColumn: Column[Array[TestOrganisasjonId]] = Column.columnToArray(column, implicitly) + implicit lazy val arrayToStatement: ToStatement[Array[TestOrganisasjonId]] = ToStatement.arrayToParameter(ParameterMetaData.StringParameterMetaData).contramap(_.map(_.value)) + implicit lazy val bijection: Bijection[TestOrganisasjonId, String] = Bijection[TestOrganisasjonId, String](_.value)(TestOrganisasjonId.apply) + implicit lazy val column: Column[TestOrganisasjonId] = Column.columnToString.map(TestOrganisasjonId.apply) + implicit lazy val ordering: Ordering[TestOrganisasjonId] = Ordering.by(_.value) + implicit lazy val parameterMetadata: ParameterMetaData[TestOrganisasjonId] = new ParameterMetaData[TestOrganisasjonId] { + override def sqlType: String = ParameterMetaData.StringParameterMetaData.sqlType + override def jdbcType: Int = ParameterMetaData.StringParameterMetaData.jdbcType + } + implicit lazy val reads: Reads[TestOrganisasjonId] = Reads.StringReads.map(TestOrganisasjonId.apply) + implicit lazy val text: Text[TestOrganisasjonId] = new Text[TestOrganisasjonId] { + override def unsafeEncode(v: TestOrganisasjonId, sb: StringBuilder) = Text.stringInstance.unsafeEncode(v.value, sb) + override def unsafeArrayEncode(v: TestOrganisasjonId, sb: StringBuilder) = Text.stringInstance.unsafeArrayEncode(v.value, sb) + } + implicit lazy val toStatement: ToStatement[TestOrganisasjonId] = ToStatement.stringToStatement.contramap(_.value) + implicit lazy val writes: Writes[TestOrganisasjonId] = Writes.StringWrites.contramap(_.value) +} diff --git a/typo-tester-anorm/generated-and-checked-in/adventureworks/public/test_organisasjon/TestOrganisasjonRepo.scala b/typo-tester-anorm/generated-and-checked-in/adventureworks/public/test_organisasjon/TestOrganisasjonRepo.scala new file mode 100644 index 0000000000..c2467f2ddb --- /dev/null +++ b/typo-tester-anorm/generated-and-checked-in/adventureworks/public/test_organisasjon/TestOrganisasjonRepo.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 test_organisasjon + +import java.sql.Connection +import typo.dsl.DeleteBuilder +import typo.dsl.SelectBuilder +import typo.dsl.UpdateBuilder + +trait TestOrganisasjonRepo { + def delete: DeleteBuilder[TestOrganisasjonFields, TestOrganisasjonRow] + def deleteById(organisasjonskode: TestOrganisasjonId)(implicit c: Connection): Boolean + def deleteByIds(organisasjonskodes: Array[TestOrganisasjonId])(implicit c: Connection): Int + def insert(unsaved: TestOrganisasjonRow)(implicit c: Connection): TestOrganisasjonRow + def insertStreaming(unsaved: Iterator[TestOrganisasjonRow], batchSize: Int = 10000)(implicit c: Connection): Long + def select: SelectBuilder[TestOrganisasjonFields, TestOrganisasjonRow] + def selectAll(implicit c: Connection): List[TestOrganisasjonRow] + def selectById(organisasjonskode: TestOrganisasjonId)(implicit c: Connection): Option[TestOrganisasjonRow] + def selectByIds(organisasjonskodes: Array[TestOrganisasjonId])(implicit c: Connection): List[TestOrganisasjonRow] + def selectByIdsTracked(organisasjonskodes: Array[TestOrganisasjonId])(implicit c: Connection): Map[TestOrganisasjonId, TestOrganisasjonRow] + def update: UpdateBuilder[TestOrganisasjonFields, TestOrganisasjonRow] + def upsert(unsaved: TestOrganisasjonRow)(implicit c: Connection): TestOrganisasjonRow + def upsertBatch(unsaved: Iterable[TestOrganisasjonRow])(implicit c: Connection): List[TestOrganisasjonRow] + /* NOTE: this functionality is not safe if you use auto-commit mode! it runs 3 SQL statements */ + def upsertStreaming(unsaved: Iterator[TestOrganisasjonRow], batchSize: Int = 10000)(implicit c: Connection): Int +} diff --git a/typo-tester-anorm/generated-and-checked-in/adventureworks/public/test_organisasjon/TestOrganisasjonRepoImpl.scala b/typo-tester-anorm/generated-and-checked-in/adventureworks/public/test_organisasjon/TestOrganisasjonRepoImpl.scala new file mode 100644 index 0000000000..f5b5220496 --- /dev/null +++ b/typo-tester-anorm/generated-and-checked-in/adventureworks/public/test_organisasjon/TestOrganisasjonRepoImpl.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 test_organisasjon + +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 TestOrganisasjonRepoImpl extends TestOrganisasjonRepo { + override def delete: DeleteBuilder[TestOrganisasjonFields, TestOrganisasjonRow] = { + DeleteBuilder(""""public"."test_organisasjon"""", TestOrganisasjonFields.structure) + } + override def deleteById(organisasjonskode: TestOrganisasjonId)(implicit c: Connection): Boolean = { + SQL"""delete from "public"."test_organisasjon" where "organisasjonskode" = ${ParameterValue(organisasjonskode, null, TestOrganisasjonId.toStatement)}""".executeUpdate() > 0 + } + override def deleteByIds(organisasjonskodes: Array[TestOrganisasjonId])(implicit c: Connection): Int = { + SQL"""delete + from "public"."test_organisasjon" + where "organisasjonskode" = ANY(${organisasjonskodes}) + """.executeUpdate() + + } + override def insert(unsaved: TestOrganisasjonRow)(implicit c: Connection): TestOrganisasjonRow = { + SQL"""insert into "public"."test_organisasjon"("organisasjonskode") + values (${ParameterValue(unsaved.organisasjonskode, null, TestOrganisasjonId.toStatement)}) + returning "organisasjonskode" + """ + .executeInsert(TestOrganisasjonRow.rowParser(1).single) + + } + override def insertStreaming(unsaved: Iterator[TestOrganisasjonRow], batchSize: Int = 10000)(implicit c: Connection): Long = { + streamingInsert(s"""COPY "public"."test_organisasjon"("organisasjonskode") FROM STDIN""", batchSize, unsaved)(TestOrganisasjonRow.text, c) + } + override def select: SelectBuilder[TestOrganisasjonFields, TestOrganisasjonRow] = { + SelectBuilderSql(""""public"."test_organisasjon"""", TestOrganisasjonFields.structure, TestOrganisasjonRow.rowParser) + } + override def selectAll(implicit c: Connection): List[TestOrganisasjonRow] = { + SQL"""select "organisasjonskode" + from "public"."test_organisasjon" + """.as(TestOrganisasjonRow.rowParser(1).*) + } + override def selectById(organisasjonskode: TestOrganisasjonId)(implicit c: Connection): Option[TestOrganisasjonRow] = { + SQL"""select "organisasjonskode" + from "public"."test_organisasjon" + where "organisasjonskode" = ${ParameterValue(organisasjonskode, null, TestOrganisasjonId.toStatement)} + """.as(TestOrganisasjonRow.rowParser(1).singleOpt) + } + override def selectByIds(organisasjonskodes: Array[TestOrganisasjonId])(implicit c: Connection): List[TestOrganisasjonRow] = { + SQL"""select "organisasjonskode" + from "public"."test_organisasjon" + where "organisasjonskode" = ANY(${organisasjonskodes}) + """.as(TestOrganisasjonRow.rowParser(1).*) + + } + override def selectByIdsTracked(organisasjonskodes: Array[TestOrganisasjonId])(implicit c: Connection): Map[TestOrganisasjonId, TestOrganisasjonRow] = { + val byId = selectByIds(organisasjonskodes).view.map(x => (x.organisasjonskode, x)).toMap + organisasjonskodes.view.flatMap(id => byId.get(id).map(x => (id, x))).toMap + } + override def update: UpdateBuilder[TestOrganisasjonFields, TestOrganisasjonRow] = { + UpdateBuilder(""""public"."test_organisasjon"""", TestOrganisasjonFields.structure, TestOrganisasjonRow.rowParser) + } + override def upsert(unsaved: TestOrganisasjonRow)(implicit c: Connection): TestOrganisasjonRow = { + SQL"""insert into "public"."test_organisasjon"("organisasjonskode") + values ( + ${ParameterValue(unsaved.organisasjonskode, null, TestOrganisasjonId.toStatement)} + ) + on conflict ("organisasjonskode") + do update set "organisasjonskode" = EXCLUDED."organisasjonskode" + returning "organisasjonskode" + """ + .executeInsert(TestOrganisasjonRow.rowParser(1).single) + + } + override def upsertBatch(unsaved: Iterable[TestOrganisasjonRow])(implicit c: Connection): List[TestOrganisasjonRow] = { + def toNamedParameter(row: TestOrganisasjonRow): List[NamedParameter] = List( + NamedParameter("organisasjonskode", ParameterValue(row.organisasjonskode, null, TestOrganisasjonId.toStatement)) + ) + unsaved.toList match { + case Nil => Nil + case head :: rest => + new anorm.adventureworks.ExecuteReturningSyntax.Ops( + BatchSql( + s"""insert into "public"."test_organisasjon"("organisasjonskode") + values ({organisasjonskode}) + on conflict ("organisasjonskode") + do nothing + returning "organisasjonskode" + """, + toNamedParameter(head), + rest.map(toNamedParameter)* + ) + ).executeReturning(TestOrganisasjonRow.rowParser(1).*) + } + } + /* NOTE: this functionality is not safe if you use auto-commit mode! it runs 3 SQL statements */ + override def upsertStreaming(unsaved: Iterator[TestOrganisasjonRow], batchSize: Int = 10000)(implicit c: Connection): Int = { + SQL"""create temporary table test_organisasjon_TEMP (like "public"."test_organisasjon") on commit drop""".execute(): @nowarn + streamingInsert(s"""copy test_organisasjon_TEMP("organisasjonskode") from stdin""", batchSize, unsaved)(TestOrganisasjonRow.text, c): @nowarn + SQL"""insert into "public"."test_organisasjon"("organisasjonskode") + select * from test_organisasjon_TEMP + on conflict ("organisasjonskode") + do nothing + ; + drop table test_organisasjon_TEMP;""".executeUpdate() + } +} diff --git a/typo-tester-anorm/generated-and-checked-in/adventureworks/public/test_organisasjon/TestOrganisasjonRepoMock.scala b/typo-tester-anorm/generated-and-checked-in/adventureworks/public/test_organisasjon/TestOrganisasjonRepoMock.scala new file mode 100644 index 0000000000..af047dafb1 --- /dev/null +++ b/typo-tester-anorm/generated-and-checked-in/adventureworks/public/test_organisasjon/TestOrganisasjonRepoMock.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 test_organisasjon + +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 TestOrganisasjonRepoMock(map: scala.collection.mutable.Map[TestOrganisasjonId, TestOrganisasjonRow] = scala.collection.mutable.Map.empty) extends TestOrganisasjonRepo { + override def delete: DeleteBuilder[TestOrganisasjonFields, TestOrganisasjonRow] = { + DeleteBuilderMock(DeleteParams.empty, TestOrganisasjonFields.structure, map) + } + override def deleteById(organisasjonskode: TestOrganisasjonId)(implicit c: Connection): Boolean = { + map.remove(organisasjonskode).isDefined + } + override def deleteByIds(organisasjonskodes: Array[TestOrganisasjonId])(implicit c: Connection): Int = { + organisasjonskodes.map(id => map.remove(id)).count(_.isDefined) + } + override def insert(unsaved: TestOrganisasjonRow)(implicit c: Connection): TestOrganisasjonRow = { + val _ = if (map.contains(unsaved.organisasjonskode)) + sys.error(s"id ${unsaved.organisasjonskode} already exists") + else + map.put(unsaved.organisasjonskode, unsaved) + + unsaved + } + override def insertStreaming(unsaved: Iterator[TestOrganisasjonRow], batchSize: Int = 10000)(implicit c: Connection): Long = { + unsaved.foreach { row => + map += (row.organisasjonskode -> row) + } + unsaved.size.toLong + } + override def select: SelectBuilder[TestOrganisasjonFields, TestOrganisasjonRow] = { + SelectBuilderMock(TestOrganisasjonFields.structure, () => map.values.toList, SelectParams.empty) + } + override def selectAll(implicit c: Connection): List[TestOrganisasjonRow] = { + map.values.toList + } + override def selectById(organisasjonskode: TestOrganisasjonId)(implicit c: Connection): Option[TestOrganisasjonRow] = { + map.get(organisasjonskode) + } + override def selectByIds(organisasjonskodes: Array[TestOrganisasjonId])(implicit c: Connection): List[TestOrganisasjonRow] = { + organisasjonskodes.flatMap(map.get).toList + } + override def selectByIdsTracked(organisasjonskodes: Array[TestOrganisasjonId])(implicit c: Connection): Map[TestOrganisasjonId, TestOrganisasjonRow] = { + val byId = selectByIds(organisasjonskodes).view.map(x => (x.organisasjonskode, x)).toMap + organisasjonskodes.view.flatMap(id => byId.get(id).map(x => (id, x))).toMap + } + override def update: UpdateBuilder[TestOrganisasjonFields, TestOrganisasjonRow] = { + UpdateBuilderMock(UpdateParams.empty, TestOrganisasjonFields.structure, map) + } + override def upsert(unsaved: TestOrganisasjonRow)(implicit c: Connection): TestOrganisasjonRow = { + map.put(unsaved.organisasjonskode, unsaved): @nowarn + unsaved + } + override def upsertBatch(unsaved: Iterable[TestOrganisasjonRow])(implicit c: Connection): List[TestOrganisasjonRow] = { + unsaved.map { row => + map += (row.organisasjonskode -> 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[TestOrganisasjonRow], batchSize: Int = 10000)(implicit c: Connection): Int = { + unsaved.foreach { row => + map += (row.organisasjonskode -> row) + } + unsaved.size + } +} diff --git a/typo-tester-anorm/generated-and-checked-in/adventureworks/public/test_organisasjon/TestOrganisasjonRow.scala b/typo-tester-anorm/generated-and-checked-in/adventureworks/public/test_organisasjon/TestOrganisasjonRow.scala new file mode 100644 index 0000000000..17bfbc6413 --- /dev/null +++ b/typo-tester-anorm/generated-and-checked-in/adventureworks/public/test_organisasjon/TestOrganisasjonRow.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 test_organisasjon + +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.test_organisasjon + Primary key: organisasjonskode */ +case class TestOrganisasjonRow( + organisasjonskode: TestOrganisasjonId +){ + val id = organisasjonskode + } + +object TestOrganisasjonRow { + implicit lazy val reads: Reads[TestOrganisasjonRow] = Reads[TestOrganisasjonRow](json => JsResult.fromTry( + Try( + TestOrganisasjonRow( + organisasjonskode = json.\("organisasjonskode").as(TestOrganisasjonId.reads) + ) + ) + ), + ) + def rowParser(idx: Int): RowParser[TestOrganisasjonRow] = RowParser[TestOrganisasjonRow] { row => + Success( + TestOrganisasjonRow( + organisasjonskode = row(idx + 0)(TestOrganisasjonId.column) + ) + ) + } + implicit lazy val text: Text[TestOrganisasjonRow] = Text.instance[TestOrganisasjonRow]{ (row, sb) => + TestOrganisasjonId.text.unsafeEncode(row.organisasjonskode, sb) + } + implicit lazy val writes: OWrites[TestOrganisasjonRow] = OWrites[TestOrganisasjonRow](o => + new JsObject(ListMap[String, JsValue]( + "organisasjonskode" -> TestOrganisasjonId.writes.writes(o.organisasjonskode) + )) + ) +} diff --git a/typo-tester-anorm/generated-and-checked-in/adventureworks/public/test_sak_soknadsalternativ/TestSakSoknadsalternativFields.scala b/typo-tester-anorm/generated-and-checked-in/adventureworks/public/test_sak_soknadsalternativ/TestSakSoknadsalternativFields.scala new file mode 100644 index 0000000000..c10b135725 --- /dev/null +++ b/typo-tester-anorm/generated-and-checked-in/adventureworks/public/test_sak_soknadsalternativ/TestSakSoknadsalternativFields.scala @@ -0,0 +1,65 @@ +/** + * File has been automatically generated by `typo`. + * + * IF YOU CHANGE THIS FILE YOUR CHANGES WILL BE OVERWRITTEN. + */ +package adventureworks +package public +package test_sak_soknadsalternativ + +import adventureworks.public.test_organisasjon.TestOrganisasjonId +import adventureworks.public.test_utdanningstilbud.TestUtdanningstilbudFields +import adventureworks.public.test_utdanningstilbud.TestUtdanningstilbudId +import adventureworks.public.test_utdanningstilbud.TestUtdanningstilbudRow +import typo.dsl.ForeignKey +import typo.dsl.Path +import typo.dsl.Required +import typo.dsl.SqlExpr +import typo.dsl.SqlExpr.CompositeIn +import typo.dsl.SqlExpr.CompositeIn.TuplePart +import typo.dsl.SqlExpr.Field +import typo.dsl.SqlExpr.FieldLikeNoHkt +import typo.dsl.SqlExpr.IdField +import typo.dsl.Structure.Relation + +trait TestSakSoknadsalternativFields { + def organisasjonskodeSaksbehandler: IdField[String, TestSakSoknadsalternativRow] + def utdanningsmulighetKode: IdField[String, TestSakSoknadsalternativRow] + def organisasjonskodeTilbyder: Field[TestOrganisasjonId, TestSakSoknadsalternativRow] + def fkTestUtdanningstilbud: ForeignKey[TestUtdanningstilbudFields, TestUtdanningstilbudRow] = + ForeignKey[TestUtdanningstilbudFields, TestUtdanningstilbudRow]("public.test_sak_soknadsalternativ_organisasjonskode_tilbyder_utda_fkey", Nil) + .withColumnPair(organisasjonskodeTilbyder, _.organisasjonskode) + .withColumnPair(utdanningsmulighetKode, _.utdanningsmulighetKode) + def compositeIdIs(compositeId: TestSakSoknadsalternativId): SqlExpr[Boolean, Required] = + organisasjonskodeSaksbehandler.isEqual(compositeId.organisasjonskodeSaksbehandler).and(utdanningsmulighetKode.isEqual(compositeId.utdanningsmulighetKode)) + def compositeIdIn(compositeIds: Array[TestSakSoknadsalternativId]): SqlExpr[Boolean, Required] = + new CompositeIn(compositeIds)(TuplePart(organisasjonskodeSaksbehandler)(_.organisasjonskodeSaksbehandler), TuplePart(utdanningsmulighetKode)(_.utdanningsmulighetKode)) + + def extractTestUtdanningstilbudIdIs(id: TestUtdanningstilbudId): SqlExpr[Boolean, Required] = + organisasjonskodeTilbyder.isEqual(id.organisasjonskode).and(utdanningsmulighetKode.isEqual(id.utdanningsmulighetKode)) + def extractTestUtdanningstilbudIdIn(ids: Array[TestUtdanningstilbudId]): SqlExpr[Boolean, Required] = + new CompositeIn(ids)(TuplePart(organisasjonskodeTilbyder)(_.organisasjonskode), TuplePart(utdanningsmulighetKode)(_.utdanningsmulighetKode)) + +} + +object TestSakSoknadsalternativFields { + lazy val structure: Relation[TestSakSoknadsalternativFields, TestSakSoknadsalternativRow] = + new Impl(Nil) + + private final class Impl(val _path: List[Path]) + extends Relation[TestSakSoknadsalternativFields, TestSakSoknadsalternativRow] { + + override lazy val fields: TestSakSoknadsalternativFields = new TestSakSoknadsalternativFields { + override def organisasjonskodeSaksbehandler = IdField[String, TestSakSoknadsalternativRow](_path, "organisasjonskode_saksbehandler", None, None, x => x.organisasjonskodeSaksbehandler, (row, value) => row.copy(organisasjonskodeSaksbehandler = value)) + override def utdanningsmulighetKode = IdField[String, TestSakSoknadsalternativRow](_path, "utdanningsmulighet_kode", None, None, x => x.utdanningsmulighetKode, (row, value) => row.copy(utdanningsmulighetKode = value)) + override def organisasjonskodeTilbyder = Field[TestOrganisasjonId, TestSakSoknadsalternativRow](_path, "organisasjonskode_tilbyder", None, None, x => x.organisasjonskodeTilbyder, (row, value) => row.copy(organisasjonskodeTilbyder = value)) + } + + override lazy val columns: List[FieldLikeNoHkt[?, TestSakSoknadsalternativRow]] = + List[FieldLikeNoHkt[?, TestSakSoknadsalternativRow]](fields.organisasjonskodeSaksbehandler, fields.utdanningsmulighetKode, fields.organisasjonskodeTilbyder) + + override def copy(path: List[Path]): Impl = + new Impl(path) + } + +} diff --git a/typo-tester-anorm/generated-and-checked-in/adventureworks/public/test_sak_soknadsalternativ/TestSakSoknadsalternativId.scala b/typo-tester-anorm/generated-and-checked-in/adventureworks/public/test_sak_soknadsalternativ/TestSakSoknadsalternativId.scala new file mode 100644 index 0000000000..d308596814 --- /dev/null +++ b/typo-tester-anorm/generated-and-checked-in/adventureworks/public/test_sak_soknadsalternativ/TestSakSoknadsalternativId.scala @@ -0,0 +1,46 @@ +/** + * File has been automatically generated by `typo`. + * + * IF YOU CHANGE THIS FILE YOUR CHANGES WILL BE OVERWRITTEN. + */ +package adventureworks +package public +package test_sak_soknadsalternativ + +import adventureworks.public.test_utdanningstilbud.TestUtdanningstilbudId +import play.api.libs.json.JsObject +import play.api.libs.json.JsResult +import play.api.libs.json.JsValue +import play.api.libs.json.OWrites +import play.api.libs.json.Reads +import play.api.libs.json.Writes +import scala.collection.immutable.ListMap +import scala.util.Try + +/** Type for the composite primary key of table `public.test_sak_soknadsalternativ` */ +case class TestSakSoknadsalternativId( + organisasjonskodeSaksbehandler: String, + utdanningsmulighetKode: String +) +object TestSakSoknadsalternativId { + def from(TestUtdanningstilbudId: TestUtdanningstilbudId, organisasjonskodeSaksbehandler: String): TestSakSoknadsalternativId = TestSakSoknadsalternativId( + organisasjonskodeSaksbehandler = organisasjonskodeSaksbehandler, + utdanningsmulighetKode = TestUtdanningstilbudId.utdanningsmulighetKode + ) + implicit lazy val ordering: Ordering[TestSakSoknadsalternativId] = Ordering.by(x => (x.organisasjonskodeSaksbehandler, x.utdanningsmulighetKode)) + implicit lazy val reads: Reads[TestSakSoknadsalternativId] = Reads[TestSakSoknadsalternativId](json => JsResult.fromTry( + Try( + TestSakSoknadsalternativId( + organisasjonskodeSaksbehandler = json.\("organisasjonskode_saksbehandler").as(Reads.StringReads), + utdanningsmulighetKode = json.\("utdanningsmulighet_kode").as(Reads.StringReads) + ) + ) + ), + ) + implicit lazy val writes: OWrites[TestSakSoknadsalternativId] = OWrites[TestSakSoknadsalternativId](o => + new JsObject(ListMap[String, JsValue]( + "organisasjonskode_saksbehandler" -> Writes.StringWrites.writes(o.organisasjonskodeSaksbehandler), + "utdanningsmulighet_kode" -> Writes.StringWrites.writes(o.utdanningsmulighetKode) + )) + ) +} diff --git a/typo-tester-anorm/generated-and-checked-in/adventureworks/public/test_sak_soknadsalternativ/TestSakSoknadsalternativRepo.scala b/typo-tester-anorm/generated-and-checked-in/adventureworks/public/test_sak_soknadsalternativ/TestSakSoknadsalternativRepo.scala new file mode 100644 index 0000000000..ce9aac28cb --- /dev/null +++ b/typo-tester-anorm/generated-and-checked-in/adventureworks/public/test_sak_soknadsalternativ/TestSakSoknadsalternativRepo.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 test_sak_soknadsalternativ + +import java.sql.Connection +import typo.dsl.DeleteBuilder +import typo.dsl.SelectBuilder +import typo.dsl.UpdateBuilder + +trait TestSakSoknadsalternativRepo { + def delete: DeleteBuilder[TestSakSoknadsalternativFields, TestSakSoknadsalternativRow] + def deleteById(compositeId: TestSakSoknadsalternativId)(implicit c: Connection): Boolean + def deleteByIds(compositeIds: Array[TestSakSoknadsalternativId])(implicit c: Connection): Int + def insert(unsaved: TestSakSoknadsalternativRow)(implicit c: Connection): TestSakSoknadsalternativRow + def insertStreaming(unsaved: Iterator[TestSakSoknadsalternativRow], batchSize: Int = 10000)(implicit c: Connection): Long + def select: SelectBuilder[TestSakSoknadsalternativFields, TestSakSoknadsalternativRow] + def selectAll(implicit c: Connection): List[TestSakSoknadsalternativRow] + def selectById(compositeId: TestSakSoknadsalternativId)(implicit c: Connection): Option[TestSakSoknadsalternativRow] + def selectByIds(compositeIds: Array[TestSakSoknadsalternativId])(implicit c: Connection): List[TestSakSoknadsalternativRow] + def selectByIdsTracked(compositeIds: Array[TestSakSoknadsalternativId])(implicit c: Connection): Map[TestSakSoknadsalternativId, TestSakSoknadsalternativRow] + def update: UpdateBuilder[TestSakSoknadsalternativFields, TestSakSoknadsalternativRow] + def update(row: TestSakSoknadsalternativRow)(implicit c: Connection): Boolean + def upsert(unsaved: TestSakSoknadsalternativRow)(implicit c: Connection): TestSakSoknadsalternativRow + def upsertBatch(unsaved: Iterable[TestSakSoknadsalternativRow])(implicit c: Connection): List[TestSakSoknadsalternativRow] + /* NOTE: this functionality is not safe if you use auto-commit mode! it runs 3 SQL statements */ + def upsertStreaming(unsaved: Iterator[TestSakSoknadsalternativRow], batchSize: Int = 10000)(implicit c: Connection): Int +} diff --git a/typo-tester-anorm/generated-and-checked-in/adventureworks/public/test_sak_soknadsalternativ/TestSakSoknadsalternativRepoImpl.scala b/typo-tester-anorm/generated-and-checked-in/adventureworks/public/test_sak_soknadsalternativ/TestSakSoknadsalternativRepoImpl.scala new file mode 100644 index 0000000000..165ca16865 --- /dev/null +++ b/typo-tester-anorm/generated-and-checked-in/adventureworks/public/test_sak_soknadsalternativ/TestSakSoknadsalternativRepoImpl.scala @@ -0,0 +1,140 @@ +/** + * File has been automatically generated by `typo`. + * + * IF YOU CHANGE THIS FILE YOUR CHANGES WILL BE OVERWRITTEN. + */ +package adventureworks +package public +package test_sak_soknadsalternativ + +import adventureworks.public.test_organisasjon.TestOrganisasjonId +import anorm.BatchSql +import anorm.NamedParameter +import anorm.ParameterValue +import anorm.SqlStringInterpolation +import anorm.ToStatement +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 TestSakSoknadsalternativRepoImpl extends TestSakSoknadsalternativRepo { + override def delete: DeleteBuilder[TestSakSoknadsalternativFields, TestSakSoknadsalternativRow] = { + DeleteBuilder(""""public"."test_sak_soknadsalternativ"""", TestSakSoknadsalternativFields.structure) + } + override def deleteById(compositeId: TestSakSoknadsalternativId)(implicit c: Connection): Boolean = { + SQL"""delete from "public"."test_sak_soknadsalternativ" where "organisasjonskode_saksbehandler" = ${ParameterValue(compositeId.organisasjonskodeSaksbehandler, null, ToStatement.stringToStatement)} AND "utdanningsmulighet_kode" = ${ParameterValue(compositeId.utdanningsmulighetKode, null, ToStatement.stringToStatement)}""".executeUpdate() > 0 + } + override def deleteByIds(compositeIds: Array[TestSakSoknadsalternativId])(implicit c: Connection): Int = { + val organisasjonskodeSaksbehandler = compositeIds.map(_.organisasjonskodeSaksbehandler) + val utdanningsmulighetKode = compositeIds.map(_.utdanningsmulighetKode) + SQL"""delete + from "public"."test_sak_soknadsalternativ" + where ("organisasjonskode_saksbehandler", "utdanningsmulighet_kode") + in (select unnest(${organisasjonskodeSaksbehandler}), unnest(${utdanningsmulighetKode})) + """.executeUpdate() + + } + override def insert(unsaved: TestSakSoknadsalternativRow)(implicit c: Connection): TestSakSoknadsalternativRow = { + SQL"""insert into "public"."test_sak_soknadsalternativ"("organisasjonskode_saksbehandler", "utdanningsmulighet_kode", "organisasjonskode_tilbyder") + values (${ParameterValue(unsaved.organisasjonskodeSaksbehandler, null, ToStatement.stringToStatement)}, ${ParameterValue(unsaved.utdanningsmulighetKode, null, ToStatement.stringToStatement)}, ${ParameterValue(unsaved.organisasjonskodeTilbyder, null, TestOrganisasjonId.toStatement)}) + returning "organisasjonskode_saksbehandler", "utdanningsmulighet_kode", "organisasjonskode_tilbyder" + """ + .executeInsert(TestSakSoknadsalternativRow.rowParser(1).single) + + } + override def insertStreaming(unsaved: Iterator[TestSakSoknadsalternativRow], batchSize: Int = 10000)(implicit c: Connection): Long = { + streamingInsert(s"""COPY "public"."test_sak_soknadsalternativ"("organisasjonskode_saksbehandler", "utdanningsmulighet_kode", "organisasjonskode_tilbyder") FROM STDIN""", batchSize, unsaved)(TestSakSoknadsalternativRow.text, c) + } + override def select: SelectBuilder[TestSakSoknadsalternativFields, TestSakSoknadsalternativRow] = { + SelectBuilderSql(""""public"."test_sak_soknadsalternativ"""", TestSakSoknadsalternativFields.structure, TestSakSoknadsalternativRow.rowParser) + } + override def selectAll(implicit c: Connection): List[TestSakSoknadsalternativRow] = { + SQL"""select "organisasjonskode_saksbehandler", "utdanningsmulighet_kode", "organisasjonskode_tilbyder" + from "public"."test_sak_soknadsalternativ" + """.as(TestSakSoknadsalternativRow.rowParser(1).*) + } + override def selectById(compositeId: TestSakSoknadsalternativId)(implicit c: Connection): Option[TestSakSoknadsalternativRow] = { + SQL"""select "organisasjonskode_saksbehandler", "utdanningsmulighet_kode", "organisasjonskode_tilbyder" + from "public"."test_sak_soknadsalternativ" + where "organisasjonskode_saksbehandler" = ${ParameterValue(compositeId.organisasjonskodeSaksbehandler, null, ToStatement.stringToStatement)} AND "utdanningsmulighet_kode" = ${ParameterValue(compositeId.utdanningsmulighetKode, null, ToStatement.stringToStatement)} + """.as(TestSakSoknadsalternativRow.rowParser(1).singleOpt) + } + override def selectByIds(compositeIds: Array[TestSakSoknadsalternativId])(implicit c: Connection): List[TestSakSoknadsalternativRow] = { + val organisasjonskodeSaksbehandler = compositeIds.map(_.organisasjonskodeSaksbehandler) + val utdanningsmulighetKode = compositeIds.map(_.utdanningsmulighetKode) + SQL"""select "organisasjonskode_saksbehandler", "utdanningsmulighet_kode", "organisasjonskode_tilbyder" + from "public"."test_sak_soknadsalternativ" + where ("organisasjonskode_saksbehandler", "utdanningsmulighet_kode") + in (select unnest(${organisasjonskodeSaksbehandler}), unnest(${utdanningsmulighetKode})) + """.as(TestSakSoknadsalternativRow.rowParser(1).*) + + } + override def selectByIdsTracked(compositeIds: Array[TestSakSoknadsalternativId])(implicit c: Connection): Map[TestSakSoknadsalternativId, TestSakSoknadsalternativRow] = { + val byId = selectByIds(compositeIds).view.map(x => (x.compositeId, x)).toMap + compositeIds.view.flatMap(id => byId.get(id).map(x => (id, x))).toMap + } + override def update: UpdateBuilder[TestSakSoknadsalternativFields, TestSakSoknadsalternativRow] = { + UpdateBuilder(""""public"."test_sak_soknadsalternativ"""", TestSakSoknadsalternativFields.structure, TestSakSoknadsalternativRow.rowParser) + } + override def update(row: TestSakSoknadsalternativRow)(implicit c: Connection): Boolean = { + val compositeId = row.compositeId + SQL"""update "public"."test_sak_soknadsalternativ" + set "organisasjonskode_tilbyder" = ${ParameterValue(row.organisasjonskodeTilbyder, null, TestOrganisasjonId.toStatement)} + where "organisasjonskode_saksbehandler" = ${ParameterValue(compositeId.organisasjonskodeSaksbehandler, null, ToStatement.stringToStatement)} AND "utdanningsmulighet_kode" = ${ParameterValue(compositeId.utdanningsmulighetKode, null, ToStatement.stringToStatement)} + """.executeUpdate() > 0 + } + override def upsert(unsaved: TestSakSoknadsalternativRow)(implicit c: Connection): TestSakSoknadsalternativRow = { + SQL"""insert into "public"."test_sak_soknadsalternativ"("organisasjonskode_saksbehandler", "utdanningsmulighet_kode", "organisasjonskode_tilbyder") + values ( + ${ParameterValue(unsaved.organisasjonskodeSaksbehandler, null, ToStatement.stringToStatement)}, + ${ParameterValue(unsaved.utdanningsmulighetKode, null, ToStatement.stringToStatement)}, + ${ParameterValue(unsaved.organisasjonskodeTilbyder, null, TestOrganisasjonId.toStatement)} + ) + on conflict ("organisasjonskode_saksbehandler", "utdanningsmulighet_kode") + do update set + "organisasjonskode_tilbyder" = EXCLUDED."organisasjonskode_tilbyder" + returning "organisasjonskode_saksbehandler", "utdanningsmulighet_kode", "organisasjonskode_tilbyder" + """ + .executeInsert(TestSakSoknadsalternativRow.rowParser(1).single) + + } + override def upsertBatch(unsaved: Iterable[TestSakSoknadsalternativRow])(implicit c: Connection): List[TestSakSoknadsalternativRow] = { + def toNamedParameter(row: TestSakSoknadsalternativRow): List[NamedParameter] = List( + NamedParameter("organisasjonskode_saksbehandler", ParameterValue(row.organisasjonskodeSaksbehandler, null, ToStatement.stringToStatement)), + NamedParameter("utdanningsmulighet_kode", ParameterValue(row.utdanningsmulighetKode, null, ToStatement.stringToStatement)), + NamedParameter("organisasjonskode_tilbyder", ParameterValue(row.organisasjonskodeTilbyder, null, TestOrganisasjonId.toStatement)) + ) + unsaved.toList match { + case Nil => Nil + case head :: rest => + new anorm.adventureworks.ExecuteReturningSyntax.Ops( + BatchSql( + s"""insert into "public"."test_sak_soknadsalternativ"("organisasjonskode_saksbehandler", "utdanningsmulighet_kode", "organisasjonskode_tilbyder") + values ({organisasjonskode_saksbehandler}, {utdanningsmulighet_kode}, {organisasjonskode_tilbyder}) + on conflict ("organisasjonskode_saksbehandler", "utdanningsmulighet_kode") + do update set + "organisasjonskode_tilbyder" = EXCLUDED."organisasjonskode_tilbyder" + returning "organisasjonskode_saksbehandler", "utdanningsmulighet_kode", "organisasjonskode_tilbyder" + """, + toNamedParameter(head), + rest.map(toNamedParameter)* + ) + ).executeReturning(TestSakSoknadsalternativRow.rowParser(1).*) + } + } + /* NOTE: this functionality is not safe if you use auto-commit mode! it runs 3 SQL statements */ + override def upsertStreaming(unsaved: Iterator[TestSakSoknadsalternativRow], batchSize: Int = 10000)(implicit c: Connection): Int = { + SQL"""create temporary table test_sak_soknadsalternativ_TEMP (like "public"."test_sak_soknadsalternativ") on commit drop""".execute(): @nowarn + streamingInsert(s"""copy test_sak_soknadsalternativ_TEMP("organisasjonskode_saksbehandler", "utdanningsmulighet_kode", "organisasjonskode_tilbyder") from stdin""", batchSize, unsaved)(TestSakSoknadsalternativRow.text, c): @nowarn + SQL"""insert into "public"."test_sak_soknadsalternativ"("organisasjonskode_saksbehandler", "utdanningsmulighet_kode", "organisasjonskode_tilbyder") + select * from test_sak_soknadsalternativ_TEMP + on conflict ("organisasjonskode_saksbehandler", "utdanningsmulighet_kode") + do update set + "organisasjonskode_tilbyder" = EXCLUDED."organisasjonskode_tilbyder" + ; + drop table test_sak_soknadsalternativ_TEMP;""".executeUpdate() + } +} diff --git a/typo-tester-anorm/generated-and-checked-in/adventureworks/public/test_sak_soknadsalternativ/TestSakSoknadsalternativRepoMock.scala b/typo-tester-anorm/generated-and-checked-in/adventureworks/public/test_sak_soknadsalternativ/TestSakSoknadsalternativRepoMock.scala new file mode 100644 index 0000000000..dea0515026 --- /dev/null +++ b/typo-tester-anorm/generated-and-checked-in/adventureworks/public/test_sak_soknadsalternativ/TestSakSoknadsalternativRepoMock.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 test_sak_soknadsalternativ + +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 TestSakSoknadsalternativRepoMock(map: scala.collection.mutable.Map[TestSakSoknadsalternativId, TestSakSoknadsalternativRow] = scala.collection.mutable.Map.empty) extends TestSakSoknadsalternativRepo { + override def delete: DeleteBuilder[TestSakSoknadsalternativFields, TestSakSoknadsalternativRow] = { + DeleteBuilderMock(DeleteParams.empty, TestSakSoknadsalternativFields.structure, map) + } + override def deleteById(compositeId: TestSakSoknadsalternativId)(implicit c: Connection): Boolean = { + map.remove(compositeId).isDefined + } + override def deleteByIds(compositeIds: Array[TestSakSoknadsalternativId])(implicit c: Connection): Int = { + compositeIds.map(id => map.remove(id)).count(_.isDefined) + } + override def insert(unsaved: TestSakSoknadsalternativRow)(implicit c: Connection): TestSakSoknadsalternativRow = { + val _ = if (map.contains(unsaved.compositeId)) + sys.error(s"id ${unsaved.compositeId} already exists") + else + map.put(unsaved.compositeId, unsaved) + + unsaved + } + override def insertStreaming(unsaved: Iterator[TestSakSoknadsalternativRow], batchSize: Int = 10000)(implicit c: Connection): Long = { + unsaved.foreach { row => + map += (row.compositeId -> row) + } + unsaved.size.toLong + } + override def select: SelectBuilder[TestSakSoknadsalternativFields, TestSakSoknadsalternativRow] = { + SelectBuilderMock(TestSakSoknadsalternativFields.structure, () => map.values.toList, SelectParams.empty) + } + override def selectAll(implicit c: Connection): List[TestSakSoknadsalternativRow] = { + map.values.toList + } + override def selectById(compositeId: TestSakSoknadsalternativId)(implicit c: Connection): Option[TestSakSoknadsalternativRow] = { + map.get(compositeId) + } + override def selectByIds(compositeIds: Array[TestSakSoknadsalternativId])(implicit c: Connection): List[TestSakSoknadsalternativRow] = { + compositeIds.flatMap(map.get).toList + } + override def selectByIdsTracked(compositeIds: Array[TestSakSoknadsalternativId])(implicit c: Connection): Map[TestSakSoknadsalternativId, TestSakSoknadsalternativRow] = { + val byId = selectByIds(compositeIds).view.map(x => (x.compositeId, x)).toMap + compositeIds.view.flatMap(id => byId.get(id).map(x => (id, x))).toMap + } + override def update: UpdateBuilder[TestSakSoknadsalternativFields, TestSakSoknadsalternativRow] = { + UpdateBuilderMock(UpdateParams.empty, TestSakSoknadsalternativFields.structure, map) + } + override def update(row: TestSakSoknadsalternativRow)(implicit c: Connection): Boolean = { + map.get(row.compositeId) match { + case Some(`row`) => false + case Some(_) => + map.put(row.compositeId, row): @nowarn + true + case None => false + } + } + override def upsert(unsaved: TestSakSoknadsalternativRow)(implicit c: Connection): TestSakSoknadsalternativRow = { + map.put(unsaved.compositeId, unsaved): @nowarn + unsaved + } + override def upsertBatch(unsaved: Iterable[TestSakSoknadsalternativRow])(implicit c: Connection): List[TestSakSoknadsalternativRow] = { + unsaved.map { row => + map += (row.compositeId -> 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[TestSakSoknadsalternativRow], batchSize: Int = 10000)(implicit c: Connection): Int = { + unsaved.foreach { row => + map += (row.compositeId -> row) + } + unsaved.size + } +} diff --git a/typo-tester-anorm/generated-and-checked-in/adventureworks/public/test_sak_soknadsalternativ/TestSakSoknadsalternativRow.scala b/typo-tester-anorm/generated-and-checked-in/adventureworks/public/test_sak_soknadsalternativ/TestSakSoknadsalternativRow.scala new file mode 100644 index 0000000000..371166d4cc --- /dev/null +++ b/typo-tester-anorm/generated-and-checked-in/adventureworks/public/test_sak_soknadsalternativ/TestSakSoknadsalternativRow.scala @@ -0,0 +1,77 @@ +/** + * File has been automatically generated by `typo`. + * + * IF YOU CHANGE THIS FILE YOUR CHANGES WILL BE OVERWRITTEN. + */ +package adventureworks +package public +package test_sak_soknadsalternativ + +import adventureworks.public.test_organisasjon.TestOrganisasjonId +import adventureworks.public.test_utdanningstilbud.TestUtdanningstilbudId +import anorm.Column +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 play.api.libs.json.Writes +import scala.collection.immutable.ListMap +import scala.util.Try + +/** Table: public.test_sak_soknadsalternativ + Composite primary key: organisasjonskode_saksbehandler, utdanningsmulighet_kode */ +case class TestSakSoknadsalternativRow( + organisasjonskodeSaksbehandler: String, + /** Points to [[test_utdanningstilbud.TestUtdanningstilbudRow.utdanningsmulighetKode]] */ + utdanningsmulighetKode: String, + /** Points to [[test_utdanningstilbud.TestUtdanningstilbudRow.organisasjonskode]] */ + organisasjonskodeTilbyder: TestOrganisasjonId +){ + val compositeId: TestSakSoknadsalternativId = TestSakSoknadsalternativId(organisasjonskodeSaksbehandler, utdanningsmulighetKode) + val id = compositeId + val extractTestUtdanningstilbudId: TestUtdanningstilbudId = TestUtdanningstilbudId( + organisasjonskode = organisasjonskodeTilbyder, + utdanningsmulighetKode = utdanningsmulighetKode + ) + } + +object TestSakSoknadsalternativRow { + def apply(compositeId: TestSakSoknadsalternativId, organisasjonskodeTilbyder: TestOrganisasjonId) = + new TestSakSoknadsalternativRow(compositeId.organisasjonskodeSaksbehandler, compositeId.utdanningsmulighetKode, organisasjonskodeTilbyder) + implicit lazy val reads: Reads[TestSakSoknadsalternativRow] = Reads[TestSakSoknadsalternativRow](json => JsResult.fromTry( + Try( + TestSakSoknadsalternativRow( + organisasjonskodeSaksbehandler = json.\("organisasjonskode_saksbehandler").as(Reads.StringReads), + utdanningsmulighetKode = json.\("utdanningsmulighet_kode").as(Reads.StringReads), + organisasjonskodeTilbyder = json.\("organisasjonskode_tilbyder").as(TestOrganisasjonId.reads) + ) + ) + ), + ) + def rowParser(idx: Int): RowParser[TestSakSoknadsalternativRow] = RowParser[TestSakSoknadsalternativRow] { row => + Success( + TestSakSoknadsalternativRow( + organisasjonskodeSaksbehandler = row(idx + 0)(Column.columnToString), + utdanningsmulighetKode = row(idx + 1)(Column.columnToString), + organisasjonskodeTilbyder = row(idx + 2)(TestOrganisasjonId.column) + ) + ) + } + implicit lazy val text: Text[TestSakSoknadsalternativRow] = Text.instance[TestSakSoknadsalternativRow]{ (row, sb) => + Text.stringInstance.unsafeEncode(row.organisasjonskodeSaksbehandler, sb) + sb.append(Text.DELIMETER) + Text.stringInstance.unsafeEncode(row.utdanningsmulighetKode, sb) + sb.append(Text.DELIMETER) + TestOrganisasjonId.text.unsafeEncode(row.organisasjonskodeTilbyder, sb) + } + implicit lazy val writes: OWrites[TestSakSoknadsalternativRow] = OWrites[TestSakSoknadsalternativRow](o => + new JsObject(ListMap[String, JsValue]( + "organisasjonskode_saksbehandler" -> Writes.StringWrites.writes(o.organisasjonskodeSaksbehandler), + "utdanningsmulighet_kode" -> Writes.StringWrites.writes(o.utdanningsmulighetKode), + "organisasjonskode_tilbyder" -> TestOrganisasjonId.writes.writes(o.organisasjonskodeTilbyder) + )) + ) +} diff --git a/typo-tester-anorm/generated-and-checked-in/adventureworks/public/test_utdanningstilbud/TestUtdanningstilbudFields.scala b/typo-tester-anorm/generated-and-checked-in/adventureworks/public/test_utdanningstilbud/TestUtdanningstilbudFields.scala new file mode 100644 index 0000000000..8d12859730 --- /dev/null +++ b/typo-tester-anorm/generated-and-checked-in/adventureworks/public/test_utdanningstilbud/TestUtdanningstilbudFields.scala @@ -0,0 +1,55 @@ +/** + * File has been automatically generated by `typo`. + * + * IF YOU CHANGE THIS FILE YOUR CHANGES WILL BE OVERWRITTEN. + */ +package adventureworks +package public +package test_utdanningstilbud + +import adventureworks.public.test_organisasjon.TestOrganisasjonFields +import adventureworks.public.test_organisasjon.TestOrganisasjonId +import adventureworks.public.test_organisasjon.TestOrganisasjonRow +import typo.dsl.ForeignKey +import typo.dsl.Path +import typo.dsl.Required +import typo.dsl.SqlExpr +import typo.dsl.SqlExpr.CompositeIn +import typo.dsl.SqlExpr.CompositeIn.TuplePart +import typo.dsl.SqlExpr.FieldLikeNoHkt +import typo.dsl.SqlExpr.IdField +import typo.dsl.Structure.Relation + +trait TestUtdanningstilbudFields { + def organisasjonskode: IdField[TestOrganisasjonId, TestUtdanningstilbudRow] + def utdanningsmulighetKode: IdField[String, TestUtdanningstilbudRow] + def fkTestOrganisasjon: ForeignKey[TestOrganisasjonFields, TestOrganisasjonRow] = + ForeignKey[TestOrganisasjonFields, TestOrganisasjonRow]("public.test_utdanningstilbud_organisasjonskode_fkey", Nil) + .withColumnPair(organisasjonskode, _.organisasjonskode) + def compositeIdIs(compositeId: TestUtdanningstilbudId): SqlExpr[Boolean, Required] = + organisasjonskode.isEqual(compositeId.organisasjonskode).and(utdanningsmulighetKode.isEqual(compositeId.utdanningsmulighetKode)) + def compositeIdIn(compositeIds: Array[TestUtdanningstilbudId]): SqlExpr[Boolean, Required] = + new CompositeIn(compositeIds)(TuplePart(organisasjonskode)(_.organisasjonskode), TuplePart(utdanningsmulighetKode)(_.utdanningsmulighetKode)) + +} + +object TestUtdanningstilbudFields { + lazy val structure: Relation[TestUtdanningstilbudFields, TestUtdanningstilbudRow] = + new Impl(Nil) + + private final class Impl(val _path: List[Path]) + extends Relation[TestUtdanningstilbudFields, TestUtdanningstilbudRow] { + + override lazy val fields: TestUtdanningstilbudFields = new TestUtdanningstilbudFields { + override def organisasjonskode = IdField[TestOrganisasjonId, TestUtdanningstilbudRow](_path, "organisasjonskode", None, None, x => x.organisasjonskode, (row, value) => row.copy(organisasjonskode = value)) + override def utdanningsmulighetKode = IdField[String, TestUtdanningstilbudRow](_path, "utdanningsmulighet_kode", None, None, x => x.utdanningsmulighetKode, (row, value) => row.copy(utdanningsmulighetKode = value)) + } + + override lazy val columns: List[FieldLikeNoHkt[?, TestUtdanningstilbudRow]] = + List[FieldLikeNoHkt[?, TestUtdanningstilbudRow]](fields.organisasjonskode, fields.utdanningsmulighetKode) + + override def copy(path: List[Path]): Impl = + new Impl(path) + } + +} diff --git a/typo-tester-anorm/generated-and-checked-in/adventureworks/public/test_utdanningstilbud/TestUtdanningstilbudId.scala b/typo-tester-anorm/generated-and-checked-in/adventureworks/public/test_utdanningstilbud/TestUtdanningstilbudId.scala new file mode 100644 index 0000000000..8e448776b5 --- /dev/null +++ b/typo-tester-anorm/generated-and-checked-in/adventureworks/public/test_utdanningstilbud/TestUtdanningstilbudId.scala @@ -0,0 +1,42 @@ +/** + * File has been automatically generated by `typo`. + * + * IF YOU CHANGE THIS FILE YOUR CHANGES WILL BE OVERWRITTEN. + */ +package adventureworks +package public +package test_utdanningstilbud + +import adventureworks.public.test_organisasjon.TestOrganisasjonId +import play.api.libs.json.JsObject +import play.api.libs.json.JsResult +import play.api.libs.json.JsValue +import play.api.libs.json.OWrites +import play.api.libs.json.Reads +import play.api.libs.json.Writes +import scala.collection.immutable.ListMap +import scala.util.Try + +/** Type for the composite primary key of table `public.test_utdanningstilbud` */ +case class TestUtdanningstilbudId( + organisasjonskode: TestOrganisasjonId, + utdanningsmulighetKode: String +) +object TestUtdanningstilbudId { + implicit lazy val ordering: Ordering[TestUtdanningstilbudId] = Ordering.by(x => (x.organisasjonskode, x.utdanningsmulighetKode)) + implicit lazy val reads: Reads[TestUtdanningstilbudId] = Reads[TestUtdanningstilbudId](json => JsResult.fromTry( + Try( + TestUtdanningstilbudId( + organisasjonskode = json.\("organisasjonskode").as(TestOrganisasjonId.reads), + utdanningsmulighetKode = json.\("utdanningsmulighet_kode").as(Reads.StringReads) + ) + ) + ), + ) + implicit lazy val writes: OWrites[TestUtdanningstilbudId] = OWrites[TestUtdanningstilbudId](o => + new JsObject(ListMap[String, JsValue]( + "organisasjonskode" -> TestOrganisasjonId.writes.writes(o.organisasjonskode), + "utdanningsmulighet_kode" -> Writes.StringWrites.writes(o.utdanningsmulighetKode) + )) + ) +} diff --git a/typo-tester-anorm/generated-and-checked-in/adventureworks/public/test_utdanningstilbud/TestUtdanningstilbudRepo.scala b/typo-tester-anorm/generated-and-checked-in/adventureworks/public/test_utdanningstilbud/TestUtdanningstilbudRepo.scala new file mode 100644 index 0000000000..68cf0fbd69 --- /dev/null +++ b/typo-tester-anorm/generated-and-checked-in/adventureworks/public/test_utdanningstilbud/TestUtdanningstilbudRepo.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 test_utdanningstilbud + +import java.sql.Connection +import typo.dsl.DeleteBuilder +import typo.dsl.SelectBuilder +import typo.dsl.UpdateBuilder + +trait TestUtdanningstilbudRepo { + def delete: DeleteBuilder[TestUtdanningstilbudFields, TestUtdanningstilbudRow] + def deleteById(compositeId: TestUtdanningstilbudId)(implicit c: Connection): Boolean + def deleteByIds(compositeIds: Array[TestUtdanningstilbudId])(implicit c: Connection): Int + def insert(unsaved: TestUtdanningstilbudRow)(implicit c: Connection): TestUtdanningstilbudRow + def insertStreaming(unsaved: Iterator[TestUtdanningstilbudRow], batchSize: Int = 10000)(implicit c: Connection): Long + def select: SelectBuilder[TestUtdanningstilbudFields, TestUtdanningstilbudRow] + def selectAll(implicit c: Connection): List[TestUtdanningstilbudRow] + def selectById(compositeId: TestUtdanningstilbudId)(implicit c: Connection): Option[TestUtdanningstilbudRow] + def selectByIds(compositeIds: Array[TestUtdanningstilbudId])(implicit c: Connection): List[TestUtdanningstilbudRow] + def selectByIdsTracked(compositeIds: Array[TestUtdanningstilbudId])(implicit c: Connection): Map[TestUtdanningstilbudId, TestUtdanningstilbudRow] + def update: UpdateBuilder[TestUtdanningstilbudFields, TestUtdanningstilbudRow] + def upsert(unsaved: TestUtdanningstilbudRow)(implicit c: Connection): TestUtdanningstilbudRow + def upsertBatch(unsaved: Iterable[TestUtdanningstilbudRow])(implicit c: Connection): List[TestUtdanningstilbudRow] + /* NOTE: this functionality is not safe if you use auto-commit mode! it runs 3 SQL statements */ + def upsertStreaming(unsaved: Iterator[TestUtdanningstilbudRow], batchSize: Int = 10000)(implicit c: Connection): Int +} diff --git a/typo-tester-anorm/generated-and-checked-in/adventureworks/public/test_utdanningstilbud/TestUtdanningstilbudRepoImpl.scala b/typo-tester-anorm/generated-and-checked-in/adventureworks/public/test_utdanningstilbud/TestUtdanningstilbudRepoImpl.scala new file mode 100644 index 0000000000..d28fa84dae --- /dev/null +++ b/typo-tester-anorm/generated-and-checked-in/adventureworks/public/test_utdanningstilbud/TestUtdanningstilbudRepoImpl.scala @@ -0,0 +1,128 @@ +/** + * File has been automatically generated by `typo`. + * + * IF YOU CHANGE THIS FILE YOUR CHANGES WILL BE OVERWRITTEN. + */ +package adventureworks +package public +package test_utdanningstilbud + +import adventureworks.public.test_organisasjon.TestOrganisasjonId +import anorm.BatchSql +import anorm.NamedParameter +import anorm.ParameterValue +import anorm.SqlStringInterpolation +import anorm.ToStatement +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 TestUtdanningstilbudRepoImpl extends TestUtdanningstilbudRepo { + override def delete: DeleteBuilder[TestUtdanningstilbudFields, TestUtdanningstilbudRow] = { + DeleteBuilder(""""public"."test_utdanningstilbud"""", TestUtdanningstilbudFields.structure) + } + override def deleteById(compositeId: TestUtdanningstilbudId)(implicit c: Connection): Boolean = { + SQL"""delete from "public"."test_utdanningstilbud" where "organisasjonskode" = ${ParameterValue(compositeId.organisasjonskode, null, TestOrganisasjonId.toStatement)} AND "utdanningsmulighet_kode" = ${ParameterValue(compositeId.utdanningsmulighetKode, null, ToStatement.stringToStatement)}""".executeUpdate() > 0 + } + override def deleteByIds(compositeIds: Array[TestUtdanningstilbudId])(implicit c: Connection): Int = { + val organisasjonskode = compositeIds.map(_.organisasjonskode) + val utdanningsmulighetKode = compositeIds.map(_.utdanningsmulighetKode) + SQL"""delete + from "public"."test_utdanningstilbud" + where ("organisasjonskode", "utdanningsmulighet_kode") + in (select unnest(${organisasjonskode}), unnest(${utdanningsmulighetKode})) + """.executeUpdate() + + } + override def insert(unsaved: TestUtdanningstilbudRow)(implicit c: Connection): TestUtdanningstilbudRow = { + SQL"""insert into "public"."test_utdanningstilbud"("organisasjonskode", "utdanningsmulighet_kode") + values (${ParameterValue(unsaved.organisasjonskode, null, TestOrganisasjonId.toStatement)}, ${ParameterValue(unsaved.utdanningsmulighetKode, null, ToStatement.stringToStatement)}) + returning "organisasjonskode", "utdanningsmulighet_kode" + """ + .executeInsert(TestUtdanningstilbudRow.rowParser(1).single) + + } + override def insertStreaming(unsaved: Iterator[TestUtdanningstilbudRow], batchSize: Int = 10000)(implicit c: Connection): Long = { + streamingInsert(s"""COPY "public"."test_utdanningstilbud"("organisasjonskode", "utdanningsmulighet_kode") FROM STDIN""", batchSize, unsaved)(TestUtdanningstilbudRow.text, c) + } + override def select: SelectBuilder[TestUtdanningstilbudFields, TestUtdanningstilbudRow] = { + SelectBuilderSql(""""public"."test_utdanningstilbud"""", TestUtdanningstilbudFields.structure, TestUtdanningstilbudRow.rowParser) + } + override def selectAll(implicit c: Connection): List[TestUtdanningstilbudRow] = { + SQL"""select "organisasjonskode", "utdanningsmulighet_kode" + from "public"."test_utdanningstilbud" + """.as(TestUtdanningstilbudRow.rowParser(1).*) + } + override def selectById(compositeId: TestUtdanningstilbudId)(implicit c: Connection): Option[TestUtdanningstilbudRow] = { + SQL"""select "organisasjonskode", "utdanningsmulighet_kode" + from "public"."test_utdanningstilbud" + where "organisasjonskode" = ${ParameterValue(compositeId.organisasjonskode, null, TestOrganisasjonId.toStatement)} AND "utdanningsmulighet_kode" = ${ParameterValue(compositeId.utdanningsmulighetKode, null, ToStatement.stringToStatement)} + """.as(TestUtdanningstilbudRow.rowParser(1).singleOpt) + } + override def selectByIds(compositeIds: Array[TestUtdanningstilbudId])(implicit c: Connection): List[TestUtdanningstilbudRow] = { + val organisasjonskode = compositeIds.map(_.organisasjonskode) + val utdanningsmulighetKode = compositeIds.map(_.utdanningsmulighetKode) + SQL"""select "organisasjonskode", "utdanningsmulighet_kode" + from "public"."test_utdanningstilbud" + where ("organisasjonskode", "utdanningsmulighet_kode") + in (select unnest(${organisasjonskode}), unnest(${utdanningsmulighetKode})) + """.as(TestUtdanningstilbudRow.rowParser(1).*) + + } + override def selectByIdsTracked(compositeIds: Array[TestUtdanningstilbudId])(implicit c: Connection): Map[TestUtdanningstilbudId, TestUtdanningstilbudRow] = { + val byId = selectByIds(compositeIds).view.map(x => (x.compositeId, x)).toMap + compositeIds.view.flatMap(id => byId.get(id).map(x => (id, x))).toMap + } + override def update: UpdateBuilder[TestUtdanningstilbudFields, TestUtdanningstilbudRow] = { + UpdateBuilder(""""public"."test_utdanningstilbud"""", TestUtdanningstilbudFields.structure, TestUtdanningstilbudRow.rowParser) + } + override def upsert(unsaved: TestUtdanningstilbudRow)(implicit c: Connection): TestUtdanningstilbudRow = { + SQL"""insert into "public"."test_utdanningstilbud"("organisasjonskode", "utdanningsmulighet_kode") + values ( + ${ParameterValue(unsaved.organisasjonskode, null, TestOrganisasjonId.toStatement)}, + ${ParameterValue(unsaved.utdanningsmulighetKode, null, ToStatement.stringToStatement)} + ) + on conflict ("organisasjonskode", "utdanningsmulighet_kode") + do update set "organisasjonskode" = EXCLUDED."organisasjonskode" + returning "organisasjonskode", "utdanningsmulighet_kode" + """ + .executeInsert(TestUtdanningstilbudRow.rowParser(1).single) + + } + override def upsertBatch(unsaved: Iterable[TestUtdanningstilbudRow])(implicit c: Connection): List[TestUtdanningstilbudRow] = { + def toNamedParameter(row: TestUtdanningstilbudRow): List[NamedParameter] = List( + NamedParameter("organisasjonskode", ParameterValue(row.organisasjonskode, null, TestOrganisasjonId.toStatement)), + NamedParameter("utdanningsmulighet_kode", ParameterValue(row.utdanningsmulighetKode, null, ToStatement.stringToStatement)) + ) + unsaved.toList match { + case Nil => Nil + case head :: rest => + new anorm.adventureworks.ExecuteReturningSyntax.Ops( + BatchSql( + s"""insert into "public"."test_utdanningstilbud"("organisasjonskode", "utdanningsmulighet_kode") + values ({organisasjonskode}, {utdanningsmulighet_kode}) + on conflict ("organisasjonskode", "utdanningsmulighet_kode") + do nothing + returning "organisasjonskode", "utdanningsmulighet_kode" + """, + toNamedParameter(head), + rest.map(toNamedParameter)* + ) + ).executeReturning(TestUtdanningstilbudRow.rowParser(1).*) + } + } + /* NOTE: this functionality is not safe if you use auto-commit mode! it runs 3 SQL statements */ + override def upsertStreaming(unsaved: Iterator[TestUtdanningstilbudRow], batchSize: Int = 10000)(implicit c: Connection): Int = { + SQL"""create temporary table test_utdanningstilbud_TEMP (like "public"."test_utdanningstilbud") on commit drop""".execute(): @nowarn + streamingInsert(s"""copy test_utdanningstilbud_TEMP("organisasjonskode", "utdanningsmulighet_kode") from stdin""", batchSize, unsaved)(TestUtdanningstilbudRow.text, c): @nowarn + SQL"""insert into "public"."test_utdanningstilbud"("organisasjonskode", "utdanningsmulighet_kode") + select * from test_utdanningstilbud_TEMP + on conflict ("organisasjonskode", "utdanningsmulighet_kode") + do nothing + ; + drop table test_utdanningstilbud_TEMP;""".executeUpdate() + } +} diff --git a/typo-tester-anorm/generated-and-checked-in/adventureworks/public/test_utdanningstilbud/TestUtdanningstilbudRepoMock.scala b/typo-tester-anorm/generated-and-checked-in/adventureworks/public/test_utdanningstilbud/TestUtdanningstilbudRepoMock.scala new file mode 100644 index 0000000000..72fa51cffd --- /dev/null +++ b/typo-tester-anorm/generated-and-checked-in/adventureworks/public/test_utdanningstilbud/TestUtdanningstilbudRepoMock.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 test_utdanningstilbud + +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 TestUtdanningstilbudRepoMock(map: scala.collection.mutable.Map[TestUtdanningstilbudId, TestUtdanningstilbudRow] = scala.collection.mutable.Map.empty) extends TestUtdanningstilbudRepo { + override def delete: DeleteBuilder[TestUtdanningstilbudFields, TestUtdanningstilbudRow] = { + DeleteBuilderMock(DeleteParams.empty, TestUtdanningstilbudFields.structure, map) + } + override def deleteById(compositeId: TestUtdanningstilbudId)(implicit c: Connection): Boolean = { + map.remove(compositeId).isDefined + } + override def deleteByIds(compositeIds: Array[TestUtdanningstilbudId])(implicit c: Connection): Int = { + compositeIds.map(id => map.remove(id)).count(_.isDefined) + } + override def insert(unsaved: TestUtdanningstilbudRow)(implicit c: Connection): TestUtdanningstilbudRow = { + val _ = if (map.contains(unsaved.compositeId)) + sys.error(s"id ${unsaved.compositeId} already exists") + else + map.put(unsaved.compositeId, unsaved) + + unsaved + } + override def insertStreaming(unsaved: Iterator[TestUtdanningstilbudRow], batchSize: Int = 10000)(implicit c: Connection): Long = { + unsaved.foreach { row => + map += (row.compositeId -> row) + } + unsaved.size.toLong + } + override def select: SelectBuilder[TestUtdanningstilbudFields, TestUtdanningstilbudRow] = { + SelectBuilderMock(TestUtdanningstilbudFields.structure, () => map.values.toList, SelectParams.empty) + } + override def selectAll(implicit c: Connection): List[TestUtdanningstilbudRow] = { + map.values.toList + } + override def selectById(compositeId: TestUtdanningstilbudId)(implicit c: Connection): Option[TestUtdanningstilbudRow] = { + map.get(compositeId) + } + override def selectByIds(compositeIds: Array[TestUtdanningstilbudId])(implicit c: Connection): List[TestUtdanningstilbudRow] = { + compositeIds.flatMap(map.get).toList + } + override def selectByIdsTracked(compositeIds: Array[TestUtdanningstilbudId])(implicit c: Connection): Map[TestUtdanningstilbudId, TestUtdanningstilbudRow] = { + val byId = selectByIds(compositeIds).view.map(x => (x.compositeId, x)).toMap + compositeIds.view.flatMap(id => byId.get(id).map(x => (id, x))).toMap + } + override def update: UpdateBuilder[TestUtdanningstilbudFields, TestUtdanningstilbudRow] = { + UpdateBuilderMock(UpdateParams.empty, TestUtdanningstilbudFields.structure, map) + } + override def upsert(unsaved: TestUtdanningstilbudRow)(implicit c: Connection): TestUtdanningstilbudRow = { + map.put(unsaved.compositeId, unsaved): @nowarn + unsaved + } + override def upsertBatch(unsaved: Iterable[TestUtdanningstilbudRow])(implicit c: Connection): List[TestUtdanningstilbudRow] = { + unsaved.map { row => + map += (row.compositeId -> 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[TestUtdanningstilbudRow], batchSize: Int = 10000)(implicit c: Connection): Int = { + unsaved.foreach { row => + map += (row.compositeId -> row) + } + unsaved.size + } +} diff --git a/typo-tester-anorm/generated-and-checked-in/adventureworks/public/test_utdanningstilbud/TestUtdanningstilbudRow.scala b/typo-tester-anorm/generated-and-checked-in/adventureworks/public/test_utdanningstilbud/TestUtdanningstilbudRow.scala new file mode 100644 index 0000000000..26c4dfb866 --- /dev/null +++ b/typo-tester-anorm/generated-and-checked-in/adventureworks/public/test_utdanningstilbud/TestUtdanningstilbudRow.scala @@ -0,0 +1,65 @@ +/** + * File has been automatically generated by `typo`. + * + * IF YOU CHANGE THIS FILE YOUR CHANGES WILL BE OVERWRITTEN. + */ +package adventureworks +package public +package test_utdanningstilbud + +import adventureworks.public.test_organisasjon.TestOrganisasjonId +import anorm.Column +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 play.api.libs.json.Writes +import scala.collection.immutable.ListMap +import scala.util.Try + +/** Table: public.test_utdanningstilbud + Composite primary key: organisasjonskode, utdanningsmulighet_kode */ +case class TestUtdanningstilbudRow( + /** Points to [[test_organisasjon.TestOrganisasjonRow.organisasjonskode]] */ + organisasjonskode: TestOrganisasjonId, + utdanningsmulighetKode: String +){ + val compositeId: TestUtdanningstilbudId = TestUtdanningstilbudId(organisasjonskode, utdanningsmulighetKode) + val id = compositeId + } + +object TestUtdanningstilbudRow { + def apply(compositeId: TestUtdanningstilbudId) = + new TestUtdanningstilbudRow(compositeId.organisasjonskode, compositeId.utdanningsmulighetKode) + implicit lazy val reads: Reads[TestUtdanningstilbudRow] = Reads[TestUtdanningstilbudRow](json => JsResult.fromTry( + Try( + TestUtdanningstilbudRow( + organisasjonskode = json.\("organisasjonskode").as(TestOrganisasjonId.reads), + utdanningsmulighetKode = json.\("utdanningsmulighet_kode").as(Reads.StringReads) + ) + ) + ), + ) + def rowParser(idx: Int): RowParser[TestUtdanningstilbudRow] = RowParser[TestUtdanningstilbudRow] { row => + Success( + TestUtdanningstilbudRow( + organisasjonskode = row(idx + 0)(TestOrganisasjonId.column), + utdanningsmulighetKode = row(idx + 1)(Column.columnToString) + ) + ) + } + implicit lazy val text: Text[TestUtdanningstilbudRow] = Text.instance[TestUtdanningstilbudRow]{ (row, sb) => + TestOrganisasjonId.text.unsafeEncode(row.organisasjonskode, sb) + sb.append(Text.DELIMETER) + Text.stringInstance.unsafeEncode(row.utdanningsmulighetKode, sb) + } + implicit lazy val writes: OWrites[TestUtdanningstilbudRow] = OWrites[TestUtdanningstilbudRow](o => + new JsObject(ListMap[String, JsValue]( + "organisasjonskode" -> TestOrganisasjonId.writes.writes(o.organisasjonskode), + "utdanningsmulighet_kode" -> Writes.StringWrites.writes(o.utdanningsmulighetKode) + )) + ) +} 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 8a9129eae2..e6b1bdd743 100644 --- a/typo-tester-anorm/generated-and-checked-in/adventureworks/testInsert.scala +++ b/typo-tester-anorm/generated-and-checked-in/adventureworks/testInsert.scala @@ -219,6 +219,14 @@ import adventureworks.public.table_with_generated_columns.TableWithGeneratedColu import adventureworks.public.table_with_generated_columns.TableWithGeneratedColumnsRepoImpl import adventureworks.public.table_with_generated_columns.TableWithGeneratedColumnsRow import adventureworks.public.table_with_generated_columns.TableWithGeneratedColumnsRowUnsaved +import adventureworks.public.test_organisasjon.TestOrganisasjonId +import adventureworks.public.test_organisasjon.TestOrganisasjonRepoImpl +import adventureworks.public.test_organisasjon.TestOrganisasjonRow +import adventureworks.public.test_sak_soknadsalternativ.TestSakSoknadsalternativRepoImpl +import adventureworks.public.test_sak_soknadsalternativ.TestSakSoknadsalternativRow +import adventureworks.public.test_utdanningstilbud.TestUtdanningstilbudId +import adventureworks.public.test_utdanningstilbud.TestUtdanningstilbudRepoImpl +import adventureworks.public.test_utdanningstilbud.TestUtdanningstilbudRow import adventureworks.public.title.TitleId import adventureworks.public.title.TitleRepoImpl import adventureworks.public.title.TitleRow @@ -796,6 +804,9 @@ class TestInsert(random: Random, domainInsert: TestDomainInsert) { xmles: Option[Array[TypoXml]] = None )(implicit c: Connection): PgtestnullRow = (new PgtestnullRepoImpl).insert(new PgtestnullRow(bool = bool, box = box, bpchar = bpchar, bytea = bytea, char = char, circle = circle, date = date, float4 = float4, float8 = float8, hstore = hstore, inet = inet, int2 = int2, int2vector = int2vector, int4 = int4, int8 = int8, interval = interval, json = json, jsonb = jsonb, line = line, lseg = lseg, money = money, mydomain = mydomain, myenum = myenum, name = name, numeric = numeric, path = path, point = point, polygon = polygon, text = text, time = time, timestamp = timestamp, timestampz = timestampz, timez = timez, uuid = uuid, varchar = varchar, vector = vector, xml = xml, boxes = boxes, bpchares = bpchares, chares = chares, circlees = circlees, datees = datees, float4es = float4es, float8es = float8es, inetes = inetes, int2es = int2es, int2vectores = int2vectores, int4es = int4es, int8es = int8es, intervales = intervales, jsones = jsones, jsonbes = jsonbes, linees = linees, lseges = lseges, moneyes = moneyes, mydomaines = mydomaines, myenumes = myenumes, namees = namees, numerices = numerices, pathes = pathes, pointes = pointes, polygones = polygones, textes = textes, timees = timees, timestampes = timestampes, timestampzes = timestampzes, timezes = timezes, uuides = uuides, varchares = varchares, xmles = xmles)) def publicTableWithGeneratedColumns(name: TableWithGeneratedColumnsId = TableWithGeneratedColumnsId(random.alphanumeric.take(20).mkString))(implicit c: Connection): TableWithGeneratedColumnsRow = (new TableWithGeneratedColumnsRepoImpl).insert(new TableWithGeneratedColumnsRowUnsaved(name = name)) + def publicTestOrganisasjon(organisasjonskode: TestOrganisasjonId = TestOrganisasjonId(random.alphanumeric.take(20).mkString))(implicit c: Connection): TestOrganisasjonRow = (new TestOrganisasjonRepoImpl).insert(new TestOrganisasjonRow(organisasjonskode = organisasjonskode)) + def publicTestSakSoknadsalternativ(TestUtdanningstilbudId: TestUtdanningstilbudId, organisasjonskodeSaksbehandler: String = random.alphanumeric.take(20).mkString)(implicit c: Connection): TestSakSoknadsalternativRow = (new TestSakSoknadsalternativRepoImpl).insert(new TestSakSoknadsalternativRow(organisasjonskodeSaksbehandler = organisasjonskodeSaksbehandler, utdanningsmulighetKode = TestUtdanningstilbudId.utdanningsmulighetKode, organisasjonskodeTilbyder = TestUtdanningstilbudId.organisasjonskode)) + def publicTestUtdanningstilbud(organisasjonskode: TestOrganisasjonId, utdanningsmulighetKode: String = random.alphanumeric.take(20).mkString)(implicit c: Connection): TestUtdanningstilbudRow = (new TestUtdanningstilbudRepoImpl).insert(new TestUtdanningstilbudRow(organisasjonskode = organisasjonskode, utdanningsmulighetKode = utdanningsmulighetKode)) def publicTitle(code: TitleId = TitleId(random.alphanumeric.take(20).mkString))(implicit c: Connection): TitleRow = (new TitleRepoImpl).insert(new TitleRow(code = code)) def publicTitleDomain(code: TitleDomainId = TitleDomainId(domainInsert.publicShortText(random)))(implicit c: Connection): TitleDomainRow = (new TitleDomainRepoImpl).insert(new TitleDomainRow(code = code)) def publicTitledperson(titleShort: TitleDomainId = TitleDomainId.All(random.nextInt(4)), diff --git a/typo-tester-doobie/generated-and-checked-in/adventureworks/public/test_organisasjon/TestOrganisasjonFields.scala b/typo-tester-doobie/generated-and-checked-in/adventureworks/public/test_organisasjon/TestOrganisasjonFields.scala new file mode 100644 index 0000000000..e6198a24cb --- /dev/null +++ b/typo-tester-doobie/generated-and-checked-in/adventureworks/public/test_organisasjon/TestOrganisasjonFields.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 test_organisasjon + +import typo.dsl.Path +import typo.dsl.SqlExpr.FieldLikeNoHkt +import typo.dsl.SqlExpr.IdField +import typo.dsl.Structure.Relation + +trait TestOrganisasjonFields { + def organisasjonskode: IdField[TestOrganisasjonId, TestOrganisasjonRow] +} + +object TestOrganisasjonFields { + lazy val structure: Relation[TestOrganisasjonFields, TestOrganisasjonRow] = + new Impl(Nil) + + private final class Impl(val _path: List[Path]) + extends Relation[TestOrganisasjonFields, TestOrganisasjonRow] { + + override lazy val fields: TestOrganisasjonFields = new TestOrganisasjonFields { + override def organisasjonskode = IdField[TestOrganisasjonId, TestOrganisasjonRow](_path, "organisasjonskode", None, None, x => x.organisasjonskode, (row, value) => row.copy(organisasjonskode = value)) + } + + override lazy val columns: List[FieldLikeNoHkt[?, TestOrganisasjonRow]] = + List[FieldLikeNoHkt[?, TestOrganisasjonRow]](fields.organisasjonskode) + + override def copy(path: List[Path]): Impl = + new Impl(path) + } + +} diff --git a/typo-tester-doobie/generated-and-checked-in/adventureworks/public/test_organisasjon/TestOrganisasjonId.scala b/typo-tester-doobie/generated-and-checked-in/adventureworks/public/test_organisasjon/TestOrganisasjonId.scala new file mode 100644 index 0000000000..09ded0e890 --- /dev/null +++ b/typo-tester-doobie/generated-and-checked-in/adventureworks/public/test_organisasjon/TestOrganisasjonId.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 test_organisasjon + +import doobie.postgres.Text +import doobie.util.Get +import doobie.util.Put +import doobie.util.meta.Meta +import io.circe.Decoder +import io.circe.Encoder +import typo.dsl.Bijection + +/** Type for the primary key of table `public.test_organisasjon` */ +case class TestOrganisasjonId(value: String) extends AnyVal +object TestOrganisasjonId { + implicit lazy val arrayGet: Get[Array[TestOrganisasjonId]] = adventureworks.StringArrayMeta.get.map(_.map(TestOrganisasjonId.apply)) + implicit lazy val arrayPut: Put[Array[TestOrganisasjonId]] = adventureworks.StringArrayMeta.put.contramap(_.map(_.value)) + implicit lazy val bijection: Bijection[TestOrganisasjonId, String] = Bijection[TestOrganisasjonId, String](_.value)(TestOrganisasjonId.apply) + implicit lazy val decoder: Decoder[TestOrganisasjonId] = Decoder.decodeString.map(TestOrganisasjonId.apply) + implicit lazy val encoder: Encoder[TestOrganisasjonId] = Encoder.encodeString.contramap(_.value) + implicit lazy val get: Get[TestOrganisasjonId] = Meta.StringMeta.get.map(TestOrganisasjonId.apply) + implicit lazy val ordering: Ordering[TestOrganisasjonId] = Ordering.by(_.value) + implicit lazy val put: Put[TestOrganisasjonId] = Meta.StringMeta.put.contramap(_.value) + implicit lazy val text: Text[TestOrganisasjonId] = new Text[TestOrganisasjonId] { + override def unsafeEncode(v: TestOrganisasjonId, sb: StringBuilder) = Text.stringInstance.unsafeEncode(v.value, sb) + override def unsafeArrayEncode(v: TestOrganisasjonId, sb: StringBuilder) = Text.stringInstance.unsafeArrayEncode(v.value, sb) + } +} diff --git a/typo-tester-doobie/generated-and-checked-in/adventureworks/public/test_organisasjon/TestOrganisasjonRepo.scala b/typo-tester-doobie/generated-and-checked-in/adventureworks/public/test_organisasjon/TestOrganisasjonRepo.scala new file mode 100644 index 0000000000..95b55aa307 --- /dev/null +++ b/typo-tester-doobie/generated-and-checked-in/adventureworks/public/test_organisasjon/TestOrganisasjonRepo.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 test_organisasjon + +import doobie.free.connection.ConnectionIO +import fs2.Stream +import typo.dsl.DeleteBuilder +import typo.dsl.SelectBuilder +import typo.dsl.UpdateBuilder + +trait TestOrganisasjonRepo { + def delete: DeleteBuilder[TestOrganisasjonFields, TestOrganisasjonRow] + def deleteById(organisasjonskode: TestOrganisasjonId): ConnectionIO[Boolean] + def deleteByIds(organisasjonskodes: Array[TestOrganisasjonId]): ConnectionIO[Int] + def insert(unsaved: TestOrganisasjonRow): ConnectionIO[TestOrganisasjonRow] + def insertStreaming(unsaved: Stream[ConnectionIO, TestOrganisasjonRow], batchSize: Int = 10000): ConnectionIO[Long] + def select: SelectBuilder[TestOrganisasjonFields, TestOrganisasjonRow] + def selectAll: Stream[ConnectionIO, TestOrganisasjonRow] + def selectById(organisasjonskode: TestOrganisasjonId): ConnectionIO[Option[TestOrganisasjonRow]] + def selectByIds(organisasjonskodes: Array[TestOrganisasjonId]): Stream[ConnectionIO, TestOrganisasjonRow] + def selectByIdsTracked(organisasjonskodes: Array[TestOrganisasjonId]): ConnectionIO[Map[TestOrganisasjonId, TestOrganisasjonRow]] + def update: UpdateBuilder[TestOrganisasjonFields, TestOrganisasjonRow] + def upsert(unsaved: TestOrganisasjonRow): ConnectionIO[TestOrganisasjonRow] + def upsertBatch(unsaved: List[TestOrganisasjonRow]): Stream[ConnectionIO, TestOrganisasjonRow] + /* NOTE: this functionality is not safe if you use auto-commit mode! it runs 3 SQL statements */ + def upsertStreaming(unsaved: Stream[ConnectionIO, TestOrganisasjonRow], batchSize: Int = 10000): ConnectionIO[Int] +} diff --git a/typo-tester-doobie/generated-and-checked-in/adventureworks/public/test_organisasjon/TestOrganisasjonRepoImpl.scala b/typo-tester-doobie/generated-and-checked-in/adventureworks/public/test_organisasjon/TestOrganisasjonRepoImpl.scala new file mode 100644 index 0000000000..3d964d70cc --- /dev/null +++ b/typo-tester-doobie/generated-and-checked-in/adventureworks/public/test_organisasjon/TestOrganisasjonRepoImpl.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 test_organisasjon + +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 TestOrganisasjonRepoImpl extends TestOrganisasjonRepo { + override def delete: DeleteBuilder[TestOrganisasjonFields, TestOrganisasjonRow] = { + DeleteBuilder(""""public"."test_organisasjon"""", TestOrganisasjonFields.structure) + } + override def deleteById(organisasjonskode: TestOrganisasjonId): ConnectionIO[Boolean] = { + sql"""delete from "public"."test_organisasjon" where "organisasjonskode" = ${fromWrite(organisasjonskode)(Write.fromPut(TestOrganisasjonId.put))}""".update.run.map(_ > 0) + } + override def deleteByIds(organisasjonskodes: Array[TestOrganisasjonId]): ConnectionIO[Int] = { + sql"""delete from "public"."test_organisasjon" where "organisasjonskode" = ANY(${organisasjonskodes})""".update.run + } + override def insert(unsaved: TestOrganisasjonRow): ConnectionIO[TestOrganisasjonRow] = { + sql"""insert into "public"."test_organisasjon"("organisasjonskode") + values (${fromWrite(unsaved.organisasjonskode)(Write.fromPut(TestOrganisasjonId.put))}) + returning "organisasjonskode" + """.query(using TestOrganisasjonRow.read).unique + } + override def insertStreaming(unsaved: Stream[ConnectionIO, TestOrganisasjonRow], batchSize: Int = 10000): ConnectionIO[Long] = { + new FragmentOps(sql"""COPY "public"."test_organisasjon"("organisasjonskode") FROM STDIN""").copyIn(unsaved, batchSize)(using TestOrganisasjonRow.text) + } + override def select: SelectBuilder[TestOrganisasjonFields, TestOrganisasjonRow] = { + SelectBuilderSql(""""public"."test_organisasjon"""", TestOrganisasjonFields.structure, TestOrganisasjonRow.read) + } + override def selectAll: Stream[ConnectionIO, TestOrganisasjonRow] = { + sql"""select "organisasjonskode" from "public"."test_organisasjon"""".query(using TestOrganisasjonRow.read).stream + } + override def selectById(organisasjonskode: TestOrganisasjonId): ConnectionIO[Option[TestOrganisasjonRow]] = { + sql"""select "organisasjonskode" from "public"."test_organisasjon" where "organisasjonskode" = ${fromWrite(organisasjonskode)(Write.fromPut(TestOrganisasjonId.put))}""".query(using TestOrganisasjonRow.read).option + } + override def selectByIds(organisasjonskodes: Array[TestOrganisasjonId]): Stream[ConnectionIO, TestOrganisasjonRow] = { + sql"""select "organisasjonskode" from "public"."test_organisasjon" where "organisasjonskode" = ANY(${organisasjonskodes})""".query(using TestOrganisasjonRow.read).stream + } + override def selectByIdsTracked(organisasjonskodes: Array[TestOrganisasjonId]): ConnectionIO[Map[TestOrganisasjonId, TestOrganisasjonRow]] = { + selectByIds(organisasjonskodes).compile.toList.map { rows => + val byId = rows.view.map(x => (x.organisasjonskode, x)).toMap + organisasjonskodes.view.flatMap(id => byId.get(id).map(x => (id, x))).toMap + } + } + override def update: UpdateBuilder[TestOrganisasjonFields, TestOrganisasjonRow] = { + UpdateBuilder(""""public"."test_organisasjon"""", TestOrganisasjonFields.structure, TestOrganisasjonRow.read) + } + override def upsert(unsaved: TestOrganisasjonRow): ConnectionIO[TestOrganisasjonRow] = { + sql"""insert into "public"."test_organisasjon"("organisasjonskode") + values ( + ${fromWrite(unsaved.organisasjonskode)(Write.fromPut(TestOrganisasjonId.put))} + ) + on conflict ("organisasjonskode") + do update set "organisasjonskode" = EXCLUDED."organisasjonskode" + returning "organisasjonskode" + """.query(using TestOrganisasjonRow.read).unique + } + override def upsertBatch(unsaved: List[TestOrganisasjonRow]): Stream[ConnectionIO, TestOrganisasjonRow] = { + Update[TestOrganisasjonRow]( + s"""insert into "public"."test_organisasjon"("organisasjonskode") + values (?) + on conflict ("organisasjonskode") + do nothing + returning "organisasjonskode"""" + )(using TestOrganisasjonRow.write) + .updateManyWithGeneratedKeys[TestOrganisasjonRow]("organisasjonskode")(unsaved)(using catsStdInstancesForList, TestOrganisasjonRow.read) + } + /* NOTE: this functionality is not safe if you use auto-commit mode! it runs 3 SQL statements */ + override def upsertStreaming(unsaved: Stream[ConnectionIO, TestOrganisasjonRow], batchSize: Int = 10000): ConnectionIO[Int] = { + for { + _ <- sql"""create temporary table test_organisasjon_TEMP (like "public"."test_organisasjon") on commit drop""".update.run + _ <- new FragmentOps(sql"""copy test_organisasjon_TEMP("organisasjonskode") from stdin""").copyIn(unsaved, batchSize)(using TestOrganisasjonRow.text) + res <- sql"""insert into "public"."test_organisasjon"("organisasjonskode") + select * from test_organisasjon_TEMP + on conflict ("organisasjonskode") + do nothing + ; + drop table test_organisasjon_TEMP;""".update.run + } yield res + } +} diff --git a/typo-tester-doobie/generated-and-checked-in/adventureworks/public/test_organisasjon/TestOrganisasjonRepoMock.scala b/typo-tester-doobie/generated-and-checked-in/adventureworks/public/test_organisasjon/TestOrganisasjonRepoMock.scala new file mode 100644 index 0000000000..16e11e6462 --- /dev/null +++ b/typo-tester-doobie/generated-and-checked-in/adventureworks/public/test_organisasjon/TestOrganisasjonRepoMock.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 test_organisasjon + +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 TestOrganisasjonRepoMock(map: scala.collection.mutable.Map[TestOrganisasjonId, TestOrganisasjonRow] = scala.collection.mutable.Map.empty) extends TestOrganisasjonRepo { + override def delete: DeleteBuilder[TestOrganisasjonFields, TestOrganisasjonRow] = { + DeleteBuilderMock(DeleteParams.empty, TestOrganisasjonFields.structure, map) + } + override def deleteById(organisasjonskode: TestOrganisasjonId): ConnectionIO[Boolean] = { + delay(map.remove(organisasjonskode).isDefined) + } + override def deleteByIds(organisasjonskodes: Array[TestOrganisasjonId]): ConnectionIO[Int] = { + delay(organisasjonskodes.map(id => map.remove(id)).count(_.isDefined)) + } + override def insert(unsaved: TestOrganisasjonRow): ConnectionIO[TestOrganisasjonRow] = { + delay { + val _ = if (map.contains(unsaved.organisasjonskode)) + sys.error(s"id ${unsaved.organisasjonskode} already exists") + else + map.put(unsaved.organisasjonskode, unsaved) + + unsaved + } + } + override def insertStreaming(unsaved: Stream[ConnectionIO, TestOrganisasjonRow], batchSize: Int = 10000): ConnectionIO[Long] = { + unsaved.compile.toList.map { rows => + var num = 0L + rows.foreach { row => + map += (row.organisasjonskode -> row) + num += 1 + } + num + } + } + override def select: SelectBuilder[TestOrganisasjonFields, TestOrganisasjonRow] = { + SelectBuilderMock(TestOrganisasjonFields.structure, delay(map.values.toList), SelectParams.empty) + } + override def selectAll: Stream[ConnectionIO, TestOrganisasjonRow] = { + Stream.emits(map.values.toList) + } + override def selectById(organisasjonskode: TestOrganisasjonId): ConnectionIO[Option[TestOrganisasjonRow]] = { + delay(map.get(organisasjonskode)) + } + override def selectByIds(organisasjonskodes: Array[TestOrganisasjonId]): Stream[ConnectionIO, TestOrganisasjonRow] = { + Stream.emits(organisasjonskodes.flatMap(map.get).toList) + } + override def selectByIdsTracked(organisasjonskodes: Array[TestOrganisasjonId]): ConnectionIO[Map[TestOrganisasjonId, TestOrganisasjonRow]] = { + selectByIds(organisasjonskodes).compile.toList.map { rows => + val byId = rows.view.map(x => (x.organisasjonskode, x)).toMap + organisasjonskodes.view.flatMap(id => byId.get(id).map(x => (id, x))).toMap + } + } + override def update: UpdateBuilder[TestOrganisasjonFields, TestOrganisasjonRow] = { + UpdateBuilderMock(UpdateParams.empty, TestOrganisasjonFields.structure, map) + } + override def upsert(unsaved: TestOrganisasjonRow): ConnectionIO[TestOrganisasjonRow] = { + delay { + map.put(unsaved.organisasjonskode, unsaved): @nowarn + unsaved + } + } + override def upsertBatch(unsaved: List[TestOrganisasjonRow]): Stream[ConnectionIO, TestOrganisasjonRow] = { + Stream.emits { + unsaved.map { row => + map += (row.organisasjonskode -> 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, TestOrganisasjonRow], batchSize: Int = 10000): ConnectionIO[Int] = { + unsaved.compile.toList.map { rows => + var num = 0 + rows.foreach { row => + map += (row.organisasjonskode -> row) + num += 1 + } + num + } + } +} diff --git a/typo-tester-doobie/generated-and-checked-in/adventureworks/public/test_organisasjon/TestOrganisasjonRow.scala b/typo-tester-doobie/generated-and-checked-in/adventureworks/public/test_organisasjon/TestOrganisasjonRow.scala new file mode 100644 index 0000000000..aa5c7ee7b7 --- /dev/null +++ b/typo-tester-doobie/generated-and-checked-in/adventureworks/public/test_organisasjon/TestOrganisasjonRow.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 test_organisasjon + +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.test_organisasjon + Primary key: organisasjonskode */ +case class TestOrganisasjonRow( + organisasjonskode: TestOrganisasjonId +){ + val id = organisasjonskode + } + +object TestOrganisasjonRow { + implicit lazy val decoder: Decoder[TestOrganisasjonRow] = Decoder.forProduct1[TestOrganisasjonRow, TestOrganisasjonId]("organisasjonskode")(TestOrganisasjonRow.apply)(TestOrganisasjonId.decoder) + implicit lazy val encoder: Encoder[TestOrganisasjonRow] = Encoder.forProduct1[TestOrganisasjonRow, TestOrganisasjonId]("organisasjonskode")(x => (x.organisasjonskode))(TestOrganisasjonId.encoder) + implicit lazy val read: Read[TestOrganisasjonRow] = new Read[TestOrganisasjonRow]( + gets = List( + (TestOrganisasjonId.get, Nullability.NoNulls) + ), + unsafeGet = (rs: ResultSet, i: Int) => TestOrganisasjonRow( + organisasjonskode = TestOrganisasjonId.get.unsafeGetNonNullable(rs, i + 0) + ) + ) + implicit lazy val text: Text[TestOrganisasjonRow] = Text.instance[TestOrganisasjonRow]{ (row, sb) => + TestOrganisasjonId.text.unsafeEncode(row.organisasjonskode, sb) + } + implicit lazy val write: Write[TestOrganisasjonRow] = new Write[TestOrganisasjonRow]( + puts = List((TestOrganisasjonId.put, Nullability.NoNulls)), + toList = x => List(x.organisasjonskode), + unsafeSet = (rs, i, a) => { + TestOrganisasjonId.put.unsafeSetNonNullable(rs, i + 0, a.organisasjonskode) + }, + unsafeUpdate = (ps, i, a) => { + TestOrganisasjonId.put.unsafeUpdateNonNullable(ps, i + 0, a.organisasjonskode) + } + ) +} diff --git a/typo-tester-doobie/generated-and-checked-in/adventureworks/public/test_sak_soknadsalternativ/TestSakSoknadsalternativFields.scala b/typo-tester-doobie/generated-and-checked-in/adventureworks/public/test_sak_soknadsalternativ/TestSakSoknadsalternativFields.scala new file mode 100644 index 0000000000..c10b135725 --- /dev/null +++ b/typo-tester-doobie/generated-and-checked-in/adventureworks/public/test_sak_soknadsalternativ/TestSakSoknadsalternativFields.scala @@ -0,0 +1,65 @@ +/** + * File has been automatically generated by `typo`. + * + * IF YOU CHANGE THIS FILE YOUR CHANGES WILL BE OVERWRITTEN. + */ +package adventureworks +package public +package test_sak_soknadsalternativ + +import adventureworks.public.test_organisasjon.TestOrganisasjonId +import adventureworks.public.test_utdanningstilbud.TestUtdanningstilbudFields +import adventureworks.public.test_utdanningstilbud.TestUtdanningstilbudId +import adventureworks.public.test_utdanningstilbud.TestUtdanningstilbudRow +import typo.dsl.ForeignKey +import typo.dsl.Path +import typo.dsl.Required +import typo.dsl.SqlExpr +import typo.dsl.SqlExpr.CompositeIn +import typo.dsl.SqlExpr.CompositeIn.TuplePart +import typo.dsl.SqlExpr.Field +import typo.dsl.SqlExpr.FieldLikeNoHkt +import typo.dsl.SqlExpr.IdField +import typo.dsl.Structure.Relation + +trait TestSakSoknadsalternativFields { + def organisasjonskodeSaksbehandler: IdField[String, TestSakSoknadsalternativRow] + def utdanningsmulighetKode: IdField[String, TestSakSoknadsalternativRow] + def organisasjonskodeTilbyder: Field[TestOrganisasjonId, TestSakSoknadsalternativRow] + def fkTestUtdanningstilbud: ForeignKey[TestUtdanningstilbudFields, TestUtdanningstilbudRow] = + ForeignKey[TestUtdanningstilbudFields, TestUtdanningstilbudRow]("public.test_sak_soknadsalternativ_organisasjonskode_tilbyder_utda_fkey", Nil) + .withColumnPair(organisasjonskodeTilbyder, _.organisasjonskode) + .withColumnPair(utdanningsmulighetKode, _.utdanningsmulighetKode) + def compositeIdIs(compositeId: TestSakSoknadsalternativId): SqlExpr[Boolean, Required] = + organisasjonskodeSaksbehandler.isEqual(compositeId.organisasjonskodeSaksbehandler).and(utdanningsmulighetKode.isEqual(compositeId.utdanningsmulighetKode)) + def compositeIdIn(compositeIds: Array[TestSakSoknadsalternativId]): SqlExpr[Boolean, Required] = + new CompositeIn(compositeIds)(TuplePart(organisasjonskodeSaksbehandler)(_.organisasjonskodeSaksbehandler), TuplePart(utdanningsmulighetKode)(_.utdanningsmulighetKode)) + + def extractTestUtdanningstilbudIdIs(id: TestUtdanningstilbudId): SqlExpr[Boolean, Required] = + organisasjonskodeTilbyder.isEqual(id.organisasjonskode).and(utdanningsmulighetKode.isEqual(id.utdanningsmulighetKode)) + def extractTestUtdanningstilbudIdIn(ids: Array[TestUtdanningstilbudId]): SqlExpr[Boolean, Required] = + new CompositeIn(ids)(TuplePart(organisasjonskodeTilbyder)(_.organisasjonskode), TuplePart(utdanningsmulighetKode)(_.utdanningsmulighetKode)) + +} + +object TestSakSoknadsalternativFields { + lazy val structure: Relation[TestSakSoknadsalternativFields, TestSakSoknadsalternativRow] = + new Impl(Nil) + + private final class Impl(val _path: List[Path]) + extends Relation[TestSakSoknadsalternativFields, TestSakSoknadsalternativRow] { + + override lazy val fields: TestSakSoknadsalternativFields = new TestSakSoknadsalternativFields { + override def organisasjonskodeSaksbehandler = IdField[String, TestSakSoknadsalternativRow](_path, "organisasjonskode_saksbehandler", None, None, x => x.organisasjonskodeSaksbehandler, (row, value) => row.copy(organisasjonskodeSaksbehandler = value)) + override def utdanningsmulighetKode = IdField[String, TestSakSoknadsalternativRow](_path, "utdanningsmulighet_kode", None, None, x => x.utdanningsmulighetKode, (row, value) => row.copy(utdanningsmulighetKode = value)) + override def organisasjonskodeTilbyder = Field[TestOrganisasjonId, TestSakSoknadsalternativRow](_path, "organisasjonskode_tilbyder", None, None, x => x.organisasjonskodeTilbyder, (row, value) => row.copy(organisasjonskodeTilbyder = value)) + } + + override lazy val columns: List[FieldLikeNoHkt[?, TestSakSoknadsalternativRow]] = + List[FieldLikeNoHkt[?, TestSakSoknadsalternativRow]](fields.organisasjonskodeSaksbehandler, fields.utdanningsmulighetKode, fields.organisasjonskodeTilbyder) + + override def copy(path: List[Path]): Impl = + new Impl(path) + } + +} diff --git a/typo-tester-doobie/generated-and-checked-in/adventureworks/public/test_sak_soknadsalternativ/TestSakSoknadsalternativId.scala b/typo-tester-doobie/generated-and-checked-in/adventureworks/public/test_sak_soknadsalternativ/TestSakSoknadsalternativId.scala new file mode 100644 index 0000000000..b826a6aa1e --- /dev/null +++ b/typo-tester-doobie/generated-and-checked-in/adventureworks/public/test_sak_soknadsalternativ/TestSakSoknadsalternativId.scala @@ -0,0 +1,27 @@ +/** + * File has been automatically generated by `typo`. + * + * IF YOU CHANGE THIS FILE YOUR CHANGES WILL BE OVERWRITTEN. + */ +package adventureworks +package public +package test_sak_soknadsalternativ + +import adventureworks.public.test_utdanningstilbud.TestUtdanningstilbudId +import io.circe.Decoder +import io.circe.Encoder + +/** Type for the composite primary key of table `public.test_sak_soknadsalternativ` */ +case class TestSakSoknadsalternativId( + organisasjonskodeSaksbehandler: String, + utdanningsmulighetKode: String +) +object TestSakSoknadsalternativId { + implicit lazy val decoder: Decoder[TestSakSoknadsalternativId] = Decoder.forProduct2[TestSakSoknadsalternativId, String, String]("organisasjonskode_saksbehandler", "utdanningsmulighet_kode")(TestSakSoknadsalternativId.apply)(Decoder.decodeString, Decoder.decodeString) + implicit lazy val encoder: Encoder[TestSakSoknadsalternativId] = Encoder.forProduct2[TestSakSoknadsalternativId, String, String]("organisasjonskode_saksbehandler", "utdanningsmulighet_kode")(x => (x.organisasjonskodeSaksbehandler, x.utdanningsmulighetKode))(Encoder.encodeString, Encoder.encodeString) + def from(TestUtdanningstilbudId: TestUtdanningstilbudId, organisasjonskodeSaksbehandler: String): TestSakSoknadsalternativId = TestSakSoknadsalternativId( + organisasjonskodeSaksbehandler = organisasjonskodeSaksbehandler, + utdanningsmulighetKode = TestUtdanningstilbudId.utdanningsmulighetKode + ) + implicit lazy val ordering: Ordering[TestSakSoknadsalternativId] = Ordering.by(x => (x.organisasjonskodeSaksbehandler, x.utdanningsmulighetKode)) +} diff --git a/typo-tester-doobie/generated-and-checked-in/adventureworks/public/test_sak_soknadsalternativ/TestSakSoknadsalternativRepo.scala b/typo-tester-doobie/generated-and-checked-in/adventureworks/public/test_sak_soknadsalternativ/TestSakSoknadsalternativRepo.scala new file mode 100644 index 0000000000..6d66684e50 --- /dev/null +++ b/typo-tester-doobie/generated-and-checked-in/adventureworks/public/test_sak_soknadsalternativ/TestSakSoknadsalternativRepo.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 test_sak_soknadsalternativ + +import doobie.free.connection.ConnectionIO +import fs2.Stream +import typo.dsl.DeleteBuilder +import typo.dsl.SelectBuilder +import typo.dsl.UpdateBuilder + +trait TestSakSoknadsalternativRepo { + def delete: DeleteBuilder[TestSakSoknadsalternativFields, TestSakSoknadsalternativRow] + def deleteById(compositeId: TestSakSoknadsalternativId): ConnectionIO[Boolean] + def deleteByIds(compositeIds: Array[TestSakSoknadsalternativId]): ConnectionIO[Int] + def insert(unsaved: TestSakSoknadsalternativRow): ConnectionIO[TestSakSoknadsalternativRow] + def insertStreaming(unsaved: Stream[ConnectionIO, TestSakSoknadsalternativRow], batchSize: Int = 10000): ConnectionIO[Long] + def select: SelectBuilder[TestSakSoknadsalternativFields, TestSakSoknadsalternativRow] + def selectAll: Stream[ConnectionIO, TestSakSoknadsalternativRow] + def selectById(compositeId: TestSakSoknadsalternativId): ConnectionIO[Option[TestSakSoknadsalternativRow]] + def selectByIds(compositeIds: Array[TestSakSoknadsalternativId]): Stream[ConnectionIO, TestSakSoknadsalternativRow] + def selectByIdsTracked(compositeIds: Array[TestSakSoknadsalternativId]): ConnectionIO[Map[TestSakSoknadsalternativId, TestSakSoknadsalternativRow]] + def update: UpdateBuilder[TestSakSoknadsalternativFields, TestSakSoknadsalternativRow] + def update(row: TestSakSoknadsalternativRow): ConnectionIO[Boolean] + def upsert(unsaved: TestSakSoknadsalternativRow): ConnectionIO[TestSakSoknadsalternativRow] + def upsertBatch(unsaved: List[TestSakSoknadsalternativRow]): Stream[ConnectionIO, TestSakSoknadsalternativRow] + /* NOTE: this functionality is not safe if you use auto-commit mode! it runs 3 SQL statements */ + def upsertStreaming(unsaved: Stream[ConnectionIO, TestSakSoknadsalternativRow], batchSize: Int = 10000): ConnectionIO[Int] +} diff --git a/typo-tester-doobie/generated-and-checked-in/adventureworks/public/test_sak_soknadsalternativ/TestSakSoknadsalternativRepoImpl.scala b/typo-tester-doobie/generated-and-checked-in/adventureworks/public/test_sak_soknadsalternativ/TestSakSoknadsalternativRepoImpl.scala new file mode 100644 index 0000000000..221914bd32 --- /dev/null +++ b/typo-tester-doobie/generated-and-checked-in/adventureworks/public/test_sak_soknadsalternativ/TestSakSoknadsalternativRepoImpl.scala @@ -0,0 +1,126 @@ +/** + * File has been automatically generated by `typo`. + * + * IF YOU CHANGE THIS FILE YOUR CHANGES WILL BE OVERWRITTEN. + */ +package adventureworks +package public +package test_sak_soknadsalternativ + +import adventureworks.public.test_organisasjon.TestOrganisasjonId +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.meta.Meta +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 TestSakSoknadsalternativRepoImpl extends TestSakSoknadsalternativRepo { + override def delete: DeleteBuilder[TestSakSoknadsalternativFields, TestSakSoknadsalternativRow] = { + DeleteBuilder(""""public"."test_sak_soknadsalternativ"""", TestSakSoknadsalternativFields.structure) + } + override def deleteById(compositeId: TestSakSoknadsalternativId): ConnectionIO[Boolean] = { + sql"""delete from "public"."test_sak_soknadsalternativ" where "organisasjonskode_saksbehandler" = ${fromWrite(compositeId.organisasjonskodeSaksbehandler)(Write.fromPut(Meta.StringMeta.put))} AND "utdanningsmulighet_kode" = ${fromWrite(compositeId.utdanningsmulighetKode)(Write.fromPut(Meta.StringMeta.put))}""".update.run.map(_ > 0) + } + override def deleteByIds(compositeIds: Array[TestSakSoknadsalternativId]): ConnectionIO[Int] = { + val organisasjonskodeSaksbehandler = compositeIds.map(_.organisasjonskodeSaksbehandler) + val utdanningsmulighetKode = compositeIds.map(_.utdanningsmulighetKode) + sql"""delete + from "public"."test_sak_soknadsalternativ" + where ("organisasjonskode_saksbehandler", "utdanningsmulighet_kode") + in (select unnest(${organisasjonskodeSaksbehandler}), unnest(${utdanningsmulighetKode})) + """.update.run + + } + override def insert(unsaved: TestSakSoknadsalternativRow): ConnectionIO[TestSakSoknadsalternativRow] = { + sql"""insert into "public"."test_sak_soknadsalternativ"("organisasjonskode_saksbehandler", "utdanningsmulighet_kode", "organisasjonskode_tilbyder") + values (${fromWrite(unsaved.organisasjonskodeSaksbehandler)(Write.fromPut(Meta.StringMeta.put))}, ${fromWrite(unsaved.utdanningsmulighetKode)(Write.fromPut(Meta.StringMeta.put))}, ${fromWrite(unsaved.organisasjonskodeTilbyder)(Write.fromPut(TestOrganisasjonId.put))}) + returning "organisasjonskode_saksbehandler", "utdanningsmulighet_kode", "organisasjonskode_tilbyder" + """.query(using TestSakSoknadsalternativRow.read).unique + } + override def insertStreaming(unsaved: Stream[ConnectionIO, TestSakSoknadsalternativRow], batchSize: Int = 10000): ConnectionIO[Long] = { + new FragmentOps(sql"""COPY "public"."test_sak_soknadsalternativ"("organisasjonskode_saksbehandler", "utdanningsmulighet_kode", "organisasjonskode_tilbyder") FROM STDIN""").copyIn(unsaved, batchSize)(using TestSakSoknadsalternativRow.text) + } + override def select: SelectBuilder[TestSakSoknadsalternativFields, TestSakSoknadsalternativRow] = { + SelectBuilderSql(""""public"."test_sak_soknadsalternativ"""", TestSakSoknadsalternativFields.structure, TestSakSoknadsalternativRow.read) + } + override def selectAll: Stream[ConnectionIO, TestSakSoknadsalternativRow] = { + sql"""select "organisasjonskode_saksbehandler", "utdanningsmulighet_kode", "organisasjonskode_tilbyder" from "public"."test_sak_soknadsalternativ"""".query(using TestSakSoknadsalternativRow.read).stream + } + override def selectById(compositeId: TestSakSoknadsalternativId): ConnectionIO[Option[TestSakSoknadsalternativRow]] = { + sql"""select "organisasjonskode_saksbehandler", "utdanningsmulighet_kode", "organisasjonskode_tilbyder" from "public"."test_sak_soknadsalternativ" where "organisasjonskode_saksbehandler" = ${fromWrite(compositeId.organisasjonskodeSaksbehandler)(Write.fromPut(Meta.StringMeta.put))} AND "utdanningsmulighet_kode" = ${fromWrite(compositeId.utdanningsmulighetKode)(Write.fromPut(Meta.StringMeta.put))}""".query(using TestSakSoknadsalternativRow.read).option + } + override def selectByIds(compositeIds: Array[TestSakSoknadsalternativId]): Stream[ConnectionIO, TestSakSoknadsalternativRow] = { + val organisasjonskodeSaksbehandler = compositeIds.map(_.organisasjonskodeSaksbehandler) + val utdanningsmulighetKode = compositeIds.map(_.utdanningsmulighetKode) + sql"""select "organisasjonskode_saksbehandler", "utdanningsmulighet_kode", "organisasjonskode_tilbyder" + from "public"."test_sak_soknadsalternativ" + where ("organisasjonskode_saksbehandler", "utdanningsmulighet_kode") + in (select unnest(${organisasjonskodeSaksbehandler}), unnest(${utdanningsmulighetKode})) + """.query(using TestSakSoknadsalternativRow.read).stream + + } + override def selectByIdsTracked(compositeIds: Array[TestSakSoknadsalternativId]): ConnectionIO[Map[TestSakSoknadsalternativId, TestSakSoknadsalternativRow]] = { + selectByIds(compositeIds).compile.toList.map { rows => + val byId = rows.view.map(x => (x.compositeId, x)).toMap + compositeIds.view.flatMap(id => byId.get(id).map(x => (id, x))).toMap + } + } + override def update: UpdateBuilder[TestSakSoknadsalternativFields, TestSakSoknadsalternativRow] = { + UpdateBuilder(""""public"."test_sak_soknadsalternativ"""", TestSakSoknadsalternativFields.structure, TestSakSoknadsalternativRow.read) + } + override def update(row: TestSakSoknadsalternativRow): ConnectionIO[Boolean] = { + val compositeId = row.compositeId + sql"""update "public"."test_sak_soknadsalternativ" + set "organisasjonskode_tilbyder" = ${fromWrite(row.organisasjonskodeTilbyder)(Write.fromPut(TestOrganisasjonId.put))} + where "organisasjonskode_saksbehandler" = ${fromWrite(compositeId.organisasjonskodeSaksbehandler)(Write.fromPut(Meta.StringMeta.put))} AND "utdanningsmulighet_kode" = ${fromWrite(compositeId.utdanningsmulighetKode)(Write.fromPut(Meta.StringMeta.put))}""" + .update + .run + .map(_ > 0) + } + override def upsert(unsaved: TestSakSoknadsalternativRow): ConnectionIO[TestSakSoknadsalternativRow] = { + sql"""insert into "public"."test_sak_soknadsalternativ"("organisasjonskode_saksbehandler", "utdanningsmulighet_kode", "organisasjonskode_tilbyder") + values ( + ${fromWrite(unsaved.organisasjonskodeSaksbehandler)(Write.fromPut(Meta.StringMeta.put))}, + ${fromWrite(unsaved.utdanningsmulighetKode)(Write.fromPut(Meta.StringMeta.put))}, + ${fromWrite(unsaved.organisasjonskodeTilbyder)(Write.fromPut(TestOrganisasjonId.put))} + ) + on conflict ("organisasjonskode_saksbehandler", "utdanningsmulighet_kode") + do update set + "organisasjonskode_tilbyder" = EXCLUDED."organisasjonskode_tilbyder" + returning "organisasjonskode_saksbehandler", "utdanningsmulighet_kode", "organisasjonskode_tilbyder" + """.query(using TestSakSoknadsalternativRow.read).unique + } + override def upsertBatch(unsaved: List[TestSakSoknadsalternativRow]): Stream[ConnectionIO, TestSakSoknadsalternativRow] = { + Update[TestSakSoknadsalternativRow]( + s"""insert into "public"."test_sak_soknadsalternativ"("organisasjonskode_saksbehandler", "utdanningsmulighet_kode", "organisasjonskode_tilbyder") + values (?,?,?) + on conflict ("organisasjonskode_saksbehandler", "utdanningsmulighet_kode") + do update set + "organisasjonskode_tilbyder" = EXCLUDED."organisasjonskode_tilbyder" + returning "organisasjonskode_saksbehandler", "utdanningsmulighet_kode", "organisasjonskode_tilbyder"""" + )(using TestSakSoknadsalternativRow.write) + .updateManyWithGeneratedKeys[TestSakSoknadsalternativRow]("organisasjonskode_saksbehandler", "utdanningsmulighet_kode", "organisasjonskode_tilbyder")(unsaved)(using catsStdInstancesForList, TestSakSoknadsalternativRow.read) + } + /* NOTE: this functionality is not safe if you use auto-commit mode! it runs 3 SQL statements */ + override def upsertStreaming(unsaved: Stream[ConnectionIO, TestSakSoknadsalternativRow], batchSize: Int = 10000): ConnectionIO[Int] = { + for { + _ <- sql"""create temporary table test_sak_soknadsalternativ_TEMP (like "public"."test_sak_soknadsalternativ") on commit drop""".update.run + _ <- new FragmentOps(sql"""copy test_sak_soknadsalternativ_TEMP("organisasjonskode_saksbehandler", "utdanningsmulighet_kode", "organisasjonskode_tilbyder") from stdin""").copyIn(unsaved, batchSize)(using TestSakSoknadsalternativRow.text) + res <- sql"""insert into "public"."test_sak_soknadsalternativ"("organisasjonskode_saksbehandler", "utdanningsmulighet_kode", "organisasjonskode_tilbyder") + select * from test_sak_soknadsalternativ_TEMP + on conflict ("organisasjonskode_saksbehandler", "utdanningsmulighet_kode") + do update set + "organisasjonskode_tilbyder" = EXCLUDED."organisasjonskode_tilbyder" + ; + drop table test_sak_soknadsalternativ_TEMP;""".update.run + } yield res + } +} diff --git a/typo-tester-doobie/generated-and-checked-in/adventureworks/public/test_sak_soknadsalternativ/TestSakSoknadsalternativRepoMock.scala b/typo-tester-doobie/generated-and-checked-in/adventureworks/public/test_sak_soknadsalternativ/TestSakSoknadsalternativRepoMock.scala new file mode 100644 index 0000000000..37e7334f49 --- /dev/null +++ b/typo-tester-doobie/generated-and-checked-in/adventureworks/public/test_sak_soknadsalternativ/TestSakSoknadsalternativRepoMock.scala @@ -0,0 +1,111 @@ +/** + * File has been automatically generated by `typo`. + * + * IF YOU CHANGE THIS FILE YOUR CHANGES WILL BE OVERWRITTEN. + */ +package adventureworks +package public +package test_sak_soknadsalternativ + +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 TestSakSoknadsalternativRepoMock(map: scala.collection.mutable.Map[TestSakSoknadsalternativId, TestSakSoknadsalternativRow] = scala.collection.mutable.Map.empty) extends TestSakSoknadsalternativRepo { + override def delete: DeleteBuilder[TestSakSoknadsalternativFields, TestSakSoknadsalternativRow] = { + DeleteBuilderMock(DeleteParams.empty, TestSakSoknadsalternativFields.structure, map) + } + override def deleteById(compositeId: TestSakSoknadsalternativId): ConnectionIO[Boolean] = { + delay(map.remove(compositeId).isDefined) + } + override def deleteByIds(compositeIds: Array[TestSakSoknadsalternativId]): ConnectionIO[Int] = { + delay(compositeIds.map(id => map.remove(id)).count(_.isDefined)) + } + override def insert(unsaved: TestSakSoknadsalternativRow): ConnectionIO[TestSakSoknadsalternativRow] = { + delay { + val _ = if (map.contains(unsaved.compositeId)) + sys.error(s"id ${unsaved.compositeId} already exists") + else + map.put(unsaved.compositeId, unsaved) + + unsaved + } + } + override def insertStreaming(unsaved: Stream[ConnectionIO, TestSakSoknadsalternativRow], batchSize: Int = 10000): ConnectionIO[Long] = { + unsaved.compile.toList.map { rows => + var num = 0L + rows.foreach { row => + map += (row.compositeId -> row) + num += 1 + } + num + } + } + override def select: SelectBuilder[TestSakSoknadsalternativFields, TestSakSoknadsalternativRow] = { + SelectBuilderMock(TestSakSoknadsalternativFields.structure, delay(map.values.toList), SelectParams.empty) + } + override def selectAll: Stream[ConnectionIO, TestSakSoknadsalternativRow] = { + Stream.emits(map.values.toList) + } + override def selectById(compositeId: TestSakSoknadsalternativId): ConnectionIO[Option[TestSakSoknadsalternativRow]] = { + delay(map.get(compositeId)) + } + override def selectByIds(compositeIds: Array[TestSakSoknadsalternativId]): Stream[ConnectionIO, TestSakSoknadsalternativRow] = { + Stream.emits(compositeIds.flatMap(map.get).toList) + } + override def selectByIdsTracked(compositeIds: Array[TestSakSoknadsalternativId]): ConnectionIO[Map[TestSakSoknadsalternativId, TestSakSoknadsalternativRow]] = { + selectByIds(compositeIds).compile.toList.map { rows => + val byId = rows.view.map(x => (x.compositeId, x)).toMap + compositeIds.view.flatMap(id => byId.get(id).map(x => (id, x))).toMap + } + } + override def update: UpdateBuilder[TestSakSoknadsalternativFields, TestSakSoknadsalternativRow] = { + UpdateBuilderMock(UpdateParams.empty, TestSakSoknadsalternativFields.structure, map) + } + override def update(row: TestSakSoknadsalternativRow): ConnectionIO[Boolean] = { + delay { + map.get(row.compositeId) match { + case Some(`row`) => false + case Some(_) => + map.put(row.compositeId, row): @nowarn + true + case None => false + } + } + } + override def upsert(unsaved: TestSakSoknadsalternativRow): ConnectionIO[TestSakSoknadsalternativRow] = { + delay { + map.put(unsaved.compositeId, unsaved): @nowarn + unsaved + } + } + override def upsertBatch(unsaved: List[TestSakSoknadsalternativRow]): Stream[ConnectionIO, TestSakSoknadsalternativRow] = { + Stream.emits { + unsaved.map { row => + map += (row.compositeId -> 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, TestSakSoknadsalternativRow], batchSize: Int = 10000): ConnectionIO[Int] = { + unsaved.compile.toList.map { rows => + var num = 0 + rows.foreach { row => + map += (row.compositeId -> row) + num += 1 + } + num + } + } +} diff --git a/typo-tester-doobie/generated-and-checked-in/adventureworks/public/test_sak_soknadsalternativ/TestSakSoknadsalternativRow.scala b/typo-tester-doobie/generated-and-checked-in/adventureworks/public/test_sak_soknadsalternativ/TestSakSoknadsalternativRow.scala new file mode 100644 index 0000000000..ace8c149cc --- /dev/null +++ b/typo-tester-doobie/generated-and-checked-in/adventureworks/public/test_sak_soknadsalternativ/TestSakSoknadsalternativRow.scala @@ -0,0 +1,78 @@ +/** + * File has been automatically generated by `typo`. + * + * IF YOU CHANGE THIS FILE YOUR CHANGES WILL BE OVERWRITTEN. + */ +package adventureworks +package public +package test_sak_soknadsalternativ + +import adventureworks.public.test_organisasjon.TestOrganisasjonId +import adventureworks.public.test_utdanningstilbud.TestUtdanningstilbudId +import doobie.enumerated.Nullability +import doobie.postgres.Text +import doobie.util.Read +import doobie.util.Write +import doobie.util.meta.Meta +import io.circe.Decoder +import io.circe.Encoder +import java.sql.ResultSet + +/** Table: public.test_sak_soknadsalternativ + Composite primary key: organisasjonskode_saksbehandler, utdanningsmulighet_kode */ +case class TestSakSoknadsalternativRow( + organisasjonskodeSaksbehandler: String, + /** Points to [[test_utdanningstilbud.TestUtdanningstilbudRow.utdanningsmulighetKode]] */ + utdanningsmulighetKode: String, + /** Points to [[test_utdanningstilbud.TestUtdanningstilbudRow.organisasjonskode]] */ + organisasjonskodeTilbyder: TestOrganisasjonId +){ + val compositeId: TestSakSoknadsalternativId = TestSakSoknadsalternativId(organisasjonskodeSaksbehandler, utdanningsmulighetKode) + val id = compositeId + val extractTestUtdanningstilbudId: TestUtdanningstilbudId = TestUtdanningstilbudId( + organisasjonskode = organisasjonskodeTilbyder, + utdanningsmulighetKode = utdanningsmulighetKode + ) + } + +object TestSakSoknadsalternativRow { + def apply(compositeId: TestSakSoknadsalternativId, organisasjonskodeTilbyder: TestOrganisasjonId) = + new TestSakSoknadsalternativRow(compositeId.organisasjonskodeSaksbehandler, compositeId.utdanningsmulighetKode, organisasjonskodeTilbyder) + implicit lazy val decoder: Decoder[TestSakSoknadsalternativRow] = Decoder.forProduct3[TestSakSoknadsalternativRow, String, String, TestOrganisasjonId]("organisasjonskode_saksbehandler", "utdanningsmulighet_kode", "organisasjonskode_tilbyder")(TestSakSoknadsalternativRow.apply)(Decoder.decodeString, Decoder.decodeString, TestOrganisasjonId.decoder) + implicit lazy val encoder: Encoder[TestSakSoknadsalternativRow] = Encoder.forProduct3[TestSakSoknadsalternativRow, String, String, TestOrganisasjonId]("organisasjonskode_saksbehandler", "utdanningsmulighet_kode", "organisasjonskode_tilbyder")(x => (x.organisasjonskodeSaksbehandler, x.utdanningsmulighetKode, x.organisasjonskodeTilbyder))(Encoder.encodeString, Encoder.encodeString, TestOrganisasjonId.encoder) + implicit lazy val read: Read[TestSakSoknadsalternativRow] = new Read[TestSakSoknadsalternativRow]( + gets = List( + (Meta.StringMeta.get, Nullability.NoNulls), + (Meta.StringMeta.get, Nullability.NoNulls), + (TestOrganisasjonId.get, Nullability.NoNulls) + ), + unsafeGet = (rs: ResultSet, i: Int) => TestSakSoknadsalternativRow( + organisasjonskodeSaksbehandler = Meta.StringMeta.get.unsafeGetNonNullable(rs, i + 0), + utdanningsmulighetKode = Meta.StringMeta.get.unsafeGetNonNullable(rs, i + 1), + organisasjonskodeTilbyder = TestOrganisasjonId.get.unsafeGetNonNullable(rs, i + 2) + ) + ) + implicit lazy val text: Text[TestSakSoknadsalternativRow] = Text.instance[TestSakSoknadsalternativRow]{ (row, sb) => + Text.stringInstance.unsafeEncode(row.organisasjonskodeSaksbehandler, sb) + sb.append(Text.DELIMETER) + Text.stringInstance.unsafeEncode(row.utdanningsmulighetKode, sb) + sb.append(Text.DELIMETER) + TestOrganisasjonId.text.unsafeEncode(row.organisasjonskodeTilbyder, sb) + } + implicit lazy val write: Write[TestSakSoknadsalternativRow] = new Write[TestSakSoknadsalternativRow]( + puts = List((Meta.StringMeta.put, Nullability.NoNulls), + (Meta.StringMeta.put, Nullability.NoNulls), + (TestOrganisasjonId.put, Nullability.NoNulls)), + toList = x => List(x.organisasjonskodeSaksbehandler, x.utdanningsmulighetKode, x.organisasjonskodeTilbyder), + unsafeSet = (rs, i, a) => { + Meta.StringMeta.put.unsafeSetNonNullable(rs, i + 0, a.organisasjonskodeSaksbehandler) + Meta.StringMeta.put.unsafeSetNonNullable(rs, i + 1, a.utdanningsmulighetKode) + TestOrganisasjonId.put.unsafeSetNonNullable(rs, i + 2, a.organisasjonskodeTilbyder) + }, + unsafeUpdate = (ps, i, a) => { + Meta.StringMeta.put.unsafeUpdateNonNullable(ps, i + 0, a.organisasjonskodeSaksbehandler) + Meta.StringMeta.put.unsafeUpdateNonNullable(ps, i + 1, a.utdanningsmulighetKode) + TestOrganisasjonId.put.unsafeUpdateNonNullable(ps, i + 2, a.organisasjonskodeTilbyder) + } + ) +} diff --git a/typo-tester-doobie/generated-and-checked-in/adventureworks/public/test_utdanningstilbud/TestUtdanningstilbudFields.scala b/typo-tester-doobie/generated-and-checked-in/adventureworks/public/test_utdanningstilbud/TestUtdanningstilbudFields.scala new file mode 100644 index 0000000000..8d12859730 --- /dev/null +++ b/typo-tester-doobie/generated-and-checked-in/adventureworks/public/test_utdanningstilbud/TestUtdanningstilbudFields.scala @@ -0,0 +1,55 @@ +/** + * File has been automatically generated by `typo`. + * + * IF YOU CHANGE THIS FILE YOUR CHANGES WILL BE OVERWRITTEN. + */ +package adventureworks +package public +package test_utdanningstilbud + +import adventureworks.public.test_organisasjon.TestOrganisasjonFields +import adventureworks.public.test_organisasjon.TestOrganisasjonId +import adventureworks.public.test_organisasjon.TestOrganisasjonRow +import typo.dsl.ForeignKey +import typo.dsl.Path +import typo.dsl.Required +import typo.dsl.SqlExpr +import typo.dsl.SqlExpr.CompositeIn +import typo.dsl.SqlExpr.CompositeIn.TuplePart +import typo.dsl.SqlExpr.FieldLikeNoHkt +import typo.dsl.SqlExpr.IdField +import typo.dsl.Structure.Relation + +trait TestUtdanningstilbudFields { + def organisasjonskode: IdField[TestOrganisasjonId, TestUtdanningstilbudRow] + def utdanningsmulighetKode: IdField[String, TestUtdanningstilbudRow] + def fkTestOrganisasjon: ForeignKey[TestOrganisasjonFields, TestOrganisasjonRow] = + ForeignKey[TestOrganisasjonFields, TestOrganisasjonRow]("public.test_utdanningstilbud_organisasjonskode_fkey", Nil) + .withColumnPair(organisasjonskode, _.organisasjonskode) + def compositeIdIs(compositeId: TestUtdanningstilbudId): SqlExpr[Boolean, Required] = + organisasjonskode.isEqual(compositeId.organisasjonskode).and(utdanningsmulighetKode.isEqual(compositeId.utdanningsmulighetKode)) + def compositeIdIn(compositeIds: Array[TestUtdanningstilbudId]): SqlExpr[Boolean, Required] = + new CompositeIn(compositeIds)(TuplePart(organisasjonskode)(_.organisasjonskode), TuplePart(utdanningsmulighetKode)(_.utdanningsmulighetKode)) + +} + +object TestUtdanningstilbudFields { + lazy val structure: Relation[TestUtdanningstilbudFields, TestUtdanningstilbudRow] = + new Impl(Nil) + + private final class Impl(val _path: List[Path]) + extends Relation[TestUtdanningstilbudFields, TestUtdanningstilbudRow] { + + override lazy val fields: TestUtdanningstilbudFields = new TestUtdanningstilbudFields { + override def organisasjonskode = IdField[TestOrganisasjonId, TestUtdanningstilbudRow](_path, "organisasjonskode", None, None, x => x.organisasjonskode, (row, value) => row.copy(organisasjonskode = value)) + override def utdanningsmulighetKode = IdField[String, TestUtdanningstilbudRow](_path, "utdanningsmulighet_kode", None, None, x => x.utdanningsmulighetKode, (row, value) => row.copy(utdanningsmulighetKode = value)) + } + + override lazy val columns: List[FieldLikeNoHkt[?, TestUtdanningstilbudRow]] = + List[FieldLikeNoHkt[?, TestUtdanningstilbudRow]](fields.organisasjonskode, fields.utdanningsmulighetKode) + + override def copy(path: List[Path]): Impl = + new Impl(path) + } + +} diff --git a/typo-tester-doobie/generated-and-checked-in/adventureworks/public/test_utdanningstilbud/TestUtdanningstilbudId.scala b/typo-tester-doobie/generated-and-checked-in/adventureworks/public/test_utdanningstilbud/TestUtdanningstilbudId.scala new file mode 100644 index 0000000000..84bdb2af16 --- /dev/null +++ b/typo-tester-doobie/generated-and-checked-in/adventureworks/public/test_utdanningstilbud/TestUtdanningstilbudId.scala @@ -0,0 +1,23 @@ +/** + * File has been automatically generated by `typo`. + * + * IF YOU CHANGE THIS FILE YOUR CHANGES WILL BE OVERWRITTEN. + */ +package adventureworks +package public +package test_utdanningstilbud + +import adventureworks.public.test_organisasjon.TestOrganisasjonId +import io.circe.Decoder +import io.circe.Encoder + +/** Type for the composite primary key of table `public.test_utdanningstilbud` */ +case class TestUtdanningstilbudId( + organisasjonskode: TestOrganisasjonId, + utdanningsmulighetKode: String +) +object TestUtdanningstilbudId { + implicit lazy val decoder: Decoder[TestUtdanningstilbudId] = Decoder.forProduct2[TestUtdanningstilbudId, TestOrganisasjonId, String]("organisasjonskode", "utdanningsmulighet_kode")(TestUtdanningstilbudId.apply)(TestOrganisasjonId.decoder, Decoder.decodeString) + implicit lazy val encoder: Encoder[TestUtdanningstilbudId] = Encoder.forProduct2[TestUtdanningstilbudId, TestOrganisasjonId, String]("organisasjonskode", "utdanningsmulighet_kode")(x => (x.organisasjonskode, x.utdanningsmulighetKode))(TestOrganisasjonId.encoder, Encoder.encodeString) + implicit lazy val ordering: Ordering[TestUtdanningstilbudId] = Ordering.by(x => (x.organisasjonskode, x.utdanningsmulighetKode)) +} diff --git a/typo-tester-doobie/generated-and-checked-in/adventureworks/public/test_utdanningstilbud/TestUtdanningstilbudRepo.scala b/typo-tester-doobie/generated-and-checked-in/adventureworks/public/test_utdanningstilbud/TestUtdanningstilbudRepo.scala new file mode 100644 index 0000000000..9974e5a9a9 --- /dev/null +++ b/typo-tester-doobie/generated-and-checked-in/adventureworks/public/test_utdanningstilbud/TestUtdanningstilbudRepo.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 test_utdanningstilbud + +import doobie.free.connection.ConnectionIO +import fs2.Stream +import typo.dsl.DeleteBuilder +import typo.dsl.SelectBuilder +import typo.dsl.UpdateBuilder + +trait TestUtdanningstilbudRepo { + def delete: DeleteBuilder[TestUtdanningstilbudFields, TestUtdanningstilbudRow] + def deleteById(compositeId: TestUtdanningstilbudId): ConnectionIO[Boolean] + def deleteByIds(compositeIds: Array[TestUtdanningstilbudId]): ConnectionIO[Int] + def insert(unsaved: TestUtdanningstilbudRow): ConnectionIO[TestUtdanningstilbudRow] + def insertStreaming(unsaved: Stream[ConnectionIO, TestUtdanningstilbudRow], batchSize: Int = 10000): ConnectionIO[Long] + def select: SelectBuilder[TestUtdanningstilbudFields, TestUtdanningstilbudRow] + def selectAll: Stream[ConnectionIO, TestUtdanningstilbudRow] + def selectById(compositeId: TestUtdanningstilbudId): ConnectionIO[Option[TestUtdanningstilbudRow]] + def selectByIds(compositeIds: Array[TestUtdanningstilbudId]): Stream[ConnectionIO, TestUtdanningstilbudRow] + def selectByIdsTracked(compositeIds: Array[TestUtdanningstilbudId]): ConnectionIO[Map[TestUtdanningstilbudId, TestUtdanningstilbudRow]] + def update: UpdateBuilder[TestUtdanningstilbudFields, TestUtdanningstilbudRow] + def upsert(unsaved: TestUtdanningstilbudRow): ConnectionIO[TestUtdanningstilbudRow] + def upsertBatch(unsaved: List[TestUtdanningstilbudRow]): Stream[ConnectionIO, TestUtdanningstilbudRow] + /* NOTE: this functionality is not safe if you use auto-commit mode! it runs 3 SQL statements */ + def upsertStreaming(unsaved: Stream[ConnectionIO, TestUtdanningstilbudRow], batchSize: Int = 10000): ConnectionIO[Int] +} diff --git a/typo-tester-doobie/generated-and-checked-in/adventureworks/public/test_utdanningstilbud/TestUtdanningstilbudRepoImpl.scala b/typo-tester-doobie/generated-and-checked-in/adventureworks/public/test_utdanningstilbud/TestUtdanningstilbudRepoImpl.scala new file mode 100644 index 0000000000..df4fd25df1 --- /dev/null +++ b/typo-tester-doobie/generated-and-checked-in/adventureworks/public/test_utdanningstilbud/TestUtdanningstilbudRepoImpl.scala @@ -0,0 +1,113 @@ +/** + * File has been automatically generated by `typo`. + * + * IF YOU CHANGE THIS FILE YOUR CHANGES WILL BE OVERWRITTEN. + */ +package adventureworks +package public +package test_utdanningstilbud + +import adventureworks.public.test_organisasjon.TestOrganisasjonId +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.meta.Meta +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 TestUtdanningstilbudRepoImpl extends TestUtdanningstilbudRepo { + override def delete: DeleteBuilder[TestUtdanningstilbudFields, TestUtdanningstilbudRow] = { + DeleteBuilder(""""public"."test_utdanningstilbud"""", TestUtdanningstilbudFields.structure) + } + override def deleteById(compositeId: TestUtdanningstilbudId): ConnectionIO[Boolean] = { + sql"""delete from "public"."test_utdanningstilbud" where "organisasjonskode" = ${fromWrite(compositeId.organisasjonskode)(Write.fromPut(TestOrganisasjonId.put))} AND "utdanningsmulighet_kode" = ${fromWrite(compositeId.utdanningsmulighetKode)(Write.fromPut(Meta.StringMeta.put))}""".update.run.map(_ > 0) + } + override def deleteByIds(compositeIds: Array[TestUtdanningstilbudId]): ConnectionIO[Int] = { + val organisasjonskode = compositeIds.map(_.organisasjonskode) + val utdanningsmulighetKode = compositeIds.map(_.utdanningsmulighetKode) + sql"""delete + from "public"."test_utdanningstilbud" + where ("organisasjonskode", "utdanningsmulighet_kode") + in (select unnest(${organisasjonskode}), unnest(${utdanningsmulighetKode})) + """.update.run + + } + override def insert(unsaved: TestUtdanningstilbudRow): ConnectionIO[TestUtdanningstilbudRow] = { + sql"""insert into "public"."test_utdanningstilbud"("organisasjonskode", "utdanningsmulighet_kode") + values (${fromWrite(unsaved.organisasjonskode)(Write.fromPut(TestOrganisasjonId.put))}, ${fromWrite(unsaved.utdanningsmulighetKode)(Write.fromPut(Meta.StringMeta.put))}) + returning "organisasjonskode", "utdanningsmulighet_kode" + """.query(using TestUtdanningstilbudRow.read).unique + } + override def insertStreaming(unsaved: Stream[ConnectionIO, TestUtdanningstilbudRow], batchSize: Int = 10000): ConnectionIO[Long] = { + new FragmentOps(sql"""COPY "public"."test_utdanningstilbud"("organisasjonskode", "utdanningsmulighet_kode") FROM STDIN""").copyIn(unsaved, batchSize)(using TestUtdanningstilbudRow.text) + } + override def select: SelectBuilder[TestUtdanningstilbudFields, TestUtdanningstilbudRow] = { + SelectBuilderSql(""""public"."test_utdanningstilbud"""", TestUtdanningstilbudFields.structure, TestUtdanningstilbudRow.read) + } + override def selectAll: Stream[ConnectionIO, TestUtdanningstilbudRow] = { + sql"""select "organisasjonskode", "utdanningsmulighet_kode" from "public"."test_utdanningstilbud"""".query(using TestUtdanningstilbudRow.read).stream + } + override def selectById(compositeId: TestUtdanningstilbudId): ConnectionIO[Option[TestUtdanningstilbudRow]] = { + sql"""select "organisasjonskode", "utdanningsmulighet_kode" from "public"."test_utdanningstilbud" where "organisasjonskode" = ${fromWrite(compositeId.organisasjonskode)(Write.fromPut(TestOrganisasjonId.put))} AND "utdanningsmulighet_kode" = ${fromWrite(compositeId.utdanningsmulighetKode)(Write.fromPut(Meta.StringMeta.put))}""".query(using TestUtdanningstilbudRow.read).option + } + override def selectByIds(compositeIds: Array[TestUtdanningstilbudId]): Stream[ConnectionIO, TestUtdanningstilbudRow] = { + val organisasjonskode = compositeIds.map(_.organisasjonskode) + val utdanningsmulighetKode = compositeIds.map(_.utdanningsmulighetKode) + sql"""select "organisasjonskode", "utdanningsmulighet_kode" + from "public"."test_utdanningstilbud" + where ("organisasjonskode", "utdanningsmulighet_kode") + in (select unnest(${organisasjonskode}), unnest(${utdanningsmulighetKode})) + """.query(using TestUtdanningstilbudRow.read).stream + + } + override def selectByIdsTracked(compositeIds: Array[TestUtdanningstilbudId]): ConnectionIO[Map[TestUtdanningstilbudId, TestUtdanningstilbudRow]] = { + selectByIds(compositeIds).compile.toList.map { rows => + val byId = rows.view.map(x => (x.compositeId, x)).toMap + compositeIds.view.flatMap(id => byId.get(id).map(x => (id, x))).toMap + } + } + override def update: UpdateBuilder[TestUtdanningstilbudFields, TestUtdanningstilbudRow] = { + UpdateBuilder(""""public"."test_utdanningstilbud"""", TestUtdanningstilbudFields.structure, TestUtdanningstilbudRow.read) + } + override def upsert(unsaved: TestUtdanningstilbudRow): ConnectionIO[TestUtdanningstilbudRow] = { + sql"""insert into "public"."test_utdanningstilbud"("organisasjonskode", "utdanningsmulighet_kode") + values ( + ${fromWrite(unsaved.organisasjonskode)(Write.fromPut(TestOrganisasjonId.put))}, + ${fromWrite(unsaved.utdanningsmulighetKode)(Write.fromPut(Meta.StringMeta.put))} + ) + on conflict ("organisasjonskode", "utdanningsmulighet_kode") + do update set "organisasjonskode" = EXCLUDED."organisasjonskode" + returning "organisasjonskode", "utdanningsmulighet_kode" + """.query(using TestUtdanningstilbudRow.read).unique + } + override def upsertBatch(unsaved: List[TestUtdanningstilbudRow]): Stream[ConnectionIO, TestUtdanningstilbudRow] = { + Update[TestUtdanningstilbudRow]( + s"""insert into "public"."test_utdanningstilbud"("organisasjonskode", "utdanningsmulighet_kode") + values (?,?) + on conflict ("organisasjonskode", "utdanningsmulighet_kode") + do nothing + returning "organisasjonskode", "utdanningsmulighet_kode"""" + )(using TestUtdanningstilbudRow.write) + .updateManyWithGeneratedKeys[TestUtdanningstilbudRow]("organisasjonskode", "utdanningsmulighet_kode")(unsaved)(using catsStdInstancesForList, TestUtdanningstilbudRow.read) + } + /* NOTE: this functionality is not safe if you use auto-commit mode! it runs 3 SQL statements */ + override def upsertStreaming(unsaved: Stream[ConnectionIO, TestUtdanningstilbudRow], batchSize: Int = 10000): ConnectionIO[Int] = { + for { + _ <- sql"""create temporary table test_utdanningstilbud_TEMP (like "public"."test_utdanningstilbud") on commit drop""".update.run + _ <- new FragmentOps(sql"""copy test_utdanningstilbud_TEMP("organisasjonskode", "utdanningsmulighet_kode") from stdin""").copyIn(unsaved, batchSize)(using TestUtdanningstilbudRow.text) + res <- sql"""insert into "public"."test_utdanningstilbud"("organisasjonskode", "utdanningsmulighet_kode") + select * from test_utdanningstilbud_TEMP + on conflict ("organisasjonskode", "utdanningsmulighet_kode") + do nothing + ; + drop table test_utdanningstilbud_TEMP;""".update.run + } yield res + } +} diff --git a/typo-tester-doobie/generated-and-checked-in/adventureworks/public/test_utdanningstilbud/TestUtdanningstilbudRepoMock.scala b/typo-tester-doobie/generated-and-checked-in/adventureworks/public/test_utdanningstilbud/TestUtdanningstilbudRepoMock.scala new file mode 100644 index 0000000000..9d4a1aae3f --- /dev/null +++ b/typo-tester-doobie/generated-and-checked-in/adventureworks/public/test_utdanningstilbud/TestUtdanningstilbudRepoMock.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 test_utdanningstilbud + +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 TestUtdanningstilbudRepoMock(map: scala.collection.mutable.Map[TestUtdanningstilbudId, TestUtdanningstilbudRow] = scala.collection.mutable.Map.empty) extends TestUtdanningstilbudRepo { + override def delete: DeleteBuilder[TestUtdanningstilbudFields, TestUtdanningstilbudRow] = { + DeleteBuilderMock(DeleteParams.empty, TestUtdanningstilbudFields.structure, map) + } + override def deleteById(compositeId: TestUtdanningstilbudId): ConnectionIO[Boolean] = { + delay(map.remove(compositeId).isDefined) + } + override def deleteByIds(compositeIds: Array[TestUtdanningstilbudId]): ConnectionIO[Int] = { + delay(compositeIds.map(id => map.remove(id)).count(_.isDefined)) + } + override def insert(unsaved: TestUtdanningstilbudRow): ConnectionIO[TestUtdanningstilbudRow] = { + delay { + val _ = if (map.contains(unsaved.compositeId)) + sys.error(s"id ${unsaved.compositeId} already exists") + else + map.put(unsaved.compositeId, unsaved) + + unsaved + } + } + override def insertStreaming(unsaved: Stream[ConnectionIO, TestUtdanningstilbudRow], batchSize: Int = 10000): ConnectionIO[Long] = { + unsaved.compile.toList.map { rows => + var num = 0L + rows.foreach { row => + map += (row.compositeId -> row) + num += 1 + } + num + } + } + override def select: SelectBuilder[TestUtdanningstilbudFields, TestUtdanningstilbudRow] = { + SelectBuilderMock(TestUtdanningstilbudFields.structure, delay(map.values.toList), SelectParams.empty) + } + override def selectAll: Stream[ConnectionIO, TestUtdanningstilbudRow] = { + Stream.emits(map.values.toList) + } + override def selectById(compositeId: TestUtdanningstilbudId): ConnectionIO[Option[TestUtdanningstilbudRow]] = { + delay(map.get(compositeId)) + } + override def selectByIds(compositeIds: Array[TestUtdanningstilbudId]): Stream[ConnectionIO, TestUtdanningstilbudRow] = { + Stream.emits(compositeIds.flatMap(map.get).toList) + } + override def selectByIdsTracked(compositeIds: Array[TestUtdanningstilbudId]): ConnectionIO[Map[TestUtdanningstilbudId, TestUtdanningstilbudRow]] = { + selectByIds(compositeIds).compile.toList.map { rows => + val byId = rows.view.map(x => (x.compositeId, x)).toMap + compositeIds.view.flatMap(id => byId.get(id).map(x => (id, x))).toMap + } + } + override def update: UpdateBuilder[TestUtdanningstilbudFields, TestUtdanningstilbudRow] = { + UpdateBuilderMock(UpdateParams.empty, TestUtdanningstilbudFields.structure, map) + } + override def upsert(unsaved: TestUtdanningstilbudRow): ConnectionIO[TestUtdanningstilbudRow] = { + delay { + map.put(unsaved.compositeId, unsaved): @nowarn + unsaved + } + } + override def upsertBatch(unsaved: List[TestUtdanningstilbudRow]): Stream[ConnectionIO, TestUtdanningstilbudRow] = { + Stream.emits { + unsaved.map { row => + map += (row.compositeId -> 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, TestUtdanningstilbudRow], batchSize: Int = 10000): ConnectionIO[Int] = { + unsaved.compile.toList.map { rows => + var num = 0 + rows.foreach { row => + map += (row.compositeId -> row) + num += 1 + } + num + } + } +} diff --git a/typo-tester-doobie/generated-and-checked-in/adventureworks/public/test_utdanningstilbud/TestUtdanningstilbudRow.scala b/typo-tester-doobie/generated-and-checked-in/adventureworks/public/test_utdanningstilbud/TestUtdanningstilbudRow.scala new file mode 100644 index 0000000000..abca6e3077 --- /dev/null +++ b/typo-tester-doobie/generated-and-checked-in/adventureworks/public/test_utdanningstilbud/TestUtdanningstilbudRow.scala @@ -0,0 +1,64 @@ +/** + * File has been automatically generated by `typo`. + * + * IF YOU CHANGE THIS FILE YOUR CHANGES WILL BE OVERWRITTEN. + */ +package adventureworks +package public +package test_utdanningstilbud + +import adventureworks.public.test_organisasjon.TestOrganisasjonId +import doobie.enumerated.Nullability +import doobie.postgres.Text +import doobie.util.Read +import doobie.util.Write +import doobie.util.meta.Meta +import io.circe.Decoder +import io.circe.Encoder +import java.sql.ResultSet + +/** Table: public.test_utdanningstilbud + Composite primary key: organisasjonskode, utdanningsmulighet_kode */ +case class TestUtdanningstilbudRow( + /** Points to [[test_organisasjon.TestOrganisasjonRow.organisasjonskode]] */ + organisasjonskode: TestOrganisasjonId, + utdanningsmulighetKode: String +){ + val compositeId: TestUtdanningstilbudId = TestUtdanningstilbudId(organisasjonskode, utdanningsmulighetKode) + val id = compositeId + } + +object TestUtdanningstilbudRow { + def apply(compositeId: TestUtdanningstilbudId) = + new TestUtdanningstilbudRow(compositeId.organisasjonskode, compositeId.utdanningsmulighetKode) + implicit lazy val decoder: Decoder[TestUtdanningstilbudRow] = Decoder.forProduct2[TestUtdanningstilbudRow, TestOrganisasjonId, String]("organisasjonskode", "utdanningsmulighet_kode")(TestUtdanningstilbudRow.apply)(TestOrganisasjonId.decoder, Decoder.decodeString) + implicit lazy val encoder: Encoder[TestUtdanningstilbudRow] = Encoder.forProduct2[TestUtdanningstilbudRow, TestOrganisasjonId, String]("organisasjonskode", "utdanningsmulighet_kode")(x => (x.organisasjonskode, x.utdanningsmulighetKode))(TestOrganisasjonId.encoder, Encoder.encodeString) + implicit lazy val read: Read[TestUtdanningstilbudRow] = new Read[TestUtdanningstilbudRow]( + gets = List( + (TestOrganisasjonId.get, Nullability.NoNulls), + (Meta.StringMeta.get, Nullability.NoNulls) + ), + unsafeGet = (rs: ResultSet, i: Int) => TestUtdanningstilbudRow( + organisasjonskode = TestOrganisasjonId.get.unsafeGetNonNullable(rs, i + 0), + utdanningsmulighetKode = Meta.StringMeta.get.unsafeGetNonNullable(rs, i + 1) + ) + ) + implicit lazy val text: Text[TestUtdanningstilbudRow] = Text.instance[TestUtdanningstilbudRow]{ (row, sb) => + TestOrganisasjonId.text.unsafeEncode(row.organisasjonskode, sb) + sb.append(Text.DELIMETER) + Text.stringInstance.unsafeEncode(row.utdanningsmulighetKode, sb) + } + implicit lazy val write: Write[TestUtdanningstilbudRow] = new Write[TestUtdanningstilbudRow]( + puts = List((TestOrganisasjonId.put, Nullability.NoNulls), + (Meta.StringMeta.put, Nullability.NoNulls)), + toList = x => List(x.organisasjonskode, x.utdanningsmulighetKode), + unsafeSet = (rs, i, a) => { + TestOrganisasjonId.put.unsafeSetNonNullable(rs, i + 0, a.organisasjonskode) + Meta.StringMeta.put.unsafeSetNonNullable(rs, i + 1, a.utdanningsmulighetKode) + }, + unsafeUpdate = (ps, i, a) => { + TestOrganisasjonId.put.unsafeUpdateNonNullable(ps, i + 0, a.organisasjonskode) + Meta.StringMeta.put.unsafeUpdateNonNullable(ps, i + 1, a.utdanningsmulighetKode) + } + ) +} 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 e670b898c6..9167f86be0 100644 --- a/typo-tester-doobie/generated-and-checked-in/adventureworks/testInsert.scala +++ b/typo-tester-doobie/generated-and-checked-in/adventureworks/testInsert.scala @@ -219,6 +219,14 @@ import adventureworks.public.table_with_generated_columns.TableWithGeneratedColu import adventureworks.public.table_with_generated_columns.TableWithGeneratedColumnsRepoImpl import adventureworks.public.table_with_generated_columns.TableWithGeneratedColumnsRow import adventureworks.public.table_with_generated_columns.TableWithGeneratedColumnsRowUnsaved +import adventureworks.public.test_organisasjon.TestOrganisasjonId +import adventureworks.public.test_organisasjon.TestOrganisasjonRepoImpl +import adventureworks.public.test_organisasjon.TestOrganisasjonRow +import adventureworks.public.test_sak_soknadsalternativ.TestSakSoknadsalternativRepoImpl +import adventureworks.public.test_sak_soknadsalternativ.TestSakSoknadsalternativRow +import adventureworks.public.test_utdanningstilbud.TestUtdanningstilbudId +import adventureworks.public.test_utdanningstilbud.TestUtdanningstilbudRepoImpl +import adventureworks.public.test_utdanningstilbud.TestUtdanningstilbudRow import adventureworks.public.title.TitleId import adventureworks.public.title.TitleRepoImpl import adventureworks.public.title.TitleRow @@ -796,6 +804,9 @@ class TestInsert(random: Random, domainInsert: TestDomainInsert) { xmles: Option[Array[TypoXml]] = None ): ConnectionIO[PgtestnullRow] = (new PgtestnullRepoImpl).insert(new PgtestnullRow(bool = bool, box = box, bpchar = bpchar, bytea = bytea, char = char, circle = circle, date = date, float4 = float4, float8 = float8, hstore = hstore, inet = inet, int2 = int2, int2vector = int2vector, int4 = int4, int8 = int8, interval = interval, json = json, jsonb = jsonb, line = line, lseg = lseg, money = money, mydomain = mydomain, myenum = myenum, name = name, numeric = numeric, path = path, point = point, polygon = polygon, text = text, time = time, timestamp = timestamp, timestampz = timestampz, timez = timez, uuid = uuid, varchar = varchar, vector = vector, xml = xml, boxes = boxes, bpchares = bpchares, chares = chares, circlees = circlees, datees = datees, float4es = float4es, float8es = float8es, inetes = inetes, int2es = int2es, int2vectores = int2vectores, int4es = int4es, int8es = int8es, intervales = intervales, jsones = jsones, jsonbes = jsonbes, linees = linees, lseges = lseges, moneyes = moneyes, mydomaines = mydomaines, myenumes = myenumes, namees = namees, numerices = numerices, pathes = pathes, pointes = pointes, polygones = polygones, textes = textes, timees = timees, timestampes = timestampes, timestampzes = timestampzes, timezes = timezes, uuides = uuides, varchares = varchares, xmles = xmles)) def publicTableWithGeneratedColumns(name: TableWithGeneratedColumnsId = TableWithGeneratedColumnsId(random.alphanumeric.take(20).mkString)): ConnectionIO[TableWithGeneratedColumnsRow] = (new TableWithGeneratedColumnsRepoImpl).insert(new TableWithGeneratedColumnsRowUnsaved(name = name)) + def publicTestOrganisasjon(organisasjonskode: TestOrganisasjonId = TestOrganisasjonId(random.alphanumeric.take(20).mkString)): ConnectionIO[TestOrganisasjonRow] = (new TestOrganisasjonRepoImpl).insert(new TestOrganisasjonRow(organisasjonskode = organisasjonskode)) + def publicTestSakSoknadsalternativ(TestUtdanningstilbudId: TestUtdanningstilbudId, organisasjonskodeSaksbehandler: String = random.alphanumeric.take(20).mkString): ConnectionIO[TestSakSoknadsalternativRow] = (new TestSakSoknadsalternativRepoImpl).insert(new TestSakSoknadsalternativRow(organisasjonskodeSaksbehandler = organisasjonskodeSaksbehandler, utdanningsmulighetKode = TestUtdanningstilbudId.utdanningsmulighetKode, organisasjonskodeTilbyder = TestUtdanningstilbudId.organisasjonskode)) + def publicTestUtdanningstilbud(organisasjonskode: TestOrganisasjonId, utdanningsmulighetKode: String = random.alphanumeric.take(20).mkString): ConnectionIO[TestUtdanningstilbudRow] = (new TestUtdanningstilbudRepoImpl).insert(new TestUtdanningstilbudRow(organisasjonskode = organisasjonskode, utdanningsmulighetKode = utdanningsmulighetKode)) def publicTitle(code: TitleId = TitleId(random.alphanumeric.take(20).mkString)): ConnectionIO[TitleRow] = (new TitleRepoImpl).insert(new TitleRow(code = code)) def publicTitleDomain(code: TitleDomainId = TitleDomainId(domainInsert.publicShortText(random))): ConnectionIO[TitleDomainRow] = (new TitleDomainRepoImpl).insert(new TitleDomainRow(code = code)) def publicTitledperson(titleShort: TitleDomainId = TitleDomainId.All(random.nextInt(4)), diff --git a/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/test_organisasjon/TestOrganisasjonFields.scala b/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/test_organisasjon/TestOrganisasjonFields.scala new file mode 100644 index 0000000000..e6198a24cb --- /dev/null +++ b/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/test_organisasjon/TestOrganisasjonFields.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 test_organisasjon + +import typo.dsl.Path +import typo.dsl.SqlExpr.FieldLikeNoHkt +import typo.dsl.SqlExpr.IdField +import typo.dsl.Structure.Relation + +trait TestOrganisasjonFields { + def organisasjonskode: IdField[TestOrganisasjonId, TestOrganisasjonRow] +} + +object TestOrganisasjonFields { + lazy val structure: Relation[TestOrganisasjonFields, TestOrganisasjonRow] = + new Impl(Nil) + + private final class Impl(val _path: List[Path]) + extends Relation[TestOrganisasjonFields, TestOrganisasjonRow] { + + override lazy val fields: TestOrganisasjonFields = new TestOrganisasjonFields { + override def organisasjonskode = IdField[TestOrganisasjonId, TestOrganisasjonRow](_path, "organisasjonskode", None, None, x => x.organisasjonskode, (row, value) => row.copy(organisasjonskode = value)) + } + + override lazy val columns: List[FieldLikeNoHkt[?, TestOrganisasjonRow]] = + List[FieldLikeNoHkt[?, TestOrganisasjonRow]](fields.organisasjonskode) + + override def copy(path: List[Path]): Impl = + new Impl(path) + } + +} diff --git a/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/test_organisasjon/TestOrganisasjonId.scala b/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/test_organisasjon/TestOrganisasjonId.scala new file mode 100644 index 0000000000..f0c14c48f0 --- /dev/null +++ b/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/test_organisasjon/TestOrganisasjonId.scala @@ -0,0 +1,36 @@ +/** + * File has been automatically generated by `typo`. + * + * IF YOU CHANGE THIS FILE YOUR CHANGES WILL BE OVERWRITTEN. + */ +package adventureworks +package public +package test_organisasjon + +import typo.dsl.Bijection +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.test_organisasjon` */ +case class TestOrganisasjonId(value: String) extends AnyVal +object TestOrganisasjonId { + implicit lazy val arrayJdbcDecoder: JdbcDecoder[Array[TestOrganisasjonId]] = adventureworks.StringArrayDecoder.map(_.map(TestOrganisasjonId.apply)) + implicit lazy val arrayJdbcEncoder: JdbcEncoder[Array[TestOrganisasjonId]] = adventureworks.StringArrayEncoder.contramap(_.map(_.value)) + implicit lazy val arraySetter: Setter[Array[TestOrganisasjonId]] = adventureworks.StringArraySetter.contramap(_.map(_.value)) + implicit lazy val bijection: Bijection[TestOrganisasjonId, String] = Bijection[TestOrganisasjonId, String](_.value)(TestOrganisasjonId.apply) + implicit lazy val jdbcDecoder: JdbcDecoder[TestOrganisasjonId] = JdbcDecoder.stringDecoder.map(TestOrganisasjonId.apply) + implicit lazy val jdbcEncoder: JdbcEncoder[TestOrganisasjonId] = JdbcEncoder.stringEncoder.contramap(_.value) + implicit lazy val jsonDecoder: JsonDecoder[TestOrganisasjonId] = JsonDecoder.string.map(TestOrganisasjonId.apply) + implicit lazy val jsonEncoder: JsonEncoder[TestOrganisasjonId] = JsonEncoder.string.contramap(_.value) + implicit lazy val ordering: Ordering[TestOrganisasjonId] = Ordering.by(_.value) + implicit lazy val pgType: PGType[TestOrganisasjonId] = PGType.PGTypeString.as + implicit lazy val setter: Setter[TestOrganisasjonId] = Setter.stringSetter.contramap(_.value) + implicit lazy val text: Text[TestOrganisasjonId] = new Text[TestOrganisasjonId] { + override def unsafeEncode(v: TestOrganisasjonId, sb: StringBuilder) = Text.stringInstance.unsafeEncode(v.value, sb) + override def unsafeArrayEncode(v: TestOrganisasjonId, sb: StringBuilder) = Text.stringInstance.unsafeArrayEncode(v.value, sb) + } +} diff --git a/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/test_organisasjon/TestOrganisasjonRepo.scala b/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/test_organisasjon/TestOrganisasjonRepo.scala new file mode 100644 index 0000000000..383bdec028 --- /dev/null +++ b/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/test_organisasjon/TestOrganisasjonRepo.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 test_organisasjon + +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 TestOrganisasjonRepo { + def delete: DeleteBuilder[TestOrganisasjonFields, TestOrganisasjonRow] + def deleteById(organisasjonskode: TestOrganisasjonId): ZIO[ZConnection, Throwable, Boolean] + def deleteByIds(organisasjonskodes: Array[TestOrganisasjonId]): ZIO[ZConnection, Throwable, Long] + def insert(unsaved: TestOrganisasjonRow): ZIO[ZConnection, Throwable, TestOrganisasjonRow] + def insertStreaming(unsaved: ZStream[ZConnection, Throwable, TestOrganisasjonRow], batchSize: Int = 10000): ZIO[ZConnection, Throwable, Long] + def select: SelectBuilder[TestOrganisasjonFields, TestOrganisasjonRow] + def selectAll: ZStream[ZConnection, Throwable, TestOrganisasjonRow] + def selectById(organisasjonskode: TestOrganisasjonId): ZIO[ZConnection, Throwable, Option[TestOrganisasjonRow]] + def selectByIds(organisasjonskodes: Array[TestOrganisasjonId]): ZStream[ZConnection, Throwable, TestOrganisasjonRow] + def selectByIdsTracked(organisasjonskodes: Array[TestOrganisasjonId]): ZIO[ZConnection, Throwable, Map[TestOrganisasjonId, TestOrganisasjonRow]] + def update: UpdateBuilder[TestOrganisasjonFields, TestOrganisasjonRow] + def upsert(unsaved: TestOrganisasjonRow): ZIO[ZConnection, Throwable, UpdateResult[TestOrganisasjonRow]] + // 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, TestOrganisasjonRow], batchSize: Int = 10000): ZIO[ZConnection, Throwable, Long] +} diff --git a/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/test_organisasjon/TestOrganisasjonRepoImpl.scala b/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/test_organisasjon/TestOrganisasjonRepoImpl.scala new file mode 100644 index 0000000000..cebf1c5eb5 --- /dev/null +++ b/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/test_organisasjon/TestOrganisasjonRepoImpl.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 test_organisasjon + +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 TestOrganisasjonRepoImpl extends TestOrganisasjonRepo { + override def delete: DeleteBuilder[TestOrganisasjonFields, TestOrganisasjonRow] = { + DeleteBuilder(""""public"."test_organisasjon"""", TestOrganisasjonFields.structure) + } + override def deleteById(organisasjonskode: TestOrganisasjonId): ZIO[ZConnection, Throwable, Boolean] = { + sql"""delete from "public"."test_organisasjon" where "organisasjonskode" = ${Segment.paramSegment(organisasjonskode)(TestOrganisasjonId.setter)}""".delete.map(_ > 0) + } + override def deleteByIds(organisasjonskodes: Array[TestOrganisasjonId]): ZIO[ZConnection, Throwable, Long] = { + sql"""delete from "public"."test_organisasjon" where "organisasjonskode" = ANY(${organisasjonskodes})""".delete + } + override def insert(unsaved: TestOrganisasjonRow): ZIO[ZConnection, Throwable, TestOrganisasjonRow] = { + sql"""insert into "public"."test_organisasjon"("organisasjonskode") + values (${Segment.paramSegment(unsaved.organisasjonskode)(TestOrganisasjonId.setter)}) + returning "organisasjonskode" + """.insertReturning(using TestOrganisasjonRow.jdbcDecoder).map(_.updatedKeys.head) + } + override def insertStreaming(unsaved: ZStream[ZConnection, Throwable, TestOrganisasjonRow], batchSize: Int = 10000): ZIO[ZConnection, Throwable, Long] = { + streamingInsert(s"""COPY "public"."test_organisasjon"("organisasjonskode") FROM STDIN""", batchSize, unsaved)(TestOrganisasjonRow.text) + } + override def select: SelectBuilder[TestOrganisasjonFields, TestOrganisasjonRow] = { + SelectBuilderSql(""""public"."test_organisasjon"""", TestOrganisasjonFields.structure, TestOrganisasjonRow.jdbcDecoder) + } + override def selectAll: ZStream[ZConnection, Throwable, TestOrganisasjonRow] = { + sql"""select "organisasjonskode" from "public"."test_organisasjon"""".query(using TestOrganisasjonRow.jdbcDecoder).selectStream() + } + override def selectById(organisasjonskode: TestOrganisasjonId): ZIO[ZConnection, Throwable, Option[TestOrganisasjonRow]] = { + sql"""select "organisasjonskode" from "public"."test_organisasjon" where "organisasjonskode" = ${Segment.paramSegment(organisasjonskode)(TestOrganisasjonId.setter)}""".query(using TestOrganisasjonRow.jdbcDecoder).selectOne + } + override def selectByIds(organisasjonskodes: Array[TestOrganisasjonId]): ZStream[ZConnection, Throwable, TestOrganisasjonRow] = { + sql"""select "organisasjonskode" from "public"."test_organisasjon" where "organisasjonskode" = ANY(${Segment.paramSegment(organisasjonskodes)(TestOrganisasjonId.arraySetter)})""".query(using TestOrganisasjonRow.jdbcDecoder).selectStream() + } + override def selectByIdsTracked(organisasjonskodes: Array[TestOrganisasjonId]): ZIO[ZConnection, Throwable, Map[TestOrganisasjonId, TestOrganisasjonRow]] = { + selectByIds(organisasjonskodes).runCollect.map { rows => + val byId = rows.view.map(x => (x.organisasjonskode, x)).toMap + organisasjonskodes.view.flatMap(id => byId.get(id).map(x => (id, x))).toMap + } + } + override def update: UpdateBuilder[TestOrganisasjonFields, TestOrganisasjonRow] = { + UpdateBuilder(""""public"."test_organisasjon"""", TestOrganisasjonFields.structure, TestOrganisasjonRow.jdbcDecoder) + } + override def upsert(unsaved: TestOrganisasjonRow): ZIO[ZConnection, Throwable, UpdateResult[TestOrganisasjonRow]] = { + sql"""insert into "public"."test_organisasjon"("organisasjonskode") + values ( + ${Segment.paramSegment(unsaved.organisasjonskode)(TestOrganisasjonId.setter)} + ) + on conflict ("organisasjonskode") + do update set "organisasjonskode" = EXCLUDED."organisasjonskode" + returning "organisasjonskode"""".insertReturning(using TestOrganisasjonRow.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, TestOrganisasjonRow], batchSize: Int = 10000): ZIO[ZConnection, Throwable, Long] = { + val created = sql"""create temporary table test_organisasjon_TEMP (like "public"."test_organisasjon") on commit drop""".execute + val copied = streamingInsert(s"""copy test_organisasjon_TEMP("organisasjonskode") from stdin""", batchSize, unsaved)(TestOrganisasjonRow.text) + val merged = sql"""insert into "public"."test_organisasjon"("organisasjonskode") + select * from test_organisasjon_TEMP + on conflict ("organisasjonskode") + do nothing + ; + drop table test_organisasjon_TEMP;""".update + created *> copied *> merged + } +} diff --git a/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/test_organisasjon/TestOrganisasjonRepoMock.scala b/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/test_organisasjon/TestOrganisasjonRepoMock.scala new file mode 100644 index 0000000000..c77d1b17bd --- /dev/null +++ b/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/test_organisasjon/TestOrganisasjonRepoMock.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 test_organisasjon + +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 TestOrganisasjonRepoMock(map: scala.collection.mutable.Map[TestOrganisasjonId, TestOrganisasjonRow] = scala.collection.mutable.Map.empty) extends TestOrganisasjonRepo { + override def delete: DeleteBuilder[TestOrganisasjonFields, TestOrganisasjonRow] = { + DeleteBuilderMock(DeleteParams.empty, TestOrganisasjonFields.structure, map) + } + override def deleteById(organisasjonskode: TestOrganisasjonId): ZIO[ZConnection, Throwable, Boolean] = { + ZIO.succeed(map.remove(organisasjonskode).isDefined) + } + override def deleteByIds(organisasjonskodes: Array[TestOrganisasjonId]): ZIO[ZConnection, Throwable, Long] = { + ZIO.succeed(organisasjonskodes.map(id => map.remove(id)).count(_.isDefined).toLong) + } + override def insert(unsaved: TestOrganisasjonRow): ZIO[ZConnection, Throwable, TestOrganisasjonRow] = { + ZIO.succeed { + val _ = + if (map.contains(unsaved.organisasjonskode)) + sys.error(s"id ${unsaved.organisasjonskode} already exists") + else + map.put(unsaved.organisasjonskode, unsaved) + + unsaved + } + } + override def insertStreaming(unsaved: ZStream[ZConnection, Throwable, TestOrganisasjonRow], batchSize: Int = 10000): ZIO[ZConnection, Throwable, Long] = { + unsaved.scanZIO(0L) { case (acc, row) => + ZIO.succeed { + map += (row.organisasjonskode -> row) + acc + 1 + } + }.runLast.map(_.getOrElse(0L)) + } + override def select: SelectBuilder[TestOrganisasjonFields, TestOrganisasjonRow] = { + SelectBuilderMock(TestOrganisasjonFields.structure, ZIO.succeed(Chunk.fromIterable(map.values)), SelectParams.empty) + } + override def selectAll: ZStream[ZConnection, Throwable, TestOrganisasjonRow] = { + ZStream.fromIterable(map.values) + } + override def selectById(organisasjonskode: TestOrganisasjonId): ZIO[ZConnection, Throwable, Option[TestOrganisasjonRow]] = { + ZIO.succeed(map.get(organisasjonskode)) + } + override def selectByIds(organisasjonskodes: Array[TestOrganisasjonId]): ZStream[ZConnection, Throwable, TestOrganisasjonRow] = { + ZStream.fromIterable(organisasjonskodes.flatMap(map.get)) + } + override def selectByIdsTracked(organisasjonskodes: Array[TestOrganisasjonId]): ZIO[ZConnection, Throwable, Map[TestOrganisasjonId, TestOrganisasjonRow]] = { + selectByIds(organisasjonskodes).runCollect.map { rows => + val byId = rows.view.map(x => (x.organisasjonskode, x)).toMap + organisasjonskodes.view.flatMap(id => byId.get(id).map(x => (id, x))).toMap + } + } + override def update: UpdateBuilder[TestOrganisasjonFields, TestOrganisasjonRow] = { + UpdateBuilderMock(UpdateParams.empty, TestOrganisasjonFields.structure, map) + } + override def upsert(unsaved: TestOrganisasjonRow): ZIO[ZConnection, Throwable, UpdateResult[TestOrganisasjonRow]] = { + ZIO.succeed { + map.put(unsaved.organisasjonskode, 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, TestOrganisasjonRow], batchSize: Int = 10000): ZIO[ZConnection, Throwable, Long] = { + unsaved.scanZIO(0L) { case (acc, row) => + ZIO.succeed { + map += (row.organisasjonskode -> row) + acc + 1 + } + }.runLast.map(_.getOrElse(0L)) + } +} diff --git a/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/test_organisasjon/TestOrganisasjonRow.scala b/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/test_organisasjon/TestOrganisasjonRow.scala new file mode 100644 index 0000000000..30aa0cc837 --- /dev/null +++ b/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/test_organisasjon/TestOrganisasjonRow.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 test_organisasjon + +import zio.jdbc.JdbcDecoder +import zio.json.JsonDecoder +import zio.json.JsonEncoder +import zio.json.ast.Json +import zio.json.internal.Write + +/** Table: public.test_organisasjon + Primary key: organisasjonskode */ +case class TestOrganisasjonRow( + organisasjonskode: TestOrganisasjonId +){ + val id = organisasjonskode + } + +object TestOrganisasjonRow { + implicit lazy val jdbcDecoder: JdbcDecoder[TestOrganisasjonRow] = TestOrganisasjonId.jdbcDecoder.map(v => TestOrganisasjonRow(organisasjonskode = v)) + implicit lazy val jsonDecoder: JsonDecoder[TestOrganisasjonRow] = JsonDecoder[Json.Obj].mapOrFail { jsonObj => + val organisasjonskode = jsonObj.get("organisasjonskode").toRight("Missing field 'organisasjonskode'").flatMap(_.as(TestOrganisasjonId.jsonDecoder)) + if (organisasjonskode.isRight) + Right(TestOrganisasjonRow(organisasjonskode = organisasjonskode.toOption.get)) + else Left(List[Either[String, Any]](organisasjonskode).flatMap(_.left.toOption).mkString(", ")) + } + implicit lazy val jsonEncoder: JsonEncoder[TestOrganisasjonRow] = new JsonEncoder[TestOrganisasjonRow] { + override def unsafeEncode(a: TestOrganisasjonRow, indent: Option[Int], out: Write): Unit = { + out.write("{") + out.write(""""organisasjonskode":""") + TestOrganisasjonId.jsonEncoder.unsafeEncode(a.organisasjonskode, indent, out) + out.write("}") + } + } + implicit lazy val text: Text[TestOrganisasjonRow] = Text.instance[TestOrganisasjonRow]{ (row, sb) => + TestOrganisasjonId.text.unsafeEncode(row.organisasjonskode, sb) + } +} diff --git a/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/test_sak_soknadsalternativ/TestSakSoknadsalternativFields.scala b/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/test_sak_soknadsalternativ/TestSakSoknadsalternativFields.scala new file mode 100644 index 0000000000..c10b135725 --- /dev/null +++ b/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/test_sak_soknadsalternativ/TestSakSoknadsalternativFields.scala @@ -0,0 +1,65 @@ +/** + * File has been automatically generated by `typo`. + * + * IF YOU CHANGE THIS FILE YOUR CHANGES WILL BE OVERWRITTEN. + */ +package adventureworks +package public +package test_sak_soknadsalternativ + +import adventureworks.public.test_organisasjon.TestOrganisasjonId +import adventureworks.public.test_utdanningstilbud.TestUtdanningstilbudFields +import adventureworks.public.test_utdanningstilbud.TestUtdanningstilbudId +import adventureworks.public.test_utdanningstilbud.TestUtdanningstilbudRow +import typo.dsl.ForeignKey +import typo.dsl.Path +import typo.dsl.Required +import typo.dsl.SqlExpr +import typo.dsl.SqlExpr.CompositeIn +import typo.dsl.SqlExpr.CompositeIn.TuplePart +import typo.dsl.SqlExpr.Field +import typo.dsl.SqlExpr.FieldLikeNoHkt +import typo.dsl.SqlExpr.IdField +import typo.dsl.Structure.Relation + +trait TestSakSoknadsalternativFields { + def organisasjonskodeSaksbehandler: IdField[String, TestSakSoknadsalternativRow] + def utdanningsmulighetKode: IdField[String, TestSakSoknadsalternativRow] + def organisasjonskodeTilbyder: Field[TestOrganisasjonId, TestSakSoknadsalternativRow] + def fkTestUtdanningstilbud: ForeignKey[TestUtdanningstilbudFields, TestUtdanningstilbudRow] = + ForeignKey[TestUtdanningstilbudFields, TestUtdanningstilbudRow]("public.test_sak_soknadsalternativ_organisasjonskode_tilbyder_utda_fkey", Nil) + .withColumnPair(organisasjonskodeTilbyder, _.organisasjonskode) + .withColumnPair(utdanningsmulighetKode, _.utdanningsmulighetKode) + def compositeIdIs(compositeId: TestSakSoknadsalternativId): SqlExpr[Boolean, Required] = + organisasjonskodeSaksbehandler.isEqual(compositeId.organisasjonskodeSaksbehandler).and(utdanningsmulighetKode.isEqual(compositeId.utdanningsmulighetKode)) + def compositeIdIn(compositeIds: Array[TestSakSoknadsalternativId]): SqlExpr[Boolean, Required] = + new CompositeIn(compositeIds)(TuplePart(organisasjonskodeSaksbehandler)(_.organisasjonskodeSaksbehandler), TuplePart(utdanningsmulighetKode)(_.utdanningsmulighetKode)) + + def extractTestUtdanningstilbudIdIs(id: TestUtdanningstilbudId): SqlExpr[Boolean, Required] = + organisasjonskodeTilbyder.isEqual(id.organisasjonskode).and(utdanningsmulighetKode.isEqual(id.utdanningsmulighetKode)) + def extractTestUtdanningstilbudIdIn(ids: Array[TestUtdanningstilbudId]): SqlExpr[Boolean, Required] = + new CompositeIn(ids)(TuplePart(organisasjonskodeTilbyder)(_.organisasjonskode), TuplePart(utdanningsmulighetKode)(_.utdanningsmulighetKode)) + +} + +object TestSakSoknadsalternativFields { + lazy val structure: Relation[TestSakSoknadsalternativFields, TestSakSoknadsalternativRow] = + new Impl(Nil) + + private final class Impl(val _path: List[Path]) + extends Relation[TestSakSoknadsalternativFields, TestSakSoknadsalternativRow] { + + override lazy val fields: TestSakSoknadsalternativFields = new TestSakSoknadsalternativFields { + override def organisasjonskodeSaksbehandler = IdField[String, TestSakSoknadsalternativRow](_path, "organisasjonskode_saksbehandler", None, None, x => x.organisasjonskodeSaksbehandler, (row, value) => row.copy(organisasjonskodeSaksbehandler = value)) + override def utdanningsmulighetKode = IdField[String, TestSakSoknadsalternativRow](_path, "utdanningsmulighet_kode", None, None, x => x.utdanningsmulighetKode, (row, value) => row.copy(utdanningsmulighetKode = value)) + override def organisasjonskodeTilbyder = Field[TestOrganisasjonId, TestSakSoknadsalternativRow](_path, "organisasjonskode_tilbyder", None, None, x => x.organisasjonskodeTilbyder, (row, value) => row.copy(organisasjonskodeTilbyder = value)) + } + + override lazy val columns: List[FieldLikeNoHkt[?, TestSakSoknadsalternativRow]] = + List[FieldLikeNoHkt[?, TestSakSoknadsalternativRow]](fields.organisasjonskodeSaksbehandler, fields.utdanningsmulighetKode, fields.organisasjonskodeTilbyder) + + override def copy(path: List[Path]): Impl = + new Impl(path) + } + +} diff --git a/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/test_sak_soknadsalternativ/TestSakSoknadsalternativId.scala b/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/test_sak_soknadsalternativ/TestSakSoknadsalternativId.scala new file mode 100644 index 0000000000..c9e30a9361 --- /dev/null +++ b/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/test_sak_soknadsalternativ/TestSakSoknadsalternativId.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 test_sak_soknadsalternativ + +import adventureworks.public.test_utdanningstilbud.TestUtdanningstilbudId +import zio.json.JsonDecoder +import zio.json.JsonEncoder +import zio.json.ast.Json +import zio.json.internal.Write + +/** Type for the composite primary key of table `public.test_sak_soknadsalternativ` */ +case class TestSakSoknadsalternativId( + organisasjonskodeSaksbehandler: String, + utdanningsmulighetKode: String +) +object TestSakSoknadsalternativId { + def from(TestUtdanningstilbudId: TestUtdanningstilbudId, organisasjonskodeSaksbehandler: String): TestSakSoknadsalternativId = TestSakSoknadsalternativId( + organisasjonskodeSaksbehandler = organisasjonskodeSaksbehandler, + utdanningsmulighetKode = TestUtdanningstilbudId.utdanningsmulighetKode + ) + implicit lazy val jsonDecoder: JsonDecoder[TestSakSoknadsalternativId] = JsonDecoder[Json.Obj].mapOrFail { jsonObj => + val organisasjonskodeSaksbehandler = jsonObj.get("organisasjonskode_saksbehandler").toRight("Missing field 'organisasjonskode_saksbehandler'").flatMap(_.as(JsonDecoder.string)) + val utdanningsmulighetKode = jsonObj.get("utdanningsmulighet_kode").toRight("Missing field 'utdanningsmulighet_kode'").flatMap(_.as(JsonDecoder.string)) + if (organisasjonskodeSaksbehandler.isRight && utdanningsmulighetKode.isRight) + Right(TestSakSoknadsalternativId(organisasjonskodeSaksbehandler = organisasjonskodeSaksbehandler.toOption.get, utdanningsmulighetKode = utdanningsmulighetKode.toOption.get)) + else Left(List[Either[String, Any]](organisasjonskodeSaksbehandler, utdanningsmulighetKode).flatMap(_.left.toOption).mkString(", ")) + } + implicit lazy val jsonEncoder: JsonEncoder[TestSakSoknadsalternativId] = new JsonEncoder[TestSakSoknadsalternativId] { + override def unsafeEncode(a: TestSakSoknadsalternativId, indent: Option[Int], out: Write): Unit = { + out.write("{") + out.write(""""organisasjonskode_saksbehandler":""") + JsonEncoder.string.unsafeEncode(a.organisasjonskodeSaksbehandler, indent, out) + out.write(",") + out.write(""""utdanningsmulighet_kode":""") + JsonEncoder.string.unsafeEncode(a.utdanningsmulighetKode, indent, out) + out.write("}") + } + } + implicit lazy val ordering: Ordering[TestSakSoknadsalternativId] = Ordering.by(x => (x.organisasjonskodeSaksbehandler, x.utdanningsmulighetKode)) +} diff --git a/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/test_sak_soknadsalternativ/TestSakSoknadsalternativRepo.scala b/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/test_sak_soknadsalternativ/TestSakSoknadsalternativRepo.scala new file mode 100644 index 0000000000..5dcbcb7604 --- /dev/null +++ b/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/test_sak_soknadsalternativ/TestSakSoknadsalternativRepo.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 test_sak_soknadsalternativ + +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 TestSakSoknadsalternativRepo { + def delete: DeleteBuilder[TestSakSoknadsalternativFields, TestSakSoknadsalternativRow] + def deleteById(compositeId: TestSakSoknadsalternativId): ZIO[ZConnection, Throwable, Boolean] + def deleteByIds(compositeIds: Array[TestSakSoknadsalternativId]): ZIO[ZConnection, Throwable, Long] + def insert(unsaved: TestSakSoknadsalternativRow): ZIO[ZConnection, Throwable, TestSakSoknadsalternativRow] + def insertStreaming(unsaved: ZStream[ZConnection, Throwable, TestSakSoknadsalternativRow], batchSize: Int = 10000): ZIO[ZConnection, Throwable, Long] + def select: SelectBuilder[TestSakSoknadsalternativFields, TestSakSoknadsalternativRow] + def selectAll: ZStream[ZConnection, Throwable, TestSakSoknadsalternativRow] + def selectById(compositeId: TestSakSoknadsalternativId): ZIO[ZConnection, Throwable, Option[TestSakSoknadsalternativRow]] + def selectByIds(compositeIds: Array[TestSakSoknadsalternativId]): ZStream[ZConnection, Throwable, TestSakSoknadsalternativRow] + def selectByIdsTracked(compositeIds: Array[TestSakSoknadsalternativId]): ZIO[ZConnection, Throwable, Map[TestSakSoknadsalternativId, TestSakSoknadsalternativRow]] + def update: UpdateBuilder[TestSakSoknadsalternativFields, TestSakSoknadsalternativRow] + def update(row: TestSakSoknadsalternativRow): ZIO[ZConnection, Throwable, Boolean] + def upsert(unsaved: TestSakSoknadsalternativRow): ZIO[ZConnection, Throwable, UpdateResult[TestSakSoknadsalternativRow]] + // 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, TestSakSoknadsalternativRow], batchSize: Int = 10000): ZIO[ZConnection, Throwable, Long] +} diff --git a/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/test_sak_soknadsalternativ/TestSakSoknadsalternativRepoImpl.scala b/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/test_sak_soknadsalternativ/TestSakSoknadsalternativRepoImpl.scala new file mode 100644 index 0000000000..e93283b196 --- /dev/null +++ b/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/test_sak_soknadsalternativ/TestSakSoknadsalternativRepoImpl.scala @@ -0,0 +1,108 @@ +/** + * File has been automatically generated by `typo`. + * + * IF YOU CHANGE THIS FILE YOUR CHANGES WILL BE OVERWRITTEN. + */ +package adventureworks +package public +package test_sak_soknadsalternativ + +import adventureworks.public.test_organisasjon.TestOrganisasjonId +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.SqlFragment.Setter +import zio.jdbc.UpdateResult +import zio.jdbc.ZConnection +import zio.jdbc.sqlInterpolator +import zio.stream.ZStream + +class TestSakSoknadsalternativRepoImpl extends TestSakSoknadsalternativRepo { + override def delete: DeleteBuilder[TestSakSoknadsalternativFields, TestSakSoknadsalternativRow] = { + DeleteBuilder(""""public"."test_sak_soknadsalternativ"""", TestSakSoknadsalternativFields.structure) + } + override def deleteById(compositeId: TestSakSoknadsalternativId): ZIO[ZConnection, Throwable, Boolean] = { + sql"""delete from "public"."test_sak_soknadsalternativ" where "organisasjonskode_saksbehandler" = ${Segment.paramSegment(compositeId.organisasjonskodeSaksbehandler)(Setter.stringSetter)} AND "utdanningsmulighet_kode" = ${Segment.paramSegment(compositeId.utdanningsmulighetKode)(Setter.stringSetter)}""".delete.map(_ > 0) + } + override def deleteByIds(compositeIds: Array[TestSakSoknadsalternativId]): ZIO[ZConnection, Throwable, Long] = { + val organisasjonskodeSaksbehandler = compositeIds.map(_.organisasjonskodeSaksbehandler) + val utdanningsmulighetKode = compositeIds.map(_.utdanningsmulighetKode) + sql"""delete + from "public"."test_sak_soknadsalternativ" + where ("organisasjonskode_saksbehandler", "utdanningsmulighet_kode") + in (select unnest(${organisasjonskodeSaksbehandler}), unnest(${utdanningsmulighetKode})) + """.delete + + } + override def insert(unsaved: TestSakSoknadsalternativRow): ZIO[ZConnection, Throwable, TestSakSoknadsalternativRow] = { + sql"""insert into "public"."test_sak_soknadsalternativ"("organisasjonskode_saksbehandler", "utdanningsmulighet_kode", "organisasjonskode_tilbyder") + values (${Segment.paramSegment(unsaved.organisasjonskodeSaksbehandler)(Setter.stringSetter)}, ${Segment.paramSegment(unsaved.utdanningsmulighetKode)(Setter.stringSetter)}, ${Segment.paramSegment(unsaved.organisasjonskodeTilbyder)(TestOrganisasjonId.setter)}) + returning "organisasjonskode_saksbehandler", "utdanningsmulighet_kode", "organisasjonskode_tilbyder" + """.insertReturning(using TestSakSoknadsalternativRow.jdbcDecoder).map(_.updatedKeys.head) + } + override def insertStreaming(unsaved: ZStream[ZConnection, Throwable, TestSakSoknadsalternativRow], batchSize: Int = 10000): ZIO[ZConnection, Throwable, Long] = { + streamingInsert(s"""COPY "public"."test_sak_soknadsalternativ"("organisasjonskode_saksbehandler", "utdanningsmulighet_kode", "organisasjonskode_tilbyder") FROM STDIN""", batchSize, unsaved)(TestSakSoknadsalternativRow.text) + } + override def select: SelectBuilder[TestSakSoknadsalternativFields, TestSakSoknadsalternativRow] = { + SelectBuilderSql(""""public"."test_sak_soknadsalternativ"""", TestSakSoknadsalternativFields.structure, TestSakSoknadsalternativRow.jdbcDecoder) + } + override def selectAll: ZStream[ZConnection, Throwable, TestSakSoknadsalternativRow] = { + sql"""select "organisasjonskode_saksbehandler", "utdanningsmulighet_kode", "organisasjonskode_tilbyder" from "public"."test_sak_soknadsalternativ"""".query(using TestSakSoknadsalternativRow.jdbcDecoder).selectStream() + } + override def selectById(compositeId: TestSakSoknadsalternativId): ZIO[ZConnection, Throwable, Option[TestSakSoknadsalternativRow]] = { + sql"""select "organisasjonskode_saksbehandler", "utdanningsmulighet_kode", "organisasjonskode_tilbyder" from "public"."test_sak_soknadsalternativ" where "organisasjonskode_saksbehandler" = ${Segment.paramSegment(compositeId.organisasjonskodeSaksbehandler)(Setter.stringSetter)} AND "utdanningsmulighet_kode" = ${Segment.paramSegment(compositeId.utdanningsmulighetKode)(Setter.stringSetter)}""".query(using TestSakSoknadsalternativRow.jdbcDecoder).selectOne + } + override def selectByIds(compositeIds: Array[TestSakSoknadsalternativId]): ZStream[ZConnection, Throwable, TestSakSoknadsalternativRow] = { + val organisasjonskodeSaksbehandler = compositeIds.map(_.organisasjonskodeSaksbehandler) + val utdanningsmulighetKode = compositeIds.map(_.utdanningsmulighetKode) + sql"""select "organisasjonskode_saksbehandler", "utdanningsmulighet_kode", "organisasjonskode_tilbyder" + from "public"."test_sak_soknadsalternativ" + where ("organisasjonskode_saksbehandler", "utdanningsmulighet_kode") + in (select unnest(${organisasjonskodeSaksbehandler}), unnest(${utdanningsmulighetKode})) + """.query(using TestSakSoknadsalternativRow.jdbcDecoder).selectStream() + + } + override def selectByIdsTracked(compositeIds: Array[TestSakSoknadsalternativId]): ZIO[ZConnection, Throwable, Map[TestSakSoknadsalternativId, TestSakSoknadsalternativRow]] = { + selectByIds(compositeIds).runCollect.map { rows => + val byId = rows.view.map(x => (x.compositeId, x)).toMap + compositeIds.view.flatMap(id => byId.get(id).map(x => (id, x))).toMap + } + } + override def update: UpdateBuilder[TestSakSoknadsalternativFields, TestSakSoknadsalternativRow] = { + UpdateBuilder(""""public"."test_sak_soknadsalternativ"""", TestSakSoknadsalternativFields.structure, TestSakSoknadsalternativRow.jdbcDecoder) + } + override def update(row: TestSakSoknadsalternativRow): ZIO[ZConnection, Throwable, Boolean] = { + val compositeId = row.compositeId + sql"""update "public"."test_sak_soknadsalternativ" + set "organisasjonskode_tilbyder" = ${Segment.paramSegment(row.organisasjonskodeTilbyder)(TestOrganisasjonId.setter)} + where "organisasjonskode_saksbehandler" = ${Segment.paramSegment(compositeId.organisasjonskodeSaksbehandler)(Setter.stringSetter)} AND "utdanningsmulighet_kode" = ${Segment.paramSegment(compositeId.utdanningsmulighetKode)(Setter.stringSetter)}""".update.map(_ > 0) + } + override def upsert(unsaved: TestSakSoknadsalternativRow): ZIO[ZConnection, Throwable, UpdateResult[TestSakSoknadsalternativRow]] = { + sql"""insert into "public"."test_sak_soknadsalternativ"("organisasjonskode_saksbehandler", "utdanningsmulighet_kode", "organisasjonskode_tilbyder") + values ( + ${Segment.paramSegment(unsaved.organisasjonskodeSaksbehandler)(Setter.stringSetter)}, + ${Segment.paramSegment(unsaved.utdanningsmulighetKode)(Setter.stringSetter)}, + ${Segment.paramSegment(unsaved.organisasjonskodeTilbyder)(TestOrganisasjonId.setter)} + ) + on conflict ("organisasjonskode_saksbehandler", "utdanningsmulighet_kode") + do update set + "organisasjonskode_tilbyder" = EXCLUDED."organisasjonskode_tilbyder" + returning "organisasjonskode_saksbehandler", "utdanningsmulighet_kode", "organisasjonskode_tilbyder"""".insertReturning(using TestSakSoknadsalternativRow.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, TestSakSoknadsalternativRow], batchSize: Int = 10000): ZIO[ZConnection, Throwable, Long] = { + val created = sql"""create temporary table test_sak_soknadsalternativ_TEMP (like "public"."test_sak_soknadsalternativ") on commit drop""".execute + val copied = streamingInsert(s"""copy test_sak_soknadsalternativ_TEMP("organisasjonskode_saksbehandler", "utdanningsmulighet_kode", "organisasjonskode_tilbyder") from stdin""", batchSize, unsaved)(TestSakSoknadsalternativRow.text) + val merged = sql"""insert into "public"."test_sak_soknadsalternativ"("organisasjonskode_saksbehandler", "utdanningsmulighet_kode", "organisasjonskode_tilbyder") + select * from test_sak_soknadsalternativ_TEMP + on conflict ("organisasjonskode_saksbehandler", "utdanningsmulighet_kode") + do update set + "organisasjonskode_tilbyder" = EXCLUDED."organisasjonskode_tilbyder" + ; + drop table test_sak_soknadsalternativ_TEMP;""".update + created *> copied *> merged + } +} diff --git a/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/test_sak_soknadsalternativ/TestSakSoknadsalternativRepoMock.scala b/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/test_sak_soknadsalternativ/TestSakSoknadsalternativRepoMock.scala new file mode 100644 index 0000000000..5501d911da --- /dev/null +++ b/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/test_sak_soknadsalternativ/TestSakSoknadsalternativRepoMock.scala @@ -0,0 +1,102 @@ +/** + * File has been automatically generated by `typo`. + * + * IF YOU CHANGE THIS FILE YOUR CHANGES WILL BE OVERWRITTEN. + */ +package adventureworks +package public +package test_sak_soknadsalternativ + +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 TestSakSoknadsalternativRepoMock(map: scala.collection.mutable.Map[TestSakSoknadsalternativId, TestSakSoknadsalternativRow] = scala.collection.mutable.Map.empty) extends TestSakSoknadsalternativRepo { + override def delete: DeleteBuilder[TestSakSoknadsalternativFields, TestSakSoknadsalternativRow] = { + DeleteBuilderMock(DeleteParams.empty, TestSakSoknadsalternativFields.structure, map) + } + override def deleteById(compositeId: TestSakSoknadsalternativId): ZIO[ZConnection, Throwable, Boolean] = { + ZIO.succeed(map.remove(compositeId).isDefined) + } + override def deleteByIds(compositeIds: Array[TestSakSoknadsalternativId]): ZIO[ZConnection, Throwable, Long] = { + ZIO.succeed(compositeIds.map(id => map.remove(id)).count(_.isDefined).toLong) + } + override def insert(unsaved: TestSakSoknadsalternativRow): ZIO[ZConnection, Throwable, TestSakSoknadsalternativRow] = { + ZIO.succeed { + val _ = + if (map.contains(unsaved.compositeId)) + sys.error(s"id ${unsaved.compositeId} already exists") + else + map.put(unsaved.compositeId, unsaved) + + unsaved + } + } + override def insertStreaming(unsaved: ZStream[ZConnection, Throwable, TestSakSoknadsalternativRow], batchSize: Int = 10000): ZIO[ZConnection, Throwable, Long] = { + unsaved.scanZIO(0L) { case (acc, row) => + ZIO.succeed { + map += (row.compositeId -> row) + acc + 1 + } + }.runLast.map(_.getOrElse(0L)) + } + override def select: SelectBuilder[TestSakSoknadsalternativFields, TestSakSoknadsalternativRow] = { + SelectBuilderMock(TestSakSoknadsalternativFields.structure, ZIO.succeed(Chunk.fromIterable(map.values)), SelectParams.empty) + } + override def selectAll: ZStream[ZConnection, Throwable, TestSakSoknadsalternativRow] = { + ZStream.fromIterable(map.values) + } + override def selectById(compositeId: TestSakSoknadsalternativId): ZIO[ZConnection, Throwable, Option[TestSakSoknadsalternativRow]] = { + ZIO.succeed(map.get(compositeId)) + } + override def selectByIds(compositeIds: Array[TestSakSoknadsalternativId]): ZStream[ZConnection, Throwable, TestSakSoknadsalternativRow] = { + ZStream.fromIterable(compositeIds.flatMap(map.get)) + } + override def selectByIdsTracked(compositeIds: Array[TestSakSoknadsalternativId]): ZIO[ZConnection, Throwable, Map[TestSakSoknadsalternativId, TestSakSoknadsalternativRow]] = { + selectByIds(compositeIds).runCollect.map { rows => + val byId = rows.view.map(x => (x.compositeId, x)).toMap + compositeIds.view.flatMap(id => byId.get(id).map(x => (id, x))).toMap + } + } + override def update: UpdateBuilder[TestSakSoknadsalternativFields, TestSakSoknadsalternativRow] = { + UpdateBuilderMock(UpdateParams.empty, TestSakSoknadsalternativFields.structure, map) + } + override def update(row: TestSakSoknadsalternativRow): ZIO[ZConnection, Throwable, Boolean] = { + ZIO.succeed { + map.get(row.compositeId) match { + case Some(`row`) => false + case Some(_) => + map.put(row.compositeId, row): @nowarn + true + case None => false + } + } + } + override def upsert(unsaved: TestSakSoknadsalternativRow): ZIO[ZConnection, Throwable, UpdateResult[TestSakSoknadsalternativRow]] = { + ZIO.succeed { + map.put(unsaved.compositeId, 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, TestSakSoknadsalternativRow], batchSize: Int = 10000): ZIO[ZConnection, Throwable, Long] = { + unsaved.scanZIO(0L) { case (acc, row) => + ZIO.succeed { + map += (row.compositeId -> row) + acc + 1 + } + }.runLast.map(_.getOrElse(0L)) + } +} diff --git a/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/test_sak_soknadsalternativ/TestSakSoknadsalternativRow.scala b/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/test_sak_soknadsalternativ/TestSakSoknadsalternativRow.scala new file mode 100644 index 0000000000..51e7a314c9 --- /dev/null +++ b/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/test_sak_soknadsalternativ/TestSakSoknadsalternativRow.scala @@ -0,0 +1,77 @@ +/** + * File has been automatically generated by `typo`. + * + * IF YOU CHANGE THIS FILE YOUR CHANGES WILL BE OVERWRITTEN. + */ +package adventureworks +package public +package test_sak_soknadsalternativ + +import adventureworks.public.test_organisasjon.TestOrganisasjonId +import adventureworks.public.test_utdanningstilbud.TestUtdanningstilbudId +import java.sql.ResultSet +import zio.jdbc.JdbcDecoder +import zio.json.JsonDecoder +import zio.json.JsonEncoder +import zio.json.ast.Json +import zio.json.internal.Write + +/** Table: public.test_sak_soknadsalternativ + Composite primary key: organisasjonskode_saksbehandler, utdanningsmulighet_kode */ +case class TestSakSoknadsalternativRow( + organisasjonskodeSaksbehandler: String, + /** Points to [[test_utdanningstilbud.TestUtdanningstilbudRow.utdanningsmulighetKode]] */ + utdanningsmulighetKode: String, + /** Points to [[test_utdanningstilbud.TestUtdanningstilbudRow.organisasjonskode]] */ + organisasjonskodeTilbyder: TestOrganisasjonId +){ + val compositeId: TestSakSoknadsalternativId = TestSakSoknadsalternativId(organisasjonskodeSaksbehandler, utdanningsmulighetKode) + val id = compositeId + val extractTestUtdanningstilbudId: TestUtdanningstilbudId = TestUtdanningstilbudId( + organisasjonskode = organisasjonskodeTilbyder, + utdanningsmulighetKode = utdanningsmulighetKode + ) + } + +object TestSakSoknadsalternativRow { + def apply(compositeId: TestSakSoknadsalternativId, organisasjonskodeTilbyder: TestOrganisasjonId) = + new TestSakSoknadsalternativRow(compositeId.organisasjonskodeSaksbehandler, compositeId.utdanningsmulighetKode, organisasjonskodeTilbyder) + implicit lazy val jdbcDecoder: JdbcDecoder[TestSakSoknadsalternativRow] = new JdbcDecoder[TestSakSoknadsalternativRow] { + override def unsafeDecode(columIndex: Int, rs: ResultSet): (Int, TestSakSoknadsalternativRow) = + columIndex + 2 -> + TestSakSoknadsalternativRow( + organisasjonskodeSaksbehandler = JdbcDecoder.stringDecoder.unsafeDecode(columIndex + 0, rs)._2, + utdanningsmulighetKode = JdbcDecoder.stringDecoder.unsafeDecode(columIndex + 1, rs)._2, + organisasjonskodeTilbyder = TestOrganisasjonId.jdbcDecoder.unsafeDecode(columIndex + 2, rs)._2 + ) + } + implicit lazy val jsonDecoder: JsonDecoder[TestSakSoknadsalternativRow] = JsonDecoder[Json.Obj].mapOrFail { jsonObj => + val organisasjonskodeSaksbehandler = jsonObj.get("organisasjonskode_saksbehandler").toRight("Missing field 'organisasjonskode_saksbehandler'").flatMap(_.as(JsonDecoder.string)) + val utdanningsmulighetKode = jsonObj.get("utdanningsmulighet_kode").toRight("Missing field 'utdanningsmulighet_kode'").flatMap(_.as(JsonDecoder.string)) + val organisasjonskodeTilbyder = jsonObj.get("organisasjonskode_tilbyder").toRight("Missing field 'organisasjonskode_tilbyder'").flatMap(_.as(TestOrganisasjonId.jsonDecoder)) + if (organisasjonskodeSaksbehandler.isRight && utdanningsmulighetKode.isRight && organisasjonskodeTilbyder.isRight) + Right(TestSakSoknadsalternativRow(organisasjonskodeSaksbehandler = organisasjonskodeSaksbehandler.toOption.get, utdanningsmulighetKode = utdanningsmulighetKode.toOption.get, organisasjonskodeTilbyder = organisasjonskodeTilbyder.toOption.get)) + else Left(List[Either[String, Any]](organisasjonskodeSaksbehandler, utdanningsmulighetKode, organisasjonskodeTilbyder).flatMap(_.left.toOption).mkString(", ")) + } + implicit lazy val jsonEncoder: JsonEncoder[TestSakSoknadsalternativRow] = new JsonEncoder[TestSakSoknadsalternativRow] { + override def unsafeEncode(a: TestSakSoknadsalternativRow, indent: Option[Int], out: Write): Unit = { + out.write("{") + out.write(""""organisasjonskode_saksbehandler":""") + JsonEncoder.string.unsafeEncode(a.organisasjonskodeSaksbehandler, indent, out) + out.write(",") + out.write(""""utdanningsmulighet_kode":""") + JsonEncoder.string.unsafeEncode(a.utdanningsmulighetKode, indent, out) + out.write(",") + out.write(""""organisasjonskode_tilbyder":""") + TestOrganisasjonId.jsonEncoder.unsafeEncode(a.organisasjonskodeTilbyder, indent, out) + out.write("}") + } + } + implicit lazy val text: Text[TestSakSoknadsalternativRow] = Text.instance[TestSakSoknadsalternativRow]{ (row, sb) => + Text.stringInstance.unsafeEncode(row.organisasjonskodeSaksbehandler, sb) + sb.append(Text.DELIMETER) + Text.stringInstance.unsafeEncode(row.utdanningsmulighetKode, sb) + sb.append(Text.DELIMETER) + TestOrganisasjonId.text.unsafeEncode(row.organisasjonskodeTilbyder, sb) + } +} diff --git a/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/test_utdanningstilbud/TestUtdanningstilbudFields.scala b/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/test_utdanningstilbud/TestUtdanningstilbudFields.scala new file mode 100644 index 0000000000..8d12859730 --- /dev/null +++ b/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/test_utdanningstilbud/TestUtdanningstilbudFields.scala @@ -0,0 +1,55 @@ +/** + * File has been automatically generated by `typo`. + * + * IF YOU CHANGE THIS FILE YOUR CHANGES WILL BE OVERWRITTEN. + */ +package adventureworks +package public +package test_utdanningstilbud + +import adventureworks.public.test_organisasjon.TestOrganisasjonFields +import adventureworks.public.test_organisasjon.TestOrganisasjonId +import adventureworks.public.test_organisasjon.TestOrganisasjonRow +import typo.dsl.ForeignKey +import typo.dsl.Path +import typo.dsl.Required +import typo.dsl.SqlExpr +import typo.dsl.SqlExpr.CompositeIn +import typo.dsl.SqlExpr.CompositeIn.TuplePart +import typo.dsl.SqlExpr.FieldLikeNoHkt +import typo.dsl.SqlExpr.IdField +import typo.dsl.Structure.Relation + +trait TestUtdanningstilbudFields { + def organisasjonskode: IdField[TestOrganisasjonId, TestUtdanningstilbudRow] + def utdanningsmulighetKode: IdField[String, TestUtdanningstilbudRow] + def fkTestOrganisasjon: ForeignKey[TestOrganisasjonFields, TestOrganisasjonRow] = + ForeignKey[TestOrganisasjonFields, TestOrganisasjonRow]("public.test_utdanningstilbud_organisasjonskode_fkey", Nil) + .withColumnPair(organisasjonskode, _.organisasjonskode) + def compositeIdIs(compositeId: TestUtdanningstilbudId): SqlExpr[Boolean, Required] = + organisasjonskode.isEqual(compositeId.organisasjonskode).and(utdanningsmulighetKode.isEqual(compositeId.utdanningsmulighetKode)) + def compositeIdIn(compositeIds: Array[TestUtdanningstilbudId]): SqlExpr[Boolean, Required] = + new CompositeIn(compositeIds)(TuplePart(organisasjonskode)(_.organisasjonskode), TuplePart(utdanningsmulighetKode)(_.utdanningsmulighetKode)) + +} + +object TestUtdanningstilbudFields { + lazy val structure: Relation[TestUtdanningstilbudFields, TestUtdanningstilbudRow] = + new Impl(Nil) + + private final class Impl(val _path: List[Path]) + extends Relation[TestUtdanningstilbudFields, TestUtdanningstilbudRow] { + + override lazy val fields: TestUtdanningstilbudFields = new TestUtdanningstilbudFields { + override def organisasjonskode = IdField[TestOrganisasjonId, TestUtdanningstilbudRow](_path, "organisasjonskode", None, None, x => x.organisasjonskode, (row, value) => row.copy(organisasjonskode = value)) + override def utdanningsmulighetKode = IdField[String, TestUtdanningstilbudRow](_path, "utdanningsmulighet_kode", None, None, x => x.utdanningsmulighetKode, (row, value) => row.copy(utdanningsmulighetKode = value)) + } + + override lazy val columns: List[FieldLikeNoHkt[?, TestUtdanningstilbudRow]] = + List[FieldLikeNoHkt[?, TestUtdanningstilbudRow]](fields.organisasjonskode, fields.utdanningsmulighetKode) + + override def copy(path: List[Path]): Impl = + new Impl(path) + } + +} diff --git a/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/test_utdanningstilbud/TestUtdanningstilbudId.scala b/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/test_utdanningstilbud/TestUtdanningstilbudId.scala new file mode 100644 index 0000000000..7f52a29b9d --- /dev/null +++ b/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/test_utdanningstilbud/TestUtdanningstilbudId.scala @@ -0,0 +1,41 @@ +/** + * File has been automatically generated by `typo`. + * + * IF YOU CHANGE THIS FILE YOUR CHANGES WILL BE OVERWRITTEN. + */ +package adventureworks +package public +package test_utdanningstilbud + +import adventureworks.public.test_organisasjon.TestOrganisasjonId +import zio.json.JsonDecoder +import zio.json.JsonEncoder +import zio.json.ast.Json +import zio.json.internal.Write + +/** Type for the composite primary key of table `public.test_utdanningstilbud` */ +case class TestUtdanningstilbudId( + organisasjonskode: TestOrganisasjonId, + utdanningsmulighetKode: String +) +object TestUtdanningstilbudId { + implicit lazy val jsonDecoder: JsonDecoder[TestUtdanningstilbudId] = JsonDecoder[Json.Obj].mapOrFail { jsonObj => + val organisasjonskode = jsonObj.get("organisasjonskode").toRight("Missing field 'organisasjonskode'").flatMap(_.as(TestOrganisasjonId.jsonDecoder)) + val utdanningsmulighetKode = jsonObj.get("utdanningsmulighet_kode").toRight("Missing field 'utdanningsmulighet_kode'").flatMap(_.as(JsonDecoder.string)) + if (organisasjonskode.isRight && utdanningsmulighetKode.isRight) + Right(TestUtdanningstilbudId(organisasjonskode = organisasjonskode.toOption.get, utdanningsmulighetKode = utdanningsmulighetKode.toOption.get)) + else Left(List[Either[String, Any]](organisasjonskode, utdanningsmulighetKode).flatMap(_.left.toOption).mkString(", ")) + } + implicit lazy val jsonEncoder: JsonEncoder[TestUtdanningstilbudId] = new JsonEncoder[TestUtdanningstilbudId] { + override def unsafeEncode(a: TestUtdanningstilbudId, indent: Option[Int], out: Write): Unit = { + out.write("{") + out.write(""""organisasjonskode":""") + TestOrganisasjonId.jsonEncoder.unsafeEncode(a.organisasjonskode, indent, out) + out.write(",") + out.write(""""utdanningsmulighet_kode":""") + JsonEncoder.string.unsafeEncode(a.utdanningsmulighetKode, indent, out) + out.write("}") + } + } + implicit lazy val ordering: Ordering[TestUtdanningstilbudId] = Ordering.by(x => (x.organisasjonskode, x.utdanningsmulighetKode)) +} diff --git a/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/test_utdanningstilbud/TestUtdanningstilbudRepo.scala b/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/test_utdanningstilbud/TestUtdanningstilbudRepo.scala new file mode 100644 index 0000000000..9e8b8d3daa --- /dev/null +++ b/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/test_utdanningstilbud/TestUtdanningstilbudRepo.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 test_utdanningstilbud + +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 TestUtdanningstilbudRepo { + def delete: DeleteBuilder[TestUtdanningstilbudFields, TestUtdanningstilbudRow] + def deleteById(compositeId: TestUtdanningstilbudId): ZIO[ZConnection, Throwable, Boolean] + def deleteByIds(compositeIds: Array[TestUtdanningstilbudId]): ZIO[ZConnection, Throwable, Long] + def insert(unsaved: TestUtdanningstilbudRow): ZIO[ZConnection, Throwable, TestUtdanningstilbudRow] + def insertStreaming(unsaved: ZStream[ZConnection, Throwable, TestUtdanningstilbudRow], batchSize: Int = 10000): ZIO[ZConnection, Throwable, Long] + def select: SelectBuilder[TestUtdanningstilbudFields, TestUtdanningstilbudRow] + def selectAll: ZStream[ZConnection, Throwable, TestUtdanningstilbudRow] + def selectById(compositeId: TestUtdanningstilbudId): ZIO[ZConnection, Throwable, Option[TestUtdanningstilbudRow]] + def selectByIds(compositeIds: Array[TestUtdanningstilbudId]): ZStream[ZConnection, Throwable, TestUtdanningstilbudRow] + def selectByIdsTracked(compositeIds: Array[TestUtdanningstilbudId]): ZIO[ZConnection, Throwable, Map[TestUtdanningstilbudId, TestUtdanningstilbudRow]] + def update: UpdateBuilder[TestUtdanningstilbudFields, TestUtdanningstilbudRow] + def upsert(unsaved: TestUtdanningstilbudRow): ZIO[ZConnection, Throwable, UpdateResult[TestUtdanningstilbudRow]] + // 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, TestUtdanningstilbudRow], batchSize: Int = 10000): ZIO[ZConnection, Throwable, Long] +} diff --git a/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/test_utdanningstilbud/TestUtdanningstilbudRepoImpl.scala b/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/test_utdanningstilbud/TestUtdanningstilbudRepoImpl.scala new file mode 100644 index 0000000000..3e7fa81d46 --- /dev/null +++ b/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/test_utdanningstilbud/TestUtdanningstilbudRepoImpl.scala @@ -0,0 +1,99 @@ +/** + * File has been automatically generated by `typo`. + * + * IF YOU CHANGE THIS FILE YOUR CHANGES WILL BE OVERWRITTEN. + */ +package adventureworks +package public +package test_utdanningstilbud + +import adventureworks.public.test_organisasjon.TestOrganisasjonId +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.SqlFragment.Setter +import zio.jdbc.UpdateResult +import zio.jdbc.ZConnection +import zio.jdbc.sqlInterpolator +import zio.stream.ZStream + +class TestUtdanningstilbudRepoImpl extends TestUtdanningstilbudRepo { + override def delete: DeleteBuilder[TestUtdanningstilbudFields, TestUtdanningstilbudRow] = { + DeleteBuilder(""""public"."test_utdanningstilbud"""", TestUtdanningstilbudFields.structure) + } + override def deleteById(compositeId: TestUtdanningstilbudId): ZIO[ZConnection, Throwable, Boolean] = { + sql"""delete from "public"."test_utdanningstilbud" where "organisasjonskode" = ${Segment.paramSegment(compositeId.organisasjonskode)(TestOrganisasjonId.setter)} AND "utdanningsmulighet_kode" = ${Segment.paramSegment(compositeId.utdanningsmulighetKode)(Setter.stringSetter)}""".delete.map(_ > 0) + } + override def deleteByIds(compositeIds: Array[TestUtdanningstilbudId]): ZIO[ZConnection, Throwable, Long] = { + val organisasjonskode = compositeIds.map(_.organisasjonskode) + val utdanningsmulighetKode = compositeIds.map(_.utdanningsmulighetKode) + sql"""delete + from "public"."test_utdanningstilbud" + where ("organisasjonskode", "utdanningsmulighet_kode") + in (select unnest(${organisasjonskode}), unnest(${utdanningsmulighetKode})) + """.delete + + } + override def insert(unsaved: TestUtdanningstilbudRow): ZIO[ZConnection, Throwable, TestUtdanningstilbudRow] = { + sql"""insert into "public"."test_utdanningstilbud"("organisasjonskode", "utdanningsmulighet_kode") + values (${Segment.paramSegment(unsaved.organisasjonskode)(TestOrganisasjonId.setter)}, ${Segment.paramSegment(unsaved.utdanningsmulighetKode)(Setter.stringSetter)}) + returning "organisasjonskode", "utdanningsmulighet_kode" + """.insertReturning(using TestUtdanningstilbudRow.jdbcDecoder).map(_.updatedKeys.head) + } + override def insertStreaming(unsaved: ZStream[ZConnection, Throwable, TestUtdanningstilbudRow], batchSize: Int = 10000): ZIO[ZConnection, Throwable, Long] = { + streamingInsert(s"""COPY "public"."test_utdanningstilbud"("organisasjonskode", "utdanningsmulighet_kode") FROM STDIN""", batchSize, unsaved)(TestUtdanningstilbudRow.text) + } + override def select: SelectBuilder[TestUtdanningstilbudFields, TestUtdanningstilbudRow] = { + SelectBuilderSql(""""public"."test_utdanningstilbud"""", TestUtdanningstilbudFields.structure, TestUtdanningstilbudRow.jdbcDecoder) + } + override def selectAll: ZStream[ZConnection, Throwable, TestUtdanningstilbudRow] = { + sql"""select "organisasjonskode", "utdanningsmulighet_kode" from "public"."test_utdanningstilbud"""".query(using TestUtdanningstilbudRow.jdbcDecoder).selectStream() + } + override def selectById(compositeId: TestUtdanningstilbudId): ZIO[ZConnection, Throwable, Option[TestUtdanningstilbudRow]] = { + sql"""select "organisasjonskode", "utdanningsmulighet_kode" from "public"."test_utdanningstilbud" where "organisasjonskode" = ${Segment.paramSegment(compositeId.organisasjonskode)(TestOrganisasjonId.setter)} AND "utdanningsmulighet_kode" = ${Segment.paramSegment(compositeId.utdanningsmulighetKode)(Setter.stringSetter)}""".query(using TestUtdanningstilbudRow.jdbcDecoder).selectOne + } + override def selectByIds(compositeIds: Array[TestUtdanningstilbudId]): ZStream[ZConnection, Throwable, TestUtdanningstilbudRow] = { + val organisasjonskode = compositeIds.map(_.organisasjonskode) + val utdanningsmulighetKode = compositeIds.map(_.utdanningsmulighetKode) + sql"""select "organisasjonskode", "utdanningsmulighet_kode" + from "public"."test_utdanningstilbud" + where ("organisasjonskode", "utdanningsmulighet_kode") + in (select unnest(${organisasjonskode}), unnest(${utdanningsmulighetKode})) + """.query(using TestUtdanningstilbudRow.jdbcDecoder).selectStream() + + } + override def selectByIdsTracked(compositeIds: Array[TestUtdanningstilbudId]): ZIO[ZConnection, Throwable, Map[TestUtdanningstilbudId, TestUtdanningstilbudRow]] = { + selectByIds(compositeIds).runCollect.map { rows => + val byId = rows.view.map(x => (x.compositeId, x)).toMap + compositeIds.view.flatMap(id => byId.get(id).map(x => (id, x))).toMap + } + } + override def update: UpdateBuilder[TestUtdanningstilbudFields, TestUtdanningstilbudRow] = { + UpdateBuilder(""""public"."test_utdanningstilbud"""", TestUtdanningstilbudFields.structure, TestUtdanningstilbudRow.jdbcDecoder) + } + override def upsert(unsaved: TestUtdanningstilbudRow): ZIO[ZConnection, Throwable, UpdateResult[TestUtdanningstilbudRow]] = { + sql"""insert into "public"."test_utdanningstilbud"("organisasjonskode", "utdanningsmulighet_kode") + values ( + ${Segment.paramSegment(unsaved.organisasjonskode)(TestOrganisasjonId.setter)}, + ${Segment.paramSegment(unsaved.utdanningsmulighetKode)(Setter.stringSetter)} + ) + on conflict ("organisasjonskode", "utdanningsmulighet_kode") + do update set "organisasjonskode" = EXCLUDED."organisasjonskode" + returning "organisasjonskode", "utdanningsmulighet_kode"""".insertReturning(using TestUtdanningstilbudRow.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, TestUtdanningstilbudRow], batchSize: Int = 10000): ZIO[ZConnection, Throwable, Long] = { + val created = sql"""create temporary table test_utdanningstilbud_TEMP (like "public"."test_utdanningstilbud") on commit drop""".execute + val copied = streamingInsert(s"""copy test_utdanningstilbud_TEMP("organisasjonskode", "utdanningsmulighet_kode") from stdin""", batchSize, unsaved)(TestUtdanningstilbudRow.text) + val merged = sql"""insert into "public"."test_utdanningstilbud"("organisasjonskode", "utdanningsmulighet_kode") + select * from test_utdanningstilbud_TEMP + on conflict ("organisasjonskode", "utdanningsmulighet_kode") + do nothing + ; + drop table test_utdanningstilbud_TEMP;""".update + created *> copied *> merged + } +} diff --git a/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/test_utdanningstilbud/TestUtdanningstilbudRepoMock.scala b/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/test_utdanningstilbud/TestUtdanningstilbudRepoMock.scala new file mode 100644 index 0000000000..17b4fa3fcf --- /dev/null +++ b/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/test_utdanningstilbud/TestUtdanningstilbudRepoMock.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 test_utdanningstilbud + +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 TestUtdanningstilbudRepoMock(map: scala.collection.mutable.Map[TestUtdanningstilbudId, TestUtdanningstilbudRow] = scala.collection.mutable.Map.empty) extends TestUtdanningstilbudRepo { + override def delete: DeleteBuilder[TestUtdanningstilbudFields, TestUtdanningstilbudRow] = { + DeleteBuilderMock(DeleteParams.empty, TestUtdanningstilbudFields.structure, map) + } + override def deleteById(compositeId: TestUtdanningstilbudId): ZIO[ZConnection, Throwable, Boolean] = { + ZIO.succeed(map.remove(compositeId).isDefined) + } + override def deleteByIds(compositeIds: Array[TestUtdanningstilbudId]): ZIO[ZConnection, Throwable, Long] = { + ZIO.succeed(compositeIds.map(id => map.remove(id)).count(_.isDefined).toLong) + } + override def insert(unsaved: TestUtdanningstilbudRow): ZIO[ZConnection, Throwable, TestUtdanningstilbudRow] = { + ZIO.succeed { + val _ = + if (map.contains(unsaved.compositeId)) + sys.error(s"id ${unsaved.compositeId} already exists") + else + map.put(unsaved.compositeId, unsaved) + + unsaved + } + } + override def insertStreaming(unsaved: ZStream[ZConnection, Throwable, TestUtdanningstilbudRow], batchSize: Int = 10000): ZIO[ZConnection, Throwable, Long] = { + unsaved.scanZIO(0L) { case (acc, row) => + ZIO.succeed { + map += (row.compositeId -> row) + acc + 1 + } + }.runLast.map(_.getOrElse(0L)) + } + override def select: SelectBuilder[TestUtdanningstilbudFields, TestUtdanningstilbudRow] = { + SelectBuilderMock(TestUtdanningstilbudFields.structure, ZIO.succeed(Chunk.fromIterable(map.values)), SelectParams.empty) + } + override def selectAll: ZStream[ZConnection, Throwable, TestUtdanningstilbudRow] = { + ZStream.fromIterable(map.values) + } + override def selectById(compositeId: TestUtdanningstilbudId): ZIO[ZConnection, Throwable, Option[TestUtdanningstilbudRow]] = { + ZIO.succeed(map.get(compositeId)) + } + override def selectByIds(compositeIds: Array[TestUtdanningstilbudId]): ZStream[ZConnection, Throwable, TestUtdanningstilbudRow] = { + ZStream.fromIterable(compositeIds.flatMap(map.get)) + } + override def selectByIdsTracked(compositeIds: Array[TestUtdanningstilbudId]): ZIO[ZConnection, Throwable, Map[TestUtdanningstilbudId, TestUtdanningstilbudRow]] = { + selectByIds(compositeIds).runCollect.map { rows => + val byId = rows.view.map(x => (x.compositeId, x)).toMap + compositeIds.view.flatMap(id => byId.get(id).map(x => (id, x))).toMap + } + } + override def update: UpdateBuilder[TestUtdanningstilbudFields, TestUtdanningstilbudRow] = { + UpdateBuilderMock(UpdateParams.empty, TestUtdanningstilbudFields.structure, map) + } + override def upsert(unsaved: TestUtdanningstilbudRow): ZIO[ZConnection, Throwable, UpdateResult[TestUtdanningstilbudRow]] = { + ZIO.succeed { + map.put(unsaved.compositeId, 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, TestUtdanningstilbudRow], batchSize: Int = 10000): ZIO[ZConnection, Throwable, Long] = { + unsaved.scanZIO(0L) { case (acc, row) => + ZIO.succeed { + map += (row.compositeId -> row) + acc + 1 + } + }.runLast.map(_.getOrElse(0L)) + } +} diff --git a/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/test_utdanningstilbud/TestUtdanningstilbudRow.scala b/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/test_utdanningstilbud/TestUtdanningstilbudRow.scala new file mode 100644 index 0000000000..6ffc48f283 --- /dev/null +++ b/typo-tester-zio-jdbc/generated-and-checked-in/adventureworks/public/test_utdanningstilbud/TestUtdanningstilbudRow.scala @@ -0,0 +1,63 @@ +/** + * File has been automatically generated by `typo`. + * + * IF YOU CHANGE THIS FILE YOUR CHANGES WILL BE OVERWRITTEN. + */ +package adventureworks +package public +package test_utdanningstilbud + +import adventureworks.public.test_organisasjon.TestOrganisasjonId +import java.sql.ResultSet +import zio.jdbc.JdbcDecoder +import zio.json.JsonDecoder +import zio.json.JsonEncoder +import zio.json.ast.Json +import zio.json.internal.Write + +/** Table: public.test_utdanningstilbud + Composite primary key: organisasjonskode, utdanningsmulighet_kode */ +case class TestUtdanningstilbudRow( + /** Points to [[test_organisasjon.TestOrganisasjonRow.organisasjonskode]] */ + organisasjonskode: TestOrganisasjonId, + utdanningsmulighetKode: String +){ + val compositeId: TestUtdanningstilbudId = TestUtdanningstilbudId(organisasjonskode, utdanningsmulighetKode) + val id = compositeId + } + +object TestUtdanningstilbudRow { + def apply(compositeId: TestUtdanningstilbudId) = + new TestUtdanningstilbudRow(compositeId.organisasjonskode, compositeId.utdanningsmulighetKode) + implicit lazy val jdbcDecoder: JdbcDecoder[TestUtdanningstilbudRow] = new JdbcDecoder[TestUtdanningstilbudRow] { + override def unsafeDecode(columIndex: Int, rs: ResultSet): (Int, TestUtdanningstilbudRow) = + columIndex + 1 -> + TestUtdanningstilbudRow( + organisasjonskode = TestOrganisasjonId.jdbcDecoder.unsafeDecode(columIndex + 0, rs)._2, + utdanningsmulighetKode = JdbcDecoder.stringDecoder.unsafeDecode(columIndex + 1, rs)._2 + ) + } + implicit lazy val jsonDecoder: JsonDecoder[TestUtdanningstilbudRow] = JsonDecoder[Json.Obj].mapOrFail { jsonObj => + val organisasjonskode = jsonObj.get("organisasjonskode").toRight("Missing field 'organisasjonskode'").flatMap(_.as(TestOrganisasjonId.jsonDecoder)) + val utdanningsmulighetKode = jsonObj.get("utdanningsmulighet_kode").toRight("Missing field 'utdanningsmulighet_kode'").flatMap(_.as(JsonDecoder.string)) + if (organisasjonskode.isRight && utdanningsmulighetKode.isRight) + Right(TestUtdanningstilbudRow(organisasjonskode = organisasjonskode.toOption.get, utdanningsmulighetKode = utdanningsmulighetKode.toOption.get)) + else Left(List[Either[String, Any]](organisasjonskode, utdanningsmulighetKode).flatMap(_.left.toOption).mkString(", ")) + } + implicit lazy val jsonEncoder: JsonEncoder[TestUtdanningstilbudRow] = new JsonEncoder[TestUtdanningstilbudRow] { + override def unsafeEncode(a: TestUtdanningstilbudRow, indent: Option[Int], out: Write): Unit = { + out.write("{") + out.write(""""organisasjonskode":""") + TestOrganisasjonId.jsonEncoder.unsafeEncode(a.organisasjonskode, indent, out) + out.write(",") + out.write(""""utdanningsmulighet_kode":""") + JsonEncoder.string.unsafeEncode(a.utdanningsmulighetKode, indent, out) + out.write("}") + } + } + implicit lazy val text: Text[TestUtdanningstilbudRow] = Text.instance[TestUtdanningstilbudRow]{ (row, sb) => + TestOrganisasjonId.text.unsafeEncode(row.organisasjonskode, sb) + sb.append(Text.DELIMETER) + Text.stringInstance.unsafeEncode(row.utdanningsmulighetKode, 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 0bc9ac468d..a379077615 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 @@ -219,6 +219,14 @@ import adventureworks.public.table_with_generated_columns.TableWithGeneratedColu import adventureworks.public.table_with_generated_columns.TableWithGeneratedColumnsRepoImpl import adventureworks.public.table_with_generated_columns.TableWithGeneratedColumnsRow import adventureworks.public.table_with_generated_columns.TableWithGeneratedColumnsRowUnsaved +import adventureworks.public.test_organisasjon.TestOrganisasjonId +import adventureworks.public.test_organisasjon.TestOrganisasjonRepoImpl +import adventureworks.public.test_organisasjon.TestOrganisasjonRow +import adventureworks.public.test_sak_soknadsalternativ.TestSakSoknadsalternativRepoImpl +import adventureworks.public.test_sak_soknadsalternativ.TestSakSoknadsalternativRow +import adventureworks.public.test_utdanningstilbud.TestUtdanningstilbudId +import adventureworks.public.test_utdanningstilbud.TestUtdanningstilbudRepoImpl +import adventureworks.public.test_utdanningstilbud.TestUtdanningstilbudRow import adventureworks.public.title.TitleId import adventureworks.public.title.TitleRepoImpl import adventureworks.public.title.TitleRow @@ -797,6 +805,9 @@ class TestInsert(random: Random, domainInsert: TestDomainInsert) { xmles: Option[Array[TypoXml]] = None ): ZIO[ZConnection, Throwable, PgtestnullRow] = (new PgtestnullRepoImpl).insert(new PgtestnullRow(bool = bool, box = box, bpchar = bpchar, bytea = bytea, char = char, circle = circle, date = date, float4 = float4, float8 = float8, hstore = hstore, inet = inet, int2 = int2, int2vector = int2vector, int4 = int4, int8 = int8, interval = interval, json = json, jsonb = jsonb, line = line, lseg = lseg, money = money, mydomain = mydomain, myenum = myenum, name = name, numeric = numeric, path = path, point = point, polygon = polygon, text = text, time = time, timestamp = timestamp, timestampz = timestampz, timez = timez, uuid = uuid, varchar = varchar, vector = vector, xml = xml, boxes = boxes, bpchares = bpchares, chares = chares, circlees = circlees, datees = datees, float4es = float4es, float8es = float8es, inetes = inetes, int2es = int2es, int2vectores = int2vectores, int4es = int4es, int8es = int8es, intervales = intervales, jsones = jsones, jsonbes = jsonbes, linees = linees, lseges = lseges, moneyes = moneyes, mydomaines = mydomaines, myenumes = myenumes, namees = namees, numerices = numerices, pathes = pathes, pointes = pointes, polygones = polygones, textes = textes, timees = timees, timestampes = timestampes, timestampzes = timestampzes, timezes = timezes, uuides = uuides, varchares = varchares, xmles = xmles)) def publicTableWithGeneratedColumns(name: TableWithGeneratedColumnsId = TableWithGeneratedColumnsId(random.alphanumeric.take(20).mkString)): ZIO[ZConnection, Throwable, TableWithGeneratedColumnsRow] = (new TableWithGeneratedColumnsRepoImpl).insert(new TableWithGeneratedColumnsRowUnsaved(name = name)) + def publicTestOrganisasjon(organisasjonskode: TestOrganisasjonId = TestOrganisasjonId(random.alphanumeric.take(20).mkString)): ZIO[ZConnection, Throwable, TestOrganisasjonRow] = (new TestOrganisasjonRepoImpl).insert(new TestOrganisasjonRow(organisasjonskode = organisasjonskode)) + def publicTestSakSoknadsalternativ(TestUtdanningstilbudId: TestUtdanningstilbudId, organisasjonskodeSaksbehandler: String = random.alphanumeric.take(20).mkString): ZIO[ZConnection, Throwable, TestSakSoknadsalternativRow] = (new TestSakSoknadsalternativRepoImpl).insert(new TestSakSoknadsalternativRow(organisasjonskodeSaksbehandler = organisasjonskodeSaksbehandler, utdanningsmulighetKode = TestUtdanningstilbudId.utdanningsmulighetKode, organisasjonskodeTilbyder = TestUtdanningstilbudId.organisasjonskode)) + def publicTestUtdanningstilbud(organisasjonskode: TestOrganisasjonId, utdanningsmulighetKode: String = random.alphanumeric.take(20).mkString): ZIO[ZConnection, Throwable, TestUtdanningstilbudRow] = (new TestUtdanningstilbudRepoImpl).insert(new TestUtdanningstilbudRow(organisasjonskode = organisasjonskode, utdanningsmulighetKode = utdanningsmulighetKode)) def publicTitle(code: TitleId = TitleId(random.alphanumeric.take(20).mkString)): ZIO[ZConnection, Throwable, TitleRow] = (new TitleRepoImpl).insert(new TitleRow(code = code)) def publicTitleDomain(code: TitleDomainId = TitleDomainId(domainInsert.publicShortText(random))): ZIO[ZConnection, Throwable, TitleDomainRow] = (new TitleDomainRepoImpl).insert(new TitleDomainRow(code = code)) def publicTitledperson(titleShort: TitleDomainId = TitleDomainId.All(random.nextInt(4)), diff --git a/typo/src/scala/typo/internal/FkAnalysis.scala b/typo/src/scala/typo/internal/FkAnalysis.scala index cf59cf9e7a..4de87ae99b 100644 --- a/typo/src/scala/typo/internal/FkAnalysis.scala +++ b/typo/src/scala/typo/internal/FkAnalysis.scala @@ -96,7 +96,7 @@ object FkAnalysis { remainingThisCols.partition(col => candidateFk.thisFk.cols.contains(col.dbName)) match { case (consumedNewCols, rest) if consumedNewCols.nonEmpty => val affectedThisCols = reshuffle(candidateFk, thisOriginalColumns) - byFk = (candidateFk.thisFk, ColsFromFk(candidateFk.otherId, affectedThisCols)) :: byFk + byFk = (candidateFk.thisFk, ColsFromFk(candidateFk.otherId, affectedThisCols, candidateFk)) :: byFk remainingThisCols = rest case _ => () } @@ -107,13 +107,24 @@ object FkAnalysis { } /** A composite ID type from another table, and the columns in this table which can be extracted¬ */ - case class ColsFromFk(otherCompositeId: IdComputed.Composite, thisColumns: List[ComputedColumn]) { + case class ColsFromFk(otherCompositeId: IdComputed.Composite, thisColumns: List[ComputedColumn], candidateFk: CandidateFk) { + def param: sc.Param = otherCompositeId.param def withParamName(name: sc.Ident): ColsFromFk = - copy(otherCompositeId = otherCompositeId.copy(paramName = name)) - lazy val colPairs: List[(ComputedColumn, ComputedColumn)] = - otherCompositeId.cols.toList.zip(thisColumns) + copy(otherCompositeId = otherCompositeId.copy(paramName = name), candidateFk = candidateFk) + lazy val colPairs: List[(ComputedColumn, ComputedColumn)] = { + // Map columns correctly based on FK relationship + thisColumns.map { thisCol => + // Find the position of this column in the FK's thisFk.cols + val indexInFk = candidateFk.thisFk.cols.toList.indexWhere(_ == thisCol.dbName) + // Get the corresponding column name in the other table + val otherColName = candidateFk.thisFk.otherCols.toList(indexInFk) + // Find the corresponding column in the other composite ID + val otherCol = otherCompositeId.cols.find(_.dbName == otherColName).get + (otherCol, thisCol) + } + } lazy val expr: Map[sc.Ident, sc.Code] = colPairs.map { case (fromId, col) => (col.name, code"${param.name}.${fromId.name}") }.toMap } @@ -190,4 +201,5 @@ object FkAnalysis { thisOriginalColumns.toList .filter(col => candidateFk.thisFk.cols.contains(col.dbName)) .sortBy(thisCol => candidateFk.thisFk.cols.toList.indexWhere(_ == thisCol.dbCol.name)) + }