Making the username unique

I noticed that the username, something that’s often considered unique, is never checked for uniqueness. This might be eventually described and fixed in the section regarding authentication once it comes out, so apologies if I’m skipping ahead, but for those interested, here’s how you can implement that yourself even now.

In the Models/User.swift, remove automatic conformance to the Migration protocol and instead implement it yourself, like this:

extension User: Migration {
    static func prepare(on connection: PostgreSQLConnection) -> Future<Void> {
        return Database.create(self, on: connection) { builder in
            try addProperties(to: builder)
            try builder.addIndex(to: \.username, isUnique: true)
        }
    }
}

Revert the database to drop the users table and re-create it again – except this time username should be checked for uniqueness on a database level.

Once you try re-running your tests, however, you’ll find a lot of them suddenly failing. That’s happening because the User.create helper method located in the AppTests/Models+Testable.swift file happily creates new user anytime it’s called, and it’s called often, creating duplicate users. You can modify it like this:

extension User {
    static func create(name: String = "Luke", username: String = "lukes", on connection: PostgreSQLConnection) throws -> User {
        // Required due to the added UNIQUE constraint
        if let existing = try User.query(on: connection).filter(\.username == username).first().wait() {
            return existing
        }

        let user = User(name: name, username: username)

        return try user.save(on: connection).wait()
    }
}

And now your tests should be passing again.

@cellane thanks! This is coming in the auth chapter, though given the DB is reverted each time there shouldn’t be that many failing tests :thinking:

1 Like

Although looking through them there are lots of instances where it could do! Noted

1 Like