Использование парообразных для поддержки моделей - PullRequest
0 голосов
/ 27 января 2019

В настоящее время я борюсь за то, чтобы сделать упор с паром / жидкостью.У меня есть что-то вроде этого:

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:), однако он будет обновляться только в том случае, если идентификатор совпадает (в моем понимании).Поскольку клиент не отправляет идентификатор, я не совсем уверен, как с этим справиться.

Также я не могу декодировать модель, так как учетная запись отправляется без deviceTokenId, и, следовательно, декодирование не удастся.Я думаю, что я могу решить последнюю проблему, переопределив NodeCovertible или используя две разные модели (одну для декодирования json без идентификатора и фактической модели сверху).Однако первая проблема все еще остается.

Что я точно хочу сделать:

  1. Обновить DeviceToken, если запись с токеном уже существует, иначе создать ее

  2. Если учетная запись с комбинацией имени пользователя и службы уже существует, обновите ее имя пользователя, служба и deviceTokenId создайте ее.DeviceTokenId - это идентификатор, возвращенный с 1.

Есть ли шанс, что вы мне поможете?

1 Ответ

0 голосов
/ 28 января 2019

Для всех, кто заинтересован: я решил это, написав расширение на 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)])
    }

    ....
}

Я решил другую проблему, с которой у меня не получалась модель базы данныхдекодируется, поскольку идентификатор не был отправлен от клиента, используя внутреннюю структуру, которая будет содержать только те свойства, которые отправит клиент.Идентификатор и другие свойства, сгенерированные базой данных, находятся во внешней структуре.Что-то вроде:

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
    }
}
...