## Cleanup - [ ] Schemas and attached databases: can we enhance our pragma handling from https://sqlite.org/forum/forumpost/27f85a4634 - [ ] SQLCipher: sqlite3_rekey is discouraged (https://github.com/ccgus/fmdb/issues/547#issuecomment-259219320) - [ ] Write regression tests for #156 and #157 - [ ] deprecate ScopeAdapter(base, scopes), because base.addingScopes has a better implementation - [ ] https://github.com/groue/GRDB.swift/issues/514 - [ ] Test NOT TESTED methods - [ ] Get inspiration from the templates at https://github.com/woocommerce/woocommerce-ios/tree/develop/.github (https://github.com/woocommerce/woocommerce-ios/pull/3523) ## Documentation - [ ] Enhance the introduction to SQLRequest, based on the feedback in https://github.com/groue/GRDB.swift/issues/617 - [ ] Association: document how to use aggregates with inner join (testAnnotatedWithHasManyDefaultMaxJoiningRequired) - [ ] Should we document that `PRAGMA locking_mode = EXCLUSIVE` improves performances? https://sqlite.org/forum/forumpost/866bf3407a ## Features - [ ] Detect when `ColumnExpression.noOverwrite` excludes a non-existing column. Code is in DOA.upsertStatement()`. We should not silently ignore non-existing columns, as demonstrated by . - [ ] Can Swift 5.5 help us with `select(.all)` (request of RowDecoder), `select(.id)` (request of RowDecoder.ID), `select(.rowid)` (request of Int64)? - [ ] Direct access to statement for bindings - [ ] Property wrapper that decodes dictionaries (but how to tell the key column?) - [X] See if SQLITE_FCNTL_DATA_VERSION could help working around the lack of snapshots in order to avoid double initial fetch of ValueObservation. Result: no, it does not look it returns values that are comparable between two distinct SQLite connections (from the initial reader, and from the writer thhat starts the observation) - [X] Grab all FTS tokens in a string - [NO] Can we generate EXISTS with association? `Team.annotated(with: Team.players.exists)` No. We already have `Team.annotated(with: Team.players.isEmpty == false)`. It does not use an EXISTS expression, but a JOIN, and this is better for the internal consistency of the query interface, and the rules that deal with association keys. - [X] GRDB 6: have DatabaseRegionObservation produce DatabaseCancellable just as ValueObservation. - [X] RangeReplaceableCollection should have append(contentsOf: cursor) - [ ] GRDB 6: choose persistence table - [ ] GRDB 6: decoding errors - [X] throwing FetchableRecord initializer FIRST - [X] throwing Decodable FetchableRecord initializer SECOND - [X] deal with as much value decoding error as possible - [?] expose throwing row accessors - [ ] GRDB 6: Batch insert & Batch insert RETURNING - https://stackoverflow.com/questions/1609637/is-it-possible-to-insert-multiple-rows-at-a-time-in-an-sqlite-database - [ ] GRDB 6: INSERT or UPDATE columns to their default value - [X] GRDB 6: afterNextTransactionCommit -> afterNextTransaction(onCommit:onRollback:) - [ ] GRDB 6: encoding errors for record (`EncodableRecord.encode(to:)`) - [X] throwing EncodableRecord.encode FIRST - [?] GRDB 6: protocol-based record container? This could avoid computing & encoding values we do not need. - [ ] GRDB 6: encoding & statement binding errors for database values (conversion to DatabaseValue, statement binding, etc) - [ ] Prevent Date > 9999 from being encoded - [X] GRDB 6: Swift 5.7 - [X] GRDB 6: any / some - [X] GRDB 6: primary associated types (cursor, requests, ...) - [X] GRDB 6: remove existential/generic duplicated methods - [ ] GRDB 6: remove useless AnyXXX Type erasers - [X] GRDB 6: conflict resolution in persistence methods - [X] GRDB 6: UPSERT - [X] GRDB 6: support for RETURNING - [X] Support for default values: `Player.insert(db, as: FullPlayer.self)` - [?] GRDB 6: allow mutating `update` (for timestamps) - [?] GRDB 6: let record choose persistence table (insert(into:) ?) - [?] GRDB 6: Support opaque return types (macOS Catalina, iOS 13, tvOS 13, watchOS 6 and later: https://stackoverflow.com/questions/56518406) - [ ] Long run edition. Use case: user edits the database (CRUD) but the application wants to commit and the end of the editing session. * Create an edition SQLite connection with an open transaction (a new kind of DatabaseWriter with a save() method) * All other writes will fail with SQLITE_BUSY. Unless they are schedules in a target dispatch queue which is paused during the edition. - [ ] Can we use generated columns to makes it convenient to index on inserted JSON objects? https://github.com/apple/swift-package-manager/pull/3090#issuecomment-740091760 - [ ] Look at [@FetchRequest](https://developer.apple.com/documentation/swiftui/fetchrequest): managed object context is stored in the environment, and error processing happens somewhere else (where?). - [ ] Handle SQLITE_LIMIT_VARIABLE_NUMBER in deleteAll(_:keys:) and similar APIs. https://www.sqlite.org/limits.html - [X] Subqueries: ~request.isEmpty~ / [X] request.exists() - [ ] Subqueries: request.count - [ ] Extract one row from a hasMany association (the one with the maximum date, the one with a flag set, etc.) https://stackoverflow.com/questions/43188771/sqlite-join-query-most-recent-posts-by-each-user (failed PR: https://github.com/groue/GRDB.swift/pull/767) - [ ] Turn a hasMany to hasOne without first/last : hasMany(Book.self).filter(Column("isBest") /* assume a single book is flagged best */).asOne() - [ ] Support for more kinds of joins: https://github.com/groue/GRDB.swift/issues/740 - [ ] HasAndBelongsToMany: https://github.com/groue/GRDB.swift/issues/711 - [ ] Support UNION https://github.com/groue/GRDB.swift/issues/671 (https://www.sqlite.org/lang_select.html#compound) - [ ] Measure the duration of transactions - [ ] Improve SQL generation for `Player.....fetchCount(db)`, especially with distinct. Try to avoid `SELECT COUNT(*) FROM (SELECT DISTINCT player.* ...)` - [ ] Alternative technique for custom SQLite builds: see the Podfile at https://github.com/CocoaPods/CocoaPods/issues/9104, and https://github.com/clemensg/sqlite3pod - [ ] Attach databases. Interesting question: what happens when one attaches a non-WAL db to a databasePool? - [ ] SQL Generation - [ ] date functions - [ ] NOW/CURRENT_TIMESTAMP - [ ] ROUND() http://marc.info/?l=sqlite-users&m=130419182719263 - [ ] RANDOM() https://www.sqlite.org/lang_corefunc.html - [ ] GLOB https://www.sqlite.org/lang_expr.html - [ ] REGEXP https://www.sqlite.org/lang_expr.html - [ ] CASE x WHEN w1 THEN r1 WHEN w2 THEN r2 ELSE r3 END https://www.sqlite.org/lang_expr.html - [ ] Allow concurrent reads from a snapshot - [ ] Check https://sqlite.org/sqlar.html - [ ] More schema alterations - [ ] Database.clearSchemaCache() is fine, but what about dbPool readers? Can we invalidate the cache for a whole pool? - [ ] What can we do with `cross-module-optimization`? See https://github.com/apple/swift-homomorphic-encryption ## Unsure if necessary - [ ] Have TableAlias embed the record type - [ ] Have SQLPrimaryKeyExpression embed the record type - [ ] Remove support for suspended databases - https://inessential.com/2020/02/13/how_we_fixed_the_dreaded_0xdead10cc_cras - [ ] https://sqlite.org/pragma.html#pragma_index_xinfo - [ ] filter(rowid:), filter(rowids:) - [ ] https://github.com/apple/swift-evolution/blob/master/proposals/0075-import-test.md - [ ] https://forums.swift.org/t/how-to-encode-objects-of-unknown-type/12253/6 - [ ] Configuration.crashOnError = true - [ ] Glossary (Database Access Methods, etc.) - [ ] Not sure: type safety for SQL expressions - [ ] Introduce some record protocol with an associated primary key type. Restrict filter(key:) methods to this type. Allow distinguishing FooId from BarId types. - [ ] Replace Column with TypedColumn. How to avoid code duplication (repeated types)? Keypaths? - [ ] Remove prefix from association keys when association name is namespaced: https://github.com/groue/GRDB.swift/issues/584#issuecomment-517658122 - [ ] Alternative support for custom SQLite builds, with CocoaPods: https://github.com/CocoaPods/CocoaPods/issues/9103 ## Unsure how - [ ] Association limits: `Author.including(optional: Author.books.order(date.desc).first)` - [ ] Joins and full-text tables - [ ] UPSERT https://www.sqlite.org/lang_UPSERT.html - [ ] Support for "INSERT INTO ... SELECT ...". - [ ] Look at the jazzy configuration of https://github.com/bignerdranch/Deferred - [ ] Predicates, so that a filter can be evaluated both on the database, and on a record instance. After investigation, we can't do it reliably without knowing the collation used by a column. And SQLite does not provide this information elsewhere than in the full CREATE TABLE statement stored in sqlite_master. - [ ] ValueObservation erasure ``` // Do better than this observation.mapReducer { _, reducer in AnyValueReducer(reducer) } ``` - [ ] new.updateChanges(from: old) vs. old.updateChanges(with: { old.a = new.a }). This is confusing. ## Reading list - Documentation generation: https://twitter.com/jckarter/status/987525569196650496: cmark is the implementation the Swift compiler uses for doc comments etc. - VACUUM (https://blogs.gnome.org/jnelson/) - http://www.sqlite.org/intern-v-extern-blob.html - https://sqlite.org/sharedcache.html - Undo: https://www.sqlite.org/undoredo.html - Undo: https://sqlite.org/sessionintro.html - Swift, Xcode:List of Swift documentation keywords: https://swift.org/documentation/api-design-guidelines.html#special-instructions - Swift, Xcode:Amazing tip from Xcode labs: add a EXCLUDED_SOURCE_FILE_NAMES build setting to conditionally exclude sources for different configuration: https://twitter.com/zats/status/74386298602026496 - SQLITE_ENABLE_SQLLOG: http://mjtsai.com/blog/2016/07/19/sqlite_enable_sqllog/ - Swift, Xcode: https://github.com/apple/swift/blob/master/docs/OptimizationTips.rst - Associations: http://docs.diesel.rs/diesel/associations/index.html - FTS: http://cocoamine.net/blog/2015/09/07/contentless-fts4-for-large-immutable-documents/ - pinyin: http://hustlzp.com/post/2016/02/ios-full-text-search-using-sqlite-fts4 - Realm oddity: http://stackoverflow.com/questions/41721769/realm-update-object-without-updating-lists - File protection: https://github.com/ccgus/fmdb/issues/262 - File protection: https://lists.apple.com/archives/cocoa-dev/2012/Aug/msg00527.html - [iOS apps are terminated every time they enter the background if they share an encrypted database with an app extension](https://github.com/sqlcipher/sqlcipher/issues/255) - [Cross-Process notifications with CFNotificationCenterGetDarwinNotifyCenter](https://www.avanderlee.com/swift/core-data-app-extension-data-sharing/)