Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/assuncaocharles/ngx-indexed-db

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.
https://github.com/assuncaocharles/ngx-indexed-db

hacktoberfest indexeddb schema storage

Last synced: 5 days ago
JSON representation

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.

Awesome Lists containing this project

README

        

# ngx-indexed-db

[![All Contributors](https://img.shields.io/badge/all_contributors-3-orange.svg?style=flat-square)](#contributors-)

[![Known Vulnerabilities](https://snyk.io/test/github/assuncaocharles/ngx-indexed-db/badge.svg)](https://snyk.io/test/github/assuncaocharles/ngx-indexed-db) [![CodeFactor](https://www.codefactor.io/repository/github/assuncaocharles/ngx-indexed-db/badge/master)](https://www.codefactor.io/repository/github/assuncaocharles/ngx-indexed-db/overview/master) [![Build Status](https://travis-ci.com/assuncaocharles/ngx-indexed-db.svg?branch=master)](https://travis-ci.com/assuncaocharles/ngx-indexed-db) ![CI](https://github.com/assuncaocharles/ngx-indexed-db/workflows/CI/badge.svg)

`ngx-indexed-db` is a service (CSR & SSR) that wraps IndexedDB database in an Angular service combined with the power of observables.

## Installation

```bash
$ npm install ngx-indexed-db
```

OR

```bash
$ yarn add ngx-indexed-db
```

## Usage

### With Module
Import the `NgxIndexedDBModule` and set up it:

```js
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)
],
...
})
```
### With Standalone API

Use `provideIndexedDb` and set it up:

```js
import { provideIndexedDb, 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 } }
]
}]
};

const appConfig: ApplicationConfig = {
providers: [...,provideIndexedDb(dbConfig),...]
}

OR

@NgModule({
...
providers:[
...
provideIndexedDb(dbConfig)
],
...
})
```

### SSR

Starting from version 19.2.0, `ngx-indexed-db` fully supports **Server-Side Rendering (SSR)**. This enhancement prevents issues related to the absence of `window.indexedDB` in server environments.

Additionally, you can provide a custom implementation of IndexedDB using an **injection token**. This allows greater flexibility, especially when mocking IndexedDB for testing or in non-browser environments (like SSR).

```js
const SERVER_INDEXED_DB = new InjectionToken('Server Indexed Db');
```

### Migrations

```js
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:

```js
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

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

```js
this.dbService
.add('people', {
name: `Bruce Wayne`,
email: `[email protected]`,
})
.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): Observable

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

```typescript
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

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

```typescript
this.dbService.bulkDelete('people', [5, 6]).subscribe((result) => {
console.log('result: ', result);
});
```

### bulkGet(storeName: string, keys: Array): Observable

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

```typescript
this.dbService.bulkGet('people', [1, 3, 5]).subscribe((result) => {
console.log('results: ', result);
});
```

### bulkPut(storeName: string, values: Array): Observable

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

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

### update(storeName: string, value: T): Observable

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

```js
this.dbService
.update('people', {
id: 1,
email: '[email protected]',
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

```js
this.dbService.getByKey('people', 1).subscribe((people) => {
console.log(people);
});
```

### getAll(storeName: string): Observable

Return all elements from one store

- @param storeName The name of the store to select the items

```js
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.

```js
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

```js
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.

```js
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

```js
this.dbService.deleteObjectStore(this.storneNameToDelete);
```

### delete(storeName: string, key: Key): Observable

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

```js
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

```js
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`

```js
this.dbService.openCursor('people', IDBKeyRange.bound("A", "F")).subscribe((evt) => {
const cursor = (evt.target as IDBOpenDBRequest).result as unknown as IDBCursorWithValue;
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`

```js
this.dbService.openCursorByIndex('people', 'name', IDBKeyRange.only('john')).subscribe((evt) => {
const cursor = (evt.target as IDBOpenDBRequest).result as unknown as IDBCursorWithValue;
if(cursor) {
console.log(cursor.value);
cursor.continue();
} else {
console.log('Entries all displayed.');
}
});
```

### getAllByIndex(storeName: string, indexName: string, keyRange: IDBKeyRange): Observable

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.

```js
this.dbService.getAllByIndex('people', 'name', IDBKeyRange.only('john')).subscribe((allPeopleByIndex) => {
console.log('All: ', allPeopleByIndex);
});
```

### getDatabaseVersion(): Observable

Returns the current database version.

```js
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

```js
this.dbService.clear('people').subscribe((successDeleted) => {
console.log('success? ', successDeleted);
});
```

### deleteDatabase(): Observable

Returns true if successfully delete the DB.

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

### getAllObjectStoreNames(): Observable

Returns all object store names.

```js
this.dbService.getAllObjectStoreNames().subscribe((storeNames) => {
console.log('storeNames: ', storeNames);
});
```

## License

Released under the terms of the [MIT License](LICENSE).

## Contributors โœจ

Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):



Angelo Parziale

๐Ÿšง ๐Ÿ’ป

Charles Assunรงรฃo

๐Ÿ’ป ๐Ÿ“– ๐Ÿšง

coolweb

๐Ÿšง

This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!