嘿嘿,
我正在使用norm,一個 nim 編程語言中的 orm 。我有 2 種不同的模型,例如:
import std/options
import norm
type
A {.tableName: "Surprise".} = ref object of Model
name: string
Surprise = ref object of Model
name: string
anotherFieldThatExistsOnTheSQLTableButNotOnA: int
B = ref object of Model
name: string
myA: Option[A]
我希望能夠在編譯時找出myA指向給定表(這里Surprise)的給定外鍵欄位(這里)的名稱,即使模型的名稱與實際表不同或者是只讀的模型(例如 A)。這樣我就可以在編譯時撰寫 SQL 查詢,從而獲得許多多對一的關系。
更重要的是,我希望這種外鍵關系的獲取基于tableName模型,而不是模型本身。因此,如果我要定義一個 proc getRelatedFieldName(startType: typedesc[A], otherType: typedesc[B]),它需要為兩個getRelatedFieldName(A, B)AND給出相同的結果getRelatedFieldName(A, Surprise)。
我怎樣才能做到這一點?
uj5u.com熱心網友回復:
感謝 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")
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/410127.html
標籤:
