Skip to content

Commit

Permalink
Merge pull request #563 from groue/dev/eager-loading-from-optional-to…
Browse files Browse the repository at this point in the history
…-one

More tests for eager loading of hasMany associations
  • Loading branch information
groue authored Jun 30, 2019
2 parents 738ea4e + 2b401fe commit 7defc8e
Show file tree
Hide file tree
Showing 5 changed files with 750 additions and 7 deletions.
71 changes: 69 additions & 2 deletions Tests/GRDBTests/AssociationPrefetchingCodableRecordTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ private struct C: TableRecord, FetchableRecord, Decodable, Equatable {
}
private struct D: TableRecord, FetchableRecord, Decodable, Equatable {
var cold1: Int64
var cold2: Int64
var cold2: Int64?
var cold3: String
}

Expand Down Expand Up @@ -61,6 +61,7 @@ class AssociationPrefetchingCodableRecordTests: GRDBTestCase {
INSERT INTO d (cold1, cold2, cold3) VALUES (?, ?, ?);
INSERT INTO d (cold1, cold2, cold3) VALUES (?, ?, ?);
INSERT INTO d (cold1, cold2, cold3) VALUES (?, ?, ?);
INSERT INTO d (cold1, cold2, cold3) VALUES (?, ?, ?);
""",
arguments: [
1, "a1",
Expand All @@ -77,6 +78,7 @@ class AssociationPrefetchingCodableRecordTests: GRDBTestCase {
11, 8, "d2",
12, 8, "d3",
13, 9, "d4",
14, nil, "d5",
])
}
}
Expand Down Expand Up @@ -791,7 +793,6 @@ class AssociationPrefetchingCodableRecordTests: GRDBTestCase {
}
}

// TODO: make a variant with joining(optional:)
func testIncludingOptionalBelongsToIncludingAllHasMany() throws {
let dbQueue = try makeDatabaseQueue()
try dbQueue.write { db in
Expand Down Expand Up @@ -1014,6 +1015,72 @@ class AssociationPrefetchingCodableRecordTests: GRDBTestCase {
}
}

func testJoiningOptionalHasOneThroughIncludingAllHasMany() throws {
let dbQueue = try makeDatabaseQueue()
try dbQueue.write { db in
// Plain request
do {
let request = D
.joining(optional: D
.hasOne(A.self, through: D.belongsTo(C.self), using: C.belongsTo(A.self))
.including(all: A
.hasMany(B.self)
.orderByPrimaryKey()))
.orderByPrimaryKey()

// Record (flat)
do {
struct Record: FetchableRecord, Decodable, Equatable {
var d: D
var bs: [B] // not optional
}

// Record.fetchAll
do {
let records = try Record.fetchAll(db, request)
XCTAssertEqual(records, [
Record(
d: D(row: ["cold1": 10, "cold2": 7, "cold3": "d1"]),
bs: [
B(row: ["colb1": 4, "colb2": 1, "colb3": "b1"]),
B(row: ["colb1": 5, "colb2": 1, "colb3": "b2"]),
]),
Record(
d: D(row: ["cold1": 11, "cold2": 8, "cold3": "d2"]),
bs: [
B(row: ["colb1": 6, "colb2": 2, "colb3": "b3"]),
]),
Record(
d: D(row: ["cold1": 12, "cold2": 8, "cold3": "d3"]),
bs: [
B(row: ["colb1": 6, "colb2": 2, "colb3": "b3"]),
]),
Record(
d: D(row: ["cold1": 13, "cold2": 9, "cold3": "d4"]),
bs: [
B(row: ["colb1": 6, "colb2": 2, "colb3": "b3"]),
]),
Record(
d: D(row: ["cold1": 14, "cold2": nil, "cold3": "d5"]),
bs: []),
])
}

// Record.fetchOne
do {
let record = try Record.fetchOne(db, request)!
XCTAssertEqual(record, Record(
d: D(row: ["cold1": 10, "cold2": 7, "cold3": "d1"]),
bs: [
B(row: ["colb1": 4, "colb2": 1, "colb3": "b1"]),
B(row: ["colb1": 5, "colb2": 1, "colb3": "b2"]),
]))
}
}
}
}
}

func testSelfJoin() throws {
struct Employee: TableRecord, FetchableRecord, Decodable, Hashable {
static let subordinates = hasMany(Employee.self, key: "subordinates")
Expand Down
80 changes: 78 additions & 2 deletions Tests/GRDBTests/AssociationPrefetchingFetchableRecordTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ private struct C: TableRecord, FetchableRecord, Equatable {
}
private struct D: TableRecord, FetchableRecord, Equatable {
var cold1: Int64
var cold2: Int64
var cold2: Int64?
var cold3: String

init(row: Row) {
Expand Down Expand Up @@ -83,6 +83,7 @@ class AssociationPrefetchingFetchableRecordTests: GRDBTestCase {
INSERT INTO d (cold1, cold2, cold3) VALUES (?, ?, ?);
INSERT INTO d (cold1, cold2, cold3) VALUES (?, ?, ?);
INSERT INTO d (cold1, cold2, cold3) VALUES (?, ?, ?);
INSERT INTO d (cold1, cold2, cold3) VALUES (?, ?, ?);
""",
arguments: [
1, "a1",
Expand All @@ -99,6 +100,7 @@ class AssociationPrefetchingFetchableRecordTests: GRDBTestCase {
11, 8, "d2",
12, 8, "d3",
13, 9, "d4",
14, nil, "d5",
])
}
}
Expand Down Expand Up @@ -973,7 +975,6 @@ class AssociationPrefetchingFetchableRecordTests: GRDBTestCase {
}
}

// TODO: make a variant with joining(optional:)
func testIncludingOptionalBelongsToIncludingAllHasMany() throws {
let dbQueue = try makeDatabaseQueue()
try dbQueue.write { db in
Expand Down Expand Up @@ -1243,4 +1244,79 @@ class AssociationPrefetchingFetchableRecordTests: GRDBTestCase {
}
}
}

func testJoiningOptionalHasOneThroughIncludingAllHasMany() throws {
let dbQueue = try makeDatabaseQueue()
try dbQueue.write { db in
// Plain request
do {
let request = D
.joining(optional: D
.hasOne(A.self, through: D.belongsTo(C.self), using: C.belongsTo(A.self))
.including(all: A
.hasMany(B.self)
.orderByPrimaryKey()))
.orderByPrimaryKey()

// Record (flat)
do {
struct Record: FetchableRecord, Equatable {
var d: D
var bs: [B] // not optional

init(d: D, bs: [B]) {
self.d = d
self.bs = bs
}

init(row: Row) {
self.init(d: D(row: row), bs: row["bs"])
}
}

// Record.fetchAll
do {
let records = try Record.fetchAll(db, request)
XCTAssertEqual(records, [
Record(
d: D(row: ["cold1": 10, "cold2": 7, "cold3": "d1"]),
bs: [
B(row: ["colb1": 4, "colb2": 1, "colb3": "b1"]),
B(row: ["colb1": 5, "colb2": 1, "colb3": "b2"]),
]),
Record(
d: D(row: ["cold1": 11, "cold2": 8, "cold3": "d2"]),
bs: [
B(row: ["colb1": 6, "colb2": 2, "colb3": "b3"]),
]),
Record(
d: D(row: ["cold1": 12, "cold2": 8, "cold3": "d3"]),
bs: [
B(row: ["colb1": 6, "colb2": 2, "colb3": "b3"]),
]),
Record(
d: D(row: ["cold1": 13, "cold2": 9, "cold3": "d4"]),
bs: [
B(row: ["colb1": 6, "colb2": 2, "colb3": "b3"]),
]),
Record(
d: D(row: ["cold1": 14, "cold2": nil, "cold3": "d5"]),
bs: []),
])
}

// Record.fetchOne
do {
let record = try Record.fetchOne(db, request)!
XCTAssertEqual(record, Record(
d: D(row: ["cold1": 10, "cold2": 7, "cold3": "d1"]),
bs: [
B(row: ["colb1": 4, "colb2": 1, "colb3": "b1"]),
B(row: ["colb1": 5, "colb2": 1, "colb3": "b2"]),
]))
}
}
}
}
}
}
22 changes: 21 additions & 1 deletion Tests/GRDBTests/AssociationPrefetchingObservationTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,6 @@ class AssociationPrefetchingObservationTests: GRDBTestCase {
}
}

// TODO: make a variant with joining(optional:)
func testIncludingOptionalBelongsToIncludingAllHasMany() throws {
let dbQueue = try makeDatabaseQueue()
try dbQueue.write { db in
Expand Down Expand Up @@ -287,4 +286,25 @@ class AssociationPrefetchingObservationTests: GRDBTestCase {
}
}
}

func testJoiningOptionalHasOneThroughIncludingAllHasMany() throws {
let dbQueue = try makeDatabaseQueue()
try dbQueue.write { db in
// Plain request
do {
let request = D
.joining(optional: D
.hasOne(A.self, through: D.belongsTo(C.self), using: C.belongsTo(A.self))
.including(all: A
.hasMany(B.self)
.orderByPrimaryKey()))
.orderByPrimaryKey()

try XCTAssert([
"a(*),b(colb1,colb2,colb3),c(colc1,colc2),d(cold1,cold2,cold3)", // iOS 12
"a(cola1),b(colb1,colb2,colb3),c(colc1,colc2),d(cold1,cold2,cold3)", // iOS 9
].contains(request.databaseRegion(db).description))
}
}
}
}
73 changes: 72 additions & 1 deletion Tests/GRDBTests/AssociationPrefetchingRowTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ class AssociationPrefetchingRowTests: GRDBTestCase {
INSERT INTO d (cold1, cold2, cold3) VALUES (?, ?, ?);
INSERT INTO d (cold1, cold2, cold3) VALUES (?, ?, ?);
INSERT INTO d (cold1, cold2, cold3) VALUES (?, ?, ?);
INSERT INTO d (cold1, cold2, cold3) VALUES (?, ?, ?);
""",
arguments: [
1, "a1",
Expand All @@ -63,6 +64,7 @@ class AssociationPrefetchingRowTests: GRDBTestCase {
11, 8, "d2",
12, 8, "d3",
13, 9, "d4",
14, nil, "d5",
])
}
}
Expand Down Expand Up @@ -779,7 +781,6 @@ class AssociationPrefetchingRowTests: GRDBTestCase {
}
}

// TODO: make a variant with joining(optional:)
func testIncludingOptionalBelongsToIncludingAllHasMany() throws {
let dbQueue = try makeDatabaseQueue()
try dbQueue.write { db in
Expand Down Expand Up @@ -991,6 +992,76 @@ class AssociationPrefetchingRowTests: GRDBTestCase {
}
}

func testJoiningOptionalHasOneThroughIncludingAllHasMany() throws {
let dbQueue = try makeDatabaseQueue()
try dbQueue.write { db in
// Plain request
do {
let request = D
.joining(optional: D
.hasOne(A.self, through: D.belongsTo(C.self), using: C.belongsTo(A.self))
.including(all: A
.hasMany(B.self)
.orderByPrimaryKey()))
.orderByPrimaryKey()

// Row.fetchAll
do {
let rows = try Row.fetchAll(db, request)
XCTAssertEqual(rows.count, 5)

XCTAssertEqual(rows[0].description, "[cold1:10 cold2:7 cold3:\"d1\"]")
XCTAssertEqual(rows[0].debugDescription, """
▿ [cold1:10 cold2:7 cold3:"d1"]
+ bs: 2 rows
""")

XCTAssertEqual(rows[0].unscoped, ["cold1": 10, "cold2": 7, "cold3": "d1"])
XCTAssertEqual(rows[0].prefetchedRows.keys, ["bs"])
XCTAssertEqual(rows[0].prefetchedRows["bs"]!.count, 2)
XCTAssertEqual(rows[0].prefetchedRows["bs"]![0], ["colb1": 4, "colb2": 1, "colb3": "b1", "grdb_colc1": 7])
XCTAssertEqual(rows[0].prefetchedRows["bs"]![1], ["colb1": 5, "colb2": 1, "colb3": "b2", "grdb_colc1": 7])
XCTAssertEqual(rows[0].scopes.count, 0)

XCTAssertEqual(rows[1].unscoped, ["cold1": 11, "cold2": 8, "cold3": "d2"])
XCTAssertEqual(rows[1].prefetchedRows.keys, ["bs"])
XCTAssertEqual(rows[1].prefetchedRows["bs"]!.count, 1)
XCTAssertEqual(rows[1].prefetchedRows["bs"]![0], ["colb1": 6, "colb2": 2, "colb3": "b3", "grdb_colc1": 8])
XCTAssertEqual(rows[1].scopes.count, 0)

XCTAssertEqual(rows[2].unscoped, ["cold1": 12, "cold2": 8, "cold3": "d3"])
XCTAssertEqual(rows[2].prefetchedRows.keys, ["bs"])
XCTAssertEqual(rows[2].prefetchedRows["bs"]!.count, 1)
XCTAssertEqual(rows[2].prefetchedRows["bs"]![0], ["colb1": 6, "colb2": 2, "colb3": "b3", "grdb_colc1": 8])
XCTAssertEqual(rows[2].scopes.count, 0)

XCTAssertEqual(rows[3].unscoped, ["cold1": 13, "cold2": 9, "cold3": "d4"])
XCTAssertEqual(rows[3].prefetchedRows.keys, ["bs"])
XCTAssertEqual(rows[3].prefetchedRows["bs"]!.count, 1)
XCTAssertEqual(rows[3].prefetchedRows["bs"]![0], ["colb1": 6, "colb2": 2, "colb3": "b3", "grdb_colc1": 9])
XCTAssertEqual(rows[3].scopes.count, 0)

XCTAssertEqual(rows[4].unscoped, ["cold1": 14, "cold2": nil, "cold3": "d5"])
XCTAssertEqual(rows[4].prefetchedRows.keys, ["bs"])
XCTAssertEqual(rows[4].prefetchedRows["bs"]!.count, 0)
XCTAssertEqual(rows[4].scopes.count, 0)
}

// Row.fetchOne
do {
let row = try Row.fetchOne(db, request)!

XCTAssertEqual(row.unscoped, ["cold1": 10, "cold2": 7, "cold3": "d1"])
XCTAssertEqual(row.prefetchedRows.keys, ["bs"])
XCTAssertEqual(row.prefetchedRows["bs"]!.count, 2)
XCTAssertEqual(row.prefetchedRows["bs"]![0], ["colb1": 4, "colb2": 1, "colb3": "b1", "grdb_colc1": 7])
XCTAssertEqual(row.prefetchedRows["bs"]![1], ["colb1": 5, "colb2": 1, "colb3": "b2", "grdb_colc1": 7])
XCTAssertEqual(row.scopes.count, 0)
}
}
}
}

func testEquatable() throws {
let dbQueue = try makeDatabaseQueue()
try dbQueue.read { db in
Expand Down
Loading

0 comments on commit 7defc8e

Please sign in to comment.