Improving Ecto ergonomics in ad-hoc querying scenarios

Last week I spent some time back in Rails world, and ActiveRecord in particular, and I was stunned how many keystrokes it saved me, compared to Ecto.

Not just keystrokes, some decisions are definitely more lax from security standpoint, but come in very handy, especially when making ad-hoc operations from the Rails console.

For example, Ecto is very particular in the data in side of creating queries, which ends up being quite verbose.

In ActiveRecord, we can query records by passing it a hash:

posts = Post.where(title: "Changelog", tags: ["post", "changelog"], published_at: nil)

the IN and IS NULL parts of the query will be infered from the hash.

We can also pass a Hash with string keys, or atom keys, and it’s not fussy about it either.

In Ecto, we have to either compose query by hand, or use keyword list this way:

posts = DB.Repo.query(DB.Post, title: "Changelog", ...)

But that will not work either for the IN clause or and won’t work for the IS NULL either because Ecto strictly enforces that comparison with nil is unsafe… which it kinda is, but on the edge cases like finding user by access token etc., and in a lot of places it’s just fine.

So far I ended up writing some helpers, but these are different between projects. For example, to support NIL values in the params one could write a reducer like this:

query =  Enum.reduce(params, base_query, fn                                                                                                                     
    { key, value}, query when not is_nil(value) ->                                                                                                                         
       from(o in query, where: field(o, ^key) == ^value)    
    {key, nil}, query ->                                                                                                                                                  
        from(o in query, where: is_nil(field(o, ^key)))                                                                                                                     

The helper could be extended to support arrays etc.

Question is: is there a better way and/or did someone wrote an ActiveRecord-esque library for Ecto that would make working with records from console a bit more Rails-like?