11defmodule Feeb.DB.Query do
22 require Logger
3+ alias Feeb.DB.Schema
34 alias __MODULE__ . Binding
45
56 @ initial_q { "" , { [ ] , [ ] } , nil }
@@ -53,10 +54,14 @@ defmodule Feeb.DB.Query do
5354 adhoc_query_id
5455 end
5556
56- def get_templated_query_id ( { context , domain , :__insert } , target_fields , meta ) do
57+ def get_templated_query_id ( query_id , target_fields , meta \\ % { } )
58+
59+ def get_templated_query_id ( { context , domain , :__insert } = query_id , target_fields , _meta ) do
60+ model = Schema . get_model_from_query_id ( query_id )
61+
5762 target_fields =
5863 if target_fields == :all do
59- meta . schema . __cols__ ( )
64+ model . __cols__ ( )
6065 else
6166 raise "Not supported for now, add & test it once needed"
6267 target_fields
@@ -70,11 +75,14 @@ defmodule Feeb.DB.Query do
7075 real_query_id
7176
7277 nil ->
73- compile_templated_query ( :__insert , real_query_id , target_fields )
78+ compile_templated_query ( :__insert , real_query_id , target_fields , model )
7479 end
7580 end
7681
77- def get_templated_query_id ( { context , domain , :__update } , target_fields , _meta ) do
82+ def get_templated_query_id ( { context , domain , :__update } = query_id , target_fields , _meta ) do
83+ model = Schema . get_model_from_query_id ( query_id )
84+
85+ # TODO: Transparently include `updated_at` (if present in the model)
7886 target_fields = Enum . sort ( target_fields )
7987
8088 query_name_suffix =
@@ -92,22 +100,24 @@ defmodule Feeb.DB.Query do
92100 real_query_id
93101
94102 nil ->
95- compile_templated_query ( :__update , real_query_id , target_fields )
103+ compile_templated_query ( :__update , real_query_id , target_fields , model )
96104 end
97105 end
98106
99107 def get_templated_query_id ( { _context , _domain , query_name } = query_id , target_fields , _meta )
100108 when query_name in [ :__all , :__fetch , :__delete ] do
109+ model = Schema . get_model_from_query_id ( query_id )
110+
101111 case get ( query_id ) do
102112 { _ , _ , _ } = _compiled_query ->
103113 query_id
104114
105115 nil ->
106- compile_templated_query ( query_name , query_id , target_fields )
116+ compile_templated_query ( query_name , query_id , target_fields , model )
107117 end
108118 end
109119
110- defp compile_templated_query ( :__insert , { _ , domain , _ } = query_id , target_fields ) do
120+ defp compile_templated_query ( :__insert , { _ , domain , _ } = query_id , target_fields , _model ) do
111121 columns_clause = target_fields |> Enum . join ( ", " )
112122
113123 values_clause =
@@ -123,42 +133,48 @@ defmodule Feeb.DB.Query do
123133 query_id
124134 end
125135
126- defp compile_templated_query ( :__update , { _ , domain , _ } = query_id , target_fields ) do
127- # Hard-coded for now, but we may need this to be dynamc in the future
128- primary_key_col = :id
136+ defp compile_templated_query ( :__update , { _ , domain , _ } = query_id , target_fields , model ) do
137+ primary_keys = model . __primary_keys__ ( )
138+ assert_adhoc_query! ( primary_keys , query_id , model )
129139
130- set_clause =
140+ set_conditions =
131141 target_fields
132142 |> Enum . reduce ( [ ] , fn field , acc ->
133143 [ "#{ field } = ?" | acc ]
134144 end )
135145 |> Enum . reverse ( )
136146 |> Enum . join ( ", " )
137147
138- sql = "UPDATE #{ domain } SET #{ set_clause } WHERE id = ? ;"
139- adhoc_query = { sql , { [ ] , target_fields ++ [ primary_key_col ] } , :update }
148+ sql = "UPDATE #{ domain } SET #{ set_conditions } #{ generate_where_clause ( primary_keys ) } ;"
149+ adhoc_query = { sql , { [ ] , target_fields ++ primary_keys } , :update }
140150 append_runtime_query ( query_id , adhoc_query )
141151
142152 query_id
143153 end
144154
145- defp compile_templated_query ( :__all , { _ , domain , _ } = query_id , _target_fields ) do
155+ defp compile_templated_query ( :__all , { _ , domain , _ } = query_id , _target_fields , _model ) do
146156 sql = "SELECT * FROM #{ domain } ;"
147157 adhoc_query = { sql , { [ :* ] , [ ] } , :select }
148158 append_runtime_query ( query_id , adhoc_query )
149159 query_id
150160 end
151161
152- defp compile_templated_query ( :__fetch , { _ , domain , _ } = query_id , _target_fields ) do
153- sql = "SELECT * FROM #{ domain } WHERE id = ?;"
154- adhoc_query = { sql , { [ :* ] , [ :id ] } , :select }
162+ defp compile_templated_query ( :__fetch , { _ , domain , _ } = query_id , _target_fields , model ) do
163+ primary_keys = model . __primary_keys__ ( )
164+ assert_adhoc_query! ( primary_keys , query_id , model )
165+ sql = "SELECT * FROM #{ domain } #{ generate_where_clause ( primary_keys ) } ;"
166+
167+ adhoc_query = { sql , { [ :* ] , primary_keys } , :select }
155168 append_runtime_query ( query_id , adhoc_query )
156169 query_id
157170 end
158171
159- defp compile_templated_query ( :__delete , { _ , domain , _ } = query_id , _target_fields ) do
160- sql = "DELETE FROM #{ domain } WHERE id = ?;"
161- adhoc_query = { sql , { [ ] , [ :id ] } , :delete }
172+ defp compile_templated_query ( :__delete , { _ , domain , _ } = query_id , _target_fields , model ) do
173+ primary_keys = model . __primary_keys__ ( )
174+ assert_adhoc_query! ( primary_keys , query_id , model )
175+ sql = "DELETE FROM #{ domain } #{ generate_where_clause ( primary_keys ) } ;"
176+
177+ adhoc_query = { sql , { [ ] , primary_keys } , :delete }
162178 append_runtime_query ( query_id , adhoc_query )
163179 query_id
164180 end
@@ -235,6 +251,24 @@ defmodule Feeb.DB.Query do
235251 defp get_returning_fields ( { _ , _ , operation } ) when operation in [ :update , :delete ] ,
236252 do: "*"
237253
254+ defp generate_where_clause ( primary_keys ) when is_list ( primary_keys ) do
255+ where_conditions =
256+ primary_keys
257+ |> Enum . reduce ( [ ] , fn field , acc ->
258+ [ "#{ field } = ?" | acc ]
259+ end )
260+ |> Enum . reverse ( )
261+ |> Enum . join ( " AND " )
262+
263+ "WHERE #{ where_conditions } "
264+ end
265+
266+ defp assert_adhoc_query! ( nil , query_id , model ) do
267+ raise ( "Can't generate adhoc query #{ inspect ( query_id ) } because #{ inspect ( model ) } has no PKs" )
268+ end
269+
270+ defp assert_adhoc_query! ( _ , _ , _ ) , do: :ok
271+
238272 # Line-break
239273 defp handle_line ( << >> , qs , id , q ) when not is_nil ( id ) do
240274 { sql , { fields_bindings , params_bindings } , query_type } = q
0 commit comments