129 lines
3.8 KiB
TypeScript
129 lines
3.8 KiB
TypeScript
import { z } from "zod";
|
|
import { Collection, Entry } from "./entry.ts";
|
|
import { QueriedOf, StoredOfField, Table } from "./typing.ts";
|
|
|
|
export class Schema<T extends Table<T>> {
|
|
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<T extends Table<T>> {
|
|
public readonly nodes;
|
|
public readonly kv;
|
|
public readonly prefix;
|
|
|
|
public constructor(nodes: Schema<T>, kv: Deno.Kv, prefix: string) {
|
|
this.nodes = nodes;
|
|
this.kv = kv;
|
|
this.prefix = prefix;
|
|
}
|
|
|
|
public static async open<T extends Table<T>>(nodes: Schema<T>, path: string, prefix: string = "store") {
|
|
const kv = await Deno.openKv(path);
|
|
return new Store(nodes, kv, prefix);
|
|
}
|
|
|
|
public empty_collection<S extends keyof T>(produces: S) {
|
|
return new Collection(this, produces, this.new_id());
|
|
}
|
|
|
|
public async get<S extends keyof T>(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<S extends keyof T, F extends keyof T[S]>(schema: S, values: QueriedOf<T, S>) {
|
|
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<S extends keyof T>(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<S extends keyof T, F extends keyof T[S]>(
|
|
schema: S,
|
|
id: string,
|
|
field: F,
|
|
value: StoredOfField<T, S, F>,
|
|
) {
|
|
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<S extends keyof T, F extends keyof T[S]>(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<S extends keyof T, F extends keyof T[S]>(schema: S, id: string, field: F) {
|
|
await this.kv.delete([this.prefix, "fields", schema, id, field]);
|
|
}
|
|
|
|
public async entry_exists<S extends keyof T>(schema: S, id: string) {
|
|
const result = await this.kv.get([this.prefix, "entries", schema, id]);
|
|
return result !== null;
|
|
}
|
|
|
|
public async delete_entry<S extends keyof T>(schema: S, id: string) {
|
|
await this.kv.delete([this.prefix, "entries", schema, id]);
|
|
}
|
|
|
|
public async *list_entries<S extends keyof T>(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]);
|
|
}
|
|
}
|