Sharing code in an umbrella application

Lets say I have an umbrella application that has one application that has common code.


app_shared is common code that can be used by both app_a and app_b.

A common use case is shared code that will manage users for example. Both app_a and app_b have their own DBs and users.

How do we configure the Ecto Repo such that app_shared can use the right repo?

If we configure the repo in the config.exs, for example, in app_a

config :app_shared, ecto_repo: AppA.Repo

Similarly, for app_b

config :app_shared, ecto_repo: AppB.Repo

But that won’t work because app_b will override the one set in app_a config.exs.

Short of passing in the repo to app_shared on every function call from app_a or app_b, can anything else be done? Any macro magic that might help?

Could you relegate persistence to app_a and app_b?

@wzph - Not sure that that means. In terms of code?

Yeah, basically have a and b own their respective Ecto.Repos, then any shared data manipulation can be extracted to shared. In other words, can you avoid hitting the db from app_shared?

Most of the api in shared is simple - get_user_by_id, get_user_by_name etc. There is nothing complicated to extract except connect to the repo and do its thing. All I can think with my limited experience in Elixir is to pass in the repo from each app on every function call. Beyond that, there could be things that could be done in a smart way - polymorphism, figuring out the calling app somehow and having a central genserver provide the right repo. The problem though is, how would the shared app function know “who” is calling without explicitly telling it on each function invocation? How would shared_app know whether app_a is calling it or app_b is calling it. If there is a way to do it then that would solve the problem. I don’t know of a way.

I don’t know the answer to this myself, but if you create a __using__ macro in module A and then use that module in module B, can you access one of B’s constants from the code in __using__? If so, you could just define a constant in the modules that use module A, which A could reference to get the repo.

Often in situations where you have multiple apps in the umbrella that depend on the same database I opt to break out another app, which I often call db that acts as a single place to contain migrations and also repository configuration. Then you can depend on this db app in app_a / app_b and app_shared.

@cjbell - The situation is slightly different here. Its different db in the different apps (app_a and app_b) with some shared code (app_shared). I was trying to avoid passing in the repo into the shared code on every function call from app_a and app_b. I can’t seem to think of a way. Macros perhaps - but all of shared code should be built with macros then and used in app_a and app_b. There isn’t a way to configure app_shared to say - if you are app_a, then use repo_a and if you are app_b, then use repo_b. Since this information is known upfront and we don’t have to wait till runtime to know it, it would be nice if there was a way to figure out somehow which repo to use in app_shared depending on the app making the function call.