Chapter 31.4: Enums Tests UserType

I’ve been following the Server Side Swift Book and now I’m kinda stuck when adding the userType.
It runs, but the tests won’t run anymore.
I’ve tried to add it on my own by using what I learned, something seems to be missing (for me) tho.

This is the error I’m getting:
**error codes.vapor.application : database-id=psql psql_connection_id=D952CE7C-83B3-4902-9AF5-5CD7ED3C1CA9 psql_error=PSQLError(base: PostgresNIO.PSQLError.Base.server(PostgresNIO.PSQLBackendMessage.ErrorResponse(fields: [Severity: "ERROR", Message: "type \"userType\" already exists", Routine: "DefineEnum", File: "typecmds.c", Localized Severity: "ERROR", Line: "1189", Code: "42710"]))) Query failed**

in Models+Testable.swift I added userType: UserType = .standard, in the create function and

let user = User(
      name: name,
      username: createUsername,
      password: password,
      email: "\(createUsername)@test.com",
      userType: userType)

in UserTests.swift I added
let usersUserType = UserType.standard and updated let user = try User.create(name: usersName, username: usersUsername, userType: usersUserType, on: app.db)

I stopped and removed the docker container and I am starting it with

docker run --name postgres-test \
  -e POSTGRES_DB=vapor-test \
  -e POSTGRES_USER=vapor_username \
  -e POSTGRES_PASSWORD=vapor_password \
  -p 5433:5432 -d postgres:12-alpine

still having the error tho. Not sure how to fix this.

What migrations do you have and what do they look like? (Anything related to User and the enum)

I followed the book for that and don’t think I’ve added anything else, just tried to include what I had from the chapters before.

import Fluent

struct CreateUser: Migration {
  func prepare(on database: Database) -> EventLoopFuture<Void> {
    database.enum("userType")
      .case("admin")
      .case("standard")
      .case("restricted")
      .create()
      .flatMap { userType in
        database.schema("users")

          .id()

          .field("name", .string, .required)
          .field("username", .string, .required)
          .field("password", .string, .required)
          .field("siwaIdentifier", .string)
          .field("email", .string, .required)
          .field("profilePicture", .string)
          .field("userType", userType, .required)

          .unique(on: "email")
          .unique(on: "username")

          .create()
      }
  }

  func revert(on database: Database) -> EventLoopFuture<Void> {
    database.schema("users").delete()
  }
}

extension User {
  enum v20210410 {
    static let schemaName = "users"
    static let id = FieldKey(stringLiteral: "id")
    static let name = FieldKey(stringLiteral: "name")
    static let username = FieldKey(stringLiteral: "username")
    static let password = FieldKey(stringLiteral: "password")
    static let email = FieldKey(stringLiteral: "email")
    static let siwaIdentifier = FieldKey(stringLiteral: "siwaIdentifier")
    static let profilePicture = FieldKey(stringLiteral: "profilePicture")
  }
  enum v20210411 {
    static let twitterURL = FieldKey(stringLiteral: "twitterURL")
  }
  enum v20210425 {
    static let userType = FieldKey(stringLiteral: "userType")
  }
}

Right I see what’s happening. You’re not deleting the enum in your revert. So in the first test, it creates the enum, creates the user table, runs the test then deletes the user table. Then the next next, tries to create the enum again and fails because it hasn’t been removed. So you need to change your revert to delete the enum

Well, that sounds easier then it is for me. haha

func revert(on database: Database) -> EventLoopFuture<Void> {
    database.enum("userType").delete()
    database.schema("users").delete()
  }

when build shows the error

Missing return in a function expected to return 'EventLoopFuture<Void>'; did you mean to return the last expression?

I have no idea what do do with that information, I tried the fix of adding return before database.schema… but the end error is the same as before.

Edit:

the revert should look like this to not throw any errors

func revert(on database: Database) -> EventLoopFuture<Void> {
    database.schema("users").delete().flatMap {
      database.enum("userType").delete()
    }
  }

This works now, thanks @0xtim for the help!

2 Likes