我正在構建一個 Web 應用程式并使用一個名為norm的 ORM 。因此,我有一個帶有一堆表的 SQL 資料庫,所有這些表都對應于我在 nim 中擁有的各種模型。通常,它們處于多對多關系中,例如:
type
A = ref object of Model
name: string
B = ref object of Model
anotherName: string
C = ref object of Model
myA: A
myB: B
由于目前實作規范的方式,如果我想要給定 A 的所有條目 B 或給定 B 的所有條目 A,我必須查詢 C。
當我真正想要 seq[A] 或 seq[B] 時,這給我留下了 seq[C]。
mapIt當然,對于一組特定的 A、B 和 C,我可以使用以下函式迭代 seq sequtils:
import sequtils
let myASeq: seq[A] = myCSeq.mapit(it.myA)
但是考慮到我有大約 20 個這樣的關系,我不想在那里執行 20 次相同的事情。我更喜歡一種通用的方式,我可以myA以某種方式輸入欄位名稱(例如)并即時解決它。我怎樣才能做到這一點?
uj5u.com熱心網友回復:
感謝 nim discord 服務器上非常樂于助人的人(向 ElegantBeef 致敬),他們對我進行了這方面的教育。有兩種方法可以解決這個問題:
1.如果在寫代碼的時候知道欄位名,可以使用模板
這是首選,因為模板比宏更易于理解。import norm/[model, pragmas]
import std/[sequtils, typetraits, macros, json]
template mapModel[T: Model](mySeq: seq[T], field: untyped): seq[untyped] = mySeq.mapIt(it.field)
示例用法:
type
A = ref object of Model
name: string
D = ref object of Model
myothernameid: string
myDA: A
var myDSeq: seq[D] = @[]
let anA: A = A(name: "this is an A")
myDSeq.add(D(myothernameid: "la", myDA: anA))
myDSeq.add(D(myothernameid: "le", myDA: anA))
echo %*myDSeq # [{"myothernameid":"la","myDA":{"name":"this is an A","id":0},"id":0},{"myothernameid":"le","myDA":{"name":"this is an A","id":0},"id":0}]
let myASeq: seq[A] = mapModel(myDSeq, "myDA")
echo %*myASeq # [{"name":"this is an A","id":0},{"name":"this is an A","id":0}]
2.如果編譯時只知道特定欄位的名稱為靜態字串,可以使用宏
如果您只能在編譯時訪問欄位名稱而不是欄位本身,則此選項很有用,因為這可能因when條件而異。
import norm/[model, pragmas]
import std/[sequtils, typetraits, macros, json]
macro mapModel[T: Model](mySeq: seq[T], field: static string): untyped =
newCall(bindSym"mapIt", mySeq, nnkDotExpr.newTree(ident"it", ident field))
示例用法:
var myDSeq: seq[D] = @[]
let anA: A = A(name: "this is an A")
myDSeq.add(D(myothernameid: "la", myDA: anA))
myDSeq.add(D(myothernameid: "le", myDA: anA))
echo %*myDSeq # As Before
let myASeq: seq[A] = mapModel(myDSeq, "myDA")
echo %*myASeq # As Before
為了解釋宏的作用,我自己并沒有完全理解,但寫下了我從與 ElegantBeef 的聊天中得到的資訊:
newCall --> 你即將收到一些我稱之為可呼叫的要執行的東西,這樣做
bindSym"mapIt" --> 呼叫系結到符號“mapIt”的函式,并使用以下引數執行此操作
mySeq --> 傳遞給“mapIt”符號函式的第一個引數
nnkDotExpr.newTree--> 這將是一個執行樹或任何它們被稱為它的東西,它決議為一個可呼叫的,例如一個 proc 或一個 func。特別是一個可呼叫的點運算式。
ident"it" --> 帶有符號“it”的變數的值,由“mapIt”函式提供
ident field --> 具有包含在欄位變數中的符號的變數的值。
nnkDotExpr.newTree(ident"it", ident field)--> 在其上呼叫一個點運算式以獲取其欄位的值,該值按欄位中包含的名稱進行。這相當于it.la如果欄位包含“la”
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/410126.html
標籤:
