UNPKG

@rikishi/watermelondb

Version:

Build powerful React Native and React web apps that scale from hundreds to tens of thousands of records and remain fast

684 lines (640 loc) β€’ 68.6 kB
<!DOCTYPE HTML> <html lang="en" class="sidebar-visible no-js light"> <head> <!-- Book generated using mdBook --> <meta charset="UTF-8"> <title>Changelog - WatermelonDB documentation</title> <!-- Custom HTML head --> <meta content="text/html; charset=utf-8" http-equiv="Content-Type"> <meta name="description" content=""> <meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="theme-color" content="#ffffff" /> <link rel="icon" href="favicon.svg"> <link rel="shortcut icon" href="favicon.png"> <link rel="stylesheet" href="css/variables.css"> <link rel="stylesheet" href="css/general.css"> <link rel="stylesheet" href="css/chrome.css"> <link rel="stylesheet" href="css/print.css" media="print"> <!-- Fonts --> <link rel="stylesheet" href="FontAwesome/css/font-awesome.css"> <link rel="stylesheet" href="fonts/fonts.css"> <!-- Highlight.js Stylesheets --> <link rel="stylesheet" href="highlight.css"> <link rel="stylesheet" href="tomorrow-night.css"> <link rel="stylesheet" href="ayu-highlight.css"> <!-- Custom theme stylesheets --> </head> <body> <!-- Provide site root to javascript --> <script type="text/javascript"> var path_to_root = ""; var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "navy" : "light"; </script> <!-- Work around some values being stored in localStorage wrapped in quotes --> <script type="text/javascript"> try { var theme = localStorage.getItem('mdbook-theme'); var sidebar = localStorage.getItem('mdbook-sidebar'); if (theme.startsWith('"') && theme.endsWith('"')) { localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1)); } if (sidebar.startsWith('"') && sidebar.endsWith('"')) { localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1)); } } catch (e) { } </script> <!-- Set the theme before any content is loaded, prevents flash --> <script type="text/javascript"> var theme; try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { } if (theme === null || theme === undefined) { theme = default_theme; } var html = document.querySelector('html'); html.classList.remove('no-js') html.classList.remove('light') html.classList.add(theme); html.classList.add('js'); </script> <!-- Hide / unhide sidebar before it is displayed --> <script type="text/javascript"> var html = document.querySelector('html'); var sidebar = 'hidden'; if (document.body.clientWidth >= 1080) { try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { } sidebar = sidebar || 'visible'; } html.classList.remove('sidebar-visible'); html.classList.add("sidebar-" + sidebar); </script> <nav id="sidebar" class="sidebar" aria-label="Table of contents"> <div class="sidebar-scrollbox"> <ol class="chapter"><li class="chapter-item expanded "><a href="ch01-00-get-excited.html"><strong aria-hidden="true">1.</strong> Get excited</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="index.html"><strong aria-hidden="true">1.1.</strong> Check out the README</a></li><li class="chapter-item expanded "><a href="Demo.html"><strong aria-hidden="true">1.2.</strong> See the demo</a></li></ol></li><li class="chapter-item expanded "><a href="ch02-00-learn-to-use.html"><strong aria-hidden="true">2.</strong> Learn to use Watermelon</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="Installation.html"><strong aria-hidden="true">2.1.</strong> Installation</a></li><li class="chapter-item expanded "><a href="Setup.html"><strong aria-hidden="true">2.2.</strong> Setup</a></li><li class="chapter-item expanded "><a href="Schema.html"><strong aria-hidden="true">2.3.</strong> Schema</a></li><li class="chapter-item expanded "><a href="Model.html"><strong aria-hidden="true">2.4.</strong> Defining Models</a></li><li class="chapter-item expanded "><a href="CRUD.html"><strong aria-hidden="true">2.5.</strong> Create, Read, Update, Delete</a></li><li class="chapter-item expanded "><a href="Components.html"><strong aria-hidden="true">2.6.</strong> Connecting to React Components</a></li><li class="chapter-item expanded "><a href="Query.html"><strong aria-hidden="true">2.7.</strong> Querying</a></li><li class="chapter-item expanded "><a href="Relation.html"><strong aria-hidden="true">2.8.</strong> Relations</a></li><li class="chapter-item expanded "><a href="Writers.html"><strong aria-hidden="true">2.9.</strong> Writers, Readers, batching</a></li></ol></li><li class="chapter-item expanded "><a href="ch03-00-advanced.html"><strong aria-hidden="true">3.</strong> Advanced guides</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="Advanced/Migrations.html"><strong aria-hidden="true">3.1.</strong> Migrations</a></li><li class="chapter-item expanded "><a href="Advanced/Sync.html"><strong aria-hidden="true">3.2.</strong> Sync</a></li><li class="chapter-item expanded "><a href="Advanced/CreateUpdateTracking.html"><strong aria-hidden="true">3.3.</strong> Automatic create/update tracking</a></li><li class="chapter-item expanded "><a href="Advanced/AdvancedFields.html"><strong aria-hidden="true">3.4.</strong> Advanced fields</a></li><li class="chapter-item expanded "><a href="Advanced/Flow.html"><strong aria-hidden="true">3.5.</strong> Flow</a></li><li class="chapter-item expanded "><a href="Advanced/LocalStorage.html"><strong aria-hidden="true">3.6.</strong> LocalStorage</a></li><li class="chapter-item expanded "><a href="Advanced/ProTips.html"><strong aria-hidden="true">3.7.</strong> Pro tips</a></li><li class="chapter-item expanded "><a href="Advanced/Performance.html"><strong aria-hidden="true">3.8.</strong> Performance tips</a></li><li class="chapter-item expanded "><a href="Advanced/SharingDatabaseAcrossTargets.html"><strong aria-hidden="true">3.9.</strong> iOS - Sharing database across targets</a></li></ol></li><li class="chapter-item expanded "><a href="ch04-00-deeper.html"><strong aria-hidden="true">4.</strong> Dig deeper into WatermelonDB</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="Implementation/Architecture.html"><strong aria-hidden="true">4.1.</strong> Architecture</a></li><li class="chapter-item expanded "><a href="Implementation/Adapters.html"><strong aria-hidden="true">4.2.</strong> Adapters</a></li><li class="chapter-item expanded "><a href="Implementation/SyncImpl.html"><strong aria-hidden="true">4.3.</strong> Sync implementation</a></li></ol></li><li class="chapter-item expanded "><a href="ch04-00-deeper.html"><strong aria-hidden="true">5.</strong> Other</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="Roadmap.html"><strong aria-hidden="true">5.1.</strong> Roadmap</a></li><li class="chapter-item expanded "><a href="CONTRIBUTING.html"><strong aria-hidden="true">5.2.</strong> Contributing</a></li><li class="chapter-item expanded "><a href="CHANGELOG.html" class="active"><strong aria-hidden="true">5.3.</strong> Changelog</a></li></ol></li></ol> </div> <div id="sidebar-resize-handle" class="sidebar-resize-handle"></div> </nav> <div id="page-wrapper" class="page-wrapper"> <div class="page"> <div id="menu-bar-hover-placeholder"></div> <div id="menu-bar" class="menu-bar sticky bordered"> <div class="left-buttons"> <button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar"> <i class="fa fa-bars"></i> </button> <button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list"> <i class="fa fa-paint-brush"></i> </button> <ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu"> <li role="none"><button role="menuitem" class="theme" id="light">Light (default)</button></li> <li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li> <li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li> <li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li> <li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li> </ul> <button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar"> <i class="fa fa-search"></i> </button> </div> <h1 class="menu-title">WatermelonDB documentation</h1> <div class="right-buttons"> <a href="print.html" title="Print this book" aria-label="Print this book"> <i id="print-button" class="fa fa-print"></i> </a> </div> </div> <div id="search-wrapper" class="hidden"> <form id="searchbar-outer" class="searchbar-outer"> <input type="search" name="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header"> </form> <div id="searchresults-outer" class="searchresults-outer hidden"> <div id="searchresults-header" class="searchresults-header"></div> <ul id="searchresults"> </ul> </div> </div> <!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM --> <script type="text/javascript"> document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible'); document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible'); Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) { link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1); }); </script> <div id="content" class="content"> <main> <h1 id="changelog"><a class="header" href="#changelog">Changelog</a></h1> <p>All notable changes to this project will be documented in this file.</p> <p>Contributors: Please add your changes to CHANGELOG-Unreleased.md</p> <h2 id="024---2021-10-28"><a class="header" href="#024---2021-10-28">0.24 - 2021-10-28</a></h2> <h3 id="breaking-changes"><a class="header" href="#breaking-changes">BREAKING CHANGES</a></h3> <ul> <li><code>Q.experimentalSortBy</code>, <code>Q.experimentalSkip</code>, <code>Q.experimentalTake</code> have been renamed to <code>Q.sortBy</code>, <code>Q.skip</code>, <code>Q.take</code> respectively</li> <li><strong>RxJS has been updated to 7.3.0</strong>. If you're not importing from <code>rxjs</code> in your app, this doesn't apply to you. If you are, read RxJS 7 breaking changes: https://rxjs.dev/deprecations/breaking-changes</li> </ul> <h3 id="new-features"><a class="header" href="#new-features">New features</a></h3> <ul> <li><strong>LocalStorage</strong>. <code>database.localStorage</code> is now available</li> <li><strong>sortBy, skip, take</strong> are now available in LokiJSAdapter as well</li> <li><strong>Disposable records</strong>. 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 <code>collection.disposableFromDirtyRaw()</code>. This is useful when you're adding online-only features to an otherwise offline-first app.</li> <li>[Sync] <code>experimentalRejectedIds</code> parameter now available in push response to allow partial rejection of an otherwise successful sync</li> </ul> <h3 id="fixes"><a class="header" href="#fixes">Fixes</a></h3> <ul> <li>Fixes an issue when using Headless JS on Android with JSI mode enabled - pass <code>usesExclusiveLocking: true</code> to SQLiteAdapter to enable</li> <li>Fixes Typescript annotations for Collection and adapters/sqlite</li> </ul> <h2 id="023---2021-07-22"><a class="header" href="#023---2021-07-22">0.23 - 2021-07-22</a></h2> <p>This is a big release to WatermelonDB with new advanced features, great performance improvements, and important fixes to JSI on Android.</p> <p>Please don't get scared off the long list of breaking changes - they are all either simple Find&amp;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.</p> <h3 id="breaking-changes-1"><a class="header" href="#breaking-changes-1">BREAKING CHANGES</a></h3> <ul> <li><strong>iOS Installation change</strong>. You need to add this line to your Podfile: <code>pod 'simdjson', path: '../node_modules/@nozbe/simdjson'</code></li> <li>Deprecated <code>new Database({ actionsEnabled: false })</code> options is now removed. Actions are always enabled.</li> <li>Deprecated <code>new SQLiteAdapter({ synchronous: true })</code> option is now removed. Use <code>{ jsi: true }</code> instead.</li> <li>Deprecated <code>Q.unsafeLokiFilter</code> is now removed. Use <code>Q.unsafeLokiTransform((raws, loki) =&gt; raws.filter(raw =&gt; ...))</code> instead.</li> <li>Deprecated <code>Query.hasJoins</code> is now removed</li> <li>Changes to <code>LokiJSAdapter</code> constructor options: <ul> <li><code>indexedDBSerializer</code> -&gt; <code>extraIncrementalIDBOptions: { serializeChunk, deserializeChunk }</code></li> <li><code>onIndexedDBFetchStart</code> -&gt; <code>extraIncrementalIDBOptions: { onFetchStart }</code></li> <li><code>onIndexedDBVersionChange</code> -&gt; <code>extraIncrementalIDBOptions: { onversionchange }</code></li> <li><code>autosave: false</code> -&gt; <code>extraLokiOptions: { autosave: false }</code></li> </ul> </li> <li>Changes to Internal APIs. These were never meant to be public, and so are unlikely to affect you: <ul> <li><code>Model._isCommited</code>, <code>._hasPendingUpdate</code>, <code>._hasPendingDelete</code> have been removed and changed to <code>Model._pendingState</code></li> <li><code>Collection.unsafeClearCache()</code> is no longer exposed</li> </ul> </li> <li>Values passed to <code>adapter.setLocal()</code> 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</li> <li><code>unsafeSql</code> passed to <code>appSchema</code> 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.</li> <li><strong>Changes to sync change tracking</strong>. The behavior of <code>record._raw._changed</code> and <code>record._raw._status</code> (a.k.a. <code>record.syncStatus</code>) 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. <ul> <li>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.</li> </ul> </li> </ul> <h3 id="deprecations"><a class="header" href="#deprecations">Deprecations</a></h3> <ul> <li><code>database.action(() =&gt; {})</code> is now deprecated. Use <code>db.write(() =&gt; {})</code> instead (or <code>db.read(() =&gt; {})</code> if you only need consistency but are not writing any changes to DB)</li> <li><code>@action</code> is now deprecated. Use <code>@writer</code> or <code>@reader</code> instead</li> <li><code>.subAction()</code> is now deprecated. Use <code>.callReader()</code> or <code>.callWriter()</code> instead</li> <li><code>Collection.unsafeFetchRecordsWithSQL()</code> is now deprecated. Use <code>collection.query(Q.unsafeSqlQuery(&quot;select * from...&quot;)).fetch()</code> instead.</li> </ul> <h3 id="new-features-1"><a class="header" href="#new-features-1">New features</a></h3> <ul> <li><code>db.write(writer =&gt; { ... writer.batch() })</code> - you can now call batch on the interface passed to a writer block</li> <li><strong>Fetching record IDs and unsafe raws.</strong> You can now optimize fetching of queries that only require IDs, not full cached records: <ul> <li><code>await query.fetchIds()</code> will return an array of record ids</li> <li><code>await query.unsafeFetchRaw()</code> will return an array of unsanitized, unsafe raw objects (use alongside <code>Q.unsafeSqlQuery</code> to exclude unnecessary or include extra columns)</li> <li>advanced <code>adapter.queryIds()</code>, <code>adapter.unsafeQueryRaw</code> are also available</li> </ul> </li> <li><strong>Raw SQL queries</strong>. New syntax for running unsafe raw SQL queries: <ul> <li><code>collection.query(Q.unsafeSqlQuery(&quot;select * from tasks where foo = ?&quot;, ['bar'])).fetch()</code></li> <li>You can now also run <code>.fetchCount()</code>, <code>.fetchIds()</code> on SQL queries</li> <li>You can now safely pass values for SQL placeholders by passing an array</li> <li>You can also observe an unsafe raw SQL query -- with some caveats! refer to documentation for more details</li> </ul> </li> <li><strong>Unsafe raw execute</strong>. You can now execute arbitrary SQL queries (SQLiteAdapter) or access Loki object directly (LokiJSAdapter) using <code>adapter.unsafeExecute</code> -- see docs for more details</li> <li><strong>Turbo Login</strong>. You can now speed up the initial (login) sync by up to 5.3x with Turbo Login. See Sync docs for more details.</li> <li>New diagnostic tool - <strong>debugPrintChanges</strong>. See Sync documentation for more details</li> </ul> <h3 id="performance"><a class="header" href="#performance">Performance</a></h3> <ul> <li>The order of Q. clauses in a query is now preserved - previously, the clauses could get rearranged and produce a suboptimal query</li> <li>[SQLite] <code>adapter.batch()</code> with large numbers of created/updated/deleted records is now between 16-48% faster</li> <li>[LokiJS] Querying and finding is now faster - unnecessary data copy is skipped</li> <li>[jsi] 15-30% faster querying on JSC (iOS) when the number of returned records is large</li> <li>[jsi] up to 52% faster batch creation (yes, that's on top of the improvement listed above!)</li> <li>Fixed a performance bug that caused observed items on a list observer with <code>.observeWithColumns()</code> to be unnecessarily re-rendered just before they were removed from the list</li> </ul> <h3 id="changes"><a class="header" href="#changes">Changes</a></h3> <ul> <li>All Watermelon console logs are prepended with a πŸ‰ tag</li> <li>Extra protections against improper use of writers/readers (formerly actions) have been added</li> <li>Queries with multiple top-level <code>Q.on('table', ...)</code> now produce a warning. Use <code>Q.on('table', [condition1, condition2, ...])</code> syntax instead.</li> <li>[jsi] WAL mode is now used</li> </ul> <h3 id="fixes-1"><a class="header" href="#fixes-1">Fixes</a></h3> <ul> <li>[jsi] Fix a race condition where commands sent to the database right after instantiating SQLiteAdapter would fail</li> <li>[jsi] Fix incorrect error reporting on some sqlite errors</li> <li>[jsi] Fix issue where app would crash on Android/Hermes on reload</li> <li>[jsi] Fix IO errors on Android</li> <li>[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</li> </ul> <h3 id="internal"><a class="header" href="#internal">Internal</a></h3> <ul> <li>Internal changes to SQLiteAdapter: <ul> <li>.batch is no longer available on iOS implementation</li> <li>.batch/.batchJSON internal format has changed</li> <li>.getDeletedRecords, destroyDeletedRecords, setLocal, removeLocal is no longer available</li> </ul> </li> <li>encoded SQLiteAdapter schema has changed</li> <li>LokiJSAdapter has had many internal changes</li> </ul> <h2 id="022---2021-05-07"><a class="header" href="#022---2021-05-07">0.22 - 2021-05-07</a></h2> <h3 id="breaking-changes-2"><a class="header" href="#breaking-changes-2">BREAKING CHANGES</a></h3> <ul> <li>[SQLite] <code>experimentalUseJSI: true</code> option has been renamed to <code>jsi: true</code></li> </ul> <h3 id="deprecations-1"><a class="header" href="#deprecations-1">Deprecations</a></h3> <ul> <li>[LokiJS] <code>Q.unsafeLokiFilter</code> is now deprecated and will be removed in a future version. Use <code>Q.unsafeLokiTransform((raws, loki) =&gt; raws.filter(raw =&gt; ...))</code> instead.</li> </ul> <h3 id="new-features-2"><a class="header" href="#new-features-2">New features</a></h3> <ul> <li>[SQLite] [JSI] <code>jsi: true</code> now works on Android - see docs for installation info</li> </ul> <h3 id="performance-1"><a class="header" href="#performance-1">Performance</a></h3> <ul> <li>Removed dependency on rambdax and made the util library smaller</li> <li>Faster withObservables</li> </ul> <h3 id="changes-1"><a class="header" href="#changes-1">Changes</a></h3> <ul> <li>Synchronization: <code>pushChanges</code> is optional, will not calculate local changes if not specified.</li> <li>withObservables is now a dependency of WatermelonDB for simpler installation and consistent updates. You can (and generally should) delete <code>@nozbe/with-observables</code> from your app's package.json</li> <li>[Docs] Add advanced tutorial to share database across iOS targets - @thiagobrez</li> <li>[SQLite] Allowed callbacks (within the migrationEvents object) to be passed so as to track the migration events status ( onStart, onSuccess, onError ) - @avinashlng1080</li> <li>[SQLite] Added a dev-only <code>Query._sql()</code> method for quickly extracting SQL from Queries for debugging purposes</li> </ul> <h3 id="fixes-2"><a class="header" href="#fixes-2">Fixes</a></h3> <ul> <li>Non-react statics hoisting in <code>withDatabase()</code></li> <li>Fixed incorrect reference to <code>process</code>, which can break apps in some environments (e.g. webpack5)</li> <li>[SQLite] [JSI] Fixed JSI mode when running on Hermes</li> <li>Fixed a race condition when using standard fetch methods alongside <code>Collection.unsafeFetchRecordsWithSQL</code> - @jspizziri</li> <li>withObservables shouldn't cause any RxJS issues anymore as it no longer imports RxJS</li> <li>[Typescript] Added <code>onSetUpError</code> and <code>onIndexedDBFetchStart</code> fields to <code>LokiAdapterOptions</code>; fixes TS error - @3DDario</li> <li>[Typescript] Removed duplicated identifiers <code>useWebWorker</code> and <code>useIncrementalIndexedDB</code> in <code>LokiAdapterOptions</code> - @3DDario</li> <li>[Typescript] Fix default export in logger util</li> </ul> <h2 id="021---2021-03-24"><a class="header" href="#021---2021-03-24">0.21 - 2021-03-24</a></h2> <h3 id="breaking-changes-3"><a class="header" href="#breaking-changes-3">BREAKING CHANGES</a></h3> <ul> <li>[LokiJS] <code>useWebWorker</code> and <code>useIncrementalIndexedDB</code> options are now required (previously, skipping them would only trigger a warning)</li> </ul> <h3 id="new-features-3"><a class="header" href="#new-features-3">New features</a></h3> <ul> <li>[Model] <code>Model.update</code> method now returns updated record</li> <li>[adapters] <code>onSetUpError: Error =&gt; void</code> option is added to both <code>SQLiteAdapter</code> and <code>LokiJSAdapter</code>. Supply this option to catch initialization errors and offer the user to reload or log out</li> <li>[LokiJS] new <code>extraLokiOptions</code> and <code>extraIncrementalIDBOptions</code> options</li> <li>[Android] Autolinking is now supported. <ul> <li>If You upgrade to <code>&lt;= v0.21.0</code> <strong>AND</strong> are on a version of React Native which supports Autolinking, you will need to remove the config manually linking WatermelonDB.</li> <li>You can resolve this issue by <strong>REMOVING</strong> the lines of config from your project which are <em>added</em> in the <code>Manual Install ONLY</code> section of the <a href="https://nozbe.github.io/WatermelonDB/Installation.html#android-react-native">Android Install docs</a>.</li> </ul> </li> </ul> <h3 id="performance-2"><a class="header" href="#performance-2">Performance</a></h3> <ul> <li>[LokiJS] Improved performance of launching the app</li> </ul> <h3 id="changes-2"><a class="header" href="#changes-2">Changes</a></h3> <ul> <li>[LokiJS] <code>useWebWorker: true</code> and <code>useIncrementalIndexedDB: false</code> options are now deprecated. If you rely on these features, please file an issue!</li> <li>[Sync] Optional <code>log</code> passed to sync now has more helpful diagnostic information</li> <li>[Sync] Open-sourced a simple SyncLogger you can optionally use. See docs for more info.</li> <li>[SQLiteAdapter] <code>synchronous:true</code> option is now deprecated and will be replaced with <code>experimentalUseJSI: true</code> in the future. Please test if your app compiles and works well with <code>experimentalUseJSI: true</code>, and if not - file an issue!</li> <li>[LokiJS] Changed default autosave interval from 250 to 500ms</li> <li>[Typescript] Add <code>experimentalNestedJoin</code> definition and <code>unsafeSqlExpr</code> clause</li> </ul> <h3 id="fixes-3"><a class="header" href="#fixes-3">Fixes</a></h3> <ul> <li>[LokiJS] Fixed a case where IndexedDB could get corrupted over time</li> <li>[Resilience] Added extra diagnostics for when you encounter the <code>Record ID aa#bb was sent over the bridge, but it's not cached</code> error and a recovery path (LokiJSAdapter-only). Please file an issue if you encounter this issue!</li> <li>[Typescript] Fixed type on OnFunction to accept <code>and</code> in join</li> <li>[Typescript] Fixed type <code>database#batch(records)</code>'s argument <code>records</code> to accept mixed types</li> </ul> <h3 id="internal-1"><a class="header" href="#internal-1">Internal</a></h3> <ul> <li>Added an experimental mode where a broken database state is detected, further mutations prevented, and the user notified</li> </ul> <h2 id="020---2020-10-05"><a class="header" href="#020---2020-10-05">0.20 - 2020-10-05</a></h2> <h3 id="breaking-changes-4"><a class="header" href="#breaking-changes-4">BREAKING CHANGES</a></h3> <p>This release has unintentionally broken RxJS for some apps using <code>with-observables</code>. If you have this issue, please update <code>@nozbe/with-observables</code> to the latest version.</p> <h3 id="new-features-4"><a class="header" href="#new-features-4">New features</a></h3> <ul> <li>[Sync] Conflict resolution can now be customized. See docs for more details</li> <li>[Android] Autolinking is now supported</li> <li>[LokiJS] Adapter autosave option is now configurable</li> </ul> <h3 id="changes-3"><a class="header" href="#changes-3">Changes</a></h3> <ul> <li>Interal RxJS imports have been refactor such that rxjs-compat should never be used now</li> <li>[Performance] Tweak Babel config to produce smaller code</li> <li>[Performance] LokiJS-based apps will now take up to 30% less time to load the database (id and unique indicies are generated lazily)</li> </ul> <h3 id="fixes-4"><a class="header" href="#fixes-4">Fixes</a></h3> <ul> <li>[iOS] Fixed crash on database reset in apps linked against iOS 14 SDK</li> <li>[LokiJS] Fix <code>Q.like</code> being broken for multi-line strings on web</li> <li>Fixed warn &quot;import cycle&quot; from DialogProvider (#786) by @gmonte.</li> <li>Fixed cache date as instance of Date (#828) by @djorkaeffalexandre.</li> </ul> <h2 id="019---2020-08-17"><a class="header" href="#019---2020-08-17">0.19 - 2020-08-17</a></h2> <h3 id="new-features-5"><a class="header" href="#new-features-5">New features</a></h3> <ul> <li>[iOS] Added CocoaPods support - @leninlin</li> <li>[NodeJS] Introducing a new SQLite Adapter based integration to NodeJS. This requires a peer dependency on <a href="https://github.com/JoshuaWise/better-sqlite3">better-sqlite3</a> and should work with the same configuration as iOS/Android - @sidferreira</li> <li>[Android] <code>exerimentalUseJSI</code> option has been enabled on Android. However, it requires some app-specific setup which is not yet documented - stay tuned for upcoming releases</li> <li>[Schema] [Migrations] You can now pass <code>unsafeSql</code> parameters to schema builder and migration steps to modify SQL generated to set up the database or perform migrations. There's also new <code>unsafeExecuteSql</code> migration step. Please use this only if you know what you're doing β€” you shouldn't need this in 99% of cases. See Schema and Migrations docs for more details</li> <li>[LokiJS] [Performance] Added experimental <code>onIndexedDBFetchStart</code> and <code>indexedDBSerializer</code> options to <code>LokiJSAdapter</code>. These can be used to improve app launch time. See <code>src/adapters/lokijs/index.js</code> for more details.</li> </ul> <h3 id="changes-4"><a class="header" href="#changes-4">Changes</a></h3> <ul> <li>[Performance] findAndObserve is now able to emit a value synchronously. By extension, this makes Relations put into withObservables able to render the child component in one shot. Avoiding the extra unnecessary render cycles avoids a lot of DOM and React commit-phase work, which can speed up loading some views by 30%</li> <li>[Performance] LokiJS is now faster (refactored encodeQuery, skipped unnecessary clone operations)</li> </ul> <h2 id="018---2020-06-30"><a class="header" href="#018---2020-06-30">0.18 - 2020-06-30</a></h2> <p>Another WatermelonDB release after just a week? Yup! And it's jam-packed full of features!</p> <h3 id="new-features-6"><a class="header" href="#new-features-6">New features</a></h3> <ul> <li> <p>[Query] <code>Q.on</code> queries are now far more flexible. Previously, they could only be placed at the top level of a query. See Docs for more details. Now, you can:</p> <ul> <li> <p>Pass multiple conditions on the related query, like so:</p> <pre><code class="language-js">collection.query( Q.on('projects', [ Q.where('foo', 'bar'), Q.where('bar', 'baz'), ]) ) </code></pre> </li> <li> <p>You can place <code>Q.on</code> deeper inside the query (nested inside <code>Q.and()</code>, <code>Q.or()</code>). However, you must explicitly list all tables you're joining on at the beginning of a query, using: <code>Q.experimentalJoinTables(['join_table1', 'join_table2'])</code>.</p> </li> <li> <p>You can nest <code>Q.on</code> conditions inside <code>Q.on</code>, e.g. to make a condition on a grandchild. To do so, it's required to pass <code>Q.experimentalNestedJoin('parent_table', 'grandparent_table')</code> at the beginning of a query</p> </li> </ul> </li> <li> <p>[Query] <code>Q.unsafeSqlExpr()</code> and <code>Q.unsafeLokiExpr()</code> are introduced to allow adding bits of queries that are not supported by the WatermelonDB query language without having to use <code>unsafeFetchRecordsWithSQL()</code>. See docs for more details</p> </li> <li> <p>[Query] <code>Q.unsafeLokiFilter((rawRecord, loki) =&gt; boolean)</code> can now be used as an escape hatch to make queries with LokiJSAdapter that are not otherwise possible (e.g. multi-table column comparisons). See docs for more details</p> </li> </ul> <h3 id="changes-5"><a class="header" href="#changes-5">Changes</a></h3> <ul> <li>[Performance] [LokiJS] Improved performance of queries containing query comparisons on LokiJSAdapter</li> <li>[Docs] Added Contributing guide for Query language improvements</li> <li>[Deprecation] <code>Query.hasJoins</code> is deprecated</li> <li>[DX] Queries with bad associations now show more helpful error message</li> <li>[Query] Counting queries that contain <code>Q.experimentalTake</code> / <code>Q.experimentalSkip</code> is currently broken - previously it would return incorrect results, but now it will throw an error to avoid confusion. Please contribute to fix the root cause!</li> </ul> <h3 id="fixes-5"><a class="header" href="#fixes-5">Fixes</a></h3> <ul> <li>[Typescript] Fixed types of Relation</li> </ul> <h3 id="internal-2"><a class="header" href="#internal-2">Internal</a></h3> <ul> <li><code>QueryDescription</code> structure has been changed.</li> </ul> <h2 id="0171---2020-06-24"><a class="header" href="#0171---2020-06-24">0.17.1 - 2020-06-24</a></h2> <ul> <li>Fixed broken iOS build - @mlecoq</li> </ul> <h2 id="017---2020-06-22"><a class="header" href="#017---2020-06-22">0.17 - 2020-06-22</a></h2> <h3 id="new-features-7"><a class="header" href="#new-features-7">New features</a></h3> <ul> <li> <p>[Sync] Introducing Migration Syncs - this allows fully consistent synchronization when migrating between schema versions. Previously, there was no mechanism to incrementally fetch all remote changes in new tables and columns after a migration - so local copy was likely inconsistent, requiring a re-login. After adopting migration syncs, Watermelon Sync will request from backend all missing information. See Sync docs for more details.</p> </li> <li> <p>[iOS] Introducing a new native SQLite database integration, rewritten from scratch in C++, based on React Native's JSI (JavaScript Interface). It is to be considered experimental, however we intend to make it the default (and eventually, the only) implementation. In a later release, Android version will be introduced.</p> <pre><code> The new adapter is up to 3x faster than the previously fastest `synchronous: true` option, however this speedup is only achieved with some unpublished React Native patches. To try out JSI, add `experimentalUseJSI: true` to `SQLiteAdapter` constructor. </code></pre> </li> <li> <p>[Query] Added <code>Q.experimentalSortBy(sortColumn, sortOrder)</code>, <code>Q.experimentalTake(count)</code>, <code>Q.experimentalSkip(count)</code> methods (only availble with SQLiteAdapter) - @Kenneth-KT</p> </li> <li> <p><code>Database.batch()</code> can now be called with a single array of models</p> </li> <li> <p>[DX] <code>Database.get(tableName)</code> is now a shortcut for <code>Database.collections.get(tableName)</code></p> </li> <li> <p>[DX] Query is now thenable - you can now use <code>await query</code> and <code>await query.count</code> instead of <code>await query.fetch()</code> and <code>await query.fetchCount()</code></p> </li> <li> <p>[DX] Relation is now thenable - you can now use <code>await relation</code> instead of <code>await relation.fetch()</code></p> </li> <li> <p>[DX] Exposed <code>collection.db</code> and <code>model.db</code> as shortcuts to get to their Database object</p> </li> </ul> <h3 id="changes-6"><a class="header" href="#changes-6">Changes</a></h3> <ul> <li>[Hardening] Column and table names starting with <code>__</code>, Object property names (e.g. <code>constructor</code>), and some reserved keywords are now forbidden</li> <li>[DX] [Hardening] QueryDescription builder methods do tighter type checks, catching more bugs, and preventing users from unwisely passing unsanitized user data into Query builder methods</li> <li>[DX] [Hardening] Adapters check early if table names are valid</li> <li>[DX] Collection.find reports an error more quickly if an obviously invalid ID is passed</li> <li>[DX] Intializing Database with invalid model classes will now show a helpful error</li> <li>[DX] DatabaseProvider shows a more helpful error if used improperly</li> <li>[Sync] Sync no longer fails if pullChanges returns collections that don't exist on the frontend - shows a warning instead. This is to make building backwards-compatible backends less error-prone</li> <li>[Sync] [Docs] Sync documentation has been rewritten, and is now closer in detail to a formal specification</li> <li>[Hardening] database.collections.get() better validates passed value</li> <li>[Hardening] Prevents unsafe strings from being passed as column name/table name arguments in QueryDescription</li> </ul> <h3 id="fixes-6"><a class="header" href="#fixes-6">Fixes</a></h3> <ul> <li>[Sync] Fixed <code>RangeError: Maximum call stack size exceeded</code> when syncing large amounts of data - @leninlin</li> <li>[iOS] Fixed a bug that could cause a database operation to fail with an (6) SQLITE_LOCKED error</li> <li>[iOS] Fixed 'jsi/jsi.h' file not found when building at the consumer level. Added path <code>$(SRCROOT)/../../../../../ios/Pods/Headers/Public/React-jsi</code> to Header Search Paths (issue #691) - @victorbutler</li> <li>[Native] SQLite keywords used as table or column names no longer crash</li> <li>Fixed potential issues when subscribing to database, collection, model, queries passing a subscriber function with the same identity more than once</li> </ul> <h3 id="internal-3"><a class="header" href="#internal-3">Internal</a></h3> <ul> <li>Fixed broken adapter tests</li> </ul> <h2 id="0151-0161-fix-0162---2020-06-03"><a class="header" href="#0151-0161-fix-0162---2020-06-03">0.15.1, 0.16.1-fix, 0.16.2 - 2020-06-03</a></h2> <p>This is a security patch for a vulnerability that could cause maliciously crafted record IDs to cause all or some of user's data to be deleted. More information available via GitHub security advisory</p> <h2 id="0161---2020-05-18"><a class="header" href="#0161---2020-05-18">0.16.1 - 2020-05-18</a></h2> <h3 id="changes-7"><a class="header" href="#changes-7">Changes</a></h3> <ul> <li><code>Database.unsafeResetDatabase()</code> is now less unsafe β€”Β more application bugs are being caught</li> </ul> <h3 id="fixes-7"><a class="header" href="#fixes-7">Fixes</a></h3> <ul> <li>[iOS] Fix build in apps using Flipper</li> <li>[Typescript] Added type definition for <code>setGenerator</code>.</li> <li>[Typescript] Fixed types of decorators.</li> <li>[Typescript] Add Tests to test Types.</li> <li>Fixed typo in learn-to-use docs.</li> <li>[Typescript] Fixed types of changes.</li> </ul> <h3 id="internal-4"><a class="header" href="#internal-4">Internal</a></h3> <ul> <li>[SQLite] Infrastruture for a future JSI adapter has been added</li> </ul> <h2 id="016---2020-03-06"><a class="header" href="#016---2020-03-06">0.16 - 2020-03-06</a></h2> <h3 id="-breaking"><a class="header" href="#-breaking">⚠️ Breaking</a></h3> <ul> <li><code>experimentalUseIncrementalIndexedDB</code> has been renamed to <code>useIncrementalIndexedDB</code></li> </ul> <h4 id="low-breakage-risk"><a class="header" href="#low-breakage-risk">Low breakage risk</a></h4> <ul> <li>[adapters] Adapter API has changed from returning Promise to taking callbacks as the last argument. This won't affect you unless you call on adapter methods directly. <code>database.adapter</code> returns a new <code>DatabaseAdapterCompat</code> which has the same shape as old adapter API. You can use <code>database.adapter.underlyingAdapter</code> to get back <code>SQLiteAdapter</code> / <code>LokiJSAdapter</code></li> <li>[Collection] <code>Collection.fetchQuery</code> and <code>Collection.fetchCount</code> are removed. Please use <code>Query.fetch()</code> and <code>Query.fetchCount()</code>.</li> </ul> <h3 id="new-features-8"><a class="header" href="#new-features-8">New features</a></h3> <ul> <li>[SQLiteAdapter] [iOS] Add new <code>synchronous</code> option to adapter: <code>new SQLiteAdapter({ ..., synchronous: true })</code>. When enabled, database operations will block JavaScript thread. Adapter actions will resolve in the next microtask, which simplifies building flicker-free interfaces. Adapter will fall back to async operation when synchronous adapter is not available (e.g. when doing remote debugging)</li> <li>[LokiJS] Added new <code>onQuotaExceededError?: (error: Error) =&gt; void</code> option to <code>LokiJSAdapter</code> constructor. This is called when underlying IndexedDB encountered a quota exceeded error (ran out of allotted disk space for app) This means that app can't save more data or that it will fall back to using in-memory database only Note that this only works when <code>useWebWorker: false</code></li> </ul> <h3 id="changes-8"><a class="header" href="#changes-8">Changes</a></h3> <ul> <li>[Performance] Watermelon internals have been rewritten not to rely on Promises and allow some fetch/observe calls to resolve synchronously. Do not rely on this -- external API is still based on Rx and Promises and may resolve either asynchronously or synchronously depending on capabilities. This is meant as a internal performance optimization only for the time being.</li> <li>[LokiJS] [Performance] Improved worker queue implementation for performance</li> <li>[observation] Refactored observer implementations for performance</li> </ul> <h3 id="fixes-8"><a class="header" href="#fixes-8">Fixes</a></h3> <ul> <li>Fixed a possible cause for &quot;Record ID xxx#yyy was sent over the bridge, but it's not cached&quot; error</li> <li>[LokiJS] Fixed an issue preventing database from saving when using <code>experimentalUseIncrementalIndexedDB</code></li> <li>Fixed a potential issue when using <code>database.unsafeResetDatabase()</code></li> <li>[iOS] Fixed issue with clearing database under experimental synchronous mode</li> </ul> <h3 id="new-features-experimental"><a class="header" href="#new-features-experimental">New features (Experimental)</a></h3> <ul> <li>[Model] Added experimental <code>model.experimentalSubscribe((isDeleted) =&gt; { ... })</code> method as a vanilla JS alternative to Rx based <code>model.observe()</code>. Unlike the latter, it does not notify the subscriber immediately upon subscription.</li> <li>[Collection] Added internal <code>collection.experimentalSubscribe((changeSet) =&gt; { ... })</code> method as a vanilla JS alternative to Rx based <code>collection.changes</code> (you probably shouldn't be using this API anyway)</li> <li>[Database] Added experimental <code>database.experimentalSubscribe(['table1', 'table2'], () =&gt; { ... })</code> method as a vanilla JS alternative to Rx-based <code>database.withChangesForTables()</code>. Unlike the latter, <code>experimentalSubscribe</code> notifies the subscriber only once after a batch that makes a change in multiple collections subscribed to. It also doesn't notify the subscriber immediately upon subscription, and doesn't send details about the changes, only a signal.</li> <li>Added <code>experimentalDisableObserveCountThrottling()</code> to <code>@rikishi/watermelondb/observation/observeCount</code> that globally disables count observation throttling. We think that throttling on WatermelonDB level is not a good feature and will be removed in a future release - and will be better implemented on app level if necessary</li> <li>[Query] Added experimental <code>query.experimentalSubscribe(records =&gt; { ... })</code>, <code>query.experimentalSubscribeWithColumns(['col1', 'col2'], records =&gt; { ... })</code>, and <code>query.experimentalSubscribeToCount(count =&gt; { ... })</code> methods</li> </ul> <h2 id="015---2019-11-08"><a class="header" href="#015---2019-11-08">0.15 - 2019-11-08</a></h2> <h3 id="highlights"><a class="header" href="#highlights">Highlights</a></h3> <p>This is a <strong>massive</strong> new update to WatermelonDB! πŸ‰</p> <ul> <li> <p><strong>Up to 23x faster sync</strong>. You heard that right. We've made big improvements to performance. In our tests, with a massive sync (first login, 45MB of data / 65K records) we got a speed up of:</p> <ul> <li>5.7s -&gt; 1.2s on web (5x)</li> <li>142s -&gt; 6s on iOS (23x)</li> </ul> <p>Expect more improvements in the coming releases!</p> </li> <li> <p><strong>Improved LokiJS adapter</strong>. Option to disable web workers, important Safari 13 fix, better performance, and now works in Private Modes. We recommend adding <code>useWebWorker: false, experimentalUseIncrementalIndexedDB: true</code> options to the <code>LokiJSAdapter</code> constructor to take advantage of the improvements, but please read further changelog to understand the implications of this.</p> </li> <li> <p><strong>Raw SQL queries</strong> now available on iOS and Android thanks to the community</p> </li> <li> <p><strong>Improved TypeScript support</strong> β€” thanks to the community</p> </li> </ul> <h3 id="-breaking-1"><a class="header" href="#-breaking-1">⚠️ Breaking</a></h3> <ul> <li>Deprecated <code>bool</code> schema column type is removed -- please change to <code>boolean</code></li> <li>Experimental <code>experimentalSetOnlyMarkAsChangedIfDiffers(false)</code> API is now removed</li> </ul> <h3 id="new-featuers"><a class="header" href="#new-featuers">New featuers</a></h3> <ul> <li> <p>[Collection] Add <code>Collection.unsafeFetchRecordsWithSQL()</code> method. You can use it to fetch record using raw SQL queries on iOS and Android. Please be careful to avoid SQL injection and other pitfalls of raw queries</p> </li> <li> <p>[LokiJS] Introduces new <code>new LokiJSAdapter({ ..., experimentalUseIncrementalIndexedDB: true })</code> option. When enabled, database will be saved to browser's IndexedDB using a new adapter that only saves the changed records, instead of the entire database.</p> <p><strong>This works around a serious bug in Safari 13</strong> (https://bugs.webkit.org/show_bug.cgi?id=202137) that causes large databases to quickly balloon to gigabytes of temporary trash</p> <p>This also improves performance of incremental saves, although initial page load or very, very large saves might be slightly slower.</p> <p>This is intended to become the new default option, but it's not backwards compatible (if enabled, old database will be lost). <strong>You're welcome to contribute an automatic migration code.</strong></p> <p>Note that this option is still experimental, and might change in breaking ways at any time.</p> </li> <li> <p>[LokiJS] Introduces new <code>new LokiJSAdapter({ ..., useWebWorker: false })</code> option. Before, web workers were always used with <code>LokiJSAdapter</code>. Although web workers may have some performance benefits, disabling them may lead to lower memory consumption, lower latency, and easier debugging. YMMV.</p> </li> <li> <p>[LokiJS] Added <code>onIndexedDBVersionChange</code> option to <code>LokiJSAdapter</code>. This is a callback that's called when internal IDB version changed (most likely the database was deleted in another browser tab). Pass a callback to force log out in this copy of the app as well. Note that this only works when using incrementalIDB and not using web workers</p> </li> <li> <p>[Model] Add <code>Model._dangerouslySetRawWithoutMarkingColumnChange()</code> method. You probably shouldn't use it, but if you know what you're doing and want to live-update records from server without marking record as updated, this is useful</p> </li> <li> <p>[Collection] Add <code>Collection.prepareCreateFromDirtyRaw()</code></p> </li> <li> <p>@json decorator sanitizer functions take an optional second argument, with a reference to the model</p> </li> </ul> <h3 id="fixes-9"><a class="header" href="#fixes-9">Fixes</a></h3> <ul> <li>Pinned required <code>rambdax</code> version to 2.15.0 to avoid console logging bug. In a future release we will switch to our own fork of <code>rambdax</code> to avoid future breakages like this.</li> </ul> <h3 id="improvements"><a class="header" href="#improvements">Improvements</a></h3> <ul> <li>[Performance] Make large batches a lot faster (1.3s shaved off on a 65K insert sample)</li> <li>[Performance] [iOS] Make large batch inserts an order of magnitude faster</li> <li>[Performance] [iOS] Make encoding very large queries (with thousands of parameters) 20x faster</li> <li>[Performance] [LokiJS] Make batch inserts faster (1.5s shaved off on a 65K insert sample)</li> <li>[Performance] [LokiJS] Various performance improvements</li> <li>[Performance] [Sync] Make Sync faster</li> <li>[Performance] Make observation faster</li> <li>[Performance] [Android] Make batches faster</li> <li>Fix app glitches and performance issues caused by race conditions in <code>Query.observeWithColumns()</code></li> <li>[LokiJS] Persistence adapter will now be automatically selected based on availability. By default, IndexedDB is used. But now, if unavailable (e.g. in private mode), ephemeral memory adapter will be used.</li> <li>Disabled console logs regarding new observations (it never actually counted all observations) and time to query/count/batch (the measures were wildly inaccurate because of asynchronicity - actual times are much lower)</li> <li>[withObservables] Improved performance and debuggability (update withObservables package separately