174 lines
6.7 KiB
Swift
174 lines
6.7 KiB
Swift
import XCTest
|
|
import GRDB
|
|
|
|
private struct Team: Codable, FetchableRecord, PersistableRecord {
|
|
static let databaseTableName = "teams"
|
|
var id: Int64
|
|
var name: String
|
|
}
|
|
|
|
private struct Player: Codable, FetchableRecord, PersistableRecord {
|
|
static let databaseTableName = "players"
|
|
static let team = Player.belongsTo(Team.self)
|
|
var id: Int64
|
|
var teamId: Int64?
|
|
var name: String
|
|
}
|
|
|
|
private struct PlayerWithRequiredTeam: Decodable, FetchableRecord {
|
|
var player: Player
|
|
var team: Team
|
|
static let team = Player.team.forKey(CodingKeys.team)
|
|
}
|
|
|
|
private struct PlayerWithOptionalTeam: Decodable, FetchableRecord {
|
|
var player: Player
|
|
var team: Team?
|
|
static let team = Player.team.forKey(CodingKeys.team)
|
|
}
|
|
|
|
private struct PlayerWithTeamName: Decodable, FetchableRecord {
|
|
var player: Player
|
|
var teamName: String?
|
|
}
|
|
|
|
private extension QueryInterfaceRequest<Player> {
|
|
func filter(teamName: String) -> QueryInterfaceRequest<Player> {
|
|
joining(required: PlayerWithOptionalTeam.team.filter(Column("name") == teamName))
|
|
}
|
|
|
|
func orderedByTeamName() -> QueryInterfaceRequest<Player> {
|
|
let teamAlias = TableAlias()
|
|
return joining(optional: PlayerWithOptionalTeam.team.aliased(teamAlias))
|
|
.order(teamAlias[Column("name")], Column("name"))
|
|
}
|
|
}
|
|
|
|
/// Test support for Decodable records
|
|
class AssociationBelongsToDecodableRecordTests: GRDBTestCase {
|
|
|
|
override func setup(_ dbWriter: some DatabaseWriter) throws {
|
|
try dbWriter.write { db in
|
|
try db.create(table: "teams") { t in
|
|
t.primaryKey("id", .integer)
|
|
t.column("name", .text)
|
|
}
|
|
try db.create(table: "players") { t in
|
|
t.primaryKey("id", .integer)
|
|
t.belongsTo("team")
|
|
t.column("name", .text)
|
|
}
|
|
|
|
try Team(id: 1, name: "Reds").insert(db)
|
|
try Player(id: 1, teamId: 1, name: "Arthur").insert(db)
|
|
try Player(id: 2, teamId: nil, name: "Barbara").insert(db)
|
|
}
|
|
}
|
|
|
|
func testIncludingRequired() throws {
|
|
let dbQueue = try makeDatabaseQueue()
|
|
let request = Player
|
|
.including(required: PlayerWithRequiredTeam.team)
|
|
.asRequest(of: PlayerWithRequiredTeam.self)
|
|
let records = try dbQueue.inDatabase { try request.fetchAll($0) }
|
|
XCTAssertEqual(records.count, 1)
|
|
XCTAssertEqual(records[0].player.id, 1)
|
|
XCTAssertEqual(records[0].player.teamId, 1)
|
|
XCTAssertEqual(records[0].player.name, "Arthur")
|
|
XCTAssertEqual(records[0].team.id, 1)
|
|
XCTAssertEqual(records[0].team.name, "Reds")
|
|
}
|
|
|
|
func testAnnotatedWithRequired() throws {
|
|
let dbQueue = try makeDatabaseQueue()
|
|
let request = Player
|
|
.annotated(withRequired: Player.team.select(Column("name").forKey("teamName")))
|
|
.asRequest(of: PlayerWithTeamName.self)
|
|
let records = try dbQueue.inDatabase { try request.fetchAll($0) }
|
|
XCTAssertEqual(records.count, 1)
|
|
XCTAssertEqual(records[0].player.id, 1)
|
|
XCTAssertEqual(records[0].player.teamId, 1)
|
|
XCTAssertEqual(records[0].player.name, "Arthur")
|
|
XCTAssertEqual(records[0].teamName, "Reds")
|
|
}
|
|
|
|
func testIncludingOptional() throws {
|
|
let dbQueue = try makeDatabaseQueue()
|
|
let request = Player
|
|
.including(optional: PlayerWithOptionalTeam.team)
|
|
.asRequest(of: PlayerWithOptionalTeam.self)
|
|
let records = try dbQueue.inDatabase { try request.fetchAll($0) }
|
|
XCTAssertEqual(records.count, 2)
|
|
XCTAssertEqual(records[0].player.id, 1)
|
|
XCTAssertEqual(records[0].player.teamId, 1)
|
|
XCTAssertEqual(records[0].player.name, "Arthur")
|
|
XCTAssertEqual(records[0].team!.id, 1)
|
|
XCTAssertEqual(records[0].team!.name, "Reds")
|
|
XCTAssertEqual(records[1].player.id, 2)
|
|
XCTAssertNil(records[1].player.teamId)
|
|
XCTAssertEqual(records[1].player.name, "Barbara")
|
|
XCTAssertNil(records[1].team)
|
|
}
|
|
|
|
func testAnnotatedWithOptional() throws {
|
|
let dbQueue = try makeDatabaseQueue()
|
|
let request = Player
|
|
.annotated(withOptional: Player.team.select(Column("name").forKey("teamName")))
|
|
.asRequest(of: PlayerWithTeamName.self)
|
|
let records = try dbQueue.inDatabase { try request.fetchAll($0) }
|
|
XCTAssertEqual(records.count, 2)
|
|
XCTAssertEqual(records[0].player.id, 1)
|
|
XCTAssertEqual(records[0].player.teamId, 1)
|
|
XCTAssertEqual(records[0].player.name, "Arthur")
|
|
XCTAssertEqual(records[0].teamName, "Reds")
|
|
XCTAssertEqual(records[1].player.id, 2)
|
|
XCTAssertEqual(records[1].player.name, "Barbara")
|
|
XCTAssertNil(records[1].teamName)
|
|
}
|
|
|
|
func testJoiningRequired() throws {
|
|
let dbQueue = try makeDatabaseQueue()
|
|
let request = Player.joining(required: Player.team)
|
|
let players = try dbQueue.inDatabase { try request.fetchAll($0) }
|
|
XCTAssertEqual(players.count, 1)
|
|
XCTAssertEqual(players[0].id, 1)
|
|
XCTAssertEqual(players[0].teamId, 1)
|
|
XCTAssertEqual(players[0].name, "Arthur")
|
|
}
|
|
|
|
func testJoiningsOptional() throws {
|
|
let dbQueue = try makeDatabaseQueue()
|
|
let request = Player.joining(optional: Player.team)
|
|
let players = try dbQueue.inDatabase { try request.fetchAll($0) }
|
|
XCTAssertEqual(players.count, 2)
|
|
XCTAssertEqual(players[0].id, 1)
|
|
XCTAssertEqual(players[0].teamId, 1)
|
|
XCTAssertEqual(players[0].name, "Arthur")
|
|
XCTAssertEqual(players[1].id, 2)
|
|
XCTAssertNil(players[1].teamId)
|
|
XCTAssertEqual(players[1].name, "Barbara")
|
|
}
|
|
|
|
func testRequestRefining() throws {
|
|
let dbQueue = try makeDatabaseQueue()
|
|
let request = Player
|
|
.including(required: PlayerWithRequiredTeam.team.select(Column("name"), Column("id")))
|
|
.filter(teamName: "Reds")
|
|
.orderedByTeamName()
|
|
.asRequest(of: PlayerWithRequiredTeam.self)
|
|
let records = try dbQueue.inDatabase { try request.fetchAll($0) }
|
|
XCTAssertEqual(lastSQLQuery, """
|
|
SELECT "players".*, "teams"."name", "teams"."id" \
|
|
FROM "players" \
|
|
JOIN "teams" ON ("teams"."id" = "players"."teamId") AND ("teams"."name" = 'Reds') \
|
|
ORDER BY "teams"."name", "players"."name"
|
|
""")
|
|
XCTAssertEqual(records.count, 1)
|
|
XCTAssertEqual(records[0].player.id, 1)
|
|
XCTAssertEqual(records[0].player.teamId, 1)
|
|
XCTAssertEqual(records[0].player.name, "Arthur")
|
|
XCTAssertEqual(records[0].team.id, 1)
|
|
XCTAssertEqual(records[0].team.name, "Reds")
|
|
}
|
|
}
|