1

ヘイホー、

私は、nim プログラミング言語の orm であるnormを使用しています。私はこのような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 クエリを記述して、多対 1 の関係を取得できます。

tableNameさらに重要なことは、この外部キー関係の取得は、モデル自体ではなく、モデルの に基づくことです。したがって、 proc を定義する場合、両方のANDgetRelatedFieldName(startType: typedesc[A], otherType: typedesc[B])に対して同じ結果を与える必要があります。getRelatedFieldName(A, B)getRelatedFieldName(A, Surprise)

どうすればこれを達成できますか?

4

1 に答える 1

2

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")


于 2022-01-07T23:30:20.127 に答える