./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 56 RowCond = <<"WHERE luser = ? AND lserver = ? AND remote_bare_jid = ?">>,
40 56 mongoose_rdbms:prepare(inbox_select_entry, inbox,
41 [luser, lserver, remote_bare_jid],
42 <<"SELECT", (query_row())/binary, "FROM inbox ", RowCond/binary>>),
43 56 mongoose_rdbms:prepare(inbox_select_unread_count, inbox,
44 [luser, lserver, remote_bare_jid],
45 <<"SELECT unread_count FROM inbox ", RowCond/binary>>),
46 56 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 56 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 56 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 56 mongoose_rdbms:prepare(inbox_clean_global_bin, inbox, [timestamp],
59 <<"DELETE FROM inbox WHERE box='bin' AND timestamp < ?">>),
60 56 mongoose_rdbms:prepare(inbox_clean_domain_bin, inbox, [lserver, timestamp],
61 <<"DELETE FROM inbox WHERE",
62 " lserver = ? AND box='bin' AND timestamp < ?">>),
63 56 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 56 mongoose_rdbms:prepare(inbox_delete_row, inbox,
67 [luser, lserver, remote_bare_jid],
68 <<"DELETE FROM inbox ", RowCond/binary>>),
69 56 mongoose_rdbms:prepare(inbox_delete, inbox,
70 [luser, lserver],
71 <<"DELETE FROM inbox WHERE luser = ? AND lserver = ?">>),
72 56 prepare_remove_domain(Opts),
73 % upserts
74 56 BoxQuery = <<"CASE WHEN ?='bin' THEN 'bin'",
75 " WHEN inbox.box='archive' THEN 'inbox'",
76 " ELSE inbox.box END">>,
77 56 UniqueKeyFields = [<<"luser">>, <<"lserver">>, <<"remote_bare_jid">>],
78 56 InsertFields = UniqueKeyFields ++ [<<"msg_id">>, <<"box">>, <<"content">>, <<"unread_count">>, <<"timestamp">>],
79 56 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 56 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 56 ok.
96
97 prepare_remove_domain(#{delete_domain_limit := infinity}) ->
98 54 mongoose_rdbms:prepare(
99 inbox_delete_domain, inbox, [lserver], <<"DELETE FROM inbox WHERE lserver = ?">>);
100 prepare_remove_domain(#{delete_domain_limit := Limit}) ->
101 2 LimitSQL = case mongoose_rdbms:db_type() of
102
:-(
mssql -> throw(delete_domain_limit_not_supported_for_mssql);
103 2 _ -> {MaybeLimitSQL, _} = rdbms_queries:get_db_specific_limits_binaries(Limit),
104 2 MaybeLimitSQL
105 end,
106 2 ServerTable = <<"(SELECT * FROM ",
107 "(SELECT lserver, luser, remote_bare_jid FROM inbox",
108 " WHERE lserver = ? ", LimitSQL/binary, ") AS T)">>,
109 2 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 1133 case get_inbox_rdbms(HostType, LUser, LServer, Params) of
119 {selected, []} ->
120 239 [];
121 {selected, Res} ->
122 894 [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 120 Res = execute_select_unread_count(HostType, LUser, LServer, RemBareJID),
129 120 {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 120 {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 205 Content = exml:to_binary(Packet),
144 205 Unique = [LUser, LServer, LToBareJid],
145 205 Update = [MsgId, <<"inbox">>, Content, Count, Timestamp],
146 205 Insert = [LUser, LServer, LToBareJid, MsgId, <<"inbox">>, Content, Count, Timestamp],
147 205 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 205 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 8 {updated, BinN} = mongoose_rdbms:execute_successfully(
158 HostType, inbox_clean_user_bin, [LServer, LUser, TS]),
159 8 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 7 {updated, BinN} = mongoose_rdbms:execute_successfully(
166 HostType, inbox_clean_domain_bin, [LServer, TS]),
167 7 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 11 case mongoose_rdbms:execute(HostType, inbox_clean_global_bin, [TS]) of
173 {updated, BinN} ->
174 11 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 5 Res = execute_delete(HostType, LUser, LServer, LToBareJid),
185 5 check_result(Res).
186
187 -spec remove_domain(HostType :: mongooseim:host_type(),
188 LServer :: jid:lserver()) -> term().
189 remove_domain(HostType, LServer) ->
190 2 DeleteDomainLimit = gen_mod:get_module_opt(HostType, mod_inbox, delete_domain_limit),
191 2 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 280 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 280 Content = exml:to_binary(Packet),
207 280 Unique = [LUser, LServer, LToBareJid],
208 280 Update = [MsgId, <<"inbox">>, Content, Incrs, Timestamp],
209 280 Insert = [LUser, LServer, LToBareJid, MsgId, <<"inbox">>, Content, Incrs, Timestamp],
210 280 Res = rdbms_queries:execute_upsert(HostType, inbox_upsert_incr_unread, Insert, Update, Unique),
211 280 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 61 Res = execute_reset_unread(HostType, LUser, LServer, LToBareJid, MsgId, TS),
219 61 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 740 Res = execute_delete(HostType, LUser, LServer),
226 740 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 2 case execute_select_full_entry(HostType, LUser, LServer, RemBareJID) of
233 {selected, []} ->
234
:-(
[];
235 {selected, [Selected]} ->
236 2 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 2 case execute_select_properties(HostType, LUser, LServer, RemBareJID) of
244 {selected, []} ->
245
:-(
[];
246 {selected, [Selected]} ->
247 2 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 102 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 8 {error, <<"item-not-found">>};
262 {selected, [Result]} ->
263 94 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 1133 QueryName = lookup_query_name(Params),
277 1133 case mongoose_rdbms:prepared(QueryName) of
278 false ->
279 18 SQL = lookup_query(Params),
280 18 Columns = lookup_query_columns(Params),
281 18 mongoose_rdbms:prepare(QueryName, inbox, Columns, SQL);
282 true ->
283 1115 ok
284 end,
285 1133 Args = lookup_query_args(LServer, LUser, Params),
286 1133 mongoose_rdbms:execute_successfully(HostType, QueryName, Args).
287
288 set_entry_properties_rdbms(HostType, LUser, LServer, RemBareJID, Properties) ->
289 102 QueryName = update_query_name(Properties),
290 102 case mongoose_rdbms:prepared(QueryName) of
291 false ->
292 6 SQL = update_properties_query(Properties),
293 6 Columns = update_query_columns(Properties),
294 6 mongoose_rdbms:prepare(QueryName, inbox, Columns, SQL);
295 true ->
296 96 ok
297 end,
298 102 {atomic, TransactionResult} =
299 mongoose_rdbms:sql_transaction(
300 LServer,
301 102 fun() -> set_entry_properties_t(HostType, QueryName, LUser, LServer, RemBareJID, Properties) end),
302 102 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 102 Args = update_query_args(LUser, LServer, RemBareJID, Properties),
309 102 case mongoose_rdbms:execute_successfully(HostType, QueryName, Args) of
310 {updated, 1} ->
311 94 execute_select_properties(HostType, LUser, LServer, RemBareJID);
312 Other ->
313 8 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 18 OrderSQL = order_to_sql(Order),
321 18 {LimitSQL, MSLimitSQL} = sql_and_where_limit(maps:get(limit, Params, undefined)),
322 18 Conditions = [lookup_sql_condition(Key, maps:get(Key, Params, undefined))
323 18 || Key <- [start, 'end', hidden_read, box]],
324 18 ["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 1133 Args = [LUser, LServer | [maps:get(Key, Params) || Key <- lookup_arg_keys(Params)]],
331 1133 case maps:get(limit, Params, undefined) of
332 1116 undefined -> Args;
333 17 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 18 Columns = [luser, lserver | lists:map(fun param_to_column/1, lookup_arg_keys(Params))],
339 18 case maps:get(limit, Params, undefined) of
340 14 undefined -> Columns;
341 4 _ -> 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 1151 lists:filter(
347 1151 fun(box) -> maps:is_key(box, Params) andalso maps:get(box, Params, undefined) =/= <<"all">>;
348 2302 (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 1133 IDString = lists:flatmap(fun(Param) ->
354 6798 param_id(Param, maps:get(Param, Params, undefined))
355 end, lookup_param_keys()),
356 1133 list_to_atom("inbox_lookup" ++ IDString).
357
358 -spec lookup_param_keys() -> [atom()].
359 lookup_param_keys() ->
360 1133 [order, limit, start, 'end', hidden_read, box].
361
362 -spec param_to_column(atom()) -> atom().
363 7 param_to_column(start) -> timestamp;
364 5 param_to_column('end') -> timestamp;
365 7 param_to_column(box) -> box.
366
367 -spec param_id(Key :: atom(), Value :: any()) -> string().
368 920 param_id(box, undefined) -> "_no_bin";
369 5 param_id(box, <<"all">>) -> "";
370 208 param_id(box, _) -> "_box";
371 3264 param_id(_, undefined) -> "";
372 1078 param_id(order, desc) -> "_desc";
373 55 param_id(order, asc) -> "_asc";
374 17 param_id(limit, _) -> "_lim";
375 60 param_id(start, _) -> "_start";
376 58 param_id('end', _) -> "_end";
377 14 param_id(hidden_read, true) -> "_hr";
378 1119 param_id(hidden_read, false) -> "".
379
380 -spec order_to_sql(Order :: asc | desc) -> binary().
381 5 order_to_sql(asc) -> <<"ASC">>;
382 13 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 14 {"", ""};
387 sql_and_where_limit(_) ->
388 4 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 7 " AND timestamp >= ?";
393 lookup_sql_condition('end', Timestamp) when is_integer(Timestamp) ->
394 5 " AND timestamp <= ?";
395 lookup_sql_condition(hidden_read, true) ->
396 1 " AND unread_count > 0";
397 lookup_sql_condition(box, undefined) ->
398 10 " AND box <> 'bin'";
399 lookup_sql_condition(box, <<"all">>) ->
400 1 "";
401 lookup_sql_condition(box, Val) when is_binary(Val) ->
402 7 " AND box = ?";
403 lookup_sql_condition(_, _) ->
404 41 "".
405
406 %% Property update
407
408 update_properties_query(Properties) ->
409 6 KVs = [{Key, maps:get(Key, Properties, undefined)} || Key <- property_keys()],
410 6 Parts = [update_sql_part(Key, Value) || {Key, Value} <- KVs, Value =/= undefined],
411 6 ["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 102 [maps:get(Key, Properties) || Key <- update_arg_keys(Properties)] ++
416 [LUser, LServer, RemBareJID].
417
418 update_query_columns(Properties) ->
419 6 update_arg_keys(Properties) ++ [luser, lserver, remote_bare_jid].
420
421 update_arg_keys(Properties) ->
422 108 lists:filter(fun(Key) -> maps:is_key(Key, Properties) end, [box, muted_until]).
423
424 update_query_name(Properties) ->
425 102 IDString = lists:flatmap(fun(Prop) ->
426 306 property_id(Prop, maps:get(Prop, Properties, undefined))
427 end, property_keys()),
428 102 list_to_atom("inbox_update_properties" ++ IDString).
429
430 property_keys() ->
431 108 [unread_count, box, muted_until].
432
433 -spec property_id(Key :: atom(), Value :: any()) -> string().
434 194 property_id(_, undefined) -> "";
435 16 property_id(unread_count, 0) -> "_read";
436 8 property_id(unread_count, 1) -> "_unread";
437 68 property_id(box, _) -> "_box";
438 20 property_id(muted_until, _) -> "_muted".
439
440 -spec update_sql_part(Key :: atom(), Value :: any()) -> string().
441 update_sql_part(unread_count, 0) ->
442 3 "unread_count = 0";
443 update_sql_part(unread_count, 1) ->
444 1 "unread_count = CASE unread_count WHEN 0 THEN 1 ELSE unread_count END";
445 update_sql_part(box, Val) when is_binary(Val) ->
446 2 "box = ?";
447 update_sql_part(muted_until, Val) when is_integer(Val) ->
448 3 "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 120 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 2 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 96 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 3 mongoose_rdbms:execute_successfully(HostType, inbox_reset_unread,
474 [LUser, LServer, RemBareJID, TS]);
475 execute_reset_unread(HostType, LUser, LServer, RemBareJID, MsgId, TS) ->
476 58 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 5 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 740 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 1 mongoose_rdbms:execute_successfully(HostType, inbox_delete_domain, [LServer]);
493 execute_delete_domain(HostType, LServer, Limit) ->
494 1 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 74 <<" 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 980 {ok, Parsed} = exml:parse(mongoose_rdbms:unescape_binary(HostType, Content)),
511 980 BCount = mongoose_rdbms:result_to_integer(Count),
512 980 NumericTimestamp = mongoose_rdbms:result_to_integer(Timestamp),
513 980 NumericMutedUntil = mongoose_rdbms:result_to_integer(MutedUntil),
514 980 #{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 96 Count = mongoose_rdbms:result_to_integer(BCount),
526 96 MutedUntil = mongoose_rdbms:result_to_integer(BMutedUntil),
527 96 #{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 205 case lists:member(Val, ValList) of
535 205 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 60 {ok, 0};
544 check_result({selected, [{Val}]}) ->
545 60 parse_result(Val);
546 check_result({updated, _, [{Val}]}) ->
547
:-(
parse_result(Val);
548 check_result({updated, _}) ->
549 1712 ok;
550 check_result(Result) ->
551
:-(
{error, {bad_result, Result}}.
552
553 parse_result(Value) when is_integer(Value) ->
554 60 {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