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

[Feature] Ability to provide custom hierarchy to init method #81

Closed
kirillsalykin opened this issue Apr 17, 2020 · 6 comments
Closed

[Feature] Ability to provide custom hierarchy to init method #81

kirillsalykin opened this issue Apr 17, 2020 · 6 comments

Comments

@kirillsalykin
Copy link

kirillsalykin commented Apr 17, 2020

Consider this scenario:

There is a system described as

(def system-map
 {:adapter/jetty {:port 8080, :handler (ig/ref :handler/greet)}
   :data/store {:jdbc-url "some-yrl}
   :handler/greet {:name "Alice",  :data-store (ig/ref :data/store)}})

For development and production env I want :data/store to be some sql db - with init-key :sql/store.
But for test env I want it to be some mock (which just stores data in atom, for instance) -
with init-key :inmemory/store
(And obviously I don't want to use different system-maps).

It seems natural that I can specify that both keys (:sql/store and :inmemory/store) derived from the :data/store - but this leads to the exception because clojure cant decide which key to use for init-key multimethod.

As a solution, I propose to extend init fn so it accepts local hierarchy, where one can specify how the particular key should be initialised.

For instance, with mentioned system-map it may look like this:

(ig/init system-map (keys system-map) (-> (make-hierarchy) (derive :inmemory/store :data/store))

And during key building integrant just get all descendants of the :data/store and if there is no ambiguity - the descendant will be used.

what do you think?

UPD:

I've started the PR #80.

But I see conflicts with how composite keys now defined (they are also build with derive). Please advise how can I proceed.

Your feedback is much appreciated!

Thanks!

@weavejester
Copy link
Owner

weavejester commented Apr 17, 2020

It's an interesting idea, but why not just change the configuration to use the test key? The effect will be the same without the need to mess around with the hierarchy.

@kirillsalykin
Copy link
Author

It should be changed more than in one place, right?
Also as I mentioned - i dont want the system-map to be changed.

@weavejester
Copy link
Owner

It should be changed more than in one place, right?

What do you mean? You only need to change the keys you want to replace. Everything else, including references, can remain the same.

Also as I mentioned - i dont want the system-map to be changed.

Do you mean the configuration map? The system map is the return value of ig/init.

Also why don't you want it to be changed?

@kirillsalykin
Copy link
Author

What do you mean? You only need to change the keys you want to replace. Everything else, including references, can remain the same.

So, if I'll replace :data/store with :sql/store all refs to :data/store will be properly resolved?

(def system-map
 {:adapter/jetty {:port 8080, :handler (ig/ref :handler/greet)}
   :sql/store {:jdbc-url "some-yrl}
   :handler/greet {:name "Alice",  :data-store (ig/ref :data/store)}})

if so - it may solve my issues.

Do you mean the configuration map? The system map is the return value of ig/init.

Yes, sorry, I meant configuration map.

Also why don't you want it to be changed?

I think you want to use the same configuration map in tests as in prod.

@weavejester
Copy link
Owner

So, if I'll replace :data/store with :sql/store all refs to :data/store will be properly resolved?

Yes, that's right. A reference like #ig/ref :data/store will look for a key that derives from :data/store.

It's common practice to have both test and production services derive from the same base key, so that you can transparently swap in fake services for testing without altering any other part of the configuration.

I think you want to use the same configuration map in tests as in prod.

Whether you change the keys in the configuration, or change the hierarchy, the resulting system map is the same, and different to production.

My preference is to change the configuration directly, as not only is that simpler (as we don't have to worry about local hierarchies), but it also allows test services to be configured separately to production services.

For example, you might have a fake emailer service that writes to a file, and the filename could be part of the config:

{:fake/emailer {:filename "emails.log"}}

And in production:

{:real/emailer {:smtp "example.com"}}

@kirillsalykin
Copy link
Author

Makes sense.

Thanks for clarification!

Closing issue and PR.

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

No branches or pull requests

2 participants