Socket
Socket
Sign inDemoInstall

@n1md7/indexeddb-promise

Package Overview
Dependencies
Maintainers
1
Versions
32
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@n1md7/indexeddb-promise - npm Package Compare versions

Comparing version 6.0.0 to 6.1.0

lib/Decorators.d.ts

11

lib/Database.d.ts

@@ -5,8 +5,10 @@ import { Optional } from 'utility-types';

export declare class Database {
protected readonly config: ConfigType;
protected readonly config: ConfigType | ConfigType<Function>;
private readonly __connection;
protected readonly databaseName: string;
protected readonly tables: string[];
protected readonly databaseVersion: number;
protected readonly connection: Promise<IDBDatabase>;
constructor(config: ConfigType);
constructor(config: ConfigType | ConfigType<Function>);
get configuration(): ConfigType<TableType> | ConfigType<Function>;
get connection(): Promise<IDBDatabase>;
/**

@@ -20,3 +22,4 @@ * @description This method is used to get the indexes of the table, verify and return it.

private static insertInitialValues;
useModel<CollectionType extends Optional<TimeStampsType>>(tableName: string): Model<CollectionType>;
useModel<CollectionType>(target: new () => CollectionType): Model<CollectionType & Optional<TimeStampsType>>;
useModel<CollectionType>(tableName: string): Model<CollectionType & Optional<TimeStampsType>>;
}

@@ -64,2 +64,3 @@ "use strict";

var IDBError_1 = __importDefault(require("./IDBError"));
var Decorators_1 = require("./Decorators");
var Database = /** @class */ (function () {

@@ -76,3 +77,45 @@ function Database(config) {

}
var validated = schema_1.ConfigSchema.validate(config);
if (!Array.isArray(config === null || config === void 0 ? void 0 : config.tables)) {
throw new IDBError_1.default(IDBError_1.default.compose('Config.tables has to be an Array'));
}
var hasMetadata = config.tables.every(function (table) { return typeof table === 'function'; });
var hasPlainConfig = config.tables.every(function (table) { return typeof table === 'object'; });
if (!hasMetadata && !hasPlainConfig) {
throw new IDBError_1.default(IDBError_1.default.compose('Config.tables has to be an Array of Objects or Annotated Classes'));
}
if (hasMetadata) {
// Serialize to plain config
config.tables = config.tables.map(function (target) {
var classMeta = (0, Decorators_1.getClassMetadata)(target);
var propertyMeta = (0, Decorators_1.getPropertyMetadata)(target);
var composeConfig = {
name: classMeta.name,
timestamps: classMeta.timestamps,
primaryKey: {},
indexes: {},
};
var propertyEntries = Object.entries(propertyMeta);
propertyEntries.forEach(function (_a) {
var propertyName = _a[0], value = _a[1];
if (value.primaryKey)
composeConfig.primaryKey = {
name: propertyName,
autoIncrement: value.primaryKey.autoIncrement,
unique: value.primaryKey.unique,
};
if (value.indexed)
composeConfig.indexes[propertyName] = {
multiEntry: value.indexed.multiEntry,
unique: value.indexed.unique,
};
});
return composeConfig;
});
}
// else it's already plain config
// Validate plain config
var validated = schema_1.ConfigSchema.validate(config, {
abortEarly: true,
allowUnknown: false,
});
if (validated.error) {

@@ -85,3 +128,3 @@ throw new IDBError_1.default(validated.error.details);

this.databaseVersion = this.config.version;
this.connection = new Promise(function (resolve, reject) {
this.__connection = new Promise(function (resolve, reject) {
if (!window || !('indexedDB' in window) || !('open' in window.indexedDB)) {

@@ -93,17 +136,33 @@ return reject('Unsupported environment');

request.onsuccess = function () {
var connection = request.result;
connection.onversionchange = function () {
console.info('Database version changed');
console.info('Connection closed.');
connection.close();
var __connection = request.result;
__connection.onversionchange = function () {
console.info("[" + _this.databaseName + "]: Database version changed.");
console.info("[" + _this.databaseName + "]: Connection closed.");
__connection.close();
};
return resolve(connection);
return resolve(__connection);
};
request.onblocked = function () {
request.result.close();
console.error(request.error || 'Database blocked');
console.error("[" + _this.databaseName + "]: " + (request.error || 'Database blocked'));
};
request.onupgradeneeded = function (event) { return Database.onUpgradeNeeded(request.result, _this.config, event.oldVersion); };
request.onupgradeneeded = function (event) {
return Database.onUpgradeNeeded(request.result, _this.config, event.oldVersion);
};
});
}
Object.defineProperty(Database.prototype, "configuration", {
get: function () {
return this.config;
},
enumerable: false,
configurable: true
});
Object.defineProperty(Database.prototype, "connection", {
get: function () {
return this.__connection;
},
enumerable: false,
configurable: true
});
/**

@@ -113,3 +172,4 @@ * @description This method is used to get the indexes of the table, verify and return it.

Database.verify = function (data, tables) {
if (!tables.length) {
var _a = tables[0], tableIsNull = _a === void 0 ? null : _a;
if (tableIsNull === null) {
throw new Error('Tables should not be empty/undefined');

@@ -134,3 +194,3 @@ }

request.onblocked = function () {
console.log("Couldn't delete database due to the operation being blocked");
console.log("[" + name + "]: Couldn't delete database due to the operation being blocked");
};

@@ -160,3 +220,3 @@ request.onsuccess = function () { return resolve('Database has been removed'); };

db.deleteObjectStore(table.name);
console.info("DB version changed, removing table: " + table.name + " for the fresh start");
console.info("[" + database.name + "]: DB version changed, removing table: " + table.name + " for the fresh start");
}

@@ -212,11 +272,20 @@ store = db.createObjectStore(table.name, {

};
Database.prototype.useModel = function (tableName) {
if (!this.tables.includes(tableName)) {
throw new Error("Table [" + tableName + "] does not exist");
Database.prototype.useModel = function (target) {
var tableName = { value: '' };
if (typeof target === 'string')
tableName.value = target;
if (typeof target === 'function')
tableName.value = (0, Decorators_1.getClassMetadata)(target).name;
if (!tableName.value)
throw new Error('Invalid tableName or tableClass.');
if (!this.tables.includes(tableName.value)) {
throw new Error("[" + this.databaseName + "]: Table [" + tableName.value + "] does not exist.");
}
var table = this.config.tables.find(function (_a) {
var name = _a.name;
return name === tableName;
return name === tableName.value;
});
return new Model_1.default(this.connection, table);
if (typeof target === 'string')
return new Model_1.default(this.__connection, table);
return new Model_1.default(this.__connection, table);
};

@@ -223,0 +292,0 @@ return Database;

export { Database } from './Database';
export * from './Decorators';
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
Object.defineProperty(exports, "__esModule", { value: true });

@@ -6,2 +16,3 @@ exports.Database = void 0;

Object.defineProperty(exports, "Database", { enumerable: true, get: function () { return Database_1.Database; } });
__exportStar(require("./Decorators"), exports);
//# sourceMappingURL=index.js.map

@@ -21,9 +21,16 @@ "use strict";

primaryKey: joi_1.default.object({
name: joi_1.default.string().required().label('Primary key name').example('id'),
name: joi_1.default.string().optional().label('Primary key name').default('id').example('id'),
autoIncrement: joi_1.default.boolean()
.required()
.optional()
.label('Auto increment')
.default(true)
.example(true)
.description('If true, the object store has a key generator.'),
unique: joi_1.default.boolean().required().label('Unique').example(true),
unique: joi_1.default.boolean().optional().default(true).label('Unique').example(true),
})
.optional()
.default({
name: 'id',
autoIncrement: true,
unique: true,
}),

@@ -33,3 +40,4 @@ indexes: joi_1.default.object()

unique: joi_1.default.boolean()
.required()
.optional()
.default(false)
.label('Unique')

@@ -39,4 +47,5 @@ .example(true)

multiEntry: joi_1.default.boolean()
.required()
.optional()
.label('Multi entry')
.default(true)
.example(true)

@@ -46,4 +55,5 @@ .description('If true, the index will add an entry in the index for each array element when the keyPath' +

}))
.required()
.example([{ name: 'index', unique: true, multiEntry: true }])
.optional()
.default({})
.example({ username: { unique: true, multiEntry: false }, password: { unique: false, multiEntry: false } })
.label('Indexes')

@@ -60,2 +70,3 @@ .description('It creates a new field/column defining a new data point for each database record to contain.'),

.optional()
.default([])
.label('Initial data')

@@ -62,0 +73,0 @@ .example([{ name: 'John', age: 30 }])

@@ -1,5 +0,5 @@

export declare type ConfigType = {
export declare type ConfigType<T = TableType> = {
version: number;
name: string;
tables: TableType[];
tables: T[];
};

@@ -6,0 +6,0 @@ export declare type TimeStampsType = {

{
"name": "@n1md7/indexeddb-promise",
"version": "6.0.0",
"version": "6.1.0",
"description": "Indexed DB wrapper with promises",

@@ -61,4 +61,7 @@ "main": "./lib/index.js",

"lint-staged": "^11.2.6",
"nodemon": "^2.0.15",
"prettier": "2.4.1",
"reflect-metadata": "^0.1.13",
"ts-jest": "^27.0.7",
"ts-node": "^10.4.0",
"tsify": "^5.0.4",

@@ -65,0 +68,0 @@ "typescript": "^4.4.4",

@@ -22,10 +22,2 @@ [![npm databaseVersion](https://badge.fury.io/js/@n1md7%2Findexeddb-promise.svg)](https://badge.fury.io/js/@n1md7%2Findexeddb-promise)

or
```shell script
<script src="https://bundle.run/@n1md7/indexeddb-promise@5.0.21"></script>
<script src="https://unpkg.com/@n1md7/indexeddb-promise@5.0.21/src/index.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@n1md7/indexeddb-promise@5.0.21/dist/indexed-db.min.js"></script>
```
### Available methods

@@ -37,3 +29,2 @@

- openCursor
- setTable
- selectByIndex

@@ -121,9 +112,9 @@ - selectByPk

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
`IndexedDB` variable globally which contains `Model`. They can be extracted as following
```javascript
const { Database } = IndexedDBModel;
const { Database } = IndexedDB;
// or
const Database = IndexedDBModel.Database;
const Database = IndexedDB.Database;
```

@@ -134,3 +125,3 @@

```javascript
const db = new IndexedDBModel.Database({
const db = new IndexedDB.Database({
databaseVersion: 1,

@@ -167,3 +158,3 @@ databaseName: 'myNewDatabase',

<script>
const db = new IndexedDBModel.Database({
const db = new IndexedDB.Database({
databaseVersion: 1,

@@ -215,4 +206,4 @@ databaseName: 'myNewDatabase',

```javascript
const IndexedDBModel = require('@n1md7/indexeddb-promise');
const { Database } = IndexedDBModel;
const IndexedDB = require('@n1md7/indexeddb-promise');
const { Database } = IndexedDB;
// or

@@ -222,3 +213,3 @@ import { Database } from '@n1md7/indexeddb-promise';

Typescript example
TypeScript example

@@ -286,3 +277,3 @@ ```typescript

const users = database.useModel<Users>('users');
await users.insert({
const user = await users.insert({
username: 'admin',

@@ -301,1 +292,46 @@ password: 'admin',

```
```typescript
import { Table, PrimaryKey, Indexed, Database } from '@n1md7/indexeddb-promise';
@Table({ name: '__Name__', timestamps: true })
class SomeTable {
@PrimaryKey({ autoIncrement: true, unique: true })
id: number;
@Indexed({ unique: true, multiEntry: false })
username: string;
@Indexed({ unique: false })
age: number;
otherData: string;
}
const anotherDb = new Database({
version: 1,
name: 'Other-DB',
tables: [SomeTable],
});
const model = anotherDb.useModel(SomeTable);
(async () => {
await model
.insert({
username: 'John',
age: 20,
otherData: 'Some data',
})
.catch((error) => console.error(error));
model.selectAll().then((results) => {
if (results) {
results.forEach((result) => {
// result is inferred to be SomeTable
console.log(result.username);
});
}
});
})();
```

@@ -7,10 +7,11 @@ import { Optional } from 'utility-types';

import IDBError from './IDBError';
import { getClassMetadata, getPropertyMetadata } from './Decorators';
export class Database {
private readonly __connection: Promise<IDBDatabase>;
protected readonly databaseName: string = 'DefaultDatabase';
protected readonly tables: string[] = ['DefaultTable'];
protected readonly databaseVersion: number = 1;
protected readonly connection: Promise<IDBDatabase>;
constructor(protected readonly config: ConfigType) {
constructor(protected readonly config: ConfigType | ConfigType<Function>) {
if (Array.isArray(config)) {

@@ -20,3 +21,47 @@ throw new IDBError(IDBError.compose('Config has to be an Object'));

const validated: Joi.ValidationResult = ConfigSchema.validate(config);
if (!Array.isArray(config?.tables)) {
throw new IDBError(IDBError.compose('Config.tables has to be an Array'));
}
const hasMetadata = (config as ConfigType<Function>).tables.every((table) => typeof table === 'function');
const hasPlainConfig = (config as ConfigType).tables.every((table) => typeof table === 'object');
if (!hasMetadata && !hasPlainConfig) {
throw new IDBError(IDBError.compose('Config.tables has to be an Array of Objects or Annotated Classes'));
}
if (hasMetadata) {
// Serialize to plain config
(config as ConfigType).tables = (config as ConfigType<Function>).tables.map((target: Function) => {
const classMeta = getClassMetadata(target);
const propertyMeta = getPropertyMetadata(target);
const composeConfig: TableType = {
name: classMeta.name,
timestamps: classMeta.timestamps,
primaryKey: {},
indexes: {},
} as TableType;
const propertyEntries = Object.entries(propertyMeta);
propertyEntries.forEach(([propertyName, value]) => {
if (value.primaryKey)
composeConfig.primaryKey = {
name: propertyName,
autoIncrement: value.primaryKey.autoIncrement,
unique: value.primaryKey.unique,
};
if (value.indexed)
composeConfig.indexes[propertyName] = {
multiEntry: value.indexed.multiEntry,
unique: value.indexed.unique,
};
});
return composeConfig;
});
}
// else it's already plain config
// Validate plain config
const validated: Joi.ValidationResult<ConfigType> = ConfigSchema.validate(config as ConfigType, {
abortEarly: true,
allowUnknown: false,
});
if (validated.error) {

@@ -30,3 +75,3 @@ throw new IDBError(validated.error.details);

this.connection = new Promise((resolve, reject) => {
this.__connection = new Promise((resolve, reject) => {
if (!window || !('indexedDB' in window) || !('open' in window.indexedDB)) {

@@ -38,22 +83,31 @@ return reject('Unsupported environment');

request.onerror = () => reject(request.error);
request.onsuccess = function () {
const connection = request.result;
connection.onversionchange = function () {
console.info('Database version changed');
console.info('Connection closed.');
connection.close();
request.onsuccess = () => {
const __connection = request.result;
__connection.onversionchange = () => {
console.info(`[${this.databaseName}]: Database version changed.`);
console.info(`[${this.databaseName}]: Connection closed.`);
__connection.close();
};
return resolve(connection);
return resolve(__connection);
};
request.onblocked = function () {
request.onblocked = () => {
request.result.close();
console.error(request.error || 'Database blocked');
console.error(`[${this.databaseName}]: ${request.error || 'Database blocked'}`);
};
request.onupgradeneeded = (event) => Database.onUpgradeNeeded(request.result, this.config, event.oldVersion);
request.onupgradeneeded = (event) =>
Database.onUpgradeNeeded(request.result, this.config as ConfigType, event.oldVersion);
});
}
public get configuration() {
return this.config;
}
public get connection() {
return this.__connection;
}
/**

@@ -63,3 +117,4 @@ * @description This method is used to get the indexes of the table, verify and return it.

public static verify<T>(data: T, tables: TableType[]): T {
if (!tables.length) {
const [tableIsNull = null] = tables;
if (tableIsNull === null) {
throw new Error('Tables should not be empty/undefined');

@@ -75,2 +130,3 @@ }

});
return data;

@@ -82,4 +138,4 @@ }

const request = window.indexedDB.deleteDatabase(name);
request.onblocked = function () {
console.log("Couldn't delete database due to the operation being blocked");
request.onblocked = () => {
console.log(`[${name}]: Couldn't delete database due to the operation being blocked`);
};

@@ -95,3 +151,3 @@ request.onsuccess = () => resolve('Database has been removed');

db.deleteObjectStore(table.name);
console.info(`DB version changed, removing table: ${table.name} for the fresh start`);
console.info(`[${database.name}]: DB version changed, removing table: ${table.name} for the fresh start`);
}

@@ -131,10 +187,21 @@ const store = db.createObjectStore(table.name, {

public useModel<CollectionType extends Optional<TimeStampsType>>(tableName: string) {
if (!this.tables.includes(tableName)) {
throw new Error(`Table [${tableName}] does not exist`);
public useModel<CollectionType>(target: new () => CollectionType): Model<CollectionType & Optional<TimeStampsType>>;
public useModel<CollectionType>(tableName: string): Model<CollectionType & Optional<TimeStampsType>>;
public useModel<CollectionType>(target: string | ((new () => CollectionType) & Optional<TimeStampsType>)) {
const tableName = { value: '' };
if (typeof target === 'string') tableName.value = target;
if (typeof target === 'function') tableName.value = getClassMetadata(target).name;
if (!tableName.value) throw new Error('Invalid tableName or tableClass.');
if (!this.tables.includes(tableName.value)) {
throw new Error(`[${this.databaseName}]: Table [${tableName.value}] does not exist.`);
}
const table = this.config.tables.find(({ name }) => name === tableName);
return new Model<CollectionType>(this.connection, table);
const table = (this.config as ConfigType).tables.find(({ name }) => name === tableName.value);
if (typeof target === 'string')
return new Model<CollectionType & Optional<TimeStampsType>>(this.__connection, table);
return new Model(this.__connection, table);
}
}
export { Database } from './Database';
export * from './Decorators';

@@ -19,10 +19,17 @@ import Joi from 'joi';

primaryKey: Joi.object({
name: Joi.string().required().label('Primary key name').example('id'),
name: Joi.string().optional().label('Primary key name').default('id').example('id'),
autoIncrement: Joi.boolean()
.required()
.optional()
.label('Auto increment')
.default(true)
.example(true)
.description('If true, the object store has a key generator.'),
unique: Joi.boolean().required().label('Unique').example(true),
}),
unique: Joi.boolean().optional().default(true).label('Unique').example(true),
})
.optional()
.default({
name: 'id',
autoIncrement: true,
unique: true,
}),
indexes: Joi.object()

@@ -33,3 +40,4 @@ .pattern(

unique: Joi.boolean()
.required()
.optional()
.default(false)
.label('Unique')

@@ -39,4 +47,5 @@ .example(true)

multiEntry: Joi.boolean()
.required()
.optional()
.label('Multi entry')
.default(true)
.example(true)

@@ -49,4 +58,5 @@ .description(

)
.required()
.example([{ name: 'index', unique: true, multiEntry: true }])
.optional()
.default({})
.example({ username: { unique: true, multiEntry: false }, password: { unique: false, multiEntry: false } })
.label('Indexes')

@@ -63,2 +73,3 @@ .description('It creates a new field/column defining a new data point for each database record to contain.'),

.optional()
.default([])
.label('Initial data')

@@ -65,0 +76,0 @@ .example([{ name: 'John', age: 30 }])

@@ -1,5 +0,5 @@

export type ConfigType = {
export type ConfigType<T = TableType> = {
version: number;
name: string;
tables: TableType[];
tables: T[];
};

@@ -6,0 +6,0 @@ export type TimeStampsType = {

Sorry, the diff of this file is too big to display

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

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc