UNPKG

@scenemesh/entity-engine

Version:

一个“元数据驱动 + 组件适配 + 动态关系 + 视图管线”式的实体引擎。以 **Model + View + FieldType + SuiteAdapter + DataSource** 为五大支点,统一 CRUD / 查询 / 引用管理 / 视图渲染 / 扩展注册,支持在运行期无侵入拼装出 **表单、网格、主从、看板、仪表盘、流程/树形视图** 等多形态界面。

1,604 lines (1,582 loc) 168 kB
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _chunk4XLO6XC7js = require('./chunk-4XLO6XC7.js'); // src/modules/build-in/module.json var module_default = { name: "build-in-module", version: "1.0.0", description: "\u5185\u5EFA\u6A21\u5757", provider: "Scenemesh Team", dependencies: [], url: "http://github.com/scenemesh" }; // src/modules/build-in/config/config.ts var models = [ { name: "__default__", title: "\u9ED8\u8BA4\u6A21\u578B", description: "Default Model", fields: [] }, { name: "__config__", title: "\u914D\u7F6E\u6A21\u578B", description: "Config Model", fields: [ { name: "name", title: "\u914D\u7F6E\u540D\u79F0", description: "\u914D\u7F6E\u540D\u79F0", type: "string", isRequired: true, searchable: true }, { name: "version", title: "\u914D\u7F6E\u7248\u672C", description: "\u914D\u7F6E\u7248\u672C", type: "number", isRequired: true, searchable: false }, { name: "content", title: "\u914D\u7F6E\u5185\u5BB9", description: "\u914D\u7F6E\u5185\u5BB9", type: "string", isRequired: true, searchable: false } ] }, { name: "entity-change-log", title: "\u5B9E\u4F53\u53D8\u66F4\u8BB0\u5F55", description: "Entity Change Log", fields: [ { name: "modelName", title: "Model Name", description: "Model Name", type: "string", isRequired: true, searchable: true }, { name: "objectId", title: "Object ID", description: "Object ID", type: "string", isRequired: true, searchable: true }, { name: "changedBy", title: "Changed By", description: "Changed By", type: "string", isRequired: true, searchable: true }, { name: "changeType", title: "Change Type", description: "Change Type", type: "string", isRequired: true, searchable: true }, { name: "changeDetails", title: "Change Details", description: "Change Details", type: "json", isRequired: false, searchable: false } ] }, { name: "ee-base-user", title: "\u7528\u6237\u6A21\u578B", description: "Entity User Model", fields: [ { name: "userName", title: "\u7528\u6237\u540D\u79F0", description: "\u7528\u6237\u540D\u79F0", type: "string", isRequired: true, searchable: true }, { name: "email", title: "\u90AE\u7BB1", description: "\u90AE\u7BB1\u5730\u5740", type: "string", isRequired: true, searchable: true }, { name: "password", title: "\u767B\u5F55\u5BC6\u7801", description: "\u767B\u5F55\u5BC6\u7801", type: "string", isRequired: true }, { name: "avatar", title: "\u5934\u50CF", description: "\u5934\u50CF", type: "binary", isRequired: false, searchable: false } ] } ]; var views = [ { name: "entity-change-log-grid-view", title: "\u5B9E\u4F53\u53D8\u66F4\u7F51\u683C\u89C6\u56FE", description: "Entity Change Log Grid View", modelName: "entity-change-log", viewType: "grid", items: [ { name: "modelName", title: "Model Name", spanCols: 12 }, { name: "objectId", title: "Object ID", spanCols: 12 }, { name: "changedBy", title: "Changed By", spanCols: 12 }, { name: "changeType", title: "Change Type", spanCols: 12 }, { name: "changeDetails", title: "Change Details", spanCols: 12 } ] }, { name: "ee-base-user-grid-view", title: "\u7528\u6237\u7F51\u683C\u89C6\u56FE", description: "\u7528\u6237\u7F51\u683C\u89C6\u56FE", modelName: "ee-base-user", viewType: "grid", items: [ { name: "userName", title: "\u7528\u6237\u540D\u79F0", spanCols: 12 }, { name: "email", title: "\u767B\u5F55\u90AE\u7BB1", spanCols: 12 }, { name: "avatar", title: "\u5934\u50CF", widget: "image", spanCols: 12 } ] }, { name: "ee-base-user-form-view", title: "\u7528\u6237\u7F51\u683C\u89C6\u56FE", description: "\u7528\u6237\u7F51\u683C\u89C6\u56FE", modelName: "ee-base-user", viewType: "form", items: [ { name: "userName", title: "\u7528\u6237\u540D\u79F0", spanCols: 12 }, { name: "email", title: "\u767B\u5F55\u90AE\u7BB1", spanCols: 12 }, { name: "password", title: "\u767B\u5F55\u5BC6\u7801", widget: "password", spanCols: 12 }, { name: "avatar", title: "\u5934\u50CF", widget: "image", spanCols: 12 } ] } ]; // src/modules/build-in/buildin.module.ts var servletHandler = { path: "/ttt", methods: ["GET", "POST"], async handle(req, res) { console.log("BuildinModule: handleRequest called"); res.write(new Response(`Hello from BuildinModule servlet! ${req.endpoint}`)); } }; var BuildinModule = class { constructor() { this.info = module_default; } async setupConfig(args) { console.log("BuildinModule: loadConfig called"); args.models.push(...models); args.views.push(...views); args.servlets.push(servletHandler); } async setupComponents(args) { const authView = await Promise.resolve().then(() => _interopRequireWildcard(require("./auth.view-XE4MBUE7.js"))); args.views.push(new authView.default()); const mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./shell-settings-target-renderer-7N2CQ3VK.js"))); args.renderers.push(mod.default); const menu = await Promise.resolve().then(() => _interopRequireWildcard(require("./shell-settings-menu-renderer-J6GZ7KUA.js"))); args.renderers.push(menu.default); console.log("BuildinModule: loadComponents called"); } async setupData(args) { const demoUser = { id: "3706a32d89d04423bc84cc1f9366881d", modelName: "ee-base-user", values: { userName: "Demo User", email: "demo@demo.com", password: "fe01ce2a7fbac8fafaed7c982a04e229", role: [] } }; args.entities.push(demoUser); } }; // src/core/types/session.types.ts var EntitySession = class { constructor(sessionId, userInfo, update = () => { }) { this.sessionId = sessionId; this.userInfo = userInfo; this.update = update; } isAuthenticated() { return !!this.userInfo; } }; // src/core/delegate/delegate.ts var _zod = require('zod'); var EntityFieldDelegate = class { constructor(field) { this._field = field; } get name() { return this._field.name; } get title() { return this._field.title; } get type() { return this._field.type; } get typeOptions() { return this._field.typeOptions; } get description() { return this._field.description; } get defaultValue() { return this._field.defaultValue; } get isRequired() { return _nullishCoalesce(this._field.isRequired, () => ( false)); } get isPrimaryKey() { return _nullishCoalesce(this._field.isPrimaryKey, () => ( false)); } get isUnique() { return _nullishCoalesce(this._field.isUnique, () => ( false)); } get editable() { return _nullishCoalesce(this._field.editable, () => ( true)); } get searchable() { return _nullishCoalesce(this._field.searchable, () => ( false)); } get refModel() { return this._field.refModel; } get refField() { return this._field.refField; } get schema() { return this._field.schema; } get order() { return this._field.order; } }; var EntityModelDelegate = class { constructor(model, typeRegistry) { this._model = model; this._typeRegistry = typeRegistry; } get name() { return this._model.name; } get title() { return this._model.title; } get description() { return this._model.description; } get external() { return this._model.external; } get externalConfig() { return this._model.externalConfig; } isSupportFeature(feature) { if (!this._model.external) return true; const fs = _optionalChain([this, 'access', _2 => _2._model, 'access', _3 => _3.externalConfig, 'optionalAccess', _4 => _4.features]) || []; console.log("@@@@@@@@@@@@@@ Supported features:", this._model.name, fs); return fs.includes(feature); } findPrimaryKeyFields() { return this._model.fields.filter((field) => field.isPrimaryKey); } findUniqueFields() { return this._model.fields.filter((field) => field.isUnique); } findFieldByName(name) { return this._model.fields.find((field) => field.name === name); } findFieldByTitle(title) { return this._model.fields.find((field) => field.title === title); } findSearchableFields() { return this._model.fields.filter((field) => field.searchable); } get schema() { return _zod.z.object({ ...this._model.fields.reduce((acc, field) => { const fschema = this.getFieldSchema(field); if (fschema) { acc[field.name] = fschema; } return acc; }, {}) }); } getFieldSchema(field) { if (field.schema) { return field.schema; } const typer = this._typeRegistry.getFieldTyper(field.type); if (typer) { return typer.getDefaultSchema(field); } return void 0; } toSupplementedValues(input) { const obj = { ...input, ...this._model.fields.reduce((acc, field) => { if (!input[field.name]) { acc[field.name] = input[field.name] || this.getFieldDefaultValue(field); return acc; } else { return acc; } }, {}) }; return obj; } getFieldDefaultValue(field) { if (field.defaultValue !== void 0) { return field.defaultValue; } const typer = this._typeRegistry.getFieldTyper(field.type); if (typer) { return typer.getDefaultValue(field); } return void 0; } getQueryMeta() { const itemMetas = []; const searchableFields = this.fields.filter((f) => f.searchable); searchableFields.forEach((field) => { const meta = this.getFieldQueryItemMeta(field); if (meta) { itemMetas.push(meta); } }); return { queryItemMetas: itemMetas }; } getFieldQueryItemMeta(field) { if (!field.searchable) return void 0; const operators = []; const options = []; const normalizeOptionItem = (item) => { if (item == null) return void 0; if (typeof item === "object") { const value = "value" in item ? item.value : item; const label = "label" in item ? item.label : String(value); return { label, value }; } return { label: String(item), value: item }; }; if (field.type === "string") { operators.push( "eq" /* EQ */, "contains" /* CONTAINS */, "startsWith" /* STARTS_WITH */, "endsWith" /* ENDS_WITH */, "isNotNull" /* IS_NOT_NULL */, "isNull" /* IS_NULL */ ); } if (field.type === "number") { operators.push( "eq" /* EQ */, "gt" /* GT */, "lt" /* LT */, "isNotNull" /* IS_NOT_NULL */, "isNull" /* IS_NULL */ ); } if (field.type === "boolean") { operators.push("eq" /* EQ */, "isNotNull" /* IS_NOT_NULL */, "isNull" /* IS_NULL */); options.push({ label: "\u662F", value: true }); options.push({ label: "\u5426", value: false }); } if (field.type === "date") { operators.push( "eq" /* EQ */, "gt" /* GT */, "lt" /* LT */, "between" /* BETWEEN */, "isNotNull" /* IS_NOT_NULL */, "isNull" /* IS_NULL */ ); } if (field.type === "enum") { operators.push( "eq" /* EQ */, "ne" /* NE */, "isNotNull" /* IS_NOT_NULL */, "isNull" /* IS_NULL */ ); const raw = _optionalChain([field, 'access', _5 => _5.typeOptions, 'optionalAccess', _6 => _6.options]); if (Array.isArray(raw)) { for (const r of raw) { const norm = normalizeOptionItem(r); if (norm) options.push(norm); } } else { const norm = normalizeOptionItem(raw); if (norm) options.push(norm); } } if (field.type === "array") { operators.push( "in" /* IN */, "notIn" /* NOT_IN */, "isNotNull" /* IS_NOT_NULL */, "isNull" /* IS_NULL */ ); const raw = _optionalChain([field, 'access', _7 => _7.typeOptions, 'optionalAccess', _8 => _8.options]); if (Array.isArray(raw)) { for (const r of raw) { const norm = normalizeOptionItem(r); if (norm) options.push(norm); } } } if (operators.length > 0) { return { field, operators, options }; } return void 0; } get fields() { return this._model.fields.map((field) => new EntityFieldDelegate(field)); } }; var EntityViewFieldDelegate = class _EntityViewFieldDelegate { constructor(field) { this._field = field; } get name() { return this._field.name; } get title() { return this._field.title; } get description() { return this._field.description; } get icon() { return this._field.icon; } get widget() { return this._field.widget; } get widgetOptions() { return this._field.widgetOptions; } get width() { return this._field.width; } get flex() { return this._field.flex; } get spanCols() { return this._field.spanCols; } get order() { return this._field.order; } get fields() { return _optionalChain([this, 'access', _9 => _9._field, 'access', _10 => _10.fields, 'optionalAccess', _11 => _11.map, 'call', _12 => _12((field) => new _EntityViewFieldDelegate(field))]); } get hiddenWhen() { return this._field.hiddenWhen; } get showWhen() { return this._field.showWhen; } get readOnlyWhen() { return this._field.readOnlyWhen; } get disabledWhen() { return this._field.disabledWhen; } get requiredWhen() { return this._field.requiredWhen; } }; var EntityViewDelegate = class _EntityViewDelegate { constructor(view, metaRegistry, typeRegistry) { this._view = view; this._metaRegistry = metaRegistry; this._typeRegistry = typeRegistry; } get name() { return this._view.name; } get title() { return this._view.title; } get description() { return this._view.description; } get modelName() { return this._view.modelName; } get viewType() { return this._view.viewType; } get density() { return this._view.density; } get viewOptions() { return this._view.viewOptions; } get items() { return this._view.items.map((item) => new EntityViewFieldDelegate(item)); } get hilites() { return this._view.hilites; } get canEdit() { return this._view.canEdit; } get canNew() { return this._view.canNew; } get canDelete() { return this._view.canDelete; } toSupplementedView(viewOptions) { const view = { ...this._view, ...viewOptions && Object.keys(viewOptions).length > 0 ? { viewOptions } : {}, density: this._view.density || "medium", items: this._view.items.map((field) => this.supplementField(field)) }; return new _EntityViewDelegate(view, this._metaRegistry, this._typeRegistry); } supplementField(item) { if ("fields" in item) { const panel = item; return { ...panel, fields: panel.fields.map((field) => this.supplementField(field)) }; } else { const field = item; const modelField = _optionalChain([this, 'access', _13 => _13._metaRegistry, 'access', _14 => _14.getModel, 'call', _15 => _15(this._view.modelName), 'optionalAccess', _16 => _16.findFieldByName, 'call', _17 => _17(field.name)]); if (!modelField) { return field; } else { return { ...field, title: field.title || modelField.title, description: field.description || modelField.description, order: field.order || modelField.order || 0, flex: field.flex || 0, widget: this.getFieldWidget(field, modelField) }; } } } getFieldWidget(field, modelField) { if (field.widget) { return field.widget; } if (!modelField) { return "none"; } const typer = this._typeRegistry.getFieldTyper(modelField.type); if (typer) { return typer.getDefaultWidgetType(this._view.viewType); } switch (modelField.type) { case "string": return "textfield"; case "number": return "number"; case "boolean": return "switch"; case "date": return "date"; case "enum": case "array": return "select"; case "one_to_many": return "reference"; case "many_to_many": return "reference"; case "many_to_one": case "one_to_one": return "select"; default: return "none"; } } }; // src/core/delegate/meta.serializer.ts var _zodtojsonschema = require('zod-to-json-schema'); var _zodfromjsonschema = require('zod-from-json-schema'); function serializeFieldSchema(schema) { if (schema) { try { return _zodtojsonschema.zodToJsonSchema.call(void 0, schema); } catch (e) { console.error("Failed to serialize Zod schema to JSON schema:", e); } } return void 0; } function deserializeFieldSchema(_data) { if (_data) { try { return _zodfromjsonschema.convertJsonSchemaToZod.call(void 0, _data); } catch (e) { console.error("Failed to deserialize Zod schema from JSON schema:", e); } } return void 0; } function serializeEntityModel(model) { const safe = { name: model.name, title: model.title, description: model.description, external: model.external, externalConfig: { features: _optionalChain([model, 'access', _18 => _18.externalConfig, 'optionalAccess', _19 => _19.features]) || [] }, fields: model.fields.map((field) => ({ name: field.name, title: field.title, type: field.type, typeOptions: field.typeOptions, description: field.description, defaultValue: field.defaultValue, isRequired: field.isRequired, isPrimaryKey: field.isPrimaryKey, isUnique: field.isUnique, editable: field.editable, searchable: field.searchable, refModel: field.refModel, refField: field.refField, order: field.order, // 添加 schemaSerialized 字段,保留原字段 schema 以便未来恢复 schemaSerialized: serializeFieldSchema(field.schema) })) }; return safe; } function deserializeEntityModel(json) { if (!json) return void 0; try { const obj = JSON.parse(json); if (!obj || typeof obj !== "object") return void 0; if (typeof obj.name !== "string" || typeof obj.title !== "string") return void 0; if (!Array.isArray(obj.fields)) return void 0; const fields = obj.fields.filter((f) => f && typeof f === "object").map((f) => { const { name, title, type, typeOptions, description, defaultValue, isRequired, isPrimaryKey, isUnique, editable, searchable, refModel, refField, order, schemaSerialized } = f; if (typeof name !== "string" || typeof title !== "string" || typeof type !== "string") { return void 0; } return { name, title, type, typeOptions, description, defaultValue, isRequired, isPrimaryKey, isUnique, editable, searchable, refModel, refField, order, schema: deserializeFieldSchema(schemaSerialized) }; }).filter(Boolean); const model = { name: obj.name, title: obj.title, external: obj.external, externalConfig: obj.externalConfig, description: typeof obj.description === "string" ? obj.description : void 0, fields }; return model; } catch (e2) { return void 0; } } function serializeEntityView(view) { if (!view) return void 0; const VERSION = 1; const cloneField = (field) => { if (!field || typeof field !== "object") return void 0; const { name: name2, title: title2, description: description2, icon, widget, widgetOptions, width, flex, spanCols, order, fields, hiddenWhen, showWhen, readOnlyWhen, disabledWhen, requiredWhen, referenceView, referenceComp } = field; if (typeof name2 !== "string") return void 0; const safe2 = { name: name2, title: title2, description: description2, icon, widget, widgetOptions: widgetOptions ? JSON.parse(JSON.stringify(widgetOptions)) : void 0, width, flex, spanCols, order, hiddenWhen, showWhen, readOnlyWhen, disabledWhen, requiredWhen, referenceView, referenceComp }; if (Array.isArray(fields)) { const child = fields.map((f) => cloneField(f)).filter(Boolean); if (child.length > 0) safe2.fields = child; } return safe2; }; const { name, title, description, modelName, viewType, viewOptions, items, hilites, canEdit, canNew, canDelete, density } = view; if (typeof name !== "string" || typeof title !== "string" || typeof modelName !== "string" || typeof viewType !== "string") { throw new Error("Invalid IEntityView: missing required string fields"); } const safeItems = Array.isArray(items) ? items.map((it) => cloneField(it)).filter(Boolean) : []; const safe = { __viewSerializerVersion: VERSION, name, title, description, modelName, viewType, viewOptions: viewOptions ? JSON.parse(JSON.stringify(viewOptions)) : void 0, items: safeItems, hilites: Array.isArray(hilites) ? hilites.filter((h) => h && typeof h === "object" && typeof h.when === "string").map((h) => ({ when: h.when, color: h.color })) : void 0, canEdit, canNew, canDelete, density }; return safe; } function deserializeEntityView(json) { if (!json) return void 0; try { const obj = JSON.parse(json); if (!obj || typeof obj !== "object") return void 0; const { name, title, description, modelName, viewType, viewOptions, items, hilites, canEdit, canNew, canDelete, density } = obj; if (typeof name !== "string" || typeof title !== "string" || typeof modelName !== "string" || typeof viewType !== "string") { return void 0; } const reviveField = (field) => { if (!field || typeof field !== "object") return void 0; if (typeof field.name !== "string") return void 0; const f = { name: field.name, title: typeof field.title === "string" ? field.title : void 0, description: typeof field.description === "string" ? field.description : void 0, icon: typeof field.icon === "string" ? field.icon : void 0, widget: typeof field.widget === "string" ? field.widget : void 0, widgetOptions: field.widgetOptions && typeof field.widgetOptions === "object" ? field.widgetOptions : void 0, width: typeof field.width === "number" ? field.width : void 0, flex: field.flex === 0 || field.flex === 1 ? field.flex : void 0, spanCols: typeof field.spanCols === "number" ? field.spanCols : void 0, order: typeof field.order === "number" ? field.order : void 0, hiddenWhen: typeof field.hiddenWhen === "string" ? field.hiddenWhen : void 0, showWhen: typeof field.showWhen === "string" ? field.showWhen : void 0, readOnlyWhen: typeof field.readOnlyWhen === "string" ? field.readOnlyWhen : void 0, disabledWhen: typeof field.disabledWhen === "string" ? field.disabledWhen : void 0, requiredWhen: typeof field.requiredWhen === "string" ? field.requiredWhen : void 0, referenceView: field.referenceView && typeof field.referenceView === "object" ? field.referenceView : void 0, referenceComp: field.referenceComp && typeof field.referenceComp === "object" ? field.referenceComp : void 0 }; if (Array.isArray(field.fields)) { const child = field.fields.map((c) => reviveField(c)).filter(Boolean); if (child.length > 0) f.fields = child; } return f; }; const safeItems = Array.isArray(items) ? items.map((it) => reviveField(it)).filter(Boolean) : []; const safe = { name, title, description: typeof description === "string" ? description : void 0, modelName, viewType, viewOptions: viewOptions && typeof viewOptions === "object" ? viewOptions : void 0, items: safeItems, hilites: Array.isArray(hilites) ? hilites.filter((h) => h && typeof h.when === "string").map((h) => ({ when: h.when, color: h.color })) : void 0, canEdit: typeof canEdit === "boolean" ? canEdit : void 0, canNew: typeof canNew === "boolean" ? canNew : void 0, canDelete: typeof canDelete === "boolean" ? canDelete : void 0, density: density === "small" || density === "medium" || density === "large" ? density : void 0 }; return safe; } catch (e3) { return void 0; } } // src/core/delegate/delegate.registry.ts var EntityMetaRegistry = class { constructor(typeRegistry, eventEmitter) { this._models = /* @__PURE__ */ new Map(); this._views = /* @__PURE__ */ new Map(); this._typeRegistry = typeRegistry; this._eventEmitter = eventEmitter; } getModel(name) { return this._models.get(name); } get models() { return Array.from(this._models.values()); } get views() { return Array.from(this._views.values()); } getView(name) { return this._views.get(name); } cleanup() { this._models.clear(); this._views.clear(); } findView(modelName, viewType, name) { let _view = void 0; if (name) { _view = this._views.get(name); } if (!_view) { const values = Array.from(this._views.values()); _view = values.find( (view) => view.modelName === modelName && view.viewType === viewType ); } if (!_view) { const m = this.getModel(modelName); if (m) { const _viewData = { name: `${modelName}-${viewType}`, title: `${m.title}`, description: `${m.description}`, modelName: m.name, viewType, density: "medium", items: m.fields.map((field) => ({ name: field.name, title: field.title, description: field.description, order: field.order || 0, flex: 0 })) }; _view = new EntityViewDelegate(_viewData, this, this._typeRegistry); } } return _view; } registerModel(model) { if (!model) { throw new Error("Model cannot be undefined or null"); } if (!model.name) { throw new Error("Model must have a name"); } this._models.set(model.name, new EntityModelDelegate(model, this._typeRegistry)); } registerView(view) { if (!view) { throw new Error("View cannot be undefined or null"); } if (!view.modelName || !view.name || !view.viewType) { throw new Error("View must have modelName, name, and viewType defined"); } this._views.set(view.name, new EntityViewDelegate(view, this, this._typeRegistry)); } toPlainModelObject(model) { return serializeEntityModel(model); } toPlainViewObject(view) { return serializeEntityView(view.toSupplementedView()); } updateOrRegisterByPlainObject(config) { let ref = 0; if (Array.isArray(config.models)) { config.models.forEach((m) => { const model = deserializeEntityModel(JSON.stringify(m)); if (model) { if (this.getModel(model.name)) { this._models.delete(model.name); } this.registerModel(model); ref++; } }); } if (Array.isArray(config.views)) { config.views.forEach((v) => { const view = deserializeEntityView(JSON.stringify(v)); console.log(`Deserialized view:`, view); if (view) { if (this.getView(view.name)) { this._views.delete(view.name); } this.registerView(view); ref++; } }); } if (ref > 0) { this._eventEmitter.emit({ name: "config.updated", parameter: { modelIds: _optionalChain([config, 'access', _20 => _20.models, 'optionalAccess', _21 => _21.map, 'call', _22 => _22((m) => m.name)]) || [], viewIds: _optionalChain([config, 'access', _23 => _23.views, 'optionalAccess', _24 => _24.map, 'call', _25 => _25((v) => v.name)]) || [] } }); } } toJSONString() { const models2 = this.models.map((model) => serializeEntityModel(model)); const views2 = this.views.map((view) => serializeEntityView(view)); return JSON.stringify({ models: models2, views: views2 }); } fromJSONString(json) { if (!json) return; try { const obj = JSON.parse(json); if (!obj || typeof obj !== "object") return; const { models: models2, views: views2 } = obj; this.cleanup(); if (Array.isArray(models2)) { models2.forEach((m, idx) => { try { const model = deserializeEntityModel(JSON.stringify(m)); if (model) { this.registerModel(model); } } catch (e) { console.warn("[EntityMetaRegistry] Failed to load model index", idx, e); } }); } if (Array.isArray(views2)) { views2.forEach((v, idx) => { try { const view = deserializeEntityView(JSON.stringify(v)); if (view) { if (view.modelName === "__default__" || this.getModel(view.modelName)) { this.registerView(view); } else { console.warn( `[EntityMetaRegistry] Skip view '${view.name}' because model '${view.modelName}' not found.` ); } } } catch (e) { console.warn("[EntityMetaRegistry] Failed to load view index", idx, e); } }); } } catch (e) { console.error("[EntityMetaRegistry] fromJSONString parse error:", e); } } }; // src/services/api/trpc/vanilla-client.ts var _superjson = require('superjson'); var _superjson2 = _interopRequireDefault(_superjson); var _client = require('@trpc/client'); function createVanillaTrpcClient(url) { return _client.createTRPCClient.call(void 0, { links: [ _client.httpBatchLink.call(void 0, { url, transformer: _superjson2.default, maxURLLength: 2048 // Set a safe max URL length }) ] }); } // src/lib/data/data-utils.ts function convertRawEntityObject(eo) { if (eo) { const values = (() => { if (!eo.values || typeof eo.values !== "object") { return {}; } if (Array.isArray(eo.values)) { return {}; } return eo.values; })(); return { id: eo.id, modelName: eo.modelName, isDeleted: eo.isDeleted, createdAt: eo.createdAt, updatedAt: eo.updatedAt, values // ...(typeof eo.valuesJson === 'object' && eo.valuesJson !== null ? eo.valuesJson : {}) }; } return null; } function convertEntityTree(treeNode) { if (!treeNode) return null; return { children: treeNode.children.map((item) => convertEntityTree(item)).filter((item) => item != null), data: convertRawEntityObject(treeNode.data), parentId: treeNode.parentId }; } // src/core/datasources/trpc.datasource.ts var TRPCEntityObjectDataSource = class { constructor(settings) { this._serverUrl = "__"; this._settings = settings; } get __vanillaTrpcClient() { const serverUrl = this._settings.getUrl("/trpc"); if (!this._vanillaTrpcClient || this._serverUrl !== serverUrl) { console.log("Creating new TRPC client with URL:", serverUrl); this._serverUrl = serverUrl; this._vanillaTrpcClient = createVanillaTrpcClient(serverUrl); } return this._vanillaTrpcClient; } async findPlainConfig(input) { return await this.__vanillaTrpcClient.model.findPlainConfig.query(input); } async findGroupedObjects(input) { const result = await this.__vanillaTrpcClient.model.findGroupedObjects.query({ modelName: input.modelName, groupBy: input.groupBy, query: input.query, reference: input.reference, aggregations: input.aggregations, groupSortBy: input.groupSortBy, objectSortBy: input.objectSortBy }); return { groups: result.groups.map((group) => ({ key: group.key, count: group.count, objects: group.objects.map((obj) => convertRawEntityObject(obj)).filter((obj) => obj !== null && obj !== void 0), aggregations: group.aggregations })), totalCount: result.totalCount }; } async findOne(input) { const ret = await this.__vanillaTrpcClient.model.findObject.query({ id: input.id, modelName: input.modelName }); return Promise.resolve(convertRawEntityObject(ret)); } async findMany(input) { const query = input.query || {}; const ret = await this.__vanillaTrpcClient.model.listObjects.query({ modelName: input.modelName, pagination: { page: _nullishCoalesce(_optionalChain([query, 'optionalAccess', _26 => _26.pageIndex]), () => ( 1)), pageSize: _nullishCoalesce(_optionalChain([query, 'optionalAccess', _27 => _27.pageSize]), () => ( 10)) }, reference: _optionalChain([query, 'optionalAccess', _28 => _28.references]), filter: _optionalChain([query, 'optionalAccess', _29 => _29.filter]), withAllReferences: input.withAllReferences }); return Promise.resolve({ data: ret.data.map((obj) => convertRawEntityObject(obj)).filter((obj) => obj !== null && obj !== void 0), count: ret.count }); } async findTreeObjects(input) { const ret = await this.__vanillaTrpcClient.model.treeObjects.query(input); if (Array.isArray(ret)) { const nodes = []; ret.forEach((node, index) => { const cnode = convertEntityTree(node); if (cnode) { nodes.push(cnode); } }); return Promise.resolve(nodes); } else { return Promise.resolve(convertEntityTree(ret)); } } async findOneWithReferences(input) { const ret = await this.__vanillaTrpcClient.model.findOneWithReferences.query({ objectId: input.id, includeFieldNames: input.includeFieldNames }); return Promise.resolve(convertRawEntityObject(ret)); } async create(input) { const values = _nullishCoalesce(input.data.values, () => ( {})); const ret = await this.__vanillaTrpcClient.model.createObject.mutate({ id: input.data.id, modelName: input.modelName, values, reference: input.reference }); return Promise.resolve(convertRawEntityObject(ret)); } async update(input) { if (!input.data.values) { throw new Error("\u66F4\u65B0\u5BF9\u8C61\u65F6 values \u4E0D\u80FD\u4E3A\u7A7A"); } const ret = await this.__vanillaTrpcClient.model.updateObject.mutate({ id: input.id, values: input.data.values }); return Promise.resolve(ret ? true : false); } async updateValues(input) { if (!input.values) { throw new Error("\u66F4\u65B0\u5BF9\u8C61\u65F6 values \u4E0D\u80FD\u4E3A\u7A7A"); } const ret = await this.__vanillaTrpcClient.model.updateValues.mutate({ id: input.id, values: input.values }); if (ret) { return true; } return false; } async delete(input) { const ret = await this.__vanillaTrpcClient.model.deleteObject.mutate({ id: input.id }); return Promise.resolve(ret ? true : false); } async deleteMany(input) { const ret = await this.__vanillaTrpcClient.model.deleteObjects.mutate({ ids: input.ids }); return Promise.resolve(ret ? true : false); } async findCount(input) { const ret = await this.__vanillaTrpcClient.model.countObjects.query({ modelName: input.modelName }); return Promise.resolve(ret); } async findManyWithReferences(input) { const ret = await this.__vanillaTrpcClient.model.listWithChildren.query({ modelName: input.modelName, childFieldName: input.childrenFieldName, pagination: { page: _nullishCoalesce(_optionalChain([input, 'access', _30 => _30.query, 'optionalAccess', _31 => _31.pageIndex]), () => ( 1)), pageSize: _nullishCoalesce(_optionalChain([input, 'access', _32 => _32.query, 'optionalAccess', _33 => _33.pageSize]), () => ( 10)) }, filter: _optionalChain([input, 'access', _34 => _34.query, 'optionalAccess', _35 => _35.filter]) }); return Promise.resolve({ data: ret.data.map(convertRawEntityObject).filter((obj) => obj !== null && obj !== void 0), count: ret.count }); } async findReferences(input) { const ret = await this.__vanillaTrpcClient.model.findObjectReferencesOM.query(input); return Promise.resolve(ret); } async validate(input) { return Promise.resolve(true); } async findReferencesCount(input) { const ret = await this.__vanillaTrpcClient.model.findObjectReferencesCountOM.query(input); return Promise.resolve(ret); } async createReference(input) { const ret = await this.__vanillaTrpcClient.model.createObjectReference.mutate(input); return Promise.resolve(ret); } async createReferences(input) { const ret = await this.__vanillaTrpcClient.model.createObjectReferences.mutate(input); return Promise.resolve(ret); } async deleteReference(input) { const ret = await this.__vanillaTrpcClient.model.deleteObjectReference.mutate(input); return Promise.resolve(ret); } async deleteReferences(input) { const ret = await this.__vanillaTrpcClient.model.deleteObjectReferences.mutate(input); return Promise.resolve(ret); } }; // src/core/datasources/datasource.factory.ts var EntityDataSourceFactory = class { constructor(settings) { this._dataSource = null; this._settings = settings; } getDataSource() { if (!this._dataSource) { this._dataSource = new TRPCEntityObjectDataSource(this._settings); } return this._dataSource; } }; // src/services/api/services/model.service.ts var _client3 = require('@prisma/client'); var _cuid2 = require('@paralleldrive/cuid2'); // src/services/api/routers/utils/enhanced-query.ts function buildForestFromFlatNodes(flatNodes) { const nodeMap = /* @__PURE__ */ new Map(); const forest = []; flatNodes.forEach((node) => { const { parentId, ...data } = node; nodeMap.set(node.id, { data, parentId, children: [] }); }); nodeMap.forEach((node) => { if (node.parentId) { const parent = nodeMap.get(node.parentId); if (parent) { parent.children.push(node); } } else { forest.push(node); } }); return forest; } async function getFullTree(prisma, fromModelName, fromFieldName, rootId) { if (rootId) { const flatNodesForSubtree = await prisma.$queryRaw` WITH RECURSIVE SubTreeEdges AS ( -- 起始部分:从指定的 rootId 开始查找其直接子节点 SELECT "toObjectId", "fromObjectId" FROM "EntityObjectReference" WHERE "fromObjectId" = ${rootId} AND "fromModelName" = ${fromModelName} AND "fromFieldName" = ${fromFieldName} UNION ALL -- 递归部分:继续查找子孙节点 SELECT eor."toObjectId", eor."fromObjectId" FROM "EntityObjectReference" eor JOIN SubTreeEdges ste ON eor."fromObjectId" = ste."toObjectId" WHERE eor."fromModelName" = ${fromModelName} AND eor."fromFieldName" = ${fromFieldName} ), NodesInSubTree AS ( -- 将根节点自己和所有子孙节点的ID合并 SELECT ${rootId} AS id UNION ALL SELECT "toObjectId" FROM SubTreeEdges ) -- 查询这些节点的信息及其父节点ID SELECT eo.*, ste."fromObjectId" as "parentId" FROM NodesInSubTree nist JOIN "EntityObject" eo ON nist.id = eo.id LEFT JOIN SubTreeEdges ste ON nist.id = ste."toObjectId"; `; const forest = buildForestFromFlatNodes(flatNodesForSubtree); return forest.length > 0 ? forest[0] : null; } else { const flatNodesForForest = await prisma.$queryRaw` WITH RECURSIVE DescendantEdges AS ( SELECT "toObjectId", "fromObjectId" FROM "EntityObjectReference" WHERE "fromModelName" = ${fromModelName} AND "fromFieldName" = ${fromFieldName} UNION ALL SELECT eor."toObjectId", eor."fromObjectId" FROM "EntityObjectReference" eor JOIN DescendantEdges de ON eor."fromObjectId" = de."toObjectId" WHERE eor."fromModelName" = ${fromModelName} AND eor."fromFieldName" = ${fromFieldName} ), NodesInConnectedTrees AS ( SELECT "toObjectId" AS id FROM DescendantEdges UNION SELECT "fromObjectId" AS id FROM DescendantEdges ) SELECT eo.*, de."fromObjectId" AS "parentId" FROM NodesInConnectedTrees nict JOIN "EntityObject" eo ON nict.id = eo.id LEFT JOIN (SELECT DISTINCT "toObjectId", "fromObjectId" FROM DescendantEdges) AS de ON nict.id = de."toObjectId" UNION ALL SELECT eo.*, NULL AS "parentId" FROM "EntityObject" eo WHERE eo."modelName" = ${fromModelName} AND NOT EXISTS ( SELECT 1 FROM "EntityObjectReference" eor WHERE eor."toObjectId" = eo.id AND eor."fromModelName" = ${fromModelName} AND eor."fromFieldName" = ${fromFieldName} ) AND NOT EXISTS ( SELECT 1 FROM "EntityObjectReference" eor WHERE eor."fromObjectId" = eo.id AND eor."fromModelName" = ${fromModelName} AND eor."fromFieldName" = ${fromFieldName} ); `; return buildForestFromFlatNodes(flatNodesForForest); } } function buildHierarchyInValues(flatList) { if (!flatList || !Array.isArray(flatList) || flatList.length === 0) { console.error( "[buildHierarchyInValues] Error: Input 'flatList' is empty or invalid. Returning null." ); return null; } const nodeMap = /* @__PURE__ */ new Map(); let root = null; flatList.forEach((item) => { if (!item || typeof item.id === "undefined") { console.warn( "[buildHierarchyInValues] Warning: Skipping invalid item in flatList:", item ); return; } const initialValues = typeof item.values === "object" && item.values !== null ? item.values : {}; const node = { id: item.id, modelName: item.modelName, values: initialValues, isDeleted: item.isDeleted }; nodeMap.set(node.id, node); }); flatList.forEach((item) => { if (!item || typeof item.toid === "undefined") return; const parentId = item.fromid; const childId = item.toid; const relationField = item.viafield; if (!parentId || parentId === null) { if (root === null) { root = nodeMap.get(childId); console.warn( `[buildHierarchyInValues] Warning: root node found. Using '${childId}' as the root.` ); } else { console.warn( `[buildHierarchyInValues] Warning: Multiple root nodes found. Using '${root.id}' as the root. Another root found: '${childId}'.` ); } return; } if (relationField && nodeMap.has(parentId) && nodeMap.has(childId)) { const parentNode = nodeMap.get(parentId); const childNode = nodeMap.get(childId); if (!parentNode.values[relationField]) { parentNode.values[relationField] = []; } if (Array.isArray(parentNode.values[relationField])) { parentNode.values[relationField].push(childNode); } else { parentNode.values[relationField] = childNode; } } else if (relationField) { console.warn( `[buildHierarchyInValues] Warning: Could not form relationship for item. Missing parent or child in nodeMap.`, item ); } }); if (root === null) { console.error( "[buildHierarchyInValues] Error: Failed to determine a root node from the provided data. Make sure at least one item has a null 'fromId'." ); } return root; } async function getDeepEntityFirstLevelFilter(prisma, startId, fieldNamesToInclude) { let filterClause = _client3.Prisma.empty; if (fieldNamesToInclude && fieldNamesToInclude.length > 0) { filterClause = _client3.Prisma.sql` AND ( eg.depth > 0 -- 如果深度大于0 (即非第一层),则条件为真,允许通行 OR ref."fromFieldName" IN (${_client3.Prisma.join(fieldNamesToInclude)}) -- 否则 (在第一层),检查fieldName ) `; } const flatList = await prisma.$queryRaw( _client3.Prisma.sql` WITH RECURSIVE EntityGraph AS ( SELECT eo.id AS toId, NULL::VARCHAR AS fromId, NULL::VARCHAR AS viaField, 0 AS depth FROM "EntityObject" AS eo WHERE eo.id = ${startId} UNION ALL SELECT ref."toObjectId" AS toId, ref."fromObjectId" AS fromId, ref."fromFieldName" AS viaField, eg.depth + 1 FROM "EntityObjectReference" AS ref JOIN EntityGraph AS eg ON ref."fromObjectId" = eg.toId WHERE eg.depth < 10 ${filterClause} -- <-- 在这里注入新的、深度感知的过滤条件 ) SELECT graph.toId, graph.fromId, graph.viaField, graph.depth, eo.id, eo."modelName", eo.values, eo."isDeleted" FROM EntityGraph AS graph JOIN "EntityObject" AS eo ON graph.toId = eo.id; ` ); if (!Array.isArray(flatList) || flatList.length === 0) { return null; } const root = buildHierarchyInValues(flatList); return root; } // src/services/api/services/mode.external.service.ts var _pg = require('pg'); var _poolMap; var ModelExternalPoolService = class { constructor() { _chunk4XLO6XC7js.__privateAdd.call(void 0, this, _poolMap); _chunk4XLO6XC7js.__privateSet.call(void 0, this, _poolMap, /* @__PURE__ */ new Map()); } async getPool(url) { try { if (!_chunk4XLO6XC7js.__privateGet.call(void 0, this, _poolMap).has(url)) { const pool = new (0, _pg.Pool)({ connectionString: url }); await pool.connect(); _chunk4XLO6XC7js.__privateGet.call(void 0, this, _poolMap).set(url, pool); } return Promise.resolve(_chunk4XLO6XC7js.__privateGet.call(void 0, this, _poolMap).get(url)); } catch (error) { console.error("Error getting database pool:", error); return null; } } }; _poolMap = new WeakMap(); var modelExternalPoolService = new ModelExternalPoolService(); async function externalfindObjectLogic(engine, input) { const model = engine.metaRegistry.getModel(input.modelName); if (!model) { throw new Error(`Model not found: ${input.modelName}`); } const externalConfig = model.externalConfig; if (!externalConfig) { throw new Error(`External config not found for model: ${input.modelName}`); } const pool = await modelExternalPoolService.getPool(externalConfig.url); if (!pool) { throw new Error("Failed to acquire external database pool"); } const result = await pool.query( `SELECT * FROM "${externalConfig.tableName}" WHERE "${_optionalChain([externalConfig, 'access', _36 => _36.mappings, 'access', _37 => _37.find, 'call', _38 => _38((m) => m.local === "$$id"), 'optionalAccess', _39 => _39.remote])}" = $1 LIMIT 1`, [input.id] ); if (result && result.rows && result.rows.length > 0) { return convertRowToEntityObject(result.rows[0], model, externalConfig); } return null; } async function externalListObjectsLogic(engine, input) { const { modelName, pagination, reference, filter } = input; if (reference) { throw new Error("External model listing with reference filter is not supported yet."); } const skip = ((_nullishCoalesce(_optionalChain([pagination, 'optionalAccess', _40 => _40.page]), () => ( 1))) - 1) * (_nullishCoalesce(_optionalChain([