3
votes

This puzzles me:

I have a model in which I want to use an enum. I first declare the enum:

enum MenuChoices: String, Codable {
    case reachableAt
    case attentionTo
    case reasonVisit
    case reasonProblem
}

Then it is in my fields of the class:

@Enum(key: "menu_choices")
var menuChoices: MenuChoices

I then create it in the database using a migration:

struct CreateUserMenu: Migration {    
func prepare(on database: Database) -> EventLoopFuture<Void> {
    return database.enum("menu_choices")
        .case("reachable_at")
        .case("attention_to")
        .case("reason_visit")
        .case("reason_problem")
        .create()
        .flatMap { menu_choices in
            return database.schema("user_menus")
                .id()
                .field("created_at", .datetime, .required)
                .field("updated_at",.datetime, .required)
                .field("deleted_at",.datetime)
                .field("menu_choices", menu_choices)
                .field("be_nl", .string)
                .field("be_fr", .string)
                .field("en_us", .string)
                .create()
        }
    }
}

So far so good. This migration works and the database looks ok. But when I want to add some data to seed the database in another migration I get an error :

let test = UserMenu( menuChoices: MenuChoices.reachableAt, beNl: "nl", beFr: "fra", enUs: "eng")
let _ = test.save(on: database)

+ App.addUserMenus on default
Would you like to continue?
y/n> y
[ ERROR ] previousError(MySQL error: Server error: Data truncated for column 'menu_choices' at row 1)
Fatal error: Error raised at top level: previousError(MySQL error: Server error: Data truncated for column 'menu_choices' at row 1): file /AppleInternal/BuildRoot/Library/Caches/com.apple.xbs/Sources/swiftlang/swiftlang-1103.8.25.8/swift/stdlib/public/core/ErrorType.swift, line 200
    USSS-Voyager-II:24yours data$ 

Unfortunately this error doesn’t really help to pinpoint the source of the problem

1
Isn't it just that the string value for MenuChoices.reachableAt resolves to "reachableAt" but the mysql enum will be looking for "reachable_at"?Nick
I don't think so. If you take a look at my "struct CreateUserMenu: Migration {... " code you will see that at database level I use reachable_at. I just saw similar code here : stemmetje.com/2020/05/creating-a-database-enum-in-vapor-4 and don't see any differences with mine :( Concerning your way of doing it: you use myEnum.rawvalue() to save it to a string in the db ?Glenn
What happens if you define the swift enum case as case reachableAt = "reachable_at"? I don't use rawValue().Nick
Woehaa. This is working now! If you make it an answer to my question I can accept your answer!Glenn

1 Answers

3
votes

The problem is that there is no mapping between the swift definition of the enum and the Fluent enum. Putting a string literal value for your swift enum definition that matches the string literal value of the Fluent will fix the problem.

enum MenuChoices: String, Codable {
    case reachableAt = "reachable_at"
    case attentionTo = "attention_to"
    case reasonVisit = "reason_visit"
    case reasonProblem = "reason_problem"
}