感谢 nim discord 服务器上非常有帮助的人的一些提示,我能够编写解决方案。
答案是:Nim 的泛型、Nim 的getCustomPragmaVal
宏和 Norm 的table
模板。
下面的代码采用 2 种模型类型。它虚拟实例化了,sourceType
因为这是可能对您的targetType
. 然后,它遍历 of 的字段sourceType
并检查它们是否直接是 Model 类型、是否使用fk
又名 foreignKey pragma 进行注释,或者是一种Option[Model]
类型。
如果该字段具有Model
类型,则问题已解决,因为您只需调用即可Model.table()
完成。如果该字段具有fk
编译指示,您可以简单地调用getCustomPragmaVal
以获取该字段作为外键的模型。有了它,你就有了类型,并且可以调用table()
它。最后,你可能有一个Option[Model]
类型。在这种情况下,您需要使用genericParams函数提取泛型参数(参见此处)。这样你就可以再次访问类型并调用table()
它。
proc getRelatedFieldName[M: Model, O:Model](targetType: typedesc[O], sourceType: typedesc[M]): Option[string] =
let source = sourceType()
for sourceFieldName, sourceFieldValue in source[].fieldPairs:
#Handles case where field is an int64 with fk pragma
when sourceFieldValue.hasCustomPragma(fk):
when O.table() == sourceFieldValue.getCustomPragmaVal(fk).table():
return some(sourceFieldName)
#Handles case where field is a Model type
when sourceFieldValue is Model:
when O.table() == sourceFieldValue.type().table():
return some(sourceFieldName)
#Handles case where field is a Option[Model] type
when sourceFieldValue is Option:
when sourceFieldValue.get() is Model:
when O.table() == genericParams(sourceFieldValue.type()).get(0).table():
return some(sourceFieldName)
return none(string)
例子
type
A = ref object of Model # <-- has implicit tableName "A"
name: string
AC {.tableName: "A".} = ref object of Model
myothername: string
name: string
B = ref object of Model # <-- has implicit tableName "B"
name: string
myA: Option[A]
D = ref object of Model
myothernameid: int
myDA: A
E = ref object of Model
myotherbool: bool
myEA {.fk: A.}: int64
echo A.getRelatedFieldName(B) # some("myA")
echo AC.getRelatedFieldName(B) # some("myA")
echo A.getRelatedFieldName(D) # some("myDA")
echo AC.getRelatedFieldName(D) # some("myDA")
echo A.getRelatedFieldName(E) # some("myEA")
echo AC.getRelatedFieldName(E) # some("myEA")