Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 26 additions & 5 deletions src/cigogne.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,12 @@ pub fn main() {
cigogne_config
|> config.merge(config)
|> update_config()
cli.InitConfig -> cigogne_config |> update_config()
cli.PrintUnapplied(config:) ->
cigogne_config
|> config.merge(config)
|> create_engine()
|> result.map(print_unapplied)
}
|> result.map_error(print_error)
}
Expand Down Expand Up @@ -521,12 +527,27 @@ pub fn get_non_applied_migrations(

fn show(engine: MigrationEngine) -> Nil {
let migration_names = engine.applied |> list.map(migration.to_fullname)
let to_apply = engine.non_applied |> list.map(migration.to_fullname)

io.println(
"Applied migrations: [\n" <> migration_names |> string.join(",\n\t") <> "]",
"Applied migrations: [\n\t"
<> migration_names |> string.join(",\n\t")
<> "\n]\n",
)
io.println(
"Migrations to apply: [\n\t" <> to_apply |> string.join(",\n\t") <> "\n]",
)
}

fn print_unapplied(migration_engine: MigrationEngine) -> Nil {
io.print("Unapplied migrations:")

use unapplied_mig <- list.each(migration_engine.non_applied)

io.println("\n\n--- == " <> migration.to_fullname(unapplied_mig) <> " ==\n")
io.println(unapplied_mig.queries_up |> string.join("\n"))
}

/// Print a MigrateError to the standard error stream.
pub fn print_error(error: CigogneError) -> Nil {
io.println_error(get_error_message(error))
Expand All @@ -535,8 +556,8 @@ pub fn print_error(error: CigogneError) -> Nil {
fn get_error_message(error: CigogneError) -> String {
case error {
CompoundError(errors:) ->
"Many errors happened ! Here is the list:\n"
<> errors |> list.map(get_error_message) |> string.join("\n\n")
"Many errors happened ! Here is the list:\n "
<> errors |> list.map(get_error_message) |> string.join("\n ")
ConfigError(error:) ->
"Configuration error: " <> config.get_error_message(error)
DatabaseError(error:) ->
Expand All @@ -545,10 +566,10 @@ fn get_error_message(error: CigogneError) -> String {
LibNotIncluded(name:) ->
"There were no migrations for library "
<> name
<> " !\nDid you include it ?"
<> " ! Did you include it ?"
MigrationError(error:) ->
"Migration error: " <> migration.get_error_message(error)
NothingToApply -> "There is no migration to apply !\nYou are up-to-date !"
NothingToApply -> "There is no migration to apply ! You are up-to-date !"
NothingToRollback -> "There is no migration to rollback !"
ParserError(error:) ->
"Parser error: " <> parser_formatter.get_error_message(error)
Expand Down
6 changes: 3 additions & 3 deletions src/cigogne/config.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -359,13 +359,13 @@ pub fn get_migrations_folder(migrations_config: MigrationsConfig) -> String {
pub fn get_error_message(error: ConfigError) {
case error {
AppNameError ->
"Couldn't get the application's name !\nAre you in a folder with a gleam.toml file ?"
"Couldn't get the application's name ! Are you in a folder with a gleam.toml file ?"
AppNotFound(name:) ->
"Could not find an application with name "
<> name
<> "\nDid you correctly add it to your project ?"
<> " Did you correctly add it to your project ?"
ConfigFileNotFound(path:) ->
"Could not find this project's config file.\nNote: it should be at "
"Could not find this project's config file. Note: it should be at "
<> path
FSError(error:) -> "FS error: " <> fs.get_error_message(error)
}
Expand Down
37 changes: 31 additions & 6 deletions src/cigogne/internal/cli.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ pub type CliActions {
IncludeLib(config: config.Config, lib_name: String)
RemoveLib(config: config.Config, lib_name: String)
UpdateConfig(config: config.Config)
InitConfig
PrintUnapplied(config: config.Config)
}

pub fn get_action(
Expand All @@ -27,6 +29,8 @@ pub fn get_action(
|> cli_lib.add_action(include_lib_action(application_name))
|> cli_lib.add_action(remove_lib_action(application_name))
|> cli_lib.add_action(update_config_action(application_name))
|> cli_lib.add_action(init_config_action())
|> cli_lib.add_action(print_unapplied_action(application_name))
|> cli_lib.run(args)
}

Expand Down Expand Up @@ -71,7 +75,7 @@ fn show_migrations_action(
) -> cli_lib.Action(CliActions) {
cli_lib.create_action(
["show"],
"Show the last / currently applied migration",
"Show data about the current state of migrations",
{
use config <- cli_lib.map_action(config_decoder(application_name))
ShowMigrations(config)
Expand All @@ -80,7 +84,7 @@ fn show_migrations_action(
}

fn migrate_up_all_action(application_name: String) -> cli_lib.Action(CliActions) {
cli_lib.create_action(["up-all"], "Apply all non-applied migrations", {
cli_lib.create_action(["all"], "Apply all non-applied migrations", {
use config <- cli_lib.map_action(config_decoder(application_name))
MigrateUpAll(config)
})
Expand Down Expand Up @@ -108,7 +112,7 @@ fn new_migration_action(application_name: String) -> cli_lib.Action(CliActions)

fn include_lib_action(application_name: String) -> cli_lib.Action(CliActions) {
cli_lib.create_action(
["include-lib"],
["include"],
"Include migrations from specified library",
{
use config <- cli_lib.then_action(config_decoder(application_name))
Expand All @@ -126,7 +130,7 @@ fn include_lib_action(application_name: String) -> cli_lib.Action(CliActions) {

fn remove_lib_action(application_name: String) -> cli_lib.Action(CliActions) {
cli_lib.create_action(
["remove-lib"],
["remove"],
"Remove migrations from specified library",
{
use config <- cli_lib.then_action(config_decoder(application_name))
Expand All @@ -144,15 +148,36 @@ fn remove_lib_action(application_name: String) -> cli_lib.Action(CliActions) {

fn update_config_action(application_name: String) -> cli_lib.Action(CliActions) {
cli_lib.create_action(
["update-config"],
"Create or update cigogne's config for your project",
["config", "update"],
"Update cigogne's config for your project with provided options",
{
use config <- cli_lib.then_action(config_decoder(application_name))
cli_lib.options(UpdateConfig(config:))
},
)
}

fn init_config_action() -> cli_lib.Action(CliActions) {
cli_lib.create_action(
["config", "init"],
"Create cigogne's config for your project",
{ cli_lib.options(InitConfig) },
)
}

fn print_unapplied_action(
application_name: String,
) -> cli_lib.Action(CliActions) {
cli_lib.create_action(
["print", "unapplied"],
"Print all unapplied migrations as SQL strings",
{
use config <- cli_lib.then_action(config_decoder(application_name))
cli_lib.options(PrintUnapplied(config:))
},
)
}

fn config_decoder(
application_name: String,
) -> cli_lib.ActionDecoder(config.Config) {
Expand Down
55 changes: 39 additions & 16 deletions src/cigogne/internal/cli_lib.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -290,10 +290,8 @@ fn print_help(command: Command(a)) -> Nil {
io.println("Usage: gleam run -m " <> command.name <> " <action> [<flags>]")
io.println("")
io.println("Available actions:")
list.each(command.actions |> list.reverse, fn(action) {
let action_path = action.action_path |> string.join(" ")
io.println(" " <> action_path <> " - " <> action.help)
})

print_actions(command.actions)

io.println("")
io.println(
Expand All @@ -303,22 +301,54 @@ fn print_help(command: Command(a)) -> Nil {
)
}

fn print_actions(actions: List(Action(a))) -> Nil {
let actions_data =
actions
|> list.map(fn(a) { #(a.action_path |> string.join(" "), a.help) })
let max_action_length =
list.fold(actions_data, 0, fn(acc, d) { int.max(acc, string.length(d.0)) })
let action_column_width = { max_action_length / 4 } * 4 + 4

list.each(actions_data |> list.reverse, fn(action) {
io.println(
" "
<> action.0 |> string.pad_end(action_column_width, " ")
<> " - "
<> action.1,
)
})
}

fn print_help_action(action: Action(a)) -> Nil {
{ action.action_path |> string.join(" ") <> "\n" <> action.help }
|> box_text(80)
|> io.println

io.println("")
io.println("Available flags:")
list.each(action.decoder.flag_defs, fn(flag) {

print_flags(action.decoder.flag_defs)
}

fn print_flags(flags: List(Flag)) -> Nil {
let flags_data =
flags
|> list.map(fn(f) {
#(print_flag(f.name) <> " " <> f.type_, f.description, f.aliases)
})
let max_flag_length =
list.fold(flags_data, 0, fn(acc, d) { int.max(acc, string.length(d.0)) })
let flag_column_width = { max_flag_length / 4 } * 4 + 4

list.each(flags_data, fn(flag) {
{
justify_left(print_flag(flag.name) <> " " <> flag.type_, 20)
flag.0 |> string.pad_end(flag_column_width, " ")
<> " - "
<> flag.description
<> flag.1
<> "\n"
<> string.repeat(" ", 24)
<> string.repeat(" ", flag_column_width + 4)
<> "Aliases: "
<> flag.aliases |> list.map(print_flag) |> string.join(", ")
<> flag.2 |> list.map(print_flag) |> string.join(", ")
}
|> io.println()
})
Expand All @@ -332,13 +362,6 @@ fn print_flag(flag_name: String) {
}
}

fn justify_left(text: String, width: Int) {
case string.length(text) {
i if i < width -> text <> string.repeat(" ", width - i)
_ -> text
}
}

fn box_text(text: String, max_width: Int) -> String {
let lines = center_text(text, max_width - 4) |> string.split("\n")
let actual_width = string.length(lines |> list.first |> result.unwrap("")) + 4
Expand Down
6 changes: 3 additions & 3 deletions src/cigogne/internal/database.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ fn describe_query_error(error: pog.QueryError) -> String {
pog.ConnectionUnavailable -> "CONNECTION UNAVAILABLE"
pog.ConstraintViolated(message, _constraint, _detail) -> message
pog.PostgresqlError(_code, _name, message) ->
"Postgresql error : " <> message
"Postgresql error: " <> message
pog.UnexpectedArgumentCount(expected, got) ->
"Expected "
<> int.to_string(expected)
Expand All @@ -321,8 +321,8 @@ fn describe_query_error(error: pog.QueryError) -> String {
pog.UnexpectedArgumentType(expected, got) ->
"Expected argument of type " <> expected <> ", got " <> got <> " !"
pog.UnexpectedResultType(errs) ->
"Unexpected result type ! \n"
<> list.map(errs, describe_decode_error) |> string.join("\n")
"Unexpected result types !\n "
<> list.map(errs, describe_decode_error) |> string.join("\n ")
pog.QueryTimeout -> "Query Timeout"
}
}
Expand Down
5 changes: 2 additions & 3 deletions src/cigogne/internal/fs.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,8 @@ fn read_files(paths: List(String)) -> Result(List(File), FSError) {
pub fn get_error_message(error: FSError) -> String {
case error {
CompoundError(errors:) ->
"List of errors : [\n"
<> errors |> list.map(get_error_message) |> string.join(",\n\t")
<> "\n]"
"Many FS errors happened: \n "
<> errors |> list.map(get_error_message) |> string.join("\n ")
MissingFileError(file:) -> "Could not find file at path " <> file
MissingFolderError(folder:) ->
"Could not find folder at path " <> folder <> "/"
Expand Down
2 changes: 1 addition & 1 deletion src/cigogne/internal/parser_formatter.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,7 @@ pub fn get_error_message(error: ParserError) -> String {
UnfinishedLiteral(context:) -> "Invalid migration: Unfinished " <> context
WrongFormat(name:) ->
name
<> " isn't a valid migration name !\nIt should be YYYYMMDDHHmmss-<NAME>"
<> " isn't a valid migration name ! It should be YYYYMMDDHHmmss-<NAME>"
NotASQLFile(filepath:) -> filepath <> " is not a .sql file"
}
}
11 changes: 5 additions & 6 deletions src/cigogne/migration.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -209,23 +209,22 @@ pub fn is_zero_migration(migration: Migration) -> Bool {
pub fn get_error_message(error: MigrationError) -> String {
case error {
CompoundError(errors:) ->
"Many errors happened : ["
<> errors |> list.map(get_error_message) |> string.join(",\n\t")
<> "]"
"Many migration errors happened: \n "
<> errors |> list.map(get_error_message) |> string.join(",\n ")
FileHashChanged(fullname:) ->
"Hash of file "
<> fullname
<> " has changed !\nDid you modify the file after applying the migration ?"
<> " has changed ! Did you modify the file after applying the migration ?"
MigrationNotFound(fullname:) ->
"Could not find a matching migration file for "
<> fullname
<> ".\nCheck there is a file named "
<> ". Check there is a file named "
<> fullname
<> ".sql in your migrations folder."
NameTooLongError(name:) ->
"Name "
<> name
<> "is too long !\nMigration names shouldn't exceed 255 characters."
<> "is too long ! Migration names shouldn't exceed 255 characters."
NothingToMergeError -> "Could not merge 0 migrations"
}
}