GRDB.swift v1.2.0 Release Notes
-
๐ Released July 13, 2017 • diff
๐ New
๐ Record types that do not provide values for all table columns in their
encode(to:)
method are now supported.The table creation API has been enhanced:
SQLite supports untyped columns:
try dbQueue.inDatabase { db in // CREATE TABLE t(a, b) try db.create(table: "t") { t in t.column("a") t.column("b") } }
Untyped columns behave like decimal, boolean, date columns, and generally all columns with NUMERIC type affinity.
This feature addresses #169.
The
indexed()
methods lets you create a non-unique index on a table column:try dbQueue.inDatabase { db in // CREATE TABLE rounds(score INTEGER) // CREATE INDEX rounds_on_score ON rounds(score) try db.create(table: "rounds") { t in t.column("score", .integer).indexed() } }
It is now possible to define references to tables without any explicit primary key. The generated SQL then uses the
rowid
hidden primary key column:try dbQueue.inDatabase { db in // CREATE TABLE nodes( // name TEXT, // parentId INTEGER REFERENCES nodes(rowid) // ) try db.create(table: "nodes") { t in t.column("name", .text) t.column("parentId", .integer).references("nodes") } }
๐
DatabaseQueue
,DatabasePool
and their common protocolDatabaseReader
can now perform "unsafe reentrant reads" (documentation):try dbPool.read { db in // This is allowed try dbPool.unsafeReentrantRead { db in ... } }
๐ Fixed
DatabasePool.read
, andDatabasePool.unsafeRead
now raise a fatal error when used in a reentrant way:try dbPool.read { db in // fatal error: "Database methods are not reentrant." try dbPool.read { db in ... } }
While this change may appear as a breaking change, it is really a fix: reentrant reads deadlock as soon as the maximum number of readers has been reached.
API diff
final class ColumnDefinition { + @discardableResult func indexed() -> Self } final class TableDefinition { - func column(_ name: String, _ type: Database.ColumnType) -> ColumnDefinition + func column(_ name: String, _ type: Database.ColumnType? = nil) -> ColumnDefinition } protocol DatabaseReader { + func unsafeReentrantRead<T>(_ block: (Database) throws -> T) throws -> T }