luminus-framework/luminus

REPL instructions in migrations.html not working

winks opened this issue · 7 comments

winks commented

To interactively create a new migration, https://luminusweb.com/docs/migrations.html tells you to do this:

(mount.core/start  #'<app>.db.core/*db*)
(user/create-migration "add-users-table")

I can not get this to work. Fresh sample project created this week via lein new luminus foobar +postgres, then adjusting :database-url in dev-config.edn, the db connection is known to work via lein run.

This is what I get:

$ cd foobar
$ lein repl

user=> (mount.core/start #'foobar.db.core/*db*)
Execution error (ClassCastException) at foobar.db.core/eval13540$fn (core.clj:14).
class mount.core.DerefableState cannot be cast to class clojure.lang.IFn (mount.core.DerefableState is in unnamed module of loader clojure.lang.DynamicClassLoader @57540fd0; clojure.lang.IFn is in unnamed module of loader 'app')

### this is the error that confuses me

user=> (user/start)
2021-12-30 09:48:46,579 [nREPL-session-b1f4b012-2cd9-4cfa-87a4-e9f735c8e430] ERROR luminus.http-server - server failed to start on port: 3000 
java.lang.RuntimeException: java.net.BindException: Address already in use

# this is not the problem, I know it's running, but I was playing around a bit

user=> (user/create-migration "foo" )
nil

### nothing happened

user=> (mount.core/start #'foobar.db.core/*db*)
{:started []}

### no more error

user=> (user/create-migration "change-something" )
nil

### still nothing happened

Also the line before the mount.start reads:

(defstate ^:dynamic *db*
  :start (conman/connect! {:jdbc-url (env :database-url)})
  :stop (conman/disconnect! *db*))

whereas in the code it is currently

(defstate ^:dynamic *db*
  :start (if-let [jdbc-url (env :database-url)]
           (conman/connect! {:jdbc-url jdbc-url})
           (do
             (log/warn "database connection URL was not found, please set :database-url in your config, e.g: dev-config.edn")
             *db*))
  :stop (conman/disconnect! *db*))

and I can't tell if that's a simplified version by default, or if it has changed meanwhile, or something else

The problem is that your *db* connection is not being started until (user/start) is called. The address already in use error indicates that one of the resources defined using defstate is trying to start on a port that's currently being used. If you're getting nil output that should be fine, did you look if the file was created on the filesystem after running the command?

winks commented

The problem is that your db connection is not being started until (user/start) is called.

Yes, that was my original point, the docs tell you to do X, but you need to to Y which isn't pointed out

The address already in use error indicates that one of the resources defined using defstate is trying to start on a port that's currently being used.

Yes, that is the only part that was unsurprising :)

If you're getting nil output that should be fine, did you look if the file was created on the filesystem after running the command?

The first one failed (user/create-migration "foo" ) no migrations generated.

The second one succeeded (user/create-migration "change-something" ) but only after the undocumented call to user/start.

I'm mostly wondering if the version from the docs with just mount.core/start can be made to work (again?), as described.

Just to be clear, when you run (mount.core/start #'<app>.db.core/*db*) you replace <app> with the actual namespace from your app?

winks commented

Yes of course.

$ lein new luminus migtest +postgres
Generating a Luminus project.
$ cd migtest 
$ vi dev-config.edn  # for db credentials
$ find resources/migrations 
resources/migrations
resources/migrations/20211230150621-add-users-table.down.sql
resources/migrations/20211230150621-add-users-table.up.sql
$ lein repl
nREPL server started on port 33943 on host 127.0.0.1 - nrepl://127.0.0.1:33943
REPL-y 0.5.1, nREPL 0.9.0
Clojure 1.10.3
OpenJDK 64-Bit Server VM 11.0.13+8-Ubuntu-0ubuntu1.18.04
    Docs: (doc function-name-here)
          (find-doc "part-of-name-here")
  Source: (source function-name-here)
 Javadoc: (javadoc java-object-or-class-here)
    Exit: Control+D or (exit) or (quit)
 Results: Stored in vars *1, *2, *3, an exception in *e

user=> (mount.core/start #'migtest.db.core/*db*)
Execution error (ClassCastException) at migtest.db.core/eval13540$fn (core.clj:14).
class mount.core.DerefableState cannot be cast to class clojure.lang.IFn (mount.core.DerefableState is in unnamed module of loader clojure.lang.DynamicClassLoader @57540fd0; clojure.lang.IFn is in unnamed module of loader 'app')

Oh I see your problem, the issue is that *db* relies on env to get the database url. Since nothing is started by default you'd need to run (mount.core/start #'migtest.config/env #'migtest.db.core/*db*). I'll update the docs to make a note of that.

winks commented

Ah, that's the magic incantation that works. Thanks!

winks commented

Reopen, misclick.