@flavoai/fastfold
Version:
Zero-boilerplate backend for React apps with auto-generated CRUD and declarative security
194 lines • 6.63 kB
JavaScript
import { eq, and, sql } from 'drizzle-orm';
export class DrizzleAdapter {
db;
schema;
constructor(db, schema) {
this.db = db;
this.schema = schema;
}
/**
* Get table schema object by name
*/
getTable(tableName) {
const table = this.schema[tableName];
if (!table) {
throw new Error(`Table '${tableName}' not found in schema`);
}
return table;
}
/**
* Query records from a table
*/
async query(tableName, params = {}) {
const table = this.getTable(tableName);
let query = this.db.select().from(table);
// Apply where conditions
if (params.where) {
const conditions = this.buildWhereConditions(table, params.where);
if (conditions.length > 0) {
query = query.where(and(...conditions));
}
}
// Apply ordering
if (params.orderBy) {
const orderConditions = Object.entries(params.orderBy).map(([field, direction]) => {
const column = table[field];
if (!column)
throw new Error(`Column '${field}' not found in table '${tableName}'`);
return direction === 'desc' ? sql `${column} DESC` : sql `${column} ASC`;
});
query = query.orderBy(...orderConditions);
}
// Apply pagination
if (params.limit) {
query = query.limit(params.limit);
}
if (params.offset) {
query = query.offset(params.offset);
}
return await query;
}
/**
* Create a new record
*/
async create(tableName, data) {
const table = this.getTable(tableName);
const result = await this.db.insert(table).values(data).returning();
return result[0];
}
/**
* Update a record by ID
*/
async update(tableName, id, data) {
const table = this.getTable(tableName);
const result = await this.db
.update(table)
.set(data)
.where(eq(table.id, id))
.returning();
if (result.length === 0) {
throw new Error(`Record with id '${id}' not found in table '${tableName}'`);
}
return result[0];
}
/**
* Delete a record by ID
*/
async delete(tableName, id) {
const table = this.getTable(tableName);
const result = await this.db
.delete(table)
.where(eq(table.id, id))
.returning();
return result.length > 0;
}
/**
* Count records in a table
*/
async count(tableName, where) {
const table = this.getTable(tableName);
let query = this.db.select({ count: sql `count(*)` }).from(table);
if (where) {
const conditions = this.buildWhereConditions(table, where);
if (conditions.length > 0) {
query = query.where(and(...conditions));
}
}
const result = await query;
return parseInt(result[0].count);
}
/**
* Find a single record by ID
*/
async findById(tableName, id) {
const table = this.getTable(tableName);
const result = await this.db
.select()
.from(table)
.where(eq(table.id, id))
.limit(1);
return result[0] || null;
}
/**
* Query with relations using Drizzle's relational query API
*/
async queryWithRelations(tableName, params = {}) {
if (!this.db.query || !this.db.query[tableName]) {
// Fallback to regular query if relational API not available
return this.query(tableName, params);
}
let query = {};
// Apply where conditions
if (params.where) {
query.where = (table, { eq, and }) => {
const conditions = Object.entries(params.where).map(([field, value]) => {
return eq(table[field], value);
});
return conditions.length === 1 ? conditions[0] : and(...conditions);
};
}
// Apply relations
if (params.with) {
query.with = params.with;
}
// Apply ordering
if (params.orderBy) {
query.orderBy = (table, { desc, asc }) => {
return Object.entries(params.orderBy).map(([field, direction]) => {
return direction === 'desc' ? desc(table[field]) : asc(table[field]);
});
};
}
// Apply pagination
if (params.limit) {
query.limit = params.limit;
}
if (params.offset) {
query.offset = params.offset;
}
return await this.db.query[tableName].findMany(query);
}
/**
* Build where conditions for Drizzle queries
*/
buildWhereConditions(table, where) {
return Object.entries(where).map(([field, value]) => {
const column = table[field];
if (!column)
throw new Error(`Column '${field}' not found`);
if (typeof value === 'object' && value !== null) {
// Handle operators like { gte: 18 }, { in: [1, 2, 3] }
const [operator, operatorValue] = Object.entries(value)[0];
switch (operator) {
case 'gte':
return sql `${column} >= ${operatorValue}`;
case 'lte':
return sql `${column} <= ${operatorValue}`;
case 'gt':
return sql `${column} > ${operatorValue}`;
case 'lt':
return sql `${column} < ${operatorValue}`;
case 'in':
return sql `${column} IN ${operatorValue}`;
case 'notIn':
return sql `${column} NOT IN ${operatorValue}`;
case 'like':
return sql `${column} LIKE ${operatorValue}`;
default:
return eq(column, value);
}
}
return eq(column, value);
});
}
/**
* Get available table names from schema
*/
getTableNames() {
return Object.keys(this.schema).filter(key => {
// Filter out relation definitions (they typically end with 'Relations')
return !key.endsWith('Relations') && typeof this.schema[key] === 'object';
});
}
}
//# sourceMappingURL=drizzle.js.map