Files
ProjectE/worker/database.ts
T
mbatchelder 73335484f8 feat: migrate from PocketBase to PostgreSQL with Drizzle ORM
- Add @project-e/db package with Drizzle schema and migrations
- Replace PocketBase client with PostgreSQL-based database client
- Migrate auth from custom to NextAuth.js
- Add Docker Compose with PostgreSQL container
- Update worker to use new database client
- Remove PocketBase-specific files and migrations
- Add drizzle config and initial migration
2026-07-24 07:08:29 -04:00

66 lines
2.5 KiB
TypeScript

import { and, eq } from 'drizzle-orm';
import { db, records } from '@project-e/db';
type RecordData = Record<string, any>;
function serialize(record: typeof records.$inferSelect): RecordData {
return {
...record.data,
id: record.id,
created: record.createdAt.toISOString(),
updated: record.updatedAt.toISOString(),
};
}
function matchesFilter(record: RecordData, filter?: string): boolean {
if (!filter) return true;
return filter.split('&&').every((term) => {
const match = term.trim().match(/^([a-zA-Z_][\w]*)\s*(=|<=|<)\s*(.+)$/);
if (!match) return false;
const [, field, operator, rawExpected] = match;
const expected = rawExpected.trim().replace(/^"|"$/g, '');
const actual = record[field];
if (operator === '=') return String(actual) === expected;
if (operator === '<=') return String(actual ?? '') <= expected;
return String(actual ?? '') < expected;
});
}
export function createDatabaseClient() {
return {
collection(collection: string) {
return {
async getList(page = 1, perPage = 50, options: { filter?: string; sort?: string } = {}) {
const rows = (await db.select().from(records).where(eq(records.collection, collection)))
.map(serialize)
.filter((record) => matchesFilter(record, options.filter));
return {
items: rows.slice((page - 1) * perPage, page * perPage),
totalItems: rows.length,
totalPages: Math.max(1, Math.ceil(rows.length / perPage)),
page,
perPage,
};
},
async create(data: RecordData) {
const [record] = await db.insert(records).values({ collection, data }).returning();
return serialize(record);
},
async update(id: string, data: RecordData) {
const [existing] = await db.select().from(records).where(and(eq(records.id, id), eq(records.collection, collection))).limit(1);
if (!existing) throw new Error(`Record ${id} not found`);
const [record] = await db.update(records)
.set({ data: { ...existing.data, ...data }, updatedAt: new Date() })
.where(and(eq(records.id, id), eq(records.collection, collection)))
.returning();
return serialize(record);
},
async delete(id: string) {
await db.delete(records).where(and(eq(records.id, id), eq(records.collection, collection)));
return true;
},
};
},
};
}