
This video is only available to subscribers. Start a subscription today to get access to this and 484 other videos.
Scripting in Swift with Marathon - Part 2
This is a continuation from Part 1.
Quick correction: In the episode I said that Vapor uses a package to generate xcode project files, but this is incorrect. Vapor uses swift package manager directly, which has a
generate-xcodeproj
command and does the job.
Creating files
Now that we have our templates ready to go, we need to save these to an actual file on disk.
let template = ....
try migrationsFolder.createFile(named: filename, contents: template)
This adds new files on disk, but the Xcode project doesn't know about them yet, so we'll have to inform the user to run vapor xcode
again to get them added to the
Now that we have auto-numbered migration files on disk, we need a way to tell Vapor about these.
Creating a Migration Support file
We want to be able to ingest these migration files during Vapor setup. In configure.swift
we'll add this line:
var migrations = MigrationConfig()
migrations.runAutoMigrations() // doesn't exist yet
Next, we need to add an extension that includes all of our generated migrations listed.
func migrationSupportSwiftFile() -> String {
return """
/* This file is generated. Do not edit. */
import Vapor
import FluentPostgreSQL
extension MigrationConfig {
mutating func runAutoMigrations() {
/// add all migrations here
}
}
"""
}
We need to give this method the list of all of our type names, but we also need to know what type of migration it is (model or plain migration). We'll wrap this up in a type:
struct MigrationDescriptor {
let name: String
let command: String
func toMigrationSwift() -> String {
return "add(\(command): \(name).self, database: .psql)"
}
}
Next we need to gather all of the migration files, skipping over the support file we're about to generate (so we don't treat that as a migration).
let migrationSupportFilename = "_MigrationSupport.swift"
let descriptors = migrationFiles
.filter { $0.name != migrationSupportFilename }
.map { file -> MigrationDescriptor in
let parts = file.nameExcludingExtension.components(separatedBy: "_")
let name = parts[1]
let command = parts.count > 2 && parts[2] == "model" ? "model" : "migration"
return MigrationDescriptor(name: name, command: command)
}
Here we're using a convention that model migrations will be suffixed with _model
.
Now we can pass these in to the function we created earlier:
func migrationSupportSwiftFile(_ migrationDescriptors: [MigrationDescriptor]) -> String {
let migrationList = migrationDescriptors
.map { $0.toMigrationSwift() }
.joined(separator: "\n ")
return """
/* This file is generated. Do not edit. */
import Vapor
import FluentPostgreSQL
extension MigrationConfig {
mutating func runAutoMigrations() {
\(migrationList)
}
}
"""
}
Finally we need to save this file to disk:
let supportFile = migrationSupportSwiftFile(descriptors)
try migrationsFolder.createFile(named: migrationSupportFilename, contents: supportFile)
print("Created \(filename) 🥳. Make sure to run vapor xcode to regenerate your project.")