UNPKG

zumito-db

Version:

Multi-driver database abstraction layer with decorator-based models

117 lines (116 loc) 4.3 kB
import { toSqlOperator } from '../operators.js'; export class SqlCompiler { compileSelect(ir) { const params = []; const fields = ir.select && ir.select.length > 0 ? ir.select.join(', ') : '*'; const table = ir.collection; const where = this.compileWhere(ir.where, params); const order = this.compileOrder(ir.sort); const limit = ir.limit ? `LIMIT ${ir.limit}` : ''; const offset = ir.offset ? `OFFSET ${ir.offset}` : ''; let sql = `SELECT ${fields} FROM ${table}`; if (where) sql += ` WHERE ${where.sql}`; if (order) sql += ` ORDER BY ${order}`; if (limit) sql += ` ${limit}`; if (offset) sql += ` ${offset}`; return { sql, params: where ? where.params.concat(params) : params }; } compileInsert(collection, data) { const keys = Object.keys(data); const placeholders = keys.map(() => '?').join(', '); const params = keys.map(k => data[k]); const sql = `INSERT INTO ${collection} (${keys.join(', ')}) VALUES (${placeholders})`; return { sql, params }; } compileUpdate(collection, data, ir) { const params = []; const setClauses = Object.keys(data).map(k => { params.push(data[k]); return `${k} = ?`; }).join(', '); const where = this.compileWhere(ir.where, params); let sql = `UPDATE ${collection} SET ${setClauses}`; if (where) { sql += ` WHERE ${where.sql}`; params.push(...where.params); } return { sql, params }; } compileDelete(collection, ir) { const params = []; const where = this.compileWhere(ir.where, params); let sql = `DELETE FROM ${collection}`; if (where) { sql += ` WHERE ${where.sql}`; params.push(...where.params); } return { sql, params }; } compileCount(collection, ir) { const params = []; const where = this.compileWhere(ir.where, params); let sql = `SELECT COUNT(*) as count FROM ${collection}`; if (where) { sql += ` WHERE ${where.sql}`; params.push(...where.params); } return { sql, params }; } compileCreateTable(collection, fields) { const cols = fields.map(f => { let col = `${f.name} ${this.mapType(f.type)}`; if (f.primary) col += ' PRIMARY KEY'; if (!f.nullable) col += ' NOT NULL'; if (f.unique) col += ' UNIQUE'; return col; }); return `CREATE TABLE IF NOT EXISTS ${collection} (${cols.join(', ')})`; } compileWhere(clauses, params) { if (!clauses || clauses.length === 0) return null; const localParams = []; const parts = []; for (const clause of clauses) { const logic = parts.length > 0 ? ` ${clause.logic.toUpperCase()} ` : ''; if (clause.operator === 'in' || clause.operator === 'nin') { const placeholders = clause.value.map(() => '?').join(', '); parts.push(`${logic}${clause.field} ${toSqlOperator(clause.operator)} (${placeholders})`); localParams.push(...clause.value); } else if (clause.operator === 'between') { parts.push(`${logic}${clause.field} BETWEEN ? AND ?`); localParams.push(clause.value[0], clause.value[1]); } else { parts.push(`${logic}${clause.field} ${toSqlOperator(clause.operator)} ?`); localParams.push(clause.value); } } return { sql: parts.join(''), params: localParams }; } compileOrder(sort) { if (!sort || sort.length === 0) return ''; return sort.map(s => `${s.field} ${s.dir.toUpperCase()}`).join(', '); } mapType(type) { const mapping = { string: 'TEXT', number: 'REAL', boolean: 'INTEGER', date: 'TEXT', object: 'TEXT', array: 'TEXT', any: 'TEXT', }; return mapping[type] || 'TEXT'; } }