WatermelonDB v0.24 Release Notes

Release Date: 2021-10-28 // over 2 years ago

    • Q.experimentalSortBy, Q.experimentalSkip, Q.experimentalTake have been renamed to Q.sortBy, Q.skip, Q.take respectively
    • โšก๏ธ RxJS has been updated to 7.3.0. If you're not importing from rxjs in your app, this doesn't apply to you. If you are, read RxJS 7 breaking changes: https://rxjs.dev/deprecations/breaking-changes

    ๐Ÿ†• New features

    • LocalStorage. database.localStorage is now available
    • sortBy, skip, take are now available in LokiJSAdapter as well
    • Disposable records. Read-only records that cannot be saved in the database, updated, or deleted and only exist for as long as you keep a reference to them in memory can now be created using collection.disposableFromDirtyRaw(). This is useful when you're adding online-only features to an otherwise offline-first app.
    • ๐Ÿ”€ [Sync] experimentalRejectedIds parameter now available in push response to allow partial rejection of an otherwise successful sync

    ๐Ÿ›  Fixes

    • ๐Ÿ›  Fixes an issue when using Headless JS on Android with JSI mode enabled - pass usesExclusiveLocking: true to SQLiteAdapter to enable
    • ๐Ÿ›  Fixes Typescript annotations for Collection and adapters/sqlite

Previous changes from v0.23

  • ๐Ÿš€ This is a big release to WatermelonDB with new advanced features, great performance improvements, and important fixes to JSI on Android.

    โฌ†๏ธ Please don't get scared off the long list of breaking changes - they are all either simple Find&Replace renames or changes to internals you probably don't use. It shouldn't take you more than 15 minutes to upgrade to 0.23.


    • iOS Installation change. You need to add this line to your Podfile: pod 'simdjson', path: '../node_modules/@nozbe/simdjson'
    • ๐Ÿšš Deprecated new Database({ actionsEnabled: false }) options is now removed. Actions are always enabled.
    • ๐Ÿ”€ Deprecated new SQLiteAdapter({ synchronous: true }) option is now removed. Use { jsi: true } instead.
    • ๐Ÿšš Deprecated Q.unsafeLokiFilter is now removed. Use Q.unsafeLokiTransform((raws, loki) => raws.filter(raw => ...)) instead.
    • ๐Ÿšš Deprecated Query.hasJoins is now removed
    • ๐Ÿ”„ Changes to LokiJSAdapter constructor options:
      • indexedDBSerializer -> extraIncrementalIDBOptions: { serializeChunk, deserializeChunk }
      • onIndexedDBFetchStart -> extraIncrementalIDBOptions: { onFetchStart }
      • onIndexedDBVersionChange -> extraIncrementalIDBOptions: { onversionchange }
      • autosave: false -> extraLokiOptions: { autosave: false }
    • ๐Ÿ”„ Changes to Internal APIs. These were never meant to be public, and so are unlikely to affect you:
      • Model._isCommited, ._hasPendingUpdate, ._hasPendingDelete have been removed and changed to Model._pendingState
      • Collection.unsafeClearCache() is no longer exposed
    • Values passed to adapter.setLocal() are now validated to be strings. This is technically a bug fix, since local storage was always documented to only accept strings, however applications may have relied on this lack of validation. Adding this validation was necessary to achieve consistent behavior between SQLiteAdapter and LokiJSAdapter
    • ๐Ÿ‘€ unsafeSql passed to appSchema will now also be called when dropping and later recreating all database indices on large batches. A second argument was added so you can distinguish between these cases. See Schema docs for more details.
    • ๐Ÿ”„ Changes to sync change tracking. The behavior of record._raw._changed and record._raw._status (a.k.a. record.syncStatus) has changed. This is unlikely to be a breaking change to you, unless you're writing your own sync engine or rely on these low-level details.
      • Previously, _changed was always empty when _status=created. Now, _changed is not populated during initial creation of a record, but a later update will add changed fields to _changed. This change was necessary to fix a long-standing Sync bug.

    ๐Ÿ—„ Deprecations

    • ๐Ÿ—„ database.action(() => {}) is now deprecated. Use db.write(() => {}) instead (or db.read(() => {}) if you only need consistency but are not writing any changes to DB)
    • ๐Ÿ—„ @action is now deprecated. Use @writer or @reader instead
    • ๐Ÿ—„ .subAction() is now deprecated. Use .callReader() or .callWriter() instead
    • ๐Ÿ—„ Collection.unsafeFetchRecordsWithSQL() is now deprecated. Use collection.query(Q.unsafeSqlQuery("select * from...")).fetch() instead.

    ๐Ÿ†• New features

    • db.write(writer => { ... writer.batch() }) - you can now call batch on the interface passed to a writer block
    • Fetching record IDs and unsafe raws. You can now optimize fetching of queries that only require IDs, not full cached records:
      • await query.fetchIds() will return an array of record ids
      • await query.unsafeFetchRaw() will return an array of unsanitized, unsafe raw objects (use alongside Q.unsafeSqlQuery to exclude unnecessary or include extra columns)
      • advanced adapter.queryIds(), adapter.unsafeQueryRaw are also available
    • Raw SQL queries. New syntax for running unsafe raw SQL queries:
      • collection.query(Q.unsafeSqlQuery("select * from tasks where foo = ?", ['bar'])).fetch()
      • You can now also run .fetchCount(), .fetchIds() on SQL queries
      • You can now safely pass values for SQL placeholders by passing an array
      • You can also observe an unsafe raw SQL query -- with some caveats! refer to documentation for more details
    • Unsafe raw execute. You can now execute arbitrary SQL queries (SQLiteAdapter) or access Loki object directly (LokiJSAdapter) using adapter.unsafeExecute -- see docs for more details
    • Turbo Login. You can now speed up the initial (login) sync by up to 5.3x with Turbo Login. See Sync docs for more details.
    • ๐Ÿ–จ New diagnostic tool - debugPrintChanges. See Sync documentation for more details

    ๐ŸŽ Performance

    • The order of Q. clauses in a query is now preserved - previously, the clauses could get rearranged and produce a suboptimal query
    • โšก๏ธ [SQLite] adapter.batch() with large numbers of created/updated/deleted records is now between 16-48% faster
    • [LokiJS] Querying and finding is now faster - unnecessary data copy is skipped
    • [jsi] 15-30% faster querying on JSC (iOS) when the number of returned records is large
    • [jsi] up to 52% faster batch creation (yes, that's on top of the improvement listed above!)
    • ๐Ÿ›  Fixed a performance bug that caused observed items on a list observer with .observeWithColumns() to be unnecessarily re-rendered just before they were removed from the list

    ๐Ÿ”„ Changes

    • ๐Ÿ”Š All Watermelon console logs are prepended with a ๐Ÿ‰ tag
    • Extra protections against improper use of writers/readers (formerly actions) have been added
    • โš  Queries with multiple top-level Q.on('table', ...) now produce a warning. Use Q.on('table', [condition1, condition2, ...]) syntax instead.
    • [jsi] WAL mode is now used

    ๐Ÿ›  Fixes

    • [jsi] Fix a race condition where commands sent to the database right after instantiating SQLiteAdapter would fail
    • [jsi] Fix incorrect error reporting on some sqlite errors
    • [jsi] Fix issue where app would crash on Android/Hermes on reload
    • [jsi] Fix IO errors on Android
    • โšก๏ธ [sync] Fixed a long-standing bug that would cause records that are created before a sync and updated during sync's push to lose their most recent changes on a subsequent sync


    • Internal changes to SQLiteAdapter:
      • .batch is no longer available on iOS implementation
      • .batch/.batchJSON internal format has changed
      • .getDeletedRecords, destroyDeletedRecords, setLocal, removeLocal is no longer available
    • encoded SQLiteAdapter schema has changed
    • LokiJSAdapter has had many internal changes