Changelog History
Page 10
-
v3.2.0 Changes
๐ Released July 8, 2018 • diff
๐ New
- #381: Nuking db during development
๐ Documentation Diff
- ๐ [The
eraseDatabaseOnSchemaChange
Option](README.md#the-erasedatabaseonschemachange-option): See how a DatabaseMigrator can automatically recreate the whole database when a migration has changed its definition.
API diff
struct DatabaseMigrator { + var eraseDatabaseOnSchemaChange: Bool } extension DatabaseWriter { + func erase() throws + func vacuum() throws }
-
v3.0.0 Changes
๐ Released June 7, 2018 • diff
GRDB 3 is a release focused on modernization, safety, and associations between record types.
๐ It comes with new features, but also a few breaking changes, and a set of updated good practices. The [GRDB 2 Migration Guide](Documentation/GRDB2MigrationGuide.md) will help you upgrading your applications.
๐ New
- Associations and Joins (#319).
- โจ Enhancements to logical operators (#336).
- Foster auto-incremented primary keys (#337).
- ColumnExpression Protocol (#340).
- ๐ Improved parsing of dates and date components (#334 by @sobri909).
- Common API for requests and associations derivation (#347).
DatabaseMigrator.appliedMigrations(in:)
returns the set of applied migrations identifiers in a database (#321).Database.isSQLiteInternalTable(_:)
returns whether a table name is an internal SQLite table (#321).Database.isGRDBInternalTable(_:)
returns whether a table name is an internal GRDB table (#321).- โฌ๏ธ Upgrade custom SQLite builds to v3.23.0 (thanks to @swiftlyfalling).
- ๐ Improve Row descriptions (#331).
- Request derivation protocols (#329).
- ๐ง Preliminary Linux support for the main framework (#354).
- Automatic table name generation (#355).
- Delayed Request Ordering (#365).
๐ฅ Breaking Changes
- Swift 4.1 is now required.
- โ iOS 8 sunsetting: GRDB 3 is only tested on iOS 9+, due to a limitation in Xcode 9.3. Code that targets older versions of SQLite and iOS is still there, but is not supported.
- The Record protocols have been renamed:
RowConvertible
toFetchableRecord
,Persistable
toPersistableRecord
, andTableMapping
toTableRecord
(#314). - Implicit transaction in DatabasePool.write and DatabaseQueue.write (#332).
- ๐
Request
andTypedRequest
protocols have been merged intoFetchRequest
(#311, #328, #348). - Reversing unordered requests has no effect (#342).
- ๐ The
IteratorCursor
type has been removed. UseAnyCursor
instead (#312). - Row scopes collection, breadth-first scope search (#335).
- Expressions are no longer PATs (#330).
- ๐ Deprecated APIs have been removed.
๐ Documentation Diff
- ๐ [Associations](Documentation/AssociationsBasics.md): Discover the major GRDB 3 feature
- [Database Queues](README.md#database-queues): focus on the
read
andwrite
methods. - [Database Pools](README.md#database-pools): focus on the
read
andwrite
methods. - [Transactions and Savepoints](README.md#transactions-and-savepoints): the chapter has been rewritten in order to introduce transactions as a power-user feature.
- [ScopeAdapter](README.md#scopeadapter): do you use row adapters? If so, have a look.
- โก๏ธ [TableRecord Protocol](README.md#tablerecord-protocol): updated for the new automatic generation of database table name.
- [Examples of Record Definitions](README.md#examples-of-record-definitions): this new chapter provides a handy reference of the three main ways to define record types (Codable, plain struct, Record subclass).
- [SQL Operators](README.md#sql-operators): the chapter introduces the new
joined(operator:)
method that lets you join a chain of expressions withAND
orOR
without nesting:[cond1, cond2, ...].joined(operator: .and)
. - [Custom Requests](README.md#custom-requests): the old
Request
andTypedRequest
protocols have been replaced withFetchRequest
. If you want to know more about custom requests, check this chapter. - [Customized Decoding of Database Rows](README.md#customized-decoding-of-database-rows): learn how to escape the ready-made
FetchableRecord
protocol when it does not fit your needs. - โ [Migrations](README.md#migrations): learn how to check if a migration has been applied (very useful for migration tests).
-
v2.9.0 Changes
๐ Released February 25, 2018 • diff
๐ New
- ๐ Changes tracking overhaul: changes tracking, a feature previously restricted to the
Record
class and its subclasses, is now available for all records. And it has a better looking API (documentation). - Database snapshots: Database pools can now take database snapshots. A snapshot sees an unchanging database content, as it existed at the moment the snapshot was created (documentation).
- ๐ Improved support for joined queries: more than a set on new APIs, we provide a set of guidelines that will help you deal with your wildest joined queries. Check the new Joined Queries Support documentation chapter.
Database.columns(in:)
returns information about the columns of a table.Request.adapted(_:)
is no longer experimental.- ๐
Configuration.allowsUnsafeTransactions
lets you leave transactions opened between two database accesses (see below). - ๐ Support for explicit transaction management, via the new
Database.beginTransaction
,commit
, androllback
methods.
๐ Fixed
It is now a programmer error to leave a transaction opened at the end of a database access block:
// Fatal error: A transaction has been left opened at the end of a database access try dbQueue.inDatabase { db in try db.beginTransaction() }
One can still opt-in for the unsafe behavior by setting the new
allowsUnsafeTransactions
configuration flag:var config = Configuration() config.allowsUnsafeTransactions = true let dbQueue = DatabaseQueue(configuration: config) // OK try dbQueue.inDatabase { db in try db.beginTransaction() }
๐ Deprecated
- ๐
Database.columnCount(in:)
is deprecated. Usedb.columns(in:).count
instead. - ๐
RecordBox
, introduced in 2.7.0, was ill-advised. It has been deprecated. Use changes tracking methods on the Persistable protocol instead. - ๐
Record.hasPersistentChangedValues
has been deprecated, renamedhasDatabaseChanges
. - ๐
Record.persistentChangedValues
has been deprecated, renameddatabaseChanges
.
๐ Documentation Diff
- โก๏ธ The Changes Tracking chapter has been updated for the new universal support for record changes.
- A new Database Snapshots chapter has been added.
- โก๏ธ The Concurrency chapter has been updated for database snapshots.
- A new Differences between Database Queues and Pools chapter has been added, that attempts at visually show how much database pools are different from database queues.
- ๐ A new Joined Queries Support chapter has been added.
- The Row Adapters chapter has been made consistent with the new chapter on joined queries.
- The Codable Records chapter has been made consistent with the new chapter on joined queries.
- โก๏ธ The Database Schema Introspection has been updated for
Database.columns(in:)
API diff
+struct ColumnInfo { + let name: String + let type: String + let isNotNull: Bool + let defaultValueSQL: String? + let primaryKeyIndex: Int +} struct Configuration { + var allowsUnsafeTransactions: Bool } class Database { + @available(*, deprecated, message: "Use db.columns(in: tableName).count instead") func columnCount(in tableName: String) throws -> Int + func columns(in tableName: String) throws -> [ColumnInfo] + func beginTransaction(_ kind: TransactionKind? = nil) throws + func rollback() throws + func commit() throws } class DatabasePool { + func makeSnapshot() throws -> DatabaseSnapshot } +class DatabaseSnapshot: DatabaseReader { } extension MutablePersistable { + @discardableResult + func updateChanges(_ db: Database, from record: MutablePersistable) throws -> Bool + func databaseEqual(_ record: Self) -> Bool + func databaseChanges(from record: MutablePersistable) -> [String: DatabaseValue] } class Record { - final func updateChanges(_ db: Database) throws + @discardableResult + final func updateChanges(_ db: Database) throws -> Bool } +@available(*, deprecated, message: "Prefer changes methods defined on the MutablePersistable protocol: databaseEqual(_:), databaseChanges(from:), updateChanges(from:)") class RecordBox: Record { } class Row { + var unscoped: Row + var containsNonNullValue: Bool + func hasNull(atIndex index: Int) -> Bool + subscript<Record: RowConvertible>(_ scope: String) -> Record + subscript<Record: RowConvertible>(_ scope: String) -> Record? } extension TableMapping { + static func selectionSQL(alias: String? = nil) -> String + static func numberOfSelectedColumns(_ db: Database) throws -> Int } +struct EmptyRowAdapter: RowAdapter { } struct ScopeAdapter { + init(base: RowAdapter, scopes: [String: RowAdapter]) } +func splittingRowAdapters(columnCounts: [Int]) -> [RowAdapter]
- ๐ Changes tracking overhaul: changes tracking, a feature previously restricted to the
-
v2.8.0 Changes
๐ Released January 29, 2018 • diff
๐ New
- โฌ๏ธ Upgrade custom SQLite builds to v3.22.0 (thanks to @swiftlyfalling).
- The FTS5 full-text search engine has been enhanced with initial token queries, and FTS5Pattern has gained a new initializer:
FTS5Pattern(matchingPrefixPhrase:)
- The
Cursor
protocol is extended with more methods inspired by the standard Sequence protocol:drop(while:)
,dropFirst()
,dropFirst(_:)
,dropLast()
,dropLast(_:)
,joined(separator:)
,prefix(_:)
,max()
,max(by:)
,min()
,min(by:)
,prefix(while:)
,reduce(into:_:)
,suffix(_:)
,
-
v2.7.0 Changes
๐ Released January 21, 2018 • diff
๐ New
๐ The new RecordBox class brings changes tracking to any record type (documentation):
// A regular record struct struct Player: RowConvertible, MutablePersistable { ... } try dbQueue.inDatabase { db in // Fetch a boxed player if let boxedPlayer = try RecordBox<Player>.fetchOne(db, key: 1) { // boxedPlayer.value is Player boxedPlayer.value.score = 300 if boxedPlayer.hasPersistentChangedValues { print("player has been modified") } // Does nothing if player has not been modified: try boxedPlayer.updateChanges(db) } }
-
v2.6.1 Changes
๐ Released January 19, 2018 • diff
๐ Fixed
- ๐ Fixed a crash that could happen when a transaction observer uses the
stopObservingDatabaseChangesUntilNextTransaction()
method.
- ๐ Fixed a crash that could happen when a transaction observer uses the
-
v2.6.0 Changes
๐ Released January 18, 2018 • diff
๐ New
Database observation has been enhanced:
TransactionObserver.stopObservingDatabaseChangesUntilNextTransaction()
allows transaction observers to stop observing the database for the remaining extent of a transaction.- GRDB no longer prevents the truncate optimization when no transaction observers are interested in deleted rows.
- FetchedRecordsController now avoids checking for changes in untracked rowIds.
DatabaseRegion
is a new public type that helps transaction observers recognize impactful database changes. This type is not documented in the main documentation. For more information, see DatabaseRegion reference, and look at FetchedRecordsController implementation.TransactionObserver
protocol provides default implementations for rarely used callbacks.
Row
adopts RandomAccessCollection
API diff
extension TransactionObserver { + func stopObservingDatabaseChangesUntilNextTransaction() + + // Default implementation + func databaseWillCommit() throws + + #if SQLITE_ENABLE_PREUPDATE_HOOK + // Default implementation + func databaseWillChange(with event: DatabasePreUpdateEvent) + #endif } +struct DatabaseRegion: Equatable { + var isEmpty: Bool + + init() + + func union(_ other: DatabaseRegion) -> DatabaseRegion + mutating func formUnion(_ other: DatabaseRegion) + + func isModified(byEventsOfKind eventKind: DatabaseEventKind) -> Bool + func isModified(by event: DatabaseEvent) -> Bool +} class SelectStatement { + var fetchedRegion: DatabaseRegion + + @available(*, deprecated, renamed:"DatabaseRegion") + typealias SelectionInfo = DatabaseRegion + + @available(*, deprecated, renamed:"fetchedRegion") + var selectionInfo: DatabaseRegion } enum DatabaseEventKind { - func impacts(_ selectionInfo: SelectStatement.SelectionInfo) -> Bool + @available(*, deprecated, message: "Use DatabaseRegion.isModified(byEventsOfKind:) instead") + func impacts(_ region: DatabaseRegion) -> Bool } protocol Request { + // Default implementation + func fetchedRegion(_ db: Database) throws -> DatabaseRegion } +extension Row: RandomAccessCollection { +} +extension RowIndex: Strideable { }
-
v2.5.0 Changes
๐ Released January 11, 2018 • diff
๐ Fixed
- ๐ Transaction observers used to be notified of some database changes they were not interested into, in case of complex statements with side effects (foreign key cascades or sql triggers). This has been fixed.
๐ New
๐ The query interface has learned to build requests from any key (primary keys and unique keys) (documentation):
// SELECT * FROM players WHERE id = 1 let request = Player.filter(key: 1) let player = try request.fetchOne(db) // Player? // SELECT * FROM countries WHERE isoCode IN ('FR', 'US') let request = Country.filter(keys: ["FR", "US"]) let countries = try request.fetchAll(db) // [Country] // SELECT * FROM players WHERE email = '[email protected]' let request = Player.filter(key: ["email": "[email protected]"]) let player = try request.fetchOne(db) // Player?
This feature has been introduced in order to ease the use of RxGRDB:
// New Player.filter(key: 1).rx .fetchOne(in: dbQueue) .subscribe(onNext: { player: Player? in print("Player 1 has changed") })
API diff
extension TableMapping { + static func filter<PrimaryKeyType: DatabaseValueConvertible>(key: PrimaryKeyType?) -> QueryInterfaceRequest<Self> + static func filter<Sequence: Swift.Sequence>(keys: Sequence) -> QueryInterfaceRequest<Self> where Sequence.Element: DatabaseValueConvertible + static func filter(key: [String: DatabaseValueConvertible?]?) -> QueryInterfaceRequest<Self> + static func filter(keys: [[String: DatabaseValueConvertible?]]) -> QueryInterfaceRequest<Self> } extension QueryInterfaceRequest where T: TableMapping { + func filter<PrimaryKeyType: DatabaseValueConvertible>(key: PrimaryKeyType?) -> QueryInterfaceRequest<T> + func filter<Sequence: Swift.Sequence>(keys: Sequence) -> QueryInterfaceRequest<T> where Sequence.Element: DatabaseValueConvertible + func filter(key: [String: DatabaseValueConvertible?]?) -> QueryInterfaceRequest<T> + func filter(keys: [[String: DatabaseValueConvertible?]]) -> QueryInterfaceRequest<T> } extension RowConvertible where Self: TableMapping { - static func fetchOne(_ db: Database, key: [String: DatabaseValueConvertible?]) throws -> Self? + static func fetchOne(_ db: Database, key: [String: DatabaseValueConvertible?]?) throws -> Self? }