@pvermeer/dexie-rxjs-addon
TypeScript icon, indicating that this package has built-in type declarations

1.1.1 • Public • Published

Dexie RxJs Addon

NPM Version NPM Version master lerna Conventional Commits

This addon can be used as a stand-alone addon for Dexie.js yet is also part of dexie-addon-suite NPM Version that combines a number of addons for Dexie. It contains code to combine some addons like populated rxjs observables.

Install over npm

npm install @pvermeer/dexie-rxjs-addon rxjs

Dependencies

rxjs: https://rxjs-dev.firebaseapp.com/

Dexie.js: Dexie RxJs Addon depends on Dexie.js v3. NPM Version

npm install dexie

Documentation

Extend RxJs to your Dexie Database!

Plugin is written to extend Dexie.js with your own RxJs by adding methods and properties to the Dexie classes. RxJs is not bundled so you can use your own implementation.

This addon implements the Dexie.Observable addon to detect changes.

How to use

Addon

Add dexieRxjs() to your Dexie database. See below examples and https://dexie.org for more info.

changes$

On the Dexie database itself you can get an observable for all changes. It reflects the Dexie.Observable addon. See https://dexie.org/docs/Observable/Dexie.Observable for more info.

interface Database {
  /**
   * Get on('changes') from 'dexie-observable' as an RxJs observable and observe changes.
   * @link https://dexie.org/docs/Observable/Dexie.Observable
   */
  changes$: Observable<import("dexie-observable/api").IDatabaseChange[]>;
}

Table.$

The Dexie Tables are extended with $ property. This returns a ObservableTable with many normal Table methods but now they return Observable instead of a DexiePromise.

interface TableExtended<T, TKey> {
  $: ObservableTable<T, TKey>;
}

ObservableTable

Instead of the Dexie.Table an ObservableTable is returned after using $.

class ObservableTable<T, TKey> {
  /**
   * Observable stream of table changes.
   * Emits updated value on changes.
   * @note Stays open so unsubscribe.
   */
  public changes(): Observable<IDatabaseChange[]>;
  /**
   * Create an Observable Collection of this table.
   */
  public toCollection(): ObservableCollection<T, TKey>;
  /**
   * Observable stream of the complete Table.
   * Emits updated Table array on changes.
   * @note Stays open so unsubscribe.
   */
  public toArray(): Observable<T[]>;
  /**
   * Observable stream of a get request.
   * Emits updated value on changes.
   * @note Stays open so unsubscribe.
   */
  public get(
    keyOrequalityCriterias:
      | TKey
      | {
          [key: string]: any;
        }
  ): Observable<T | undefined>;
  /**
   * Observable stream of a where query.
   * Emits updated values on changes, including new or updated records that are in range.
   * @return ObservableWhereClause that behaves like a normal Dexie where-clause or an ObservableCollection.
   * @note Stays open so unsubscribe.
   */
  public where(index: string | string[]): ObservableWhereClause<T, TKey>;
  public where(equalityCriterias: {
    [key: string]: IndexableType;
  }): ObservableCollection<T, TKey>;
  /**
   * Observable stream of the complete Table orderd by indexed key.
   * Emits updated Table array on changes.
   * @note Stays open so unsubscribe.
   */
  public orderBy(index: string | string[]): ObservableCollection<T, TKey> {
    const collection = this._table.orderBy(
      Array.isArray(index) ? `[${index.join("+")}]` : index
    );
    const observableCollection = new ObservableCollection(
      this._db,
      this._table,
      collection
    );
    return observableCollection;
  }
  /**
   * Observable stream of the complete Table count.
   * Emits updated new number on changes.
   * @note Stays open so unsubscribe.
   */
  public count(): Observable<number> {
    const count$ = this.toCollection().count();
    return count$;
  }

  // Mapped Dexie Table methods
  public filter: (
    ...args: Parameters<Table["filter"]>
  ) => ObservableCollection<T, TKey>;
  public offset: (
    ...args: Parameters<Table["offset"]>
  ) => ObservableCollection<T, TKey>;
  public limit: (
    ...args: Parameters<Table["limit"]>
  ) => ObservableCollection<T, TKey>;
  public reverse: (
    ...args: Parameters<Table["reverse"]>
  ) => ObservableCollection<T, TKey>;
}

Example

import { Subscription } from "rxjs";

const subs = new Subscription();

const friends = get20Friends(); // Array of 20 friends
await db.friends.bulkAdd(Friends);

const friend$ = await db.friends.$.get(1);
const table$ = await db.friends.$.toArray();
const friends$ = await db.friends.$.where(":id").anyOf([1, 13]).toArray();

const noFriends$ = await db.friends.$.where(":id").equals(99).toArray();
const lateFriend$ = await db.friends.$.where("customId").equals(4556).toArray();

// All observables emit on subscribe
subs.add(
  // Logs friend with id 1
  friend$.subscribe((friend) => {
    console.log(friend);
  })
);
subs.add(
  // Logs all 20 friends []
  table$.subscribe((friends) => {
    console.log(friends);
  })
);
subs.add(
  // Logs only friends with id 1 and 13 []
  friends$.subscribe((friends) => {
    console.log(friends);
  })
);
subs.add(
  // Logs empty array, does not emit until a friend with id 99 is added to the table
  noFriends$.subscribe((friends) => {
    console.log(friends);
  })
);
subs.add(
  // Logs empty array, does not emit until a friend with customId 4556 is added to the table
  lateFriend$.subscribe((friends) => {
    console.log(friends);
  })
);

await db.friends.update(1, { name: "Testie" });
// Expect only friend$, table$, friends$ to log their updated results.

await db.friends.add({ customId: 4556 });
// Expect only table$ and lateFriend$ to log their results.

// Don't forget to unsubscribe when done! (many ways to handle this, see RxJs documentation and guides / blogs)
subs.unsubscribe();

Load the addon

Example (ESM)

import Dexie from "dexie";
import { dexieRxjs } from "@pvermeer/dexie-rxjs-addon";

// Declare Database
const db = new Dexie("FriendDatabase", {
  addons: [dexieRxjs],
});
db.version(1).stores({ friends: "++id, name, shoeSize, age" });

// Open the database
db.open().then(() => {
  console.log("DB loaded! :D");
  // Use Dexie
});

Example (Typescript)

import Dexie from "dexie";
import { dexieRxjs } from "@pvermeer/dexie-rxjs-addon";

interface Friend {
  id?: number;
  name?: string;
  shoeSize?: number;
  age?: number;
}

// Declare Database
class FriendsDatabase extends Dexie {
  public friends: Dexie.Table<Friend, string>;
  constructor(name: string) {
    super(name);
    dexieRxjs(this);
    this.version(1).stores({
      friends: "++id, name, shoeSize, age",
    });
  }
}

const db = new FriendDatabase("FriendsDatabase");

// Open the database
db.open().then(() => {
  console.log("DB loaded! :D");
  // Use Dexie
});

Example (HTML import)

Bundled & minified package: https://unpkg.com/@pvermeer/dexie-rxjs-addon@latest/dist/dexie-rxjs-addon.min.js.

Addon is exported as namespace DexieRxjsAddon

<!DOCTYPE html>
<html>
  <head>
    <!-- Include Dexie -->
    <script src="https://unpkg.com/dexie@latest/dist/dexie.js"></script>

    <!-- Include RxJs -->
    <script src="https://unpkg.com/rxjs/dist/bundles/rxjs.umd.min.js"></script>

    <!-- Include DexieRxjsAddon (always after dependencies) -->
    <script src="https://unpkg.com/@pvermeer/dexie-rxjs-addon@latest/dist/dexie-rxjs-addon.min.js"></script>

    <script>
      // Define your database
      const db = new Dexie("FriendDatabase", {
        addons: [DexieRxjsAddon.dexieRxjs],
      });
      db.version(1).stores({ friends: "++id, name, shoeSize, age" });

      // Open the database
      db.open().then(() => {
        console.log("DB loaded! :D");
        // Do Dexie stuff
      });
    </script>
  </head>
</html>

API

The packet exposes a single export:

function dexieRxjs(db: Dexie): void;

Also exports some other classes and types to support further extension. See declaration or source.


Dexie.js

Dexie.js is a wrapper library for indexedDB - the standard database in the browser. http://dexie.org

Package Sidebar

Install

npm i @pvermeer/dexie-rxjs-addon

Weekly Downloads

232

Version

1.1.1

License

MIT

Unpacked Size

827 kB

Total Files

22

Last publish

Collaborators

  • pvermeer