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

Foreign keys in DSL #93

Merged
merged 1 commit into from
May 24, 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
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,13 @@ package person

import testdb.hardcoded.myschema.Number
import testdb.hardcoded.myschema.Sector
import testdb.hardcoded.myschema.football_club.FootballClubFields
import testdb.hardcoded.myschema.football_club.FootballClubId
import testdb.hardcoded.myschema.football_club.FootballClubRow
import testdb.hardcoded.myschema.marital_status.MaritalStatusFields
import testdb.hardcoded.myschema.marital_status.MaritalStatusId
import testdb.hardcoded.myschema.marital_status.MaritalStatusRow
import typo.dsl.ForeignKey
import typo.dsl.Path
import typo.dsl.SqlExpr.Field
import typo.dsl.SqlExpr.FieldLikeNoHkt
Expand All @@ -32,6 +37,12 @@ trait PersonFields {
def workEmail: OptField[/* max 254 chars */ String, PersonRow]
def sector: Field[Sector, PersonRow]
def favoriteNumber: Field[Number, PersonRow]
def fkFootballClub: ForeignKey[FootballClubFields, FootballClubRow] =
ForeignKey[FootballClubFields, FootballClubRow]("myschema.person_favourite_football_club_id_fkey", Nil)
.withColumnPair(favouriteFootballClubId, _.id)
def fkMaritalStatus: ForeignKey[MaritalStatusFields, MaritalStatusRow] =
ForeignKey[MaritalStatusFields, MaritalStatusRow]("myschema.person_marital_status_id_fkey", Nil)
.withColumnPair(maritalStatusId, _.id)
}

object PersonFields {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,13 @@ package person

import testdb.hardcoded.myschema.Number
import testdb.hardcoded.myschema.Sector
import testdb.hardcoded.myschema.football_club.FootballClubFields
import testdb.hardcoded.myschema.football_club.FootballClubId
import testdb.hardcoded.myschema.football_club.FootballClubRow
import testdb.hardcoded.myschema.marital_status.MaritalStatusFields
import testdb.hardcoded.myschema.marital_status.MaritalStatusId
import testdb.hardcoded.myschema.marital_status.MaritalStatusRow
import typo.dsl.ForeignKey
import typo.dsl.Path
import typo.dsl.SqlExpr.Field
import typo.dsl.SqlExpr.FieldLikeNoHkt
Expand All @@ -32,6 +37,12 @@ trait PersonFields {
def workEmail: OptField[/* max 254 chars */ String, PersonRow]
def sector: Field[Sector, PersonRow]
def favoriteNumber: Field[Number, PersonRow]
def fkFootballClub: ForeignKey[FootballClubFields, FootballClubRow] =
ForeignKey[FootballClubFields, FootballClubRow]("myschema.person_favourite_football_club_id_fkey", Nil)
.withColumnPair(favouriteFootballClubId, _.id)
def fkMaritalStatus: ForeignKey[MaritalStatusFields, MaritalStatusRow] =
ForeignKey[MaritalStatusFields, MaritalStatusRow]("myschema.person_marital_status_id_fkey", Nil)
.withColumnPair(maritalStatusId, _.id)
}

object PersonFields {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,13 @@ package person

import testdb.hardcoded.myschema.Number
import testdb.hardcoded.myschema.Sector
import testdb.hardcoded.myschema.football_club.FootballClubFields
import testdb.hardcoded.myschema.football_club.FootballClubId
import testdb.hardcoded.myschema.football_club.FootballClubRow
import testdb.hardcoded.myschema.marital_status.MaritalStatusFields
import testdb.hardcoded.myschema.marital_status.MaritalStatusId
import testdb.hardcoded.myschema.marital_status.MaritalStatusRow
import typo.dsl.ForeignKey
import typo.dsl.Path
import typo.dsl.SqlExpr.Field
import typo.dsl.SqlExpr.FieldLikeNoHkt
Expand All @@ -32,6 +37,12 @@ trait PersonFields {
def workEmail: OptField[/* max 254 chars */ String, PersonRow]
def sector: Field[Sector, PersonRow]
def favoriteNumber: Field[Number, PersonRow]
def fkFootballClub: ForeignKey[FootballClubFields, FootballClubRow] =
ForeignKey[FootballClubFields, FootballClubRow]("myschema.person_favourite_football_club_id_fkey", Nil)
.withColumnPair(favouriteFootballClubId, _.id)
def fkMaritalStatus: ForeignKey[MaritalStatusFields, MaritalStatusRow] =
ForeignKey[MaritalStatusFields, MaritalStatusRow]("myschema.person_marital_status_id_fkey", Nil)
.withColumnPair(maritalStatusId, _.id)
}

object PersonFields {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,13 @@ package person

import testdb.hardcoded.myschema.Number
import testdb.hardcoded.myschema.Sector
import testdb.hardcoded.myschema.football_club.FootballClubFields
import testdb.hardcoded.myschema.football_club.FootballClubId
import testdb.hardcoded.myschema.football_club.FootballClubRow
import testdb.hardcoded.myschema.marital_status.MaritalStatusFields
import testdb.hardcoded.myschema.marital_status.MaritalStatusId
import testdb.hardcoded.myschema.marital_status.MaritalStatusRow
import typo.dsl.ForeignKey
import typo.dsl.Path
import typo.dsl.SqlExpr.Field
import typo.dsl.SqlExpr.FieldLikeNoHkt
Expand All @@ -32,6 +37,12 @@ trait PersonFields {
def workEmail: OptField[/* max 254 chars */ String, PersonRow]
def sector: Field[Sector, PersonRow]
def favoriteNumber: Field[Number, PersonRow]
def fkFootballClub: ForeignKey[FootballClubFields, FootballClubRow] =
ForeignKey[FootballClubFields, FootballClubRow]("myschema.person_favourite_football_club_id_fkey", Nil)
.withColumnPair(favouriteFootballClubId, _.id)
def fkMaritalStatus: ForeignKey[MaritalStatusFields, MaritalStatusRow] =
ForeignKey[MaritalStatusFields, MaritalStatusRow]("myschema.person_marital_status_id_fkey", Nil)
.withColumnPair(maritalStatusId, _.id)
}

object PersonFields {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,13 @@ package person

import testdb.hardcoded.myschema.Number
import testdb.hardcoded.myschema.Sector
import testdb.hardcoded.myschema.football_club.FootballClubFields
import testdb.hardcoded.myschema.football_club.FootballClubId
import testdb.hardcoded.myschema.football_club.FootballClubRow
import testdb.hardcoded.myschema.marital_status.MaritalStatusFields
import testdb.hardcoded.myschema.marital_status.MaritalStatusId
import testdb.hardcoded.myschema.marital_status.MaritalStatusRow
import typo.dsl.ForeignKey
import typo.dsl.Path
import typo.dsl.SqlExpr.Field
import typo.dsl.SqlExpr.FieldLikeNoHkt
Expand All @@ -32,6 +37,12 @@ trait PersonFields {
def workEmail: OptField[/* max 254 chars */ String, PersonRow]
def sector: Field[Sector, PersonRow]
def favoriteNumber: Field[Number, PersonRow]
def fkFootballClub: ForeignKey[FootballClubFields, FootballClubRow] =
ForeignKey[FootballClubFields, FootballClubRow]("myschema.person_favourite_football_club_id_fkey", Nil)
.withColumnPair(favouriteFootballClubId, _.id)
def fkMaritalStatus: ForeignKey[MaritalStatusFields, MaritalStatusRow] =
ForeignKey[MaritalStatusFields, MaritalStatusRow]("myschema.person_marital_status_id_fkey", Nil)
.withColumnPair(maritalStatusId, _.id)
}

object PersonFields {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,13 @@ package person

import testdb.hardcoded.myschema.Number
import testdb.hardcoded.myschema.Sector
import testdb.hardcoded.myschema.football_club.FootballClubFields
import testdb.hardcoded.myschema.football_club.FootballClubId
import testdb.hardcoded.myschema.football_club.FootballClubRow
import testdb.hardcoded.myschema.marital_status.MaritalStatusFields
import testdb.hardcoded.myschema.marital_status.MaritalStatusId
import testdb.hardcoded.myschema.marital_status.MaritalStatusRow
import typo.dsl.ForeignKey
import typo.dsl.Path
import typo.dsl.SqlExpr.Field
import typo.dsl.SqlExpr.FieldLikeNoHkt
Expand All @@ -32,6 +37,12 @@ trait PersonFields {
def workEmail: OptField[/* max 254 chars */ String, PersonRow]
def sector: Field[Sector, PersonRow]
def favoriteNumber: Field[Number, PersonRow]
def fkFootballClub: ForeignKey[FootballClubFields, FootballClubRow] =
ForeignKey[FootballClubFields, FootballClubRow]("myschema.person_favourite_football_club_id_fkey", Nil)
.withColumnPair(favouriteFootballClubId, _.id)
def fkMaritalStatus: ForeignKey[MaritalStatusFields, MaritalStatusRow] =
ForeignKey[MaritalStatusFields, MaritalStatusRow]("myschema.person_marital_status_id_fkey", Nil)
.withColumnPair(maritalStatusId, _.id)
}

object PersonFields {
Expand Down
16 changes: 16 additions & 0 deletions typo-dsl-anorm/src/scala/typo/dsl/SelectBuilder.scala
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,27 @@ trait SelectBuilder[Fields, Row] {
/** Return sql for debugging. [[None]] if backed by a mock repository */
def sql: Option[Fragment]

final def joinFk[Fields2, Row2](f: Fields => ForeignKey[Fields2, Row2])(other: SelectBuilder[Fields2, Row2]): SelectBuilder[Joined[Fields, Fields2], (Row, Row2)] =
joinOn[Fields2, Option, Row2](other) { case (thisFields, thatFields) =>
val fk: ForeignKey[Fields2, Row2] = f(thisFields)

fk.columnPairs
.map { case columnPair: ForeignKey.ColumnPair[t, Fields2] =>
implicit val ord: Ordering[t] = columnPair.ordering
val left: SqlExpr[t, Option] = columnPair.thisField
val right: SqlExpr[t, Option] = columnPair.thatField(thatFields)
left === right
}
.reduce(_.and(_))
}

/** start constructing a join */
final def join[F2, Row2](other: SelectBuilder[F2, Row2]): PartialJoin[F2, Row2] =
new PartialJoin[F2, Row2](other)

final class PartialJoin[Fields2, Row2](other: SelectBuilder[Fields2, Row2]) {
def onFk(f: Fields => ForeignKey[Fields2, Row2]): SelectBuilder[Joined[Fields, Fields2], (Row, Row2)] =
joinFk(f)(other)

/** inner join with the given predicate
* {{{
Expand Down
16 changes: 16 additions & 0 deletions typo-dsl-doobie/src/scala/typo/dsl/SelectBuilder.scala
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,27 @@ trait SelectBuilder[Fields, Row] {
/** Return sql for debugging. [[None]] if backed by a mock repository */
def sql: Option[Fragment]

final def joinFk[Fields2, Row2](f: Fields => ForeignKey[Fields2, Row2])(other: SelectBuilder[Fields2, Row2]): SelectBuilder[Joined[Fields, Fields2], (Row, Row2)] =
joinOn[Fields2, Option, Row2](other) { case (thisFields, thatFields) =>
val fk: ForeignKey[Fields2, Row2] = f(thisFields)

fk.columnPairs
.map { case columnPair: ForeignKey.ColumnPair[t, Fields2] =>
implicit val ord: Ordering[t] = columnPair.ordering
val left: SqlExpr[t, Option] = columnPair.thisField
val right: SqlExpr[t, Option] = columnPair.thatField(thatFields)
left === right
}
.reduce(_.and(_))
}

/** start constructing a join */
final def join[F2, Row2](other: SelectBuilder[F2, Row2]): PartialJoin[F2, Row2] =
new PartialJoin[F2, Row2](other)

final class PartialJoin[Fields2, Row2](other: SelectBuilder[Fields2, Row2]) {
def onFk(f: Fields => ForeignKey[Fields2, Row2]): SelectBuilder[Joined[Fields, Fields2], (Row, Row2)] =
joinFk(f)(other)

/** inner join with the given predicate
* {{{
Expand Down
2 changes: 1 addition & 1 deletion typo-dsl-doobie/src/scala/typo/dsl/SqlExpr.scala
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ object SqlExpr {

sealed trait FieldLikeNotIdNoHkt[NT, R] extends FieldLikeNoHkt[NT, R]

sealed trait FieldLike[T, N[_], R] extends SqlExpr[T, N] with FieldLikeNoHkt[N[T], R] with Product {
sealed trait FieldLike[T, N[_], R] extends SqlExpr[T, N] with FieldLikeNoHkt[N[T], R] {
val path: List[Path]
val name: String
val sqlReadCast: Option[String]
Expand Down
24 changes: 24 additions & 0 deletions typo-dsl-shared/typo/dsl/ForeignKey.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package typo.dsl

case class ForeignKey[Fields2, Row2](
name: String,
columnPairs: List[ForeignKey.ColumnPair[?, Fields2]]
) {

def withColumnPair[T, ThisN[_]: Nullability, ThatN[_]: Nullability](
field: SqlExpr.FieldLike[T, ThisN, ?],
thatField: Fields2 => SqlExpr.FieldLike[T, ThatN, Row2]
)(implicit O: Ordering[T]): ForeignKey[Fields2, Row2] =
new ForeignKey[Fields2, Row2](
name,
columnPairs :+ ForeignKey.ColumnPair[T, Fields2](field.?, f => thatField(f).?, O)
)
}

object ForeignKey {
case class ColumnPair[T, Fields2](
thisField: SqlExpr[T, Option],
thatField: Fields2 => SqlExpr[T, Option],
ordering: Ordering[T]
)
}
16 changes: 16 additions & 0 deletions typo-dsl-zio-jdbc/src/scala/typo/dsl/SelectBuilder.scala
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,27 @@ trait SelectBuilder[Fields, Row] {
/** Return sql for debugging. [[None]] if backed by a mock repository */
def sql: Option[SqlFragment]

final def joinFk[Fields2, Row2](f: Fields => ForeignKey[Fields2, Row2])(other: SelectBuilder[Fields2, Row2]): SelectBuilder[Joined[Fields, Fields2], (Row, Row2)] =
joinOn[Fields2, Option, Row2](other) { case (thisFields, thatFields) =>
val fk: ForeignKey[Fields2, Row2] = f(thisFields)

fk.columnPairs
.map { case columnPair: ForeignKey.ColumnPair[t, Fields2] =>
implicit val ord: Ordering[t] = columnPair.ordering
val left: SqlExpr[t, Option] = columnPair.thisField
val right: SqlExpr[t, Option] = columnPair.thatField(thatFields)
left === right
}
.reduce(_.and(_))
}

/** start constructing a join */
final def join[F2, Row2](other: SelectBuilder[F2, Row2]): PartialJoin[F2, Row2] =
new PartialJoin[F2, Row2](other)

final class PartialJoin[Fields2, Row2](other: SelectBuilder[Fields2, Row2]) {
def onFk(f: Fields => ForeignKey[Fields2, Row2]): SelectBuilder[Joined[Fields, Fields2], (Row, Row2)] =
joinFk(f)(other)

/** inner join with the given predicate
* {{{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@ import adventureworks.customtypes.TypoLocalDateTime
import adventureworks.customtypes.TypoShort
import adventureworks.customtypes.TypoUUID
import adventureworks.person.businessentity.BusinessentityId
import adventureworks.person.person.PersonFields
import adventureworks.person.person.PersonRow
import adventureworks.public.Flag
import typo.dsl.ForeignKey
import typo.dsl.Path
import typo.dsl.SqlExpr.Field
import typo.dsl.SqlExpr.FieldLikeNoHkt
Expand All @@ -36,6 +39,9 @@ trait EmployeeFields {
def rowguid: Field[TypoUUID, EmployeeRow]
def modifieddate: Field[TypoLocalDateTime, EmployeeRow]
def organizationnode: OptField[String, EmployeeRow]
def fkPersonPerson: ForeignKey[PersonFields, PersonRow] =
ForeignKey[PersonFields, PersonRow]("humanresources.FK_Employee_Person_BusinessEntityID", Nil)
.withColumnPair(businessentityid, _.businessentityid)
}

object EmployeeFields {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,16 @@ package employeedepartmenthistory

import adventureworks.customtypes.TypoLocalDate
import adventureworks.customtypes.TypoLocalDateTime
import adventureworks.humanresources.department.DepartmentFields
import adventureworks.humanresources.department.DepartmentId
import adventureworks.humanresources.department.DepartmentRow
import adventureworks.humanresources.employee.EmployeeFields
import adventureworks.humanresources.employee.EmployeeRow
import adventureworks.humanresources.shift.ShiftFields
import adventureworks.humanresources.shift.ShiftId
import adventureworks.humanresources.shift.ShiftRow
import adventureworks.person.businessentity.BusinessentityId
import typo.dsl.ForeignKey
import typo.dsl.Path
import typo.dsl.SqlExpr.Field
import typo.dsl.SqlExpr.FieldLikeNoHkt
Expand All @@ -26,6 +33,15 @@ trait EmployeedepartmenthistoryFields {
def startdate: IdField[TypoLocalDate, EmployeedepartmenthistoryRow]
def enddate: OptField[TypoLocalDate, EmployeedepartmenthistoryRow]
def modifieddate: Field[TypoLocalDateTime, EmployeedepartmenthistoryRow]
def fkDepartment: ForeignKey[DepartmentFields, DepartmentRow] =
ForeignKey[DepartmentFields, DepartmentRow]("humanresources.FK_EmployeeDepartmentHistory_Department_DepartmentID", Nil)
.withColumnPair(departmentid, _.departmentid)
def fkEmployee: ForeignKey[EmployeeFields, EmployeeRow] =
ForeignKey[EmployeeFields, EmployeeRow]("humanresources.FK_EmployeeDepartmentHistory_Employee_BusinessEntityID", Nil)
.withColumnPair(businessentityid, _.businessentityid)
def fkShift: ForeignKey[ShiftFields, ShiftRow] =
ForeignKey[ShiftFields, ShiftRow]("humanresources.FK_EmployeeDepartmentHistory_Shift_ShiftID", Nil)
.withColumnPair(shiftid, _.shiftid)
}

object EmployeedepartmenthistoryFields {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ package employeepayhistory

import adventureworks.customtypes.TypoLocalDateTime
import adventureworks.customtypes.TypoShort
import adventureworks.humanresources.employee.EmployeeFields
import adventureworks.humanresources.employee.EmployeeRow
import adventureworks.person.businessentity.BusinessentityId
import typo.dsl.ForeignKey
import typo.dsl.Path
import typo.dsl.SqlExpr.Field
import typo.dsl.SqlExpr.FieldLikeNoHkt
Expand All @@ -22,6 +25,9 @@ trait EmployeepayhistoryFields {
def rate: Field[BigDecimal, EmployeepayhistoryRow]
def payfrequency: Field[TypoShort, EmployeepayhistoryRow]
def modifieddate: Field[TypoLocalDateTime, EmployeepayhistoryRow]
def fkEmployee: ForeignKey[EmployeeFields, EmployeeRow] =
ForeignKey[EmployeeFields, EmployeeRow]("humanresources.FK_EmployeePayHistory_Employee_BusinessEntityID", Nil)
.withColumnPair(businessentityid, _.businessentityid)
}

object EmployeepayhistoryFields {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ package jobcandidate

import adventureworks.customtypes.TypoLocalDateTime
import adventureworks.customtypes.TypoXml
import adventureworks.humanresources.employee.EmployeeFields
import adventureworks.humanresources.employee.EmployeeRow
import adventureworks.person.businessentity.BusinessentityId
import typo.dsl.ForeignKey
import typo.dsl.Path
import typo.dsl.SqlExpr.Field
import typo.dsl.SqlExpr.FieldLikeNoHkt
Expand All @@ -22,6 +25,9 @@ trait JobcandidateFields {
def businessentityid: OptField[BusinessentityId, JobcandidateRow]
def resume: OptField[TypoXml, JobcandidateRow]
def modifieddate: Field[TypoLocalDateTime, JobcandidateRow]
def fkEmployee: ForeignKey[EmployeeFields, EmployeeRow] =
ForeignKey[EmployeeFields, EmployeeRow]("humanresources.FK_JobCandidate_Employee_BusinessEntityID", Nil)
.withColumnPair(businessentityid, _.businessentityid)
}

object JobcandidateFields {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ package address
import adventureworks.customtypes.TypoBytea
import adventureworks.customtypes.TypoLocalDateTime
import adventureworks.customtypes.TypoUUID
import adventureworks.person.stateprovince.StateprovinceFields
import adventureworks.person.stateprovince.StateprovinceId
import adventureworks.person.stateprovince.StateprovinceRow
import typo.dsl.ForeignKey
import typo.dsl.Path
import typo.dsl.SqlExpr.Field
import typo.dsl.SqlExpr.FieldLikeNoHkt
Expand All @@ -28,6 +31,9 @@ trait AddressFields {
def spatiallocation: OptField[TypoBytea, AddressRow]
def rowguid: Field[TypoUUID, AddressRow]
def modifieddate: Field[TypoLocalDateTime, AddressRow]
def fkStateprovince: ForeignKey[StateprovinceFields, StateprovinceRow] =
ForeignKey[StateprovinceFields, StateprovinceRow]("person.FK_Address_StateProvince_StateProvinceID", Nil)
.withColumnPair(stateprovinceid, _.stateprovinceid)
}

object AddressFields {
Expand Down
Loading
Loading