Dexie.js

A Minimalistic Wrapper for IndexedDB

APACHE-2.0 License

Downloads
2.2M
Stars
10.7K
Committers
98

Bot releases are visible (Hide)

Dexie.js - Dexie v3.2.0-rc.3

Published by dfahlander almost 3 years ago

This is probably the last release candidate before releasing a stable 3.2.0.

Changes

  • Switch to JS implementation of indexedDB.cmp() (PR #1412)
  • Let liveQuery() be type-wise compable with RxJS (PR #1417)

Fixed Bugs

  • Deleting multiple tables in a new version using null (#1418)
  • (Another) mysterious MissingAPI error (#1400)
Dexie.js - Dexie v3.2.0-rc.2

Published by dfahlander about 3 years ago

Two minor changes:

  1. Typings: Stop exporting Dexie as namespace. Enables VSCode's ergonomic auto-import feature for dexie. The namespace export was not even working as expected. The intent had been to support those that code Typescript without using modules. But even they must have been disappointed because the typings did not only reveal parts of the Dexie API.
  2. Bugfix: #1397 Safari 14 fix breaks fakeIndexedDB
Dexie.js - Dexie v3.2.0-rc.1

Published by dfahlander about 3 years ago

This release is candidate for a new stable dexie release with liveQuery() support.

Documentation is underway.

  • Official event Dexie.on('storagemutated')
  • Bugfix for #1381 Collection.delete() fails silently for queries on virtual indexes that use .filter().
  • PR #1379 fix(bulk-delete): correctly define keys type. Fixes #1364.
Dexie.js - Dexie v3.2.0-beta.3

Published by dfahlander about 3 years ago

Support for Chrome's transaction durability option in Dexie constructor

const db = new Dexie("TestDBTrans", { chromeTransactionDurability: 'relaxed' });

PR #1367

Dexie.js - Dexie v3.2.0-beta-2

Published by dfahlander over 3 years ago

Minor updates required for addons to integrate easier in db.on('ready') to give special (vip) access to the db while initial sync or authentication is still going on (before db.open() promise finally resolves, as it won't resolve until all db.on('ready') subscribers finish their work, but they themselves will need to interact with the db to finish their work).

We are still in beta until decided whether PR #1244 should be completed before determining the official API for the undocumented liveQuery() and txcommitted event.

Note however that the useLiveQuery() API is stable no matter where we decide with PR #1244 and the not yet settled API with the similar name liveQuery() that backs useLiveQuery ().

Dexie.js - Dexie v3.2.0-beta.1

Published by dfahlander over 3 years ago

This release contains the changes and bugfixes needed to make dexie-cloud-addon able do its job. Se details below.
Bumping middle version number due to subtle changes in a few API:s.

Using DBCore.transaction()

Before, we didn't call DBCore.transaction() internally to allow middlewares to intercept transaction creation. This PR corrects that and also added a second argument for which tables / object stores to include in the transaction. This allows for DBCore middlewares to inject code into both implicit and explicit transactions.

Supplying more information to DBCoreTable.mutate().

DBCoreMutateRequest has been extended with optional parameters criteria and changeSpec. This allows for middlewares to understand the intent of the mutation (which range-query that was the criteria for the change, and which properties that is meant to be updated). For Dexie Cloud, this feature makes it possible perform consistent operations across peers and maintain offline consistency for range- or index based calls to Collection.modify() and Collection.delete().

Bugfix in virtual index

Couldn't reuse parts of primary keys - only parts of indexes.

Safari workaround: Mutations in a service worker weren't propagated to liveQuery() in browser windows.

Dexie's liveQuery() functionality broadcasts changes using BroadcastChannel which is not supported on Safari. To workaround this, we've so far been using localStorage/onstorage to communicate changes across tabs. This workaround was eventually broken with the latest release of Safari where localStorage became broken when having multiple tabs open. Also the workarond didn't solve broadcasting changes between service worker and tabs/windows. This change makes mutations that are made in the service worker propagate to all service worker clients - which can be tabs/windows or other workers, so that liveQuery() observables will emit correctly when changes are made in the service worker - also on Safari. For other browsers, this hasn't been a problem.

Other changes:

  • Dexie.delete() specifies an empty addons list to ensure no addons are involved when deleting a database using that static method.
  • Correcting typescript Observable interface to better comply with RxJs.
  • Retiring old workaround for safari 8 bug not allowing array argument to IDBDatabase.transaction().
  • Allow multiple calls to Version.upgrade() on the same version - will run all of them instead just of the latest registered.
  • Argument to on.ready() callback will get a special Dexie instance that is not blocked (vip Dexie). This was the case also before but then we had to rely on zone state. This change makes it possible to perform non-dexie operations in on.read() callback (such as fetch()), loosing the zone state (PSD) but still have VIP access to the Dexie instance. This makes the code in a on.ready() callback not having to deal with wrapping all non-Dexie calls with Promise.resolve().
Dexie.js - Dexie v3.1.0-beta.13

Published by dfahlander over 3 years ago

Bugfix: Transaction.abort() does not rollback changes (filed as a repro PR in #1329)

  • Fixed in PR #1330
Dexie.js - Dexie 3.1.0-beta.12

Published by dfahlander over 3 years ago

Fix #1236 - problems updating FileSystemFileHandle properties.

Dexie.js - Dexie v3.1.0-beta.11

Published by dfahlander over 3 years ago

This release is just to mark the change of status from alpha to beta.
Will soon take a next step and release a version with stable state (to get useLiveQuery() out in the stable release).
Just need to take a decision on how to export { liveQuery } directly from dexie or via a new library.
See PR #1244. It would be best to avoid releasing a stable before letting #1244 be committed to avoid API changes.

Dexie.js - Dexie v3.1.0-alpha.10

Published by dfahlander over 3 years ago

This fix is highly recommended for all 3.1.0-alpha.x users as it contains the important fix for #1268.

Typing corrections

Fix version signatures (PR #1287)

Fixed bugs

#1268 Maximum call stack size exceeded (a bug introduced in Dexie 3.1.0-alpha.x)
#1280 Cannot add CryptoKeys to table with auto-incrementing primary key

Dexie.js - Dexie v3.1.0-alpha.9

Published by dfahlander over 3 years ago

Bugfixes:

  • liveQuery() / useLiveQuery(): Adding new object with indexed prop of the number 0 would not trigger observers even if zero is in the observed range. commit
  • liveQuery() / useLiveQuery(): Support for multiEntry indices. PR #1242
  • Dexie.getDatabaseNames(): Small optimization for our workaround for non-chromium browsers lacking the IDBFactory.databases(). commit.
Dexie.js - Dexie v3.1.0-alpha.8

Published by dfahlander over 3 years ago

Dexie.js - Dexie v3.1.0-alpha.7

Published by dfahlander over 3 years ago

Dexie.js -

Published by dfahlander almost 4 years ago

Two bugfixes:

To install:

npm i [email protected]
Dexie.js - Dexie v3.1.0-alpha.5

Published by dfahlander almost 4 years ago

Improved liveQuery

liveQuery() was explained in this blog post some weeks before this release.

The new liveQuery() and the corresponding react hook useLiveQuery() have been improved using a Btree structure to track and match queried ranges against mutated ranges on primary keys and indices.

This release improves liveQuery() in the following ways:

  • Live queries are more fine-grained. In previous version, index-based queries where always rerun on any mutation. Only primary key based queries were selectively re-run. In this version, index based queries only re-run when the mutation would affect the result of that query.

    // The following query will emit new results when todoItems on that todoList are updated.
    // ...but not if a todo item on another list is updated.
    // ...but if a todo item is moved into our out from the list, the query will also emit new result.
    liveQuery(()=> db.todoItems.where({todoListId: todoList.id}).toArray())
    
    // The following query will emit new results when friends within the age range are updated.
    // ...but not if a friend outside the range is updated.
    // ...but if a friend's age is changes (moved into range or out from range), it will also emit result.
    liveQuery(()=> db.friends.where('age').between(20, 20).toArray())
    
    // Key-only queries will not emit new results for property updates - only when key is change
    liveQuery(() => db.friends.where('age').between(20,30).keys())
    liveQuery(() => db.friends.where('age').between(20,30).primaryKeys())
    

    count() requests may still need to emit more often on Table.put() and Table.delete() operations as we cannot detect affected keys unless the mutation is a Table.add(), Table.update() or Collection.modify(), which gives more information to DBCore about the index values of the previous object in database.

  • Rx compatible (via Rx.from()).

    import * as Rx from "rxjs";
    import { map } from "rxjs/operators";
    import { liveQuery } from "dexie";
    
    const observable = Rx.from(liveQuery(
      () => db.friends.count()
    )).pipe(
      map(friendCount => friendCount + 1)
    );
    

Also

  • Code cleanup and optimizations.
  • Option {allKeys: true} to bulkPut() and bulkAdd() will be equally fast as not providing that option.
  • PR 1104: dbName follows dependencies.indexedDB (II)
Dexie.js - Dexie v3.1.0-alpha.4

Published by dfahlander almost 4 years ago

Observability broadcasted between tabs and workers

This version broadcasts txcommitted events between tabs and workers within same origin. It does so using BroadcastChannel so that not only tabs/windows are involved but also workers. This makes the built-in observability in Dexie a nice replacement for dexie-observable addon - and better, as that addon doesnt support workers, you will probably not need the dexie-observable addon anymore unless you use it as a base for dexie-syncable. Note also that dexie-observable slows down write performance a lot while the new built-in liveQuery feature does not.

Any part of an origin (a tab, a frame, a window, a web worker, shared worker or service worker) can observe the database no matter where the database was modified. Any thread can be either producer or consumer. If one peer writes to a Dexie instance, the other part can subscribe and get notified when something change.

Sparing DOM resources

Hidden tabs and minimized windows are not being bothered. Instead they get notified when they are visible again - with an accumulated result so nothing that had happened while being asleep will get lost.

Fallback to storage-event

The implementation falls back to using storage event and localStorage if browser doesnt support BroadcastChannel (Safari). The fallback implementation does only propagate changes across windows/tabs - not workers. It would however possible to make a standalone polyfill for BroadcastChannel that would support this for workers also. I currently don't know of any such polyfill except broadcastchannel-polyfill that currently not supports workers either. If I will have time I may complement it to support all kinds of workers as well as the structuring cloning.

Example

Worker

importScripts("https://unpkg.com/[email protected]");

const db = new Dexie('mydb');
db.version(1).stores({
  logItems: '++id'
});

// Write to DB now and then...
setInterval (()=>{
  db.logItems.add({foo: "bar", time: new Date()});
}, 1000);

Browser

import React from "react";
import Dexie from "dexie";
import { useLiveQuery } from "dexie-react-hooks";

const db = new Dexie('mydb');
db.version(1).stores({
  logItems: '++id'
});

function LogWatcherComponent({limit = 50}) {
  // Observe the last {limit} items in log:
  const logItems = useLiveQuery(
    () => db.logItems.reverse().limit(limit).toArray()
  );

  return <div>
    <h1>Log viewer</h1>
    <ul>
      {logItems.map(logItem => <li key={logItem.id}>
          {logItem.time.toLocaleTimeString()} {logItem.foo}
      </li>)}
    </ul>
  </div>;
}

Read more?

Awesome React integration coming (Blog post)

Stackblitz playground

Dexie.js - Dexie v3.1.0-alpha.3

Published by dfahlander almost 4 years ago

Just a bugfix for Dexie v3.1.0-alpha.1 and some typing corrections for dexie-react-hooks.

The big news are in Dexie v3.1.0-alpha.1!

Dexie.js - Dexie v3.1.0-alpha.1

Published by dfahlander almost 4 years ago

Dexie.js with Built-in observability

This version gives Dexie.js built-in observability which has been one of the Visions for dexie, earlier named db.observe().

It's called liveQuery() instead because it is not tied to a single db instance but it is capable of turning an expression or a async function with several statements and a final return value, into a observable (compatible with the es-observable spec).

import Dexie, { liveQuery } from "dexie";

// Turn any promise-returning function into an observable:
const observable = liveQuery(
  () => getFriendsWithContactInfos({minAge: 18, maxAge: 64})
);

// The function can do several requests in a flow and/or in paralell
// and finally return a result.
// The result is what is being observed:
async function getFriendsWithContactInfos ({minAge, maxAge}) {
  // Get all friends within range:
  const friends = await db.friends
    .where('age').between(minAge, maxAge, true, true)
    .toArray();

  // Map an array of contactInfos related to each friend:
  const contactInfos = await Promise.all(friends =>
    db.contactInfos.where({friendId: friend.id})
        .toArray()
  );

  // Put the resolved contactInfos as an array prop on each friend to return
  friends.forEach((friend, idx) => friend.contactInfos = contactInfos[idx]);
  return friends; // This result is what will be observed by the observable.
}

Ok, so now we have an observable of this. Let's subscribe to it:

const subscription = observable.subscribe({
  next: result => console.log("Got result:", result),
  error: console.error
});

Lets update something that would affect the result of the query:

db.contactInfos.add({friendId: 2, type: "phoneNo", value: "1234567"});

When the above statement has been successfully committed to the DB, the function will re-execute if and only if friend with id 2 is within the queried age range (!), and our subscriber will be called with the new result of the callback.

The main reason for this new feature is better integration with frontend libraries like angular and react.
Especially for react, I've also release a new library dexie-react-hooks with the hook useLiveQuery() that will make data reactive data-fetching from IndexedDB very easy. Angular uses observables natively - so probably our ES-compliant observable can be used as it is.

A new library dexie-react-hooks

This library integrates React with the new liveQuery functionality described above

export function useLiveQuery<T, TDefault=undefined> (
  querier: () => Promise<T> | T,
  deps?: any[], // ...like deps for useMemo(). Defaults to empty array.
  defaultResult?: TDefault // Default value returned while data is loading
) : T | TDefault;

Example

const db = new Dexie('news-db');
db.version(1).stores({
  articles: '++id, title',
  articleLikes: '[articleId+userId]'
});

function MyComponent({articleId, currentUser}) {
  const article = useLiveQuery(() => db.articles.get(articleId), [articleId]);
  const numLikes = useLiveQuery(() => db.articleLikes.where({articleId: articleId}).count(), [articleId]);
  return <>
    <Article article={article} numLikes={numLikes} />
    <button onClick={() => db.articleLikes.put({userId: currentUser.id, articleId})}>
      Like! {/* clicking button will increase like count if current user hadnt liked it before */}
    </button>
  </>;
}

See more examples in dexie-react-hooks

Dexie.js - Dexie v3.0.3

Published by dfahlander almost 4 years ago

Changes since 3.0.2

This release contains fixes that improves error resilience, typing correctness and bug fixes for some edge cases.

Typing fixes

  • Fix Table.bulkGet return typing to include undefined #1098
  • Allow readonly arrays for bulk put & get methods #1106
  • Use error keys insted of values for typescript #1115

NOTE: Conditional types is now being used in dist/dexie.d.ts. If you are on an ancient typescript version (below 2.8) you will need to update typescript in your dev deps!

Improvements

  • Verify schema on open #1108
  • Repro + resolve issue #1112: typescript declaration of id makes autoInc fail #1119
  • #1136: Allow declaration-only tables for TS users

Bugfixes

  • Allow middleware hooks to return objects that contained field names that contain dotted strings #1130
  • Resolve #1127 #1131
  • #1146: Resolve #1145 Regression: SchemaError during version upgrade
  • Bugfix of #1154 (PR #1155): WhereClause.equals(undefined) should fail, but it does not fail in dexie 3.0.0-3.0.2. It behaved correctly in dexie 2.x so it's a regression. It is important that libraries fail on invalid arguments so that subtle application bugs are nailed down more easily.

Addons

  • Issue 1048 Typings of addons for Dexie 3.0 #1117
    The addons are released with the "next" tag on npm, so please test them and help me verify that #1048 is solved:
    npm i [email protected]
    npm i [email protected]
    
  • #1138: Dexie.Observable: startObserving function: remove read-only query in order to avoid TransactionInactiveError
  • Bugfix of #1148 (PR #1149).
Dexie.js -

Published by dfahlander almost 4 years ago

Bugfix of #1154 (PR #1155): WhereClause.equals(undefined) should fail, but it does not fail in dexie 3.0.0-3.0.2. It behaved correctly in dexie 2.x so it's a regression. It is important that libraries fail on invalid arguments so that subtle application bugs are nailed down more easily.