import { z } from "zod"; import { Collection, Entry } from "./entry.ts"; import { QueriedOf, StoredOfField, Table } from "./typing.ts"; export class Schema> { public readonly table; constructor(table: T) { this.table = table; } } /* note : storing values : for each field : - field is string | number | boolean : [prefix, 'entries', schema, id] <- id [prefix, 'fields', schema, id, field] <- value - field is relation one : [prefix, 'entries', schema, id] <- id [prefix, 'fields', schema, id, field] <- id_to - field is relation maybe : [prefix, 'entries', schema, id] <- id [prefix, 'fields', schema, id, field] <- id_to | null - field is relation many : [prefix, 'entries', schema, id] <- id [prefix, 'fields', schema, id, field] <- id_relation [prefix, 'relations', id_relation, id_to] <- id_to */ export class Store> { public readonly nodes; public readonly kv; public readonly prefix; public constructor(nodes: Schema, kv: Deno.Kv, prefix: string) { this.nodes = nodes; this.kv = kv; this.prefix = prefix; } public static async open>(nodes: Schema, path: string, prefix: string = "store") { const kv = await Deno.openKv(path); return new Store(nodes, kv, prefix); } public empty_collection(produces: S) { return new Collection(this, produces, this.new_id()); } public async get(schema: S, id: string) { const exists = await this.entry_exists(schema, id); if (!exists) return null; return new Entry(this, schema, id); } public async insert(schema: S, values: QueriedOf) { const entry = new Entry(this, schema, this.new_id()); for (const key in values) { const value = values[key]; await entry.set(key, value); } return entry; } public async *all(schema: S) { for await (const id of this.list_entries(schema)) { yield new Entry(this, schema, z.string().parse(id)); } } public new_id() { return `${Math.random()}`; } public async write_field( schema: S, id: string, field: F, value: StoredOfField, ) { await this.kv.set([this.prefix, "fields", schema, id, field], value); await this.kv.set([this.prefix, "entries", schema, id], id); } public async read_field(schema: S, id: string, field: F) { const result = await this.kv.get([this.prefix, "fields", schema, id, field]); return result.value; } public async delete_field(schema: S, id: string, field: F) { await this.kv.delete([this.prefix, "fields", schema, id, field]); } public async entry_exists(schema: S, id: string) { const result = await this.kv.get([this.prefix, "entries", schema, id]); return result !== null; } public async delete_entry(schema: S, id: string) { await this.kv.delete([this.prefix, "entries", schema, id]); } public async *list_entries(schema: S) { const prefix = [this.prefix, "entries", schema]; for await (const entry of this.kv.list({ prefix })) yield entry.value; } public async add_relation(id_relation: string, id_to: string) { await this.kv.set([this.prefix, "relations", id_relation, id_to], id_to); } public async remove_relation(id_relation: string, id_to: string) { await this.kv.delete([this.prefix, "relations", id_relation, id_to]); } public async *list_relations(id_relation: string) { const prefix = [this.prefix, "relations", id_relation]; for await (const entry of this.kv.list({ prefix })) yield entry.value; } public async delete_relations(id_relation: string) { await this.kv.delete([this.prefix, "relations", id_relation]); } }