Skip to content

Commit eb2378a

Browse files
committed
DatabaseSchemaSource documentation
1 parent 37dde39 commit eb2378a

File tree

1 file changed

+74
-17
lines changed

1 file changed

+74
-17
lines changed

GRDB/Core/DatabaseSchemaSource.swift

Lines changed: 74 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,42 @@
66
///
77
/// The use case for a custom schema source is enabling GRDB features that
88
/// would not work with the built-in schema introspection that is provided
9-
/// by SQLite. For example, a custom schema source can help record types
10-
/// that read or write in a database view.
9+
/// by SQLite.
1110
///
12-
/// You do not interact directly with values of such a type. Instead, you
13-
/// configure a database connection with ``Configuration/schemaSource``, and
14-
/// you call <doc:DatabaseSchemaIntrospection> methods on a
15-
/// ``Database`` connection.
11+
/// For example, if your database schema contains a view and you wish to use
12+
/// GRDB features that need a primary key, such as the
13+
/// ``FetchableRecord/find(_:id:)`` record method, or the persistence
14+
/// methods of the ``PersistableRecord`` protocol, then use a schema source
15+
/// that implements the ``columnsForPrimaryKey(_:inView:)`` method.
16+
///
17+
/// ## Enabling a Schema Source
18+
///
19+
/// To enable a schema source in a database connection, configure its
20+
/// ``Configuration/schemaSource``:
21+
///
22+
/// ```swift
23+
/// struct MySchemaSource: DatabaseSchemaSource { ... }
24+
///
25+
/// var config = Configuration()
26+
/// config.schemaSource = MySchemaSource()
27+
/// let dbQueue = try DatabaseQueue(path: "/path/to/db.sqlite", configuration: config)
28+
/// ```
29+
///
30+
/// For temporary use, call ``Database/withSchemaSource(_:execute:)``:
31+
///
32+
/// ```swift
33+
/// try dbQueue.read { db in
34+
/// try db.withSchemaSource(MySchemaSource()) {
35+
/// ...
36+
/// }
37+
/// }
38+
/// ```
39+
///
40+
/// ## Topics
41+
///
42+
/// ### Customizing the Database Schema
43+
///
44+
/// - ``columnsForPrimaryKey(_:inView:)``
1645
public protocol DatabaseSchemaSource: Sendable {
1746
/// Returns the names of the columns for the primary key in the
1847
/// provided database view.
@@ -30,18 +59,46 @@ public protocol DatabaseSchemaSource: Sendable {
3059
/// For example:
3160
///
3261
/// ```swift
62+
/// // A schema source that specifies that views have an "id" primary key.
3363
/// struct MySchemaSource: DatabaseSchemaSource {
34-
/// func columnsForPrimaryKey(
35-
/// _ db: Database,
36-
/// inView view: DatabaseObjectID
37-
/// ) throws -> [String]? {
38-
/// switch table.name {
39-
/// case "player":
40-
/// // Use the email column as the primary key of this view.
41-
/// return ["email"]
42-
///
43-
/// default:
44-
/// // Do not customize.
64+
/// func columnsForPrimaryKey(_ db: Database, inView view: DatabaseObjectID) {
65+
/// ["id"]
66+
/// }
67+
/// }
68+
///
69+
/// // A database connection configured with the schema source.
70+
/// var config = Configuration()
71+
/// config.schemaSource = MySchemaSource()
72+
/// let dbQueue = try DatabaseQueue(path: "/path/to/db.sqlite", configuration: config)
73+
///
74+
/// // A record type that feeds from a view.
75+
/// struct Player: Decodable, Identifiable, FetchableRecord {
76+
/// static let databaseTableName = "playerView"
77+
/// var id: String
78+
/// var name: String
79+
/// }
80+
///
81+
/// // Thanks to the schema source, we can fetch players by id:
82+
/// let player = try dbQueue.read { db in
83+
/// try Player.find(db, id: "alice")
84+
/// }
85+
/// ```
86+
///
87+
/// When you are developing a library that accesses database files owned
88+
/// by the users of your library, then you you should allow the host
89+
/// application to deal with their own views. To do so, return nil for
90+
/// views that your library does not manage. When necessary, use the
91+
/// `db` argument in order to query the database schema.
92+
///
93+
/// ```swift
94+
/// struct MyLbrarySchemaSource: DatabaseSchemaSource {
95+
/// func columnsForPrimaryKey(_ db: Database, inView view: DatabaseObjectID) {
96+
/// if view.name == "playerView" {
97+
/// // This is a view managed by my library:
98+
/// return ["id"]
99+
/// } else {
100+
/// // Not a view managed by my library:
101+
/// // don't mess with user's schema
45102
/// return nil
46103
/// }
47104
/// }

0 commit comments

Comments
 (0)