try dbQueue.read { db in let rows = try Row.fetchCursor(db, sql: "SELECT * FROM player") while let row = try rows.next() { let id: Int64 = row["id"] let name: String = row["name"] let score: Int = row["score"] print("\(name): \(score)") }}
try dbQueue.read { db in let rows = try Row.fetchAll(db, sql: "SELECT * FROM player") for row in rows { let name: String = row["name"] print(name) }}
try dbQueue.read { db in if let row = try Row.fetchOne(db, sql: "SELECT * FROM player WHERE id = ?", arguments: [1]) { let name: String = row["name"] print(name) }}
let row = try Row.fetchOne(db, sql: "SELECT id, name, score FROM player")!// By index (0 is leftmost column)let id: Int64 = row[0]// By column name (case-insensitive)let name: String = row["name"]let score: Int = row["score"]// Optional valueslet email: String? = row["email"] // nil if column is NULL
struct Player: FetchableRecord { let id: Int64 let name: String let score: Int init(row: Row) { id = row["id"] name = row["name"] score = row["score"] }}try dbQueue.read { db in // Fetch all players let players = try Player.fetchAll(db, sql: "SELECT * FROM player") // Fetch one player let player = try Player.fetchOne(db, sql: "SELECT * FROM player WHERE id = ?", arguments: [1])}
struct Player: Codable, FetchableRecord { let id: Int64 let name: String let score: Int}try dbQueue.read { db in let players = try Player.fetchAll(db, sql: "SELECT * FROM player")}
❌ Cannot be extracted from database access methods
try dbQueue.read { db in let cursor = try Player.fetchCursor(db, sql: "SELECT * FROM player") // Iterate once while let player = try cursor.next() { print(player.name) } // Can't iterate again - cursor is exhausted}
try dbQueue.read { db in let cursor = try String.fetchCursor(db, sql: "SELECT name FROM player") // To array let array = try Array(cursor) // To set let set = try Set(cursor) // To dictionary let cursor = try Player.fetchCursor(db, sql: "SELECT * FROM player") let dict = try Dictionary(grouping: cursor, by: { $0.team })}
try dbQueue.read { db in let players = try Player.fetchAll(db, sql: "SELECT * FROM player WHERE name = :name AND score > :score", arguments: ["name": "Arthur", "score": 1000])}
try dbQueue.read { db in let name = "Arthur" let minScore = 1000 let players = try Player.fetchAll(db, literal: """ SELECT * FROM player WHERE name = \(name) AND score > \(minScore) """)}
try dbQueue.read { db in let count = try Int.fetchOne(db, sql: "SELECT COUNT(*) FROM player")! let avgScore = try Double.fetchOne(db, sql: "SELECT AVG(score) FROM player") let maxScore = try Int.fetchOne(db, sql: "SELECT MAX(score) FROM player")}
struct TeamStats: FetchableRecord { let team: String let playerCount: Int let totalScore: Int init(row: Row) { team = row["team"] playerCount = row["playerCount"] totalScore = row["totalScore"] }}try dbQueue.read { db in let stats = try TeamStats.fetchAll(db, sql: """ SELECT team, COUNT(*) as playerCount, SUM(score) as totalScore FROM player GROUP BY team """)}
struct PlayerWithTeam: FetchableRecord { let playerName: String let teamName: String let score: Int init(row: Row) { playerName = row["playerName"] teamName = row["teamName"] score = row["score"] }}try dbQueue.read { db in let results = try PlayerWithTeam.fetchAll(db, sql: """ SELECT p.name as playerName, t.name as teamName, p.score FROM player p INNER JOIN team t ON p.teamId = t.id """)}
try dbQueue.read { db in let topPlayers = try Player.fetchAll(db, sql: """ SELECT * FROM player WHERE score > ( SELECT AVG(score) FROM player ) ORDER BY score DESC """)}
For type-safe queries without SQL, use the Query Interface:
struct Player: Codable, FetchableRecord, TableRecord { var id: Int64 var name: String var score: Int enum Columns { static let name = Column(CodingKeys.name) static let score = Column(CodingKeys.score) }}try dbQueue.read { db in // Find by primary key let player = try Player.fetchOne(db, id: 1) // Filter and order let topPlayers = try Player .filter(Player.Columns.score > 1000) .order(Player.Columns.score.desc) .limit(10) .fetchAll(db) // Count let count = try Player .filter(Player.Columns.score > 500) .fetchCount(db)}
For large result sets, prefer cursors over arrays:
try dbQueue.read { db in let cursor = try Player.fetchCursor(db, sql: "SELECT * FROM player") while let player = try cursor.next() { // Process one at a time }}
Always limit results when you don’t need all rows:
try dbQueue.read { db in let recentPlayers = try Player.fetchAll(db, sql: """ SELECT * FROM player ORDER BY created_at DESC LIMIT 100 """)}
Ensure frequently queried columns have indexes:
try dbQueue.write { db in try db.execute(sql: """ CREATE INDEX idx_player_score ON player(score) """)}
Reuse prepared statements for repeated queries:
try dbQueue.read { db in let statement = try db.makeStatement( sql: "SELECT * FROM player WHERE id = ?") for id in [1, 2, 3] { let player = try Player.fetchOne(statement, arguments: [id]) }}