nim discord サーバーの非常に親切な人々のヒントのおかげで、解決策を書くことができました。
答えは: Nim のジェネリック、Nim のgetCustomPragmaVal
マクロ、および Norm のtable
テンプレートです。
以下のコードは 2 つのモデル タイプを取ります。sourceType
これは、潜在的にあなたの へのforeignKey-fieldを持つタイプであるため、 をダミーでインスタンス化しますtargetType
。次に、フィールドを反復処理し、sourceType
それらが直接モデル型であるか、fk
別名foreignKeyプラグマで注釈が付けられているか、または型であるかをチェックします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")