From 9af78711146045cc91af42585cf93935ecc57a6f Mon Sep 17 00:00:00 2001 From: xRain Date: Sun, 16 Aug 2026 22:46:48 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20SimApiBaseModel=20=E5=AE=9E=E4=BD=93?= =?UTF-8?q?=E5=9F=BA=E7=B1=BB=EF=BC=88=E5=AF=B9=E9=BD=90=20C#=20Models/Sim?= =?UTF-8?q?ApiBaseModel=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - _id 默认 UUID v4、_createdAt/_updatedAt 自动当前时间 - mapData 反射式字段映射(忽略字段/白名单两种重载) - updateTime 刷新更新时间 --- src/models/SimApiBaseModel.cj | 120 ++++++++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 src/models/SimApiBaseModel.cj diff --git a/src/models/SimApiBaseModel.cj b/src/models/SimApiBaseModel.cj new file mode 100644 index 0000000..bd70942 --- /dev/null +++ b/src/models/SimApiBaseModel.cj @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2025 SimcuTeam. All rights reserved. + * 移植自 C# 项目 SimApi(E:\simcu\simapi-net),遵循 MIT 许可证。 + */ + +package simapi.models + +import std.collection.* +import std.reflect.* +import std.time.* +import simapi.helpers.* + +/** + * 实体基类(对齐 C# Models/SimApiBaseModel)。 + * 提供: + * - Id(默认 Guid)、CreatedAt / UpdatedAt(默认当前时间) + * - MapData:反射式字段映射(源 → 目标,同名 + 同类型;可忽略字段/白名单) + * - UpdateTime:更新 UpdatedAt + */ +public open class SimApiBaseModel { + public var _id: String = SimApiUtil.newGuid() + public var _updatedAt: DateTime = DateTime.now() + public var _createdAt: DateTime = DateTime.now() + + /// MapData 默认忽略的字段(Id / CreatedAt / UpdatedAt) + protected var _mapperIgnoreField: Array = ["_id", "_createdAt", "_updatedAt"] + + /// UpdateTime 更新的字段名 + protected var _updatedTimeField: String = "_updatedAt" + + public init() {} + + /** + * 反射映射:把 source 的同名同类型非忽略字段赋值到 this(对齐 C# MapData(source, mapAll))。 + * @param source 源对象。 + * @param mapAll 为 true 时连忽略字段(Id/CreatedAt/UpdatedAt)也映射。 + */ + public func mapData(source: Any, mapAll!: Bool = false): Unit { + let sourceProps = collectProps(TypeInfo.of(source)) + let targetProps = collectProps(TypeInfo.of(this)) + for (sp in sourceProps) { + if (mapAll || !_mapperIgnoreField.contains(sp.name)) { + copyProp(targetProps, sp, source, this) + } + } + updateTime() + } + + /** + * 反射映射:仅映射白名单字段(对齐 C# MapData(source, mapFields))。 + * @param source 源对象。 + * @param mapFields 白名单字段名。 + */ + public func mapData(source: Any, mapFields: Array): Unit { + let sourceProps = collectProps(TypeInfo.of(source)) + let targetProps = collectProps(TypeInfo.of(this)) + for (sp in sourceProps) { + if (mapFields.contains(sp.name)) { + copyProp(targetProps, sp, source, this) + } + } + updateTime() + } + + /** + * 更新 UpdatedAt 为当前时间(对齐 C# UpdateTime)。 + */ + public func updateTime(): Unit { + let targetProps = collectProps(TypeInfo.of(this)) + for (tp in targetProps) { + if (tp.name == _updatedTimeField) { + tp.setValue(this, DateTime.now()) + return + } + } + } + + // ===== 内部实现 ===== + + /// 把源属性 sp 的值复制到目标对象(要求目标存在同名同类型属性) + private static func copyProp(targetProps: ArrayList, sp: InstancePropertyInfo, + source: Any, target: Any): Unit { + for (tp in targetProps) { + if (tp.name == sp.name && tp.typeInfo == sp.typeInfo) { + tp.setValue(target, sp.getValue(source)) + return + } + } + } + + /// 收集类型(含继承链)的 public 实例属性,子类同名覆盖父类 + private static func collectProps(typeInfo: TypeInfo): ArrayList { + let result = ArrayList() + collectPropsRecursive(typeInfo, result) + result + } + + private static func collectPropsRecursive(typeInfo: TypeInfo, result: ArrayList): Unit { + if (let ct: ClassTypeInfo <- typeInfo) { + if (let Some(superType) <- ct.superClass) { + if (superType != TypeInfo.of()) { + collectPropsRecursive(superType, result) + } + } + for (p in ct.instanceProperties) { + var replaced = false + for ((index, existing) in result |> enumerate) { + if (existing.name == p.name) { + result[index] = p + replaced = true + break + } + } + if (!replaced) { + result.add(p) + } + } + } + } +}