@n1md7/indexeddb-promise
Advanced tools
Comparing version 1.1.5 to 2.0.0
{ | ||
"name": "@n1md7/indexeddb-promise", | ||
"version": "1.1.5", | ||
"description": "Indexed DB", | ||
"version": "2.0.0", | ||
"description": "Indexed DB wrapper with promises", | ||
"main": "./src/index.js", | ||
"scripts": { | ||
"minify": "browserify ./src/index.js -o ./dist/indexeddb.min.js --standalone=indexedDBModel" | ||
"minify": "browserify ./src/index.js -o ./dist/indexed-db.min.js --standalone=IndexedDB -t [ babelify --presets [ @babel/preset-env ] ]", | ||
"format": "npx prettier --write --ignore-unknown './(src|tests)/*'", | ||
"test": "npx jest --coverage --ci", | ||
"prepare": "husky install" | ||
}, | ||
"author": "Bitchiko Kodua", | ||
"author": "Harry Kodua", | ||
"license": "MIT", | ||
@@ -24,8 +27,38 @@ "keywords": [ | ||
"type": "git", | ||
"url": "git+https://github.com/bichiko/indexeddb-promise.git" | ||
"url": "git+https://github.com/n1md7/indexeddb-promise.git" | ||
}, | ||
"bugs": { | ||
"url": "https://github.com/bichiko/indexeddb-promise/issues" | ||
"url": "https://github.com/n1md7/indexeddb-promise/issues" | ||
}, | ||
"homepage": "https://github.com/bichiko/indexeddb-promise#readme" | ||
"homepage": "https://github.com/n1md7/indexeddb-promise#readme", | ||
"devDependencies": { | ||
"@babel/core": "^7.16.0", | ||
"@babel/preset-env": "^7.16.0", | ||
"@jest/globals": "^27.3.1", | ||
"babel-jest": "^27.3.1", | ||
"babelify": "^10.0.0", | ||
"browserify": "^17.0.0", | ||
"fake-indexeddb": "^3.1.7", | ||
"husky": "^7.0.4", | ||
"jest": "^27.3.1", | ||
"jest-junit": "^13.0.0", | ||
"jsdom": "^16.7.0", | ||
"lint-staged": "^11.2.6", | ||
"prettier": "2.4.1" | ||
}, | ||
"lint-staged": { | ||
"**/*": "prettier --write --ignore-unknown" | ||
}, | ||
"browserslist": { | ||
"production": [ | ||
">0.2%", | ||
"not dead", | ||
"not op_mini all" | ||
], | ||
"development": [ | ||
"last 1 chrome version", | ||
"last 1 firefox version", | ||
"last 1 safari version" | ||
] | ||
} | ||
} |
288
README.md
@@ -1,66 +0,105 @@ | ||
# Indexed DB with promises | ||
![npm](https://img.shields.io/npm/v/@n1md7/indexeddb-promise) | ||
![GitHub](https://img.shields.io/github/license/n1md7/indexeddb-promise) | ||
![npm](https://img.shields.io/npm/v/@n1md7/indexeddb-promise) | ||
![GitHub](https://img.shields.io/github/license/bichiko/indexeddb-promise) | ||
# Indexed DB wrapper with promises | ||
## Demo | ||
- [Example01](https://bichiko.github.io/indexeddb-promise/examples/Example01.html) | ||
- [Advanced Example02](https://bichiko.github.io/indexeddb-promise/examples/Example02.html) | ||
- [Basic Example01](https://n1md7.github.io/indexeddb-promise/examples/Example01.html) | ||
- [Advanced Example02](https://n1md7.github.io/indexeddb-promise/examples/Example02.html) | ||
## Installation | ||
```shell script | ||
npm install @n1md7/indexeddb-promise --save | ||
# or | ||
yarn add @n1md7/indexeddb-promise | ||
``` | ||
or | ||
```shell script | ||
yarn add @n1md7/indexeddb-promise | ||
<script src="https://bundle.run/@n1md7/indexeddb-promise@2.0.0"></script> | ||
<script src="https://unpkg.com/@n1md7/indexeddb-promise@2.0.0/src/index.js"></script> | ||
<script src="https://cdn.jsdelivr.net/npm/@n1md7/indexeddb-promise@2.0.0/dist/indexed-db.min.js"></script> | ||
``` | ||
or | ||
```html | ||
<script src="https://bundle.run/@n1md7/indexeddb-promise@1.1.3"></script> | ||
``` | ||
or | ||
```html | ||
<script src="https://unpkg.com/@n1md7/indexeddb-promise@1.1.3/src/index.js"></script> | ||
``` | ||
or | ||
```html | ||
<script src="https://cdn.jsdelivr.net/npm/@n1md7/indexeddb-promise@1.1.3/dist/indexeddb.min.js"></script> | ||
``` | ||
### Available methods | ||
### Properties | ||
- select | ||
- insert | ||
- selectAll | ||
- selectFrom | ||
- selectWhere | ||
- updateWhere | ||
- deleteWhere | ||
- selectByPk | ||
- updateByPk | ||
- deleteByPk | ||
### .selectAll() | ||
### .selectAll(): Promise | ||
Gets all the data from db and returns promise with response data | ||
### .selectFrom(pKey) | ||
### .selectByPk(pKey: string): Promise | ||
Has one parameter `pkey` as primaryKey and returns promise with data | ||
### .selectWhere({...}) | ||
### .select({...}): Promise | ||
Has one parameter `props` which can be | ||
```javascript | ||
/** | ||
* @typedef {string | number | boolean | null | undefined} Item | ||
*/ | ||
/** | ||
* @typedef {{[key: string]: Item} | Item} ListItem | ||
*/ | ||
/** | ||
* @param {{ | ||
* where?: { | ||
* [key: string]: any | ||
* } | function(ListItem[]):ListItem[], | ||
* limit?: number, | ||
* orderByDESC?: boolean, | ||
* sortBy?: string | string[] | ||
* }} options | ||
* @returns {Promise<ListItem[]>} | ||
*/ | ||
props = { | ||
limit: 10, | ||
where: (dataArray) => {return dataArray}, | ||
orderByDESC: true, | ||
sortBy: 'comments'// ['comments', 'date'] | ||
limit: 10, | ||
where: (dataArray) => { | ||
return dataArray; | ||
}, | ||
orderByDESC: true, | ||
sortBy: 'comments', // ['comments', 'date'] | ||
}; | ||
``` | ||
@where property can filter out data like | ||
```javascript | ||
where: (data) => data.filter((item) => item.username === 'admin'); | ||
``` | ||
or it can be an object, which gets data with AND(&&) comparison | ||
```javascript | ||
where: { | ||
username: 'admin', | ||
password:'admin123' | ||
} | ||
``` | ||
@where property can filter out data | ||
like `where: data => data.filter(dt.username === 'admin')` | ||
``` | ||
### .updateWhere(pKey, {...}) | ||
### .updateByPk(pKey, {...}): Promise | ||
Has two parameters `pkey` and `keyValue` pair of updated data | ||
`.updateWhere(123, {username: 'admin'})` | ||
### .deleteWhere(pKey) | ||
```javascript | ||
.updateByPk(123, { username: 'admin' }) | ||
``` | ||
### .deleteByPk(pKey): Promise | ||
Has one parameter `pKey` which record to delete based on primary key | ||
*note* primary key is type sensitive. If it is saved as integer then should pass as integer and vice versa | ||
_note_ primary key is type sensitive. If it is saved as integer then should pass as integer and vice versa | ||
## Usage example | ||
@@ -70,26 +109,22 @@ | ||
<html> | ||
<head> | ||
<head> | ||
<title>IndexedDB app</title> | ||
<script src="./dist/indexeddb-promise.min.js"></script> | ||
</head> | ||
<body> | ||
<script src="./dist/indexed-db.min.js"></script> | ||
</head> | ||
<body> | ||
<script> | ||
// Your script here | ||
// Your script here | ||
</script> | ||
</body> | ||
</body> | ||
</html> | ||
``` | ||
Once you add *indexeddb-promise.min.js* in your document then you will be able to access | ||
`indexedDBModel` variable globally which contains `Model` and `ModelConfig`. | ||
They can be extracted as following | ||
Once you add _indexed-db.min.js_ in your document then you will be able to access | ||
`IndexedDBModel` variable globally which contains `Model`. They can be extracted as following | ||
```javascript | ||
const { | ||
ModelConfig, | ||
Model | ||
} = indexedDBModel; | ||
const { Model } = IndexedDBModel; | ||
// or | ||
const ModelConfig = indexedDBModel.ModelConfig; | ||
const Model = indexedDBModel.Model; | ||
const Model = IndexedDBModel.Model; | ||
``` | ||
@@ -100,21 +135,23 @@ | ||
```javascript | ||
class Rooms extends ModelConfig{ | ||
//@overrides default method | ||
get config() { | ||
return { | ||
version: 1, | ||
databaseName: 'myNewDatabase', | ||
tableName: 'myNewTable', | ||
primaryKey: { | ||
name: 'id', | ||
autoIncrement: false | ||
}, | ||
initData: [], | ||
structure: { | ||
roomId: { unique: false, autoIncrement: true }, | ||
roomName: { unique: false, autoIncrement: false }, | ||
comments: { unique: false, autoIncrement: false } | ||
} | ||
}; | ||
} | ||
class DB extends IndexedDBModel.Model { | ||
//@overrides default method | ||
get config() { | ||
return { | ||
version: 1, | ||
databaseName: 'myNewDatabase', | ||
tableName: 'myNewTable', | ||
primaryKey: { | ||
name: 'id', | ||
autoIncrement: false, | ||
unique: true, | ||
}, | ||
initData: [], | ||
structure: { | ||
username: { unique: false, autoIncrement: false }, | ||
password: { unique: false, autoIncrement: false }, | ||
createdAt: { unique: false, autoIncrement: false }, | ||
updatedAt: { unique: false, autoIncrement: false }, | ||
}, | ||
}; | ||
} | ||
} | ||
@@ -124,65 +161,63 @@ ``` | ||
### Create connector | ||
```javascript | ||
const db = new Model(new Rooms); | ||
const db = new DB(); | ||
``` | ||
### Full example | ||
```html | ||
<html> | ||
<head> | ||
<head> | ||
<title>IndexedDB app</title> | ||
<script src="indexeddb-promise.min.js"></script> | ||
</head> | ||
<body> | ||
<script src="./dist/indexed-db.min.js"></script> | ||
</head> | ||
<body> | ||
<script> | ||
const { | ||
ModelConfig, | ||
Model | ||
} = indexedDBModel; | ||
class Rooms extends ModelConfig{ | ||
//@overrides default method | ||
get config() { | ||
return { | ||
version: 1, | ||
databaseName: 'myNewDatabase', | ||
tableName: 'myNewTable', | ||
primaryKey: { | ||
name: 'id', | ||
autoIncrement: false | ||
}, | ||
initData: [], | ||
structure: { | ||
roomId: { unique: false, autoIncrement: true }, | ||
roomName: { unique: false, autoIncrement: false }, | ||
comment: { unique: false, autoIncrement: false } | ||
} | ||
}; | ||
} | ||
class DB extends IndexedDBModel.Model { | ||
//@overrides default method | ||
get config() { | ||
return { | ||
version: 1, | ||
databaseName: 'myNewDatabase', | ||
tableName: 'myNewTable', | ||
primaryKey: { | ||
name: 'id', | ||
autoIncrement: false, | ||
unique: true, | ||
}, | ||
initData: [], | ||
structure: { | ||
username: { unique: false, autoIncrement: false }, | ||
password: { unique: false, autoIncrement: false }, | ||
createdAt: { unique: false, autoIncrement: false }, | ||
updatedAt: { unique: false, autoIncrement: false }, | ||
}, | ||
}; | ||
} | ||
const db = new Model(new Rooms); | ||
// add new record | ||
db.insertData({ | ||
'id': Math.random() * 10, | ||
'roomName': 'My room name', | ||
'roomId': 1, | ||
'comment': 'This room is awesome' | ||
}) | ||
.then(function(){ | ||
//when done click update button | ||
console.info('Yay, you have saved the data.'); | ||
}).catch(function(error){ | ||
console.error(error); | ||
}); | ||
// Get all results from DB | ||
db.selectAll() | ||
.then(function(results){ | ||
console.log(...results); | ||
}); | ||
} | ||
const db = new DB(); | ||
// add a new record | ||
db.insert({ | ||
id: Math.random() * 10, | ||
username: 'admin', | ||
password: 'nimda', | ||
createdAt: new Date(), | ||
updatedAt: new Date(), | ||
}) | ||
.then(function () { | ||
console.info('Yay, you have saved the data.'); | ||
}) | ||
.catch(function (error) { | ||
console.error(error); | ||
}); | ||
// Get all results from the database | ||
db.selectAll().then(function (results) { | ||
console.log(...results); | ||
}); | ||
</script> | ||
</body> | ||
</body> | ||
</html> | ||
@@ -192,5 +227,6 @@ ``` | ||
```javascript | ||
const indexedDBModel = require('@n1md7/indexeddb-promise'); | ||
const { ModelConfig, Model } = indexedDBModel; | ||
const IndexedDBModel = require('@n1md7/indexeddb-promise'); | ||
const { Model } = IndexedDBModel; | ||
// or | ||
import { Model } from '@n1md7/indexeddb-promise'; | ||
``` | ||
@@ -1,52 +0,99 @@ | ||
const arraySorter = function(list) { | ||
this.sortBy = function (props) { | ||
/*props = { | ||
desc: true, | ||
keys: ['comments', 'cr_date'] | ||
}*/ | ||
let sorted = []; | ||
if ('keys' in props) { | ||
if (!(props.keys instanceof Array)) { | ||
props.keys = [props.keys]; | ||
} | ||
/** | ||
* @typedef {string | number | boolean | null | undefined} Item | ||
*/ | ||
props.keys.forEach(key => { | ||
if (sorted.length === 0) { | ||
sorted = list; | ||
} | ||
sorted = sorted.sort(function (next, current) { | ||
if (!isNaN(current[key]) && !isNaN(next[key])) { | ||
//number sorting | ||
return next[key] - current[key]; | ||
} | ||
/** | ||
* @typedef {{[key: string]: Item} | Item} ListItem | ||
*/ | ||
if (!isNaN(new Date(current[key]).getDate())) { | ||
//date sorting | ||
let $current = new Date(current[key]); | ||
let $next = new Date(0); | ||
if (!isNaN(new Date(next[key]).getDate())) { | ||
$next = new Date(next[key]); | ||
} | ||
/** | ||
* @description Array sorter | ||
* @param {ListItem[]} listToBeSorted | ||
*/ | ||
const arraySorter = function (listToBeSorted) { | ||
if (!Array.isArray(listToBeSorted)) { | ||
throw new Error('The list to be sorted must be an array'); | ||
} | ||
/** | ||
* @description Sorts array by key property | ||
* @param {{ | ||
* keys: string | string[], | ||
* desc?: boolean, | ||
* } | string | {}} props | ||
* @returns {*[]} | ||
*/ | ||
this.sortBy = (props = {}) => { | ||
/** @type {{sorted: ListItem[], keys: [string]}} */ | ||
const ref = { sorted: listToBeSorted, keys: null }; | ||
if (props.hasOwnProperty('keys')) ref.keys = props.keys; | ||
if (typeof props === 'string') ref.keys = [props]; | ||
if (Array.isArray(ref.keys)) { | ||
ref.keys.forEach( | ||
/** @param {string} key */ | ||
(key) => { | ||
ref.sorted = ref.sorted.sort( | ||
/** | ||
* @param {ListItem} next | ||
* @param {ListItem} current | ||
* @returns {number} | ||
*/ | ||
function (next, current) { | ||
// Sorting by number key | ||
if (!isNaN(current[key]) && !isNaN(next[key])) { | ||
return next[key] - current[key]; | ||
} | ||
if ($current > $next) return -1; | ||
if ($current < $next) return 1; | ||
return 0; | ||
} | ||
// Sorting by date key | ||
if (!isNaN(new Date(current[key]).valueOf())) { | ||
const $current = new Date(current[key]).valueOf(); | ||
const $next = { val: new Date(0).valueOf() }; | ||
if (!isNaN(new Date(next[key]).valueOf())) { | ||
$next.val = new Date(next[key]).valueOf(); | ||
} | ||
//alphabetical sorting | ||
if (current[key].toLowerCase() > next[key].toLowerCase()) return -1; | ||
if (current[key].toLowerCase() < next[key].toLowerCase()) return 1; | ||
return 0; | ||
}); | ||
}); | ||
if ($current > $next.val) return -1; | ||
if ($current < $next.val) return 1; | ||
return 0; | ||
} | ||
// Alphabetical sorting | ||
if (current[key]?.toLowerCase() > next[key]?.toLowerCase()) return -1; | ||
if (current[key]?.toLowerCase() < next[key]?.toLowerCase()) return 1; | ||
return 0; | ||
}, | ||
); | ||
}, | ||
); | ||
} else { | ||
ref.sorted = ref.sorted.sort( | ||
/** | ||
* @param {ListItem} next | ||
* @param {ListItem} current | ||
* @returns {number} | ||
*/ | ||
function (next, current) { | ||
// Sorting by number key | ||
if (!isNaN(current) && !isNaN(next)) { | ||
return next - current; | ||
} | ||
// Alphabetical sorting | ||
if (current?.toLowerCase() > next?.toLowerCase()) return -1; | ||
if (current?.toLowerCase() < next?.toLowerCase()) return 1; | ||
return 0; | ||
}, | ||
); | ||
} | ||
if ('desc' in props && props.desc) { | ||
sorted = sorted.reverse(); | ||
} | ||
} | ||
if (props.hasOwnProperty('desc') && props.desc) { | ||
ref.sorted = ref.sorted.reverse(); | ||
} | ||
return sorted; | ||
}; | ||
return ref.sorted; | ||
}; | ||
}; | ||
module.exports = list => new arraySorter(list); | ||
/** | ||
* @description Singleton pattern for Array sorter | ||
* @param {ListItem[]} list | ||
* @returns {arraySorter} | ||
*/ | ||
module.exports = (list) => new arraySorter(list); |
506
src/index.js
const arraySorter = require('./array-sorter'); | ||
// you need to extend this Class and override config | ||
class ModelConfig { | ||
get config() { | ||
return { | ||
debug: true, | ||
version: 1, | ||
databaseName: 'DefaultDatabase', | ||
tableName: 'roomTableView', | ||
primaryKey: { | ||
name: 'id', | ||
autoIncrement: true | ||
}, | ||
/*add first row for testing*/ | ||
initData: [ | ||
{ | ||
"roomId": 1, | ||
"roomName": "Cafe", | ||
"task": true | ||
} | ||
], | ||
structure: { | ||
roomId: { unique: false, autoIncrement: true }, | ||
roomName: { unique: false, autoIncrement: false }, | ||
task: { unique: false, autoIncrement: false } | ||
} | ||
}; | ||
} | ||
/** | ||
* @typedef {{ | ||
* version: number, | ||
* databaseName: string, | ||
* tableName: string, | ||
* primaryKey: { | ||
* name: string, | ||
* autoIncrement: boolean, | ||
* unique: boolean, | ||
* }, | ||
* initData?: Array<{ | ||
* [key: string]: any, | ||
* }>, | ||
* structure: { | ||
* [key: string]: { | ||
* unique?: boolean, | ||
* multiEntry?: boolean, | ||
* }, | ||
* } | ||
* }} Config | ||
*/ | ||
set( str ) { | ||
class Model { | ||
constructor() { | ||
this.tableName = this.config.tableName || 'table'; | ||
var struct = this.config.structure, | ||
keys = Object.keys( str ), | ||
error = false; | ||
keys.forEach( function ( key ) { | ||
if ( !struct.hasOwnProperty( key ) && this.config.debug ) { | ||
error = true; | ||
console.warn( 'No such key is defined in [setup config]: ', key ); | ||
} | ||
}, this ); | ||
if (Array.isArray(this.config)) { | ||
throw new Error('Config has to be an Object'); | ||
} | ||
if ( !this.config.primaryKey.autoIncrement ) { | ||
if ( !keys.hasOwnProperty( this.config.primaryKey.name ) && this.config.debug ) { | ||
error = true; | ||
console.warn( 'Add primary key as well or change it to autoincrement = true!' ); | ||
this.fingersCrossed = new Promise((resolve, reject) => { | ||
if (!window || !('indexedDB' in window) || !('open' in window.indexedDB)) { | ||
return reject('Unsupported environment'); | ||
} | ||
} | ||
if ( error && this.config.debug ) { | ||
console.info( 'Available column names: ', this.config.structure ); | ||
console.info( 'Primary key: ', this.config.primaryKey ); | ||
} | ||
const version = this.config.version || 1; | ||
const request = window.indexedDB.open(this.config.databaseName || 'db', version); | ||
return str; | ||
} | ||
} | ||
request.onerror = function (event) { | ||
return reject('Unexpected exception: ', event.target || event); | ||
}; | ||
//main Class | ||
let Model = function ( $mydata = {} ) { | ||
let $data = $mydata.config; | ||
let version = $data.version || 1, | ||
databaseName = $data.databaseName || 'r8IndexedDB', | ||
tableName = $data.tableName || 'defaultTable', | ||
primaryKey = $data.primaryKey || 'id', | ||
data = $data.initData || [], | ||
structure = $data.structure; | ||
this.struct = $mydata; | ||
this.tableName = tableName; | ||
this.fingersCrossed = new Promise( function ( resolve, reject ) { | ||
if ( !window || !( 'indexedDB' in window ) ) { | ||
request.onsuccess = function () { | ||
const connection = request.result; | ||
connection.onversionchange = function () { | ||
connection.close(); | ||
console.info('connection closed...'); | ||
}; | ||
return reject( 'Error: not supported Browser found!' ); | ||
} | ||
return resolve(request.result); | ||
}; | ||
if ( $data instanceof Array ) { | ||
request.onblocked = function (event) { | ||
event.target.result.close(); | ||
console.warn('blocked'); | ||
}; | ||
return reject( 'Error: parameter [$data] has to be an Object!' ); | ||
} | ||
request.onupgradeneeded = (event) => { | ||
const db = event.target.result; | ||
let request = window.indexedDB.open( databaseName, version ); | ||
if ( | ||
(event.oldVersion < version && event.oldVersion !== 0) || | ||
db.objectStoreNames.contains(this.config.tableName) | ||
) { | ||
db.deleteObjectStore(this.config.tableName); | ||
console.info('Table: ', this.config.tableName, ' removed'); | ||
} | ||
const store = db.createObjectStore(this.config.tableName, { | ||
keyPath: this.config.primaryKey?.name || 'id', | ||
autoIncrement: this.config.primaryKey?.autoIncrement || true, | ||
}); | ||
request.onerror = function ( event ) { | ||
for (const key in this.config.structure) { | ||
if (this.config.structure.hasOwnProperty(key)) { | ||
store.createIndex(`Index-${key}`, key, { | ||
unique: !!this.config.structure[key].unique, | ||
multiEntry: !!this.config.structure[key].multiEntry, | ||
}); | ||
} | ||
} | ||
return reject( 'Error: Unknown', event.target ); | ||
}; | ||
request.onsuccess = function () { | ||
let connection = request.result; | ||
connection.onversionchange = function () { | ||
connection.close(); | ||
console.info( 'connection closed...' ); | ||
for (const data of this.config.initData || []) { | ||
store.add(data); | ||
} | ||
}; | ||
}); | ||
} | ||
return resolve( request.result ); | ||
/** | ||
* @constructor | ||
* @returns {Config} | ||
*/ | ||
get config() { | ||
return { | ||
version: 1, | ||
databaseName: 'DefaultDatabase', | ||
tableName: 'DefaultTable', | ||
primaryKey: { | ||
name: 'id', | ||
autoIncrement: true, | ||
}, | ||
initData: [], | ||
structure: { | ||
roomId: { unique: false, multiEntry: true }, | ||
roomName: { unique: false, multiEntry: false }, | ||
task: { unique: false, multiEntry: false }, | ||
}, | ||
}; | ||
} | ||
request.onblocked = function ( event ) { | ||
event.target.result.close(); | ||
console.warn( 'blocked' ); | ||
}; | ||
request.onupgradeneeded = function ( event ) { | ||
let db = event.target.result; | ||
if ( ( event.oldVersion < version && event.oldVersion !== 0 ) || | ||
db.objectStoreNames.contains( tableName ) ) { | ||
db.deleteObjectStore( tableName ); | ||
console.log( 'Table : ', tableName, ' removed!' ) | ||
// db.close(); | ||
/** | ||
* @description This method is used to get the structure of the table, verify and return it. | ||
* @param {{[key:string]: any}} data | ||
* @returns {{[key:string]: any}} | ||
*/ | ||
verify(data) { | ||
const keys = Object.keys(data); | ||
for (const key of keys) { | ||
if (!this.config.structure?.[key] && this.config.primaryKey?.name !== key) { | ||
throw new Error(`{${key}} is not a valid key. Not defined in configuration [structure].`); | ||
} | ||
let objectStore = db.createObjectStore( tableName, { | ||
keyPath: primaryKey.name, | ||
autoIncrement: primaryKey.autoIncrement | ||
} ); | ||
} | ||
Object.entries( structure ) | ||
.forEach( ( [ key, value ] ) => objectStore.createIndex( key, key, value ) ); | ||
for ( let i in data ) { | ||
objectStore.add( data[ i ] ); | ||
if (this.config.primaryKey?.autoIncrement === false) { | ||
if (!keys.includes(this.config.primaryKey?.name)) { | ||
throw new Error('Either include primary key as well or set {autoincrement: true}.'); | ||
} | ||
}; | ||
} ); | ||
}; | ||
} | ||
Model.prototype.insertData = function ( data ) { | ||
return data; | ||
} | ||
let myData = this.struct.set( data ); | ||
/** | ||
* @description This method is used to insert data into the table. | ||
* @param {{[key: string]: any}} data | ||
* @returns {Promise<any>} | ||
*/ | ||
insert(data) { | ||
const verifiedInsertData = this.verify(data); | ||
return new Promise( ( resolve, reject ) => { | ||
this.fingersCrossed.then( db => { | ||
let request = db.transaction( [ this.tableName ], "readwrite" ) | ||
.objectStore( this.tableName ).add( myData ); | ||
return new Promise((resolve, reject) => { | ||
this.fingersCrossed.then((db) => { | ||
const request = db | ||
.transaction([this.tableName], 'readwrite') | ||
.objectStore(this.tableName) | ||
.add(verifiedInsertData); | ||
request.onsuccess = function () { | ||
return resolve( db ); | ||
}; | ||
request.onsuccess = function () { | ||
return resolve(data, db); | ||
}; | ||
request.onerror = function () { | ||
reject( "Error: Unable to add data. Check unique values!" ); | ||
} | ||
} ); | ||
} ); | ||
}; | ||
request.onerror = function () { | ||
reject('Unable to add data. Check the unique values'); | ||
}; | ||
}); | ||
}); | ||
} | ||
/** | ||
* @description This method is used to select data from the table by Primary key. | ||
* @param {string} pKey | ||
* @returns {Promise<ListItem|null>} | ||
*/ | ||
selectByPk(pKey) { | ||
return new Promise((resolve, reject) => { | ||
this.fingersCrossed.then((db) => { | ||
const transaction = db.transaction([this.tableName]); | ||
const objectStore = transaction.objectStore(this.tableName); | ||
const request = objectStore.get(pKey); | ||
request.onerror = function () { | ||
return reject('Unable to retrieve data from the model'); | ||
}; | ||
request.onsuccess = function () { | ||
if (request.result) { | ||
return resolve(request.result); | ||
} | ||
resolve(null); | ||
}; | ||
}); | ||
}); | ||
} | ||
Model.prototype.selectFrom = function ( pkey ) { | ||
/** | ||
* @description This method is used to select all the data from the table. | ||
* @returns {Promise<ListItem[]>} | ||
*/ | ||
selectAll() { | ||
return new Promise((resolve, reject) => { | ||
this.fingersCrossed.then((db) => { | ||
const objectStore = db.transaction(this.tableName).objectStore(this.tableName); | ||
const request = objectStore.getAll(); | ||
request.onsuccess = () => { | ||
if (request.result) { | ||
return resolve(request.result); | ||
} else { | ||
return reject('No result found'); | ||
} | ||
}; | ||
request.onerror = function () { | ||
return reject("Can't get data from database"); | ||
}; | ||
}); | ||
}); | ||
} | ||
return new Promise( ( resolve, reject ) => { | ||
this.fingersCrossed.then( db => { | ||
let transaction = db.transaction( [ this.tableName ] ); | ||
let objectStore = transaction.objectStore( this.tableName ); | ||
let request = objectStore.get( pkey ); | ||
request.onerror = function () { | ||
return reject( "Unable to retrieve data from Model!" ); | ||
}; | ||
request.onsuccess = function () { | ||
if ( request.result ) { | ||
return resolve( request.result ); | ||
} else { | ||
return reject( "No result found in your Model!" ); | ||
} | ||
}; | ||
} ); | ||
} ); | ||
}; | ||
/** | ||
* @description This method is used to select data from the table. | ||
* @param {{ | ||
* where?: { | ||
* [key: string]: any | ||
* } | function(ListItem[]):ListItem[], | ||
* limit?: number, | ||
* orderByDESC?: boolean, | ||
* sortBy?: string | string[] | ||
* }} options | ||
* @returns {Promise<ListItem[]>} | ||
*/ | ||
select(options) { | ||
const props = new Proxy(options, { | ||
get: function (target, name) { | ||
return name in target ? target[name] : false; | ||
}, | ||
}); | ||
Model.prototype.selectAll = function () { | ||
return new Promise((resolve, reject) => { | ||
this.selectAll().then(resolve).catch(reject); | ||
}).then((dataBucket) => { | ||
const result = { val: [] }; | ||
if ('where' in props && props.where !== false) { | ||
if (dataBucket.length === 0) return []; | ||
return new Promise( ( resolve, reject ) => { | ||
this.fingersCrossed.then( db => { | ||
let objectStore = db.transaction( this.tableName ).objectStore( this.tableName ), | ||
dataBucket = []; | ||
let store = objectStore.openCursor(); | ||
store.onsuccess = function ( event ) { | ||
let cursor = event.target.result; | ||
if ( cursor ) { | ||
dataBucket.push( cursor.value ); | ||
cursor.continue(); | ||
if (typeof props.where === 'function') { | ||
result.val = props.where.call(dataBucket, dataBucket); | ||
} else { | ||
return resolve( dataBucket ); | ||
const whereKeys = Object.keys(props.where); | ||
result.val = dataBucket.filter((item) => { | ||
const dataKeys = Object.keys(item); | ||
for (const key of whereKeys) { | ||
if (dataKeys.includes(key) && item[key] === props.where[key]) { | ||
return true; | ||
} | ||
} | ||
return false; | ||
}); | ||
} | ||
}; | ||
store.onerror = function () { | ||
return reject( 'Can\'t open cursor' ); | ||
}; | ||
} ); | ||
} ); | ||
}; | ||
} | ||
Model.prototype.selectWhere = function ( props = { | ||
/* limit: -1, | ||
where: () => {}, | ||
orderByDESC: true, | ||
sortBy: 'comments' or ['comments', 'date']*/ | ||
} ) { | ||
props = new Proxy( props, { | ||
get: function ( target, name ) { | ||
return name in target ? target[ name ] : false; | ||
} | ||
} ); | ||
return new Promise( ( resolve, reject ) => { | ||
this.selectAll().then( data => { | ||
if ( data && data.length > 0 ) { | ||
return resolve( data ); | ||
if ('sortBy' in props && props.sortBy) { | ||
// sort data | ||
result.val = arraySorter(result.val).sortBy({ | ||
desc: 'orderByDESC' in props && props.orderByDESC, | ||
keys: [props.sortBy], | ||
}); | ||
} | ||
return reject( 'Data is empty' ); | ||
} ) | ||
} ).then( dataBucket => { | ||
if ( 'where' in props && props.where !== false ) { | ||
if ( dataBucket.length === 0 ) return []; | ||
if ( typeof props.where === 'function' ) { | ||
//do whatever like in callback fn and return | ||
dataBucket = props.where( dataBucket ); | ||
if ('limit' in props && props.limit !== false) { | ||
// slice data | ||
result.val = result.val.slice(0, +props.limit); | ||
} | ||
} | ||
if ( 'sortBy' in props && props.sortBy ) { | ||
//sort data | ||
dataBucket = arraySorter( dataBucket ).sortBy( { | ||
desc: 'orderByDESC' in props && props.orderByDESC, | ||
keys: props.sortBy | ||
} ); | ||
} | ||
return result.val; | ||
}); | ||
} | ||
if ( 'limit' in props && props.limit !== false ) { | ||
//slice data | ||
dataBucket = dataBucket.slice( 0, +props.limit ); | ||
} | ||
/** | ||
* @description This method is used to update data in the table. | ||
* @param {string} pKey | ||
* @param {{[key: string]: any}} dataToUpdate | ||
* @returns {Promise<any>} | ||
*/ | ||
updateByPk(pKey, dataToUpdate) { | ||
return new Promise((resolve, reject) => { | ||
this.fingersCrossed.then((db) => { | ||
this.selectByPk(pKey).then((fetchedData) => { | ||
const transaction = db.transaction([this.tableName], 'readwrite'); | ||
const store = transaction.objectStore(this.tableName); | ||
const data = Object.assign(fetchedData, dataToUpdate); | ||
const save = store.put(data); | ||
save.onsuccess = function () { | ||
return resolve(data); | ||
}; | ||
save.onerror = function () { | ||
return reject('Cannot update data'); | ||
}; | ||
}); | ||
}); | ||
}); | ||
} | ||
return dataBucket; | ||
} ); | ||
}; | ||
Model.prototype.updateWhere = function ( pKey, keyval ) { | ||
return new Promise( ( resolve, reject ) => { | ||
this.fingersCrossed.then( db => { | ||
this.selectFrom( pKey ).then( data => { | ||
var transaction = db.transaction( [ this.tableName ], "readwrite" ); | ||
var store = transaction.objectStore( this.tableName ); | ||
keyval = Object.assign( data, keyval ); | ||
let done = store.put( keyval ); | ||
done.onsuccess = function () { | ||
return resolve( true ); | ||
/** | ||
* @description This method is used to delete data from the table. | ||
* @param {string} pKey | ||
* @returns {Promise<unknown>} | ||
*/ | ||
deleteByPk(pKey) { | ||
return new Promise((resolve, reject) => { | ||
this.fingersCrossed.then((db) => { | ||
const request = db.transaction([this.tableName], 'readwrite').objectStore(this.tableName).delete(pKey); | ||
request.onsuccess = function () { | ||
return resolve(pKey); | ||
}; | ||
done.onerror = function () { | ||
return reject( true ); | ||
request.onerror = function () { | ||
return reject("Couldn't remove an item"); | ||
}; | ||
} ); | ||
} ); | ||
} ); | ||
}; | ||
}); | ||
}); | ||
} | ||
} | ||
Model.prototype.deleteWhere = function ( pkey ) { | ||
return new Promise( ( resolve, reject ) => { | ||
this.fingersCrossed.then( db => { | ||
let request = db.transaction( [ this.tableName ], "readwrite" ) | ||
.objectStore( this.tableName ).delete( pkey ); | ||
request.onsuccess = function () { | ||
return resolve( "Some Data have been removed from your Model." ); | ||
}; | ||
request.onerror = function () { | ||
return reject( 'couldn\'t delete' ); | ||
}; | ||
} ); | ||
} ); | ||
}; | ||
module.exports = { | ||
ModelConfig, | ||
Model | ||
}; | ||
module.exports = { Model }; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
75445
17
1651
229
13
1