mirror of
https://github.com/shishantbiswas/bknd.git
synced 2026-03-16 12:37:20 +00:00
117 lines
2.9 KiB
TypeScript
117 lines
2.9 KiB
TypeScript
import { omitKeys } from "bknd/utils";
|
|
import type { EntityManager } from "data/entities";
|
|
import { TransformPersistFailedException } from "../errors";
|
|
import { Field, type TActionContext, type TRenderContext, baseFieldConfigSchema } from "./Field";
|
|
import type { TFieldTSType } from "data/entities/EntityTypescript";
|
|
import { s } from "bknd/utils";
|
|
|
|
export const jsonFieldConfigSchema = s
|
|
.strictObject({
|
|
default_value: s.any(),
|
|
...omitKeys(baseFieldConfigSchema.properties, ["default_value"]),
|
|
})
|
|
.partial();
|
|
|
|
export type JsonFieldConfig = s.Static<typeof jsonFieldConfigSchema>;
|
|
|
|
export class JsonField<Required extends true | false = false, TypeOverride = object> extends Field<
|
|
JsonFieldConfig,
|
|
TypeOverride,
|
|
Required
|
|
> {
|
|
override readonly type = "json";
|
|
|
|
protected getSchema() {
|
|
return jsonFieldConfigSchema;
|
|
}
|
|
|
|
/**
|
|
* Transform value after retrieving from database
|
|
* @param value
|
|
*/
|
|
override transformRetrieve(value: any): any {
|
|
const val = super.transformRetrieve(value);
|
|
|
|
if (val === null && this.hasDefault()) {
|
|
return this.getDefault();
|
|
}
|
|
|
|
if (this.isSerialized(val)) {
|
|
return JSON.parse(val);
|
|
}
|
|
|
|
return val;
|
|
}
|
|
|
|
isSerializable(value: any) {
|
|
try {
|
|
const stringified = JSON.stringify(value);
|
|
if (stringified === JSON.stringify(JSON.parse(stringified))) {
|
|
return true;
|
|
}
|
|
} catch (e) {}
|
|
|
|
return false;
|
|
}
|
|
|
|
isSerialized(value: any) {
|
|
try {
|
|
if (typeof value === "string") {
|
|
return value === JSON.stringify(JSON.parse(value));
|
|
}
|
|
} catch (e) {}
|
|
|
|
return false;
|
|
}
|
|
|
|
override isValid(value: any): boolean {
|
|
return this.isSerializable(value);
|
|
}
|
|
|
|
override getValue(value: any, context: TRenderContext): any {
|
|
switch (context) {
|
|
case "table":
|
|
if (value === null) return null;
|
|
return JSON.stringify(value);
|
|
case "submit":
|
|
if (!value || (typeof value === "string" && value.length === 0)) {
|
|
return null;
|
|
} else if (typeof value === "object") {
|
|
return value;
|
|
}
|
|
|
|
return JSON.parse(value);
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
override async transformPersist(
|
|
_value: any,
|
|
em: EntityManager<any>,
|
|
context: TActionContext,
|
|
): Promise<string | undefined> {
|
|
const value = await super.transformPersist(_value, em, context);
|
|
if (this.nullish(value)) return value;
|
|
|
|
if (!this.isSerializable(value)) {
|
|
throw new TransformPersistFailedException(
|
|
`Field "${this.name}" must be serializable to JSON.`,
|
|
);
|
|
}
|
|
|
|
if (this.isSerialized(value)) {
|
|
return value;
|
|
}
|
|
|
|
return JSON.stringify(value);
|
|
}
|
|
|
|
override toType(): TFieldTSType {
|
|
return {
|
|
...super.toType(),
|
|
type: "any",
|
|
};
|
|
}
|
|
}
|