Comparing version 0.0.3 to 0.0.4
import { Dict } from './interface'; | ||
export default class Builder { | ||
export declare class Builder { | ||
sql: Dict; | ||
@@ -8,12 +8,12 @@ _fields: string[]; | ||
private parser; | ||
options: object; | ||
constructor(options: any); | ||
options: Dict; | ||
constructor(options: Dict); | ||
table(table: string): Builder; | ||
isEmpty(data: any): boolean; | ||
isEmpty(data: string[] | string | Dict): boolean; | ||
fields(fields: string[]): Builder; | ||
where(condition: any): Builder; | ||
where(condition: Dict): Builder; | ||
order(orderBy: Dict): Builder; | ||
limit(limit: number): Builder; | ||
offset(offset: number): Builder; | ||
group(field: string | string[]): this; | ||
group(field: string | string[]): Builder; | ||
select(options?: Dict | null): { | ||
@@ -20,0 +20,0 @@ sql: string; |
"use strict"; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const parser_1 = __importDefault(require("./parser")); | ||
const printj_1 = require("printj"); | ||
class Builder { | ||
constructor(options) { | ||
exports.Builder = void 0; | ||
var parser_1 = require("./parser"); | ||
var printj_1 = require("printj"); | ||
var Builder = /** @class */ (function () { | ||
function Builder(options) { | ||
this.options = options; | ||
this.parser = new parser_1.default(); | ||
this.parser = new parser_1.Parser(); | ||
this.tableName = ''; | ||
@@ -17,7 +15,7 @@ this._fields = []; | ||
} | ||
table(table) { | ||
Builder.prototype.table = function (table) { | ||
this.tableName = table; | ||
return this; | ||
} | ||
isEmpty(data) { | ||
}; | ||
Builder.prototype.isEmpty = function (data) { | ||
if (!data) { | ||
@@ -30,4 +28,4 @@ return true; | ||
return !Boolean(Object.keys(data).length); | ||
} | ||
fields(fields) { | ||
}; | ||
Builder.prototype.fields = function (fields) { | ||
if (this.isEmpty(fields)) { | ||
@@ -38,36 +36,37 @@ return this; | ||
return this; | ||
} | ||
where(condition) { | ||
}; | ||
Builder.prototype.where = function (condition) { | ||
if (this.isEmpty(condition)) { | ||
return this; | ||
} | ||
const { sql, params } = this.parser.parse(condition); | ||
this.sql.where = { sql: `WHERE ${sql}`, params }; | ||
var _a = this.parser.parse(condition), sql = _a.sql, params = _a.params; | ||
this.sql.where = { sql: "WHERE " + sql, params: params }; | ||
return this; | ||
} | ||
order(orderBy) { | ||
}; | ||
Builder.prototype.order = function (orderBy) { | ||
var _this = this; | ||
if (this.isEmpty(orderBy)) { | ||
return this; | ||
} | ||
Object.entries(orderBy).forEach((elm => { | ||
const [field, sort] = elm; | ||
this.sql.order = { sql: `ORDER BY ? ?`, params: [field, sort] }; | ||
Object.entries(orderBy).forEach((function (elm) { | ||
var field = elm[0], sort = elm[1]; | ||
_this.sql.order = { sql: "ORDER BY " + field + " " + sort, params: [] }; | ||
})); | ||
return this; | ||
} | ||
limit(limit) { | ||
}; | ||
Builder.prototype.limit = function (limit) { | ||
if (!limit) { | ||
return this; | ||
} | ||
this.sql.limit = { sql: `LIMIT ?`, params: [limit] }; | ||
this.sql.limit = { sql: "LIMIT ?", params: [limit] }; | ||
return this; | ||
} | ||
offset(offset) { | ||
}; | ||
Builder.prototype.offset = function (offset) { | ||
if (!offset) { | ||
return this; | ||
} | ||
this.sql.offset = { sql: `OFFSET ?`, params: [offset] }; | ||
this.sql.offset = { sql: "OFFSET ?", params: [offset] }; | ||
return this; | ||
} | ||
group(field) { | ||
}; | ||
Builder.prototype.group = function (field) { | ||
if (this.isEmpty(field)) { | ||
@@ -77,67 +76,70 @@ return this; | ||
this.sql.group = { | ||
sql: `GROUP BY ?`, | ||
params: [field === null || field === void 0 ? void 0 : field.toString()] | ||
sql: "GROUP BY " + field.toString(), | ||
params: [] | ||
}; | ||
return this; | ||
} | ||
select(options = null) { | ||
const select = 'SELECT %s FROM `%s` %s'; | ||
const fields = this.isEmpty(this._fields) ? '*' : this._fields.join(','); | ||
const { sql, params } = this.toSql(); | ||
const sqlStr = (0, printj_1.sprintf)(select, fields, this.tableName, sql); | ||
}; | ||
Builder.prototype.select = function (options) { | ||
if (options === void 0) { options = null; } | ||
var select = 'SELECT %s FROM `%s` %s'; | ||
var fields = this.isEmpty(this._fields) ? '*' : this._fields.join(','); | ||
var _a = this.toSql(), sql = _a.sql, params = _a.params; | ||
var sqlStr = (0, printj_1.sprintf)(select, fields, this.tableName, sql); | ||
this.free(); | ||
return { sql: sqlStr, params }; | ||
} | ||
delete() { | ||
const delSql = 'DELETE FROM `%s` %s'; | ||
const { sql, params } = this.toSql(); | ||
const sqlStr = (0, printj_1.sprintf)(delSql, this.tableName, sql); | ||
return { sql: sqlStr, params: params }; | ||
}; | ||
Builder.prototype.delete = function () { | ||
var delSql = 'DELETE FROM `%s` %s'; | ||
var _a = this.toSql(), sql = _a.sql, params = _a.params; | ||
var sqlStr = (0, printj_1.sprintf)(delSql, this.tableName, sql); | ||
this.free(); | ||
return { sql: sqlStr, params }; | ||
} | ||
update(data, options = {}) { | ||
const setSql = []; | ||
const changed = []; | ||
Object.entries(data).forEach(elm => { | ||
const [field, value] = elm; | ||
return { sql: sqlStr, params: params }; | ||
}; | ||
Builder.prototype.update = function (data, options) { | ||
if (options === void 0) { options = {}; } | ||
var setSql = []; | ||
var changed = []; | ||
Object.entries(data).forEach(function (elm) { | ||
var field = elm[0], value = elm[1]; | ||
if (value && value.$inc) { | ||
setSql.push(`\`${field}\`=\`${field}\` + ${value.inc}`); | ||
setSql.push("`" + field + "`=`" + field + "` + " + value.inc); | ||
} | ||
else { | ||
setSql.push(`${field}=?`); | ||
setSql.push(field + "=?"); | ||
changed.push(value === null || value === void 0 ? void 0 : value.toString()); | ||
} | ||
}); | ||
const { sql, params } = this.toSql(); | ||
params.map(i => changed.push(i)); | ||
const upSql = `UPDATE \`%s\` SET %s %s`; | ||
const sqlStr = (0, printj_1.sprintf)(upSql, this.tableName, setSql.join(','), sql); | ||
var _a = this.toSql(), sql = _a.sql, params = _a.params; | ||
params.map(function (i) { return changed.push(i); }); | ||
var upSql = "UPDATE `%s` SET %s %s"; | ||
var sqlStr = (0, printj_1.sprintf)(upSql, this.tableName, setSql.join(','), sql); | ||
this.free(); | ||
return { sql: sqlStr, params }; | ||
} | ||
insert(data) { | ||
const fields = []; | ||
const params = []; | ||
for (const field in data) { | ||
fields.push(`\`${field}\``); | ||
return { sql: sqlStr, params: changed }; | ||
}; | ||
Builder.prototype.insert = function (data) { | ||
var fields = []; | ||
var params = []; | ||
for (var field in data) { | ||
fields.push("`" + field + "`"); | ||
params.push(data[field]); | ||
} | ||
const fieldStr = fields.join(','); | ||
const placeholder = fields.map(_ => '?').join(','); | ||
const sql = 'INSERT INTO `%s` (%s) VALUES (%s)'; | ||
const preSql = (0, printj_1.sprintf)(sql, this.tableName, fieldStr, placeholder); | ||
return { sql: preSql, params }; | ||
} | ||
toSql() { | ||
const sqlObj = []; | ||
const values = []; | ||
const sequence = ['where', 'group', 'order', 'offset', 'limit']; | ||
sequence.forEach(item => { | ||
if (!this.sql[item]) { | ||
var fieldStr = fields.join(','); | ||
var placeholder = fields.map(function (_) { return '?'; }).join(','); | ||
var sql = 'INSERT INTO `%s` (%s) VALUES (%s)'; | ||
var preSql = (0, printj_1.sprintf)(sql, this.tableName, fieldStr, placeholder); | ||
return { sql: preSql, params: params }; | ||
}; | ||
Builder.prototype.toSql = function () { | ||
var _this = this; | ||
var sqlObj = []; | ||
var values = []; | ||
var sequence = ['where', 'group', 'order', 'offset', 'limit']; | ||
sequence.forEach(function (item) { | ||
if (!_this.sql[item]) { | ||
return; | ||
} | ||
const { sql, params } = this.sql[item]; | ||
var _a = _this.sql[item], sql = _a.sql, params = _a.params; | ||
sqlObj.push(sql); | ||
if (Array.isArray(params)) { | ||
params.map(v => values.push(v)); | ||
params.map(function (v) { return values.push(v); }); | ||
} | ||
@@ -149,10 +151,11 @@ else { | ||
return { sql: sqlObj.join(' '), params: values }; | ||
} | ||
free() { | ||
}; | ||
Builder.prototype.free = function () { | ||
this._fields = []; | ||
this.values = []; | ||
this.sql = {}; | ||
} | ||
; | ||
} | ||
exports.default = Builder; | ||
}; | ||
return Builder; | ||
}()); | ||
exports.Builder = Builder; | ||
//# sourceMappingURL=builder.js.map |
import Sqlite from 'better-sqlite3'; | ||
import { Dict, Definition } from './interface'; | ||
import { Dict, Schema, ModelOpts } from './interface'; | ||
export declare class Model { | ||
db: Sqlite.Database; | ||
dbFile: string; | ||
table: string; | ||
definition: Definition; | ||
attributes: Dict; | ||
changed: Dict; | ||
pk: string; | ||
constructor(definition?: Definition, dbFile?: string, table?: string); | ||
initialize(): void; | ||
private _db; | ||
protected _table: string; | ||
protected _schema: Schema; | ||
protected _dbFile: string; | ||
private _attributes; | ||
private _changed; | ||
private _pk; | ||
constructor(options: ModelOpts); | ||
get db(): Sqlite.Database; | ||
initialize(config: ModelOpts): void; | ||
attr(name: string, value: any): void; | ||
instance(data: Dict): any; | ||
clone<T extends Model>(instance: T): T; | ||
instance(data: Dict): Model; | ||
toObject(): Dict; | ||
toJSON(): Dict; | ||
exec(sql: string): any; | ||
find(where: Dict, options?: Dict): Dict[]; | ||
findOne(where: Dict, options?: Dict): Dict | null; | ||
findAll(where: Dict, options?: Dict): Dict[]; | ||
findById(id: bigint | number): Dict | null; | ||
findByIds(ids: number[]): Dict[]; | ||
insert(data: Dict): Dict; | ||
update(where: Dict, data: Dict): Dict; | ||
updateAttributes(data: Dict): Dict; | ||
upsert(data: Dict): Dict; | ||
save(): Dict; | ||
find(where: Dict, options?: Dict): Model[]; | ||
count(where: Dict): number; | ||
findOne(where: Dict, options?: Dict): Model | null; | ||
findAll(where: Dict, options?: Dict): Model[]; | ||
findById(id: bigint | number): Model | null; | ||
findByIds(ids: number[]): Model[]; | ||
create(data: Dict): Model; | ||
insert(data: Dict): Model; | ||
update(where: Dict, data: Dict): Model[]; | ||
updateAttributes(data: Dict): Model; | ||
upsert(data: Dict): Model; | ||
save(): Model; | ||
remove(): Sqlite.RunResult; | ||
deleteById(id: number): boolean; | ||
delete(where: Dict): Sqlite.RunResult; | ||
} |
@@ -1,192 +0,238 @@ | ||
'use strict'; | ||
var __importDefault = | ||
(this && this.__importDefault) || | ||
function (mod) { | ||
return mod && mod.__esModule ? mod : { default: mod }; | ||
}; | ||
Object.defineProperty(exports, '__esModule', { value: true }); | ||
"use strict"; | ||
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { | ||
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { | ||
if (ar || !(i in from)) { | ||
if (!ar) ar = Array.prototype.slice.call(from, 0, i); | ||
ar[i] = from[i]; | ||
} | ||
} | ||
return to.concat(ar || Array.prototype.slice.call(from)); | ||
}; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.Model = void 0; | ||
const better_sqlite3_1 = __importDefault(require('better-sqlite3')); | ||
const builder_1 = __importDefault(require('./builder')); | ||
class Database { | ||
constructor(file, options = {}) { | ||
console.log('dddvvvvv', file); | ||
this.db = (0, better_sqlite3_1.default)(file, options); | ||
} | ||
static getInstance(file, options = {}) { | ||
if (Database.instance) { | ||
return Database.instance; | ||
var builder_1 = require("./builder"); | ||
var db_1 = __importDefault(require("./db")); | ||
var ramda_1 = require("ramda"); | ||
var Model = /** @class */ (function () { | ||
function Model(options) { | ||
this._schema = {}; | ||
this._attributes = {}; | ||
this._changed = {}; | ||
this._pk = []; | ||
this.initialize(options); | ||
} | ||
return new Database(file, options); | ||
} | ||
} | ||
class Model { | ||
constructor(definition = {}, dbFile, table) { | ||
this.definition = definition; | ||
this.attributes = {}; | ||
this.changed = {}; | ||
this.dbFile = dbFile; | ||
this.table = table; | ||
} | ||
initialize() { | ||
if (!this.db) { | ||
this.db = Database.getInstance(this.dbFile).db; | ||
} | ||
for (const key in this.definition) { | ||
if (this.definition[key].pk) { | ||
this.pk = key; | ||
break; | ||
} | ||
} | ||
} | ||
attr(name, value) { | ||
if (name === this.pk) { | ||
this.pk = value; | ||
} | ||
this.attributes[name] = value; | ||
} | ||
instance(data) { | ||
const instance = new Model(this.definition); | ||
for (const key in data) { | ||
instance.attr(key, data[key]); | ||
} | ||
const handler = { | ||
get(target, key) { | ||
if (Reflect.has(target.changed, key)) { | ||
return Reflect.get(target.changed, key); | ||
Object.defineProperty(Model.prototype, "db", { | ||
get: function () { | ||
return this._db.db; | ||
}, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
Model.prototype.initialize = function (config) { | ||
if (this._db) { | ||
return; | ||
} | ||
if (Reflect.has(target.attributes, key)) { | ||
return Reflect.get(target.attributes, key); | ||
if (config.dbFile) { | ||
this._dbFile = config.dbFile; | ||
} | ||
if (typeof this[key] === 'function') { | ||
return this[key]; | ||
if (config.schema) { | ||
this._schema = config.schema; | ||
} | ||
if (config.table) { | ||
this._table = config.table; | ||
} | ||
this._db = db_1.default.getInstance(this._dbFile, config.dbOptions); | ||
for (var key in this._schema) { | ||
if (this._schema[key].pk) { | ||
this._pk.push(key); | ||
} | ||
} | ||
return; | ||
}; | ||
Model.prototype.attr = function (name, value) { | ||
this._attributes[name] = value; | ||
}; | ||
Model.prototype.clone = function (instance) { | ||
return Object.assign(Object.create(Model.prototype), instance); | ||
}; | ||
Model.prototype.instance = function (data) { | ||
this._changed = {}; | ||
this._attributes = {}; | ||
var instance = this.clone(this); | ||
for (var key in data) { | ||
instance.attr(key, data[key]); | ||
} | ||
var handler = { | ||
constructor: function (target, args) { | ||
return new (target.bind.apply(target, __spreadArray([void 0], args, false)))(); | ||
}, | ||
get: function (target, key) { | ||
if (Reflect.has(target._changed, key)) { | ||
return Reflect.get(target._changed, key); | ||
} | ||
if (Reflect.has(target._attributes, key)) { | ||
return Reflect.get(target._attributes, key); | ||
} | ||
if (Reflect.has(instance, key)) { | ||
return instance[key]; | ||
} | ||
return undefined; | ||
}, | ||
set: function (target, key, value) { | ||
if (value instanceof Function) { | ||
return Reflect.set(target, key, value); | ||
} | ||
if (Reflect.has(target._attributes, key) && !(0, ramda_1.equals)(Reflect.get(target._attributes, key), value)) { | ||
Reflect.set(target._changed, key, value); | ||
} | ||
if (Reflect.has(instance, key)) { | ||
return instance[key] = value; | ||
} | ||
return true; | ||
} | ||
}; | ||
var proxy = new Proxy(instance, handler); | ||
return proxy; | ||
}; | ||
Model.prototype.toObject = function () { | ||
return this._attributes; | ||
}; | ||
Model.prototype.toJSON = function () { | ||
return this.toObject(); | ||
}; | ||
Model.prototype.exec = function (sql) { | ||
return this.db.exec(sql); | ||
}; | ||
Model.prototype.find = function (where, options) { | ||
var _this = this; | ||
if (options === void 0) { options = {}; } | ||
var limit = options.limit, offset = options.offset, order = options.order, fields = options.fields, group = options.group; | ||
var builder = new builder_1.Builder({}); | ||
var _a = builder.table(this._table) | ||
.where(where) | ||
.fields(fields) | ||
.order(order) | ||
.group(group) | ||
.limit(limit) | ||
.offset(offset) | ||
.select(), sql = _a.sql, params = _a.params; | ||
var stmt = this.db.prepare(sql); | ||
var res = stmt.all.apply(stmt, params); | ||
if (options.rows) { | ||
return res; | ||
} | ||
return res.map(function (item) { | ||
return _this.instance(item); | ||
}); | ||
}; | ||
Model.prototype.count = function (where) { | ||
var res = this.findOne(where, { fields: ['count(*) as count'] }); | ||
return Number(res.count); | ||
}; | ||
Model.prototype.findOne = function (where, options) { | ||
if (options === void 0) { options = {}; } | ||
options.limit = 1; | ||
var res = this.find(where, options); | ||
if (res.length) { | ||
return res[0]; | ||
} | ||
return null; | ||
}, | ||
set(target, key, value) { | ||
target.changed[key] = value; | ||
}; | ||
Model.prototype.findAll = function (where, options) { | ||
if (options === void 0) { options = {}; } | ||
return this.find(where, options); | ||
}; | ||
Model.prototype.findById = function (id) { | ||
return this.findOne({ id: id }); | ||
}; | ||
Model.prototype.findByIds = function (ids) { | ||
return this.find({ id: { '$in': ids } }); | ||
}; | ||
Model.prototype.create = function (data) { | ||
return this.insert(data); | ||
}; | ||
Model.prototype.insert = function (data) { | ||
var _a; | ||
var builder = new builder_1.Builder({}); | ||
var _b = builder.table(this._table).insert(data), sql = _b.sql, params = _b.params; | ||
var lastInsertRowid = (_a = this.db.prepare(sql)).run.apply(_a, params).lastInsertRowid; | ||
return this.findById(lastInsertRowid); | ||
}; | ||
Model.prototype.update = function (where, data) { | ||
var _a; | ||
var builder = new builder_1.Builder({}); | ||
var _b = builder.table(this._table) | ||
.where(where) | ||
.update(data), sql = _b.sql, params = _b.params; | ||
(_a = this.db.prepare(sql)).run.apply(_a, params); | ||
return this.find(where); | ||
}; | ||
Model.prototype.updateAttributes = function (data) { | ||
var _this = this; | ||
if (!this._pk) { | ||
throw new Error('updateAttributes must be called on instance'); | ||
} | ||
var current = this._attributes; | ||
Object.entries(data).map(function (item) { | ||
var key = item[0], value = item[1]; | ||
if ((0, ramda_1.has)(key, current)) { | ||
_this._changed[key] = value; | ||
} | ||
}); | ||
return this.save(); | ||
}; | ||
Model.prototype.upsert = function (data) { | ||
if (data.id) { | ||
var record = this.findById(data.id); | ||
if (record) { | ||
return record.updateAttributes(data); | ||
} | ||
} | ||
return this.insert(data); | ||
}; | ||
Model.prototype.save = function () { | ||
var pk = (0, ramda_1.pick)(this._pk, this._attributes); | ||
if (!this._pk || (0, ramda_1.isEmpty)(pk)) { | ||
throw new Error('save must be called on instance'); | ||
} | ||
if (!Object.keys(this._changed).length) { | ||
return this; | ||
} | ||
var instance = this.update(pk, this._changed)[0]; | ||
return instance; | ||
}; | ||
Model.prototype.remove = function () { | ||
var pk = (0, ramda_1.pick)(this._pk, this._attributes); | ||
if (!this._pk || (0, ramda_1.isEmpty)(pk)) { | ||
throw new Error('save must be called on instance'); | ||
} | ||
return this.delete(pk); | ||
}; | ||
Model.prototype.deleteById = function (id) { | ||
var _a; | ||
var record = this.findById(id); | ||
if (!record) { | ||
return false; | ||
} | ||
var builder = new builder_1.Builder({}); | ||
var _b = builder.table(this._table) | ||
.where({ id: id }) | ||
.delete(), sql = _b.sql, params = _b.params; | ||
(_a = this.db.prepare(sql)).run.apply(_a, params); | ||
return true; | ||
} | ||
}; | ||
const proxy = new Proxy(instance, handler); | ||
return proxy; | ||
} | ||
toObject() { | ||
return this.attributes; | ||
} | ||
toJSON() { | ||
return this.toJSON(); | ||
} | ||
exec(sql) { | ||
return this.db.exec(sql); | ||
} | ||
find(where, options = {}) { | ||
const { limit, offset, order, fields, group } = options; | ||
const builder = new builder_1.default({}); | ||
const { sql, params } = builder | ||
.table(this.table) | ||
.where(where) | ||
.fields(fields) | ||
.order(order) | ||
.group(group) | ||
.limit(limit) | ||
.offset(offset) | ||
.select(); | ||
console.log(sql); | ||
const stmt = this.db.prepare(sql); | ||
return stmt.all(...params); | ||
} | ||
findOne(where, options = {}) { | ||
options.limit = 1; | ||
const res = this.find(where, options); | ||
if (res.length) { | ||
return this.instance(res[0]); | ||
} | ||
return null; | ||
} | ||
findAll(where, options = {}) { | ||
return this.find(where, options); | ||
} | ||
findById(id) { | ||
return this.findOne({ id }); | ||
} | ||
findByIds(ids) { | ||
const data = this.find({ id: { $in: ids } }); | ||
if (!data.length) { | ||
return data; | ||
} | ||
} | ||
insert(data) { | ||
const builder = new builder_1.default({}); | ||
const { sql, params } = builder.table(this.table).insert(data); | ||
const { lastInsertRowid } = this.db.prepare(sql).run(...params); | ||
return this.findById(lastInsertRowid); | ||
} | ||
update(where, data) { | ||
const builder = new builder_1.default({}); | ||
const { sql, params } = builder.table(this.table).where(where).update(data); | ||
const { lastInsertRowid } = this.db.prepare(sql).run(...params); | ||
return this.findById(lastInsertRowid); | ||
} | ||
updateAttributes(data) { | ||
if (!this.pk) { | ||
throw new Error('updateAttributes must be called on instance'); | ||
} | ||
return this.update({ id: this.pk }, data); | ||
} | ||
upsert(data) { | ||
if (!data.id) { | ||
throw new Error('ID not found'); | ||
} | ||
const record = this.findById(data.id); | ||
if (record) { | ||
return this.update({ id: data.id }, data); | ||
} | ||
return this.insert(data); | ||
} | ||
save() { | ||
if (!this.pk) { | ||
throw new Error('save must be called on instance'); | ||
} | ||
return this.update({ id: this.pk }, this.changed); | ||
} | ||
deleteById(id) { | ||
const record = this.findById(id); | ||
if (!record) { | ||
return false; | ||
} | ||
const builder = new builder_1.default({}); | ||
const { sql, params } = builder.table(this.table).where({ id }).delete(); | ||
this.db.prepare(sql).run(...params); | ||
return true; | ||
} | ||
delete(where) { | ||
const builder = new builder_1.default({}); | ||
const { sql, params } = builder.table(this.table).where(where).delete(); | ||
return this.db.prepare(sql).run(...params); | ||
} | ||
} | ||
Model.prototype.delete = function (where) { | ||
var _a; | ||
var builder = new builder_1.Builder({}); | ||
var _b = builder.table(this._table) | ||
.where(where) | ||
.delete(), sql = _b.sql, params = _b.params; | ||
return (_a = this.db.prepare(sql)).run.apply(_a, params); | ||
}; | ||
return Model; | ||
}()); | ||
exports.Model = Model; | ||
function model(table = '', definition = {}) { | ||
return function cls(target) { | ||
return class extends target { | ||
constructor() { | ||
super(...arguments); | ||
this.table = table; | ||
this.definition = definition; | ||
} | ||
}; | ||
}; | ||
} | ||
// @model('users1', { a: 1 }) | ||
class User extends Model { | ||
constructor() { | ||
super(); | ||
this.dbFile = './test.db'; | ||
this.table = 'users'; | ||
this.initialize(); | ||
} | ||
} | ||
const user = new User(); | ||
// user.initialize(); | ||
// console.log(user.findOne({})); | ||
//# sourceMappingURL=model.js.map |
@@ -9,3 +9,3 @@ import { Dict } from './interface'; | ||
} | ||
export default class Parser { | ||
export declare class Parser { | ||
private tree; | ||
@@ -12,0 +12,0 @@ constructor(); |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const printj_1 = require("printj"); | ||
const OPERATOR = { | ||
exports.Parser = void 0; | ||
var printj_1 = require("printj"); | ||
var OPERATOR = { | ||
'$eq': '=', | ||
@@ -16,3 +17,3 @@ '$neq': '!=', | ||
}; | ||
const LOGICAL = { | ||
var LOGICAL = { | ||
$and: 'AND', | ||
@@ -22,27 +23,30 @@ $or: 'OR', | ||
}; | ||
class Parser { | ||
constructor() { | ||
var Parser = /** @class */ (function () { | ||
function Parser() { | ||
this.tree = []; | ||
} | ||
genNode(entities, isChild = false) { | ||
Object.entries(entities).forEach((item) => { | ||
const key = item[0]; | ||
const v = item[1]; | ||
const value = v && typeof v === 'object' ? v : { $eq: v }; | ||
Parser.prototype.genNode = function (entities, isChild) { | ||
var _this = this; | ||
if (isChild === void 0) { isChild = false; } | ||
Object.entries(entities).forEach(function (item) { | ||
var key = item[0]; | ||
var v = item[1]; | ||
var value = v && typeof v === 'object' ? v : { $eq: v }; | ||
if (!(key in LOGICAL)) { | ||
if (Array.isArray(value)) { | ||
value.forEach(i => { | ||
this.genNode(i, true); | ||
value.forEach(function (i) { | ||
_this.genNode(i, true); | ||
}); | ||
} | ||
else { | ||
Object.keys(value).map(op => { | ||
const node = { | ||
Object.keys(value).map(function (op) { | ||
var _a; | ||
var node = { | ||
type: 'field', | ||
name: key, | ||
value: { [op]: value[op] }, | ||
value: (_a = {}, _a[op] = value[op], _a), | ||
isChild: true, | ||
connector: ' AND ' | ||
}; | ||
this.tree.push(node); | ||
_this.tree.push(node); | ||
}); | ||
@@ -52,14 +56,14 @@ } | ||
else { | ||
const node = { | ||
var node = { | ||
type: 'logical', | ||
name: LOGICAL[key], | ||
value, | ||
isChild, | ||
value: value, | ||
isChild: isChild, | ||
}; | ||
this.tree.push(node); | ||
this.genNode(value, true); | ||
_this.tree.push(node); | ||
_this.genNode(value, true); | ||
} | ||
}); | ||
} | ||
getDefaultNode(isChild) { | ||
}; | ||
Parser.prototype.getDefaultNode = function (isChild) { | ||
return { | ||
@@ -69,12 +73,13 @@ type: 'operator', | ||
value: isChild ? 0 : 1, | ||
isChild, | ||
isChild: isChild, | ||
}; | ||
} | ||
parse(entities) { | ||
}; | ||
Parser.prototype.parse = function (entities) { | ||
var _this = this; | ||
this.genNode(entities); | ||
const sql = []; | ||
let prev; | ||
let level = 0; | ||
const params = []; | ||
this.tree.forEach((node) => { | ||
var sql = []; | ||
var prev; | ||
var level = 0; | ||
var params = []; | ||
this.tree.forEach(function (node) { | ||
if (node.type === 'field') { | ||
@@ -84,8 +89,8 @@ if (prev && prev.type !== 'field') { | ||
} | ||
const res = this.parseFieldNode(node); | ||
var res = _this.parseFieldNode(node); | ||
sql.push(res.sql); | ||
res.values.map((v) => params.push(v)); | ||
res.values.map(function (v) { return params.push(v); }); | ||
} | ||
else { | ||
sql.push(this.parseLogicalNode(node)); | ||
sql.push(_this.parseLogicalNode(node)); | ||
if (!node.isChild) { | ||
@@ -106,17 +111,18 @@ sql.push('('); | ||
this.free(); | ||
return { sql: sql.join('').replace(/(.*)and/i, '$1'), params }; | ||
} | ||
parseFieldNode(node) { | ||
return { sql: sql.join('').replace(/(.*)and/i, '$1'), params: params }; | ||
}; | ||
Parser.prototype.parseFieldNode = function (node) { | ||
var _this = this; | ||
var _a; | ||
let fieldStr = ''; | ||
const field = '`' + node.name + '`'; | ||
const connector = (_a = node.connector) === null || _a === void 0 ? void 0 : _a.toUpperCase().substr(1); | ||
const values = []; | ||
Object.entries(node.value).forEach(element => { | ||
const operator = element[0]; | ||
const value = element[1]; | ||
const name = `$${node.name}`; | ||
const temp = [field]; | ||
var fieldStr = ''; | ||
var field = '`' + node.name + '`'; | ||
var connector = (_a = node.connector) === null || _a === void 0 ? void 0 : _a.toUpperCase().substr(1); | ||
var values = []; | ||
Object.entries(node.value).forEach(function (element) { | ||
var operator = element[0]; | ||
var value = element[1]; | ||
// const name = `$${node.name}`; | ||
var temp = [field]; | ||
if (operator === '$inc') { | ||
temp.push(this.increment(node.name, value)); | ||
temp.push(_this.increment(node.name, value)); | ||
} | ||
@@ -129,5 +135,11 @@ else if (OPERATOR[operator]) { | ||
else { | ||
const func = this.sqlFunction(operator); | ||
temp.push((0, printj_1.sprintf)(func, name)); | ||
values.push({ [name]: value === null || value === void 0 ? void 0 : value.toString() }); | ||
var func = _this.sqlFunction(operator); | ||
if (Array.isArray(value)) { | ||
temp.push((0, printj_1.sprintf)(func, Array(value.length).fill('?').join(','))); | ||
value.map(function (v) { return values.push(v); }); | ||
} | ||
else { | ||
temp.push((0, printj_1.sprintf)(func, '?')); | ||
values.push(value === null || value === void 0 ? void 0 : value.toString()); | ||
} | ||
} | ||
@@ -137,8 +149,8 @@ temp.push(connector); | ||
}); | ||
return { sql: fieldStr, values }; | ||
} | ||
parseLogicalNode(node) { | ||
return ` ${node.name} `; | ||
} | ||
increment(field, value) { | ||
return { sql: fieldStr, values: values }; | ||
}; | ||
Parser.prototype.parseLogicalNode = function (node) { | ||
return " " + node.name + " "; | ||
}; | ||
Parser.prototype.increment = function (field, value) { | ||
if (isNaN(value)) { | ||
@@ -148,13 +160,12 @@ throw new Error('mews increment value must be number'); | ||
return '=`' + field + '` + ' + value; | ||
} | ||
sqlFunction(name) { | ||
return name.toUpperCase().replace('$', '') + ' (%s) '; | ||
} | ||
free() { | ||
}; | ||
Parser.prototype.sqlFunction = function (name) { | ||
return name.toUpperCase().replace('$', '') + '(%s)'; | ||
}; | ||
Parser.prototype.free = function () { | ||
this.tree = []; | ||
} | ||
} | ||
exports.default = Parser; | ||
// let p = new Parser(); | ||
// let r = p.parse({ a: 1, b: { $gt: 7, $lt: 9 }, c: { $in: [3, 4, 5] } }); | ||
// console.log('%j', r); | ||
}; | ||
return Parser; | ||
}()); | ||
exports.Parser = Parser; | ||
//# sourceMappingURL=parser.js.map |
@@ -1,2 +0,2 @@ | ||
import Parser from "./parser"; | ||
import { Parser } from "./parser"; | ||
import { Dict } from './interface'; | ||
@@ -6,3 +6,3 @@ import { sprintf } from 'printj'; | ||
export default class Builder { | ||
export class Builder { | ||
sql: Dict; | ||
@@ -13,5 +13,5 @@ _fields: string[]; | ||
private parser: Parser; | ||
options: object; | ||
options: Dict; | ||
constructor(options: any) { | ||
constructor(options: Dict) { | ||
this.options = options; | ||
@@ -30,3 +30,3 @@ this.parser = new Parser(); | ||
isEmpty(data: any): boolean { | ||
isEmpty(data: string[] | string | Dict): boolean { | ||
if (!data) { | ||
@@ -49,3 +49,3 @@ return true; | ||
where(condition: any): Builder { | ||
where(condition: Dict): Builder { | ||
if (this.isEmpty(condition)) { | ||
@@ -65,3 +65,3 @@ return this; | ||
const [field, sort] = elm; | ||
this.sql.order = { sql: `ORDER BY ? ?`, params: [field, sort] }; | ||
this.sql.order = { sql: `ORDER BY ${field} ${sort}`, params: [] }; | ||
})) | ||
@@ -87,3 +87,3 @@ return this; | ||
group(field: string | string[]) { | ||
group(field: string | string[]): Builder { | ||
if (this.isEmpty(field)) { | ||
@@ -93,4 +93,4 @@ return this; | ||
this.sql.group = { | ||
sql: `GROUP BY ?`, | ||
params: [field?.toString()] | ||
sql: `GROUP BY ${field.toString()}`, | ||
params: [] | ||
}; | ||
@@ -100,3 +100,3 @@ return this; | ||
select(options: Dict | null = null) { | ||
select(options: Dict | null = null): { sql: string, params: any[] } { | ||
const select = 'SELECT %s FROM `%s` %s'; | ||
@@ -110,3 +110,3 @@ const fields = this.isEmpty(this._fields) ? '*' : this._fields.join(','); | ||
delete() { | ||
delete(): { sql: string, params: any[] } { | ||
const delSql = 'DELETE FROM `%s` %s' | ||
@@ -119,3 +119,3 @@ const { sql, params } = this.toSql(); | ||
update(data: Dict, options: Dict = {}) { | ||
update(data: Dict, options: Dict = {}): { sql: string, params: any[] } { | ||
const setSql: string[] = []; | ||
@@ -140,3 +140,3 @@ const changed = []; | ||
insert(data: Dict) { | ||
insert(data: Dict): { sql: string, params: any[] } { | ||
const fields: string[] = []; | ||
@@ -155,5 +155,5 @@ const params: any[] = []; | ||
toSql() { | ||
toSql(): { sql: string, params: any[] } { | ||
const sqlObj: string[] = []; | ||
const values: any[] = [] | ||
const values: any[] = []; | ||
const sequence = ['where', 'group', 'order', 'offset', 'limit']; | ||
@@ -160,0 +160,0 @@ sequence.forEach(item => { |
205
lib/model.ts
import Sqlite from 'better-sqlite3'; | ||
import Builder from './builder'; | ||
import { Dict, Definition } from './interface'; | ||
import { Builder } from './builder'; | ||
import { Dict, Schema, ModelOpts } from './interface'; | ||
import DB from './db'; | ||
import { isEmpty, pick, has, equals } from 'ramda'; | ||
class Database { | ||
readonly db: Sqlite.Database | null; | ||
private static instance: Database; | ||
private constructor(file: string, options: Dict = {}) { | ||
this.db = Sqlite(file, options) | ||
export class Model { | ||
private _db: DB; | ||
protected _table: string; | ||
protected _schema: Schema = {}; | ||
protected _dbFile: string; | ||
private _attributes: Dict; | ||
private _changed: Dict; | ||
private _pk: string[]; | ||
constructor(options: ModelOpts) { | ||
this._attributes = {}; | ||
this._changed = {}; | ||
this._pk = []; | ||
this.initialize(options); | ||
} | ||
static getInstance(file: string, options: Dict = {}) { | ||
if (Database.instance) { | ||
return Database.instance; | ||
} | ||
return new Database(file, options); | ||
get db(): Sqlite.Database { | ||
return this._db.db; | ||
} | ||
} | ||
export class Model { | ||
db: Sqlite.Database; | ||
dbFile: string; | ||
table: string; | ||
definition: Definition; | ||
attributes: Dict; | ||
changed: Dict; | ||
pk: string; | ||
constructor(definition: Definition = {}, dbFile?: string, table?: string,) { | ||
this.definition = definition; | ||
this.attributes = {}; | ||
this.changed = {}; | ||
this.dbFile = dbFile; | ||
this.table = table; | ||
} | ||
initialize() { | ||
if (!this.db && this.dbFile) { | ||
this.db = Database.getInstance(this.dbFile).db; | ||
} | ||
if (this.pk) { | ||
initialize(config: ModelOpts): void { | ||
if (this._db) { | ||
return; | ||
} | ||
for (const key in this.definition) { | ||
if (this.definition[key].pk) { | ||
this.pk = key; | ||
break; | ||
if (config.dbFile) { | ||
this._dbFile = config.dbFile; | ||
} | ||
if (config.schema) { | ||
this._schema = config.schema; | ||
} | ||
if (config.table) { | ||
this._table = config.table; | ||
} | ||
this._db = DB.getInstance(this._dbFile, config.dbOptions); | ||
for (const key in this._schema) { | ||
if (this._schema[key].pk) { | ||
this._pk.push(key); | ||
} | ||
} | ||
return; | ||
} | ||
attr(name: string, value: any) { | ||
if (name === this.pk) { | ||
this.pk = value; | ||
} | ||
this.attributes[name] = value; | ||
attr(name: string, value: any): void { | ||
this._attributes[name] = value; | ||
} | ||
clone<T>(instance: T): T { | ||
clone<T extends Model>(instance: T): T { | ||
return Object.assign(Object.create(Model.prototype), instance); | ||
} | ||
instance(data: Dict) { | ||
instance(data: Dict): Model { | ||
this._changed = {}; | ||
this._attributes = {}; | ||
const instance = this.clone(this); | ||
@@ -72,7 +68,7 @@ for (const key in data) { | ||
get(target: any, key: string) { | ||
if (Reflect.has(target.changed, key)) { | ||
return Reflect.get(target.changed, key); | ||
if (Reflect.has(target._changed, key)) { | ||
return Reflect.get(target._changed, key); | ||
} | ||
if (Reflect.has(target.attributes, key)) { | ||
return Reflect.get(target.attributes, key); | ||
if (Reflect.has(target._attributes, key)) { | ||
return Reflect.get(target._attributes, key); | ||
} | ||
@@ -86,6 +82,10 @@ if (Reflect.has(instance, key)) { | ||
if (value instanceof Function) { | ||
target[key] = value; | ||
} else { | ||
target.changed[key] = value; | ||
return Reflect.set(target, key, value); | ||
} | ||
if (Reflect.has(target._attributes, key) && !equals(Reflect.get(target._attributes, key), value)) { | ||
Reflect.set(target._changed, key, value); | ||
} | ||
if (Reflect.has(instance, key)) { | ||
return instance[key] = value; | ||
} | ||
return true; | ||
@@ -99,3 +99,3 @@ } | ||
toObject(): Dict { | ||
return this.attributes; | ||
return this._attributes; | ||
} | ||
@@ -111,6 +111,6 @@ | ||
find(where: Dict, options: Dict = {}): Dict[] { | ||
find(where: Dict, options: Dict = {}): Model[] { | ||
const { limit, offset, order, fields, group } = options; | ||
const builder = new Builder({}); | ||
const { sql, params } = builder.table(this.table) | ||
const { sql, params } = builder.table(this._table) | ||
.where(where) | ||
@@ -124,11 +124,21 @@ .fields(fields) | ||
const stmt = this.db.prepare(sql); | ||
return stmt.all(...params) | ||
const res = stmt.all(...params); | ||
if (options.rows) { | ||
return res; | ||
} | ||
return res.map(item => { | ||
return this.instance(item); | ||
}) | ||
} | ||
count(where: Dict): number { | ||
const res = this.findOne(where, { fields: ['count(*) as count'] }); | ||
return Number(res.count); | ||
} | ||
findOne(where: Dict, options: Dict = {}): Dict | null { | ||
findOne(where: Dict, options: Dict = {}): Model | null { | ||
options.limit = 1; | ||
const res = this.find(where, options); | ||
if (res.length) { | ||
return this.instance(res[0]); | ||
return res[0]; | ||
} | ||
@@ -138,20 +148,20 @@ return null; | ||
findAll(where: Dict, options: Dict = {}): Dict[] { | ||
findAll(where: Dict, options: Dict = {}): Model[] { | ||
return this.find(where, options); | ||
} | ||
findById(id: bigint | number): Dict | null { | ||
findById(id: bigint | number): Model | null { | ||
return this.findOne({ id }); | ||
} | ||
findByIds(ids: number[]): Dict[] { | ||
const data = this.find({ id: { '$in': ids } }); | ||
if (!data.length) { | ||
return data; | ||
} | ||
findByIds(ids: number[]): Model[] { | ||
return this.find({ id: { '$in': ids } }); | ||
} | ||
create(data: Dict): Model { | ||
return this.insert(data); | ||
} | ||
insert(data: Dict): Dict { | ||
insert(data: Dict): Model { | ||
const builder = new Builder({}); | ||
const { sql, params } = builder.table(this.table).insert(data); | ||
const { sql, params } = builder.table(this._table).insert(data); | ||
const { lastInsertRowid } = this.db.prepare(sql).run(...params); | ||
@@ -161,37 +171,58 @@ return this.findById(lastInsertRowid); | ||
update(where: Dict, data: Dict): Dict { | ||
update(where: Dict, data: Dict): Model[] { | ||
const builder = new Builder({}); | ||
const { sql, params } = builder.table(this.table) | ||
const { sql, params } = builder.table(this._table) | ||
.where(where) | ||
.update(data); | ||
const { lastInsertRowid } = this.db.prepare(sql).run(...params); | ||
this.changed = {}; | ||
return this.findById(lastInsertRowid); | ||
this.db.prepare(sql).run(...params); | ||
return this.find(where); | ||
} | ||
updateAttributes(data: Dict): Dict { | ||
if (!this.pk) { | ||
updateAttributes(data: Dict): Model { | ||
if (!this._pk) { | ||
throw new Error('updateAttributes must be called on instance'); | ||
} | ||
return this.update({ id: this.pk }, data); | ||
const current = this._attributes; | ||
Object.entries(data).map(item => { | ||
const [key, value] = item; | ||
if (has(key, current)) { | ||
this._changed[key] = value; | ||
} | ||
}); | ||
return this.save(); | ||
} | ||
upsert(data: Dict): Dict { | ||
if (!data.id) { | ||
throw new Error('ID not found'); | ||
upsert(data: Dict): Model { | ||
if (data.id) { | ||
const record = this.findById(data.id); | ||
if (record) { | ||
return record.updateAttributes(data); | ||
} | ||
} | ||
const record = this.findById(data.id); | ||
if (record) { | ||
return this.update({ id: data.id }, data); | ||
} | ||
return this.insert(data); | ||
} | ||
save(): Dict { | ||
if (!this.pk) { | ||
save(): Model { | ||
const pk = pick(this._pk, this._attributes); | ||
if (!this._pk || isEmpty(pk)) { | ||
throw new Error('save must be called on instance'); | ||
} | ||
return this.update({ id: this.pk }, this.changed); | ||
if (!Object.keys(this._changed).length) { | ||
return this; | ||
} | ||
const [instance] = this.update(pk, this._changed); | ||
return instance; | ||
} | ||
remove(): Sqlite.RunResult { | ||
const pk = pick(this._pk, this._attributes) | ||
if (!this._pk || isEmpty(pk)) { | ||
throw new Error('save must be called on instance'); | ||
} | ||
return this.delete(pk); | ||
} | ||
deleteById(id: number): boolean { | ||
@@ -203,3 +234,3 @@ const record = this.findById(id); | ||
const builder = new Builder({}); | ||
const { sql, params } = builder.table(this.table) | ||
const { sql, params } = builder.table(this._table) | ||
.where({ id }) | ||
@@ -213,3 +244,3 @@ .delete(); | ||
const builder = new Builder({}); | ||
const { sql, params } = builder.table(this.table) | ||
const { sql, params } = builder.table(this._table) | ||
.where(where) | ||
@@ -216,0 +247,0 @@ .delete(); |
@@ -32,3 +32,3 @@ import { sprintf } from 'printj' | ||
export default class Parser { | ||
export class Parser { | ||
private tree: Node[]; | ||
@@ -39,3 +39,3 @@ constructor() { | ||
genNode(entities: any, isChild: boolean = false) { | ||
genNode(entities: any, isChild = false): void { | ||
Object.entries(entities).forEach((item: any[]) => { | ||
@@ -70,2 +70,3 @@ const key: string = item[0]; | ||
this.tree.push(node); | ||
this.genNode(value, true); | ||
@@ -86,3 +87,3 @@ } | ||
parse(entities: any) { | ||
parse(entities: any): { sql: string, params: any[] } { | ||
this.genNode(entities); | ||
@@ -128,3 +129,3 @@ const sql: string[] = []; | ||
const value: any = element[1]; | ||
const name = `$${node.name}`; | ||
// const name = `$${node.name}`; | ||
const temp: any[] = [field]; | ||
@@ -139,4 +140,9 @@ if (operator === '$inc') { | ||
const func = this.sqlFunction(operator); | ||
temp.push(sprintf(func, name)); | ||
values.push({ [name]: value?.toString() }); | ||
if (Array.isArray(value)) { | ||
temp.push(sprintf(func, Array(value.length).fill('?').join(','))); | ||
value.map(v => values.push(v)); | ||
} else { | ||
temp.push(sprintf(func, '?')); | ||
values.push(value?.toString()); | ||
} | ||
} | ||
@@ -162,13 +168,8 @@ temp.push(connector); | ||
private sqlFunction(name: string): string { | ||
return name.toUpperCase().replace('$', '') + ' (%s) '; | ||
return name.toUpperCase().replace('$', '') + '(%s)'; | ||
} | ||
free() { | ||
free(): void { | ||
this.tree = []; | ||
} | ||
} | ||
// let p = new Parser(); | ||
// let r = p.parse({ a: 1, b: { $gt: 7, $lt: 9 }, c: { $in: [3, 4, 5] } }); | ||
// console.log('%j', r); |
{ | ||
"name": "lite-model", | ||
"version": "0.0.3", | ||
"main": "lib/model.js", | ||
"version": "0.0.4", | ||
"main": "dist/index.js", | ||
"scripts": { | ||
"build": "tsc --build", | ||
"c": "tsc -p tsconfig.json", | ||
"build": "tsc ", | ||
"clean": "tsc --build --clean", | ||
@@ -16,5 +15,6 @@ "test": "echo \"Error: no test specified\" && exit 1" | ||
"@typescript-eslint/parser": "^4.33.0", | ||
"better-sqlite3": "^7.4.3", | ||
"better-sqlite3": "^7.4.4", | ||
"eslint": "^7.32.0", | ||
"printj": "^1.3.0" | ||
"printj": "^1.3.0", | ||
"ramda": "^0.27.1" | ||
}, | ||
@@ -21,0 +21,0 @@ "devDependencies": { |
{ | ||
"compilerOptions": { | ||
"target": "ES2018", | ||
"target": "es5", | ||
"module": "commonjs", | ||
"declaration": true, | ||
"sourceMap": false, | ||
"sourceMap": true, | ||
"allowJs": true, | ||
@@ -15,4 +15,4 @@ "rootDir": "lib", | ||
}, | ||
"include": ["lib/**/*", "lib/typings.d.ts"], | ||
"include": ["lib/**/*"], | ||
"exclude": ["node_modules", "dist", "**/__test__", "test", "docs", "tests"] | ||
} |
64497
33
1400
6
+ Addedramda@^0.27.1
+ Addedramda@0.27.2(transitive)
Updatedbetter-sqlite3@^7.4.4