Skip to content

Commit 37dde39

Browse files
committed
Public Database.schemaSource and withSchemaSource(_:execute:)
1 parent 5786391 commit 37dde39

File tree

4 files changed

+48
-8
lines changed

4 files changed

+48
-8
lines changed

GRDB/Core/Configuration.swift

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -430,9 +430,11 @@ public struct Configuration: Sendable {
430430
/// by SQLite. For example, a custom schema source can help record types
431431
/// that read or write in a database view.
432432
///
433-
/// The schema source has not effect during database migrations
434-
/// performed by ``DatabaseMigrator``. Those access the raw SQLite
435-
/// schema, unaltered.
433+
/// The schema source is automatically disabled during database
434+
/// migrations performed by ``DatabaseMigrator``: those access the raw
435+
/// SQLite schema, unaltered. If a migration needs a schema source,
436+
/// you may call ``Database/withSchemaSource(_:execute:)`` from within
437+
/// the body of a migration.
436438
public var schemaSource: (any DatabaseSchemaSource)?
437439

438440
// MARK: - Factory Configuration

GRDB/Core/Database+Schema.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ extension Database {
3535

3636
// MARK: - Database Schema
3737

38-
/// Runs the provided closure with the provided schema source.
39-
func withSchemaSource<T>(
38+
/// Executes the wrapped statements with the provided schema source.
39+
public func withSchemaSource<T>(
4040
_ schemaSource: (any DatabaseSchemaSource)?,
4141
execute block: () throws -> T
4242
) rethrows -> T {

GRDB/Core/Database.swift

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,11 @@ let SQLITE_TRANSIENT = unsafeBitCast(OpaquePointer(bitPattern: -1), to: sqlite3_
113113
/// - ``resumeNotification``
114114
/// - ``suspendNotification``
115115
///
116+
/// ### The Schema Source
117+
///
118+
/// - ``schemaSource``
119+
/// - ``withSchemaSource(_:execute:)``
120+
///
116121
/// ### Other Database Operations
117122
///
118123
/// - ``add(tokenizer:)``
@@ -187,6 +192,19 @@ public final class Database: CustomStringConvertible, CustomDebugStringConvertib
187192
/// The database configuration.
188193
public let configuration: Configuration
189194

195+
/// The current schema source.
196+
///
197+
/// By default, it is the ``Configuration/schemaSource``
198+
/// of ``configuration``. To modify the schema source,
199+
/// use ``withSchemaSource(_:execute:)``.
200+
///
201+
/// The schema source is automatically disabled (nil) during database
202+
/// migrations performed by ``DatabaseMigrator``: those access the raw
203+
/// SQLite schema, unaltered. If a migration needs a schema source,
204+
/// you may call ``Database/withSchemaSource(_:execute:)`` from within
205+
/// the body of a migration.
206+
public internal(set) var schemaSource: (any DatabaseSchemaSource)?
207+
190208
/// A description of this database connection.
191209
///
192210
/// The returned string is based on the ``Configuration/label``
@@ -276,9 +294,6 @@ public final class Database: CustomStringConvertible, CustomDebugStringConvertib
276294
/// The cache for the available database schemas (main, temp, attached databases).
277295
var schemaCache = SchemaCache()
278296

279-
/// To modify the schemaSource, use `withSchemaSource`.
280-
var schemaSource: (any DatabaseSchemaSource)?
281-
282297
/// The cache for statements managed by GRDB. It is distinct from
283298
/// `publicStatementCache` so that we do not mess with statement arguments
284299
/// set by the user.

Tests/GRDBTests/DatabaseMigratorTests.swift

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1125,22 +1125,45 @@ class DatabaseMigratorTests : GRDBTestCase {
11251125
migrator.registerMigration("A") { db in
11261126
try db.execute(sql: "CREATE VIEW myView as SELECT 1 AS id")
11271127
// Cache is empty, and schemaSource is disabled.
1128+
XCTAssertNil(db.schemaSource)
11281129
XCTAssertThrowsError(try db.primaryKey("myView"))
11291130
}
11301131
try migrator.migrate(dbQueue)
11311132
}
11321133

11331134
try dbQueue.inDatabase { db in
11341135
// Cache was cleared, and schemaSource is active.
1136+
XCTAssertNotNil(db.schemaSource)
11351137
XCTAssertNoThrow(try db.primaryKey("myView"))
11361138
}
11371139

11381140
do {
11391141
migrator.registerMigration("B") { db in
11401142
// Cache was cleared again, and schemaSource is disabled.
1143+
XCTAssertNil(db.schemaSource)
11411144
XCTAssertThrowsError(try db.primaryKey("myView"))
11421145
}
11431146
try migrator.migrate(dbQueue)
11441147
}
11451148
}
1149+
1150+
func test_schemaSource_can_be_restored_during_migrations() throws {
1151+
struct SchemaSource: DatabaseSchemaSource {
1152+
func columnsForPrimaryKey(_ db: Database, inView view: DatabaseObjectID) throws -> [String]? {
1153+
["id"]
1154+
}
1155+
}
1156+
1157+
dbConfiguration.schemaSource = SchemaSource()
1158+
let dbQueue = try makeDatabaseQueue()
1159+
var migrator = DatabaseMigrator()
1160+
1161+
migrator.registerMigration("A") { db in
1162+
try db.execute(sql: "CREATE VIEW myView as SELECT 1 AS id")
1163+
try db.withSchemaSource(SchemaSource()) {
1164+
XCTAssertNoThrow(try db.primaryKey("myView"))
1165+
}
1166+
}
1167+
try migrator.migrate(dbQueue)
1168+
}
11461169
}

0 commit comments

Comments
 (0)