Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ before_install:
- unzip -d elixir v1.4.2.zip
before_script:
- export PATH=`pwd`/elixir/bin:$PATH
- mix local.rebar --force
- mix local.hex --force
- mix deps.get --only test
script: mix test
Expand Down
52 changes: 36 additions & 16 deletions lib/sql_dust.ex
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@ defmodule SqlDust do
options = %{
select: ".*",
adapter: :mysql,
initial_variables: options[:variables] || %{},
variables: %{},
variables: options[:variables] || %{},
unique: false
}
|> Map.merge(options)
Expand All @@ -40,6 +39,33 @@ defmodule SqlDust do
|> compose_sql
end

def resolve_placeholders(placeholders, options, values \\ []) do
placeholders
|> Enum.with_index()
|> Enum.map(fn({path, index}) ->
case Regex.run(~r/option:(\w+)/, path) do
nil ->
String.split(path, ".") |> Enum.reduce(options.variables, fn(name, variables) ->
if is_map(variables) do
case MapUtils.get(variables, name) do
nil ->
if Map.has_key?(variables, name) || Map.has_key?(variables, name |> String.to_atom()) do
nil
else
Enum.at(values, index)
end
value -> value
end
else
variables
end
end)
[_match, key] ->
options[String.to_atom(key)]
end
end)
end

defp derive_select(options) do
list = split_arguments(options[:select])

Expand Down Expand Up @@ -149,15 +175,15 @@ defmodule SqlDust do

defp derive_limit(options) do
if limit = MapUtils.get(options, :limit) do
options |> interpolate_option_variable(:limit, limit)
options |> put_option_placeholder(:limit, limit)
else
options
end
end

defp derive_offset(options) do
if offset = MapUtils.get(options, :offset) do
options |> interpolate_option_variable(:offset, offset)
options |> put_option_placeholder(:offset, offset)
else
options
end
Expand Down Expand Up @@ -212,21 +238,15 @@ defmodule SqlDust do
Map.put(options, key, prefix <> (conditions |> Enum.join(" AND ")))
end

defp interpolate_option_variable(options, key, value) do
variables = options.variables
defp put_option_placeholder(options, key, value) do
interpolated_key = "option:" <> Atom.to_string(key)

variables =
unless value == "?" do
option_variables = (options.variables[:_options_] || %{}) |> Map.put(key, value)
options.variables |> Map.put(:_options_, option_variables)
else
variables
end

interpolated_key = " <<_options_." <> Atom.to_string(key) <> ">>"
options.variables
|> Map.put(interpolated_key, value)

options
|> Map.put(key, (Atom.to_string(key) |> String.upcase) <> interpolated_key)
|> Map.put(key, (Atom.to_string(key) |> String.replace("_", " ") |> String.upcase) <> " <<" <> interpolated_key <> ">>")
|> Map.put(:variables, variables)
end

Expand All @@ -248,6 +268,6 @@ defmodule SqlDust do
|> List.flatten
|> Enum.reject(&is_nil/1)
|> Enum.join("\n")
|> interpolate_variables(options.variables, options.initial_variables)
|> interpolate_placeholders(options)
end
end
25 changes: 4 additions & 21 deletions lib/sql_dust/utils/scan_utils.ex
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
defmodule SqlDust.ScanUtils do
alias SqlDust.MapUtils

@variable_regex ~r/<<([\w\.]+)>>/
@variable_regex ~r/<<((?:option:)?[\w\.]+)>>/

def split_arguments(sql) when is_list(sql) do
sql
Expand Down Expand Up @@ -126,11 +126,10 @@ defmodule SqlDust.ScanUtils do
{String.replace(sql, "{#{index}}", pattern), index}
end

def interpolate_variables(sql, variables, initial_variables) do
def interpolate_placeholders(sql, %{variables: variables}) do
excluded = scan_strings(sql)
sql = numerize_patterns(sql, excluded)


{sql, values, keys} =
@variable_regex
|> Regex.scan(sql)
Expand All @@ -139,20 +138,7 @@ defmodule SqlDust.ScanUtils do
MapUtils.get(variables, name)
end)

anonymous_key =
Regex.match?(~r(__\d+__), key) || (
String.contains?(key, "_options_") && (
!(initial_variables
|> MapUtils.get(:_options_, %{})
|> Map.keys
|> Enum.map(fn
(k) when is_atom(k) -> Atom.to_string(k)
(k) -> k
end)
|> Enum.member?(String.split(key, ".", parts: 3) |> Enum.at(1)))
)
)

anonymous_key = Regex.match?(~r(__\d+__), key)
sql = String.replace sql, match, "?", global: false
values = [value | values]
key = if anonymous_key, do: nil, else: key
Expand All @@ -164,10 +150,7 @@ defmodule SqlDust.ScanUtils do
keys = Enum.reverse(keys)

sql = interpolate_patterns(sql, excluded)
include_keys = Enum.any?(Map.keys(initial_variables), fn(key) ->
key = if is_atom(key), do: Atom.to_string(key), else: key
!Regex.match?(~r(__\d+__), key)
end)
include_keys = (length(keys) > 0) && !Enum.any?(keys, &is_nil/1)

if include_keys do
{sql, values, keys}
Expand Down
2 changes: 1 addition & 1 deletion mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ defmodule SqlDust.Mixfile do
{:benchfella, "~> 0.3.0", only: :dev},
{:earmark, "~> 0.1", only: :dev},
{:ex_doc, "~> 0.11", only: :dev},
{:credo, "~> 0.2", only: [:dev, :test]},
{:credo, "~> 0.8", only: [:dev, :test]},
{:inch_ex, ">= 0.0.0", only: :docs}
]
end
Expand Down
26 changes: 13 additions & 13 deletions mix.lock
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
%{"benchfella": {:hex, :benchfella, "0.3.4", "41d2c017b361ece5225b5ba2e3b30ae53578c57c6ebc434417b4f1c2c94cf4f3", [:mix], []},
"bunt": {:hex, :bunt, "0.1.5", "c378ea1698232597d3778e4b83234dcea4a60e7c28114b0fe53657a2c0d8885e", [:mix], []},
"credo": {:hex, :credo, "0.3.13", "90d2d2deb9d376bb2a63f81126a320c3920ce65acb1294982ab49a8aacc7d89f", [:mix], [{:bunt, "~> 0.1.4", [hex: :bunt, optional: false]}]},
"decimal": {:hex, :decimal, "1.3.1", "157b3cedb2bfcb5359372a7766dd7a41091ad34578296e951f58a946fcab49c6", [:mix], []},
"earmark": {:hex, :earmark, "0.2.1", "ba6d26ceb16106d069b289df66751734802777a3cbb6787026dd800ffeb850f3", [:mix], []},
"ecto": {:hex, :ecto, "2.0.5", "7f4c79ac41ffba1a4c032b69d7045489f0069c256de606523c65d9f8188e502d", [:mix], [{:db_connection, "~> 1.0-rc.4", [hex: :db_connection, optional: true]}, {:decimal, "~> 1.1.2 or ~> 1.2", [hex: :decimal, optional: false]}, {:mariaex, "~> 0.7.7", [hex: :mariaex, optional: true]}, {:poison, "~> 1.5 or ~> 2.0", [hex: :poison, optional: true]}, {:poolboy, "~> 1.5", [hex: :poolboy, optional: false]}, {:postgrex, "~> 0.12.0", [hex: :postgrex, optional: true]}, {:sbroker, "~> 1.0-beta", [hex: :sbroker, optional: true]}]},
"ex_doc": {:hex, :ex_doc, "0.11.4", "a064bdb720594c3745b94709b17ffb834fd858b4e0c1f48f37c0d92700759e02", [:mix], [{:earmark, "~> 0.1.17 or ~> 0.2", [hex: :earmark, optional: true]}]},
"exprintf": {:hex, :exprintf, "0.2.1", "b7e895dfb00520cfb7fc1671303b63b37dc3897c59be7cbf1ae62f766a8a0314", [:mix], []},
"exprof": {:hex, :exprof, "0.2.0", "b03f50d0d33e2f18c8e047d9188ba765dc32daba0b553ed717a98a78561d5eaf", [:mix], [{:exprintf, "~> 0.1", [hex: :exprintf, optional: false]}]},
"inch_ex": {:hex, :inch_ex, "0.5.1", "c1c18966c935944cbb2d273796b36e44fab3c54fd59f906ff026a686205b4e14", [:mix], [{:poison, "~> 1.5 or ~> 2.0", [hex: :poison, optional: false]}]},
"inflex": {:hex, :inflex, "1.6.0", "2c0c9928cd865e3b47cfaaa15c3520dfdb8c6ba5829d036296deb766f2aba770", [:mix], []},
"poison": {:hex, :poison, "2.2.0", "4763b69a8a77bd77d26f477d196428b741261a761257ff1cf92753a0d4d24a63", [:mix], []},
"poolboy": {:hex, :poolboy, "1.5.1", "6b46163901cfd0a1b43d692657ed9d7e599853b3b21b95ae5ae0a777cf9b6ca8", [:rebar], []}}
%{"benchfella": {:hex, :benchfella, "0.3.4", "41d2c017b361ece5225b5ba2e3b30ae53578c57c6ebc434417b4f1c2c94cf4f3", [:mix], [], "hexpm"},
"bunt": {:hex, :bunt, "0.2.0", "951c6e801e8b1d2cbe58ebbd3e616a869061ddadcc4863d0a2182541acae9a38", [:mix], [], "hexpm"},
"credo": {:hex, :credo, "0.8.4", "4e50acac058cf6292d6066e5b0d03da5e1483702e1ccde39abba385c9f03ead4", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}], "hexpm"},
"decimal": {:hex, :decimal, "1.3.1", "157b3cedb2bfcb5359372a7766dd7a41091ad34578296e951f58a946fcab49c6", [:mix], [], "hexpm"},
"earmark": {:hex, :earmark, "0.2.1", "ba6d26ceb16106d069b289df66751734802777a3cbb6787026dd800ffeb850f3", [:mix], [], "hexpm"},
"ecto": {:hex, :ecto, "2.0.5", "7f4c79ac41ffba1a4c032b69d7045489f0069c256de606523c65d9f8188e502d", [:mix], [{:db_connection, "~> 1.0-rc.4", [hex: :db_connection, repo: "hexpm", optional: true]}, {:decimal, "~> 1.1.2 or ~> 1.2", [hex: :decimal, repo: "hexpm", optional: false]}, {:mariaex, "~> 0.7.7", [hex: :mariaex, repo: "hexpm", optional: true]}, {:poison, "~> 1.5 or ~> 2.0", [hex: :poison, repo: "hexpm", optional: true]}, {:poolboy, "~> 1.5", [hex: :poolboy, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.12.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:sbroker, "~> 1.0-beta", [hex: :sbroker, repo: "hexpm", optional: true]}], "hexpm"},
"ex_doc": {:hex, :ex_doc, "0.11.4", "a064bdb720594c3745b94709b17ffb834fd858b4e0c1f48f37c0d92700759e02", [:mix], [{:earmark, "~> 0.1.17 or ~> 0.2", [hex: :earmark, repo: "hexpm", optional: true]}], "hexpm"},
"exprintf": {:hex, :exprintf, "0.2.1", "b7e895dfb00520cfb7fc1671303b63b37dc3897c59be7cbf1ae62f766a8a0314", [:mix], [], "hexpm"},
"exprof": {:hex, :exprof, "0.2.0", "b03f50d0d33e2f18c8e047d9188ba765dc32daba0b553ed717a98a78561d5eaf", [:mix], [{:exprintf, "~> 0.1", [hex: :exprintf, repo: "hexpm", optional: false]}], "hexpm"},
"inch_ex": {:hex, :inch_ex, "0.5.1", "c1c18966c935944cbb2d273796b36e44fab3c54fd59f906ff026a686205b4e14", [:mix], [{:poison, "~> 1.5 or ~> 2.0", [hex: :poison, repo: "hexpm", optional: false]}], "hexpm"},
"inflex": {:hex, :inflex, "1.6.0", "2c0c9928cd865e3b47cfaaa15c3520dfdb8c6ba5829d036296deb766f2aba770", [:mix], [], "hexpm"},
"poison": {:hex, :poison, "2.2.0", "4763b69a8a77bd77d26f477d196428b741261a761257ff1cf92753a0d4d24a63", [:mix], [], "hexpm"},
"poolboy": {:hex, :poolboy, "1.5.1", "6b46163901cfd0a1b43d692657ed9d7e599853b3b21b95ae5ae0a777cf9b6ca8", [:rebar], [], "hexpm"}}
77 changes: 44 additions & 33 deletions test/sql_dust_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -599,61 +599,70 @@ defmodule SqlDustTest do
SELECT `u`.*
FROM `users` `u`
LIMIT ?
""", [20]}
""",
[20],
~w(option:limit)}
end

test "limiting the query result by passing the limit in variables[:_options_][:limit]" do
test "adding an offset to the query result" do
options = %{
limit: "?",
variables: %{
_options_: %{
limit: 20
}
}
limit: 10,
offset: 20
}

assert SqlDust.from("users", options) == {"""
SELECT `u`.*
FROM `users` `u`
LIMIT ?
OFFSET ?
""",
[20],
~w(_options_.limit)}
[10, 20],
~w(option:limit option:offset)}
end

test "adding an offset to the query result" do
test "resolving placeholders" do
placeholders =
~w(person.first_name person.last_name person.last_name option:limit option:offset epic)

options = %{
variables: %{
person: %{
first_name: "Paul",
last_name: "Engel"
},
awesome: true
},
limit: 10,
offset: 20
}

assert SqlDust.from("users", options) == {"""
SELECT `u`.*
FROM `users` `u`
LIMIT ?
OFFSET ?
""", [10, 20]}
assert SqlDust.resolve_placeholders(placeholders, options) == [
"Paul", "Engel", "Engel", 10, 20, nil
]
end

test "adding an offset to the query result by passing the offset in variables[:_options_][:offset]" do
test "resolving placeholders (with fallback to static values)" do
placeholders =
~w(person.first_name person.last_name person.last_name awesome option:limit option:offset)

options = %{
limit: 10,
offset: "?",
variables: %{
_options_: %{
offset: 20
}
}
person: %{
last_name: "Engel"
},
awesome: nil
},
limit: 10,
offset: 20
}

assert SqlDust.from("users", options) == {"""
SELECT `u`.*
FROM `users` `u`
LIMIT ?
OFFSET ?
""",
[10, 20],
[nil, "_options_.offset"]}
values = [
"Ken", "Engel", "Engel", true, 10, 20
]

assert SqlDust.resolve_placeholders(placeholders, options, values) == [
"Ken", "Engel", "Engel", nil, 10, 20
]
end

test "quoting SELECT statement aliases" do
Expand Down Expand Up @@ -891,7 +900,9 @@ defmodule SqlDustTest do
HAVING (`order.count` > 5)
ORDER BY COUNT(DISTINCT `tags`.`id`) DESC
LIMIT ?
""", [5]}
""",
[5],
~w(option:limit)}
end

test "DirectiveRecord example 3" do
Expand Down