UNPKG

userdo

Version:

A Durable Object base class that provides user authentication, per-user data storage, and real-time updates for Cloudflare Workers applications.

77 lines (76 loc) 3.4 kB
import { GenericQuery } from './query'; export class GenericTable { constructor(tableName, schema, storage, userId, broadcast) { this.tableName = tableName; this.schema = schema; this.storage = storage; this.userId = userId; this.broadcast = broadcast; } async create(data) { const validated = this.schema.parse(data); const id = crypto.randomUUID(); const now = Date.now(); const insertSQL = `INSERT INTO "${this.tableName}" (id, data, created_at, updated_at, user_id) VALUES (?, ?, ?, ?, ?)`; this.storage.sql.exec(insertSQL, id, JSON.stringify(validated), now, now, this.userId); 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) { const selectSQL = `SELECT * FROM "${this.tableName}" WHERE id = ? AND user_id = ? LIMIT 1`; const cursor = this.storage.sql.exec(selectSQL, id, this.userId); const row = cursor.one(); if (!row) return null; 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(); const updateSQL = `UPDATE "${this.tableName}" SET data = ?, updated_at = ? WHERE id = ? AND user_id = ?`; this.storage.sql.exec(updateSQL, JSON.stringify(validated), now, id, this.userId); 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) { const deleteSQL = `DELETE FROM "${this.tableName}" WHERE id = ? AND user_id = ?`; this.storage.sql.exec(deleteSQL, id, this.userId); // 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).where(path, operator, value); } orderBy(field, direction = 'asc') { return new GenericQuery(this.tableName, this.storage, this.schema, this.userId).orderBy(field, direction); } limit(count) { return new GenericQuery(this.tableName, this.storage, this.schema, this.userId).limit(count); } async getAll() { return new GenericQuery(this.tableName, this.storage, this.schema, this.userId).get(); } async count() { const countSQL = `SELECT COUNT(*) as count FROM "${this.tableName}" WHERE user_id = ?`; const cursor = this.storage.sql.exec(countSQL, this.userId); const row = cursor.one(); return row ? Number(row.count) : 0; } }