From 6947d7e19899d34fa26dd5c144975dc7c1a97164 Mon Sep 17 00:00:00 2001 From: Igor Date: Fri, 2 Sep 2022 14:28:40 +0300 Subject: [PATCH] Publish IDB.js v.1.0.0 --- .gitignore | 2 + IDB.js | 253 ++++++++++++++++ README.md | 147 +++++++++ out/IDB.module.js | 1 + out/IDB.worker.js | 1 + package-lock.json | 707 +++++++++++++++++++++++++++++++++++++++++++ package.json | 15 + rollup.config.dev.js | 15 + rollup.config.js | 83 +++++ www/index.html | 23 ++ www/test.js | 53 ++++ 11 files changed, 1300 insertions(+) create mode 100644 .gitignore create mode 100644 IDB.js create mode 100644 README.md create mode 100644 out/IDB.module.js create mode 100644 out/IDB.worker.js create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 rollup.config.dev.js create mode 100644 rollup.config.js create mode 100644 www/index.html create mode 100644 www/test.js diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..32938a9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +node_modules/ +www/IDB.js diff --git a/IDB.js b/IDB.js new file mode 100644 index 0000000..e07534d --- /dev/null +++ b/IDB.js @@ -0,0 +1,253 @@ +export class IDB { +/** +* @name constructor Create database and return its wrapper +* @param name: string Database name +* @param version: number Database version +* @param objectStores: StoreDefinition[] Object stores that will create and update with database version change +* @typedef StoreDefinition {name: string, index: {keyPath?: string, autoIncrement?: boolean}} +* @param options?: IDBOptions Options for IDB object +* @typedef IDBOptions {hideLogs?: boolean}, Hide technical logs about database lifecycle events +*/ + constructor(name, version, objectStores, options) { + const response = this._argsCheck({ + name: { value: name, required: true, type: 'string' }, + version: { value: version, required: true, type: 'number' }, + objectStores: { value: objectStores, required: true, type: 'array' }, + options: { value: options, type: 'object' } + }); + const beginning = `[IDB] new IDB(${name || '_'}, ...) call ruined due to `; + if (!response.passed) { + return this._proccessError(true, beginning, response); + } + this.showLogs = options && options.hideLogs === true ? false : true; + this._listeners = {}; + this._idb = indexedDB.open(name, version); + this._idb.addEventListener('upgradeneeded', () => this._upgradeneeded(objectStores)); + this._idb.addEventListener('success', () => this._success()); + return this; + } + _upgradeneeded(objectStores) { + if (this.showLogs) console.log('[IDB] Database upgrading started'); + this.db = this._idb.result; + const actualStores = {}; + for (let store of objectStores) { + const response = this._argsCheck({ + storeName: { value: store.name, required: true, type: 'string' }, + storeIndex: { value: store.index, required: true, type: 'object' } + }); + const beginning = `[IDB] While creating object store ${store.name || '_'} ` + const end = `. Store is not created`; + if (!response.passed) { + this._proccessError(false, beginning, response, end); + continue; + } + if (!this.db.objectStoreNames.contains(store.name)) { + this.db.createObjectStore(store.name, store.index); + } + actualStores[store.name] = true; + }; + for (let storeName of this.db.objectStoreNames) { + if (!actualStores[storeName]) this.db.deleteObjectStore(storeName); + }; + } + _success() { + if (this.showLogs) console.log('[IDB] Database successfully opened'); + this.db = this._idb.result; + this.db.addEventListener('versionchange', () => this._versionchange()); + } + _versionchange() { + this.db.close(); + this._closedDueToVersionChange = true; + console.error('[IDB] Database closed due to version change, reload page'); + } + async _isDbReady() { + if (this._closedDueToVersionChange) return false; + if (!this.db) await new Promise((resolve) => { + const isComplete = () => this.db ? resolve() : setTimeout(isComplete, 5); + isComplete(); + }); + return true; + } + _err(name, store) { return `[IDB] Error in db.${name}(${store || ' '}): `; } + _checkStore(name, store) { + if (!this.db.objectStoreNames.contains(store)) { + console.error(`${this._err(name)}database haven't "${store}" store`); + return false; + } + return true; + } + _proccessError(error, beginning, argsCheck, end = '') { + const method = error ? 'error' : 'warn'; + const { errorType, argName, arg } = argsCheck; + const wait = `waiting for ${argName} argument `; + const but = `but receives `; + if (errorType == 'noValue') { + return console[method](`${beginning}${wait}${but}nothing${end}`); + } + const value = arg.value; + if (errorType == 'wrongType') { + return console[method](`${beginning}${wait}type ${value.type} ${but}type ${typeof value.value}: ${value.value}`); + } + } + _argsCheck(args) { + for (let argName in args) { + const arg = args[argName]; + if (!arg.required && !arg.value) continue; + if (arg.required && !arg.value) return { errorType: 'noValue', argName }; + let wrongType = false; + if (arg.type && arg.type == 'array') { + if (!Array.isArray(arg.value)) wrongType = true; + } + else if (arg.type && typeof arg.value !== arg.type) { + wrongType = true; + } + if (wrongType) return { errorType: 'wrongType', argName, arg }; + } + return { passed: true }; + } + _dataOperationsArgsCheck(name, args) { + let store = null; + if ('store' in args) { + store = args.store.value; + Object.assign(args.store, { required: true, type: 'string' }); + } + const response = this._argsCheck(args); + if (response.passed) return true; + return this._proccessError(true, this._err(name, store), response); + } + async _dbCall(name, args, mode, action, actionArgument, onResult, onSuccess) { + if (!this._dataOperationsArgsCheck(name, args)) return; + const isReady = await this._isDbReady(); + if (!isReady) return; + const store = args.store.value; + if (!this._checkStore(name, store)) return; + const actioner = this.db + .transaction(store, mode) + .objectStore(store) + [action](actionArgument); + return new Promise((resolve) => { + actioner.addEventListener('success', async () => { + const complete = onSuccess ? await onSuccess(actioner.result) : true; + if (complete) { + const response = onResult ? await onResult(actioner.result) : null; + resolve(response); + } + }); + }); + } + async _onDataUpdateCall(store, item) { + if (!(store in this._listeners)) return; + await Promise.all( + this._listeners[store].map(async (callback) => await callback(store, item)) + ); + } +/** +* @name setItem Add or update item in the store +* @param store: string Name of database store +* @param item: any Serializable object that IDB can store +* @example {title: 'Book', author: 'Bob', data: new ArrayBuffer(32), pages: 12} +*/ + async setItem(store, item) { + const resp = await this._dbCall('setItem', { + store: { value: store }, item: { value: item, required: true, type: 'object' } + }, 'readwrite', 'put', item, async () => await this._onDataUpdateCall(store, item)); + return resp; + } +/** +* @name getItem Receive item from store by default store key +* @param store: string Name of database store +* @param itemKey: any Key value to access item in store +*/ + async getItem(store, itemKey) { + const resp = await this._dbCall('getItem', { + store: { value: store }, itemKey: { value: itemKey, required: true } + }, 'readonly', 'get', itemKey, (result) => result); + return resp; + } +/** +* @name updateItem Sugar for getting, modifying and setting item back to the store +* @param store: string Name of database store +* @param updateCallback: UpdateCallback Async function that receives item and can directly modify them +* @function UpdateCallback(item: any) No returned value needed +*/ + async updateItem(store, itemKey, updateCallback) { + if (!this._dataOperationsArgsCheck('updateItem', { + store: { value: store }, itemKey: { value: itemKey, required: true }, + updateCallback: { value: updateCallback, required: true, type: 'function' } + })) return; + const data = await this.getItem(store, itemKey); + await updateCallback(data); + await this.setItem(store, data); + return data; + } +/** +* @name getAll Receive all items from the store +* @param store: string Name of database store +* @param onData: DataReceivingCallback(item, index) Sync function that calls every time when next item is received +* @function DataReceivingCallback(item: any, index: number) Index is items position in store +*/ + async getAll(store, onData) { + const items = []; + const resp = await this._dbCall('getAll', { + store: { value: store }, onData: { value: onData, type: 'function' } + }, 'readonly', 'openCursor', null, () => items, async (result) => { + if (result) { + const value = result.value; + const index = items.length; + items.push(value); + if (onData) onData(value, index); + result.continue(); + } else return true; + }); + return resp ? items : resp; + } +/** +* @name deleteItem Delete item from store by store default key +* @param store: string Name of database store +* @param itemKey: any Key value to access item in store +*/ + async deleteItem(store, itemKey) { + const resp = await this._dbCall('deleteItem', { + store: { value: store }, itemKey: { value: itemKey, required: true } + }, 'readwrite', 'delete', itemKey, async () => await this._onDataUpdateCall(store)); + return resp; + } +/** +* @name deleteAll Delete all items from the store +* @param store: string Name of database store +*/ + async deleteAll(store) { + const resp = await this._dbCall('deleteAll', { + store: { value: store } + }, 'readwrite', 'clear', null, async () => await this._onDataUpdateCall(store)); + return resp; + } +/** +* @name hasItem Check for item with key exist or count how much items are in the store +* @param store: string Name of database store +* @param itemKey: any Key value to access item in store, if no key - return items amount in the store +*/ + async hasItem(store, itemKey) { + const resp = await this._dbCall('hasItem', { + store: { value: store } + }, 'readonly', 'count', itemKey, (result) => itemKey ? (result == 1 ? true : false) : result); + return resp; + } +/** +* @name onDataUpdate Set a listener to the store that calls every time some changes in the store happened +* @param store: string Name of database store +* @param callback: DataUpdatedCallback Async function that calls every time when some item in the store modified +* @function DataUpdatedCallback(store: string, item: any) Item is presented only if some item was added or updated +*/ + async onDataUpdate(store, callback) { + if (!this._dataOperationsArgsCheck('updateItem', { + store: { value: store }, callback: { value: callback, required: true, type: 'function' } + })) return; + const isReady = await this._isDbReady(); + if (!isReady) return; + if (!this._checkStore('onDataUpdate', store)) return; + if (!(store in this._listeners)) this._listeners[store] = []; + this._listeners[store].push(callback); + return this; + } +}; diff --git a/README.md b/README.md new file mode 100644 index 0000000..9ecebfd --- /dev/null +++ b/README.md @@ -0,0 +1,147 @@ +# 📦 IDB.js + +**IDB.js** is a lightweight high-level promise-based wrapper for fast access to IndexedDB API + +# How to use +Open a new database by creating new instance of class. Provide database name, version and arrays of StoreDefinition object +```ts +interface StoreDefinition { + name: string, + index: { + keyPath?: string, + autoIncrement?: boolean + } +} +``` +StoreDefinition.index is [IDBObjectStoreParameters](https://w3c.github.io/IndexedDB/#dictdef-idbobjectstoreparameters) object +## Initialize database +```js +const db = new IDB('library', 1, [ + { name: 'books', index: { keyPath: 'id' } }, + { name: 'authors', index: { keyPath: 'name' } }, + { name: 'manufacturers', index: { autoIncrement: true } } +]); +``` +## Set items in stores +Add items to stores via simple db.setItem method +```js +async function addAuthor(books) { + await db.setItem('authors', { + name: 'Agatha Christie', + books: [] + }); +} +``` +## Check is item are in store and update them +Check if store have certain item via db.hasItem and update them via db.updateItem +```js +async function addBook() { + const book = { + id: 12345, + title: `Hercule Poirot's Christmas`, + author: 'Agatha Christie', + genre: 'Mysteries' + }; + await db.setItem('books', book); + const isAuthorExist = await db.hasItem('authors', book.author); + if (isAuthorExist) { + await db.updateItem('authors', book.author, (author) => { + author.books.push(book.id); + }); + } +} +``` +## Read store entries +Get one item via db.getItem and all store items via db.getAll +```js +async function renderAuthor() { + const author = await db.getItem('author', 'Agatha Christie'); + ... +} + +async function renderBooks() { + const books = await db.getAll('books'); + for (let book of books) { + renderBook(book); + } +} +``` +Additionally, you can set callback for running function every time new item receives from database, its best for speeding up some process like rendering +```js +async function renderBooksProgressive() { + await db.getAll('books', (book) => { + renderBook(book); + }); +} +``` +## Item and stores deletion +Delete whole store simply via upgrading database version and remove relevant StoreDefinition object from stores array. Delete one item via db.deleteItem and clear all store entries via db.deleteAll +```js +const db = new IDB('library', 2, [ + { name: 'books', index: { keyPath: 'id' } }, + { name: 'authors', index: { keyPath: 'name' } } +]); + +async function deleteBooks() { + await db.deleteItem('books', 12345); + await db.deleteAll('author'); +} +``` +# API +## new IDB(name: string, version: number, objectStores: StoreDefinition[], options?: IDBOptions) +Create database and return its wrapper +- **name** - Database name +- **version** - Database version +- **objectStores** - stores that will create and update with database version change +- **StoreDefinition** +```ts +interface StoreDefinition {name: string, index: {keyPath?: string, autoIncrement?: boolean}} +``` +- **options** - Options for IDB object +- **IDBOptions** - Hide technical logs about database lifecycle events +```ts +interface IDBOptions {hideLogs?: boolean} +``` +## db.setItem(store: string, item: any) +Add or update item in the store +- **store** - Name of database store +- **item** - Serializable object that IDB can store +## db.getItem(store: string, itemKey: any) +Receive item from store by default store key +- **store** - Name of database store +- **itemKey** - Key value to access item in store +## db.updateItem(store: string, updateCallback: UpdateCallback) +Sugar for getting, modifying and setting item back to the store +- **store** - Name of database store +- **updateCallback** - Async function that receives item and can directly modify them +- **UpdateCallback** - No returned value needed +```ts +function UpdateCallback(item: any) {} +``` +## db.getAll(store: string, onData: DataReceivingCallback) +Receive all items from the store +- **store** - Name of database store +- **onData** - function that calls every time when next item is received +- **DataReceivingCallback** - Index is items position in store +```ts +function DataReceivingCallback(item: any, index: number) {} +``` +## db.deleteItem(store: string, itemKey: any) +Delete item from store by store default key +- **store** - Name of database store +- **itemKey** - Key value to access item in store +## db.deleteAll(store: string) +Delete all items from the store +- **store** - Name of database store +## db.hasItem(store: string, itemKey: any) +Check for item with key exist or count how much items are in the store +- **store** - Name of database store +- **itemKey** - Key value to access item in store, if no key - return items amount in the store +## db.onDataUpdate(store: string, callback: DataUpdatedCallback) +Set a listener to the store that calls every time some changes in the store happened +- **store** - Name of database store +- **callback** - Async function that calls every time when some item in the store modified +- **DataUpdatedCallback** - Item is presented only if some item was added or updated +```ts +function DataUpdatedCallback(store: string, item: any) {} +``` diff --git a/out/IDB.module.js b/out/IDB.module.js new file mode 100644 index 0000000..f18b22a --- /dev/null +++ b/out/IDB.module.js @@ -0,0 +1 @@ +class IDB{constructor(e,t,r,s){const a=this._argsCheck({name:{value:e,required:!0,type:"string"},version:{value:t,required:!0,type:"number"},objectStores:{value:r,required:!0,type:"array"},options:{value:s,type:"object"}}),i=`[IDB] new IDB(${e||"_"}, ...) call ruined due to `;return a.passed?(this.showLogs=!s||!0!==s.hideLogs,this._listeners={},this._idb=indexedDB.open(e,t),this._idb.addEventListener("upgradeneeded",(()=>this._upgradeneeded(r))),this._idb.addEventListener("success",(()=>this._success())),this):this._proccessError(!0,i,a)}_upgradeneeded(e){this.showLogs&&console.log("[IDB] Database upgrading started"),this.db=this._idb.result;const t={};for(let r of e){const e=this._argsCheck({storeName:{value:r.name,required:!0,type:"string"},storeIndex:{value:r.index,required:!0,type:"object"}}),s=`[IDB] While creating object store ${r.name||"_"} `,a=". Store is not created";e.passed?(this.db.objectStoreNames.contains(r.name)||this.db.createObjectStore(r.name,r.index),t[r.name]=!0):this._proccessError(!1,s,e,a)}for(let e of this.db.objectStoreNames)t[e]||this.db.deleteObjectStore(e)}_success(){this.showLogs&&console.log("[IDB] Database successfully opened"),this.db=this._idb.result,this.db.addEventListener("versionchange",(()=>this._versionchange()))}_versionchange(){this.db.close(),this._closedDueToVersionChange=!0,console.error("[IDB] Database closed due to version change, reload page")}async _isDbReady(){return!this._closedDueToVersionChange&&(this.db||await new Promise((e=>{const t=()=>this.db?e():setTimeout(t,5);t()})),!0)}_err(e,t){return`[IDB] Error in db.${e}(${t||" "}): `}_checkStore(e,t){return!!this.db.objectStoreNames.contains(t)||(console.error(`${this._err(e)}database haven't "${t}" store`),!1)}_proccessError(e,t,r,s=""){const a=e?"error":"warn",{errorType:i,argName:n,arg:o}=r,l=`waiting for ${n} argument `,u="but receives ";if("noValue"==i)return console[a](`${t}${l}${u}nothing${s}`);const c=o.value;return"wrongType"==i?console[a](`${t}${l}type ${c.type} ${u}type ${typeof c.value}: ${c.value}`):void 0}_argsCheck(e){for(let t in e){const r=e[t];if(!r.required&&!r.value)continue;if(r.required&&!r.value)return{errorType:"noValue",argName:t};let s=!1;if(r.type&&"array"==r.type?Array.isArray(r.value)||(s=!0):r.type&&typeof r.value!==r.type&&(s=!0),s)return{errorType:"wrongType",argName:t,arg:r}}return{passed:!0}}_dataOperationsArgsCheck(e,t){let r=null;"store"in t&&(r=t.store.value,Object.assign(t.store,{required:!0,type:"string"}));const s=this._argsCheck(t);return!!s.passed||this._proccessError(!0,this._err(e,r),s)}async _dbCall(e,t,r,s,a,i,n){if(!this._dataOperationsArgsCheck(e,t))return;if(!await this._isDbReady())return;const o=t.store.value;if(!this._checkStore(e,o))return;const l=this.db.transaction(o,r).objectStore(o)[s](a);return new Promise((e=>{l.addEventListener("success",(async()=>{if(!n||await n(l.result)){const t=i?await i(l.result):null;e(t)}}))}))}async _onDataUpdateCall(e,t){e in this._listeners&&await Promise.all(this._listeners[e].map((async r=>await r(e,t))))}async setItem(e,t){return await this._dbCall("setItem",{store:{value:e},item:{value:t,required:!0,type:"object"}},"readwrite","put",t,(async()=>await this._onDataUpdateCall(e,t)))}async getItem(e,t){return await this._dbCall("getItem",{store:{value:e},itemKey:{value:t,required:!0}},"readonly","get",t,(e=>e))}async updateItem(e,t,r){if(!this._dataOperationsArgsCheck("updateItem",{store:{value:e},itemKey:{value:t,required:!0},updateCallback:{value:r,required:!0,type:"function"}}))return;const s=await this.getItem(e,t);return await r(s),await this.setItem(e,s),s}async getAll(e,t){const r=[],s=await this._dbCall("getAll",{store:{value:e},onData:{value:t,type:"function"}},"readonly","openCursor",null,(()=>r),(async e=>{if(!e)return!0;{const s=e.value,a=r.length;r.push(s),t&&t(s,a),e.continue()}}));return s?r:s}async deleteItem(e,t){return await this._dbCall("deleteItem",{store:{value:e},itemKey:{value:t,required:!0}},"readwrite","delete",t,(async()=>await this._onDataUpdateCall(e)))}async deleteAll(e){return await this._dbCall("deleteAll",{store:{value:e}},"readwrite","clear",null,(async()=>await this._onDataUpdateCall(e)))}async hasItem(e,t){return await this._dbCall("hasItem",{store:{value:e}},"readonly","count",t,(e=>t?1==e:e))}async onDataUpdate(e,t){if(!this._dataOperationsArgsCheck("updateItem",{store:{value:e},callback:{value:t,required:!0,type:"function"}}))return;return await this._isDbReady()&&this._checkStore("onDataUpdate",e)?(e in this._listeners||(this._listeners[e]=[]),this._listeners[e].push(t),this):void 0}}export{IDB}; diff --git a/out/IDB.worker.js b/out/IDB.worker.js new file mode 100644 index 0000000..5cb1fd8 --- /dev/null +++ b/out/IDB.worker.js @@ -0,0 +1 @@ +var IDB=function(e){"use strict";return e.IDB=class IDB{constructor(e,t,r,s){const a=this._argsCheck({name:{value:e,required:!0,type:"string"},version:{value:t,required:!0,type:"number"},objectStores:{value:r,required:!0,type:"array"},options:{value:s,type:"object"}}),i=`[IDB] new IDB(${e||"_"}, ...) call ruined due to `;return a.passed?(this.showLogs=!s||!0!==s.hideLogs,this._listeners={},this._idb=indexedDB.open(e,t),this._idb.addEventListener("upgradeneeded",(()=>this._upgradeneeded(r))),this._idb.addEventListener("success",(()=>this._success())),this):this._proccessError(!0,i,a)}_upgradeneeded(e){this.showLogs&&console.log("[IDB] Database upgrading started"),this.db=this._idb.result;const t={};for(let r of e){const e=this._argsCheck({storeName:{value:r.name,required:!0,type:"string"},storeIndex:{value:r.index,required:!0,type:"object"}}),s=`[IDB] While creating object store ${r.name||"_"} `,a=". Store is not created";e.passed?(this.db.objectStoreNames.contains(r.name)||this.db.createObjectStore(r.name,r.index),t[r.name]=!0):this._proccessError(!1,s,e,a)}for(let e of this.db.objectStoreNames)t[e]||this.db.deleteObjectStore(e)}_success(){this.showLogs&&console.log("[IDB] Database successfully opened"),this.db=this._idb.result,this.db.addEventListener("versionchange",(()=>this._versionchange()))}_versionchange(){this.db.close(),this._closedDueToVersionChange=!0,console.error("[IDB] Database closed due to version change, reload page")}async _isDbReady(){return!this._closedDueToVersionChange&&(this.db||await new Promise((e=>{const t=()=>this.db?e():setTimeout(t,5);t()})),!0)}_err(e,t){return`[IDB] Error in db.${e}(${t||" "}): `}_checkStore(e,t){return!!this.db.objectStoreNames.contains(t)||(console.error(`${this._err(e)}database haven't "${t}" store`),!1)}_proccessError(e,t,r,s=""){const a=e?"error":"warn",{errorType:i,argName:n,arg:o}=r,l=`waiting for ${n} argument `,u="but receives ";if("noValue"==i)return console[a](`${t}${l}${u}nothing${s}`);const c=o.value;return"wrongType"==i?console[a](`${t}${l}type ${c.type} ${u}type ${typeof c.value}: ${c.value}`):void 0}_argsCheck(e){for(let t in e){const r=e[t];if(!r.required&&!r.value)continue;if(r.required&&!r.value)return{errorType:"noValue",argName:t};let s=!1;if(r.type&&"array"==r.type?Array.isArray(r.value)||(s=!0):r.type&&typeof r.value!==r.type&&(s=!0),s)return{errorType:"wrongType",argName:t,arg:r}}return{passed:!0}}_dataOperationsArgsCheck(e,t){let r=null;"store"in t&&(r=t.store.value,Object.assign(t.store,{required:!0,type:"string"}));const s=this._argsCheck(t);return!!s.passed||this._proccessError(!0,this._err(e,r),s)}async _dbCall(e,t,r,s,a,i,n){if(!this._dataOperationsArgsCheck(e,t))return;if(!await this._isDbReady())return;const o=t.store.value;if(!this._checkStore(e,o))return;const l=this.db.transaction(o,r).objectStore(o)[s](a);return new Promise((e=>{l.addEventListener("success",(async()=>{if(!n||await n(l.result)){const t=i?await i(l.result):null;e(t)}}))}))}async _onDataUpdateCall(e,t){e in this._listeners&&await Promise.all(this._listeners[e].map((async r=>await r(e,t))))}async setItem(e,t){return await this._dbCall("setItem",{store:{value:e},item:{value:t,required:!0,type:"object"}},"readwrite","put",t,(async()=>await this._onDataUpdateCall(e,t)))}async getItem(e,t){return await this._dbCall("getItem",{store:{value:e},itemKey:{value:t,required:!0}},"readonly","get",t,(e=>e))}async updateItem(e,t,r){if(!this._dataOperationsArgsCheck("updateItem",{store:{value:e},itemKey:{value:t,required:!0},updateCallback:{value:r,required:!0,type:"function"}}))return;const s=await this.getItem(e,t);return await r(s),await this.setItem(e,s),s}async getAll(e,t){const r=[],s=await this._dbCall("getAll",{store:{value:e},onData:{value:t,type:"function"}},"readonly","openCursor",null,(()=>r),(async e=>{if(!e)return!0;{const s=e.value,a=r.length;r.push(s),t&&t(s,a),e.continue()}}));return s?r:s}async deleteItem(e,t){return await this._dbCall("deleteItem",{store:{value:e},itemKey:{value:t,required:!0}},"readwrite","delete",t,(async()=>await this._onDataUpdateCall(e)))}async deleteAll(e){return await this._dbCall("deleteAll",{store:{value:e}},"readwrite","clear",null,(async()=>await this._onDataUpdateCall(e)))}async hasItem(e,t){return await this._dbCall("hasItem",{store:{value:e}},"readonly","count",t,(e=>t?1==e:e))}async onDataUpdate(e,t){if(!this._dataOperationsArgsCheck("updateItem",{store:{value:e},callback:{value:t,required:!0,type:"function"}}))return;return await this._isDbReady()&&this._checkStore("onDataUpdate",e)?(e in this._listeners||(this._listeners[e]=[]),this._listeners[e].push(t),this):void 0}},Object.defineProperty(e,"__esModule",{value:!0}),e}({}); diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..f0e5189 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,707 @@ +{ + "name": "IDB.js", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "IDB.js", + "version": "1.0.0", + "devDependencies": { + "rollup": "^2.79.0", + "rollup-plugin-serve": "^2.0.1", + "rollup-plugin-terser": "^7.0.2" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", + "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz", + "integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.18.6", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", + "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.15", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz", + "integrity": "sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@types/node": { + "version": "18.7.14", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.14.tgz", + "integrity": "sha512-6bbDaETVi8oyIARulOE9qF1/Qdi/23z6emrUh0fNJRUmjznqrixD4MpGDdgOFk5Xb0m2H6Xu42JGdvAxaJR/wA==", + "dev": true + }, + "node_modules/acorn": { + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", + "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/jest-worker": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", + "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", + "dev": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^7.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/jest-worker/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/mime": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", + "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/opener": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", + "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", + "dev": true, + "bin": { + "opener": "bin/opener-bin.js" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/rollup": { + "version": "2.79.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.0.tgz", + "integrity": "sha512-x4KsrCgwQ7ZJPcFA/SUu6QVcYlO7uRLfLAy0DSA4NS2eG8japdbpM50ToH7z4iObodRYOJ0soneF0iaQRJ6zhA==", + "dev": true, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=10.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/rollup-plugin-serve": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/rollup-plugin-serve/-/rollup-plugin-serve-2.0.1.tgz", + "integrity": "sha512-/9lnzylTMwbXNQUwWAO0DIxW145wl+rmikwFXgujLJ5N9bRfWcjP+qd1XM5wxSiw8ZlBAlFy/n2zRvzcG21bBw==", + "dev": true, + "dependencies": { + "mime": ">=2.4.6", + "opener": "1" + } + }, + "node_modules/rollup-plugin-terser": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz", + "integrity": "sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.10.4", + "jest-worker": "^26.2.1", + "serialize-javascript": "^4.0.0", + "terser": "^5.0.0" + }, + "peerDependencies": { + "rollup": "^2.0.0" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/serialize-javascript": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", + "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/terser": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.15.0.tgz", + "integrity": "sha512-L1BJiXVmheAQQy+as0oF3Pwtlo4s3Wi1X2zNZ2NxOB4wx9bdS9Vk67XQENLFdLYGCK/Z2di53mTj/hBafR+dTA==", + "dev": true, + "dependencies": { + "@jridgewell/source-map": "^0.3.2", + "acorn": "^8.5.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + } + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", + "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "dev": true, + "requires": { + "@babel/highlight": "^7.18.6" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz", + "integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==", + "dev": true + }, + "@babel/highlight": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.18.6", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true + }, + "@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true + }, + "@jridgewell/source-map": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", + "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", + "dev": true, + "requires": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true + }, + "@jridgewell/trace-mapping": { + "version": "0.3.15", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz", + "integrity": "sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "@types/node": { + "version": "18.7.14", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.14.tgz", + "integrity": "sha512-6bbDaETVi8oyIARulOE9qF1/Qdi/23z6emrUh0fNJRUmjznqrixD4MpGDdgOFk5Xb0m2H6Xu42JGdvAxaJR/wA==", + "dev": true + }, + "acorn": { + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", + "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "optional": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true + }, + "jest-worker": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", + "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", + "dev": true, + "requires": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^7.0.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "mime": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", + "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", + "dev": true + }, + "opener": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", + "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", + "dev": true + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "rollup": { + "version": "2.79.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.0.tgz", + "integrity": "sha512-x4KsrCgwQ7ZJPcFA/SUu6QVcYlO7uRLfLAy0DSA4NS2eG8japdbpM50ToH7z4iObodRYOJ0soneF0iaQRJ6zhA==", + "dev": true, + "requires": { + "fsevents": "~2.3.2" + } + }, + "rollup-plugin-serve": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/rollup-plugin-serve/-/rollup-plugin-serve-2.0.1.tgz", + "integrity": "sha512-/9lnzylTMwbXNQUwWAO0DIxW145wl+rmikwFXgujLJ5N9bRfWcjP+qd1XM5wxSiw8ZlBAlFy/n2zRvzcG21bBw==", + "dev": true, + "requires": { + "mime": ">=2.4.6", + "opener": "1" + } + }, + "rollup-plugin-terser": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz", + "integrity": "sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.10.4", + "jest-worker": "^26.2.1", + "serialize-javascript": "^4.0.0", + "terser": "^5.0.0" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + }, + "serialize-javascript": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", + "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "terser": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.15.0.tgz", + "integrity": "sha512-L1BJiXVmheAQQy+as0oF3Pwtlo4s3Wi1X2zNZ2NxOB4wx9bdS9Vk67XQENLFdLYGCK/Z2di53mTj/hBafR+dTA==", + "dev": true, + "requires": { + "@jridgewell/source-map": "^0.3.2", + "acorn": "^8.5.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..1ed56e8 --- /dev/null +++ b/package.json @@ -0,0 +1,15 @@ +{ + "name": "IDB.js", + "version": "1.0.0", + "author": "lr0pb", + "scripts": { + "prebuild": "set PRODUCTION=1", + "build": "rollup -c", + "dev": "rollup -c rollup.config.dev.js -w" + }, + "devDependencies": { + "rollup": "^2.79.0", + "rollup-plugin-serve": "^2.0.1", + "rollup-plugin-terser": "^7.0.2" + } +} diff --git a/rollup.config.dev.js b/rollup.config.dev.js new file mode 100644 index 0000000..e3a7d75 --- /dev/null +++ b/rollup.config.dev.js @@ -0,0 +1,15 @@ +import serve from 'rollup-plugin-serve' + +export default { + input: 'IDB.js', + output: { + file: 'www/IDB.js', + format: 'es' + }, + plugins: [ + serve({ + contentBase: 'www', open: true, + host: 'localhost', port: 3080 + }) + ] +}; diff --git a/rollup.config.js b/rollup.config.js new file mode 100644 index 0000000..61aab88 --- /dev/null +++ b/rollup.config.js @@ -0,0 +1,83 @@ +import { terser } from 'rollup-plugin-terser' +const fs = require('fs'); + +const prod = process.env.PRODUCTION; +console.log(prod); + +export default { + input: 'IDB.js', + output: [{ + file: 'out/IDB.worker.js', + format: 'iife', + name: 'IDB' + }, { + file: 'out/IDB.module.js', + format: 'es' + }], + plugins: [ + { + name: 'readme-api-generator', + buildStart: () => generateAPI() + }, + terser({ keep_classnames: true, compress: { ecma: 2019 } }), + ] +}; + +function generateAPI() { + let readme = fs.readFileSync('./README.md', 'utf8'); + const js = fs.readFileSync('./IDB.js', 'utf8'); + readme = readme.replace(/(?<=# API\s)[\w\s(){}\[\]?:>\-,.`*#]+$/, `\n`); + const fields = js.match(/(?<=@)[\w\s():;"'\-,?{}\[\]]+(?=\s\*)/g); + const { n, e, t, f, p } = { n: 'name', e: 'example', t: 'typedef', f: 'function', p: 'param' }; + fields.map((field) => { + const type = field.match(/^[\w]+/)[0]; + let desc = type === e ? field.replace(/^[\w]+\s/, '') : field.match(/(?<=\s)[\w\s,-]+$/); + if (desc) desc = desc[0]; + return { + type, + value: type === e ? null : field.match(/(?<=\s)[\w]+/)[0], + optional: [n, e, t, f].includes(type) ? null : field.includes('?:'), + dataType: [n, e, t, f].includes(type) ? null : field.match(/(?<=\:\s)[\w\[\]]+/)[0], + args: [t, f].includes(type) ? field.match(/[(|{][\w\s{}?:,]+[)|}]/)[0] : null, + description: [n, p].includes(type) ? desc.replace(/^[\w]+\s/, '') : desc, + }; + }).forEach((field, i, arr) => { + const args = [readme, field, i, arr]; + if (field.type === n) readme = renderName(...args); + if (field.type === p) readme = renderParam(...args); + if ([t, f].includes(field.type)) readme = renderDefinition(...args); + }); + fs.writeFileSync('./README.md', readme); +} + +function renderName(readme, field, i, arr) { + i++; + const params = []; + while (arr[i].type !== 'name') { + if (arr[i].type === 'param') params.push(arr[i]); + i++; + if (!arr[i]) break; + } + let args = ''; + for (let param of params) { + args += `${param.value}${param.optional ? '?' : ''}: ${param.dataType}, `; + } + args = args.replace(/,\s$/, ''); + readme += `## ${field.value === 'constructor' ? 'new IDB' : `db.${field.value}`}(${args})\n`; + readme += `${field.description}\n`; + return readme; +} + +function renderParam(readme, field) { + readme += `- **${field.value}** - ${field.description}\n`; + return readme; +} + +function renderDefinition(readme, field) { + const isF = field.type === 'function'; + readme += `- **${field.value}**${field.description ? ` - ${field.description}` : ''}\n`; + readme += '```ts\n'; + readme += `${isF ? 'function' : 'interface'} ${field.value}${isF ? '' : ' '}${field.args}${isF ? ' {}' : ''}`; + readme += '\n```\n'; + return readme; +} diff --git a/www/index.html b/www/index.html new file mode 100644 index 0000000..c59afa8 --- /dev/null +++ b/www/index.html @@ -0,0 +1,23 @@ + + + + + + 📦 IDB.js Test suite + + + + +

📦 Open console

+ + + diff --git a/www/test.js b/www/test.js new file mode 100644 index 0000000..d5c1955 --- /dev/null +++ b/www/test.js @@ -0,0 +1,53 @@ +import { IDB } from './IDB.js' + +console.log('IDB is ready to use'); +console.log('if it is first run, there will be errors about not able to create objectStores:'); + +window.db = new IDB('database', 1, [ + { name: 'one', index: {autoIncrement: true} }, + { name: 'two', index: {keyPath: 'id'} }, + { name: 'three', index: {keyPath: 'id'} }, + { name: 'four' }, + { name: 'five', index: 'index' } +]); + +window.runTests = async function runTests() { + console.log(`error about not all args passed in constructor:`); + new IDB('errorBase', 1); + await db.setItem('one', { prop: 'num1' }); + await db.setItem('two', { prop: 'num2', id: 'id123' }); + await db.setItem('two', { prop: 'num3', id: 'id234' }); + await db.setItem('three', { prop: 'num4', id: 'id345' }); + await db.setItem('three', { prop: 'num5', id: 'id456' }); + await db.setItem('three', { prop: 'num6', id: 'id567' }); + const ais = await db.hasItem('one', 1); + console.log(`autoIncrement store working: ${ais}`); + const kps = await db.hasItem('two', 'id123'); + console.log(`keyPath store working: ${kps}`); + const item = await db.getItem('one', 1); + console.log(`read item from store, should be { prop: 'num1' }, it is: ${ + JSON.stringify(item) + }`); + await db.updateItem('two', 'id234', (item) => { + console.log(`update item with id: ${item.id}, value: ${item.prop}`); + item.prop = 'num7'; + }); + const allItems = await db.getAll('two', (item) => { + console.log(`receive item with id: ${item.id}, value: ${item.prop}`); + }); + console.log(`all items received by getAll: ${allItems.length}`); + let itemsCount = await db.hasItem('three'); + console.log(`store should have 3 items, it have: ${itemsCount}`); + await db.deleteItem('three', 'id345'); + itemsCount = await db.hasItem('three'); + console.log(`amount of items in store after deleting one: ${itemsCount}`); + await db.deleteAll('three'); + itemsCount = await db.hasItem('three'); + console.log(`amount of items in store after deleting all: ${itemsCount}`); + console.log(`error no store:`); + await db.getItem('four', '123'); + console.log(`error no value:`); + await db.deleteItem('two'); + console.log(`error wrong type:`); + await db.updateItem('one', 1, true); +}