All Versions
267
Latest Version
Avg Release Cycle
15 days
Latest Release
-

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.1.0 Changes

    ๐Ÿš€ Released June 17, 2018 • diff

    ๐Ÿ†• New

    • #371: Database can have a label.
    • โฌ†๏ธ #372: Upgrade custom SQLite builds to 3.24.0.
  • 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 to FetchableRecord, Persistable to PersistableRecord, and TableMapping to TableRecord (#314).
    • Implicit transaction in DatabasePool.write and DatabaseQueue.write (#332).
    • ๐Ÿ”€ Request and TypedRequest protocols have been merged into FetchRequest (#311, #328, #348).
    • Reversing unordered requests has no effect (#342).
    • ๐Ÿšš The IteratorCursor type has been removed. Use AnyCursor 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 and write methods.
    • [Database Pools](README.md#database-pools): focus on the read and write 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 with AND or OR without nesting: [cond1, cond2, ...].joined(operator: .and).
    • [Custom Requests](README.md#custom-requests): the old Request and TypedRequest protocols have been replaced with FetchRequest. 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.10.0 Changes

    ๐Ÿš€ Released March 30, 2018 • diff

    ๐Ÿ†• New

    • ๐Ÿ‘Œ Support for Swift 4.1 and Xcode 9.3
    • โž• Added Cursor.compactMap (SE-0187)

    ๐Ÿ—„ Deprecated

    • ๐Ÿ—„ Cursor.flatMap is deprecated. Use compactMap instead.
  • 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, and rollback 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. Use db.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, renamed hasDatabaseChanges.
    • ๐Ÿ—„ Record.persistentChangedValues has been deprecated, renamed databaseChanges.

    ๐Ÿ“š Documentation Diff

    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]
    
  • 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.
  • 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?
     }