0.4.0 • Published 7 years ago

@digitallinguistics/db-js v0.4.0

Weekly downloads
-
License
MIT
Repository
github
Last release
7 years ago

DLx Database Client

A client-side JavaScript library that connects to both IndexedDB and the DLx REST API, allowing users to sync DLx data between the browser and the cloud database. This library uses web sockets to retrieve changes to the user's data in real time, keeping the local version of the database in sync with the cloud database. When making requests to the database, each operation is first performed on a local IndexedDB database, and then sent to the server. This library also works when the user goes offline as well, waiting for connectivity to be restored before syncing, and making several sync attempts before it stops.

Notes

  • If your app only needs to store data locally, use the idb library instead.

  • If your app only needs to store data on the server, use the api-js library instead.

  • All asynchronous methods support both Promises and callbacks - simply provide the callback as the last argument to the function.

Installation

If using npm:

npm i --save @digitallinguistics/db-js

If using yarn:

yarn add @digitallinguistics/db-js

You can also include the db-js script in your page using the DLx CDN.

<script src=https://cdn.digitallinguistics.io/scripts/db.js></script>

Or download the script manually:

curl https://cdn.digitallinguistics.io/scripts/db.js -o db.js

The DLx database client also requires three dependencies, which you should include in your HTML before db-js in the following order:

  1. dlx-js
  • npm / yarn: @digitallinguistics/dlx-js
  • CDN: https://cdn.digitallinguistics.io/scripts/dlx.js/
  1. idb
  • npm / yarn: @digitallinguistics/idb
  • CDN: https://cdn.digitallinguistics.io/scripts/idb.js
  1. api-js
  • npm / yarn: @digitallinguistics/api-js
  • CDN: https://cdn.digitallinguistics.io/scripts/api.js

Including the Scripts on Your Page

The db-js library may be used either as a module (all module types are supported, including ES6) or a regular script. If using the library as a regular script, DLxDB will be made available as a global variable, and the client class will be accessible on DLxDB.default.

Using ES6 modules:

import DatabaseClient from './db.js';

Using CommonJS modules:

const DatabaseClient = require('./db.js');

As a regular script:

<!-- required dependencies -->
<script src=dlx.js></script>
<script src=idb.js></script>
<script src=api.js></script>

<!-- database client (this library) -->
<script src=db.js></script>

<!-- initialize the client -->
<script>
  const DatabaseClient = DLxDB.default;
</script>

It is strongly recommended that you include specific versions of the necessary scripts, rather than the latest version:

<script src=https://cdn.digitallinguistics.io/scripts/dlx-2.0.0.js></script>
<script src=https://cdn.digitallinguistics.io/scripts/idb-2.0.0.js></script>
<script src=https://cdn.digitallinguistics.io/scripts/api-2.0.0.js></script>
<script src=https://cdn.digitallinguistics.io/scripts/db-2.0.0.js></script>

Initializing the Database Client

To create a new database client, provide your application's client ID and client secret as options, along with your redirect URI. These will be used to retrieve an access token for sending requests to the DLx API. (If you have not yet registered your application with the DLx API and received a client ID and client secret, read the API documentation for details on how to do so.)

const db = new DatabaseClient({
  clientId:     '6d38028e-5161-47df-8652-95d1ac8e915f',
  clientSecret: 'f36557c1-38d7-4f96-9400-95f5fce8b685',
  redirect:     'https://mydomain.com/callback',
});

If you already have an access token, you may provide that instead:

const db = new DatabaseClient({ token: 'eyJhb...7HgQ' });

You can also specify whether a client instance should save data online, offline, or both by including one of those three values in the store option (default is both). You can change this setting at any time (by changing the value of DBClient.store) without needing to create a new client.

The autoSync option will tell the database client to listen for updates on the server, and automatically keep local data synchronized. Defaults to true.

View the documentation for the DatabaseClient for more options. (Click on Modules at the top of the page, and then DatabaseClient.)

Connecting to the Database & Authenticating with the API

Once the client is initialized, call db.connect() to connect to the socket and IndexedDB. This will return a Promise that resolves when the client is connected.

Before you can make a request to the database, you will need to authenticate your application. This is as easy as calling the .authenticate() method, which returns a Promise when authentication is complete. If the client is not already connected, it will be connected during authentication. If you have not yet retrieved an access token, the client will attempt to retrieve one for you. This may involve your application being redirected to a user login page.

db.authenticate()
.then(() => {
  /* begin making requests */
});

Making Requests to the Database

Once you are authenticated with the API, your application may begin making requests to the database. The client has methods for each type of operation on the database. For example, each of the following methods is available for Language items:

  • addLanguage()
  • deleteLanguage()
  • getLanguage()
  • getLanguages()
  • updateLanguage()
  • upsertLanguage()

Each method returns a Promise that resolves to the database response.

You can also use the more generic add(), delete(), get(), getAll(), update(), and upsert() methods if you wish.

View the documentation for a complete list of methods available on the database client. (Click on Modules at the top of the page, and then DatabaseClient.)

The DatabaseClient also provides access to the underlying IndexedDB client and web socket if you need to access them directly:

Events Emitted by the Database

Each time data in the database is modified, the client emits an event indicating the type of operation that was performed on the database, and the ID of the affected data. This event is emitted only after the database operation has been performed on both the local database and the server. Once your application receives the event notification, it can decide whether it needs to make a request for the updated data. This is useful for ensuring that the data in your current view stays in sync with the database.

The following events are emitted by the Socket API. These events are always emitted along with the ID of the affected item.

EventDescription
addA new item was added to the database
deleteAn item was deleted
updateA partial update was performed on the item
upsertAn item was upserted (added or replaced)
errorEmitted when any error occurs outside of a Promise callback

Your application should add listeners for each of these events, like so:

// this event will be emitted every time a new item is added to the database
db.on('add', id => {
  db.get(ID, (err, res) => { /* do something with the new data */ });
});

You can also listen to events on the underlying API client. It is recommended you listen for the error, authenticated, and unauthenticated events and respond to them as appropriate.

The DatabaseClient also has all the standard Emitter methods:

  • .emit()
  • .hasListeners
  • .listeners
  • .off()
  • .on()
  • .once()

Synchronizing the Database

While your application is running, the db-js library will attempt to automatically keep data synchronized between the local IndexedDB and the cloud database (unless the autoSync option is set to false). However, when your the user leaves the page, the local database can no longer receive updates from the server, until the user returns to that page again. In addition, if your application goes offline, some data may never be received from the server. Because of this, db-js provides two ways to sync data manually between the browser and the server: .sync() and .syncAll().

  • .sync(): Synchronizes any changes that were made either locally or on the server since the time of the last sync. The time of last sync should be provided as the lastSync option. Note: This does not synchronize all publicly-available data from the cloud database, just the items that the currently-authenticated user is listed as a Owner, Contributor, or Viewer for, or already has stored in their local database.

  • .syncAll(): Performs a complete synchronization of all items in the database. Note: This does not synchronize all publicly-available data from the cloud database, just the items that the currently-authenticated user is listed as a Owner, Contributor, or Viewer for, or already has stored in their local database.

If a sync conflict occurs, the server version will override the local version, but a local copy of the original data is made in IndexedDB with a different ID.

Handling Errors

You can add a generic error handler to listen for errors after the client is connected:

db.connect()
.then(() => db.on('error', console.error));

Otherwise, most errors will be returned in the callback function you provided when emitting an event. For example:

db.getLanguage(`12345`, (err, res) => {
  if (err) /* handle error */
  else /* do something with the response */
});

Want to Contribute?

Check out DLx's general contributing guidelines.

Maintainers

This repo is maintained by:

0.4.0

7 years ago

0.3.0

7 years ago

0.2.1

7 years ago

0.2.0

7 years ago

0.1.15

7 years ago

0.1.14

7 years ago

0.1.13

7 years ago

0.1.11

7 years ago

0.1.10

7 years ago

0.1.9

7 years ago

0.1.8

7 years ago

0.1.7

7 years ago

0.1.6

7 years ago

0.1.5

7 years ago

0.1.4

7 years ago

0.1.3

7 years ago

0.1.2

7 years ago

0.1.1

7 years ago