Skip to content
This repository has been archived by the owner on Oct 2, 2023. It is now read-only.

Commit

Permalink
init and revert: support syncing migrations down. (#32)
Browse files Browse the repository at this point in the history
  • Loading branch information
thruflo authored Feb 2, 2023
1 parent feaf709 commit d038c95
Show file tree
Hide file tree
Showing 11 changed files with 338 additions and 51 deletions.
26 changes: 24 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,12 @@ Creates a new folder for migrations in your current directory called 'migrations

The `APP` and optinally `ENV` you give should be copied from the sync service connection details provided by the ElectricSQL console. You specify here once, and the CLI stores in an `electric.json` file so you don't have to keep re-typing it.

Note that you can also sync down migrations from an existing app using:

```sh
electric init APP --sync-down
```

### Update

You can update your config using `electric config update`. See the options with:
Expand Down Expand Up @@ -180,15 +186,31 @@ electric migrations revert NAME [--env ENV]

This will copy the named migration from the ElectricSQL server to replace the local one. By default this will use the `default` environment, if you want to use a different one you can specify it with `--env ENV`.

If you're having problems with your local migrations, you can force revert:

```sh
electric migrations revert NAME --force
```

And you can revert all of the local migrations to match the migrations that have been applied on the server. This is like a force reset of the local migrations folder:

```sh
electric migrations revert --all
```

Remeber to `electric build` after resetting before importing into your local app.

### reset

If you get stuck in local development and need to reset your backend, you can wipe and re-provision your environment using:
> WARNING: Use `reset` with extreme care (and usually only in development) as it explicitly causes data loss.
If you get stuck and need to reset the migrations that have been applied on the server, you can wipe and re-provision your environment using:

```sh
electric reset [--env ENV]
```

WARNING: Use this with care (and usually only in development) as it explicitly causes data loss.
This is like a force reset of the server migrations. Remember to `electric sync` to upload your local migrations to the new server environment before restarting replication.

## Contributing

Expand Down
36 changes: 32 additions & 4 deletions apps/electric_cli/lib/electric_cli/commands/init.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,20 @@ defmodule ElectricCli.Commands.Init do
alias ElectricCli.Migrations
alias ElectricCli.Config.Environment

@flags [
sync_down: [
long: "--sync-down",
help: "Sync down the current migrations from the server.",
required: false
]
]

@options [
env: [
short: "-e",
long: "--env",
value_name: "ENV",
help: "Name of the app environment.",
help: "Name of the target environment.",
parser: :string,
default: Application.compile_env!(:electric_cli, :default_env)
]
Expand All @@ -27,9 +35,18 @@ defmodule ElectricCli.Commands.Init do
You can update your config and add environments using the `electric config`
command. See `electric config --help` for details.
Examples:
Standard usage:
electric init APP
Specify a target environment:
electric init APP --env ENV
Sync down and bootstrap the local folder with the existing migrations
from the server:
electric init APP --sync-down
"""
end

Expand All @@ -39,7 +56,8 @@ defmodule ElectricCli.Commands.Init do
about: about(),
flags:
merge_flags(
config_flags() ++
@flags ++
config_flags() ++
console_flags() ++
replication_flags()
),
Expand Down Expand Up @@ -71,6 +89,7 @@ defmodule ElectricCli.Commands.Init do
env = options.env

debug = flags.debug
should_sync_down = flags.sync_down
should_verify_app = not flags.no_verify

migrations_dir = Path.relative_to(options.migrations_dir, root)
Expand Down Expand Up @@ -112,7 +131,8 @@ defmodule ElectricCli.Commands.Init do
})

with :ok <- Config.save(config),
:ok <- Migrations.init_migrations(config) do
{:ok, %Config{} = config} <- Config.load(root),
:ok <- init_migrations(config, environment, should_sync_down, should_verify_app) do
{:success, ["ElectricCli configuration written to `#{relative_root}/`\n"]}
else
_err ->
Expand All @@ -133,4 +153,12 @@ defmodule ElectricCli.Commands.Init do
alt
end
end

defp init_migrations(%Config{} = config, %Environment{}, false, should_verify_app) do
Migrations.init_migrations(config, should_verify_app)
end

defp init_migrations(%Config{} = config, %Environment{} = environment, true, _should_verify) do
Migrations.sync_down_migrations(config, environment)
end
end
89 changes: 71 additions & 18 deletions apps/electric_cli/lib/electric_cli/commands/migrations.ex
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,40 @@ defmodule ElectricCli.Commands.Migrations do
Copies the named migration from the server to replace the local one.
Uses your `defaultEnv` unless you specify `--env ENV`.
## Examples
To revert a migration by name:
electric migrations revert NAME
Or revert all of your local migrations to match the migrations on
the server:
electric migrations revert --all
""",
args: @migration_arg,
args: [
migration_name: [
value_name: "NAME",
help: "Name of the migration",
required: false,
parser: :string
]
],
options: merge_options(env_options()),
flags: default_flags()
flags:
merge_flags(
all: [
long: "--all",
help: "Revert all local migrations and replace with migrations from the server.",
required: false
],
force: [
long: "--force",
help: "Force revert the named migration.",
required: false
]
)
]
]
]
Expand Down Expand Up @@ -96,25 +126,48 @@ defmodule ElectricCli.Commands.Migrations do
end
end

def revert(%{args: %{migration_name: migration_name}, options: %{env: env, root: root}}) do
def revert(%{args: args, flags: flags, options: %{env: env, root: root}}) do
with :ok <- Session.require_auth(),
{:ok, %Config{} = config} <- Config.load(root),
{:ok, %Environment{} = environment} <- Config.target_environment(config, env) do
Progress.run("Reverting migration", fn ->
case Migrations.revert_migration(config, environment, migration_name) do
:ok ->
{:success, "Migration reverted successfully"}

{:ok, warnings} ->
{:success, Util.format_messages("warnings", warnings)}

{:error, errors} when is_list(errors) or is_binary(errors) ->
{:error, Util.format_messages("errors", errors)}

alt ->
alt
end
end)
case {args, flags} do
{%{migration_name: name}, %{all: false}} when is_binary(name) and name != "" ->
Progress.run("Reverting migration", fn ->
case Migrations.revert_migration(config, environment, name, flags.force) do
:ok ->
{:success, "Migration reverted successfully"}

{:ok, warnings} ->
{:success, Util.format_messages("warnings", warnings)}

{:error, errors} when is_list(errors) or is_binary(errors) ->
{:error, Util.format_messages("errors", errors)}

alt ->
alt
end
end)

{%{migration_name: nil}, %{all: true}} ->
Progress.run("Reverting all migrations", fn ->
case Migrations.sync_down_migrations(config, environment) do
:ok ->
{:success, "Migrations reverted successfully"}

{:ok, warnings} ->
{:success, Util.format_messages("warnings", warnings)}

{:error, errors} when is_list(errors) or is_binary(errors) ->
{:error, Util.format_messages("errors", errors)}

alt ->
alt
end
end)

_ ->
{:error, "You must specify a migration NAME or use the --all flag."}
end
end
end
end
5 changes: 4 additions & 1 deletion apps/electric_cli/lib/electric_cli/commands/sync.ex
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ defmodule ElectricCli.Commands.Sync do

def about() do
"""
Sync migrations upto the backend.
Sync migrations up-to the backend.
This synchronises your local changes up to your ElectricSQL sync service
and builds a new javascript file at `:output_dir/:app/:env/index.js` that
Expand Down Expand Up @@ -37,6 +37,9 @@ defmodule ElectricCli.Commands.Sync do
The sync will also fail if the migration has a name that is lower in sort order
than one already applied on the server.
If you want to sync migrations down from the backend without uploading
and matching your local migrations, use `electric revert [NAME] [--all]`.
"""
end

Expand Down
4 changes: 1 addition & 3 deletions apps/electric_cli/lib/electric_cli/config.ex
Original file line number Diff line number Diff line change
Expand Up @@ -126,9 +126,7 @@ defmodule ElectricCli.Config do
|> Map.update!(:directories, &contract_directories(&1, root))
|> Map.update!(:environments, &contract_environments/1)

config_filepath =
root
|> filepath()
config_filepath = filepath(root)

with {:ok, json} <- Jason.encode(config, pretty: true),
:ok <- File.write(config_filepath, json <> "\n"),
Expand Down
2 changes: 1 addition & 1 deletion apps/electric_cli/lib/electric_cli/core.ex
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ defmodule ElectricCli.Core do
{:ok, %Manifest{} = manifest, []} <-
Migrations.hydrate_manifest(manifest, migrations_dir),
{:ok, dynamic_success_message} <- Sync.sync_migrations(manifest, environment),
{:ok, %Manifest{} = server_manifest} <- Api.get_server_migrations(app, env, true),
{:ok, %Manifest{} = server_manifest} <- Api.get_server_migrations(app, env, :satellite),
:ok <- Bundle.write(server_manifest, environment, :server, debug, output_dir) do
{:ok, dynamic_success_message}
end
Expand Down
Loading

0 comments on commit d038c95

Please sign in to comment.