mirror of
https://github.com/shishantbiswas/bknd.git
synced 2026-03-15 20:17:22 +00:00
Fix entity referencing issue during post-seeded relational fetch
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -18,6 +18,7 @@ packages/media/.env
|
|||||||
**/*/vite.config.ts.timestamp*
|
**/*/vite.config.ts.timestamp*
|
||||||
.history
|
.history
|
||||||
**/*/.db/*
|
**/*/.db/*
|
||||||
|
**/*/.configs/*
|
||||||
**/*/*.db
|
**/*/*.db
|
||||||
**/*/*.db-shm
|
**/*/*.db-shm
|
||||||
**/*/*.db-wal
|
**/*/*.db-wal
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
"type": "module",
|
"type": "module",
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
"bin": "./dist/cli/index.js",
|
"bin": "./dist/cli/index.js",
|
||||||
"version": "0.5.0-rc5",
|
"version": "0.5.0-rc6",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build:all": "NODE_ENV=production bun run build.ts --minify --types --clean && bun run build:cli",
|
"build:all": "NODE_ENV=production bun run build.ts --minify --types --clean && bun run build:cli",
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
export class Exception extends Error {
|
export class Exception extends Error {
|
||||||
code = 400;
|
code = 400;
|
||||||
override name = "Exception";
|
override name = "Exception";
|
||||||
|
protected _context = undefined;
|
||||||
|
|
||||||
constructor(message: string, code?: number) {
|
constructor(message: string, code?: number) {
|
||||||
super(message);
|
super(message);
|
||||||
@@ -9,11 +10,16 @@ export class Exception extends Error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
context(context: any) {
|
||||||
|
this._context = context;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
toJSON() {
|
toJSON() {
|
||||||
return {
|
return {
|
||||||
error: this.message,
|
error: this.message,
|
||||||
type: this.name
|
type: this.name,
|
||||||
//message: this.message
|
context: this._context
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -107,15 +107,15 @@ export class EntityManager<TBD extends object = DefaultDB> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this._entities[entityIndex] = entity;
|
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 {
|
entity(e: Entity | keyof TBD | string): Entity {
|
||||||
let entity: Entity | undefined;
|
// make sure to always retrieve by name
|
||||||
if (typeof e === "string") {
|
const entity = this.entities.find((entity) =>
|
||||||
entity = this.entities.find((entity) => entity.name === e);
|
e instanceof Entity ? entity.name === e.name : entity.name === e
|
||||||
} else if (e instanceof Entity) {
|
);
|
||||||
entity = e;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!entity) {
|
if (!entity) {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ export class Repository<TBD extends object = DefaultDB, TB extends keyof TBD = a
|
|||||||
}
|
}
|
||||||
|
|
||||||
private cloneFor(entity: Entity) {
|
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() {
|
private get conn() {
|
||||||
@@ -94,7 +94,10 @@ export class Repository<TBD extends object = DefaultDB, TB extends keyof TBD = a
|
|||||||
if (invalid.length > 0) {
|
if (invalid.length > 0) {
|
||||||
throw new InvalidSearchParamsException(
|
throw new InvalidSearchParamsException(
|
||||||
`Invalid select field(s): ${invalid.join(", ")}`
|
`Invalid select field(s): ${invalid.join(", ")}`
|
||||||
);
|
).context({
|
||||||
|
entity: entity.name,
|
||||||
|
valid: validated.select
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
validated.select = options.select;
|
validated.select = options.select;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { EntityData, Field } from "data";
|
import type { EntityData, EntityManager, Field } from "data";
|
||||||
import { transform } from "lodash-es";
|
import { transform } from "lodash-es";
|
||||||
|
|
||||||
export function getDefaultValues(fields: Field[], data: EntityData): EntityData {
|
export function getDefaultValues(fields: Field[], data: EntityData): EntityData {
|
||||||
@@ -48,3 +48,23 @@ export function getChangeSet(
|
|||||||
{} as typeof formData
|
{} 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()
|
||||||
|
}))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ export class AppMedia extends Module<typeof mediaConfigSchema> {
|
|||||||
private _storage?: Storage;
|
private _storage?: Storage;
|
||||||
|
|
||||||
override async build() {
|
override async build() {
|
||||||
console.log("building");
|
|
||||||
if (!this.config.enabled) {
|
if (!this.config.enabled) {
|
||||||
this.setBuilt();
|
this.setBuilt();
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -46,10 +46,12 @@ export abstract class Module<Schema extends TSchema = TSchema, ConfigSchema = St
|
|||||||
}
|
}
|
||||||
|
|
||||||
static ctx_flags = {
|
static ctx_flags = {
|
||||||
sync_required: false
|
sync_required: false,
|
||||||
|
ctx_reload_required: false
|
||||||
} as {
|
} as {
|
||||||
// signal that a sync is required at the end of build
|
// signal that a sync is required at the end of build
|
||||||
sync_required: boolean;
|
sync_required: boolean;
|
||||||
|
ctx_reload_required: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
onBeforeUpdate(from: ConfigSchema, to: ConfigSchema): ConfigSchema | Promise<ConfigSchema> {
|
onBeforeUpdate(from: ConfigSchema, to: ConfigSchema): ConfigSchema | Promise<ConfigSchema> {
|
||||||
|
|||||||
@@ -400,8 +400,8 @@ export class ModuleManager {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private async buildModules(options?: { graceful?: boolean }) {
|
private async buildModules(options?: { graceful?: boolean; ignoreFlags?: boolean }) {
|
||||||
this.logger.log("buildModules() triggered", options?.graceful, this._built);
|
this.logger.log("buildModules() triggered", options, this._built);
|
||||||
if (options?.graceful && this._built) {
|
if (options?.graceful && this._built) {
|
||||||
this.logger.log("skipping build (graceful)");
|
this.logger.log("skipping build (graceful)");
|
||||||
return;
|
return;
|
||||||
@@ -417,12 +417,25 @@ export class ModuleManager {
|
|||||||
this._built = true;
|
this._built = true;
|
||||||
this.logger.log("modules built", ctx.flags);
|
this.logger.log("modules built", ctx.flags);
|
||||||
|
|
||||||
if (ctx.flags.sync_required) {
|
if (options?.ignoreFlags !== true) {
|
||||||
this.logger.log("db sync requested");
|
if (ctx.flags.sync_required) {
|
||||||
await ctx.em.schema().sync({ force: true });
|
ctx.flags.sync_required = false;
|
||||||
await this.save();
|
this.logger.log("db sync requested");
|
||||||
ctx.flags.sync_required = false; // reset
|
|
||||||
|
// 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() {
|
async build() {
|
||||||
|
|||||||
@@ -125,12 +125,18 @@ export function DataTable<Data extends Record<string, any> = Record<string, any>
|
|||||||
</thead>
|
</thead>
|
||||||
) : null}
|
) : null}
|
||||||
<tbody>
|
<tbody>
|
||||||
{!data || data.length === 0 ? (
|
{!data || !Array.isArray(data) || data.length === 0 ? (
|
||||||
<tr>
|
<tr>
|
||||||
<td colSpan={select.length + (checkable ? 1 : 0)}>
|
<td colSpan={select.length + (checkable ? 1 : 0)}>
|
||||||
<div className="flex flex-col gap-2 p-8 justify-center items-center border-t border-muted">
|
<div className="flex flex-col gap-2 p-8 justify-center items-center border-t border-muted">
|
||||||
<i className="opacity-50">
|
<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>
|
</i>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { readFile } from "node:fs/promises";
|
||||||
import { serveStatic } from "@hono/node-server/serve-static";
|
import { serveStatic } from "@hono/node-server/serve-static";
|
||||||
import { createClient } from "@libsql/client/node";
|
import { createClient } from "@libsql/client/node";
|
||||||
import { App, registries } from "./src";
|
import { App, registries } from "./src";
|
||||||
@@ -6,20 +7,35 @@ import { StorageLocalAdapter } from "./src/media/storage/adapters/StorageLocalAd
|
|||||||
|
|
||||||
registries.media.register("local", StorageLocalAdapter);
|
registries.media.register("local", StorageLocalAdapter);
|
||||||
|
|
||||||
const credentials = {
|
const run_example: string | boolean = false;
|
||||||
url: import.meta.env.VITE_DB_URL!,
|
//run_example = "ex-admin-rich";
|
||||||
authToken: import.meta.env.VITE_DB_TOKEN!
|
|
||||||
};
|
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) {
|
if (!credentials.url) {
|
||||||
throw new Error("Missing VITE_DB_URL env variable. Add it to .env file");
|
throw new Error("Missing VITE_DB_URL env variable. Add it to .env file");
|
||||||
}
|
}
|
||||||
|
|
||||||
const connection = new LibsqlConnection(createClient(credentials));
|
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 {
|
export default {
|
||||||
async fetch(request: Request) {
|
async fetch(request: Request) {
|
||||||
const app = App.create({ connection });
|
const app = App.create({ connection, initialConfig });
|
||||||
|
|
||||||
app.emgr.onEvent(
|
app.emgr.onEvent(
|
||||||
App.Events.AppBuiltEvent,
|
App.Events.AppBuiltEvent,
|
||||||
async () => {
|
async () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user