簡體   English   中英

使用蒸汽流體來模擬模型

[英]Using vapor-fluent to upsert models

我目前正在努力做一個蒸氣/流利的upsert。 我有一個這樣的模型:

struct DeviceToken: PostgreSQLModel {
    var id: Int?
    var token: String
    var updatedAt: Date = Date()

    init(id: Int? = nil, token: String, updatedAt: Date = Date()) {
        self.id = id
        self.token = token
        self.updatedAt = updatedAt
    }
}

struct Account: PostgreSQLModel {
    var id: Int?
    let username: String
    let service: String
    ...
    let deviceTokenId: DeviceToken.ID

    init(id: Int? = nil, service: String, username: String, ..., deviceTokenId: DeviceToken.ID) {
        self.id = id
        self.username = username
        ....
        self.deviceTokenId = deviceTokenId
    }
}

從客戶端的東西

{
    "deviceToken": {
        "token": "ab123",
        "updatedAt": "01-01-2019 10:10:10"
    },
    "account": {
        "username": "user1",
        "service": "some service"
    }
}

發送。

我想要做的是插入新模型,如果它們不存在,則更新它們。 我看到了create(orUpdate:)方法但是只有在id相同時才會更新(在我的理解中)。 由於客戶端沒有發送id,我不太清楚如何處理這個問題。

此外,我無法解碼模型,因為帳戶是在沒有deviceTokenId情況下發送的,因此解碼將失敗。 我想我可以通過重寫NodeCovertible或使用兩個不同的模型來解決后一個問題(一個用於解碼沒有id的json和上面的實際模型)。 然而,第一個問題仍然存在。

我真正想做的是:

  1. 如果已存在具有令牌的條目,則更新DeviceToken,否則創建它

  2. 如果已存在用戶名和服務組合的帳戶更新其用戶名,則service和deviceTokenId會創建它。 DeviceTokenId是從1返回的id。

你有機會幫助我嗎?

對於每個感興趣的人:我通過在PostgreSQLModel上編寫擴展來解決它,以提供upsert方法。 我添加了一個要點,讓你看看: 這里

由於這些鏈接有時會在您需要此處的信息時被破壞,因此請快速瀏覽:

實際upsert實現:

extension QueryBuilder
where Result: PostgreSQLModel, Result.Database == Database {

    /// Creates the model or updates it depending on whether a model
    /// with the same ID already exists.
    internal func upsert(_ model: Result,
                         columns: [PostgreSQLColumnIdentifier]) -> Future<Result> {

        let row = SQLQueryEncoder(PostgreSQLExpression.self).encode(model)

        /// remove id from row if not available
        /// otherwise the not-null constraint will break
        row = row.filter { (key, value) -> Bool in
            if key == "id" && value.isNull { return false }
            return true
        }

        let values = row
            .map { row -> (PostgreSQLIdentifier, PostgreSQLExpression) in
                return (.identifier(row.key), row.value)
        }

        self.query.upsert = .upsert(columns, values)
        return create(model)
    }

}

方便的方法

extension PostgreSQLModel {

    /// Creates the model or updates it depending on whether a model
    /// with the same ID already exists.
    internal func upsert(on connection: DatabaseConnectable) -> Future<Self> {
        return Self
            .query(on: connection)
            .upsert(self, columns: [.keyPath(Self.idKey)])
    }

    internal func upsert<U>(on connection: DatabaseConnectable,
                        onConflict keyPath: KeyPath<Self, U>) -> Future<Self> {
        return Self
            .query(on: connection)
            .upsert(self, columns: [.keyPath(keyPath)])
    }

    ....
}

我解決了我的另一個問題,我的數據庫模型無法解碼,因為id不是從客戶端發送的,通過使用一個內部結構,它只保存客戶端將發送的屬性。 id和其他數據庫生成的屬性位於外部結構中。 就像是:

struct DatabaseModel: PostgreSQLModel {

    var id: Int?
    var someProperty: String

    init(id: Int? = nil, form: DatabaseModelForm) {

        self.id = id
        self.someProperty = form.someProperty
    }

    struct DatabaseModelForm: Content {
        let someProperty: String
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM