Models & Repositories

Data classes, the @Repository annotation, SQL mapping, and query patterns.

Models

Models are @Serializable data classes living in core-* modules so both contracts and implementations can reference them.

kotlin
  • Use @Contextual on UUID fields for proper serialization context.
  • Default id to UUID.NIL for new entities — the database generates the real ID on insert.
  • Keep models in the core-* module, not the implementation module.

Input Types

Input types represent data coming from GraphQL mutations:

kotlin

Repositories

Repositories are interfaces annotated with @Repository. Each method is annotated with @Query containing raw SQL. KSP generates the full JDBC implementation at compile time.

kotlin

Named Parameters

SQL parameters use :paramName syntax. When passing a model object, parameter names match the object's properties — :name maps to category.name.

Return Types

Return typeBehavior
List<T>Maps all rows to a list of model objects
T?Maps the first row, or returns null if no rows
TMaps the first row, throws if no rows
UnitExecutes the statement without reading results

returning *

The returning * SQL clause causes the database to return the inserted/updated row. Combined with a model return type, this gives you the entity with database-generated fields:

kotlin

Batch Lookups

Use any(:ids) with a List parameter for batch lookups — a single SQL query with an array parameter:

kotlin
Known limitation: @Query functions do not currently support multiple model parameters — only multiple primitive parameters. If you need to pass two model objects, destructure into primitives. This will be fixed in a future release.

@Query Options

OptionDefaultPurpose
returnUpdateCountfalseReturn the number of affected rows instead of mapping results
autoCloseResulttrueAutomatically close the result set after reading
autoCloseStatementtrueAutomatically close the prepared statement after execution