added pausing to event manager, added context aware entity schemas, fixed typings, first boot event, improved useEntityQuery mutation behavior

This commit is contained in:
dswbx
2024-12-20 20:11:49 +01:00
parent a7e3ce878a
commit deddf00c38
12 changed files with 148 additions and 55 deletions

View File

@@ -46,7 +46,7 @@ export class DataApi<DB> extends ModuleApi<DataApiOptions> {
createOne<E extends keyof DB | string, Data = E extends keyof DB ? DB[E] : EntityData>(
entity: E,
input: Data
input: Omit<Data, "id">
) {
return this.post<RepositoryResponse<Data>>([entity as any], input);
}
@@ -54,7 +54,7 @@ export class DataApi<DB> extends ModuleApi<DataApiOptions> {
updateOne<E extends keyof DB | string, Data = E extends keyof DB ? DB[E] : EntityData>(
entity: E,
id: PrimaryFieldType,
input: Partial<Data>
input: Partial<Omit<Data, "id">>
) {
return this.patch<RepositoryResponse<Data>>([entity as any, id], input);
}

View File

@@ -1,5 +1,5 @@
import { type ClassController, isDebug, tbValidator as tb } from "core";
import { Type, objectCleanEmpty, objectTransform } from "core/utils";
import { StringEnum, Type, objectCleanEmpty, objectTransform } from "core/utils";
import {
DataPermissions,
type EntityData,
@@ -182,19 +182,25 @@ export class DataController implements ClassController {
})
// read schema
.get(
"/schemas/:entity",
tb("param", Type.Object({ entity: Type.String() })),
"/schemas/:entity/:context?",
tb(
"param",
Type.Object({
entity: Type.String(),
context: Type.Optional(StringEnum(["create", "update"]))
})
),
async (c) => {
this.guard.throwUnlessGranted(DataPermissions.entityRead);
//console.log("request", c.req.raw);
const { entity } = c.req.param();
const { entity, context } = c.req.param();
if (!this.entityExists(entity)) {
console.log("not found", entity, definedEntities);
return c.notFound();
}
const _entity = this.em.entity(entity);
const schema = _entity.toSchema();
const schema = _entity.toSchema({ context } as any);
const url = new URL(c.req.url);
const base = `${url.origin}${this.config.basepath}`;
const $id = `${this.config.basepath}/schemas/${entity}`;

View File

@@ -158,7 +158,7 @@ export class Entity<
}
get label(): string {
return snakeToPascalWithSpaces(this.config.name || this.name);
return this.config.name ?? snakeToPascalWithSpaces(this.name);
}
field(name: string): Field | undefined {
@@ -210,21 +210,34 @@ export class Entity<
return true;
}
toSchema(clean?: boolean): object {
const fields = Object.fromEntries(this.fields.map((field) => [field.name, field]));
toSchema(options?: { clean: boolean; context?: "create" | "update" }): object {
let fields: Field[];
switch (options?.context) {
case "create":
case "update":
fields = this.getFillableFields(options.context);
break;
default:
fields = this.getFields(true);
}
const _fields = Object.fromEntries(fields.map((field) => [field.name, field]));
const schema = Type.Object(
transformObject(fields, (field) => ({
title: field.config.label,
$comment: field.config.description,
$field: field.type,
readOnly: !field.isFillable("update") ? true : undefined,
writeOnly: !field.isFillable("create") ? true : undefined,
...field.toJsonSchema()
})),
transformObject(_fields, (field) => {
//const hidden = field.isHidden(options?.context);
const fillable = field.isFillable(options?.context);
return {
title: field.config.label,
$comment: field.config.description,
$field: field.type,
readOnly: !fillable ? true : undefined,
...field.toJsonSchema()
};
}),
{ additionalProperties: false }
);
return clean ? JSON.parse(JSON.stringify(schema)) : schema;
return options?.clean ? JSON.parse(JSON.stringify(schema)) : schema;
}
toJSON() {

View File

@@ -25,8 +25,12 @@ export type MutatorResponse<T = EntityData[]> = {
data: T;
};
export class Mutator<DB = any, TB extends keyof DB = any, Data = Omit<DB[TB], "id">>
implements EmitsEvents
export class Mutator<
DB = any,
TB extends keyof DB = any,
Output = DB[TB],
Input = Omit<Output, "id">
> implements EmitsEvents
{
em: EntityManager<DB>;
entity: Entity;
@@ -122,7 +126,7 @@ export class Mutator<DB = any, TB extends keyof DB = any, Data = Omit<DB[TB], "i
return { ...response, data: data[0]! };
}
async insertOne(data: Data): Promise<MutatorResponse<DB[TB]>> {
async insertOne(data: Input): Promise<MutatorResponse<Output>> {
const entity = this.entity;
if (entity.type === "system" && this.__unstable_disable_system_entity_creation) {
throw new Error(`Creation of system entity "${entity.name}" is disabled`);
@@ -159,7 +163,7 @@ export class Mutator<DB = any, TB extends keyof DB = any, Data = Omit<DB[TB], "i
return res as any;
}
async updateOne(id: PrimaryFieldType, data: Data): Promise<MutatorResponse<DB[TB]>> {
async updateOne(id: PrimaryFieldType, data: Input): Promise<MutatorResponse<Output>> {
const entity = this.entity;
if (!Number.isInteger(id)) {
throw new Error("ID must be provided for update");
@@ -190,7 +194,7 @@ export class Mutator<DB = any, TB extends keyof DB = any, Data = Omit<DB[TB], "i
return res as any;
}
async deleteOne(id: PrimaryFieldType): Promise<MutatorResponse<DB[TB]>> {
async deleteOne(id: PrimaryFieldType): Promise<MutatorResponse<Output>> {
const entity = this.entity;
if (!Number.isInteger(id)) {
throw new Error("ID must be provided for deletion");
@@ -256,7 +260,7 @@ export class Mutator<DB = any, TB extends keyof DB = any, Data = Omit<DB[TB], "i
}
// @todo: decide whether entries should be deleted all at once or one by one (for events)
async deleteWhere(where?: RepoQuery["where"]): Promise<MutatorResponse<DB[TB][]>> {
async deleteWhere(where?: RepoQuery["where"]): Promise<MutatorResponse<Output[]>> {
const entity = this.entity;
const qb = this.appendWhere(this.conn.deleteFrom(entity.name), where).returning(
@@ -266,7 +270,7 @@ export class Mutator<DB = any, TB extends keyof DB = any, Data = Omit<DB[TB], "i
return (await this.many(qb)) as any;
}
async updateWhere(data: Data, where?: RepoQuery["where"]): Promise<MutatorResponse<DB[TB][]>> {
async updateWhere(data: Input, where?: RepoQuery["where"]): Promise<MutatorResponse<Output[]>> {
const entity = this.entity;
const validatedData = await this.getValidatedData(data, "update");
@@ -277,7 +281,7 @@ export class Mutator<DB = any, TB extends keyof DB = any, Data = Omit<DB[TB], "i
return (await this.many(query)) as any;
}
async insertMany(data: Data[]): Promise<MutatorResponse<DB[TB][]>> {
async insertMany(data: Input[]): Promise<MutatorResponse<Output[]>> {
const entity = this.entity;
if (entity.type === "system" && this.__unstable_disable_system_entity_creation) {
throw new Error(`Creation of system entity "${entity.name}" is disabled`);