module manager: use json schema field for additional validation

This commit is contained in:
dswbx
2024-12-05 09:50:25 +01:00
parent 3757157a06
commit a3348122e6
2 changed files with 31 additions and 10 deletions

View File

@@ -54,7 +54,7 @@ export class JsonSchemaField<
if (parentValid) { if (parentValid) {
// already checked in parent // already checked in parent
if (!value || typeof value !== "object") { if (!this.isRequired() && (!value || typeof value !== "object")) {
//console.log("jsonschema:valid: not checking", this.name, value, context); //console.log("jsonschema:valid: not checking", this.name, value, context);
return true; return true;
} }
@@ -65,6 +65,7 @@ export class JsonSchemaField<
} else { } else {
//console.log("jsonschema:invalid", this.name, value, context); //console.log("jsonschema:invalid", this.name, value, context);
} }
//console.log("jsonschema:invalid:fromParent", this.name, value, context);
return false; return false;
} }
@@ -110,9 +111,13 @@ export class JsonSchemaField<
): Promise<string | undefined> { ): Promise<string | undefined> {
const value = await super.transformPersist(_value, em, context); const value = await super.transformPersist(_value, em, context);
if (this.nullish(value)) return value; if (this.nullish(value)) return value;
//console.log("jsonschema:transformPersist", this.name, _value, context);
if (!this.isValid(value)) { if (!this.isValid(value)) {
//console.error("jsonschema:transformPersist:invalid", this.name, value);
throw new TransformPersistFailedException(this.name, value); throw new TransformPersistFailedException(this.name, value);
} else {
//console.log("jsonschema:transformPersist:valid", this.name, value);
} }
if (!value || typeof value !== "object") return this.getDefault(); if (!value || typeof value !== "object") return this.getDefault();

View File

@@ -2,7 +2,7 @@ import { Diff } from "@sinclair/typebox/value";
import { Guard } from "auth"; import { Guard } from "auth";
import { BkndError, DebugLogger, Exception, isDebug } from "core"; import { BkndError, DebugLogger, Exception, isDebug } from "core";
import { EventManager } from "core/events"; import { EventManager } from "core/events";
import { Default, type Static, objectEach, transformObject } from "core/utils"; import { Default, type Static, StringEnum, Type, objectEach, transformObject } from "core/utils";
import { import {
type Connection, type Connection,
EntityManager, EntityManager,
@@ -11,8 +11,10 @@ import {
entity, entity,
enumm, enumm,
json, json,
jsonSchema,
number number
} from "data"; } from "data";
import { TransformPersistFailedException } from "data/errors";
import { Hono } from "hono"; import { Hono } from "hono";
import { type Kysely, sql } from "kysely"; import { type Kysely, sql } from "kysely";
import { mergeWith } from "lodash-es"; import { mergeWith } from "lodash-es";
@@ -73,10 +75,20 @@ type ConfigTable<Json = ModuleConfigs> = {
updated_at?: Date; updated_at?: Date;
}; };
const configJsonSchema = Type.Union([
getDefaultSchema(),
Type.Array(
Type.Object({
type: StringEnum(["insert", "update", "delete"]),
value: Type.Any(),
path: Type.Optional(Type.String())
})
)
]);
const __bknd = entity(TABLE_NAME, { const __bknd = entity(TABLE_NAME, {
version: number().required(), version: number().required(),
type: enumm({ enum: ["config", "diff", "backup"] }).required(), type: enumm({ enum: ["config", "diff", "backup"] }).required(),
json: json().required(), json: jsonSchema({ schema: configJsonSchema }).required(),
created_at: datetime(), created_at: datetime(),
updated_at: datetime() updated_at: datetime()
}); });
@@ -223,10 +235,9 @@ export class ModuleManager {
const configs = this.configs(); const configs = this.configs();
const version = this.version(); const version = this.version();
const json = JSON.stringify(configs) as any;
try { try {
const state = await this.fetch(); const state = await this.fetch();
this.logger.log("fetched version", state.version);
if (state.version !== version) { if (state.version !== version) {
// @todo: mark all others as "backup" // @todo: mark all others as "backup"
@@ -234,12 +245,13 @@ export class ModuleManager {
await this.mutator().insertOne({ await this.mutator().insertOne({
version, version,
type: "backup", type: "backup",
json json: configs
}); });
} else { } else {
this.logger.log("version matches"); this.logger.log("version matches");
const diff = Diff(state.json, JSON.parse(json)); // clean configs because of Diff() function
const diff = Diff(state.json, JSON.parse(JSON.stringify(configs)));
this.logger.log("checking diff", diff); this.logger.log("checking diff", diff);
if (diff.length > 0) { if (diff.length > 0) {
@@ -247,14 +259,14 @@ export class ModuleManager {
await this.mutator().insertOne({ await this.mutator().insertOne({
version, version,
type: "diff", type: "diff",
json: JSON.stringify(diff) as any json: diff
}); });
// store new version // store new version
// @todo: maybe by id? // @todo: maybe by id?
await this.mutator().updateWhere( await this.mutator().updateWhere(
{ {
version, version,
json, json: configs,
updated_at: new Date() updated_at: new Date()
}, },
{ {
@@ -268,14 +280,18 @@ export class ModuleManager {
} }
} catch (e) { } catch (e) {
if (e instanceof BkndError) { if (e instanceof BkndError) {
this.logger.log("no config, just save fresh");
// no config, just save // no config, just save
await this.mutator().insertOne({ await this.mutator().insertOne({
type: "config", type: "config",
version, version,
json, json: configs,
created_at: new Date(), created_at: new Date(),
updated_at: new Date() updated_at: new Date()
}); });
} else if (e instanceof TransformPersistFailedException) {
console.error("Cannot save invalid config");
throw e;
} else { } else {
console.error("Aborting"); console.error("Aborting");
throw e; throw e;