UNPKG

userdo

Version:

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

143 lines (142 loc) 5.47 kB
export class GenericQuery { constructor(tableName, storage, schema, userId, getOrganizationContext) { this.tableName = tableName; this.storage = storage; this.schema = schema; this.userId = userId; this.getOrganizationContext = getOrganizationContext; this.conditions = []; } get organizationContext() { return this.getOrganizationContext(); } where(path, operator, value) { this.conditions.push({ path, operator, value }); return this; } orderBy(field, direction = 'asc') { this.orderByClause = { field, direction }; return this; } limit(count) { this.limitCount = count; return this; } offset(count) { this.offsetCount = count; return this; } async get() { let sql; let params; if (this.organizationContext) { sql = `SELECT * FROM "${this.tableName}" WHERE user_id = ? AND organization_id = ?`; params = [this.userId, this.organizationContext]; } else { sql = `SELECT * FROM "${this.tableName}" WHERE user_id = ?`; params = [this.userId]; } // Add WHERE conditions if (this.conditions.length > 0) { const whereConditions = this.conditions.map((c) => { const jsonPath = `$.${c.path}`; switch (c.operator) { case '==': params.push(c.value); return `json_extract(data, '${jsonPath}') = ?`; case '!=': params.push(c.value); return `json_extract(data, '${jsonPath}') != ?`; case '>': params.push(c.value); return `json_extract(data, '${jsonPath}') > ?`; case '<': params.push(c.value); return `json_extract(data, '${jsonPath}') < ?`; case 'includes': params.push(`%${c.value}%`); return `json_extract(data, '${jsonPath}') LIKE ?`; default: throw new Error(`Unsupported operator: ${c.operator}`); } }); sql += ` AND (${whereConditions.join(' AND ')})`; } // Add ORDER BY if (this.orderByClause) { const { field, direction } = this.orderByClause; if (field === 'createdAt' || field === 'updatedAt') { const dbField = field === 'createdAt' ? 'created_at' : 'updated_at'; sql += ` ORDER BY ${dbField} ${direction.toUpperCase()}`; } else { const jsonPath = `$.${field}`; sql += ` ORDER BY json_extract(data, '${jsonPath}') ${direction.toUpperCase()}`; } } // Add LIMIT and OFFSET if (this.limitCount) { sql += ` LIMIT ${this.limitCount}`; } if (this.offsetCount) { sql += ` OFFSET ${this.offsetCount}`; } const cursor = this.storage.sql.exec(sql, ...params); const results = []; for (const row of cursor) { const data = JSON.parse(row.data); results.push({ ...data, id: row.id, createdAt: new Date(row.created_at), updatedAt: new Date(row.updated_at), }); } return results; } async first() { const results = await this.limit(1).get(); return results[0] || null; } 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]; } if (this.conditions.length > 0) { const whereConditions = this.conditions.map((c) => { const jsonPath = `$.${c.path}`; switch (c.operator) { case '==': params.push(c.value); return `json_extract(data, '${jsonPath}') = ?`; case '!=': params.push(c.value); return `json_extract(data, '${jsonPath}') != ?`; case '>': params.push(c.value); return `json_extract(data, '${jsonPath}') > ?`; case '<': params.push(c.value); return `json_extract(data, '${jsonPath}') < ?`; case 'includes': params.push(`%${c.value}%`); return `json_extract(data, '${jsonPath}') LIKE ?`; default: throw new Error(`Unsupported operator: ${c.operator}`); } }); sql += ` AND (${whereConditions.join(' AND ')})`; } const cursor = this.storage.sql.exec(sql, ...params); const results = cursor.toArray(); return results.length > 0 ? Number(results[0].count) : 0; } }