import { z } from "zod"; import { Store } from "./store.ts"; import { QueriedFor, QueriedOfField, StoredFor, Table } from "./typing.ts"; export class Entry, S extends keyof T> { public readonly store; public readonly schema; public readonly id; public constructor(store: Store, schema: S, id: string) { this.store = store; this.schema = schema; this.id = id; } public async get(field: F): Promise> { if (!await this.store.entry_exists(this.schema, this.id)) throw new Error("Accessing a deleted entry"); const str = (value: unknown) => z.string().parse(value); const content = await this.store.read_field(this.schema, this.id, field); const kind = this.store.nodes.table[this.schema][field]; if (kind === "string") return z.string().parse(content) as QueriedFor; if (kind === "number") return z.number().parse(content) as QueriedFor; if (kind === "boolean") return z.boolean().parse(content) as QueriedFor; if (kind[0] === "maybe") { if (content === null) return null as QueriedFor; else return new Entry(this.store, kind[1], str(content)) as QueriedFor; } if (kind[0] === "one") return new Entry(this.store, kind[1], str(content)) as QueriedFor; if (kind[0] === "many") return new Collection(this.store, kind[1], str(content)) as QueriedFor; throw new Error("Unreachable"); } public async set(field: F, value: QueriedFor) { let raw: string | number | boolean | null; if (value instanceof Collection) raw = value.id; else if (value instanceof Entry) raw = value.id; else raw = value; await this.store.write_field(this.schema, this.id, field, raw as StoredFor); } public async delete() { const schema = this.store.nodes.table[this.schema]; for (const field in schema) { const kind = schema[field]; if (Array.isArray(kind) && kind[0] === "many") { // deno-lint-ignore no-explicit-any const collection = await this.get(field) as Collection; for await (const value of collection) this.store.remove_relation(collection.id, value.id); await this.store.delete_relations(collection.id); } await this.store.delete_field(this.schema, this.id, field); } await this.store.delete_entry(this.schema, this.id); } } export class Collection, S extends keyof T> { public readonly store; public readonly schema; public readonly id; public constructor(store: Store, schema: S, collection_id: string) { this.store = store; this.schema = schema; this.id = collection_id; } public async *[Symbol.asyncIterator]() { for await (const id_ of this.store.list_relations(this.id)) { const id = z.string().parse(id_); const entry = new Entry(this.store, this.schema, id); if (await this.store.entry_exists(this.schema, id)) yield entry; else await this.remove(entry); } } public async add(entry: Entry) { await this.store.add_relation(this.id, entry.id); } public async remove(entry: Entry) { await this.store.remove_relation(this.id, entry.id); } }