Commit afd42ef
Add DuckDB support to Typo code generator (#168)
* Add DuckDB support to Typo code generator
This commit introduces comprehensive DuckDB support to Typo, extending the
type-safe code generator to work with DuckDB's unique type system and SQL
dialect alongside existing PostgreSQL and MariaDB support.
## DuckDB Type System Modeling
DuckDB provides several type system features not present in PostgreSQL or
MariaDB:
1. **Unsigned Integer Types**: UTINYINT, USMALLINT, UINTEGER, UBIGINT,
UHUGEINT mapped to Kotlin's UByte, UShort, UInt, ULong, and BigInteger
2. **Nested/Complex Types**:
- LIST: Array-like collections with element type
- MAP: Key-value maps with typed keys and values
- STRUCT: Named field structures
- UNION: Tagged union types
3. **Temporal Type Variations**: TIMESTAMP_S, TIMESTAMP_MS, TIMESTAMP_NS
with different precision levels
These types are modeled in the db.scala type hierarchy and mapped to
appropriate Java/Kotlin/Scala runtime types in DuckDbAdapter.scala.
## SQL Dialect Differences
DuckDB's SQL dialect differs from PostgreSQL and MariaDB in several ways,
handled through the Dialect abstraction:
1. **Identifier Quoting**: Uses double quotes like PostgreSQL, unlike
MariaDB's backticks
2. **Type Casts**: Uses PostgreSQL-compatible :: syntax rather than
CAST() function
3. **Column References**: Simple alias."column" format, not PostgreSQL's
(alias)."column" format
4. **Array Parameter Syntax**: Arrays use DuckDB-specific syntax:
- PostgreSQL: ARRAY[?, ?, ...]::type[]
- DuckDB: [?, ?, ...]
## Runtime Type System
Added comprehensive runtime support in typo-runtime-java:
- **DuckDbType**: Type class providing read/write/stringify/json support
- **DuckDbRead**: ResultSet reading with nested type support (LIST, STRUCT, MAP)
- **DuckDbWrite**: PreparedStatement parameter binding
- **DuckDbStringifier**: SQL literal encoding for code generation
- **DuckDbTypename**: Type name abstraction with conversions
## Kotlin Nullable Type Handling
Fixed a type system mismatch between Java Optional and Kotlin nullable types:
**Problem**: The Kotlin .nullable() extension was using .bimap() which called
.map() on Nullable readers. This returned NonNullable<B> where B = A?, but
NonNullable throws SQLException when B is null. For Kotlin, null is a valid
value in the type system.
**Solution**: Created KotlinNullableDuckDbRead and KotlinNullableMariaRead
that handle nullable values natively:
- Wrap the underlying opt() reader
- Convert Optional.empty() → null and Optional.of(value) → value
- Return A? without NonNullable validation
- Implement DbRead.Nullable marker interface
This respects the different null handling semantics:
- Java/Scala: Non-nullable values guaranteed by construction
- Kotlin: Nullable values (T?) are natural in the type system
## Code Generation
Extended code generation in DbLibTypo.scala and DuckDbAdapter.scala:
- Repository implementations for Java, Kotlin, and Scala
- Row classes with proper unsigned type mapping
- RowParser lambdas without unnecessary !! assertions
- Test insert generation with DuckDB-specific types
## Testing
All test suites passing:
- Java DuckDB tests: 56/56 (AllScalarTypesTest, RepositoryTest, etc.)
- Kotlin DuckDB tests: 53/53 (AllScalarTypesTest, CompositeIdTest,
RepositoryTest, SqlFileArrayTest)
Generated code checked into:
- typo-tester-duckdb-java/generated-and-checked-in/
- typo-tester-duckdb-kotlin/generated-and-checked-in/
- typo-tester-duckdb-scala/generated-and-checked-in/
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
* Fix Kotlin nullable type handling and Scala 3 lambda generation
- Fix PgRead.Nullable.map() to use Optional.ofNullable() for Kotlin null support
- Generate explicit lambda for Scala 3 and TypeSupportJava to avoid LambdaConversionException
- Fixes NullPointerException in Kotlin PostgreSQL tests
- Fixes BootstrapMethodError in Scala 3 tests
* Fix Scala 3 lambda pattern matching - always generate lambda for LangScala
The previous pattern '_: LangScala | _ if lang.typeSupport == TypeSupportJava' was incorrect -
it only matched when typeSupport == TypeSupportJava, missing regular Scala 3 tests.
Now generates explicit lambda for:
- All LangScala (fixes >22 param limit and Scala 3 LambdaConversionException)
- TypeSupportJava
- Kotlin (already working)
Method references don't work for >22 params in Scala due to Function22 limit.
* wip
* Regenerate code with Scala 3 lambda fix for >22 parameter tables
Generated code now uses explicit lambdas instead of constructor method
references for RowParser, which fixes Scala 3 LambdaConversionException
on tables with many columns like production.product (25 params).
Also includes the Optional.ofNullable() fix for Kotlin nullable types.
* Format generated code with scalafmt
* wip
---------
Co-authored-by: Claude Sonnet 4.5 <[email protected]>1 parent 97da194 commit afd42ef
1,074 files changed
Lines changed: 35780 additions & 2011 deletions
File tree
- .bleep/generated-sources/typo-tester-typo-java/scripts.GenHardcodedFiles/testdb/hardcoded
- compositepk/person
- myschema
- football_club
- marital_status
- person
- db/duckdb
- duckdb_sql
- typo-dsl-java/src/java/typo/dsl
- typo-dsl-kotlin/src/kotlin/typo/kotlindsl
- typo-dsl-scala/src/scala/typo/scaladsl
- typo-runtime-java
- src/java/typo/runtime
- typo-scripts/src/scala/scripts
- typo-tester-anorm
- generated-and-checked-in-2.13/adventureworks/sales/vsalespersonsalesbyfiscalyearsdata
- generated-and-checked-in-3/adventureworks/sales/vsalespersonsalesbyfiscalyearsdata
- typo-tester-doobie
- generated-and-checked-in-2.13/adventureworks/sales/vsalespersonsalesbyfiscalyearsdata
- generated-and-checked-in-3/adventureworks/sales/vsalespersonsalesbyfiscalyearsdata
- typo-tester-duckdb-java
- generated-and-checked-in/testdb
- all_scalar_types_search
- all_scalar_types
- customer_orders
- customer_search
- customers
- customtypes
- delete_old_orders
- department_employee_details
- departments
- employee_salary_update
- employees
- insert_order_with_items
- order_details
- order_items_bulk_insert
- order_items
- order_summary_by_customer
- orders
- product_details_with_sales
- products
- update_customer_priority
- src/java/testdb
- typo-tester-duckdb-kotlin
- generated-and-checked-in/testdb
- all_scalar_types_search
- all_scalar_types
- customer_orders
- customer_search
- customers
- customtypes
- delete_old_orders
- department_employee_details
- departments
- employee_salary_update
- employees
- insert_order_with_items
- order_details
- order_items_bulk_insert
- order_items
- order_summary_by_customer
- orders
- product_details_with_sales
- products
- update_customer_priority
- typo-tester-duckdb-scala/generated-and-checked-in/testdb
- all_scalar_types_search
- all_scalar_types
- customer_orders
- customer_search
- customers
- customtypes
- delete_old_orders
- department_employee_details
- departments
- employee_salary_update
- employees
- insert_order_with_items
- order_details
- order_items_bulk_insert
- order_items
- order_summary_by_customer
- orders
- product_details_with_sales
- products
- update_customer_priority
- typo-tester-mariadb-java/generated-and-checked-in/testdb
- audit_log
- brands
- categories
- cte_test
- customer_addresses
- customer_orders
- customer_status
- customers
- inventory_check
- inventory
- mariatest_identity
- mariatest_spatial_null
- mariatest_spatial
- mariatest_unique
- mariatestnull
- mariatest
- order_details
- order_history
- order_items
- orders
- payment_methods
- payments
- price_tiers
- product_categories
- product_images
- product_prices
- product_search
- products
- promotions
- reviews
- shipments
- shipping_carriers
- simple_customer_lookup
- subquery_test
- v_customer_summary
- v_daily_sales
- v_inventory_status
- v_order_details
- v_product_catalog
- v_warehouse_coverage
- warehouses
- typo-tester-mariadb-kotlin/generated-and-checked-in/testdb
- inventory_check
- product_search
- typo-tester-mariadb-scala/generated-and-checked-in/testdb
- audit_log
- brands
- categories
- cte_test
- customer_addresses
- customer_orders
- customer_status
- customers
- inventory_check
- inventory
- mariatest_identity
- mariatest_spatial_null
- mariatest_spatial
- mariatest_unique
- mariatestnull
- mariatest
- order_details
- order_history
- order_items
- orders
- payment_methods
- payments
- price_tiers
- product_categories
- product_images
- product_prices
- product_search
- products
- promotions
- reviews
- shipments
- shipping_carriers
- simple_customer_lookup
- subquery_test
- v_customer_summary
- v_daily_sales
- v_inventory_status
- v_order_details
- v_product_catalog
- v_warehouse_coverage
- warehouses
- typo-tester-typo-java/generated-and-checked-in/adventureworks
- hr
- d
- edh
- eph
- e
- jc
- s
- humanresources
- department
- employeedepartmenthistory
- employeepayhistory
- employee
- jobcandidate
- shift
- vemployeedepartmenthistory
- vemployeedepartment
- vemployee
- vjobcandidateeducation
- vjobcandidateemployment
- vjobcandidate
- person_detail
- person_dynamic
- person_row_join
- person
- addresstype
- address
- businessentityaddress
- businessentitycontact
- businessentity
- contacttype
- countryregion
- emailaddress
- password
- personphone
- person
- phonenumbertype
- stateprovince
- vadditionalcontactinfo
- vstateprovincecountryregion
- pe
- at
- a
- bea
- bec
- be
- cr
- ct
- e
- pa
- pnt
- pp
- p
- sp
- production
- billofmaterials
- culture
- document
- illustration
- location
- productcategory
- productcosthistory
- productdescription
- productdocument
- productinventory
- productlistpricehistory
- productmodelillustration
- productmodelproductdescriptionculture
- productmodel
- productphoto
- productproductphoto
- productreview
- productsubcategory
- product
- scrapreason
- transactionhistoryarchive
- transactionhistory
- unitmeasure
- vproductanddescription
- vproductmodelcatalogdescription
- vproductmodelinstructions
- workorderrouting
- workorder
- pr
- bom
- c
- d
- i
- l
- pch
- pc
- pdoc
- pd
- pi
- plph
- pmi
- pmpdc
- pm
- ppp
- pp
- pr
- psc
- p
- sr
- tha
- th
- um
- wr
- w
- public_
- flaff
- identity_test
- issue142_2
- issue142
- only_pk_columns
- pgtestnull
- pgtest
- table_with_generated_columns
- test_organisasjon
- test_sak_soknadsalternativ
- test_utdanningstilbud
- title_domain
- titledperson
- title
- users
- purchasing
- productvendor
- purchaseorderdetail
- purchaseorderheader
- shipmethod
- vendor
- vvendorwithaddresses
- vvendorwithcontacts
- pu
- pod
- poh
- pv
- sm
- v
- sales
- countryregioncurrency
- creditcard
- currencyrate
- currency
- customer
- personcreditcard
- salesorderdetail
- salesorderheadersalesreason
- salesorderheader
- salespersonquotahistory
- salesperson
- salesreason
- salestaxrate
- salesterritoryhistory
- salesterritory
- shoppingcartitem
- specialofferproduct
- specialoffer
- store
- vindividualcustomer
- vpersondemographics
- vsalespersonsalesbyfiscalyearsdata
- vsalespersonsalesbyfiscalyears
- vsalesperson
- vstorewithaddresses
- vstorewithcontacts
- vstorewithdemographics
- sa
- cc
- crc
- cr
- cu
- c
- pcc
- sci
- sod
- sohsr
- soh
- sop
- so
- spqh
- sp
- sr
- sth
- st
- s
- tr
- update_person_returning
- typo-tester-typo-kotlin/generated-and-checked-in/adventureworks
- humanresources
- employeedepartmenthistory
- employeepayhistory
- person
- businessentityaddress
- businessentitycontact
- emailaddress
- personphone
- production
- productcosthistory
- productdocument
- productinventory
- productlistpricehistory
- productmodelillustration
- productmodelproductdescriptionculture
- productproductphoto
- workorderrouting
- public
- flaff
- only_pk_columns
- test_sak_soknadsalternativ
- test_utdanningstilbud
- purchasing
- productvendor
- purchaseorderdetail
- sales
- countryregioncurrency
- personcreditcard
- salesorderdetail
- salesorderheadersalesreason
- salespersonquotahistory
- salesterritoryhistory
- specialofferproduct
- vsalespersonsalesbyfiscalyearsdata
- typo-tester-typo-scala-new/generated-and-checked-in/adventureworks
- hr
- d
- edh
- eph
- e
- jc
- s
- humanresources
- department
- employeedepartmenthistory
- employeepayhistory
- employee
- jobcandidate
- shift
- vemployeedepartmenthistory
- vemployeedepartment
- vemployee
- vjobcandidateeducation
- vjobcandidateemployment
- vjobcandidate
- person_detail
- person_dynamic
- person_row_join
- person
- addresstype
- address
- businessentityaddress
- businessentitycontact
- businessentity
- contacttype
- countryregion
- emailaddress
- password
- personphone
- person
- phonenumbertype
- stateprovince
- vadditionalcontactinfo
- vstateprovincecountryregion
- pe
- at
- a
- bea
- bec
- be
- cr
- ct
- e
- pa
- pnt
- pp
- p
- sp
- production
- billofmaterials
- culture
- document
- illustration
- location
- productcategory
- productcosthistory
- productdescription
- productdocument
- productinventory
- productlistpricehistory
- productmodelillustration
- productmodelproductdescriptionculture
- productmodel
- productphoto
- productproductphoto
- productreview
- productsubcategory
- product
- scrapreason
- transactionhistoryarchive
- transactionhistory
- unitmeasure
- vproductanddescription
- vproductmodelcatalogdescription
- vproductmodelinstructions
- workorderrouting
- workorder
- pr
- bom
- c
- d
- i
- l
- pch
- pc
- pdoc
- pd
- pi
- plph
- pmi
- pmpdc
- pm
- ppp
- pp
- pr
- psc
- p
- sr
- tha
- th
- um
- wr
- w
- public
- flaff
- identity_test
- issue142_2
- issue142
- only_pk_columns
- pgtestnull
- pgtest
- table_with_generated_columns
- test_organisasjon
- test_sak_soknadsalternativ
- test_utdanningstilbud
- title_domain
- titledperson
- title
- users
- purchasing
- productvendor
- purchaseorderdetail
- purchaseorderheader
- shipmethod
- vendor
- vvendorwithaddresses
- vvendorwithcontacts
- pu
- pod
- poh
- pv
- sm
- v
- sales
- countryregioncurrency
- creditcard
- currencyrate
- currency
- customer
- personcreditcard
- salesorderdetail
- salesorderheadersalesreason
- salesorderheader
- salespersonquotahistory
- salesperson
- salesreason
- salestaxrate
- salesterritoryhistory
- salesterritory
- shoppingcartitem
- specialofferproduct
- specialoffer
- store
- vindividualcustomer
- vpersondemographics
- vsalespersonsalesbyfiscalyearsdata
- vsalespersonsalesbyfiscalyears
- vsalesperson
- vstorewithaddresses
- vstorewithcontacts
- vstorewithdemographics
- sa
- cc
- crc
- cr
- cu
- c
- pcc
- sci
- sod
- sohsr
- soh
- sop
- so
- spqh
- sp
- sr
- sth
- st
- s
- tr
- update_person_returning
- typo-tester-typo-scala-old/generated-and-checked-in/adventureworks
- hr
- d
- edh
- eph
- e
- jc
- s
- humanresources
- department
- employeedepartmenthistory
- employeepayhistory
- employee
- jobcandidate
- shift
- vemployeedepartmenthistory
- vemployeedepartment
- vemployee
- vjobcandidateeducation
- vjobcandidateemployment
- vjobcandidate
- person_detail
- person_dynamic
- person_row_join
- person
- addresstype
- address
- businessentityaddress
- businessentitycontact
- businessentity
- contacttype
- countryregion
- emailaddress
- password
- personphone
- person
- phonenumbertype
- stateprovince
- vadditionalcontactinfo
- vstateprovincecountryregion
- pe
- at
- a
- bea
- bec
- be
- cr
- ct
- e
- pa
- pnt
- pp
- p
- sp
- production
- billofmaterials
- culture
- document
- illustration
- location
- productcategory
- productcosthistory
- productdescription
- productdocument
- productinventory
- productlistpricehistory
- productmodelillustration
- productmodelproductdescriptionculture
- productmodel
- productphoto
- productproductphoto
- productreview
- productsubcategory
- product
- scrapreason
- transactionhistoryarchive
- transactionhistory
- unitmeasure
- vproductanddescription
- vproductmodelcatalogdescription
- vproductmodelinstructions
- workorderrouting
- workorder
- pr
- bom
- c
- d
- i
- l
- pch
- pc
- pdoc
- pd
- pi
- plph
- pmi
- pmpdc
- pm
- ppp
- pp
- pr
- psc
- p
- sr
- tha
- th
- um
- wr
- w
- public
- flaff
- identity_test
- issue142_2
- issue142
- only_pk_columns
- pgtestnull
- pgtest
- table_with_generated_columns
- test_organisasjon
- test_sak_soknadsalternativ
- test_utdanningstilbud
- title_domain
- titledperson
- title
- users
- purchasing
- productvendor
- purchaseorderdetail
- purchaseorderheader
- shipmethod
- vendor
- vvendorwithaddresses
- vvendorwithcontacts
- pu
- pod
- poh
- pv
- sm
- v
- sales
- countryregioncurrency
- creditcard
- currencyrate
- currency
- customer
- personcreditcard
- salesorderdetail
- salesorderheadersalesreason
- salesorderheader
- salespersonquotahistory
- salesperson
- salesreason
- salestaxrate
- salesterritoryhistory
- salesterritory
- shoppingcartitem
- specialofferproduct
- specialoffer
- store
- vindividualcustomer
- vpersondemographics
- vsalespersonsalesbyfiscalyearsdata
- vsalespersonsalesbyfiscalyears
- vsalesperson
- vstorewithaddresses
- vstorewithcontacts
- vstorewithdemographics
- sa
- cc
- crc
- cr
- cu
- c
- pcc
- sci
- sod
- sohsr
- soh
- sop
- so
- spqh
- sp
- sr
- sth
- st
- s
- tr
- update_person_returning
- typo-tester-zio-jdbc
- generated-and-checked-in-2.13/adventureworks/sales/vsalespersonsalesbyfiscalyearsdata
- generated-and-checked-in-3/adventureworks/sales/vsalespersonsalesbyfiscalyearsdata
- typo/src
- resources
- scala/typo
- internal
- analysis
- codegen
- duckdb
- sqlfiles
- openapi/codegen
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 1 addition & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
36 | 36 | | |
37 | 37 | | |
38 | 38 | | |
39 | | - | |
| 39 | + | |
40 | 40 | | |
41 | 41 | | |
42 | 42 | | |
| |||
Lines changed: 1 addition & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
26 | 26 | | |
27 | 27 | | |
28 | 28 | | |
29 | | - | |
| 29 | + | |
30 | 30 | | |
31 | 31 | | |
32 | 32 | | |
| |||
Lines changed: 1 addition & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
17 | 17 | | |
18 | 18 | | |
19 | 19 | | |
20 | | - | |
| 20 | + | |
21 | 21 | | |
22 | 22 | | |
23 | 23 | | |
| |||
Lines changed: 1 addition & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
101 | 101 | | |
102 | 102 | | |
103 | 103 | | |
104 | | - | |
| 104 | + | |
105 | 105 | | |
106 | 106 | | |
107 | 107 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
17 | 17 | | |
18 | 18 | | |
19 | 19 | | |
| 20 | + | |
| 21 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
375 | 375 | | |
376 | 376 | | |
377 | 377 | | |
| 378 | + | |
378 | 379 | | |
379 | 380 | | |
380 | | - | |
| 381 | + | |
| 382 | + | |
| 383 | + | |
| 384 | + | |
0 commit comments