Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Add Options#enablePrimaryKeyType (fix #77) #83

Merged
merged 1 commit into from
Jan 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 1 addition & 29 deletions site-in/customization/customize-selected-relations.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,42 +9,14 @@ Maybe you're generating code for just a part of the system, not the whole thing.
Typo has a mechanism by which you can choose which relations to generate code for.

among the arguments to `generateFromDb` is `selector`, which by default picks all relations except those in the postgres schemas.
See [Selector](customization/selector.md)

```scala
import typo.*

generateFromDb(options, selector = Selector.ExcludePostgresInternal)
```

## `Selector`

You can pick relations by expressing with `Selector` what you want:
```scala mdoc:silent
import typo.*

val personAndPet0 = Selector.fullRelationNames("myschema.person", "myschemapet") // picks exactly these tables
val personAndPet = Selector.relationNames("person", "pet") // picks these regardless of schema
val mySchema = Selector.schemas("myschema") // picks all relations in schema

// heaviest syntax, but most flexible
val custom: Selector = relName => relName.schema.exists(_.contains("foo")) && relName.name.contains("bar")

// can also invert the selector
!Selector.schemas("myschema") // matches everything except schema "myschema"
```

Selectors are also composable:

```scala mdoc:silent
// picks relations which are called `person` or `pet` AND are in the `myschema` schema
personAndPet and mySchema

// picks those who are *both* called `person` or `pet` OR are in the `myschema` schema.
// This will typically select more relations
personAndPet or mySchema
```

The and/or names follows boolean logic, and may actually be a bit counter-intuitive in this particular context. Suggestions welcome to improve naming

## Transitive relations

Expand Down
1 change: 1 addition & 0 deletions site-in/customization/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ val options = Options(
| `enableFieldValue` | Controls whether to enable `FieldValue` code generation for specific repositories (default is disabled). |
| `enableStreamingInserts` | Controls whether to enable [streaming inserts](other-features/streaming-inserts.md) |
| `enableTestInserts` | Controls whether to enable [test inserts](other-features/testing-with-random-values.md) for specific repositories (default is none). |
| `enablePrimaryKeyType` | Controls whether to enable [primary key types](type-safety/id-types.md) for specific repositories (default is all). |
| `readonlyRepo` | Specifies whether to generate read-only repositories for specific repositories. Useful when you're working on a part of the system where you only consume certain tables. (default is `false` - all mutable). |
| `enableDsl` | Enables the [SQL DSL](what-is/dsl.md) for code generation (default is `false`). |
| `keepDependencies` | Specifies whether to generate [table dependencies](type-safety/type-flow.md) in generated code even if you didn't select them (default is `false`). |
Expand Down
40 changes: 40 additions & 0 deletions site-in/customization/selector.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
---
title: Picking subsets of relations with Selector
---

For much of the customization, you select sets of relations, or enable particular pieces of code generation for a set of relations.

In order to make this convenient, there is a `Selector` data type.

## Pick relations by name or by schema
You can pick relations by expressing with `Selector` what you want:

```scala mdoc:silent
import typo.*

val personAndPet0 = Selector.fullRelationNames("myschema.person", "myschemapet") // picks exactly these tables
val personAndPet = Selector.relationNames("person", "pet") // picks these regardless of schema
val mySchema = Selector.schemas("myschema") // picks all relations in schema

// heaviest syntax, but most flexible
val custom: Selector = relName => relName.schema.exists(_.contains("foo")) && relName.name.contains("bar")

```

### Selectors can be inverted
```scala mdoc:silent
!Selector.schemas("myschema") // matches everything except schema "myschema"
```

### Selectors are also composable:

```scala mdoc:silent
// picks relations which are called `person` or `pet` AND are in the `myschema` schema
personAndPet and mySchema

// picks those who are *both* called `person` or `pet` OR are in the `myschema` schema.
// This will typically select more relations
personAndPet or mySchema
```

The and/or names follows boolean logic, and may actually be a bit counter-intuitive in this particular context. Suggestions welcome to improve naming
19 changes: 18 additions & 1 deletion site-in/type-safety/id-types.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,21 @@ case class EmployeedepartmenthistoryId(
object EmployeedepartmenthistoryId {
// ...instances
}
```
```

## I don't want these

if you have some tables where you don't want the type-safety this brings, you can [customize](customization/overview.md)
code generation by tweaking `Options#enablePrimaryKeyType`:

```scala mdoc:silent
import typo.*

val options = Options(
pkg = "mypkg",
Some(DbLibName.Doobie),
enablePrimaryKeyType = Selector.relationNames("myrelationname"),
)
```

Composite id key types are currently always created.
1 change: 1 addition & 0 deletions site/sidebars.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ const sidebars = {
{type: "doc", id: "customization/customize-naming"},
{type: "doc", id: "customization/customize-nullability"},
{type: "doc", id: "customization/customize-types"},
{type: "doc", id: "customization/selector"},
],
},
]
Expand Down
7 changes: 4 additions & 3 deletions typo-scripts/src/scala/scripts/GeneratedAdventureWorks.scala
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,11 @@ object GeneratedAdventureWorks {
case (_, "firstname") => "adventureworks.userdefined.FirstName"
case ("sales.creditcard", "creditcardid") => "adventureworks.userdefined.CustomCreditcardId"
},
enableDsl = true,
enableTestInserts = Selector.All,
generateMockRepos = !Selector.relationNames("purchaseorderdetail"),
readonlyRepo = Selector.relationNames("purchaseorderdetail")
enablePrimaryKeyType = !Selector.relationNames("billofmaterials"),
enableTestInserts = Selector.All,
readonlyRepo = Selector.relationNames("purchaseorderdetail"),
enableDsl = true
)
val targetSources = buildDir.resolve(s"$projectPath/generated-and-checked-in")

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,14 @@ package bom

import adventureworks.customtypes.TypoLocalDateTime
import adventureworks.customtypes.TypoShort
import adventureworks.production.billofmaterials.BillofmaterialsId
import adventureworks.production.product.ProductId
import adventureworks.production.unitmeasure.UnitmeasureId
import typo.dsl.SqlExpr.Field
import typo.dsl.SqlExpr.OptField

trait BomViewFields[Row] {
val id: Field[BillofmaterialsId, Row]
val billofmaterialsid: Field[BillofmaterialsId, Row]
val id: Field[Int, Row]
val billofmaterialsid: Field[Int, Row]
val productassemblyid: OptField[ProductId, Row]
val componentid: Field[ProductId, Row]
val startdate: Field[TypoLocalDateTime, Row]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ package bom

import adventureworks.customtypes.TypoLocalDateTime
import adventureworks.customtypes.TypoShort
import adventureworks.production.billofmaterials.BillofmaterialsId
import adventureworks.production.product.ProductId
import adventureworks.production.unitmeasure.UnitmeasureId
import anorm.Column
Expand All @@ -26,9 +25,9 @@ import scala.util.Try

case class BomViewRow(
/** Points to [[production.billofmaterials.BillofmaterialsRow.billofmaterialsid]] */
id: BillofmaterialsId,
id: Int,
/** Points to [[production.billofmaterials.BillofmaterialsRow.billofmaterialsid]] */
billofmaterialsid: BillofmaterialsId,
billofmaterialsid: Int,
/** Points to [[production.billofmaterials.BillofmaterialsRow.productassemblyid]] */
productassemblyid: Option[ProductId],
/** Points to [[production.billofmaterials.BillofmaterialsRow.componentid]] */
Expand All @@ -51,8 +50,8 @@ object BomViewRow {
implicit lazy val reads: Reads[BomViewRow] = Reads[BomViewRow](json => JsResult.fromTry(
Try(
BomViewRow(
id = json.\("id").as(BillofmaterialsId.reads),
billofmaterialsid = json.\("billofmaterialsid").as(BillofmaterialsId.reads),
id = json.\("id").as(Reads.IntReads),
billofmaterialsid = json.\("billofmaterialsid").as(Reads.IntReads),
productassemblyid = json.\("productassemblyid").toOption.map(_.as(ProductId.reads)),
componentid = json.\("componentid").as(ProductId.reads),
startdate = json.\("startdate").as(TypoLocalDateTime.reads),
Expand All @@ -68,8 +67,8 @@ object BomViewRow {
def rowParser(idx: Int): RowParser[BomViewRow] = RowParser[BomViewRow] { row =>
Success(
BomViewRow(
id = row(idx + 0)(BillofmaterialsId.column),
billofmaterialsid = row(idx + 1)(BillofmaterialsId.column),
id = row(idx + 0)(Column.columnToInt),
billofmaterialsid = row(idx + 1)(Column.columnToInt),
productassemblyid = row(idx + 2)(Column.columnToOption(ProductId.column)),
componentid = row(idx + 3)(ProductId.column),
startdate = row(idx + 4)(TypoLocalDateTime.column),
Expand All @@ -83,8 +82,8 @@ object BomViewRow {
}
implicit lazy val writes: OWrites[BomViewRow] = OWrites[BomViewRow](o =>
new JsObject(ListMap[String, JsValue](
"id" -> BillofmaterialsId.writes.writes(o.id),
"billofmaterialsid" -> BillofmaterialsId.writes.writes(o.billofmaterialsid),
"id" -> Writes.IntWrites.writes(o.id),
"billofmaterialsid" -> Writes.IntWrites.writes(o.billofmaterialsid),
"productassemblyid" -> Writes.OptionWrites(ProductId.writes).writes(o.productassemblyid),
"componentid" -> ProductId.writes.writes(o.componentid),
"startdate" -> TypoLocalDateTime.writes.writes(o.startdate),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ package bom

import adventureworks.customtypes.TypoLocalDateTime
import adventureworks.customtypes.TypoShort
import adventureworks.production.billofmaterials.BillofmaterialsId
import adventureworks.production.product.ProductId
import adventureworks.production.unitmeasure.UnitmeasureId
import typo.dsl.SqlExpr.Field
Expand All @@ -21,8 +20,8 @@ class BomViewStructure[Row](val prefix: Option[String], val extract: Row => BomV
extends Relation[BomViewFields, BomViewRow, Row]
with BomViewFields[Row] { outer =>

override val id = new Field[BillofmaterialsId, Row](prefix, "id", None, None)(x => extract(x).id, (row, value) => merge(row, extract(row).copy(id = value)))
override val billofmaterialsid = new Field[BillofmaterialsId, Row](prefix, "billofmaterialsid", None, None)(x => extract(x).billofmaterialsid, (row, value) => merge(row, extract(row).copy(billofmaterialsid = value)))
override val id = new Field[Int, Row](prefix, "id", None, None)(x => extract(x).id, (row, value) => merge(row, extract(row).copy(id = value)))
override val billofmaterialsid = new Field[Int, Row](prefix, "billofmaterialsid", None, None)(x => extract(x).billofmaterialsid, (row, value) => merge(row, extract(row).copy(billofmaterialsid = value)))
override val productassemblyid = new OptField[ProductId, Row](prefix, "productassemblyid", None, None)(x => extract(x).productassemblyid, (row, value) => merge(row, extract(row).copy(productassemblyid = value)))
override val componentid = new Field[ProductId, Row](prefix, "componentid", None, None)(x => extract(x).componentid, (row, value) => merge(row, extract(row).copy(componentid = value)))
override val startdate = new Field[TypoLocalDateTime, Row](prefix, "startdate", Some("text"), None)(x => extract(x).startdate, (row, value) => merge(row, extract(row).copy(startdate = value)))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import typo.dsl.SqlExpr.IdField
import typo.dsl.SqlExpr.OptField

trait BillofmaterialsFields[Row] {
val billofmaterialsid: IdField[BillofmaterialsId, Row]
val billofmaterialsid: IdField[Int, Row]
val productassemblyid: OptField[ProductId, Row]
val componentid: Field[ProductId, Row]
val startdate: Field[TypoLocalDateTime, Row]
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import typo.dsl.SelectBuilder
import typo.dsl.UpdateBuilder

trait BillofmaterialsRepo {
def delete(billofmaterialsid: BillofmaterialsId)(implicit c: Connection): Boolean
def delete(billofmaterialsid: Int)(implicit c: Connection): Boolean
def delete: DeleteBuilder[BillofmaterialsFields, BillofmaterialsRow]
def insert(unsaved: BillofmaterialsRow)(implicit c: Connection): BillofmaterialsRow
def insertStreaming(unsaved: Iterator[BillofmaterialsRow], batchSize: Int)(implicit c: Connection): Long
Expand All @@ -22,8 +22,8 @@ trait BillofmaterialsRepo {
def insertUnsavedStreaming(unsaved: Iterator[BillofmaterialsRowUnsaved], batchSize: Int)(implicit c: Connection): Long
def select: SelectBuilder[BillofmaterialsFields, BillofmaterialsRow]
def selectAll(implicit c: Connection): List[BillofmaterialsRow]
def selectById(billofmaterialsid: BillofmaterialsId)(implicit c: Connection): Option[BillofmaterialsRow]
def selectByIds(billofmaterialsids: Array[BillofmaterialsId])(implicit c: Connection): List[BillofmaterialsRow]
def selectById(billofmaterialsid: Int)(implicit c: Connection): Option[BillofmaterialsRow]
def selectByIds(billofmaterialsids: Array[Int])(implicit c: Connection): List[BillofmaterialsRow]
def update(row: BillofmaterialsRow)(implicit c: Connection): Boolean
def update: UpdateBuilder[BillofmaterialsFields, BillofmaterialsRow]
def upsert(unsaved: BillofmaterialsRow)(implicit c: Connection): BillofmaterialsRow
Expand Down
Loading