Skip to content

Instantly share code, notes, and snippets.

@Linell
Last active November 7, 2017 14:16
Show Gist options
  • Save Linell/106c2213fb30c14b41a82d9ddb2c7f32 to your computer and use it in GitHub Desktop.
Save Linell/106c2213fb30c14b41a82d9ddb2c7f32 to your computer and use it in GitHub Desktop.
defmodule Mix.Tasks.Parser do
use Mix.Task
require IEx
@shortdoc "A test of the parser."
def run(_args) do
Mix.shell.info "Greetings from the parser"
# The following tree represents a query that looks like:
# (users.enrollment_status == "E" || users.dob == "2017-11-06" || (users.is_member == true && (users.gender == "M" && users.site_id IN ("234siteid"))))
tree = Poison.decode!(~s(
{
"usedFields":[
"users.enrollment_status",
"users.dob",
"users.is_member",
"users.gender",
"users.site_id"
],
"rules":[
{
"id":"9bab8999-cdef-4012-b456-715f92375987",
"field":"users.enrollment_status",
"type":"select",
"input":"select",
"operator":"select_equals",
"values":[
{
"type":"select",
"value":"E"
}
]
},
{
"id":"aabaa8ab-89ab-4cde-b012-315f92377265",
"field":"users.dob",
"type":"date",
"input":"date",
"operator":"equal",
"values":[
{
"type":"date",
"value":"2017-11-06"
}
]
},
{
"rules":[
{
"id":"9a9b899a-0123-4456-b89a-b15f9237a0de",
"field":"users.is_member",
"type":"boolean",
"input":"boolean",
"operator":"equal",
"values":[
{
"type":"boolean",
"value":true
}
]
},
{
"rules":[
{
"id":"aa98baaa-89ab-4cde-b012-315f9238650b",
"field":"users.gender",
"type":"select",
"input":"select",
"operator":"select_equals",
"values":[
{
"type":"select",
"value":"M"
}
]
},
{
"id":"a9bb8a8b-4567-489a-bcde-f15f92389859",
"field":"users.site_id",
"type":"select",
"input":"select",
"operator":"select_any_in",
"values":[
{
"type":"multiselect",
"value":[
"234siteid"
]
}
]
}
],
"condition":"AND"
}
],
"condition":"AND"
}
],
"condition":"OR"
}
))
parsed_output = parse(tree)
IO.puts parsed_output
end
def parse(node) do
res = Enum.map(Map.get(node, "rules"), &(parse_node/1))
|> Enum.join(" " <> Map.get(node, "condition") <> " ")
"(#{res})"
end
# so every node is a set of tuples --
def parse_node(node) do
if (is_top_level_node(node)), do: parse(node), else: sql_from_rule(node)
end
def is_top_level_node(node) do
cond do
is_map(node) ->
Map.keys(node) |> Enum.member?("condition")
true -> # default condition
false
end
end
def sql_from_rule(rule) do
# IEx.pry
field = Map.get(rule, "field")
# is there a better way here?
value = Map.get(rule, "values") |> List.first |> Map.get("value")
# there will be a lot of logic around picking the operator, and
# any tips there would be appreciated
"#{field} = #{value}"
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment