1 |
|
%% Copyright (c) 2022 Peter Morgan <peter.james.morgan@gmail.com> |
2 |
|
%% |
3 |
|
%% Licensed under the Apache License, Version 2.0 (the "License"); |
4 |
|
%% you may not use this file except in compliance with the License. |
5 |
|
%% You may obtain a copy of the License at |
6 |
|
%% |
7 |
|
%% http://www.apache.org/licenses/LICENSE-2.0 |
8 |
|
%% |
9 |
|
%% Unless required by applicable law or agreed to in writing, software |
10 |
|
%% distributed under the License is distributed on an "AS IS" BASIS, |
11 |
|
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 |
|
%% See the License for the specific language governing permissions and |
13 |
|
%% limitations under the License. |
14 |
|
|
15 |
|
|
16 |
|
-module(pgmp_types). |
17 |
|
|
18 |
|
|
19 |
|
%% -export([write_file/1]). |
20 |
|
-behaviour(gen_statem). |
21 |
|
-export([cache/1]). |
22 |
|
-export([callback_mode/0]). |
23 |
|
-export([handle_event/4]). |
24 |
|
-export([init/1]). |
25 |
|
-export([server_ref/1]). |
26 |
|
-export([start_link/1]). |
27 |
|
-export([when_ready/1]). |
28 |
|
-export_type([cache/0]). |
29 |
|
-import(pgmp_statem, [nei/1]). |
30 |
|
-include("pgmp_types.hrl"). |
31 |
|
|
32 |
|
|
33 |
|
-type cache() :: #{pgmp:oid() => #{binary() => any()}}. |
34 |
|
|
35 |
|
|
36 |
|
start_link(Arg) -> |
37 |
10 |
gen_statem:start_link( |
38 |
|
{local, server_ref(Arg)}, |
39 |
|
?MODULE, |
40 |
|
[Arg], |
41 |
|
envy_gen:options(?MODULE)). |
42 |
|
|
43 |
|
|
44 |
|
-spec server_ref(pgmp_dbs_sup:db()) -> gen_statem:server_ref(). |
45 |
|
|
46 |
|
server_ref(#{application_name := ApplicationName}) -> |
47 |
76 |
pgmp_util:snake_case([binary_to_list(ApplicationName), ?MODULE]). |
48 |
|
|
49 |
|
|
50 |
|
when_ready(Arg) -> |
51 |
66 |
send_request( |
52 |
|
maps:merge( |
53 |
|
Arg, |
54 |
|
#{request => ?FUNCTION_NAME})). |
55 |
|
|
56 |
|
|
57 |
|
send_request(#{label := _} = Arg) -> |
58 |
:-( |
pgmp_statem:send_request(Arg); |
59 |
|
|
60 |
|
send_request(Arg) -> |
61 |
66 |
pgmp_statem:send_request(Arg#{label => ?MODULE}). |
62 |
|
|
63 |
|
|
64 |
|
%% write_file(Filename) -> |
65 |
|
%% {ok, Header} = file:read_file("HEADER.txt"), |
66 |
|
|
67 |
|
%% file:write_file( |
68 |
|
%% Filename, |
69 |
|
%% [io_lib:fwrite("%% -*- mode: erlang -*-~n", []), |
70 |
|
%% Header, |
71 |
|
%% maps:fold( |
72 |
|
%% fun |
73 |
|
%% (K, V, A) -> |
74 |
|
%% [io_lib:fwrite("~n~p.~n", [{K, V}]) | A] |
75 |
|
%% end, |
76 |
|
%% [], |
77 |
|
%% cache())]). |
78 |
|
|
79 |
|
|
80 |
|
-spec cache(pgmp_dbs_sup:db()) -> cache(). |
81 |
|
|
82 |
|
cache(Arg) -> |
83 |
8129 |
persistent_term:get(persistent_term_name(Arg)). |
84 |
|
|
85 |
|
|
86 |
|
persistent_term_name(#{application_name := ApplicationName}) -> |
87 |
8139 |
pgmp_util:snake_case([binary_to_list(ApplicationName), ?MODULE]). |
88 |
|
|
89 |
|
|
90 |
|
init([Arg]) -> |
91 |
10 |
case pgmp_config:enabled(?MODULE) of |
92 |
|
true -> |
93 |
10 |
{ok, |
94 |
|
unready, |
95 |
|
#{cache => ets:new(?MODULE, []), |
96 |
|
config => Arg, |
97 |
|
requests => gen_statem:reqids_new()}, |
98 |
|
nei(refresh)}; |
99 |
|
|
100 |
|
false -> |
101 |
:-( |
ignore |
102 |
|
end. |
103 |
|
|
104 |
|
|
105 |
|
callback_mode() -> |
106 |
10 |
handle_event_function. |
107 |
|
|
108 |
|
|
109 |
|
handle_event({call, _}, when_ready, unready, _) -> |
110 |
20 |
{keep_state_and_data, postpone}; |
111 |
|
|
112 |
|
handle_event({call, From}, when_ready, ready, _) -> |
113 |
66 |
{keep_state_and_data, {reply, From, ready}}; |
114 |
|
|
115 |
|
handle_event(internal, |
116 |
|
refresh, |
117 |
|
_, |
118 |
|
#{config := Config, requests := Requests} = Data) -> |
119 |
10 |
{keep_state, |
120 |
|
Data#{requests := pgmp_connection:query( |
121 |
|
#{sql=> <<?TYPE_SQL>>, |
122 |
|
label => types, |
123 |
|
server_ref => pgmp_connection:server_ref(Config), |
124 |
|
requests => Requests})}}; |
125 |
|
|
126 |
|
handle_event(info, Msg, _, #{requests := Existing} = Data) -> |
127 |
10 |
case gen_statem:check_response(Msg, Existing, true) of |
128 |
|
{{reply, Reply}, Label, Updated} -> |
129 |
10 |
{keep_state, |
130 |
|
Data#{requests := Updated}, |
131 |
|
nei({response, #{label => Label, reply => Reply}})}; |
132 |
|
|
133 |
|
{{error, {Reason, ServerRef}}, Label, UpdatedRequests} -> |
134 |
:-( |
{stop, |
135 |
|
#{reason => Reason, |
136 |
|
server_ref => ServerRef, |
137 |
|
label => Label}, |
138 |
|
Data#{requests := UpdatedRequests}} |
139 |
|
end; |
140 |
|
|
141 |
|
handle_event(internal, |
142 |
|
{response, #{label := types, reply := Replies}}, |
143 |
|
_, |
144 |
|
_) -> |
145 |
10 |
{keep_state_and_data, [nei(Reply) || Reply <- Replies]}; |
146 |
|
|
147 |
|
handle_event(internal, |
148 |
|
{command_complete, {select, _}}, |
149 |
|
_, |
150 |
|
#{config := Config, cache := Cache} = Data) -> |
151 |
10 |
persistent_term:put( |
152 |
|
persistent_term_name(Config), |
153 |
|
ets:foldl( |
154 |
|
fun |
155 |
|
({{type, OID}, Description}, A) -> |
156 |
6130 |
A#{OID => Description} |
157 |
|
end, |
158 |
|
#{}, |
159 |
|
Cache)), |
160 |
|
|
161 |
10 |
{next_state, ready, maps:without([columns], Data), hibernate}; |
162 |
|
|
163 |
|
handle_event(internal, |
164 |
|
{data_row, Columns}, |
165 |
|
_, |
166 |
|
#{cache := Cache, columns := Names}) -> |
167 |
6130 |
#{<<"oid">> := OID} = Row = maps:map( |
168 |
|
fun data_row/2, |
169 |
|
maps:from_list( |
170 |
|
lists:zip(Names, Columns))), |
171 |
6130 |
ets:insert(Cache, {{type, OID}, maps:without([oid], Row)}), |
172 |
6130 |
keep_state_and_data; |
173 |
|
|
174 |
|
handle_event(internal, {row_description, Columns}, _, Data) -> |
175 |
10 |
{keep_state, Data#{columns => Columns}}. |
176 |
|
|
177 |
|
|
178 |
|
data_row(Column, Value) when Column == <<"oid">>; |
179 |
|
Column == <<"typnamespace">>; |
180 |
|
Column == <<"typowner">>; |
181 |
|
Column == <<"typlen">>; |
182 |
|
Column == <<"typrelid">>; |
183 |
|
Column == <<"typelem">>; |
184 |
|
Column == <<"typarray">>; |
185 |
|
Column == <<"typbasetype">>; |
186 |
|
Column == <<"typtypmod">>; |
187 |
|
Column == <<"typndims">>; |
188 |
|
Column == <<"typcollation">> -> |
189 |
67430 |
binary_to_integer(Value); |
190 |
|
|
191 |
|
data_row(_, Value) -> |
192 |
128730 |
Value. |