beginners

Getting started with Clojure/ClojureScript? Welcome! Also try: https://ask.clojure.org. Check out resources at https://gist.github.com/yogthos/be323be0361c589570a6da4ccc85f58f.
piyer 2021-04-27T04:24:41.150900Z

I am trying to figureout how to use honeysql DSL with migratus. https://github.com/yogthos/migratus#modify-sql-fn has an option to format the SQL but I have to write edn style dsl and name that as *.sql.

seancorfield 2021-04-27T04:56:53.152400Z

@munichlinux You're beyond the edge of what these libraries are intended to provide -- but it's an interesting idea. In general, I don't find a DSL worthwhile for DDL for SQL migrations but I'm interested to hear what value you are getting from it?

piyer 2021-04-27T16:43:26.165600Z

@seancorfield Thank you. 1. A level of abstraction over the database (less important, in real use I never had to swap the database). 2. I kinda like the brevity of DDL that makes it really simple rather than writing a raw SQL.. I use to write nodejs for web. I used knex , here is an example:

const tableName = 'session';

exports.up = (knex) =>
  knex.schema.createTable(tableName, (table) => {
    table.string('sid').primary().notNullable();
    table.json('sess').notNullable();
    table.timestamp('expire').notNullable();
    table.timestamp('created_at').defaultTo(knex.fn.now());
    table.timestamp('updated_at').defaultTo(knex.fn.now());
  });

exports.down = (knex) => knex.schema.dropTable(tableName);

seancorfield 2021-04-27T17:14:08.165800Z

Hmm, I find plain SQL easier to read but I can see how, with a few helper functions for common columns or column types, you could use more concise code to describe tables… and migratus does let you use code-based migrations although the format is a bit verbose. Maybe @yogthos would be open to providing a more concise version that leveraged HoneySQL to format the result of calling DDL-generating functions? Not sure what that would look like tho’… just spit-balling an idea…

yogthos 2021-04-27T17:27:23.166Z

I'd be open to making it easier using HoneySQL, it shouldn't be too hard to add a layer that could parse HoneySQL markup and generate SQL strings that would then be consumed. Could leverage existing edn migrations. Currently, there are :up-fn and :down-fn keys, so perhaps could have :up-honey and :down-honey that would point to HoneySQL markup.

seancorfield 2021-04-27T17:43:53.166200Z

The “benefits” would likely come from having helper functions that generated common DDL fragments so it would need to be actual code — similar to how the EDN/code migrations work today — except that the functions would produce the ["SQL"] vector that migratus would then run honey.sql/format on.

seancorfield 2021-04-27T17:44:53.166400Z

Allowing :up-fn / :up-honey / etc to be a fully-qualified symbol so the :ns could be omitted might also be nice.

seancorfield 2021-04-27T17:45:53.166600Z

And there would need to be some way to specify options for the honey.sql/format call I guess, either globally, or on a per-migration basis.

seancorfield 2021-04-27T17:48:03.166800Z

I mean, maybe there’s also an avenue for providing HoneySQL DSL as EDN but I don’t think that’s as valuable as having functions to generate the ["SQL"] vector — the DSL is pretty verbose for DDL stuff, especially table/column specs.

piyer 2021-04-27T19:13:21.167700Z

@yogthos IMO, Here are my two options. 1. Let people write a clj file for migration. It will be foo-123.up.clj foo-123.down.clj 2. you already have a way to run a preprocessor, I can say the default preprocessor is SQL or honeysql or tomorrow's new thing. I personally like 1. As long as I have a public method up that returns string, I can do whatever I want.

piyer 2021-04-27T19:13:54.167900Z

what do you guys thing?

seancorfield 2021-04-27T19:17:11.168100Z

@munichlinux The .edn version is effectively 1. It’s declarative and based on a specific function for up and another for down.

seancorfield 2021-04-27T19:18:00.168300Z

How would an arbitrary .clj file even be used? The namespace should match the filename for a start so you can’t have . in that part.

yogthos 2021-04-27T19:20:27.169400Z

right, the current .edn version is seems very similar to option 1, it sounds like the biggest win would be in having a DSL for describing DDL fragments

piyer 2021-04-27T19:21:39.171Z

@seancorfield since these files are generated. we can generate migrations.123 as the ns.

piyer 2021-04-27T19:22:45.171600Z

I am trying to keep this independent of edn or honeysql.

piyer 2021-04-27T19:26:23.174300Z

(-> (all-ns)
     (filter (starts with migrations)
      (sort by timestamp)
      (doseq [ns all-ns]
          (ns/up)))

seancorfield 2021-04-27T19:26:29.174600Z

@munichlinux The migrations need to follow a specific naming patterns so they can be run in order and all checked off in the tracking table. (right @yogthos)

seancorfield 2021-04-27T19:26:52.174900Z

Oh, are you proposing not even using migratus and writing your own custom migrations stuff?

piyer 2021-04-27T19:28:12.175200Z

nope, I proposing to use migratus . I was just outlining how the clj will work.

piyer 2021-04-27T19:29:32.177100Z

ATM, migratus can generate the file names. I propose to generate the file with an ns if we have to take the clj approach.

yogthos 2021-04-27T19:29:37.177400Z

yeah, migratus needs to have a numeric pattern in the migration name to track the order of migrations

yogthos 2021-04-27T19:30:12.179200Z

it might also make sense to make a separate library that leverages migratus for this

Aron 2021-04-27T05:16:47.153500Z

I am getting a

Encountered error when macroexpanding cljs.core.async/go.
Encountered error when macroexpanding cljs.core/loop.
Syntax error macroexpanding.
And I have no idea what to do about it, it should work as far as I understand it. I tried to wrap it in macroexpand which expanded it but where to go from there? It looks fine.

alexmiller 2021-04-27T05:25:22.154300Z

I don't know what this might be, but generally it's helpful to include the code reproducing the problem

Aron 2021-04-27T05:28:17.154800Z

I am trying to recreate the minimal example.

Aron 2021-04-27T05:33:05.155500Z

I think I got it, I had <! in my recur, I now put that inside the loop with a let binding and it doesn't say it's bad

Aron 2021-04-27T05:35:44.156100Z

Why is it that I only get these ideas after publicly asking for help? I tried to figure out for hours alone.

2021-04-27T05:38:43.156400Z

Rubber ducking

😂 1
☝️ 4
sova-soars-the-sora 2021-04-27T18:30:44.167300Z

same here! i will often type out a question to the slack or to stack overflow and just typing it out to explain it often gives me more insight into the issue. First I hear of "rubber ducking" now I might have to get a comically large one for the desk...

Aron 2021-04-27T05:41:13.158400Z

reasonable guess, I guess 🙂 although this particular time it felt different. I already removed most of the code before writing and I just randomly figured maybe it's the <! in recur

2021-04-27T05:52:47.158600Z

A <! In a recur should in theory work fine, but the go macro on the cljs side of core.async isn't as a robust, and sometimes the way cljs macroexpands code makes it almost impossible for the go macro to rewrite it (some macros expand to a blob of js which the go macro can't rewrite)

2021-04-27T05:54:35.158700Z

So you may have hit a bug in core.async, an annoying tricky bit in how core.async and clojurescript interact, or actually done something incorrectly yourself

Aron 2021-04-27T05:56:08.159600Z

If it happens lots I would guess other than the last and provide actual examples, right now I am just extremely happy I can move on. Need to finish this stuff and start other things because ... well, life.

Pablo 2021-04-27T19:19:03.169Z

Hello everyone, I have a doubt. Can specs be defined such that only their generators are included in the development environment? not in production

seancorfield 2021-04-27T19:21:36.170800Z

@pablog Do you mean custom generators? Those are provided as functions, so they are only called if you actually do something generative to a Spec. And you can write functions such that they only load their dependencies if they are called so you can omit those dependencies from a production build if you want.

seancorfield 2021-04-27T19:21:57.171500Z

We have generators that depend on test.check which is only available at dev/test time for us.

Pablo 2021-04-27T19:26:41.174800Z

Yes, custom generators. For example, if I define something like:

(s/def ::name
  (s/with-gen string?
    #(clojure.test.check.generators/elements #{"John" "Marie"})))
And in my application I use :name in order to validate some data, I don’t want that clojure.test.check.generators stuff gets loaded on production. Even compiled and packed.

Pablo 2021-04-27T19:29:20.176400Z

The problem is that spec.alpha uses an older version of test.check

seancorfield 2021-04-27T19:29:31.176800Z

(s/def ::name
  (s/with-gen string?
    #((requiring-resolve 'clojure.test.check.generators/elements) #{"John" "Marie"})))

2021-04-27T19:29:44.178Z

isn't it the case that you can use clojure.spec.gen.alpha safely, and if you call it it auto-loads test.check?

2021-04-27T19:30:10.179Z

IOW it errors if used and check.test isn't provided, but otherwise compiles without complaint

alexmiller 2021-04-27T19:30:11.179100Z

Yes

seancorfield 2021-04-27T19:30:13.179400Z

Right, but @pablog wants a more up-to-date test.check

2021-04-27T19:30:29.179900Z

then depend on the version you want?

seancorfield 2021-04-27T19:30:31.180100Z

(which it would use if it was specified as a test dep, right?)

alexmiller 2021-04-27T19:30:44.180500Z

You can specify a dep on a newer version if you like

alexmiller 2021-04-27T19:31:40.180900Z

spec just (dyna)loads what's on the classpath

seancorfield 2021-04-27T19:35:22.182200Z

Yeah, the key thing is not referring to clojure.test.check statically in your code. Use requiring-resolve and it won’t try to load/compile it unless that code is evaluated.

Pablo 2021-04-27T19:45:49.184Z

Sorry, I think that I missed some important fact. How can I use test.check/let ?

Pablo 2021-04-27T19:46:42.184400Z

dynamically

alexmiller 2021-04-27T19:47:03.184900Z

you can't do that with spec

2021-04-27T19:47:04.185Z

the simplest thing is to only use it in code that is run locally, and just require test.check

2021-04-27T19:47:31.185400Z

the file referencing test.check can be kept out of your jar entirely

Pablo 2021-04-27T19:51:57.185900Z

Ok, thanks a lot! 🙂

2021-04-27T20:14:43.187400Z

test check's let is a macro that expands from something like (check/let [a b] c) to something like (check/bind b (fn [a] c)) and bind is a function, so using it dynamically is a lot easier than a macro

1
2021-04-27T20:16:22.188200Z

(test.check generators are a monad, and check/let is a monad comprehension for it)

2021-04-27T20:25:38.188700Z

bind is even one of the "lazy combinators" that spec sets up https://github.com/clojure/spec.alpha/blob/master/src/main/clojure/clojure/spec/gen/alpha.clj#L109-L111