prasi-lib/gen/prop/gen_prop_fields.ts

168 lines
3.7 KiB
TypeScript
Executable File

import { get as kget, set as kset } from "@/utils/idb-keyval";
const single = {} as Record<
string,
{
cols: Record<
string,
{
is_pk: boolean;
type: string;
optional: boolean;
db_type: string;
default?: any;
}
>;
rels: Record<
string,
{
type: "has-many" | "has-one";
to: {
table: string;
fields: string[];
};
from: {
table: string;
fields: string[];
};
}
>;
}
>;
export const gen_prop_fields = async (gen_table: string, depth?: number) => {
if (typeof db === "undefined") return ["- No Database -"];
const path = window.location.pathname;
let id_site = null;
try {
id_site = path.split("/")[2];
} catch (e) {
id_site = window.location.hostname;
}
return await loadSchemaLayer(
id_site,
typeof depth === "undefined" ? 4 : depth,
{},
gen_table
);
};
const loadSchemaLayer = async (
id_site: string,
depth: number,
arg: any,
table: string
) => {
let current_depth = 1;
const result = await get_layer(id_site, depth, current_depth, arg, table);
return result;
};
const get_layer = async (
id_site: string,
depth: number,
current: number,
arg: any,
table: string
) => {
const { cols, rels } = await loadSingle(id_site, table);
const options = [];
if (cols) {
for (const [k, v] of Object.entries(cols)) {
options.push({
value: JSON.stringify({
name: k,
is_pk: v.is_pk,
type: v.db_type || v.type,
optional: v.optional,
default: v.default,
}),
label: k + (!v.optional && !v.default ? " *" : ""),
alt: `${v.is_pk ? "🔑" : ""} ${v.type}`,
checked: v.is_pk,
});
}
}
if (current < depth) {
if (rels) {
for (const [k, v] of Object.entries(rels)) {
if (v?.to && v?.from) {
const to = v.to;
const from = v.from;
const r_rels = (await get_layer(
id_site,
depth,
current + 1,
arg,
v.to.table
)) as any;
options.push({
value: JSON.stringify({
name: k,
is_pk: false,
type: v.type,
optional: true,
relation: { from, to },
}),
alt: v.type === "has-many" ? `1-N` : `1-1`,
label: k,
options: r_rels,
checked: false,
});
}
}
}
}
return options;
};
const pending = {} as Record<string, Promise<any>[]>;
const loadSingle = async (id_site: string, table: string) => {
const ls_key = `schema-md-${id_site}`;
const idb_key = `${id_site}-${table}`;
let cached_raw = localStorage.getItem(ls_key);
let cached_keys: string[] = [];
if (cached_raw) {
try {
let res = JSON.parse(cached_raw);
if (!Array.isArray(res)) {
localStorage.setItem(ls_key, JSON.stringify([]));
res = [];
}
cached_keys = res;
} catch (e) {}
}
let cached = null;
if (cached_keys.includes(table)) {
cached = await kget(idb_key);
}
if (!single[table]) {
if (cached) {
single[table] = cached;
} else {
if (!pending[table]) {
pending[table] = [
db._schema.columns(table as any),
db._schema.rels(table as any),
];
}
await Promise.all(pending[table]);
single[table] = {
cols: (await pending[table][0]) as any,
rels: (await pending[table][1]) as any,
};
await kset(idb_key, single[table]);
localStorage.setItem(ls_key, JSON.stringify([...cached_keys, table]));
}
}
return single[table];
};