Skip to content

Adding Unique constraint can cause vapor to crash #62

@mredig

Description

@mredig

I've only noticed this behavior when using a SQLite db. This code seems to work fine on PostgreSQL.

This is my initial migration:

struct UserMigration_v1_0_0: Migration {
	func prepare(on database: Database) -> EventLoopFuture<Void> {
		database.eventLoop.flatten([
			database.schema(UserModel.schema)
				.id()
				.field(UserModel.FieldKeys.email, .string, .required)
				.field(UserModel.FieldKeys.password, .string, .required)
				.unique(on: UserModel.FieldKeys.email)
				.create(),
		])
	}

	func revert(on database: Database) -> EventLoopFuture<Void> {
		database.eventLoop.flatten([
			database.schema(UserModel.schema).delete()
		])
	}
}

(migration 1_1_0 doesn't touch this schema at all)

I then run this migration:

struct UserMigration_v1_2_0: Migration {
	func prepare(on database: Database) -> EventLoopFuture<Void> {
		database.schema(UserModel.schema)
			.field(UserModel.FieldKeys.appleId, .string)
			.unique(on: UserModel.FieldKeys.appleId)
			.update()
	}

	func revert(on database: Database) -> EventLoopFuture<Void> {
		database.schema(UserModel.schema)
			.deleteField(UserModel.FieldKeys.appleId)
			.update()
	}
}

and the app will crash with the following error:

2020-06-14 20:14:10.556995-0500 xctest[44335:23885144] [logging] near ",": syntax error in "ALTER TABLE "user_users" ADD "appleId" TEXT , ADD CONSTRAINT "uq:user_users.appleId" UNIQUE ("appleId")"
Fatal error: Application.shutdown() was not called before Application deinitialized.: file .../vapor/Sources/Vapor/Application.swift, line 167

Now here's where it gets weird (for me, at least). This crashes on both Mac and Linux, but if I make the following change to the followup migration, it doesn't crash on Mac, but still does on Linux. On Mac, I DO get a console warning (which, when examining the DB file, appears to result in the unique constraint simply just ignored in the end).

struct UserMigration_v1_2_0: Migration {
	func prepare(on database: Database) -> EventLoopFuture<Void> {
		database.eventLoop.flatten([
			database.schema(UserModel.schema)
				.field(UserModel.FieldKeys.appleId, .string)
				.update(),
			database.schema(UserModel.schema)
				.unique(on: UserModel.FieldKeys.appleId)
				.update(),
		])
	}

	func revert(on database: Database) -> EventLoopFuture<Void> {
		database.schema(UserModel.schema)
			.deleteField(UserModel.FieldKeys.appleId)
			.update()
	}
}

Here's the warning I get on macOS:

2020-06-14T20:18:02-0500 warning: database-id=sqlite Ignoring schema update. SQLite only supports adding columns to existing tables

I'm effectively asking for the same end result, but breaking it into two steps allows for the macOS build to simply ignore the issue and continue on.

Another thing I simply don't understand... How can this possible cause the app to deinitialize itself? There are other maintained references to the app that would prevent the reference count from reaching 0, so I feel like I'm going crazy!

Metadata

Metadata

Assignees

No one assigned

    Labels

    questionFurther information is requested

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions