Files
UUVPN/iOS-SwiftUI-Code/GRDB.swift-6.29.3/Tests/GRDBTests/AssociationHasOneThroughSQLDerivationTests.swift
T
2025-01-28 12:28:03 +08:00

259 lines
10 KiB
Swift

import XCTest
import GRDB
private struct A: TableRecord {
static let b = belongsTo(B.self)
static let c = hasOne(C.self, through: b, using: B.c)
static let restrictedC = hasOne(RestrictedC.self, through: b, using: B.restrictedC)
static let extendedC = hasOne(ExtendedC.self, through: b, using: B.extendedC)
}
private struct B: TableRecord {
static let c = belongsTo(C.self)
static let restrictedC = belongsTo(RestrictedC.self)
static let extendedC = belongsTo(ExtendedC.self)
}
private struct C: TableRecord {
}
private struct RestrictedC : TableRecord {
static let databaseTableName = "c"
static let databaseSelection: [any SQLSelectable] = [Column("name")]
}
private struct ExtendedC : TableRecord {
static let databaseTableName = "c"
static let databaseSelection: [any SQLSelectable] = [AllColumns(), Column.rowID]
}
/// Test SQL generation
class AssociationHasOneThroughSQLDerivationTests: GRDBTestCase {
override func setup(_ dbWriter: some DatabaseWriter) throws {
try dbWriter.write { db in
try db.create(table: "c") { t in
t.autoIncrementedPrimaryKey("id")
t.column("name", .text)
}
try db.create(table: "b") { t in
t.autoIncrementedPrimaryKey("id")
t.belongsTo("c")
}
try db.create(table: "a") { t in
t.autoIncrementedPrimaryKey("id")
t.belongsTo("b")
}
}
}
func testDefaultSelection() throws {
let dbQueue = try makeDatabaseQueue()
try dbQueue.inDatabase { db in
try assertEqualSQL(db, A.including(required: A.c), """
SELECT "a".*, "c".* \
FROM "a" \
JOIN "b" ON "b"."id" = "a"."bId" \
JOIN "c" ON "c"."id" = "b"."cId"
""")
try assertEqualSQL(db, A.including(required: A.restrictedC), """
SELECT "a".*, "c"."name" \
FROM "a" \
JOIN "b" ON "b"."id" = "a"."bId" \
JOIN "c" ON "c"."id" = "b"."cId"
""")
try assertEqualSQL(db, A.including(required: A.extendedC), """
SELECT "a".*, "c".*, "c"."rowid" \
FROM "a" \
JOIN "b" ON "b"."id" = "a"."bId" \
JOIN "c" ON "c"."id" = "b"."cId"
""")
}
}
func testCustomSelection() throws {
let dbQueue = try makeDatabaseQueue()
try dbQueue.inDatabase { db in
do {
let request = A.including(required: A.c
.select(Column("name")))
try assertEqualSQL(db, request, """
SELECT "a".*, "c"."name" \
FROM "a" \
JOIN "b" ON "b"."id" = "a"."bId" \
JOIN "c" ON "c"."id" = "b"."cId"
""")
}
do {
let request = A.including(required: A.c
.select(
AllColumns(),
Column.rowID))
try assertEqualSQL(db, request, """
SELECT "a".*, "c".*, "c"."rowid" \
FROM "a" \
JOIN "b" ON "b"."id" = "a"."bId" \
JOIN "c" ON "c"."id" = "b"."cId"
""")
}
do {
let aAlias = TableAlias()
let request = A
.aliased(aAlias)
.including(required: A.c
.select(
Column("name"),
(Column("id") + aAlias[Column("id")]).forKey("foo")))
try assertEqualSQL(db, request, """
SELECT "a".*, "c"."name", "c"."id" + "a"."id" AS "foo" \
FROM "a" \
JOIN "b" ON "b"."id" = "a"."bId" \
JOIN "c" ON "c"."id" = "b"."cId"
""")
}
}
}
func testFilteredAssociationImpactsJoinOnClause() throws {
let dbQueue = try makeDatabaseQueue()
try dbQueue.inDatabase { db in
do {
let request = A.including(required: A.c.filter(Column("name") != nil))
try assertEqualSQL(db, request, """
SELECT "a".*, "c".* \
FROM "a" \
JOIN "b" ON "b"."id" = "a"."bId" \
JOIN "c" ON ("c"."id" = "b"."cId") AND ("c"."name" IS NOT NULL)
""")
}
do {
let request = A.including(required: A.c.filter(key: 1))
try assertEqualSQL(db, request, """
SELECT "a".*, "c".* \
FROM "a" \
JOIN "b" ON "b"."id" = "a"."bId" \
JOIN "c" ON ("c"."id" = "b"."cId") AND ("c"."id" = 1)
""")
}
do {
let request = A.including(required: A.c.filter(keys: [1, 2, 3]))
try assertEqualSQL(db, request, """
SELECT "a".*, "c".* \
FROM "a" \
JOIN "b" ON "b"."id" = "a"."bId" \
JOIN "c" ON ("c"."id" = "b"."cId") AND ("c"."id" IN (1, 2, 3))
""")
}
do {
let request = A.including(required: A.c.filter(key: ["id": 1]))
try assertEqualSQL(db, request, """
SELECT "a".*, "c".* \
FROM "a" \
JOIN "b" ON "b"."id" = "a"."bId" \
JOIN "c" ON ("c"."id" = "b"."cId") AND ("c"."id" = 1)
""")
}
do {
let request = A.including(required: A.c.filter(keys: [["id": 1], ["id": 2]]))
try assertEqualSQL(db, request, """
SELECT "a".*, "c".* \
FROM "a" \
JOIN "b" ON "b"."id" = "a"."bId" \
JOIN "c" ON ("c"."id" = "b"."cId") AND (("c"."id" = 1) OR ("c"."id" = 2))
""")
}
do {
let cAlias = TableAlias(name: "customC")
let request = A.including(required: A.c
.aliased(cAlias)
.filter(sql: "customC.name = ?", arguments: ["foo"]))
try assertEqualSQL(db, request, """
SELECT "a".*, "customC".* \
FROM "a" \
JOIN "b" ON "b"."id" = "a"."bId" \
JOIN "c" "customC" ON ("customC"."id" = "b"."cId") AND (customC.name = 'foo')
""")
}
}
}
func testFilterAssociationInWhereClause() throws {
let dbQueue = try makeDatabaseQueue()
try dbQueue.inDatabase { db in
let cAlias = TableAlias()
let request = A
.including(required: A.c.aliased(cAlias))
.filter(cAlias[Column("name")] != nil)
try assertEqualSQL(db, request, """
SELECT "a".*, "c".* \
FROM "a" \
JOIN "b" ON "b"."id" = "a"."bId" \
JOIN "c" ON "c"."id" = "b"."cId" \
WHERE "c"."name" IS NOT NULL
""")
}
}
func testOrderAssociation() throws {
let dbQueue = try makeDatabaseQueue()
try dbQueue.inDatabase { db in
try assertEqualSQL(db, A.including(required: A.c.order(Column("name"))), """
SELECT "a".*, "c".* \
FROM "a" \
JOIN "b" ON "b"."id" = "a"."bId" \
JOIN "c" ON "c"."id" = "b"."cId" \
ORDER BY "c"."name"
""")
try assertEqualSQL(db, A.including(required: A.c.orderByPrimaryKey()), """
SELECT "a".*, "c".* \
FROM "a" \
JOIN "b" ON "b"."id" = "a"."bId" \
JOIN "c" ON "c"."id" = "b"."cId" \
ORDER BY "c"."id"
""")
try assertEqualSQL(db, A.including(required: A.c.orderByPrimaryKey()).orderByPrimaryKey(), """
SELECT "a".*, "c".* \
FROM "a" \
JOIN "b" ON "b"."id" = "a"."bId" \
JOIN "c" ON "c"."id" = "b"."cId" \
ORDER BY "a"."id", "c"."id"
""")
try assertEqualSQL(db, A.including(required: A.c.orderByPrimaryKey().reversed()).orderByPrimaryKey(), """
SELECT "a".*, "c".* \
FROM "a" \
JOIN "b" ON "b"."id" = "a"."bId" \
JOIN "c" ON "c"."id" = "b"."cId" \
ORDER BY "a"."id", "c"."id" DESC
""")
try assertEqualSQL(db, A.including(required: A.c.order(Column("name"))).reversed(), """
SELECT "a".*, "c".* \
FROM "a" \
JOIN "b" ON "b"."id" = "a"."bId" \
JOIN "c" ON "c"."id" = "b"."cId" \
ORDER BY "c"."name" DESC
""")
try assertEqualSQL(db, A.including(required: A.c.orderByPrimaryKey()).reversed(), """
SELECT "a".*, "c".* \
FROM "a" \
JOIN "b" ON "b"."id" = "a"."bId" \
JOIN "c" ON "c"."id" = "b"."cId" \
ORDER BY "c"."id" DESC
""")
try assertEqualSQL(db, A.including(required: A.c.orderByPrimaryKey()).orderByPrimaryKey().reversed(), """
SELECT "a".*, "c".* \
FROM "a" \
JOIN "b" ON "b"."id" = "a"."bId" \
JOIN "c" ON "c"."id" = "b"."cId" \
ORDER BY "a"."id" DESC, "c"."id" DESC
""")
try assertEqualSQL(db, A.including(required: A.c.orderByPrimaryKey().reversed()).orderByPrimaryKey().reversed(), """
SELECT "a".*, "c".* \
FROM "a" \
JOIN "b" ON "b"."id" = "a"."bId" \
JOIN "c" ON "c"."id" = "b"."cId" \
ORDER BY "a"."id" DESC, "c"."id"
""")
}
}
}