chore(authz mnesia api): get method supports paging
Signed-off-by: zhanghongtong <rory-z@outlook.com>
This commit is contained in:
parent
1a02e0cfd1
commit
9b3917e0d3
|
@ -118,7 +118,7 @@ definitions() ->
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
, #{type => object,
|
, #{type => object,
|
||||||
required => [cleitnid, rules],
|
required => [clientid, rules],
|
||||||
properties => #{
|
properties => #{
|
||||||
username => #{
|
username => #{
|
||||||
type => string,
|
type => string,
|
||||||
|
@ -164,6 +164,20 @@ records_api() ->
|
||||||
enum => [<<"username">>, <<"clientid">>, <<"all">>]
|
enum => [<<"username">>, <<"clientid">>, <<"all">>]
|
||||||
},
|
},
|
||||||
required => true
|
required => true
|
||||||
|
},
|
||||||
|
#{
|
||||||
|
name => page,
|
||||||
|
in => query,
|
||||||
|
required => false,
|
||||||
|
description => <<"Page Index">>,
|
||||||
|
schema => #{type => integer}
|
||||||
|
},
|
||||||
|
#{
|
||||||
|
name => limit,
|
||||||
|
in => query,
|
||||||
|
required => false,
|
||||||
|
description => <<"Page limit">>,
|
||||||
|
schema => #{type => integer}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
responses => #{
|
responses => #{
|
||||||
|
@ -391,28 +405,59 @@ purge(delete, _) ->
|
||||||
[ ekka_mnesia:dirty_delete(?ACL_TABLE, K) || K <- mnesia:dirty_all_keys(?ACL_TABLE)],
|
[ ekka_mnesia:dirty_delete(?ACL_TABLE, K) || K <- mnesia:dirty_all_keys(?ACL_TABLE)],
|
||||||
{204}.
|
{204}.
|
||||||
|
|
||||||
records(get, #{bindings := #{type := <<"username">>}}) ->
|
records(get, #{bindings := #{type := <<"username">>},
|
||||||
|
query_string := Qs
|
||||||
|
}) ->
|
||||||
MatchSpec = ets:fun2ms(
|
MatchSpec = ets:fun2ms(
|
||||||
fun({?ACL_TABLE, {username, Username}, Rules}) ->
|
fun({?ACL_TABLE, {username, Username}, Rules}) ->
|
||||||
[{username, Username}, {rules, Rules}]
|
[{username, Username}, {rules, Rules}]
|
||||||
end),
|
end),
|
||||||
{200, [ #{username => Username,
|
Format = fun ([{username, Username}, {rules, Rules}]) ->
|
||||||
rules => [ #{topic => Topic,
|
#{username => Username,
|
||||||
action => Action,
|
rules => [ #{topic => Topic,
|
||||||
permission => Permission
|
action => Action,
|
||||||
} || {Permission, Action, Topic} <- Rules]
|
permission => Permission
|
||||||
} || [{username, Username}, {rules, Rules}] <- ets:select(?ACL_TABLE, MatchSpec)]};
|
} || {Permission, Action, Topic} <- Rules]
|
||||||
records(get, #{bindings := #{type := <<"clientid">>}}) ->
|
}
|
||||||
|
end,
|
||||||
|
case Qs of
|
||||||
|
#{<<"limit">> := _, <<"page">> := _} = Page ->
|
||||||
|
{200, emqx_mgmt_api:paginate(?ACL_TABLE, MatchSpec, Page, Format)};
|
||||||
|
#{<<"limit">> := Limit} ->
|
||||||
|
case ets:select(?ACL_TABLE, MatchSpec, binary_to_integer(Limit)) of
|
||||||
|
{Rows, _Continuation} -> {200, [Format(Row) || Row <- Rows ]};
|
||||||
|
'$end_of_table' -> {404, #{code => <<"NOT_FOUND">>, message => <<"Not Found">>}}
|
||||||
|
end;
|
||||||
|
_ ->
|
||||||
|
{200, [Format(Row) || Row <- ets:select(?ACL_TABLE, MatchSpec)]}
|
||||||
|
end;
|
||||||
|
|
||||||
|
records(get, #{bindings := #{type := <<"clientid">>},
|
||||||
|
query_string := Qs
|
||||||
|
}) ->
|
||||||
MatchSpec = ets:fun2ms(
|
MatchSpec = ets:fun2ms(
|
||||||
fun({?ACL_TABLE, {clientid, Clientid}, Rules}) ->
|
fun({?ACL_TABLE, {clientid, Clientid}, Rules}) ->
|
||||||
[{clientid, Clientid}, {rules, Rules}]
|
[{clientid, Clientid}, {rules, Rules}]
|
||||||
end),
|
end),
|
||||||
{200, [ #{clientid => Clientid,
|
Format = fun ([{clientid, Clientid}, {rules, Rules}]) ->
|
||||||
rules => [ #{topic => Topic,
|
#{clientid => Clientid,
|
||||||
action => Action,
|
rules => [ #{topic => Topic,
|
||||||
permission => Permission
|
action => Action,
|
||||||
} || {Permission, Action, Topic} <- Rules]
|
permission => Permission
|
||||||
} || [{clientid, Clientid}, {rules, Rules}] <- ets:select(?ACL_TABLE, MatchSpec)]};
|
} || {Permission, Action, Topic} <- Rules]
|
||||||
|
}
|
||||||
|
end,
|
||||||
|
case Qs of
|
||||||
|
#{<<"limit">> := _, <<"page">> := _} = Page ->
|
||||||
|
{200, emqx_mgmt_api:paginate(?ACL_TABLE, MatchSpec, Page, Format)};
|
||||||
|
#{<<"limit">> := Limit} ->
|
||||||
|
case ets:select(?ACL_TABLE, MatchSpec, binary_to_integer(Limit)) of
|
||||||
|
{Rows, _Continuation} -> {200, [Format(Row) || Row <- Rows ]};
|
||||||
|
'$end_of_table' -> {404, #{code => <<"NOT_FOUND">>, message => <<"Not Found">>}}
|
||||||
|
end;
|
||||||
|
_ ->
|
||||||
|
{200, [Format(Row) || Row <- ets:select(?ACL_TABLE, MatchSpec)]}
|
||||||
|
end;
|
||||||
records(get, #{bindings := #{type := <<"all">>}}) ->
|
records(get, #{bindings := #{type := <<"all">>}}) ->
|
||||||
MatchSpec = ets:fun2ms(
|
MatchSpec = ets:fun2ms(
|
||||||
fun({?ACL_TABLE, all, Rules}) ->
|
fun({?ACL_TABLE, all, Rules}) ->
|
||||||
|
|
|
@ -174,7 +174,17 @@ t_api(_) ->
|
||||||
[#{<<"rules">> := Rules6}] = jsx:decode(Request8),
|
[#{<<"rules">> := Rules6}] = jsx:decode(Request8),
|
||||||
?assertEqual(0, length(Rules6)),
|
?assertEqual(0, length(Rules6)),
|
||||||
|
|
||||||
|
{ok, 204, _} = request(post, uri(["authorization", "sources", "built-in-database", "username"]), [ #{username => N, rules => []} || N <- lists:seq(1, 20) ]),
|
||||||
|
{ok, 200, Request9} = request(get, uri(["authorization", "sources", "built-in-database", "username?page=2&limit=5"]), []),
|
||||||
|
#{<<"data">> := Data1} = jsx:decode(Request9),
|
||||||
|
?assertEqual(5, length(Data1)),
|
||||||
|
|
||||||
|
{ok, 204, _} = request(post, uri(["authorization", "sources", "built-in-database", "clientid"]), [ #{clientid => N, rules => []} || N <- lists:seq(1, 20) ]),
|
||||||
|
{ok, 200, Request10} = request(get, uri(["authorization", "sources", "built-in-database", "clientid?limit=5"]), []),
|
||||||
|
?assertEqual(5, length(jsx:decode(Request10))),
|
||||||
|
|
||||||
{ok, 204, _} = request(delete, uri(["authorization", "sources", "built-in-database", "purge-all"]), []),
|
{ok, 204, _} = request(delete, uri(["authorization", "sources", "built-in-database", "purge-all"]), []),
|
||||||
|
?assertEqual([], mnesia:dirty_all_keys(?ACL_TABLE)),
|
||||||
|
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,9 @@
|
||||||
|
|
||||||
-include_lib("stdlib/include/qlc.hrl").
|
-include_lib("stdlib/include/qlc.hrl").
|
||||||
|
|
||||||
-export([paginate/3]).
|
-export([ paginate/3
|
||||||
|
, paginate/4
|
||||||
|
]).
|
||||||
|
|
||||||
%% first_next query APIs
|
%% first_next query APIs
|
||||||
-export([ params2qs/2
|
-export([ params2qs/2
|
||||||
|
@ -47,6 +49,23 @@ paginate(Tables, Params, RowFun) ->
|
||||||
#{meta => #{page => Page, limit => Limit, count => Count},
|
#{meta => #{page => Page, limit => Limit, count => Count},
|
||||||
data => [RowFun(Row) || Row <- Rows]}.
|
data => [RowFun(Row) || Row <- Rows]}.
|
||||||
|
|
||||||
|
paginate(Tables, MatchSpec, Params, RowFun) ->
|
||||||
|
Qh = query_handle(Tables, MatchSpec),
|
||||||
|
Count = count(Tables, MatchSpec),
|
||||||
|
Page = b2i(page(Params)),
|
||||||
|
Limit = b2i(limit(Params)),
|
||||||
|
Cursor = qlc:cursor(Qh),
|
||||||
|
case Page > 1 of
|
||||||
|
true ->
|
||||||
|
_ = qlc:next_answers(Cursor, (Page - 1) * Limit),
|
||||||
|
ok;
|
||||||
|
false -> ok
|
||||||
|
end,
|
||||||
|
Rows = qlc:next_answers(Cursor, Limit),
|
||||||
|
qlc:delete_cursor(Cursor),
|
||||||
|
#{meta => #{page => Page, limit => Limit, count => Count},
|
||||||
|
data => [RowFun(Row) || Row <- Rows]}.
|
||||||
|
|
||||||
query_handle(Table) when is_atom(Table) ->
|
query_handle(Table) when is_atom(Table) ->
|
||||||
qlc:q([R|| R <- ets:table(Table)]);
|
qlc:q([R|| R <- ets:table(Table)]);
|
||||||
query_handle([Table]) when is_atom(Table) ->
|
query_handle([Table]) when is_atom(Table) ->
|
||||||
|
@ -54,6 +73,16 @@ query_handle([Table]) when is_atom(Table) ->
|
||||||
query_handle(Tables) ->
|
query_handle(Tables) ->
|
||||||
qlc:append([qlc:q([E || E <- ets:table(T)]) || T <- Tables]).
|
qlc:append([qlc:q([E || E <- ets:table(T)]) || T <- Tables]).
|
||||||
|
|
||||||
|
query_handle(Table, MatchSpec) when is_atom(Table) ->
|
||||||
|
Options = {traverse, {select, MatchSpec}},
|
||||||
|
qlc:q([R|| R <- ets:table(Table, Options)]);
|
||||||
|
query_handle([Table], MatchSpec) when is_atom(Table) ->
|
||||||
|
Options = {traverse, {select, MatchSpec}},
|
||||||
|
qlc:q([R|| R <- ets:table(Table, Options)]);
|
||||||
|
query_handle(Tables, MatchSpec) ->
|
||||||
|
Options = {traverse, {select, MatchSpec}},
|
||||||
|
qlc:append([qlc:q([E || E <- ets:table(T, Options)]) || T <- Tables]).
|
||||||
|
|
||||||
count(Table) when is_atom(Table) ->
|
count(Table) when is_atom(Table) ->
|
||||||
ets:info(Table, size);
|
ets:info(Table, size);
|
||||||
count([Table]) when is_atom(Table) ->
|
count([Table]) when is_atom(Table) ->
|
||||||
|
@ -61,8 +90,16 @@ count([Table]) when is_atom(Table) ->
|
||||||
count(Tables) ->
|
count(Tables) ->
|
||||||
lists:sum([count(T) || T <- Tables]).
|
lists:sum([count(T) || T <- Tables]).
|
||||||
|
|
||||||
count(Table, Nodes) ->
|
count(Table, MatchSpec) when is_atom(Table) ->
|
||||||
lists:sum([rpc_call(Node, ets, info, [Table, size], 5000) || Node <- Nodes]).
|
[{MatchPattern, Where, _Re}] = MatchSpec,
|
||||||
|
NMatchSpec = [{MatchPattern, Where, [true]}],
|
||||||
|
ets:select_count(Table, NMatchSpec);
|
||||||
|
count([Table], MatchSpec) when is_atom(Table) ->
|
||||||
|
[{MatchPattern, Where, _Re}] = MatchSpec,
|
||||||
|
NMatchSpec = [{MatchPattern, Where, [true]}],
|
||||||
|
ets:select_count(Table, NMatchSpec);
|
||||||
|
count(Tables, MatchSpec) ->
|
||||||
|
lists:sum([count(T, MatchSpec) || T <- Tables]).
|
||||||
|
|
||||||
page(Params) when is_map(Params) ->
|
page(Params) when is_map(Params) ->
|
||||||
maps:get(<<"page">>, Params, 1);
|
maps:get(<<"page">>, Params, 1);
|
||||||
|
@ -122,7 +159,7 @@ cluster_query(Params, Tab, QsSchema, QueryFun) ->
|
||||||
Rows = do_cluster_query(Nodes, Tab, Qs, QueryFun, Start, Limit+1, []),
|
Rows = do_cluster_query(Nodes, Tab, Qs, QueryFun, Start, Limit+1, []),
|
||||||
Meta = #{page => Page, limit => Limit},
|
Meta = #{page => Page, limit => Limit},
|
||||||
NMeta = case CodCnt =:= 0 of
|
NMeta = case CodCnt =:= 0 of
|
||||||
true -> Meta#{count => count(Tab, Nodes)};
|
true -> Meta#{count => lists:sum([rpc_call(Node, ets, info, [Tab, size], 5000) || Node <- Nodes])};
|
||||||
_ -> Meta#{count => length(Rows)}
|
_ -> Meta#{count => length(Rows)}
|
||||||
end,
|
end,
|
||||||
#{meta => NMeta, data => lists:sublist(Rows, Limit)}.
|
#{meta => NMeta, data => lists:sublist(Rows, Limit)}.
|
||||||
|
|
Loading…
Reference in New Issue