Erlquery - compile query dsl's into erlang modules

I made a rebar plugin to precompile ‘erlquery’ files into erlang modules.

erlquery files are meant to feel like erlang modules. Inside the functions of the modules are the raw queries for whatever database dsl you are using. Calling these functions in erlang will trigger the query to your database using whatever configured query executor specified.

My motivation for making this tool was being able to write raw sql queries without string literals. raw queries are powerful but they are not aesthetically pleasing in erlang and can be error prone.

I have published erlquery to hex and have used it for a few small projects.

You can read more about erlquery in the links in below.

Links:
erlquery
rebar3_erlquery
blog post

5 Likes

Thank you for sharing!

I also tend to use a similar approach in my projects, although a bit different: I load the queries from the priv directory at load time using on_load, compile the queries to convert named parameters to positional parameters and store them into a persistent_term.

What I like about your approach is that it would in theory be possible to provide type specs and type the queries to make dialyzer happy.

In short, what would you think if erlquery:

  • Supported named parameters, so that the query functions took a map instead of a list;
  • Made code generation optional;
  • Added runtime type validation both for parameters and results;
  • Added typespecs when using code generation.

Thanks again.

2 Likes

Hi! That approach works, and is similar to my initial dumb idea of using a gen server to store the queries at runtime. I think that since you are storing in persistent_term that is closer to my precompiled approach. I’m curious how you are turning the named params into positional params. I feel like in erlang this might be helpful, but how this relates back to the sql query I would need to see.

Adding typespecs to erlquery seems like a natural addition. I almost did it, but I wasnt sure how the precompiled module would behave with dialyzer so I think that is a next step for experimentation. Few things I’m not sure about, does dialyzer look in the project src or the _build/src? If the former, than erlquery wont help, but if the latter than it will work. If it can be proven to work than I think typespecs need to be added to erlquery.

Named params seem like a good idea. I feel they are less helpful if typespecs arent included. Putting the args in a list feels primitive, but it is easy and intuitive how that interacts with the query driver. Sql langs are all positional anyways so you have to think in positional params at some point.

What would be a good reason to make code generation optional? Having a hard time thinking of one since the whole point of erlquery is to generate code :stuck_out_tongue_closed_eyes:. Open to learning one of them though.

I do think there is a natural synergy with runtime validation. I found myself going down a deeper rabbit hole that felt out of scope for erlquery. It would be really cool to generate the runtime validators at compile time. I think I would like to see the bulk of that work going to a different library like liver. And then erlquery can use it as a dependency or a plugin.

So basically, we’ve had the same ideas!!

1 Like