Expand typed SQL DSL
This commit is contained in:
parent
72606e7818
commit
314c8fb207
17 changed files with 1082 additions and 498 deletions
|
|
@ -205,7 +205,7 @@ func TestGenerateSQLInsertDoUpdate(t *testing.T) {
|
|||
fun upsertAccount(row: AccountRow): GotlinSQLQuery {
|
||||
return sql.insert<AccountRow>(row)
|
||||
.onConflict { it.id }
|
||||
.doUpdate { excluded -> set(AccountRow.balance, excluded.balance) }
|
||||
.doUpdate { excluded -> AccountRow.balance = excluded.balance }
|
||||
.build()
|
||||
}
|
||||
`)
|
||||
|
|
@ -223,8 +223,8 @@ fun upsert(row: BalanceRow): GotlinSQLQuery {
|
|||
return sql.insert<BalanceRow>(row)
|
||||
.onConflict { listOf(it.tenantId, it.id) }
|
||||
.doUpdate { excluded ->
|
||||
set(BalanceRow.amount, excluded.amount)
|
||||
set(BalanceRow.pending, excluded.pending)
|
||||
BalanceRow.amount = excluded.amount
|
||||
BalanceRow.pending = excluded.pending
|
||||
}
|
||||
.build()
|
||||
}
|
||||
|
|
@ -234,6 +234,50 @@ fun upsert(row: BalanceRow): GotlinSQLQuery {
|
|||
}
|
||||
}
|
||||
|
||||
func TestGenerateSQLJoinsAliasesGroupingOffsetAndAggregates(t *testing.T) {
|
||||
code := compileSQL(t, accountRowSource+`
|
||||
@table("customers")
|
||||
data class CustomerRow(@id var id: String, var name: String)
|
||||
data class AccountSummary(var customerId: String, var customerName: String, var total: Double, var entries: Long)
|
||||
|
||||
fun summaries(minimum: Double): GotlinSQLQuery {
|
||||
return sql.from<AccountRow>()
|
||||
.alias("account")
|
||||
.leftJoin<CustomerRow>("customer") { account, customer -> account.customerId == customer.id }
|
||||
.select { account, customer -> AccountSummary(account.customerId, customer.name, sum(account.balance), count()) }
|
||||
.where { account, customer -> account.balance > minimum }
|
||||
.groupBy { account, customer -> listOf(account.customerId, customer.name) }
|
||||
.having { account, customer -> sum(account.balance) > minimum }
|
||||
.orderByDescending { account, customer -> sum(account.balance) }
|
||||
.limit(10)
|
||||
.offset(20)
|
||||
.build()
|
||||
}
|
||||
`)
|
||||
want := `SQL: "SELECT account.customer_id, customer.name, SUM(account.balance), COUNT(*) FROM accounts AS account LEFT JOIN customers AS customer ON account.customer_id = customer.id WHERE account.balance > $1 GROUP BY account.customer_id, customer.name HAVING SUM(account.balance) > $2 ORDER BY SUM(account.balance) DESC LIMIT 10 OFFSET 20"`
|
||||
if !strings.Contains(code, want) {
|
||||
t.Fatalf("generated Go missing %q:\n%s", want, code)
|
||||
}
|
||||
if !strings.Contains(code, `Args: []any{minimum, minimum}`) {
|
||||
t.Fatalf("aggregate arguments missing:\n%s", code)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenerateSQLBulkInsert(t *testing.T) {
|
||||
code := compileSQL(t, accountRowSource+`
|
||||
fun insertAccounts(rows: List<AccountRow>): GotlinSQLQuery = sql.insertAll<AccountRow>(rows).build()
|
||||
`)
|
||||
for _, want := range []string{
|
||||
`gotlinSQLBulkInsert[AccountRow](rows, "accounts", []string{"id", "customer_id", "kind", "balance"}`,
|
||||
`func(row *AccountRow) []any { return []any{row.Id, row.CustomerId, row.AccountType, row.Balance} }`,
|
||||
`func gotlinSQLBulkInsert[T any]`,
|
||||
`panic("bulk insert requires at least one row")`,
|
||||
} {
|
||||
if !strings.Contains(code, want) {
|
||||
t.Fatalf("generated Go missing %q:\n%s", want, code)
|
||||
}
|
||||
}
|
||||
}
|
||||
func TestRejectInvalidSQLQueries(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
|
|
@ -282,12 +326,12 @@ func TestRejectInvalidSQLQueries(t *testing.T) {
|
|||
},
|
||||
{
|
||||
name: "unknown update target",
|
||||
src: accountRowSource + `fun query(row: AccountRow): GotlinSQLQuery { return sql.insert<AccountRow>(row).onConflict { it.id }.doUpdate { excluded -> set(AccountRow.missing, excluded.balance) }.build() }`,
|
||||
src: accountRowSource + `fun query(row: AccountRow): GotlinSQLQuery { return sql.insert<AccountRow>(row).onConflict { it.id }.doUpdate { excluded -> AccountRow.missing = excluded.balance }.build() }`,
|
||||
want: "has no field missing",
|
||||
},
|
||||
{
|
||||
name: "incompatible update fields",
|
||||
src: accountRowSource + `fun query(row: AccountRow): GotlinSQLQuery { return sql.insert<AccountRow>(row).onConflict { it.id }.doUpdate { excluded -> set(AccountRow.balance, excluded.accountType) }.build() }`,
|
||||
src: accountRowSource + `fun query(row: AccountRow): GotlinSQLQuery { return sql.insert<AccountRow>(row).onConflict { it.id }.doUpdate { excluded -> AccountRow.balance = excluded.accountType }.build() }`,
|
||||
want: "has type Double",
|
||||
},
|
||||
{
|
||||
|
|
@ -338,6 +382,32 @@ fun query(row: OtherRow): GotlinSQLQuery { return sql.insert<AccountRow>(row).on
|
|||
src: accountRowSource + `fun query(row: AccountRow, pool: Any, ctx: Any): List<AccountRow> { return sql.insert<AccountRow>(row).fetch(pool, ctx).unwrap() }`,
|
||||
want: "fetch() is only supported for sql.from",
|
||||
},
|
||||
{
|
||||
name: "duplicate join alias",
|
||||
src: accountRowSource + `
|
||||
@table("customers") data class CustomerRow(@id var id: String)
|
||||
fun query(): GotlinSQLQuery = sql.from<AccountRow>().alias("row").join<CustomerRow>("row") { account, customer -> account.customerId == customer.id }.build()
|
||||
`,
|
||||
want: `duplicate SQL alias "row"`,
|
||||
},
|
||||
{
|
||||
name: "having without grouping",
|
||||
src: accountRowSource + `fun query(): GotlinSQLQuery = sql.from<AccountRow>().having { count() > 0 }.build()`,
|
||||
want: "after groupBy",
|
||||
},
|
||||
{
|
||||
name: "negative offset",
|
||||
src: accountRowSource + `fun query(): GotlinSQLQuery = sql.from<AccountRow>().offset(-1).build()`,
|
||||
want: "offset() requires a non-negative Int",
|
||||
},
|
||||
{
|
||||
name: "bulk insert wrong element type",
|
||||
src: accountRowSource + `
|
||||
@table("other") data class OtherRow(@id var id: String)
|
||||
fun query(rows: List<OtherRow>): GotlinSQLQuery = sql.insertAll<AccountRow>(rows).build()
|
||||
`,
|
||||
want: "requires List<AccountRow>",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue