mirror of
https://github.com/bknd-io/bknd/
synced 2026-08-03 00:26:01 +00:00
merged origin/release/0.12
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { isDebug, tbValidator as tb } from "core";
|
||||
import { $console, isDebug, tbValidator as tb } from "core";
|
||||
import { StringEnum } from "core/utils";
|
||||
import * as tbbox from "@sinclair/typebox";
|
||||
import {
|
||||
@@ -47,7 +47,6 @@ export class DataController extends Controller {
|
||||
const template = { data: res.data, meta };
|
||||
|
||||
// @todo: this works but it breaks in FE (need to improve DataTable)
|
||||
//return objectCleanEmpty(template) as any;
|
||||
// filter empty
|
||||
return Object.fromEntries(
|
||||
Object.entries(template).filter(([_, v]) => typeof v !== "undefined" && v !== null),
|
||||
@@ -58,7 +57,6 @@ export class DataController extends Controller {
|
||||
const template = { data: res.data };
|
||||
|
||||
// filter empty
|
||||
//return objectCleanEmpty(template);
|
||||
return Object.fromEntries(Object.entries(template).filter(([_, v]) => v !== undefined));
|
||||
}
|
||||
|
||||
@@ -74,11 +72,6 @@ export class DataController extends Controller {
|
||||
const { permission, auth } = this.middlewares;
|
||||
const hono = this.create().use(auth(), permission(SystemPermissions.accessApi));
|
||||
|
||||
const definedEntities = this.em.entities.map((e) => e.name);
|
||||
const tbNumber = Type.Transform(Type.String({ pattern: "^[1-9][0-9]{0,}$" }))
|
||||
.Decode(Number.parseInt)
|
||||
.Encode(String);
|
||||
|
||||
// @todo: sample implementation how to augment handler with additional info
|
||||
function handler<HH extends Handler>(name: string, h: HH): any {
|
||||
const func = h;
|
||||
@@ -143,10 +136,8 @@ export class DataController extends Controller {
|
||||
}),
|
||||
),
|
||||
async (c) => {
|
||||
//console.log("request", c.req.raw);
|
||||
const { entity, context } = c.req.param();
|
||||
if (!this.entityExists(entity)) {
|
||||
console.warn("not found:", entity, definedEntities);
|
||||
return this.notFound(c);
|
||||
}
|
||||
const _entity = this.em.entity(entity);
|
||||
@@ -256,7 +247,6 @@ export class DataController extends Controller {
|
||||
async (c) => {
|
||||
const { entity } = c.req.param();
|
||||
if (!this.entityExists(entity)) {
|
||||
console.warn("not found:", entity, definedEntities);
|
||||
return this.notFound(c);
|
||||
}
|
||||
const options = c.req.valid("query") as RepoQuery;
|
||||
@@ -330,7 +320,6 @@ export class DataController extends Controller {
|
||||
return this.notFound(c);
|
||||
}
|
||||
const options = (await c.req.valid("json")) as RepoQuery;
|
||||
//console.log("options", options);
|
||||
const result = await this.em.repository(entity).findMany(options);
|
||||
|
||||
return c.json(this.repoResult(result), { status: result.data ? 200 : 404 });
|
||||
|
||||
@@ -38,7 +38,7 @@ export class LibsqlConnection extends SqliteConnection {
|
||||
if (clientOrCredentials && "url" in clientOrCredentials) {
|
||||
let { url, authToken, protocol } = clientOrCredentials;
|
||||
if (protocol && LIBSQL_PROTOCOLS.includes(protocol)) {
|
||||
console.log("changing protocol to", protocol);
|
||||
$console.log("changing protocol to", protocol);
|
||||
const [, rest] = url.split("://");
|
||||
url = `${protocol}://${rest}`;
|
||||
}
|
||||
|
||||
@@ -35,7 +35,6 @@ export type TAppDataField = Static<typeof fieldsSchema>;
|
||||
export type TAppDataEntityFields = Static<typeof entityFields>;
|
||||
|
||||
export const entitiesSchema = tb.Type.Object({
|
||||
//name: Type.String(),
|
||||
type: tb.Type.Optional(
|
||||
tb.Type.String({ enum: entityTypes, default: "regular", readOnly: true }),
|
||||
),
|
||||
@@ -63,7 +62,6 @@ export const indicesSchema = tb.Type.Object(
|
||||
{
|
||||
entity: tb.Type.String(),
|
||||
fields: tb.Type.Array(tb.Type.String(), { minItems: 1 }),
|
||||
//name: Type.Optional(Type.String()),
|
||||
unique: tb.Type.Optional(tb.Type.Boolean({ default: false })),
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { config } from "core";
|
||||
import { $console, config } from "core";
|
||||
import {
|
||||
type Static,
|
||||
StringEnum,
|
||||
@@ -184,9 +184,9 @@ export class Entity<
|
||||
if (existing) {
|
||||
// @todo: for now adding a graceful method
|
||||
if (JSON.stringify(existing) === JSON.stringify(field)) {
|
||||
/*console.warn(
|
||||
$console.warn(
|
||||
`Field "${field.name}" already exists on entity "${this.name}", but it's the same, so skipping.`,
|
||||
);*/
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -233,7 +233,13 @@ export class Entity<
|
||||
|
||||
for (const field of fields) {
|
||||
if (!field.isValid(data[field.name], context)) {
|
||||
console.log("Entity.isValidData:invalid", context, field.name, data[field.name]);
|
||||
$console.warn(
|
||||
"invalid data given for",
|
||||
this.name,
|
||||
context,
|
||||
field.name,
|
||||
data[field.name],
|
||||
);
|
||||
if (options?.explain) {
|
||||
throw new Error(`Field "${field.name}" has invalid data: "${data[field.name]}"`);
|
||||
}
|
||||
@@ -259,7 +265,6 @@ export class Entity<
|
||||
const _fields = Object.fromEntries(fields.map((field) => [field.name, field]));
|
||||
const schema = Type.Object(
|
||||
transformObject(_fields, (field) => {
|
||||
//const hidden = field.isHidden(options?.context);
|
||||
const fillable = field.isFillable(options?.context);
|
||||
return {
|
||||
title: field.config.label,
|
||||
@@ -277,9 +282,7 @@ export class Entity<
|
||||
|
||||
toJSON() {
|
||||
return {
|
||||
//name: this.name,
|
||||
type: this.type,
|
||||
//fields: transformObject(this.fields, (field) => field.toJSON()),
|
||||
fields: Object.fromEntries(this.fields.map((field) => [field.name, field.toJSON()])),
|
||||
config: this.config,
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { DB as DefaultDB } from "core";
|
||||
import { $console, type DB as DefaultDB } from "core";
|
||||
import { EventManager } from "core/events";
|
||||
import { sql } from "kysely";
|
||||
import { Connection } from "../connection/Connection";
|
||||
@@ -55,7 +55,6 @@ export class EntityManager<TBD extends object = DefaultDB> {
|
||||
|
||||
this.connection = connection;
|
||||
this.emgr = emgr ?? new EventManager();
|
||||
//console.log("registering events", EntityManager.Events);
|
||||
this.emgr.registerEvents(EntityManager.Events);
|
||||
}
|
||||
|
||||
@@ -90,7 +89,9 @@ export class EntityManager<TBD extends object = DefaultDB> {
|
||||
if (existing) {
|
||||
// @todo: for now adding a graceful method
|
||||
if (JSON.stringify(existing) === JSON.stringify(entity)) {
|
||||
//console.warn(`Entity "${entity.name}" already exists, but it's the same, so skipping.`);
|
||||
$console.warn(
|
||||
`Entity "${entity.name}" already exists, but it's the same, skipping adding it.`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -108,7 +109,6 @@ 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)
|
||||
}
|
||||
|
||||
@@ -295,7 +295,6 @@ export class EntityManager<TBD extends object = DefaultDB> {
|
||||
return {
|
||||
entities: Object.fromEntries(this.entities.map((e) => [e.name, e.toJSON()])),
|
||||
relations: Object.fromEntries(this.relations.all.map((r) => [r.getName(), r.toJSON()])),
|
||||
//relations: this.relations.all.map((r) => r.toJSON()),
|
||||
indices: Object.fromEntries(this.indices.map((i) => [i.name, i.toJSON()])),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { DB as DefaultDB, PrimaryFieldType } from "core";
|
||||
import { $console, type DB as DefaultDB, type PrimaryFieldType } from "core";
|
||||
import { type EmitsEvents, EventManager } from "core/events";
|
||||
import type { DeleteQueryBuilder, InsertQueryBuilder, UpdateQueryBuilder } from "kysely";
|
||||
import { type TActionContext, WhereBuilder } from "..";
|
||||
@@ -72,7 +72,6 @@ export class Mutator<
|
||||
|
||||
// if relation field (include key and value in validatedData)
|
||||
if (Array.isArray(result)) {
|
||||
//console.log("--- (instructions)", result);
|
||||
const [relation_key, relation_value] = result;
|
||||
validatedData[relation_key] = relation_value;
|
||||
}
|
||||
@@ -122,7 +121,7 @@ export class Mutator<
|
||||
};
|
||||
} catch (e) {
|
||||
// @todo: redact
|
||||
console.log("[Error in query]", sql);
|
||||
$console.error("[Error in query]", sql);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,7 +49,6 @@ export class BooleanField<Required extends true | false = false> extends Field<
|
||||
}
|
||||
|
||||
override transformRetrieve(value: unknown): boolean | null {
|
||||
//console.log("Boolean:transformRetrieve:value", value);
|
||||
if (typeof value === "undefined" || value === null) {
|
||||
if (this.isRequired()) return false;
|
||||
if (this.hasDefault()) return this.getDefault();
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { type Static, StringEnum, dayjs } from "core/utils";
|
||||
import type { EntityManager } from "../entities";
|
||||
import { Field, type TActionContext, type TRenderContext, baseFieldConfigSchema } from "./Field";
|
||||
import { $console } from "core";
|
||||
import * as tbbox from "@sinclair/typebox";
|
||||
const { Type } = tbbox;
|
||||
|
||||
export const dateFieldConfigSchema = Type.Composite(
|
||||
[
|
||||
Type.Object({
|
||||
//default_value: Type.Optional(Type.Date()),
|
||||
type: StringEnum(["date", "datetime", "week"] as const, { default: "date" }),
|
||||
timezone: Type.Optional(Type.String()),
|
||||
min_date: Type.Optional(Type.String()),
|
||||
@@ -53,13 +53,11 @@ export class DateField<Required extends true | false = false> extends Field<
|
||||
}
|
||||
|
||||
private parseDateFromString(value: string): Date {
|
||||
//console.log("parseDateFromString", value);
|
||||
if (this.config.type === "week" && value.includes("-W")) {
|
||||
const [year, week] = value.split("-W").map((n) => Number.parseInt(n, 10)) as [
|
||||
number,
|
||||
number,
|
||||
];
|
||||
//console.log({ year, week });
|
||||
// @ts-ignore causes errors on build?
|
||||
return dayjs().year(year).week(week).toDate();
|
||||
}
|
||||
@@ -69,15 +67,12 @@ export class DateField<Required extends true | false = false> extends Field<
|
||||
|
||||
override getValue(value: string, context?: TRenderContext): string | undefined {
|
||||
if (value === null || !value) return;
|
||||
//console.log("getValue", { value, context });
|
||||
const date = this.parseDateFromString(value);
|
||||
//console.log("getValue.date", date);
|
||||
|
||||
if (context === "submit") {
|
||||
try {
|
||||
return date.toISOString();
|
||||
} catch (e) {
|
||||
//console.warn("DateField.getValue:value/submit", value, e);
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
@@ -86,7 +81,7 @@ export class DateField<Required extends true | false = false> extends Field<
|
||||
try {
|
||||
return `${date.getFullYear()}-W${dayjs(date).week()}`;
|
||||
} catch (e) {
|
||||
console.warn("error - DateField.getValue:week", value, e);
|
||||
$console.warn("DateField.getValue:week error", value, String(e));
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -99,8 +94,7 @@ export class DateField<Required extends true | false = false> extends Field<
|
||||
|
||||
return this.formatDate(local);
|
||||
} catch (e) {
|
||||
console.warn("DateField.getValue:value", value);
|
||||
console.warn("DateField.getValue:e", e);
|
||||
$console.warn("DateField.getValue error", this.config.type, value, String(e));
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -119,7 +113,6 @@ export class DateField<Required extends true | false = false> extends Field<
|
||||
}
|
||||
|
||||
override transformRetrieve(_value: string): Date | null {
|
||||
//console.log("transformRetrieve DateField", _value);
|
||||
const value = super.transformRetrieve(_value);
|
||||
if (value === null) return null;
|
||||
|
||||
@@ -138,7 +131,6 @@ export class DateField<Required extends true | false = false> extends Field<
|
||||
const value = await super.transformPersist(_value, em, context);
|
||||
if (this.nullish(value)) return value;
|
||||
|
||||
//console.log("transformPersist DateField", value);
|
||||
switch (this.config.type) {
|
||||
case "date":
|
||||
case "week":
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Const, type Static, StringEnum } from "core/utils";
|
||||
import type { EntityManager } from "data";
|
||||
import { TransformPersistFailedException } from "../errors";
|
||||
import { Field, type TActionContext, type TRenderContext, baseFieldConfigSchema } from "./Field";
|
||||
import { baseFieldConfigSchema, Field, type TActionContext, type TRenderContext } from "./Field";
|
||||
import * as tbbox from "@sinclair/typebox";
|
||||
const { Type } = tbbox;
|
||||
|
||||
@@ -55,10 +55,6 @@ export class EnumField<Required extends true | false = false, TypeOverride = str
|
||||
constructor(name: string, config: Partial<EnumFieldConfig>) {
|
||||
super(name, config);
|
||||
|
||||
/*if (this.config.options.values.length === 0) {
|
||||
throw new Error(`Enum field "${this.name}" requires at least one option`);
|
||||
}*/
|
||||
|
||||
if (this.config.default_value && !this.isValidValue(this.config.default_value)) {
|
||||
throw new Error(`Default value "${this.config.default_value}" is not a valid option`);
|
||||
}
|
||||
@@ -71,10 +67,6 @@ export class EnumField<Required extends true | false = false, TypeOverride = str
|
||||
getOptions(): { label: string; value: string }[] {
|
||||
const options = this.config?.options ?? { type: "strings", values: [] };
|
||||
|
||||
/*if (options.values?.length === 0) {
|
||||
throw new Error(`Enum field "${this.name}" requires at least one option`);
|
||||
}*/
|
||||
|
||||
if (options.type === "strings") {
|
||||
return options.values?.map((option) => ({ label: option, value: option }));
|
||||
}
|
||||
|
||||
@@ -84,7 +84,6 @@ export class JsonField<Required extends true | false = false, TypeOverride = obj
|
||||
context: TActionContext,
|
||||
): Promise<string | undefined> {
|
||||
const value = await super.transformPersist(_value, em, context);
|
||||
//console.log("value", value);
|
||||
if (this.nullish(value)) return value;
|
||||
|
||||
if (!this.isSerializable(value)) {
|
||||
|
||||
@@ -48,22 +48,16 @@ export class JsonSchemaField<
|
||||
|
||||
override isValid(value: any, context: TActionContext = "update"): boolean {
|
||||
const parentValid = super.isValid(value, context);
|
||||
//console.log("jsonSchemaField:isValid", this.getJsonSchema(), this.name, value, parentValid);
|
||||
|
||||
if (parentValid) {
|
||||
// already checked in parent
|
||||
if (!this.isRequired() && (!value || typeof value !== "object")) {
|
||||
//console.log("jsonschema:valid: not checking", this.name, value, context);
|
||||
return true;
|
||||
}
|
||||
|
||||
const result = this.validator.validate(value);
|
||||
//console.log("jsonschema:errors", this.name, result.errors);
|
||||
return result.valid;
|
||||
} else {
|
||||
//console.log("jsonschema:invalid", this.name, value, context);
|
||||
}
|
||||
//console.log("jsonschema:invalid:fromParent", this.name, value, context);
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -91,7 +85,6 @@ export class JsonSchemaField<
|
||||
try {
|
||||
return Default(FromSchema(this.getJsonSchema()), {});
|
||||
} catch (e) {
|
||||
//console.error("jsonschema:transformRetrieve", e);
|
||||
return null;
|
||||
}
|
||||
} else if (this.hasDefault()) {
|
||||
@@ -109,13 +102,9 @@ export class JsonSchemaField<
|
||||
): Promise<string | undefined> {
|
||||
const value = await super.transformPersist(_value, em, context);
|
||||
if (this.nullish(value)) return value;
|
||||
//console.log("jsonschema:transformPersist", this.name, _value, context);
|
||||
|
||||
if (!this.isValid(value)) {
|
||||
//console.error("jsonschema:transformPersist:invalid", 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();
|
||||
|
||||
@@ -98,12 +98,9 @@ export function fieldTestSuite(
|
||||
test("toJSON", async () => {
|
||||
const _config = {
|
||||
..._requiredConfig,
|
||||
//order: 1,
|
||||
fillable: true,
|
||||
required: false,
|
||||
hidden: false,
|
||||
//virtual: false,
|
||||
//default_value: undefined
|
||||
};
|
||||
|
||||
function fieldJson(field: Field) {
|
||||
@@ -115,19 +112,16 @@ export function fieldTestSuite(
|
||||
}
|
||||
|
||||
expect(fieldJson(noConfigField)).toEqual({
|
||||
//name: "no_config",
|
||||
type: noConfigField.type,
|
||||
config: _config,
|
||||
});
|
||||
|
||||
expect(fieldJson(fillable)).toEqual({
|
||||
//name: "fillable",
|
||||
type: noConfigField.type,
|
||||
config: _config,
|
||||
});
|
||||
|
||||
expect(fieldJson(required)).toEqual({
|
||||
//name: "required",
|
||||
type: required.type,
|
||||
config: {
|
||||
..._config,
|
||||
@@ -136,7 +130,6 @@ export function fieldTestSuite(
|
||||
});
|
||||
|
||||
expect(fieldJson(hidden)).toEqual({
|
||||
//name: "hidden",
|
||||
type: required.type,
|
||||
config: {
|
||||
..._config,
|
||||
@@ -145,7 +138,6 @@ export function fieldTestSuite(
|
||||
});
|
||||
|
||||
expect(fieldJson(dflt)).toEqual({
|
||||
//name: "dflt",
|
||||
type: dflt.type,
|
||||
config: {
|
||||
..._config,
|
||||
@@ -154,7 +146,6 @@ export function fieldTestSuite(
|
||||
});
|
||||
|
||||
expect(fieldJson(requiredAndDefault)).toEqual({
|
||||
//name: "full",
|
||||
type: requiredAndDefault.type,
|
||||
config: {
|
||||
..._config,
|
||||
|
||||
@@ -39,7 +39,6 @@ export class EntityIndex {
|
||||
return {
|
||||
entity: this.entity.name,
|
||||
fields: this.fields.map((f) => f.name),
|
||||
//name: this.name,
|
||||
unique: this.unique,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ export function getChangeSet(
|
||||
data: EntityData,
|
||||
fields: Field[],
|
||||
): EntityData {
|
||||
//console.log("getChangeSet", formData, data);
|
||||
return transform(
|
||||
formData,
|
||||
(acc, _value, key) => {
|
||||
@@ -32,17 +31,6 @@ export function getChangeSet(
|
||||
// @todo: add typing for "action"
|
||||
if (action === "create" || newValue !== data[key]) {
|
||||
acc[key] = newValue;
|
||||
/*console.log("changed", {
|
||||
key,
|
||||
value,
|
||||
valueType: typeof value,
|
||||
prev: data[key],
|
||||
newValue,
|
||||
new: value,
|
||||
sent: acc[key]
|
||||
});*/
|
||||
} else {
|
||||
//console.log("no change", key, value, data[key]);
|
||||
}
|
||||
},
|
||||
{} as typeof formData,
|
||||
|
||||
@@ -14,15 +14,6 @@ const { Type } = tbbox;
|
||||
export type KyselyJsonFrom = any;
|
||||
export type KyselyQueryBuilder = SelectQueryBuilder<any, any, any>;
|
||||
|
||||
/*export type RelationConfig = {
|
||||
mappedBy?: string;
|
||||
inversedBy?: string;
|
||||
sourceCardinality?: number;
|
||||
connectionTable?: string;
|
||||
connectionTableMappedName?: string;
|
||||
required?: boolean;
|
||||
};*/
|
||||
|
||||
export type BaseRelationConfig = Static<typeof EntityRelation.schema>;
|
||||
|
||||
// @todo: add generic type for relation config
|
||||
@@ -167,7 +158,6 @@ export abstract class EntityRelation<
|
||||
* @param entity
|
||||
*/
|
||||
isListableFor(entity: Entity): boolean {
|
||||
//console.log("isListableFor", entity.name, this.source.entity.name, this.target.entity.name);
|
||||
return this.target.entity.name === entity.name;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import type { Static } from "core/utils";
|
||||
import type { ExpressionBuilder } from "kysely";
|
||||
import { Entity, type EntityManager } from "../entities";
|
||||
import { type Field, PrimaryField, VirtualField } from "../fields";
|
||||
import { type Field, PrimaryField } from "../fields";
|
||||
import type { RepoQuery } from "../server/data-query-impl";
|
||||
import { EntityRelation, type KyselyJsonFrom, type KyselyQueryBuilder } from "./EntityRelation";
|
||||
import { EntityRelation, type KyselyQueryBuilder } from "./EntityRelation";
|
||||
import { EntityRelationAnchor } from "./EntityRelationAnchor";
|
||||
import { RelationField } from "./RelationField";
|
||||
import { type RelationType, RelationTypes } from "./relation-types";
|
||||
@@ -48,7 +48,6 @@ export class ManyToManyRelation extends EntityRelation<typeof ManyToManyRelation
|
||||
|
||||
this.connectionTableMappedName = config?.connectionTableMappedName || connectionTable;
|
||||
this.additionalFields = additionalFields || [];
|
||||
//this.connectionTable = connectionTable;
|
||||
}
|
||||
|
||||
static defaultConnectionTable(source: Entity, target: Entity) {
|
||||
|
||||
@@ -4,7 +4,7 @@ import type { Static } from "core/utils";
|
||||
import type { ExpressionBuilder } from "kysely";
|
||||
import type { Entity, EntityManager } from "../entities";
|
||||
import type { RepoQuery } from "../server/data-query-impl";
|
||||
import { EntityRelation, type KyselyJsonFrom, type KyselyQueryBuilder } from "./EntityRelation";
|
||||
import { EntityRelation, type KyselyQueryBuilder } from "./EntityRelation";
|
||||
import { EntityRelationAnchor } from "./EntityRelationAnchor";
|
||||
import { RelationField, type RelationFieldBaseConfig } from "./RelationField";
|
||||
import type { MutationInstructionResponse } from "./RelationMutator";
|
||||
@@ -127,7 +127,6 @@ export class ManyToOneRelation extends EntityRelation<typeof ManyToOneRelation.s
|
||||
}
|
||||
|
||||
const groupBy = `${entity.name}.${entity.getPrimaryField().name}`;
|
||||
//console.log("queryInfo", entity.name, { reference, side, relationRef, entityRef, otherRef });
|
||||
|
||||
return {
|
||||
other,
|
||||
|
||||
@@ -17,11 +17,6 @@ export const relationFieldConfigSchema = Type.Composite([
|
||||
on_delete: Type.Optional(StringEnum(CASCADES, { default: "set null" })),
|
||||
}),
|
||||
]);
|
||||
/*export const relationFieldConfigSchema = baseFieldConfigSchema.extend({
|
||||
reference: z.string(),
|
||||
target: z.string(),
|
||||
target_field: z.string().catch("id"),
|
||||
});*/
|
||||
|
||||
export type RelationFieldConfig = Static<typeof relationFieldConfigSchema>;
|
||||
export type RelationFieldBaseConfig = { label?: string };
|
||||
@@ -33,16 +28,6 @@ export class RelationField extends Field<RelationFieldConfig> {
|
||||
return relationFieldConfigSchema;
|
||||
}
|
||||
|
||||
/*constructor(name: string, config?: Partial<RelationFieldConfig>) {
|
||||
//relation_name = relation_name || target.name;
|
||||
//const name = [relation_name, target.getPrimaryField().name].join("_");
|
||||
super(name, config);
|
||||
|
||||
//console.log(this.config);
|
||||
//this.relation.target = target;
|
||||
//this.relation.name = relation_name;
|
||||
}*/
|
||||
|
||||
static create(
|
||||
relation: EntityRelation,
|
||||
target: EntityRelationAnchor,
|
||||
@@ -52,7 +37,7 @@ export class RelationField extends Field<RelationFieldConfig> {
|
||||
target.reference ?? target.entity.name,
|
||||
target.entity.getPrimaryField().name,
|
||||
].join("_");
|
||||
//console.log('name', name);
|
||||
|
||||
return new RelationField(name, {
|
||||
...config,
|
||||
required: relation.required,
|
||||
|
||||
@@ -63,7 +63,6 @@ export class RelationMutator {
|
||||
// make sure it's a primitive value
|
||||
// @todo: this is not a good way of checking primitives. Null is also an object
|
||||
if (typeof value === "object") {
|
||||
console.log("value", value);
|
||||
throw new Error(`Invalid value for relation field "${key}" given, expected primitive.`);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
type Field<Type, Required extends true | false> = {
|
||||
_type: Type;
|
||||
_required: Required;
|
||||
};
|
||||
type TextField<Required extends true | false = false> = Field<string, Required> & {
|
||||
_type: string;
|
||||
required: () => TextField<true>;
|
||||
};
|
||||
type NumberField<Required extends true | false = false> = Field<number, Required> & {
|
||||
_type: number;
|
||||
required: () => NumberField<true>;
|
||||
};
|
||||
|
||||
type Entity<Fields extends Record<string, Field<any, any>> = {}> = { name: string; fields: Fields };
|
||||
|
||||
function entity<Fields extends Record<string, Field<any, any>>>(
|
||||
name: string,
|
||||
fields: Fields,
|
||||
): Entity<Fields> {
|
||||
return { name, fields };
|
||||
}
|
||||
|
||||
function text(): TextField<false> {
|
||||
return {} as any;
|
||||
}
|
||||
function number(): NumberField<false> {
|
||||
return {} as any;
|
||||
}
|
||||
|
||||
const field1 = text();
|
||||
const field1_req = text().required();
|
||||
const field2 = number();
|
||||
const user = entity("users", {
|
||||
name: text().required(),
|
||||
bio: text(),
|
||||
age: number(),
|
||||
some: number().required(),
|
||||
});
|
||||
|
||||
type InferEntityFields<T> = T extends Entity<infer Fields>
|
||||
? {
|
||||
[K in keyof Fields]: Fields[K] extends { _type: infer Type; _required: infer Required }
|
||||
? Required extends true
|
||||
? Type
|
||||
: Type | undefined
|
||||
: never;
|
||||
}
|
||||
: never;
|
||||
|
||||
type Prettify<T> = {
|
||||
[K in keyof T]: T[K];
|
||||
};
|
||||
export type Simplify<T> = { [KeyType in keyof T]: T[KeyType] } & {};
|
||||
|
||||
// from https://github.com/type-challenges/type-challenges/issues/28200
|
||||
type Merge<T> = {
|
||||
[K in keyof T]: T[K];
|
||||
};
|
||||
type OptionalUndefined<
|
||||
T,
|
||||
Props extends keyof T = keyof T,
|
||||
OptionsProps extends keyof T = Props extends keyof T
|
||||
? undefined extends T[Props]
|
||||
? Props
|
||||
: never
|
||||
: never,
|
||||
> = Merge<
|
||||
{
|
||||
[K in OptionsProps]?: T[K];
|
||||
} & {
|
||||
[K in Exclude<keyof T, OptionsProps>]: T[K];
|
||||
}
|
||||
>;
|
||||
|
||||
type UserFields = InferEntityFields<typeof user>;
|
||||
type UserFields2 = Simplify<OptionalUndefined<UserFields>>;
|
||||
|
||||
const obj: UserFields2 = { name: "h", age: 1, some: 1 };
|
||||
Reference in New Issue
Block a user