@@ -7,13 +7,16 @@ defmodule Extensions.PostgresCdcRls.Subscriptions do
77 import Postgrex , only: [ transaction: 2 , query: 3 , rollback: 2 ]
88
99 @ type conn ( ) :: Postgrex . conn ( )
10+ @ type filter :: { binary , binary , binary }
11+ @ type subscription_params :: { binary , binary , [ filter ] }
12+ @ type subscription_list :: [ % { id: binary , claims: map , subscription_params: subscription_params } ]
1013
1114 @ filter_types [ "eq" , "neq" , "lt" , "lte" , "gt" , "gte" , "in" ]
1215
13- @ spec create ( conn ( ) , String . t ( ) , [ map ( ) ] , pid ( ) , pid ( ) ) ::
16+ @ spec create ( conn ( ) , String . t ( ) , subscription_list , pid ( ) , pid ( ) ) ::
1417 { :ok , Postgrex.Result . t ( ) }
1518 | { :error , Exception . t ( ) | :malformed_subscription_params | { :subscription_insert_failed , map ( ) } }
16- def create ( conn , publication , params_list , manager , caller ) do
19+ def create ( conn , publication , subscription_list , manager , caller ) do
1720 sql = "with sub_tables as (
1821 select
1922 rr.entity
@@ -50,37 +53,30 @@ defmodule Extensions.PostgresCdcRls.Subscriptions do
5053 id"
5154
5255 transaction ( conn , fn conn ->
53- Enum . map ( params_list , fn % { id: id , claims: claims , params: params } ->
54- case parse_subscription_params ( params ) do
55- { :ok , [ schema , table , filters ] } ->
56- case query ( conn , sql , [ publication , schema , table , id , claims , filters ] ) do
57- { :ok , % { num_rows: num } = result } when num > 0 ->
58- send ( manager , { :subscribed , { caller , id } } )
59- result
56+ Enum . map ( subscription_list , fn % { id: id , claims: claims , subscription_params: params = { schema , table , filters } } ->
57+ case query ( conn , sql , [ publication , schema , table , id , claims , filters ] ) do
58+ { :ok , % { num_rows: num } = result } when num > 0 ->
59+ send ( manager , { :subscribed , { caller , id } } )
60+ result
6061
61- { :ok , _ } ->
62- msg =
63- "Unable to subscribe to changes with given parameters. Please check Realtime is enabled for the given connect parameters: [#{ params_to_log ( params ) } ]"
62+ { :ok , _ } ->
63+ msg =
64+ "Unable to subscribe to changes with given parameters. Please check Realtime is enabled for the given connect parameters: [#{ params_to_log ( params ) } ]"
6465
65- rollback ( conn , msg )
66+ rollback ( conn , msg )
6667
67- { :error , exception } ->
68- msg =
69- "Unable to subscribe to changes with given parameters. An exception happened so please check your connect parameters: [#{ params_to_log ( params ) } ]. Exception: #{ Exception . message ( exception ) } "
68+ { :error , exception } ->
69+ msg =
70+ "Unable to subscribe to changes with given parameters. An exception happened so please check your connect parameters: [#{ params_to_log ( params ) } ]. Exception: #{ Exception . message ( exception ) } "
7071
71- rollback ( conn , msg )
72- end
73-
74- { :error , reason } ->
75- rollback ( conn , reason )
72+ rollback ( conn , msg )
7673 end
7774 end )
7875 end )
7976 end
8077
81- defp params_to_log ( map ) do
82- map
83- |> Map . to_list ( )
78+ defp params_to_log ( { schema , table , filters } ) do
79+ % { schema: schema , table: table , filters: filters }
8480 |> Enum . map_join ( ", " , fn { k , v } -> "#{ k } : #{ to_log ( v ) } " end )
8581 end
8682
@@ -166,39 +162,55 @@ defmodule Extensions.PostgresCdcRls.Subscriptions do
166162
167163 ## Examples
168164
169- iex> params = %{"schema" => "public", "table" => "messages", "filter" => "subject=eq.hey"}
170- iex> Extensions.PostgresCdcRls.Subscriptions.parse_subscription_params(params)
171- {:ok, ["public", "messages", [{"subject", "eq", "hey"}]]}
165+ iex> parse_subscription_params(%{"schema" => "public", "table" => "messages", "filter" => "subject=eq.hey"})
166+ {:ok, {"public", "messages", [{"subject", "eq", "hey"}]}}
172167
173168 `in` filter:
174169
175- iex> params = %{"schema" => "public", "table" => "messages", "filter" => "subject=in.(hidee,ho)"}
176- iex> Extensions.PostgresCdcRls.Subscriptions.parse_subscription_params(params)
177- {:ok, ["public", "messages", [{"subject", "in", "{hidee,ho}"}]]}
170+ iex> parse_subscription_params(%{"schema" => "public", "table" => "messages", "filter" => "subject=in.(hidee,ho)"})
171+ {:ok, {"public", "messages", [{"subject", "in", "{hidee,ho}"}]}}
172+
173+ no filter:
174+
175+ iex> parse_subscription_params(%{"schema" => "public", "table" => "messages"})
176+ {:ok, {"public", "messages", []}}
177+
178+ only schema:
179+
180+ iex> parse_subscription_params(%{"schema" => "public"})
181+ {:ok, {"public", "*", []}}
182+
183+ only table:
184+
185+ iex> parse_subscription_params(%{"table" => "messages"})
186+ {:ok, {"public", "messages", []}}
178187
179188 An unsupported filter will respond with an error tuple:
180189
181- iex> params = %{"schema" => "public", "table" => "messages", "filter" => "subject=like.hey"}
182- iex> Extensions.PostgresCdcRls.Subscriptions.parse_subscription_params(params)
190+ iex> parse_subscription_params(%{"schema" => "public", "table" => "messages", "filter" => "subject=like.hey"})
183191 {:error, ~s(Error parsing `filter` params: ["like", "hey"])}
184192
185193 Catch `undefined` filters:
186194
187- iex> params = %{"schema" => "public", "table" => "messages", "filter" => "undefined"}
188- iex> Extensions.PostgresCdcRls.Subscriptions.parse_subscription_params(params)
195+ iex> parse_subscription_params(%{"schema" => "public", "table" => "messages", "filter" => "undefined"})
189196 {:error, ~s(Error parsing `filter` params: ["undefined"])}
190197
198+ Catch `missing params`:
199+
200+ iex> parse_subscription_params(%{})
201+ {:error, ~s(No subscription params provided. Please provide at least a `schema` or `table` to subscribe to: %{})}
202+
191203 """
192204
193- @ spec parse_subscription_params ( map ( ) ) :: { :ok , list } | { :error , binary ( ) }
205+ @ spec parse_subscription_params ( map ( ) ) :: { :ok , subscription_params } | { :error , binary ( ) }
194206 def parse_subscription_params ( params ) do
195207 case params do
196208 % { "schema" => schema , "table" => table , "filter" => filter } ->
197209 with [ col , rest ] <- String . split ( filter , "=" , parts: 2 ) ,
198210 [ filter_type , value ] when filter_type in @ filter_types <-
199211 String . split ( rest , "." , parts: 2 ) ,
200212 { :ok , formatted_value } <- format_filter_value ( filter_type , value ) do
201- { :ok , [ schema , table , [ { col , filter_type , formatted_value } ] ] }
213+ { :ok , { schema , table , [ { col , filter_type , formatted_value } ] } }
202214 else
203215 { :error , msg } ->
204216 { :error , "Error parsing `filter` params: #{ msg } " }
@@ -208,13 +220,13 @@ defmodule Extensions.PostgresCdcRls.Subscriptions do
208220 end
209221
210222 % { "schema" => schema , "table" => table } ->
211- { :ok , [ schema , table , [ ] ] }
223+ { :ok , { schema , table , [ ] } }
212224
213225 % { "schema" => schema } ->
214- { :ok , [ schema , "*" , [ ] ] }
226+ { :ok , { schema , "*" , [ ] } }
215227
216228 % { "table" => table } ->
217- { :ok , [ "public" , table , [ ] ] }
229+ { :ok , { "public" , table , [ ] } }
218230
219231 map when is_map_key ( map , "user_token" ) or is_map_key ( map , "auth_token" ) ->
220232 { :error ,
0 commit comments