feat: SimApiBaseModel 实体基类(对齐 C# Models/SimApiBaseModel)
- _id 默认 UUID v4、_createdAt/_updatedAt 自动当前时间 - mapData 反射式字段映射(忽略字段/白名单两种重载) - updateTime 刷新更新时间
This commit is contained in:
@@ -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<String> = ["_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<String>): 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<InstancePropertyInfo>, 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<InstancePropertyInfo> {
|
||||||
|
let result = ArrayList<InstancePropertyInfo>()
|
||||||
|
collectPropsRecursive(typeInfo, result)
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
private static func collectPropsRecursive(typeInfo: TypeInfo, result: ArrayList<InstancePropertyInfo>): Unit {
|
||||||
|
if (let ct: ClassTypeInfo <- typeInfo) {
|
||||||
|
if (let Some(superType) <- ct.superClass) {
|
||||||
|
if (superType != TypeInfo.of<Object>()) {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user