Skip to content

A service that wraps IndexedDB database in an Angular service. It exposes very simple observables API to enable the usage of IndexedDB without most of it plumbing.

License

Notifications You must be signed in to change notification settings

assuncaocharles/ngx-indexed-db

Repository files navigation

ngx-indexed-db

All Contributors

Known Vulnerabilities CodeFactor Build Status CI

ngx-indexed-db is a service that wraps IndexedDB database in an Angular service combined with the power of observables.

Installation

$ npm install ngx-indexed-db

OR

$ yarn add ngx-indexed-db

Usage

Import the NgxIndexedDBModule and set up it:

import { NgxIndexedDBModule, DBConfig } from 'ngx-indexed-db';

const dbConfig: DBConfig  = {
  name: 'MyDb',
  version: 1,
  objectStoresMeta: [{
    store: 'people',
    storeConfig: { keyPath: 'id', autoIncrement: true },
    storeSchema: [
      { name: 'name', keypath: 'name', options: { unique: false } },
      { name: 'email', keypath: 'email', options: { unique: false } }
    ]
  }]
};

@NgModule({
  ...
  imports: [
    ...
    NgxIndexedDBModule.forRoot(dbConfig)
  ],
  ...
})

Migrations

import { NgxIndexedDBModule, DBConfig } from 'ngx-indexed-db';

// Ahead of time compiles requires an exported function for factories
export function migrationFactory() {
  // The animal table was added with version 2 but none of the existing tables or data needed
  // to be modified so a migrator for that version is not included.
  return {
    1: (db, transaction) => {
      const store = transaction.objectStore('people');
      store.createIndex('country', 'country', { unique: false });
    },
    3: (db, transaction) => {
      const store = transaction.objectStore('people');
      store.createIndex('age', 'age', { unique: false });
    }
  };
}

const dbConfig: DBConfig  = {
  name: 'MyDb',
  version: 3,
  objectStoresMeta: [{
    store: 'people',
    storeConfig: { keyPath: 'id', autoIncrement: true },
    storeSchema: [
      { name: 'name', keypath: 'name', options: { unique: false } },
      { name: 'email', keypath: 'email', options: { unique: false } }
    ]
  }, {
    // animals added in version 2
    store: 'animals',
    storeConfig: { keyPath: 'id', autoIncrement: true },
    storeSchema: [
      { name: 'name', keypath: 'name', options: { unique: true } },
    ]
  }],
  // provide the migration factory to the DBConfig
  migrationFactory
};

@NgModule({
  ...
  imports: [
    ...
    NgxIndexedDBModule.forRoot(dbConfig)
  ],
  ...
})

NgxIndexedDB service

Import and inject the service:

import { NgxIndexedDBService } from 'ngx-indexed-db';

...
  export class AppComponent {
    constructor(private dbService: NgxIndexedDBService){
    }
  }

API

We cover several common methods used to work with the IndexedDB

add(storeName: string, value: T, key?: any): Observable<T & {id: any}>

Adds new entry in the store and returns item added

  • @param storeName The name of the store to add the item
  • @param value The entry to be added
  • @param key The optional key for the entry

It publishes in the observable the key value of the entry

this.dbService
  .add('people', {
    name: `Bruce Wayne`,
    email: `bruce@wayne.com`,
  })
  .subscribe((key) => {
    console.log('key: ', key);
  });

In the previous example I'm using undefined as the key because the key is configured in the objectStore as auto-generated.

bulkAdd(storeName: string, values: Array<T & { key?: any }>): Observable<number[]>

Adds new entries in the store and returns its key

  • @param storeName The name of the store to add the item
  • @param values The entries to be added containing optional key attribute
this.dbService
  .bulkAdd('people', [
    {
      name: `charles number ${Math.random() * 10}`,
      email: `email number ${Math.random() * 10}`,
    },
    {
      name: `charles number ${Math.random() * 10}`,
      email: `email number ${Math.random() * 10}`,
    },
  ])
  .subscribe((result) => {
    console.log('result: ', result);
  });

bulkDelete(storeName: string, keys: Key[]): Observable<number[]>

Delete multiple items in the store

  • @param storeName The name of the store to delete the items
  • @param keys The entries keys to be deleted
  this.dbService.bulkDelete('people', [5, 6]).subscribe((result) => {
    console.log('result: ', result);
  });

bulkGet(storeName: string, keys: Array): Observable<T[]>

Retrieve multiple entries in the store

  • @param storeName The name of the store to retrieve the items
  • @param keys The ids entries to be retrieve
this.dbService.bulkGet('people', [1, 3, 5]).subscribe((result) => {
    console.log('results: ', result);
  });

bulkPut(storeName: string, values: Array<T & { key?: any }>): Observable<number[]>

Adds or updates a record in store with the given value and key. Return all items present in the store

  • @param storeName The name of the store to update
  • @param items The values to update in the DB

@Return The return value is an Observable with the primary key of the object that was last in given array

@error If the call to bulkPut fails the transaction will be aborted and previously inserted entities will be deleted

this.dbService.bulkPut('people', people).subscribe((result) => {
  console.log('result: ', result);
});

update(storeName: string, value: T): Observable<T[]>

Adds or updates a record in store with the given value and key. Return item updated

  • @param storeName The name of the store to update
  • @param value The new value for the entry
this.dbService
  .update('people', {
    id: 1,
    email: 'luke@skywalker.com',
    name: 'Luke Skywalker',
  })
  .subscribe((storeData) => {
    console.log('storeData: ', storeData);
  });

getByKey(storeName: string, key: IDBValidKey): Observable

Returns entry by key.

  • @param storeName The name of the store to query
  • @param key The entry key
this.dbService.getByKey('people', 1).subscribe((people) => {
  console.log(people);
});

getAll(storeName: string): Observable<T[]>

Return all elements from one store

  • @param storeName The name of the store to select the items
this.dbService.getAll('people').subscribe((peoples) => {
  console.log(peoples);
});

getByIndex(storeName: string, indexName: string, key: IDBValidKey): Observable

Returns entry by index.

  • @param storeName The name of the store to query
  • @param indexName The index name to filter
  • @param key The entry key.
this.dbService.getByIndex('people', 'name', 'Dave').subscribe((people) => {
  console.log(people);
});

createObjectStore(storeSchema: ObjectStoreMeta, migrationFactory?: () => { [key: number]: (db: IDBDatabase, transaction: IDBTransaction) => void }): void

Allows to crate a new object store ad-hoc

  • @param storeName The name of the store to be created
  • @param migrationFactory The migration factory if exists
const storeSchema: ObjectStoreMeta = {
  store: 'people',
  storeConfig: { keyPath: 'id', autoIncrement: true },
  storeSchema: [
    { name: 'name', keypath: 'name', options: { unique: false } },
    { name: 'email', keypath: 'email', options: { unique: false } },
  ],
};

this.dbService.createObjectStore(storeSchema);

count(storeName: string, keyRange?: IDBValidKey | IDBKeyRange): Observable

Returns the number of rows in a store.

  • @param storeName The name of the store to query
  • @param keyRange The range value and criteria to apply.
this.dbService.count('people').subscribe((peopleCount) => {
  console.log(peopleCount);
});

deleteObjectStore(storeName: string): Observable

Delete the store by name, return true or false.

  • @param storeName The name of the store to query
this.dbService.deleteObjectStore(this.storneNameToDelete);

delete(storeName: string, key: Key): Observable<T[]>

Returns all items from the store after delete.

  • @param storeName The name of the store to have the entry deleted
  • @param key The key of the entry to be deleted
this.dbService.delete('people', 3).subscribe((allPeople) => {
  console.log('all people:', allPeople);
});

deleteByKey(storeName: string, key: Key): Observable

Returns true if the delete completes successfully.

  • @param storeName The name of the store to have the entry deleted
  • @param key The key of the entry to be deleted
this.dbService.deleteByKey('people', 3).subscribe((status) => {
  console.log('Deleted?:', status);
});

openCursor(storeName: string, keyRange?: IDBKeyRange, direction?: IDBCursorDirection): Observable

Returns the open cursor event

  • @param storeName The name of the store to have the entries deleted
  • @param keyRange The key range which the cursor should be open on
  • @param direction IDB Cursor Direction to work with, default to next
this.dbService.openCursor('people', IDBKeyRange.bound("A", "F")).subscribe((evt) => {
    var cursor = (evt.target as IDBOpenDBRequest).result;
    if(cursor) {
        console.log(cursor.value);
        cursor.continue();
    } else {
        console.log('Entries all displayed.');
    }
});

openCursorByIndex(storeName: string, indexName: string, keyRange: IDBKeyRange, direction?: IDBCursorDirection, mode?: DBMode): Observable

Open a cursor by index filter.

  • @param storeName The name of the store to query.
  • @param indexName The index name to filter.
  • @param keyRange The range value and criteria to apply on the index.
  • @param direction IDB Cursor Direction to work with, default to next
  • @param mode DB Mode to work with, default to readonly
this.dbService.openCursorByIndex('people', 'name', IDBKeyRange.only('john')).subscribe((evt) => {
    var cursor = (evt.target as IDBOpenDBRequest).result;
    if(cursor) {
        console.log(cursor.value);
        cursor.continue();
    } else {
        console.log('Entries all displayed.');
    }
});

getAllByIndex(storeName: string, indexName: string, keyRange: IDBKeyRange): Observable<T[]>

Returns all items by an index.

  • @param storeName The name of the store to query
  • @param indexName The index name to filter
  • @param keyRange The range value and criteria to apply on the index.
this.dbService.getAllByIndex('people', 'name', IDBKeyRange.only('john')).subscribe((allPeopleByIndex) => {
  console.log('All: ', allPeopleByIndex);
});

getDatabaseVersion(): Observable

Returns the current database version.

this.dbService.getDatabaseVersion().pipe(
  tap(response => console.log('Versione database => ', response)),
  catchError(err => {
    console.error('Error recover version => ', err);
    return throwError(err);
  })
).subscribe();

clear(storeName: string): Observable

Returns true if successfully delete all entries from the store.

  • @param storeName The name of the store to have the entries deleted
this.dbService.clear('people').subscribe((successDeleted) => {
  console.log('success? ', successDeleted);
});

deleteDatabase(): Observable

Returns true if successfully delete the DB.

this.dbService.deleteDatabase().subscribe((deleted) => {
  console.log('Database deleted successfully: ', deleted);
});

License

Released under the terms of the MIT License.

Contributors ✨

Thanks goes to these wonderful people (emoji key):


Angelo Parziale

🚧 💻

Charles Assunção

💻 📖 🚧

coolweb

🚧

This project follows the all-contributors specification. Contributions of any kind welcome!