Skip to content
This repository was archived by the owner on Mar 19, 2021. It is now read-only.

Commit 109f7be

Browse files
committed
Clean up returning_query implementation to make Ebert happier.
1 parent 284a599 commit 109f7be

File tree

1 file changed

+43
-53
lines changed

1 file changed

+43
-53
lines changed

lib/sqlitex/statement.ex

Lines changed: 43 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -315,74 +315,64 @@ defmodule Sqlitex.Statement do
315315
{:error, :invalid_returning_clause}
316316
end
317317

318-
defp returning_query(%__MODULE__{database: db,
319-
statement: statement,
320-
returning: {table, cols, command, ref}})
321-
do
322-
with_savepoint(db, fn ->
323-
with_temp_table(db, cols, fn tmp_tbl ->
324-
err = with_temp_trigger(db, table, tmp_tbl, cols, command, ref, fn ->
325-
:esqlite3.fetchall(statement)
326-
end)
327-
328-
case err do
329-
{:error, _} -> err
330-
_ ->
331-
fields = Enum.join(cols, ", ")
332-
:esqlite3.q("SELECT #{fields} FROM #{tmp_tbl}", db)
333-
end
334-
end)
335-
end)
336-
end
337-
338-
defp with_savepoint(db, func) do
318+
defp returning_query(%__MODULE__{database: db} = stmt) do
339319
sp = "sp_#{random_id()}"
340-
[] = :esqlite3.q("SAVEPOINT #{sp}", db)
341-
case safe_call(db, func, sp) do
320+
{:ok, _} = db_exec(db, "SAVEPOINT #{sp}")
321+
322+
case returning_query_in_savepoint(sp, stmt) do
342323
{:error, _} = error ->
343-
[] = :esqlite3.q("ROLLBACK TO SAVEPOINT #{sp}", db)
344-
[] = :esqlite3.q("RELEASE #{sp}", db)
324+
rollback(db, sp)
345325
error
346326
result ->
347-
[] = :esqlite3.q("RELEASE #{sp}", db)
327+
{:ok, _} = db_exec(db, "RELEASE #{sp}")
348328
result
349329
end
350330
end
351331

352-
defp safe_call(db, func, sp) do
353-
func.()
332+
defp returning_query_in_savepoint(sp, %__MODULE__{database: db,
333+
statement: statement,
334+
returning: {table, cols, cmd, ref}})
335+
do
336+
temp_table = "t_#{random_id()}"
337+
temp_fields = Enum.join(cols, ", ")
338+
339+
trigger_name = "tr_#{random_id()}"
340+
trigger_fields = Enum.map_join(cols, ", ", &"#{ref}.#{&1}")
341+
trigger = """
342+
CREATE TEMP TRIGGER #{trigger_name} AFTER #{cmd} ON main.#{table} BEGIN
343+
INSERT INTO #{temp_table} SELECT #{trigger_fields};
344+
END;
345+
"""
346+
347+
column_names = Enum.join(cols, ", ")
348+
349+
with {:ok, _} = db_exec(db, "CREATE TEMP TABLE #{temp_table} (#{temp_fields})"),
350+
{:ok, _} = db_exec(db, trigger),
351+
_ = :esqlite3.fetchall(statement),
352+
{:ok, rows} = db_exec(db, "SELECT #{column_names} FROM #{temp_table}"),
353+
{:ok, _} = db_exec(db, "DROP TRIGGER IF EXISTS #{trigger_name}"),
354+
{:ok, _} = db_exec(db, "DROP TABLE IF EXISTS #{temp_table}")
355+
do
356+
rows
357+
end
354358
catch
355-
e in RuntimeError ->
356-
[] = :esqlite3.q("ROLLBACK TO SAVEPOINT #{sp}", db)
357-
[] = :esqlite3.q("RELEASE #{sp}", db)
359+
e ->
360+
rollback(db, sp)
358361
raise e
359362
end
360363

361-
defp with_temp_table(db, returning, func) do
362-
tmp = "t_#{random_id()}"
363-
fields = Enum.join(returning, ", ")
364-
results = case :esqlite3.q("CREATE TEMP TABLE #{tmp} (#{fields})", db) do
365-
{:error, _} = err -> err
366-
_ -> func.(tmp)
367-
end
368-
:esqlite3.q("DROP TABLE IF EXISTS #{tmp}", db)
369-
results
364+
defp rollback(db, sp) do
365+
{:ok, _} = db_exec(db, "ROLLBACK TO SAVEPOINT #{sp}")
366+
{:ok, _} = db_exec(db, "RELEASE #{sp}")
370367
end
371368

372-
defp with_temp_trigger(db, table, tmp_tbl, returning, command, ref, func) do
373-
tmp = "tr_" <> random_id()
374-
fields = Enum.map_join(returning, ", ", &"#{ref}.#{&1}")
375-
sql = """
376-
CREATE TEMP TRIGGER #{tmp} AFTER #{command} ON main.#{table} BEGIN
377-
INSERT INTO #{tmp_tbl} SELECT #{fields};
378-
END;
379-
"""
380-
results = case :esqlite3.q(sql, db) do
381-
{:error, _} = err -> err
382-
_ -> func.()
369+
defp db_exec(db, sql) do
370+
case :esqlite3.q(sql, db) do
371+
{:error, _} = error ->
372+
error
373+
result ->
374+
{:ok, result}
383375
end
384-
:esqlite3.q("DROP TRIGGER IF EXISTS #{tmp}", db)
385-
results
386376
end
387377

388378
defp random_id, do: :rand.uniform |> Float.to_string |> String.slice(2..10)

0 commit comments

Comments
 (0)