Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ecto 3 support #61

Merged
merged 18 commits into from
Mar 3, 2019
Merged

Ecto 3 support #61

merged 18 commits into from
Mar 3, 2019

Conversation

abarr
Copy link

@abarr abarr commented Nov 6, 2018

Hi,

I am working on a project that we wanted to upgrade to Ecto 3.0.1. I have made changes to Triplex so we can continue development.

I could not find any guidance for submitting Pull Requests so I have followed the general conventions )However, this is my first OSS submission).

I have not updated the README as I am not sure how you want to reference eth changes.

I also could not get the tests to run outside of a project but they have passed when I have added it as a dependency to our project.

So far all use cases we used are working as expected. If I find any issues I will update.

I hope this helps.

Andrew

@mgiacomini
Copy link
Contributor

@abarr could you fix the tests? i will checkout this and try to run locally :)

@abarr
Copy link
Author

abarr commented Nov 6, 2018

@mgiacomini I am new to contributing to open source so please be patient ...

I had a look at the Travis log and it says that the tests are being run with a config of elixir 1.4.2. I had to upgrade Triplex to use elixir 1.6 so it can use Ecto 3. Are you able to change the Travis config?

@abarr
Copy link
Author

abarr commented Nov 6, 2018

I will also have a go at getting the tests running locally

@kapilpipaliya
Copy link

kapilpipaliya commented Nov 9, 2018

Triplex.create(tenant) can't run migrations, when inside Transaction. it says (invalid_schema_name) schema "foo" does not exist
but It created schema first like
CREATE SCHEMA "foo" []

If I run Triplex.create(tenant) outside transaction it work successfully.

you can test running: Repo.transaction(fn -> Triplex.create("foo") end)

@kapilpipaliya
Copy link

workaround is do not use Triplex.create("foo") in Transaction.

@mgiacomini
Copy link
Contributor

mgiacomini commented Nov 12, 2018

workaround is do not use Triplex.create("foo") in Transaction.

Yeah. I think the postgres doesn't support creating schemas/databases inside transactions, because we need to tell where it will run the operations, so if the schema/database doesn't exists it's not able to decide it.

@kapilpipaliya
Copy link

@mgiacomini but Repo.transaction(fn -> Triplex.create("foo") end) work with Ecto 2, so its already supported.

@mgiacomini
Copy link
Contributor

@kapilpipaliya humm, so I need a close look into this.

@rwngallego rwngallego mentioned this pull request Jan 21, 2019
@dhonig
Copy link

dhonig commented Jan 31, 2019

Any chance of this getting merged? I've just started a project using Ecto 3 and @abarr's work and would like to see Ecto 3 support added.

@churcho
Copy link

churcho commented Feb 20, 2019

Any chance on getting this track resolved? I am getting

(DBConnection.ConnectionError) connection not available and request was dropped from queue
 after 970ms. You can configure how long requests wait in the queue using 
:queue_target and :queue_interval` 

when I run Triplex tests on @abarr's branch as well.

kelvinst
kelvinst previously approved these changes Feb 22, 2019
@@ -27,7 +27,7 @@ defmodule Mix.Tasks.Triplex.Mysql.Install do
Mix.raise "the tenant table only makes sense for MySQL repositories"
end

path = Path.relative_to(Mix.Ecto.migrations_path(repo),
path = Path.relative_to(Mix.EctoSQL.ensure_migrations_path(repo),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, I see there is no more a migrations_path function on the new ecto_sql lib, I think it's cool anyway.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is private API and shouldn't be used by external tools. Use Ecto.Migrator.migrations_path/1 instead.

lib/triplex.ex Outdated
config = repo.config()
priv = config[:priv] || "priv/#{repo |> Module.split |> List.last |> Macro.underscore}"
app = Keyword.fetch!(config, :otp_app)
Application.app_dir(app, Path.join(priv, "tenant_migrations"))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure of the utility of this refactor here. Does the repo config changed to a map? I mean, I get that one could be confuse with the change of main value on the pipelines, is that the reason you did it?

PS.: Just out of curiosity, I think it got more readable anyway, so let's leave it your way.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can use https://hexdocs.pm/ecto_sql/3.0.5/Ecto.Migrator.html#migrations_path/1 and just replace last element with tenant_migrations.

@coveralls
Copy link

coveralls commented Feb 22, 2019

Coverage Status

Coverage increased (+10.5%) to 99.507% when pulling e62ceb2 on abarr:ecto_3_support into f49c43f on ateliware:master.

@kelvinst
Copy link
Contributor

I got what's the problem with transaction: in Ecto 3 they changed the execution of migrations to run them on another process, and by default, when you run a transaction, it links the connection to the current process, and if you start another process inside of it, that process will not use the same connection, so everything done inside the other process will be in another transaction and therefore not get anything done by the original one.

I'm checking if there is a way to solve that.

@kelvinst
Copy link
Contributor

@abarr I merged master to your branch and that broke the tests, so I did some changes to make the tests pass. You can review them on my commits for your branch.

@kapilpipaliya About the transaction problem, I explained on the previous comment. Created the issue
elixir-ecto/ecto_sql#84 for ecto people, since the only solution I see would have to add an option for Ecto.Migrator, as for how it is now, there is no way to run Triplex.create inside a transaction, so we will probably not release this any time soon, unfortunately.

@kelvinst
Copy link
Contributor

So, José answered the issue and he would not like to change what we need on ecto, because it would add too much complexity there. So I had another idea, which will maybe solve #47 too! Instead of running migrations when creating tenants, use a structure.sql dump file for it. It's a little bit more complex, but I guess it will pay off because it will make it a lot faster too.


for prefix <- Triplex.all(repo) do
new_args = delete_unwanted_args(args, [])
Mix.Task.run("ecto.migrate", ["--repo", inspect(repo), "--prefix", prefix | new_args])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I totally forgot this don't work. :(

This way it does not run the migrations inside the tenant_migrations folder, and yes on migrations folder.

Maybe we should change that too, for the new version of triplex. Instead of having a tenant_migrations folder, we could put all migrations inside migrations and if someone would not like to filter out migrations on public or tenant schemas one could do somthing like:

def change do
  if Triplex.reserved_tenant?(prefix()) do
    # run your public schema migration
  else
    # run your tenant schema migration
  end
end

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mgiacomini what do you think? We would then totally break the current working version. The dump change would break it anyways, but the solution for that would be just to run a triplex.dump, this one will take a lot more trouble for users to port to the new version, since they would have to add an if inside all of their tenant migrations.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The other solution would be rolling back to the old way of running migrations, but that's a trouble for us then, since any change on the migration stuff on ecto's side, we would have to change ours too.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, looks like the change to use only one migrations folder is not possible at all, and we will have to make it work with tenant_migrations. I'll delete my commits til now since they are all in favor of the idea of using ecto.migrate --prefix, and that will not be possible at all.

Copy link

@churcho churcho Mar 1, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kelvinst was the migration fixed?
I can't run mix triplex.migrate

How does one pass a default tenant name to migrations to ensure migrations are run for a potentially pre-existing tenant(s)?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kelvinst was the migration fixed?
I can't run mix triplex.migrate

Where are you running them? Is it your project? Are you pointing the dep to this PR branch?

How does one pass a default tenant name to migrations to ensure migrations are run for a potentially pre-existing tenant(s)?

That's pretty much what mix triplex.migrate does. It runs all the migrations for all the pre-existing tenants, not for new ones. Migration for the new ones a ran when you call Triplex.create

lib/triplex.ex Outdated
config = repo.config()
priv = config[:priv] || "priv/#{repo |> Module.split |> List.last |> Macro.underscore}"
app = Keyword.fetch!(config, :otp_app)
Application.app_dir(app, Path.join(priv, "tenant_migrations"))
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can use https://hexdocs.pm/ecto_sql/3.0.5/Ecto.Migrator.html#migrations_path/1 and just replace last element with tenant_migrations.

mix.exs Outdated Show resolved Hide resolved
config/test.exs Outdated Show resolved Hide resolved
@@ -27,7 +27,7 @@ defmodule Mix.Tasks.Triplex.Mysql.Install do
Mix.raise "the tenant table only makes sense for MySQL repositories"
end

path = Path.relative_to(Mix.Ecto.migrations_path(repo),
path = Path.relative_to(Mix.EctoSQL.ensure_migrations_path(repo),
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is private API and shouldn't be used by external tools. Use Ecto.Migrator.migrations_path/1 instead.

lib/mix/triplex.ex Outdated Show resolved Hide resolved
lib/mix/tasks/triplex.rollback.ex Outdated Show resolved Hide resolved
@kelvinst
Copy link
Contributor

@hauleth thanks for the review. I knew some of the functions are private API there. I switched the ones I could to other versions of it, but in some cases that's not possible because the public API is not the same, as for source_priv_dir for example, it returns the source code path, and Ecto.Migrator.migration_path returns it from inside the _build dir. I didn't dig into it if we could really change that, but as it is not the intention of this PR, I have created another issue for it: #62

@hauleth
Copy link

hauleth commented Feb 26, 2019

@kelvinst you can check Mix.EctoSQL source and copy respective functions as these should use only public API of Ecto.

@kelvinst
Copy link
Contributor

@kapilpipaliya and @abarr I had another idea on the transaction problem: we will make it clear we don't support that on the documentation, but will also give a way for users to guarantee the schema will get dropped if some of their stuff fails. Check 033d6d4 for details.

@kelvinst
Copy link
Contributor

@kelvinst you can check Mix.EctoSQL source and copy respective functions as these should use only public API of Ecto.

Yep, I know, will do that on another PR though, since this is an old problem and there is already too much stuff on this PR.

@kelvinst
Copy link
Contributor

@churcho can you test this PR again? Maybe it got solved by my fixes for it.

Also, changing most imports to aliases
@kelvinst
Copy link
Contributor

@hauleth at the end of the day I also did what you suggested, copied the code from Mix.EctoSQL.

This PR can be considered done now, I'm only doing some final touches for contributing and changelog files, and then I'll merge and release a new version!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants