./ct_report/coverage/mod_inbox_rdbms.COVER.html

1 %%%-------------------------------------------------------------------
2 %%% @copyright (C) 2018, Erlang Solutions Ltd.
3 %%% @doc
4 %%%
5 %%% @end
6 %%% Created : 30. Jan 2018 16:59
7 %%%-------------------------------------------------------------------
8 -module(mod_inbox_rdbms).
9
10 -include("mod_inbox.hrl").
11 -include("mongoose_logger.hrl").
12
13 -behaviour(mod_inbox_backend).
14
15 %% API
16 -export([get_inbox/4,
17 init/2,
18 set_inbox/6,
19 set_inbox_incr_unread/5,
20 reset_unread/4,
21 empty_user_bin/4,
22 empty_domain_bin/3,
23 empty_global_bin/2,
24 remove_inbox_row/2,
25 remove_domain/2,
26 clear_inbox/3,
27 get_inbox_unread/2,
28 get_full_entry/2,
29 get_entry_properties/2,
30 set_entry_properties/3]).
31 -export([check_result/1]).
32
33 %% ----------------------------------------------------------------------
34 %% API
35 %% ----------------------------------------------------------------------
36
37 %% TODO pools aren't multitenancy-ready yet
38 init(HostType, Opts) ->
39
:-(
RowCond = <<"WHERE luser = ? AND lserver = ? AND remote_bare_jid = ?">>,
40
:-(
mongoose_rdbms:prepare(inbox_select_entry, inbox,
41 [luser, lserver, remote_bare_jid],
42 <<"SELECT", (query_row())/binary, "FROM inbox ", RowCond/binary>>),
43
:-(
mongoose_rdbms:prepare(inbox_select_unread_count, inbox,
44 [luser, lserver, remote_bare_jid],
45 <<"SELECT unread_count FROM inbox ", RowCond/binary>>),
46
:-(
mongoose_rdbms:prepare(inbox_select_properties, inbox,
47 [luser, lserver, remote_bare_jid],
48 <<"SELECT box, muted_until, unread_count FROM inbox ", RowCond/binary>>),
49
:-(
mongoose_rdbms:prepare(inbox_reset_unread, inbox,
50 [luser, lserver, remote_bare_jid, timestamp],
51 <<"UPDATE inbox SET unread_count = 0 ",
52 RowCond/binary, " AND timestamp <= ?">>),
53
:-(
mongoose_rdbms:prepare(inbox_reset_unread_msg, inbox,
54 [luser, lserver, remote_bare_jid, msg_id, timestamp],
55 <<"UPDATE inbox SET unread_count = 0 ", RowCond/binary,
56 " AND msg_id = ? AND timestamp <= ?">>),
57 % removals
58
:-(
mongoose_rdbms:prepare(inbox_clean_global_bin, inbox, [timestamp],
59 <<"DELETE FROM inbox WHERE box='bin' AND timestamp < ?">>),
60
:-(
mongoose_rdbms:prepare(inbox_clean_domain_bin, inbox, [lserver, timestamp],
61 <<"DELETE FROM inbox WHERE",
62 " lserver = ? AND box='bin' AND timestamp < ?">>),
63
:-(
mongoose_rdbms:prepare(inbox_clean_user_bin, inbox, [lserver, luser, timestamp],
64 <<"DELETE FROM inbox WHERE",
65 " lserver = ? AND luser = ? AND box='bin' AND timestamp < ?">>),
66
:-(
mongoose_rdbms:prepare(inbox_delete_row, inbox,
67 [luser, lserver, remote_bare_jid],
68 <<"DELETE FROM inbox ", RowCond/binary>>),
69
:-(
mongoose_rdbms:prepare(inbox_delete, inbox,
70 [luser, lserver],
71 <<"DELETE FROM inbox WHERE luser = ? AND lserver = ?">>),
72
:-(
prepare_remove_domain(Opts),
73 % upserts
74
:-(
BoxQuery = <<"CASE WHEN ?='bin' THEN 'bin'",
75 " WHEN inbox.box='archive' THEN 'inbox'",
76 " ELSE inbox.box END">>,
77
:-(
UniqueKeyFields = [<<"luser">>, <<"lserver">>, <<"remote_bare_jid">>],
78
:-(
InsertFields = UniqueKeyFields ++ [<<"msg_id">>, <<"box">>, <<"content">>, <<"unread_count">>, <<"timestamp">>],
79
:-(
rdbms_queries:prepare_upsert(HostType, inbox_upsert, inbox,
80 InsertFields,
81 [<<"msg_id">>,
82 {expression, <<"box">>, BoxQuery},
83 <<"content">>,
84 <<"unread_count">>,
85 <<"timestamp">>],
86 UniqueKeyFields, <<"timestamp">>),
87
:-(
rdbms_queries:prepare_upsert(HostType, inbox_upsert_incr_unread, inbox,
88 InsertFields,
89 [<<"msg_id">>,
90 {expression, <<"box">>, BoxQuery},
91 <<"content">>,
92 {expression, <<"unread_count">>, <<"inbox.unread_count + ?">>},
93 <<"timestamp">>],
94 UniqueKeyFields, <<"timestamp">>),
95
:-(
ok.
96
97 prepare_remove_domain(#{delete_domain_limit := infinity}) ->
98
:-(
mongoose_rdbms:prepare(
99 inbox_delete_domain, inbox, [lserver], <<"DELETE FROM inbox WHERE lserver = ?">>);
100 prepare_remove_domain(#{delete_domain_limit := Limit}) ->
101
:-(
LimitSQL = case mongoose_rdbms:db_type() of
102
:-(
mssql -> throw(delete_domain_limit_not_supported_for_mssql);
103
:-(
_ -> {MaybeLimitSQL, _} = rdbms_queries:get_db_specific_limits_binaries(Limit),
104
:-(
MaybeLimitSQL
105 end,
106
:-(
ServerTable = <<"(SELECT * FROM ",
107 "(SELECT lserver, luser, remote_bare_jid FROM inbox",
108 " WHERE lserver = ? ", LimitSQL/binary, ") AS T)">>,
109
:-(
mongoose_rdbms:prepare(
110 inbox_incr_delete_domain, inbox, [lserver],
111 <<"DELETE FROM inbox WHERE (lserver, luser, remote_bare_jid) IN ", ServerTable/binary>>).
112
113 -spec get_inbox(HostType :: mongooseim:host_type(),
114 LUser :: jid:luser(),
115 LServer :: jid:lserver(),
116 Params :: mod_inbox:get_inbox_params()) -> [mod_inbox:inbox_res()].
117 get_inbox(HostType, LUser, LServer, Params) ->
118
:-(
case get_inbox_rdbms(HostType, LUser, LServer, Params) of
119 {selected, []} ->
120
:-(
[];
121 {selected, Res} ->
122
:-(
[decode_row(HostType, R) || R <- Res]
123 end.
124
125 -spec get_inbox_unread(mongooseim:host_type(), mod_inbox:entry_key()) ->
126 {ok, integer()}.
127 get_inbox_unread(HostType, {LUser, LServer, RemBareJID}) ->
128
:-(
Res = execute_select_unread_count(HostType, LUser, LServer, RemBareJID),
129
:-(
{ok, Val} = check_result(Res),
130 %% We read unread_count value when the message is sent and is not yet in receiver inbox
131 %% so we have to add +1
132
:-(
{ok, Val + 1}.
133
134 -spec set_inbox(HostType, InboxEntryKey, Packet, Count, MsgId, Timestamp) ->
135 mod_inbox:write_res() when
136 HostType :: mongooseim:host_type(),
137 InboxEntryKey :: mod_inbox:entry_key(),
138 Packet :: exml:element(),
139 Count :: integer(),
140 MsgId :: binary(),
141 Timestamp :: integer().
142 set_inbox(HostType, {LUser, LServer, LToBareJid}, Packet, Count, MsgId, Timestamp) ->
143
:-(
Content = exml:to_binary(Packet),
144
:-(
Unique = [LUser, LServer, LToBareJid],
145
:-(
Update = [MsgId, <<"inbox">>, Content, Count, Timestamp],
146
:-(
Insert = [LUser, LServer, LToBareJid, MsgId, <<"inbox">>, Content, Count, Timestamp],
147
:-(
Res = rdbms_queries:execute_upsert(HostType, inbox_upsert, Insert, Update, Unique),
148 %% MySQL returns 1 when an upsert is an insert
149 %% and 2, when an upsert acts as update
150
:-(
check_result_is_expected(Res, [1, 2]).
151
152 -spec empty_user_bin(HostType :: mongooseim:host_type(),
153 LServer :: jid:lserver(),
154 LUser :: jid:luser(),
155 TS :: integer()) -> non_neg_integer().
156 empty_user_bin(HostType, LServer, LUser, TS) ->
157
:-(
{updated, BinN} = mongoose_rdbms:execute_successfully(
158 HostType, inbox_clean_user_bin, [LServer, LUser, TS]),
159
:-(
mongoose_rdbms:result_to_integer(BinN).
160
161 -spec empty_domain_bin(HostType :: mongooseim:host_type(),
162 LServer :: jid:lserver(),
163 TS :: integer()) -> non_neg_integer().
164 empty_domain_bin(HostType, LServer, TS) ->
165
:-(
{updated, BinN} = mongoose_rdbms:execute_successfully(
166 HostType, inbox_clean_domain_bin, [LServer, TS]),
167
:-(
mongoose_rdbms:result_to_integer(BinN).
168
169 -spec empty_global_bin(HostType :: mongooseim:host_type(),
170 TS :: integer()) -> non_neg_integer().
171 empty_global_bin(HostType, TS) ->
172
:-(
case mongoose_rdbms:execute(HostType, inbox_clean_global_bin, [TS]) of
173 {updated, BinN} ->
174
:-(
mongoose_rdbms:result_to_integer(BinN);
175 {Error, Reason} ->
176
:-(
?LOG_WARNING(#{what => inbox_clean_global_bin_failed,
177
:-(
error => Error, reason => Reason}),
178
:-(
0
179 end.
180
181 -spec remove_inbox_row(HostType :: mongooseim:host_type(),
182 InboxEntryKey :: mod_inbox:entry_key()) -> mod_inbox:write_res().
183 remove_inbox_row(HostType, {LUser, LServer, LToBareJid}) ->
184
:-(
Res = execute_delete(HostType, LUser, LServer, LToBareJid),
185
:-(
check_result(Res).
186
187 -spec remove_domain(HostType :: mongooseim:host_type(),
188 LServer :: jid:lserver()) -> term().
189 remove_domain(HostType, LServer) ->
190
:-(
DeleteDomainLimit = gen_mod:get_module_opt(HostType, mod_inbox, delete_domain_limit),
191
:-(
execute_delete_domain(HostType, LServer, DeleteDomainLimit).
192
193 -spec set_inbox_incr_unread(
194 mongooseim:host_type(), mod_inbox:entry_key(), exml:element(), binary(), integer()) ->
195 mod_inbox:count_res().
196 set_inbox_incr_unread(HostType, Entry, Packet, MsgId, Timestamp) ->
197
:-(
set_inbox_incr_unread(HostType, Entry, Packet, MsgId, Timestamp, 1).
198
199 -spec set_inbox_incr_unread(HostType :: mongooseim:host_type(),
200 InboxEntryKey :: mod_inbox:entry_key(),
201 Packet :: exml:element(),
202 MsgId :: binary(),
203 Timestamp :: integer(),
204 Incrs :: pos_integer()) -> mod_inbox:count_res().
205 set_inbox_incr_unread(HostType, {LUser, LServer, LToBareJid}, Packet, MsgId, Timestamp, Incrs) ->
206
:-(
Content = exml:to_binary(Packet),
207
:-(
Unique = [LUser, LServer, LToBareJid],
208
:-(
Update = [MsgId, <<"inbox">>, Content, Incrs, Timestamp],
209
:-(
Insert = [LUser, LServer, LToBareJid, MsgId, <<"inbox">>, Content, Incrs, Timestamp],
210
:-(
Res = rdbms_queries:execute_upsert(HostType, inbox_upsert_incr_unread, Insert, Update, Unique),
211
:-(
check_result(Res).
212
213 -spec reset_unread(HostType :: mongooseim:host_type(),
214 InboxEntryKey :: mod_inbox:entry_key(),
215 MsgId :: binary() | undefined,
216 TS :: integer()) -> mod_inbox:write_res().
217 reset_unread(HostType, {LUser, LServer, LToBareJid}, MsgId, TS) ->
218
:-(
Res = execute_reset_unread(HostType, LUser, LServer, LToBareJid, MsgId, TS),
219
:-(
check_result(Res).
220
221 -spec clear_inbox(HostType :: mongooseim:host_type(),
222 LUser :: jid:luser(),
223 LServer :: jid:lserver()) -> mod_inbox:write_res().
224 clear_inbox(HostType, LUser, LServer) ->
225
:-(
Res = execute_delete(HostType, LUser, LServer),
226
:-(
check_result(Res).
227
228 -spec get_full_entry(HostType :: mongooseim:host_type(),
229 InboxEntryKey :: mod_inbox:entry_key()) ->
230 inbox_res() | nil().
231 get_full_entry(HostType, {LUser, LServer, RemBareJID}) ->
232
:-(
case execute_select_full_entry(HostType, LUser, LServer, RemBareJID) of
233 {selected, []} ->
234
:-(
[];
235 {selected, [Selected]} ->
236
:-(
decode_row(HostType, Selected)
237 end.
238
239 -spec get_entry_properties(HostType :: mongooseim:host_type(),
240 InboxEntryKey :: mod_inbox:entry_key()) ->
241 entry_properties() | nil().
242 get_entry_properties(HostType, {LUser, LServer, RemBareJID}) ->
243
:-(
case execute_select_properties(HostType, LUser, LServer, RemBareJID) of
244 {selected, []} ->
245
:-(
[];
246 {selected, [Selected]} ->
247
:-(
decode_properties(Selected)
248 end.
249
250 -spec set_entry_properties(HostType :: mongooseim:host_type(),
251 InboxEntryKey :: mod_inbox:entry_key(),
252 entry_properties()) ->
253 entry_properties() | {error, binary()}.
254 set_entry_properties(HostType, {LUser, LServer, RemBareJID}, Properties) ->
255
:-(
case set_entry_properties_rdbms(HostType, LUser, LServer, RemBareJID, Properties) of
256 {error, Msg} when is_list(Msg) ->
257
:-(
{error, list_to_binary(Msg)};
258 {error, Msg} ->
259
:-(
{error, Msg};
260 {updated, 0} ->
261
:-(
{error, <<"item-not-found">>};
262 {selected, [Result]} ->
263
:-(
decode_properties(Result)
264 end.
265
266 %% ----------------------------------------------------------------------
267 %% Internal functions
268 %% ----------------------------------------------------------------------
269
270 -spec get_inbox_rdbms(HostType :: mongooseim:host_type(),
271 LUser :: jid:luser(),
272 LServer :: jid:lserver(),
273 Params :: mod_inbox:get_inbox_params()) ->
274 mongoose_rdbms:query_result().
275 get_inbox_rdbms(HostType, LUser, LServer, Params) ->
276
:-(
QueryName = lookup_query_name(Params),
277
:-(
case mongoose_rdbms:prepared(QueryName) of
278 false ->
279
:-(
SQL = lookup_query(Params),
280
:-(
Columns = lookup_query_columns(Params),
281
:-(
mongoose_rdbms:prepare(QueryName, inbox, Columns, SQL);
282 true ->
283
:-(
ok
284 end,
285
:-(
Args = lookup_query_args(LServer, LUser, Params),
286
:-(
mongoose_rdbms:execute_successfully(HostType, QueryName, Args).
287
288 set_entry_properties_rdbms(HostType, LUser, LServer, RemBareJID, Properties) ->
289
:-(
QueryName = update_query_name(Properties),
290
:-(
case mongoose_rdbms:prepared(QueryName) of
291 false ->
292
:-(
SQL = update_properties_query(Properties),
293
:-(
Columns = update_query_columns(Properties),
294
:-(
mongoose_rdbms:prepare(QueryName, inbox, Columns, SQL);
295 true ->
296
:-(
ok
297 end,
298
:-(
{atomic, TransactionResult} =
299 mongoose_rdbms:sql_transaction(
300 LServer,
301
:-(
fun() -> set_entry_properties_t(HostType, QueryName, LUser, LServer, RemBareJID, Properties) end),
302
:-(
TransactionResult.
303
304 -spec set_entry_properties_t(mongooseim:host_type(), atom(), jid:luser(), jid:lserver(), jid:literal_jid(),
305 entry_properties()) ->
306 mongoose_rdbms:query_result().
307 set_entry_properties_t(HostType, QueryName, LUser, LServer, RemBareJID, Properties) ->
308
:-(
Args = update_query_args(LUser, LServer, RemBareJID, Properties),
309
:-(
case mongoose_rdbms:execute_successfully(HostType, QueryName, Args) of
310 {updated, 1} ->
311
:-(
execute_select_properties(HostType, LUser, LServer, RemBareJID);
312 Other ->
313
:-(
Other
314 end.
315
316 %% Inbox lookup
317
318 -spec lookup_query(mod_inbox:get_inbox_params()) -> iolist().
319 lookup_query(#{order := Order} = Params) ->
320
:-(
OrderSQL = order_to_sql(Order),
321
:-(
{LimitSQL, MSLimitSQL} = sql_and_where_limit(maps:get(limit, Params, undefined)),
322
:-(
Conditions = [lookup_sql_condition(Key, maps:get(Key, Params, undefined))
323
:-(
|| Key <- [start, 'end', hidden_read, box]],
324
:-(
["SELECT ", MSLimitSQL, query_row(),
325 " FROM inbox WHERE luser = ? AND lserver = ?", Conditions,
326 " ORDER BY timestamp ", OrderSQL, " ", LimitSQL].
327
328 -spec lookup_query_args(jid:lserver(), jid:luser(), mod_inbox:get_inbox_params()) -> list().
329 lookup_query_args(LServer, LUser, Params) ->
330
:-(
Args = [LUser, LServer | [maps:get(Key, Params) || Key <- lookup_arg_keys(Params)]],
331
:-(
case maps:get(limit, Params, undefined) of
332
:-(
undefined -> Args;
333
:-(
Limit -> rdbms_queries:add_limit_arg(Limit, Args)
334 end.
335
336 -spec lookup_query_columns(mod_inbox:get_inbox_params()) -> [atom()].
337 lookup_query_columns(Params) ->
338
:-(
Columns = [luser, lserver | lists:map(fun param_to_column/1, lookup_arg_keys(Params))],
339
:-(
case maps:get(limit, Params, undefined) of
340
:-(
undefined -> Columns;
341
:-(
_ -> rdbms_queries:add_limit_arg(limit, Columns)
342 end.
343
344 -spec lookup_arg_keys(mod_inbox:get_inbox_params()) -> [atom()].
345 lookup_arg_keys(Params) ->
346
:-(
lists:filter(
347
:-(
fun(box) -> maps:is_key(box, Params) andalso maps:get(box, Params, undefined) =/= <<"all">>;
348
:-(
(Key) -> maps:is_key(Key, Params)
349 end, [start, 'end', box]).
350
351 -spec lookup_query_name(mod_inbox:get_inbox_params()) -> atom().
352 lookup_query_name(Params) ->
353
:-(
IDString = lists:flatmap(fun(Param) ->
354
:-(
param_id(Param, maps:get(Param, Params, undefined))
355 end, lookup_param_keys()),
356
:-(
list_to_atom("inbox_lookup" ++ IDString).
357
358 -spec lookup_param_keys() -> [atom()].
359 lookup_param_keys() ->
360
:-(
[order, limit, start, 'end', hidden_read, box].
361
362 -spec param_to_column(atom()) -> atom().
363
:-(
param_to_column(start) -> timestamp;
364
:-(
param_to_column('end') -> timestamp;
365
:-(
param_to_column(box) -> box.
366
367 -spec param_id(Key :: atom(), Value :: any()) -> string().
368
:-(
param_id(box, undefined) -> "_no_bin";
369
:-(
param_id(box, <<"all">>) -> "";
370
:-(
param_id(box, _) -> "_box";
371
:-(
param_id(_, undefined) -> "";
372
:-(
param_id(order, desc) -> "_desc";
373
:-(
param_id(order, asc) -> "_asc";
374
:-(
param_id(limit, _) -> "_lim";
375
:-(
param_id(start, _) -> "_start";
376
:-(
param_id('end', _) -> "_end";
377
:-(
param_id(hidden_read, true) -> "_hr";
378
:-(
param_id(hidden_read, false) -> "".
379
380 -spec order_to_sql(Order :: asc | desc) -> binary().
381
:-(
order_to_sql(asc) -> <<"ASC">>;
382
:-(
order_to_sql(desc) -> <<"DESC">>.
383
384 -spec sql_and_where_limit(non_neg_integer() | undefined) -> {iolist(), iolist()}.
385 sql_and_where_limit(undefined) ->
386
:-(
{"", ""};
387 sql_and_where_limit(_) ->
388
:-(
rdbms_queries:get_db_specific_limits().
389
390 -spec lookup_sql_condition(Key :: atom(), Value :: any()) -> string().
391 lookup_sql_condition(start, Timestamp) when is_integer(Timestamp) ->
392
:-(
" AND timestamp >= ?";
393 lookup_sql_condition('end', Timestamp) when is_integer(Timestamp) ->
394
:-(
" AND timestamp <= ?";
395 lookup_sql_condition(hidden_read, true) ->
396
:-(
" AND unread_count > 0";
397 lookup_sql_condition(box, undefined) ->
398
:-(
" AND box <> 'bin'";
399 lookup_sql_condition(box, <<"all">>) ->
400
:-(
"";
401 lookup_sql_condition(box, Val) when is_binary(Val) ->
402
:-(
" AND box = ?";
403 lookup_sql_condition(_, _) ->
404
:-(
"".
405
406 %% Property update
407
408 update_properties_query(Properties) ->
409
:-(
KVs = [{Key, maps:get(Key, Properties, undefined)} || Key <- property_keys()],
410
:-(
Parts = [update_sql_part(Key, Value) || {Key, Value} <- KVs, Value =/= undefined],
411
:-(
["UPDATE inbox SET ", string:join(Parts, ", "),
412 " WHERE luser = ? AND lserver = ? AND remote_bare_jid = ?"].
413
414 update_query_args(LUser, LServer, RemBareJID, Properties) ->
415
:-(
[maps:get(Key, Properties) || Key <- update_arg_keys(Properties)] ++
416 [LUser, LServer, RemBareJID].
417
418 update_query_columns(Properties) ->
419
:-(
update_arg_keys(Properties) ++ [luser, lserver, remote_bare_jid].
420
421 update_arg_keys(Properties) ->
422
:-(
lists:filter(fun(Key) -> maps:is_key(Key, Properties) end, [box, muted_until]).
423
424 update_query_name(Properties) ->
425
:-(
IDString = lists:flatmap(fun(Prop) ->
426
:-(
property_id(Prop, maps:get(Prop, Properties, undefined))
427 end, property_keys()),
428
:-(
list_to_atom("inbox_update_properties" ++ IDString).
429
430 property_keys() ->
431
:-(
[unread_count, box, muted_until].
432
433 -spec property_id(Key :: atom(), Value :: any()) -> string().
434
:-(
property_id(_, undefined) -> "";
435
:-(
property_id(unread_count, 0) -> "_read";
436
:-(
property_id(unread_count, 1) -> "_unread";
437
:-(
property_id(box, _) -> "_box";
438
:-(
property_id(muted_until, _) -> "_muted".
439
440 -spec update_sql_part(Key :: atom(), Value :: any()) -> string().
441 update_sql_part(unread_count, 0) ->
442
:-(
"unread_count = 0";
443 update_sql_part(unread_count, 1) ->
444
:-(
"unread_count = CASE unread_count WHEN 0 THEN 1 ELSE unread_count END";
445 update_sql_part(box, Val) when is_binary(Val) ->
446
:-(
"box = ?";
447 update_sql_part(muted_until, Val) when is_integer(Val) ->
448
:-(
"muted_until = ?".
449
450 %% Query execution
451
452 -spec execute_select_unread_count(mongooseim:host_type(), jid:luser(), jid:lserver(), jid:literal_jid()) ->
453 mongoose_rdbms:query_result().
454 execute_select_unread_count(HostType, LUser, LServer, RemBareJID) ->
455
:-(
mongoose_rdbms:execute_successfully(HostType, inbox_select_unread_count,
456 [LUser, LServer, RemBareJID]).
457
458 -spec execute_select_full_entry(mongooseim:host_type(), jid:luser(), jid:lserver(), jid:literal_jid()) ->
459 mongoose_rdbms:query_result().
460 execute_select_full_entry(HostType, LUser, LServer, RemBareJID) ->
461
:-(
mongoose_rdbms:execute_successfully(HostType, inbox_select_entry,
462 [LUser, LServer, RemBareJID]).
463
464 -spec execute_select_properties(mongooseim:host_type(), jid:luser(), jid:lserver(), jid:literal_jid()) ->
465 mongoose_rdbms:query_result().
466 execute_select_properties(HostType, LUser, LServer, RemBareJID) ->
467
:-(
mongoose_rdbms:execute_successfully(HostType, inbox_select_properties,
468 [LUser, LServer, RemBareJID]).
469
470 -spec execute_reset_unread(mongooseim:host_type(), jid:luser(), jid:lserver(), jid:literal_jid(), binary() | undefined, integer()) ->
471 mongoose_rdbms:query_result().
472 execute_reset_unread(HostType, LUser, LServer, RemBareJID, undefined, TS) ->
473
:-(
mongoose_rdbms:execute_successfully(HostType, inbox_reset_unread,
474 [LUser, LServer, RemBareJID, TS]);
475 execute_reset_unread(HostType, LUser, LServer, RemBareJID, MsgId, TS) ->
476
:-(
mongoose_rdbms:execute_successfully(HostType, inbox_reset_unread_msg,
477 [LUser, LServer, RemBareJID, MsgId, TS]).
478
479 -spec execute_delete(mongooseim:host_type(),
480 jid:luser(), jid:lserver(), jid:literal_jid()) ->
481 mongoose_rdbms:query_result().
482 execute_delete(HostType, LUser, LServer, RemBareJID) ->
483
:-(
mongoose_rdbms:execute_successfully(HostType, inbox_delete_row, [LUser, LServer, RemBareJID]).
484
485 -spec execute_delete(mongooseim:host_type(), jid:lserver(), jid:luser()) -> mongoose_rdbms:query_result().
486 execute_delete(HostType, LUser, LServer) ->
487
:-(
mongoose_rdbms:execute_successfully(HostType, inbox_delete, [LUser, LServer]).
488
489 -spec execute_delete_domain(mongooseim:host_type(), jid:lserver(), infinity | non_neg_integer()) ->
490 mongoose_rdbms:query_result().
491 execute_delete_domain(HostType, LServer, infinity) ->
492
:-(
mongoose_rdbms:execute_successfully(HostType, inbox_delete_domain, [LServer]);
493 execute_delete_domain(HostType, LServer, Limit) ->
494
:-(
mod_mam_utils:incremental_delete_domain(HostType, LServer, Limit, [inbox_incr_delete_domain], 0).
495
496 %% DB result processing
497 -type db_return() :: {RemBareJID :: jid:luser(),
498 MsgId :: id(),
499 MsgContents :: binary(),
500 Timestamp :: non_neg_integer() | binary(),
501 Count :: non_neg_integer() | binary(),
502 MutedUntil :: binary(),
503 Box :: binary()}.
504
505 query_row() ->
506
:-(
<<" remote_bare_jid, msg_id, box, content, timestamp, muted_until, unread_count ">>.
507
508 -spec decode_row(mongooseim:host_type(), db_return()) -> inbox_res().
509 decode_row(HostType, {RemBareJID, MsgId, Box, Content, Timestamp, MutedUntil, Count}) ->
510
:-(
{ok, Parsed} = exml:parse(mongoose_rdbms:unescape_binary(HostType, Content)),
511
:-(
BCount = mongoose_rdbms:result_to_integer(Count),
512
:-(
NumericTimestamp = mongoose_rdbms:result_to_integer(Timestamp),
513
:-(
NumericMutedUntil = mongoose_rdbms:result_to_integer(MutedUntil),
514
:-(
#{remote_jid => RemBareJID,
515 msg_id => MsgId,
516 box => Box,
517 msg => Parsed,
518 timestamp => NumericTimestamp,
519 muted_until => NumericMutedUntil,
520 unread_count => BCount,
521 extra => []}.
522
523 -spec decode_properties({_, _, _}) -> entry_properties().
524 decode_properties({Box, BMutedUntil, BCount}) ->
525
:-(
Count = mongoose_rdbms:result_to_integer(BCount),
526
:-(
MutedUntil = mongoose_rdbms:result_to_integer(BMutedUntil),
527
:-(
#{box => Box,
528 unread_count => Count,
529 muted_until => MutedUntil,
530 extra => []}.
531
532 -spec check_result_is_expected(_, list()) -> mod_inbox:write_res().
533 check_result_is_expected({updated, Val}, ValList) when is_list(ValList) ->
534
:-(
case lists:member(Val, ValList) of
535
:-(
true -> ok;
536
:-(
_ -> {error, {expected_does_not_match, Val, ValList}}
537 end;
538 check_result_is_expected(Result, _) ->
539
:-(
{error, {bad_result, Result}}.
540
541 -spec check_result(_) -> mod_inbox:count_res().
542 check_result({selected, []}) ->
543
:-(
{ok, 0};
544 check_result({selected, [{Val}]}) ->
545
:-(
parse_result(Val);
546 check_result({updated, _, [{Val}]}) ->
547
:-(
parse_result(Val);
548 check_result({updated, _}) ->
549
:-(
ok;
550 check_result(Result) ->
551
:-(
{error, {bad_result, Result}}.
552
553 parse_result(Value) when is_integer(Value) ->
554
:-(
{ok, Value};
555 parse_result(Value) when is_binary(Value) ->
556
:-(
{ok, binary_to_integer(Value)};
557 parse_result(null) ->
558
:-(
{ok, 0};
559 parse_result(Value) ->
560
:-(
{error, {unknown_result_value_type, Value}}.
Line Hits Source