UNPKG

userdo

Version:

A Durable Object base class for building applications on Cloudflare Workers.

128 lines (127 loc) 5.54 kB
import { GenericQuery } from './query.js'; export class GenericTable { constructor(tableName, schema, storage, userId, getOrganizationContext, broadcast) { this.tableName = tableName; this.schema = schema; this.storage = storage; this.userId = userId; this.getOrganizationContext = getOrganizationContext; this.broadcast = broadcast; } get organizationContext() { return this.getOrganizationContext(); } async create(data) { const validated = this.schema.parse(data); const id = crypto.randomUUID(); const now = Date.now(); let insertSQL; let params; if (this.organizationContext) { insertSQL = `INSERT INTO "${this.tableName}" (id, data, created_at, updated_at, user_id, organization_id) VALUES (?, ?, ?, ?, ?, ?)`; params = [id, JSON.stringify(validated), now, now, this.userId, this.organizationContext]; } else { insertSQL = `INSERT INTO "${this.tableName}" (id, data, created_at, updated_at, user_id) VALUES (?, ?, ?, ?, ?)`; params = [id, JSON.stringify(validated), now, now, this.userId]; } this.storage.sql.exec(insertSQL, ...params); const result = { ...validated, id, createdAt: new Date(now), updatedAt: new Date(now) }; // Broadcast table change this.broadcast?.(`table:${this.tableName}`, { type: 'create', data: result }); return result; } async findById(id) { let selectSQL; let params; if (this.organizationContext) { selectSQL = `SELECT * FROM "${this.tableName}" WHERE id = ? AND user_id = ? AND organization_id = ? LIMIT 1`; params = [id, this.userId, this.organizationContext]; } else { selectSQL = `SELECT * FROM "${this.tableName}" WHERE id = ? AND user_id = ? LIMIT 1`; params = [id, this.userId]; } const cursor = this.storage.sql.exec(selectSQL, ...params); const results = cursor.toArray(); if (results.length === 0) { return null; } const row = results[0]; const data = JSON.parse(row.data); return { ...data, id: row.id, createdAt: new Date(row.created_at), updatedAt: new Date(row.updated_at) }; } async update(id, updates) { const existing = await this.findById(id); if (!existing) throw new Error('Record not found'); const merged = { ...existing, ...updates }; delete merged.id; delete merged.createdAt; delete merged.updatedAt; const validated = this.schema.parse(merged); const now = Date.now(); let updateSQL; let params; if (this.organizationContext) { updateSQL = `UPDATE "${this.tableName}" SET data = ?, updated_at = ? WHERE id = ? AND user_id = ? AND organization_id = ?`; params = [JSON.stringify(validated), now, id, this.userId, this.organizationContext]; } else { updateSQL = `UPDATE "${this.tableName}" SET data = ?, updated_at = ? WHERE id = ? AND user_id = ?`; params = [JSON.stringify(validated), now, id, this.userId]; } this.storage.sql.exec(updateSQL, ...params); const result = { ...validated, id, createdAt: existing.createdAt, updatedAt: new Date(now) }; // Broadcast table change this.broadcast?.(`table:${this.tableName}`, { type: 'update', data: result }); return result; } async delete(id) { let deleteSQL; let params; if (this.organizationContext) { deleteSQL = `DELETE FROM "${this.tableName}" WHERE id = ? AND user_id = ? AND organization_id = ?`; params = [id, this.userId, this.organizationContext]; } else { deleteSQL = `DELETE FROM "${this.tableName}" WHERE id = ? AND user_id = ?`; params = [id, this.userId]; } this.storage.sql.exec(deleteSQL, ...params); // Broadcast table change this.broadcast?.(`table:${this.tableName}`, { type: 'delete', data: { id } }); } where(path, operator, value) { return new GenericQuery(this.tableName, this.storage, this.schema, this.userId, this.getOrganizationContext).where(path, operator, value); } orderBy(field, direction = 'asc') { return new GenericQuery(this.tableName, this.storage, this.schema, this.userId, this.getOrganizationContext).orderBy(field, direction); } limit(count) { return new GenericQuery(this.tableName, this.storage, this.schema, this.userId, this.getOrganizationContext).limit(count); } async getAll() { return new GenericQuery(this.tableName, this.storage, this.schema, this.userId, this.getOrganizationContext).get(); } async count() { let sql; let params; if (this.organizationContext) { sql = `SELECT COUNT(*) as count FROM "${this.tableName}" WHERE user_id = ? AND organization_id = ?`; params = [this.userId, this.organizationContext]; } else { sql = `SELECT COUNT(*) as count FROM "${this.tableName}" WHERE user_id = ?`; params = [this.userId]; } const cursor = this.storage.sql.exec(sql, ...params); const results = cursor.toArray(); return results.length > 0 ? Number(results[0].count) : 0; } }