UNPKG

sqlmongoose

Version:

Mongoose-like schemas and models for SQLite3

203 lines (202 loc) 7.56 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Model = void 0; class Model { constructor(db, tableName, schema) { this.db = db; this.tableName = tableName; this.schema = schema; this.initialize(); } initialize() { const createTableQuery = this.schema.createTable(this.tableName); this.db.run(createTableQuery.join(';')); } async find(query = {}, options = {}) { let conditions = []; let values = []; if (this.isSimpleQuery(query)) { Object.entries(query).forEach(([key, value]) => { conditions.push(`${key} = ?`); values.push(value); }); } else { Object.entries(query).forEach(([field, operators]) => { Object.entries(operators).forEach(([op, value]) => { switch (op) { case 'eq': conditions.push(`${field} = ?`); values.push(value); break; case 'ne': conditions.push(`${field} != ?`); values.push(value); break; case 'gt': conditions.push(`${field} > ?`); values.push(value); break; case 'gte': conditions.push(`${field} >= ?`); values.push(value); break; case 'lt': conditions.push(`${field} < ?`); values.push(value); break; case 'lte': conditions.push(`${field} <= ?`); values.push(value); break; case 'like': conditions.push(`${field} LIKE ?`); values.push(`%${value}%`); break; case 'in': conditions.push(`${field} IN (${value.map(() => '?').join(',')})`); values.push(...value); break; } }); }); } let sql = conditions.length ? `SELECT * FROM ${this.tableName} WHERE ${conditions.join(' AND ')}` : `SELECT * FROM ${this.tableName}`; if (options.orderBy) { const orderClauses = Object.entries(options.orderBy) .map(([field, order]) => `${field} ${order}`) .join(', '); sql += ` ORDER BY ${orderClauses}`; } if (options.limit) { sql += ` LIMIT ${options.limit}`; if (options.offset) { sql += ` OFFSET ${options.offset}`; } } const results = await this.query(sql, values); if (options.populate) { return this.populateRelationships(results, options.populate); } return results; } async findOne(query) { const result = await this.find(query); return result[0] || null; } async create(data) { await this.schema.runValidation(data); for (const hook of this.schema['hooks'].preSave) { await hook(data); } const keys = Object.keys(data); const values = Object.values(data); const placeholders = new Array(keys.length).fill('?').join(','); const sql = `INSERT INTO ${this.tableName} (${keys.join(',')}) VALUES (${placeholders})`; return new Promise((resolve, reject) => { this.db.run(sql, values, function (err) { if (err) { reject(err); } else { const createdData = { ...data, id: this.lastID }; // Execute post-save hooks Promise.all(this.schema['hooks'].postSave.map((hook) => hook(createdData))) .then(() => resolve(createdData)) .catch((error) => reject(error)); } }); }); } async update(query, update) { for (const hook of this.schema['hooks'].preUpdate) { await hook(update); } let setClause = []; let values = []; if (this.isUpdateOperator(update)) { if (update.$inc) { Object.entries(update.$inc).forEach(([key, value]) => { setClause.push(`${key} = ${key} + ?`); values.push(value); }); } if (update.$set) { Object.entries(update.$set).forEach(([key, value]) => { setClause.push(`${key} = ?`); values.push(value); }); } if (update.$unset) { Object.entries(update.$unset).forEach(([key]) => { setClause.push(`${key} = NULL`); }); } } else { setClause = Object.keys(update).map(key => `${key} = ?`); values = Object.values(update); } const whereClause = Object.keys(query) .map(key => `${key} = ?`) .join(' AND '); values.push(...Object.values(query)); const sql = `UPDATE ${this.tableName} SET ${setClause.join(', ')} WHERE ${whereClause}`; return new Promise((resolve, reject) => { this.db.run(sql, values, function (err) { if (err) reject(err); resolve(this.changes); }); }); } isUpdateOperator(update) { return update.$inc !== undefined || update.$set !== undefined || update.$unset !== undefined; } async delete(query) { const whereClause = Object.keys(query) .map(key => `${key} = ?`) .join(' AND '); const values = Object.values(query); const sql = `DELETE FROM ${this.tableName} WHERE ${whereClause}`; return new Promise((resolve, reject) => { this.db.run(sql, values, function (err) { if (err) reject(err); resolve(this.changes); }); }); } async populateRelationships(results, fields) { const relationships = this.schema.getRelationships(); for (const result of results) { for (const field of fields) { if (relationships[field]) { const refModel = relationships[field]; const foreignKey = result[field]; if (foreignKey) { result[field] = await this.db.get(`SELECT * FROM ${refModel} WHERE id = ?`, [foreignKey]); } } } } return results; } isSimpleQuery(query) { return !Object.values(query).some(v => typeof v === 'object'); } query(sql, params) { return new Promise((resolve, reject) => { this.db.all(sql, params, (err, rows) => { if (err) reject(err); resolve(rows); }); }); } } exports.Model = Model;