Vapor/Fluent: Дочерний объект не сохраняется, когда массив uuid в схеме

#ios #swift #postgresql #fluent #vapor

Вопрос:

У меня есть таблица, содержащая объект Coin, с соответствующей моделью Fluent. Он отказывался сохраняться, пока я не удалил одно поле, которое должно было содержать массив uuid. Это было вызвано sources , и его функция состояла в том, чтобы обеспечить обратный путь к другим монетам, из которых была получена новая монета — например, если у пользователя есть две монеты (которые могут иметь произвольное значение количества), цель состояла в том, чтобы объединить их в одну монету с общей стоимостью объединенных монет.

Схема (с прокомментированным полем выглядит следующим образом (она включает миграцию, также с соответствующим закомментированным полем):

 final class Coin : Model, Content, ResponseEncodable {
    
    init() {}
    
    init(player: User, quantity: Int, type: CreatedFor, sources : [Coin] = []) {
        self.id = id
        self.$player.id = player.id!
        self.quantity = quantity
        self.type = type
//        self.sources = sources
    }
    
    static let schema: String = "coins"
    
    @ID(key: .id)                   var id: UUID?
    
    @Timestamp(key: "created_at", on: .create) var createdAt: Date?
    @Timestamp(key: "updated_at", on: .update) var updatedAt: Date?
    
    @Parent(key: "player")          var player: User
    
    @Field(key: "quantity")         var quantity: Int
    @Field(key: "type")             var type: CreatedFor
//    @Field(key: "sources")          var sources: [Coin]
    
    enum CreatedFor: String, Codable {
        case transfer
        case ante
        case purchase
        case winnings
        case gift
        case merge
    }
}

extension Coin {
    struct BuildCoin: Fluent.Migration {
        var name : String { "BuildCoin" }
        
        func prepare(on database: Database) -> EventLoopFuture<Void> {
            database.schema("coins")
                .id()
                .field("created_at", .datetime)
                .field("updated_at", .datetime)
                .field("player", .uuid, .required)
                .field("quantity", .int, .required, .custom("DEFAULT 0"))
                .field("type", .string, .required, .custom("DEFAULT 'gift'"))
//                .field("sources", .array(of: .uuid))
                .create()
        }
        
        func revert(on database: Database) -> EventLoopFuture<Void> {
            database.schema("coins").delete()
        }
        
    }
}
 

как только я свел все к тому месту, где возникла проблема, я смог получить эту ошибку, которая, похоже, исходит от postgres:

{"error":true,"reason":"server: column "sources" is of type uuid[] but expression is of type jsonb[] (transformAssignedExpr)"}

Я хотел бы включить это поле (но пока я могу обойтись без него). Что здесь происходит? При вызове init () он всегда вызывался только как пустой массив, поэтому я бы подумал, что это не вызовет проблем…

Заранее спасибо…

Ответ №1:

Если вы хотите сохранить как массив uuid вместо

 @Field(key: "sources") var sources: [Coin]
 

вы должны использовать

 @Field(key: "sources") var sources: [UUID]
 

Кроме того, вы пытаетесь сохранить массив монет в БД, и этот массив будет сериализован в jsonb — так как это объект, а не UUID. Глядя на свой код, я думаю, что вы должны использовать отношение «1 ко многим» или «многие ко многим».

Комментарии:

1. Спасибо, @Kac очень признателен… Я думаю, что в своей голове я объединил варианты [у]родителей [у]детей и заблудился.