Fix entity referencing issue during post-seeded relational fetch

This commit is contained in:
dswbx
2025-01-10 17:28:43 +01:00
parent e94e8d8bd1
commit bb756548a6
11 changed files with 95 additions and 29 deletions

View File

@@ -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",

View File

@@ -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
};
}
}

View File

@@ -107,15 +107,15 @@ export class EntityManager<TBD extends object = DefaultDB> {
}
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

View File

@@ -58,7 +58,7 @@ export class Repository<TBD extends object = DefaultDB, TB extends keyof TBD = a
}
private cloneFor(entity: Entity) {
return new Repository(this.em, entity, this.emgr);
return new Repository(this.em, this.em.entity(entity), this.emgr);
}
private get conn() {
@@ -94,7 +94,10 @@ export class Repository<TBD extends object = DefaultDB, TB extends keyof TBD = a
if (invalid.length > 0) {
throw new InvalidSearchParamsException(
`Invalid select field(s): ${invalid.join(", ")}`
);
).context({
entity: entity.name,
valid: validated.select
});
}
validated.select = options.select;

View File

@@ -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()
}))
};
}

View File

@@ -26,7 +26,6 @@ export class AppMedia extends Module<typeof mediaConfigSchema> {
private _storage?: Storage;
override async build() {
console.log("building");
if (!this.config.enabled) {
this.setBuilt();
return;

View File

@@ -46,10 +46,12 @@ export abstract class Module<Schema extends TSchema = TSchema, ConfigSchema = St
}
static ctx_flags = {
sync_required: false
sync_required: false,
ctx_reload_required: false
} as {
// signal that a sync is required at the end of build
sync_required: boolean;
ctx_reload_required: boolean;
};
onBeforeUpdate(from: ConfigSchema, to: ConfigSchema): ConfigSchema | Promise<ConfigSchema> {

View File

@@ -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() {

View File

@@ -125,12 +125,18 @@ export function DataTable<Data extends Record<string, any> = Record<string, any>
</thead>
) : null}
<tbody>
{!data || data.length === 0 ? (
{!data || !Array.isArray(data) || data.length === 0 ? (
<tr>
<td colSpan={select.length + (checkable ? 1 : 0)}>
<div className="flex flex-col gap-2 p-8 justify-center items-center border-t border-muted">
<i className="opacity-50">
{Array.isArray(data) ? "No data to show" : "Loading..."}
{Array.isArray(data) ? (
"No data to show"
) : !data ? (
"Loading..."
) : (
<pre>{JSON.stringify(data, null, 2)}</pre>
)}
</i>
</div>
</td>

View File

@@ -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 () => {