diff --git a/.gitignore b/.gitignore index 2232350..fe4c90f 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,7 @@ packages/media/.env **/*/vite.config.ts.timestamp* .history **/*/.db/* +**/*/.configs/* **/*/*.db **/*/*.db-shm **/*/*.db-wal diff --git a/app/package.json b/app/package.json index 1bb93d4..c4674bc 100644 --- a/app/package.json +++ b/app/package.json @@ -3,7 +3,7 @@ "type": "module", "sideEffects": false, "bin": "./dist/cli/index.js", - "version": "0.5.0-rc5", + "version": "0.5.0-rc6", "scripts": { "build:all": "NODE_ENV=production bun run build.ts --minify --types --clean && bun run build:cli", "dev": "vite", diff --git a/app/src/core/errors.ts b/app/src/core/errors.ts index 860bd9d..d9a1cdc 100644 --- a/app/src/core/errors.ts +++ b/app/src/core/errors.ts @@ -1,6 +1,7 @@ export class Exception extends Error { code = 400; override name = "Exception"; + protected _context = undefined; constructor(message: string, code?: number) { super(message); @@ -9,11 +10,16 @@ export class Exception extends Error { } } + context(context: any) { + this._context = context; + return this; + } + toJSON() { return { error: this.message, - type: this.name - //message: this.message + type: this.name, + context: this._context }; } } diff --git a/app/src/data/entities/EntityManager.ts b/app/src/data/entities/EntityManager.ts index 1e2030e..f8dfd7b 100644 --- a/app/src/data/entities/EntityManager.ts +++ b/app/src/data/entities/EntityManager.ts @@ -107,15 +107,15 @@ export class EntityManager { } this._entities[entityIndex] = entity; + + // caused issues because this.entity() was using a reference (for when initial config was given) } entity(e: Entity | keyof TBD | string): Entity { - let entity: Entity | undefined; - if (typeof e === "string") { - entity = this.entities.find((entity) => entity.name === e); - } else if (e instanceof Entity) { - entity = e; - } + // make sure to always retrieve by name + const entity = this.entities.find((entity) => + e instanceof Entity ? entity.name === e.name : entity.name === e + ); if (!entity) { // @ts-ignore diff --git a/app/src/data/entities/query/Repository.ts b/app/src/data/entities/query/Repository.ts index 171fc3b..a6dc576 100644 --- a/app/src/data/entities/query/Repository.ts +++ b/app/src/data/entities/query/Repository.ts @@ -58,7 +58,7 @@ export class Repository 0) { throw new InvalidSearchParamsException( `Invalid select field(s): ${invalid.join(", ")}` - ); + ).context({ + entity: entity.name, + valid: validated.select + }); } validated.select = options.select; diff --git a/app/src/data/helper.ts b/app/src/data/helper.ts index 74497b0..e465247 100644 --- a/app/src/data/helper.ts +++ b/app/src/data/helper.ts @@ -1,4 +1,4 @@ -import type { EntityData, Field } from "data"; +import type { EntityData, EntityManager, Field } from "data"; import { transform } from "lodash-es"; export function getDefaultValues(fields: Field[], data: EntityData): EntityData { @@ -48,3 +48,23 @@ export function getChangeSet( {} as typeof formData ); } + +export function readableEmJson(_em: EntityManager) { + return { + entities: _em.entities.map((e) => ({ + name: e.name, + fields: e.fields.map((f) => f.name), + type: e.type + })), + indices: _em.indices.map((i) => ({ + name: i.name, + entity: i.entity.name, + fields: i.fields.map((f) => f.name), + unique: i.unique + })), + relations: _em.relations.all.map((r) => ({ + name: r.getName(), + ...r.toJSON() + })) + }; +} diff --git a/app/src/media/AppMedia.ts b/app/src/media/AppMedia.ts index fc9ba42..c759479 100644 --- a/app/src/media/AppMedia.ts +++ b/app/src/media/AppMedia.ts @@ -26,7 +26,6 @@ export class AppMedia extends Module { private _storage?: Storage; override async build() { - console.log("building"); if (!this.config.enabled) { this.setBuilt(); return; diff --git a/app/src/modules/Module.ts b/app/src/modules/Module.ts index 2a4dad0..21bc5d2 100644 --- a/app/src/modules/Module.ts +++ b/app/src/modules/Module.ts @@ -46,10 +46,12 @@ export abstract class Module { diff --git a/app/src/modules/ModuleManager.ts b/app/src/modules/ModuleManager.ts index af6da0d..d5840c2 100644 --- a/app/src/modules/ModuleManager.ts +++ b/app/src/modules/ModuleManager.ts @@ -400,8 +400,8 @@ export class ModuleManager { }); } - private async buildModules(options?: { graceful?: boolean }) { - this.logger.log("buildModules() triggered", options?.graceful, this._built); + private async buildModules(options?: { graceful?: boolean; ignoreFlags?: boolean }) { + this.logger.log("buildModules() triggered", options, this._built); if (options?.graceful && this._built) { this.logger.log("skipping build (graceful)"); return; @@ -417,12 +417,25 @@ export class ModuleManager { this._built = true; this.logger.log("modules built", ctx.flags); - if (ctx.flags.sync_required) { - this.logger.log("db sync requested"); - await ctx.em.schema().sync({ force: true }); - await this.save(); - ctx.flags.sync_required = false; // reset + if (options?.ignoreFlags !== true) { + if (ctx.flags.sync_required) { + ctx.flags.sync_required = false; + this.logger.log("db sync requested"); + + // sync db + await ctx.em.schema().sync({ force: true }); + await this.save(); + } + + if (ctx.flags.ctx_reload_required) { + ctx.flags.ctx_reload_required = false; + this.logger.log("ctx reload requested"); + this.ctx(true); + } } + + // reset all falgs + ctx.flags = Module.ctx_flags; } async build() { diff --git a/app/src/ui/components/table/DataTable.tsx b/app/src/ui/components/table/DataTable.tsx index 8aa664f..01e40bf 100644 --- a/app/src/ui/components/table/DataTable.tsx +++ b/app/src/ui/components/table/DataTable.tsx @@ -125,12 +125,18 @@ export function DataTable = Record ) : null} - {!data || data.length === 0 ? ( + {!data || !Array.isArray(data) || data.length === 0 ? (
- {Array.isArray(data) ? "No data to show" : "Loading..."} + {Array.isArray(data) ? ( + "No data to show" + ) : !data ? ( + "Loading..." + ) : ( +
{JSON.stringify(data, null, 2)}
+ )}
diff --git a/app/vite.dev.ts b/app/vite.dev.ts index 6050997..16e73cd 100644 --- a/app/vite.dev.ts +++ b/app/vite.dev.ts @@ -1,3 +1,4 @@ +import { readFile } from "node:fs/promises"; import { serveStatic } from "@hono/node-server/serve-static"; import { createClient } from "@libsql/client/node"; import { App, registries } from "./src"; @@ -6,20 +7,35 @@ import { StorageLocalAdapter } from "./src/media/storage/adapters/StorageLocalAd registries.media.register("local", StorageLocalAdapter); -const credentials = { - url: import.meta.env.VITE_DB_URL!, - authToken: import.meta.env.VITE_DB_TOKEN! -}; +const run_example: string | boolean = false; +//run_example = "ex-admin-rich"; + +const credentials = run_example + ? { + url: `file:.configs/${run_example}.db` + //url: ":memory:" + } + : { + url: import.meta.env.VITE_DB_URL!, + authToken: import.meta.env.VITE_DB_TOKEN! + }; if (!credentials.url) { throw new Error("Missing VITE_DB_URL env variable. Add it to .env file"); } const connection = new LibsqlConnection(createClient(credentials)); +let initialConfig: any = undefined; +if (run_example) { + const { version, ...config } = JSON.parse( + await readFile(`.configs/${run_example}.json`, "utf-8") + ); + initialConfig = config; +} + export default { async fetch(request: Request) { - const app = App.create({ connection }); - + const app = App.create({ connection, initialConfig }); app.emgr.onEvent( App.Events.AppBuiltEvent, async () => {