@flavoai/fastfold
Version:
Zero-boilerplate backend for React apps with auto-generated CRUD and declarative security
163 lines • 5 kB
JavaScript
import Database from 'better-sqlite3';
import { BaseDatabaseAdapter } from './base';
export class SQLiteAdapter extends BaseDatabaseAdapter {
db;
filename;
constructor(filename = ':memory:') {
super();
this.filename = filename;
}
async connect() {
try {
this.db = new Database(this.filename);
this.connected = true;
}
catch (err) {
throw err;
}
}
async disconnect() {
if (!this.db)
return;
try {
this.db.close();
this.connected = false;
}
catch (err) {
throw err;
}
}
async createTable(tableName, schema) {
this.ensureConnected();
const fields = Object.entries(schema)
.map(([name, type]) => `${name} ${this.mapFieldType(type)}`)
.join(', ');
const sql = `
CREATE TABLE IF NOT EXISTS ${tableName} (
id INTEGER PRIMARY KEY AUTOINCREMENT,
${fields},
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
)
`;
try {
this.db.exec(sql);
}
catch (err) {
throw err;
}
}
async query(tableName, params) {
this.ensureConnected();
let sql = `SELECT ${params.select ? params.select.join(', ') : '*'} FROM ${tableName}`;
let values = [];
if (params.where) {
const where = this.buildWhereClause(params.where);
sql += ` ${where.sql}`;
values = where.values;
}
if (params.orderBy) {
sql += ` ${this.buildOrderByClause(params.orderBy)}`;
}
if (params.limit) {
sql += ` LIMIT ${params.limit}`;
}
if (params.offset) {
sql += ` OFFSET ${params.offset}`;
}
try {
const stmt = this.db.prepare(sql);
const rows = stmt.all(...values);
return rows;
}
catch (err) {
throw err;
}
}
async create(tableName, data) {
this.ensureConnected();
const fields = Object.keys(data);
const placeholders = fields.map(() => '?').join(', ');
const values = Object.values(data);
const sql = `
INSERT INTO ${tableName} (${fields.join(', ')})
VALUES (${placeholders})
`;
try {
const insertStmt = this.db.prepare(sql);
const result = insertStmt.run(...values);
// Fetch the created record
const selectSql = `SELECT * FROM ${tableName} WHERE id = ?`;
const selectStmt = this.db.prepare(selectSql);
const row = selectStmt.get(result.lastInsertRowid);
return row;
}
catch (err) {
throw err;
}
}
async update(tableName, id, data) {
this.ensureConnected();
const fields = Object.keys(data);
const setClause = fields.map(field => `${field} = ?`).join(', ');
const values = [...Object.values(data), id];
const sql = `
UPDATE ${tableName}
SET ${setClause}, updated_at = CURRENT_TIMESTAMP
WHERE id = ?
`;
try {
const updateStmt = this.db.prepare(sql);
updateStmt.run(...values);
// Fetch the updated record
const selectSql = `SELECT * FROM ${tableName} WHERE id = ?`;
const selectStmt = this.db.prepare(selectSql);
const row = selectStmt.get(id);
return row;
}
catch (err) {
throw err;
}
}
async delete(tableName, id) {
this.ensureConnected();
const sql = `DELETE FROM ${tableName} WHERE id = ?`;
try {
const deleteStmt = this.db.prepare(sql);
const result = deleteStmt.run(id);
return result.changes > 0;
}
catch (err) {
throw err;
}
}
async count(tableName, where) {
this.ensureConnected();
let sql = `SELECT COUNT(*) as count FROM ${tableName}`;
let values = [];
if (where) {
const whereClause = this.buildWhereClause(where);
sql += ` ${whereClause.sql}`;
values = whereClause.values;
}
try {
const countStmt = this.db.prepare(sql);
const row = countStmt.get(...values);
return row.count;
}
catch (err) {
throw err;
}
}
mapFieldType(fieldType) {
switch (fieldType) {
case 'string': return 'TEXT';
case 'number': return 'REAL';
case 'boolean': return 'INTEGER'; // SQLite doesn't have native boolean
case 'date': return 'DATETIME';
case 'json': return 'TEXT'; // Store as JSON string
default: return 'TEXT';
}
}
}
//# sourceMappingURL=sqlite.js.map