Skip to content

Commit 7da32c7

Browse files
authored
Merge pull request #1118 from noaccOS/refactor/centralize-insert-sql
refactor(appengine): centralize insert to sql definition
2 parents 972a81d + 215b8c5 commit 7da32c7

File tree

3 files changed

+80
-22
lines changed

3 files changed

+80
-22
lines changed

apps/astarte_appengine_api/lib/astarte_appengine_api/device/queries.ex

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -575,16 +575,14 @@ defmodule Astarte.AppEngine.API.Device.Queries do
575575

576576
def insert_alias(realm_name, device_id, alias_tag, alias_value) do
577577
keyspace = keyspace_name(realm_name)
578-
names_table = Name.__schema__(:source)
579578

580-
insert_alias_to_names_statement = """
581-
INSERT INTO #{keyspace}.#{names_table}
582-
(object_name, object_type, object_uuid)
583-
VALUES (?, 1, ?)
584-
"""
579+
name = %Name{
580+
object_name: alias_value,
581+
object_type: 1,
582+
object_uuid: device_id
583+
}
585584

586-
insert_alias_to_names_params = [alias_value, device_id]
587-
insert_alias_to_names_query = {insert_alias_to_names_statement, insert_alias_to_names_params}
585+
insert_alias_to_names_query = Repo.insert_to_sql(name, prefix: keyspace)
588586

589587
new_alias = %{alias_tag => alias_value}
590588

apps/astarte_appengine_api/lib/astarte_appengine_api/kv_store.ex

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -54,12 +54,6 @@ defmodule Astarte.AppEngine.API.KvStore do
5454
Keyword.t()
5555
) :: :ok | {:error, Exception.t()}
5656
def insert(kv_store_map, opts \\ []) do
57-
%{
58-
group: group,
59-
key: key,
60-
value: value
61-
} = kv_store_map
62-
6357
value_type = Map.get(kv_store_map, :value_type, :binary)
6458

6559
value_expr =
@@ -70,15 +64,13 @@ defmodule Astarte.AppEngine.API.KvStore do
7064
:string -> "varcharAsBlob(?)"
7165
end
7266

73-
{keyspace, opts} = Keyword.pop!(opts, :prefix)
74-
75-
sql =
76-
"""
77-
INSERT INTO #{keyspace}.#{@source} (group, key, value)
78-
VALUES (?, ?, #{value_expr})
79-
"""
67+
kv_store = %__MODULE__{
68+
group: kv_store_map.group,
69+
key: kv_store_map.key,
70+
value: {:custom, value_expr, kv_store_map.value}
71+
}
8072

81-
params = [group, key, value]
73+
{sql, params} = Repo.insert_to_sql(kv_store, opts)
8274

8375
with {:ok, _} <- Repo.query(sql, params, opts) do
8476
:ok

apps/astarte_appengine_api/lib/astarte_appengine_api/repo.ex

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,42 @@ defmodule Astarte.AppEngine.API.Repo do
3535
{:ok, config}
3636
end
3737

38+
def insert_to_sql(struct, opts) when is_struct(struct) do
39+
table = struct.__meta__.source
40+
insert_to_sql(table, struct, opts)
41+
end
42+
43+
def insert_to_sql(table, value, opts) do
44+
{exandra_opts, opts} = Keyword.split(opts, [:ttl, :overwrite, :timestamp])
45+
{prefix, _opts} = Keyword.pop(opts, :prefix)
46+
47+
{keys, values} =
48+
value
49+
|> Map.drop([:__struct__, :__meta__])
50+
|> Enum.unzip()
51+
52+
keys = Enum.join(keys, ", ")
53+
54+
{values, params} =
55+
values
56+
|> Enum.map(fn
57+
{:custom, string, values} when is_list(values) -> {string, values}
58+
{:custom, string, value} -> {string, [value]}
59+
value -> {"?", [value]}
60+
end)
61+
|> Enum.unzip()
62+
63+
values = Enum.join(values, ", ")
64+
65+
# We need to get rid of one level of wrapping
66+
params = Enum.flat_map(params, & &1)
67+
68+
sql =
69+
"INSERT INTO #{quote_table(prefix, table)} (#{keys}) VALUES (#{values}) #{insert_suffix(exandra_opts)}"
70+
71+
{sql, params}
72+
end
73+
3874
def fetch(queryable, id, opts \\ []) do
3975
queryable
4076
|> query_for_get(id)
@@ -87,4 +123,36 @@ defmodule Astarte.AppEngine.API.Repo do
87123
query: query,
88124
message: "expected a from expression with a schema"
89125
end
126+
127+
# source: exandra lib/exandra/connection.ex
128+
defp quote_table(nil, name), do: quote_table(name)
129+
defp quote_table(prefix, name), do: [quote_table(prefix), ?., quote_table(name)]
130+
defp quote_table(name) when is_atom(name), do: quote_table(Atom.to_string(name))
131+
defp quote_table(name), do: [name]
132+
133+
# source: exandra lib/exandra/connection.ex
134+
defp insert_suffix(opts) do
135+
suffix =
136+
case Keyword.get(opts, :overwrite, true) do
137+
true ->
138+
[]
139+
140+
_ ->
141+
[" IF NOT EXISTS"]
142+
end
143+
144+
suffix =
145+
case Keyword.get(opts, :ttl, nil) do
146+
nil -> suffix
147+
seconds when is_number(seconds) -> suffix ++ [" USING TTL #{seconds}"]
148+
end
149+
150+
case Keyword.get(opts, :timestamp, nil) do
151+
nil ->
152+
suffix
153+
154+
epoch_in_microseconds when is_number(epoch_in_microseconds) ->
155+
suffix ++ [" AND TIMESTAMP #{epoch_in_microseconds}"]
156+
end
157+
end
90158
end

0 commit comments

Comments
 (0)