iwatakeshi

iwatakeshi

Building a dynamic query using recursion

Hi :waving_hand:, I’ve been playing around with Elixir and its ecosystem for a few weeks now and I really like it so far. Also, this is my first post here so please bear with me :man_bowing:t2:.

I’m trying to mimic how Amazon’s Amplify generates the filters for its GraphQL schemas using Absinthe.
So far I was able to get ne, eq, le, ge, gt, contains, and between to work. The hard part, however, is implementing and, or, and not (lines 88 - 90) since it involves recursion and Ecto.

I’ve created a small repl.it that shows what I’ve tried so far (maybe lots of code commented off as well :sweat_smile:). In the repl.it, I’m using strings to abstract things but the goal is to use Ecto’s dynamic query feature.

The input will look something like this:

input = %{
  and: [%{ and: [%{ b: %{ eq: "4"}}], c: %{ eq: "3"}}],
  or: [%{ d: %{ eq: "2"}}],
  a: %{ eq: "1"}
}

and the output will be expressed as something like:

# a and (b == 4 and c == 3) or (d == 2)

I think I’m on the right track. I know that I eventually have to reduce a tree-like structure to a single query, but I’m not sure how to deal with a binary operator such and and or within Enum.reduce so any help would be greatly appreciated.

Thank you.

Random thought:

I think it would be super neat if Absinthe could just build the tables and hook everything up including filtering, relay, etc with just a schema like Amplify… this would be a game changer.

Most Liked

al2o3cr

al2o3cr

I interpret that document as describing a different structure where both and and or take the terms they apply to in a list. For your example, start by writing the expression with explicit parentheses:

(a == 1 and (b == 4 and c == 3)) or (d == 2)

Rules:

  • %{variable_name: %{eq: value}} corresponds to variable_name == value
  • %{var1: %{eq: v1}, var2: %{eq: v2}} corresponds to (var1 == v1) and (var2 == v2)
  • %{and: [X, Y, Z]} corresponds to the expression (X and (Y and Z))
  • %{or: [X, Y, Z]} corresponds to the expression (X or (Y or Z))

so

%{
  a: %{eq: 1},
  b: %{eq: 4},
  c: %{eq: 3}
}

corresponds to (a == 1 and (b == 4 and c == 3)). So finally

%{
  or: [
    %{
      a: %{eq: 1},
      b: %{eq: 4},
      c: %{eq: 3}
    },
    %{
      d: %{eq: 2}
    }
  ]
}

corresponds to the original expression.

The recursion you’ll need to turn the map above into Ecto operations is the derivation in reverse. You’ll likely want to use explicit recursion for this, as it’s a depth-first traversal of the input.

Last Post!

iwatakeshi

iwatakeshi

Just wanted to update and say thank you for taking your time and input! I was able to get something working (after lots of head banging :laughing:).

I’ll leave a repl.it here in case someone finds it helpful/useful and maybe even improve it.

Where Next?

Popular in Questions Top

nobody
Hi! In PHP: $_SERVER[‘SERVER_ADDR’] - in Elixir? Searched the docs for ip address and the web, no good results. Thanks!
New
hariharasudhan94
Lets say I have map like this fetching from my database %{"_id" => #BSON.ObjectId<58eb1a7a9ad169198c3dXXXX>, "email" => ...
New
hariharasudhan94
lets say i have a sample like a = 20; b = 10; if (a > b) do {:ok, "a"} end if (a < b) do {:ok, b} end if (a == b) do {:ok, "equa...
New
stefanchrobot
What’s the safe way to decode a JSON string into a struct? I want to avoid calling String.to_atom. Jason.decode can give me a map with st...
New
Lily
In templates/appointment/index.html.eex: <%= for appointment <- @appointments do %> <tr> <td><%= appoi...
New
sergio_101
I am VERY much an elixir newbie. I have taken one elixir course and one phoenix course on Udemy. During that course, I saw the instructor...
New
shijith.k
I am trying to start a new phoenix project with elixir 1.9, but mix phx.new does not work. It says that ** (Mix) The task "phx.new" could...
New

Other popular topics Top

minhajuddin
I have seen a lot of code which picks the first element from a list using Enum.at(0) instead of List.first. Is there a reason why people ...
New
hariharasudhan94
I would like to know what is the best IDE for elixir development?
New
JakeBecker
TL;DR: I’ve just released an implementation of Microsoft’s IDE-independent Language Server Protocol for Elixir. It adds language support ...
1144 54921 245
New
saif
Hello everyone, Long time lurker first time poster here. I’ve recently begun working on Elixir full-time again! :raised_hands: It’s been...
New
dblack
I’ve got an issue with an app and I’ve no idea of how to troubleshoot it. I’m hoping someone here might have seen something similar. I p...
New
TunkShif
This post is an instruction guide to help you setup your Neovim for Elixir development from scratch. It includes general information on h...
274 42533 114
New

We're in Beta

About us Mission Statement