duct

2019-02-07T12:52:03.169200Z

How can I set a dev-only JDBC database url when using the duct sql module? My dev.edn looks as follows:

{:duct.database.sql/hikaricp
 {:jdbc-database-url "jdbc:<postgresql://postgres:postgres@localhost:5432/postgres%22|postgresql://postgres:postgres@localhost:5432/postgres">}}
My base config.edn includes the following:
:duct.module/sql {}
When I switch to dev in REPL and run (go), however, I see the following:
Execution error (IllegalArgumentException) at clojure.java.jdbc/get-connection (jdbc.clj:292).
db-spec null is missing a required parameter
I will take any suggestions on how to resolve this - I do not want to simply slap the url directly into the module config because that URL is dynamic across modules.

2019-02-07T13:19:54.170800Z

So it seems that only the base profile key is loaded, hence the dev profile is not being expanded at all.

2019-02-07T13:20:29.171600Z

I don't know how to resolve this. I followed the documentation steps to the letter but it does not work for me. Are the docs out of date?

2019-02-07T13:21:29.173100Z

(doto (read-config) ig/load-namespaces)
=&gt;
#:duct.profile{:base {:duct.profile/prod {},
                      :duct.profile/dev {:duct.core/environment :development,
                                         :duct.database.sql/hikaricp {:jdbc-database-url "jdbc:<postgresql://postgres:postgres@localhost:5432/postgres%22|postgresql://postgres:postgres@localhost:5432/postgres">}},
                      :duct.profile/local {},
                      :duct.module/logging {},
                      :duct.module/sql {},
                      :duct.module.web/api {},
                      :duct.core/project-ns person-ld-api}}

2019-02-07T13:21:31.173300Z

@sgerguri I’m not sure if it helps you but I was able to fix the connection issue by writing dev.edn like : `{:duct.database/sql {:connection-uri “jdbc:<postgresql://localhost/db_dev>” :username “postgres_user” :password “db_pw”} } `

2019-02-07T13:22:18.173800Z

But if I try to build it, I get basically the same thing back:

(duct/build-config (doto (read-config) ig/load-namespaces) [:duct.profile/dev])
=&gt;
{:duct.profile/prod {},
 :duct.profile/dev {:duct.core/environment :development,
                    :duct.database.sql/hikaricp {:jdbc-database-url "jdbc:<postgresql://postgres:postgres@localhost:5432/postgres%22|postgresql://postgres:postgres@localhost:5432/postgres">}},
 :duct.profile/local {},
 :duct.module/logging {},
 :duct.module/sql {},
 :duct.module.web/api {},
 :duct.core/project-ns person-ld-api}

2019-02-07T13:23:21.174400Z

My base config.edn looks as follows:

{:duct.profile/base
 {:duct.core/project-ns person-ld-api

  :duct.profile/dev     #duct/include "dev"
  :duct.profile/local   #duct/include "local"
  :duct.profile/prod    {}

  :duct.module/logging  {}
  :duct.module.web/api  {}
  :duct.module/sql      {}
  }
 }

2019-02-07T14:43:22.176500Z

A measure of progress - this seems to work just fine on another duct project that I just created. The difference between these two repos is probably just a week and a half, tops. I checked the configs, versions of dependencies etc. and I don't see any effective difference, yet the earlier repo simply fails to properly initialise the configuration, while the latter one succeeds. Any hints on what I could be missing?

2019-02-07T15:11:21.177200Z

:jdbc-database-url => :jdbc-url?

2019-02-07T15:12:23.178300Z

Right, something that is not showing in this snippet is that I am using migrations, specifically:

:duct.migrator/ragtime
 {:migrations [#ig/ref :person-ld-api/create-database
               #ig/ref :person-ld-api/create-table]}

 [:duct.migrator.ragtime/sql :person-ld-api/create-database]
 #duct/include "migrations/001-create-db.edn"

 [:duct.migrator.ragtime/sql :person-ld-api/create-table]
 #duct/include "migrations/002-create-table.edn"
The above is in my config.edn and is what breaks it, basically.

2019-02-07T15:12:52.179200Z

I guess I am using #duct/include incorrectly - I want to simply refer to another EDN file and have it be included in here.

2019-02-07T15:13:13.179800Z

True, @jahson - I have since fixed that, however, and the migrations are what break it.

2019-02-07T15:14:25.181500Z

It seems that if one uses duct with ragtime one is effectively forced out of the edn migration files - either everything ends up being included in the config.edn file, or one has to make sql up/down files and refer to those. Neither feels like a particularly great solution.

2019-02-07T15:16:33.183200Z

:duct.migrator/ragtime
 {:database #ig/ref :xxx.database/master
  :migrations-table "xxx_migrations"
  :migrations [#ig/ref :xxx.migration/create-table1]}

[:duct.migrator.ragtime/sql :xxx.migration/create-table1]
{:up ["CREATE TABLE table1;
 :down ["DROP TABLE table1"]}
Are these migrations look like this?

2019-02-07T15:17:28.184600Z

The files I am referring to via the #duct/include have basically

{:up ["CREATE TABLE table1;"]
 :down ["DROP TABLE table1;"]}
in them.

2019-02-07T15:17:52.185400Z

I just thought I could make config.edn more concise by simply referring to these through that include.

2019-02-07T15:18:50.186500Z

I think there is nothing wrong with #duct/include

2019-02-07T15:19:13.186900Z

What is happening? Exceptions?

2019-02-07T15:19:24.187100Z

(prep)
Execution error (IllegalArgumentException) at clojure.java.jdbc/get-connection (jdbc.clj:292).
db-spec null is missing a required parameter

2019-02-07T15:20:01.187300Z

*e?

2019-02-07T15:21:26.187800Z

ExceptionInfo Error on key :duct.migrator/ragtime when building system 
Caused by:
IllegalArgumentException db-spec null is missing a required parameter
	clojure.java.jdbc/get-connection (jdbc.clj:292)
	clojure.java.jdbc/get-connection (jdbc.clj:176)
	ragtime.jdbc/get-table-metadata (jdbc.clj:27)
	ragtime.jdbc/get-table-metadata (jdbc.clj:24)
	ragtime.jdbc/table-exists? (jdbc.clj:38)
	ragtime.jdbc/table-exists? (jdbc.clj:36)
	ragtime.jdbc/ensure-migrations-table-exists (jdbc.clj:41)
	ragtime.jdbc/ensure-migrations-table-exists (jdbc.clj:40)
	ragtime.jdbc.SqlDatabase (jdbc.clj:61)
	ragtime.core/migrate-all (core.clj:57)
	ragtime.core/migrate-all (core.clj:33)
	duct.migrator.ragtime/migrate (ragtime.clj:76)

2019-02-07T15:24:07.188700Z

Interesting. I thik the issue is here https://github.com/duct-framework/migrator.ragtime/blob/master/src/duct/migrator/ragtime.clj#L63 It is happening because you should explicitly set :database I think.

2019-02-07T15:26:04.190200Z

{:duct.migrator/ragtime
 {:database   #ig/ref :duct.database/sql
  :logger     #ig/ref :duct/logger
  :strategy   :rebase
  :migrations [#ig/ref :foo.migration/create-foo-table]}}
Looks like you could just copy this from README.

2019-02-07T15:26:06.190400Z

I'm not sure that's it - I have database settings in my dev.edn.

2019-02-07T15:26:24.190700Z

I am using the sql duct module, see https://github.com/duct-framework/module.sql/blob/master/src/duct/module/sql.clj#L23.

2019-02-07T15:26:48.191400Z

My dev.edn looks as follows:

{:duct.database/sql
 {:connection-uri "jdbc:<postgresql://localhost:5432/postgres>"
  :username "PLACEHOLDER"
  :password "PLACEHOLDER"}}

2019-02-07T15:26:54.191600Z

You should provide :database for :duct.migrator/ragtime

2019-02-07T15:27:10.192Z

Yes - and I am through the dev profile.

2019-02-07T15:27:28.192400Z

That section is demoted in the module, so it gets overriden if there is a value for it.

2019-02-07T15:30:14.194400Z

Can you try to use an explicit :database to check if it will work?

2019-02-07T15:35:35.194800Z

I can - will update here later after I've tried.

2019-02-07T15:49:03.196200Z

Sorry if I sound a little bit rude — I not a native nor fluent english speaker.

2019-02-07T15:50:17.197500Z

Not at all - and I hope I did not come across that way either. I am just trying it out.

2019-02-07T15:50:49.197800Z

Hi, can I help in any way?

2019-02-07T15:50:57.198Z

Ah, the man himself!

2019-02-07T15:51:07.198300Z

Yes please, let me summarise.

2019-02-07T15:51:32.199Z

Basically, I set up a duct project with DB and routes, and was struggling to get the DB layer set up.

2019-02-07T15:51:58.199600Z

I set the project up again and am seeing success in instantiating hikari but the moment I specify some DB migrations it all blows up.

2019-02-07T15:53:01.201200Z

Could you post your config file, and the exception that occurs?

2019-02-07T15:53:53.201600Z

Contents of config.edn:

{:duct.profile/base
 {:duct.core/project-ns ld-api

  :duct.router/cascading
  []}

 :duct.profile/dev   #duct/include "dev"
 :duct.profile/local #duct/include "local"
 :duct.profile/prod  {}

 :duct.module/logging {}
 :duct.module.web/api {}
 :duct.module/sql {}

 ;; == DB migrations ==

 :duct.migrator/ragtime
 {:migrations [#ig/ref :ld-api/create-database
               #ig/ref :ld-api/create-table]}

 [:duct.migrator.ragtime/sql :ld-api/create-database]
 #duct/include "migrations/001-create-db.edn"

 [:duct.migrator.ragtime/sql :ld-api/create-table]
 #duct/include "migrations/002-create-table.edn"
 }

2019-02-07T15:54:12.201900Z

Contents of dev.edn:

{:duct.database/sql
 {:jdbc-url "jdbc:<postgresql://localhost:5432/postgres>"
  :username "PLACEHOLDER"
  :password "PLACEHOLDER"}}

2019-02-07T15:55:28.202200Z

Error:

(prep)
Execution error (IllegalArgumentException) at clojure.java.jdbc/get-connection (jdbc.clj:292).
db-spec null is missing a required parameter

2019-02-07T15:55:51.202700Z

The above happens when calling (prep) after calling (dev).

2019-02-07T15:56:34.204Z

Hm. What happens if you change :duct.database/sql to :duct.database.sql/hikaricp in your dev.edn?

2019-02-07T15:56:51.204200Z

The same.

2019-02-07T15:57:34.204600Z

Well at least that's consistent 🙂

2019-02-07T15:58:01.205300Z

Oh, I see a problem.

2019-02-07T15:58:05.205500Z

True, though that provides little comfort to me. 😄

2019-02-07T15:58:24.205900Z

Your migrator keys are outside the base profile.

2019-02-07T15:59:06.206600Z

You should dump them under :duct.profile/base, or create a new profile for them.

2019-02-07T15:59:16.206900Z

🤦 :picard-facepalm:

2019-02-07T16:00:04.207900Z

It's an easy mistake to make, because in older versions that would have worked. But there were too many issues with putting modules and non-modules in the same configuration.

2019-02-07T16:00:16.208300Z

So non-module (component) keys need to be under a profile.

2019-02-07T16:00:30.208700Z

Which is just a module that merges its contents into the configuration.

2019-02-07T16:01:17.209100Z

Unfortunately, now the config isn't being expanded properly.

2019-02-07T16:02:12.209500Z

(pprint config)
{[:duct.migrator.ragtime/sql :ld-api/create-person-table] {:up ["CREATE TABLE person (...);"],
                                                           :down ["DROP TABLE person;"]},
 :duct.profile/prod {:duct.core/requires #ig/refset :duct.profile/base,
                     :duct.core/environment :production},
 :duct.profile/dev {:duct.database.sql/hikaricp {:jdbc-url "jdbc:<postgresql://localhost:5432/postgres>",
                                                 :username "PLACEHOLDER",
                                                 :password "PLACEHOLDER"},
                    :duct.core/requires #ig/refset :duct.profile/base,
                    :duct.core/environment :development},
 :duct.migrator/ragtime {:migrations [#ig/ref :ld-api/create-database
                                      #ig/ref :ld-api/create-person-table]},
 :duct.router/cascading [],
 :duct.profile/local {:duct.core/requires #ig/refset :duct.profile/base},
 :duct.module/logging {:duct.core/requires #ig/refset :duct/profile},
 :duct.module/sql {:duct.core/requires #ig/refset :duct/profile},
 [:duct.migrator.ragtime/sql :ld-api/create-database] {:up ["CREATE DATABASE ld;"],
                                                       :down ["DROP DATABASE ld;"]},
 :duct.module.web/api {:duct.core/requires #ig/refset :duct/profile},
 :duct.core/project-ns ld-api}

2019-02-07T16:03:24.210100Z

That looks pretty mixed up... sorry, can you post your config.edn again?

2019-02-07T16:03:57.210400Z

{:duct.profile/base
 {:duct.core/project-ns ld-api

  :duct.router/cascading
                        []

  :duct.profile/dev     #duct/include "dev"
  :duct.profile/local   #duct/include "local"
  :duct.profile/prod    {}

  :duct.module/logging  {}
  :duct.module.web/api  {}
  :duct.module/sql      {}

  ;; == DB migrations ==

  :duct.migrator/ragtime
                        {:migrations [#ig/ref :ld-api/create-database
                                      #ig/ref :ld-api/create-person-table]}

  [:duct.migrator.ragtime/sql :ld-api/create-database]
                        #duct/include "migrations/001-create-db.edn"

  [:duct.migrator.ragtime/sql :ld-api/create-person-table]
                        #duct/include "migrations/002-create-person-table.edn"}
 }

2019-02-07T16:04:42.211300Z

Right. So you need to put component keys in profiles, module keys outside.

2019-02-07T16:05:46.212300Z

So:

{:duct.profile/base
 {:duct.core/project-ns ld-api
  :duct.router/cascading []

  :duct.migrator/ragtime
  {:migrations [#ig/ref :ld-api/create-database
                #ig/ref :ld-api/create-person-table]}

  [:duct.migrator.ragtime/sql :ld-api/create-database]
  #duct/include "migrations/001-create-db.edn"

  [:duct.migrator.ragtime/sql :ld-api/create-person-table]
  #duct/include "migrations/002-create-person-table.edn"}

 :duct.profile/dev     #duct/include "dev"
 :duct.profile/local   #duct/include "local"
 :duct.profile/prod    {}

 :duct.module/logging  {}
 :duct.module.web/api  {}
 :duct.module/sql      {}}

2019-02-07T16:07:05.213300Z

Ah, should've paid closer attention to https://github.com/duct-framework/docs/blob/master/GUIDE.rst. I went by what the READMEs and Wiki of duct framework and modules said, and mashed it up together based on that.

2019-02-07T16:07:31.213900Z

I'm working on some better docs that should make things clearer

2019-02-07T16:07:48.214600Z

Happy to help out once I've wrapped my head around stuff comfortably. So I have a question.

2019-02-07T16:07:54.214900Z

Sure

2019-02-07T16:09:01.215200Z

What if I want to override some component-level stuff from a non-base profile?

2019-02-07T16:09:17.215500Z

Technically, the module keys are still part of the base profile.

2019-02-07T16:09:41.216100Z

So does that mean that components can go into any profile (nested in base) and it will all work, right?

2019-02-07T16:11:28.218300Z

Can you give an example of what you mean?

2019-02-07T16:12:47.219700Z

For example, could my dev.edn file look like the following?

{:duct.database.sql/hikaricp
 {:jdbc-url "jdbc:<postgresql://localhost:5432/postgres>"
  :username "postgres"
  :password "postgres"}

:duct.migrator/ragtime
{:migrations [...]}

...
}

2019-02-07T16:13:11.219900Z

Yes, that's right.

2019-02-07T16:13:45.220700Z

Perfect, that makes sense now.

2019-02-07T16:14:01.221Z

The only things that currently can't be put in profiles are modules.

2019-02-07T16:15:13.222400Z

Thanks a lot, James. I might try my hand at a few PRs that hopefully clear up how things should be used now that I have a better understanding of it.

2019-02-07T16:15:34.222800Z

No problem. Let me know if you have any more questions.