feat(tpl): unify validations / errors var representations
This commit is contained in:
parent
b812f9af5a
commit
49f5325c67
|
@ -184,7 +184,7 @@ compile_topic({eq, Topic}) ->
|
||||||
{eq, emqx_topic:words(bin(Topic))};
|
{eq, emqx_topic:words(bin(Topic))};
|
||||||
compile_topic(Topic) ->
|
compile_topic(Topic) ->
|
||||||
Template = emqx_connector_template:parse(Topic),
|
Template = emqx_connector_template:parse(Topic),
|
||||||
ok = emqx_connector_template:validate([<<?VAR_USERNAME>>, <<?VAR_CLIENTID>>], Template),
|
ok = emqx_connector_template:validate([?VAR_USERNAME, ?VAR_CLIENTID], Template),
|
||||||
case emqx_connector_template:trivial(Template) of
|
case emqx_connector_template:trivial(Template) of
|
||||||
true -> emqx_topic:words(bin(Topic));
|
true -> emqx_topic:words(bin(Topic));
|
||||||
false -> {pattern, Template}
|
false -> {pattern, Template}
|
||||||
|
|
|
@ -78,13 +78,13 @@ t_compile(_) ->
|
||||||
emqx_authz_rule:compile({allow, {ipaddr, "127.0.0.1"}, all, [{eq, "#"}, {eq, "+"}]})
|
emqx_authz_rule:compile({allow, {ipaddr, "127.0.0.1"}, all, [{eq, "#"}, {eq, "+"}]})
|
||||||
),
|
),
|
||||||
|
|
||||||
?assertEqual(
|
?assertMatch(
|
||||||
{allow,
|
{allow,
|
||||||
{ipaddrs, [
|
{ipaddrs, [
|
||||||
{{127, 0, 0, 1}, {127, 0, 0, 1}, 32},
|
{{127, 0, 0, 1}, {127, 0, 0, 1}, 32},
|
||||||
{{192, 168, 1, 0}, {192, 168, 1, 255}, 24}
|
{{192, 168, 1, 0}, {192, 168, 1, 255}, 24}
|
||||||
]},
|
]},
|
||||||
subscribe, [{pattern, [{var, [<<"clientid">>]}]}]},
|
subscribe, [{pattern, [{var, "clientid", [_]}]}]},
|
||||||
emqx_authz_rule:compile(
|
emqx_authz_rule:compile(
|
||||||
{allow, {ipaddrs, ["127.0.0.1", "192.168.1.0/24"]}, subscribe, [?PH_S_CLIENTID]}
|
{allow, {ipaddrs, ["127.0.0.1", "192.168.1.0/24"]}, subscribe, [?PH_S_CLIENTID]}
|
||||||
)
|
)
|
||||||
|
@ -106,7 +106,7 @@ t_compile(_) ->
|
||||||
{clientid, {re_pattern, _, _, _, _}}
|
{clientid, {re_pattern, _, _, _, _}}
|
||||||
]},
|
]},
|
||||||
publish, [
|
publish, [
|
||||||
{pattern, [{var, [<<"username">>]}]}, {pattern, [{var, [<<"clientid">>]}]}
|
{pattern, [{var, "username", [_]}]}, {pattern, [{var, "clientid", [_]}]}
|
||||||
]},
|
]},
|
||||||
emqx_authz_rule:compile(
|
emqx_authz_rule:compile(
|
||||||
{allow,
|
{allow,
|
||||||
|
@ -118,9 +118,9 @@ t_compile(_) ->
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
|
||||||
?assertEqual(
|
?assertMatch(
|
||||||
{allow, {username, {eq, <<"test">>}}, publish, [
|
{allow, {username, {eq, <<"test">>}}, publish, [
|
||||||
{pattern, [<<"t/foo">>, {var, [<<"username">>]}, <<"boo">>]}
|
{pattern, [<<"t/foo">>, {var, "username", [_]}, <<"boo">>]}
|
||||||
]},
|
]},
|
||||||
emqx_authz_rule:compile({allow, {username, "test"}, publish, ["t/foo${username}boo"]})
|
emqx_authz_rule:compile({allow, {username, "test"}, publish, ["t/foo${username}boo"]})
|
||||||
),
|
),
|
||||||
|
|
|
@ -39,15 +39,15 @@
|
||||||
-endif.
|
-endif.
|
||||||
|
|
||||||
-define(PLACEHOLDERS, [
|
-define(PLACEHOLDERS, [
|
||||||
<<?VAR_USERNAME>>,
|
?VAR_USERNAME,
|
||||||
<<?VAR_CLIENTID>>,
|
?VAR_CLIENTID,
|
||||||
<<?VAR_PEERHOST>>,
|
?VAR_PEERHOST,
|
||||||
<<?VAR_PROTONAME>>,
|
?VAR_PROTONAME,
|
||||||
<<?VAR_MOUNTPOINT>>,
|
?VAR_MOUNTPOINT,
|
||||||
<<?VAR_TOPIC>>,
|
?VAR_TOPIC,
|
||||||
<<?VAR_ACTION>>,
|
?VAR_ACTION,
|
||||||
<<?VAR_CERT_SUBJECT>>,
|
?VAR_CERT_SUBJECT,
|
||||||
<<?VAR_CERT_CN_NAME>>
|
?VAR_CERT_CN_NAME
|
||||||
]).
|
]).
|
||||||
|
|
||||||
-define(PLACEHOLDERS_FOR_RICH_ACTIONS, [
|
-define(PLACEHOLDERS_FOR_RICH_ACTIONS, [
|
||||||
|
|
|
@ -36,11 +36,11 @@
|
||||||
-endif.
|
-endif.
|
||||||
|
|
||||||
-define(PLACEHOLDERS, [
|
-define(PLACEHOLDERS, [
|
||||||
<<?VAR_USERNAME>>,
|
?VAR_USERNAME,
|
||||||
<<?VAR_CLIENTID>>,
|
?VAR_CLIENTID,
|
||||||
<<?VAR_PEERHOST>>,
|
?VAR_PEERHOST,
|
||||||
<<?VAR_CERT_CN_NAME>>,
|
?VAR_CERT_CN_NAME,
|
||||||
<<?VAR_CERT_SUBJECT>>
|
?VAR_CERT_SUBJECT
|
||||||
]).
|
]).
|
||||||
|
|
||||||
description() ->
|
description() ->
|
||||||
|
|
|
@ -38,11 +38,11 @@
|
||||||
-endif.
|
-endif.
|
||||||
|
|
||||||
-define(PLACEHOLDERS, [
|
-define(PLACEHOLDERS, [
|
||||||
<<?VAR_USERNAME>>,
|
?VAR_USERNAME,
|
||||||
<<?VAR_CLIENTID>>,
|
?VAR_CLIENTID,
|
||||||
<<?VAR_PEERHOST>>,
|
?VAR_PEERHOST,
|
||||||
<<?VAR_CERT_CN_NAME>>,
|
?VAR_CERT_CN_NAME,
|
||||||
<<?VAR_CERT_SUBJECT>>
|
?VAR_CERT_SUBJECT
|
||||||
]).
|
]).
|
||||||
|
|
||||||
description() ->
|
description() ->
|
||||||
|
|
|
@ -38,11 +38,11 @@
|
||||||
-endif.
|
-endif.
|
||||||
|
|
||||||
-define(PLACEHOLDERS, [
|
-define(PLACEHOLDERS, [
|
||||||
<<?VAR_USERNAME>>,
|
?VAR_USERNAME,
|
||||||
<<?VAR_CLIENTID>>,
|
?VAR_CLIENTID,
|
||||||
<<?VAR_PEERHOST>>,
|
?VAR_PEERHOST,
|
||||||
<<?VAR_CERT_CN_NAME>>,
|
?VAR_CERT_CN_NAME,
|
||||||
<<?VAR_CERT_SUBJECT>>
|
?VAR_CERT_SUBJECT
|
||||||
]).
|
]).
|
||||||
|
|
||||||
description() ->
|
description() ->
|
||||||
|
|
|
@ -36,11 +36,11 @@
|
||||||
-endif.
|
-endif.
|
||||||
|
|
||||||
-define(PLACEHOLDERS, [
|
-define(PLACEHOLDERS, [
|
||||||
<<?VAR_CERT_CN_NAME>>,
|
?VAR_CERT_CN_NAME,
|
||||||
<<?VAR_CERT_SUBJECT>>,
|
?VAR_CERT_SUBJECT,
|
||||||
<<?VAR_PEERHOST>>,
|
?VAR_PEERHOST,
|
||||||
<<?VAR_CLIENTID>>,
|
?VAR_CLIENTID,
|
||||||
<<?VAR_USERNAME>>
|
?VAR_USERNAME
|
||||||
]).
|
]).
|
||||||
|
|
||||||
description() ->
|
description() ->
|
||||||
|
|
|
@ -37,6 +37,7 @@
|
||||||
-export_type([str/0]).
|
-export_type([str/0]).
|
||||||
-export_type([deep/0]).
|
-export_type([deep/0]).
|
||||||
-export_type([placeholder/0]).
|
-export_type([placeholder/0]).
|
||||||
|
-export_type([varname/0]).
|
||||||
-export_type([bindings/0]).
|
-export_type([bindings/0]).
|
||||||
|
|
||||||
-type t() :: str() | {'$tpl', deeptpl()}.
|
-type t() :: str() | {'$tpl', deeptpl()}.
|
||||||
|
@ -55,8 +56,9 @@
|
||||||
| port()
|
| port()
|
||||||
| reference().
|
| reference().
|
||||||
|
|
||||||
-type placeholder() :: {var, var()}.
|
-type placeholder() :: {var, varname(), accessor()}.
|
||||||
-type var() :: _Name :: [binary()].
|
-type accessor() :: [binary()].
|
||||||
|
-type varname() :: string().
|
||||||
|
|
||||||
-type scalar() :: atom() | unicode:chardata() | number().
|
-type scalar() :: atom() | unicode:chardata() | number().
|
||||||
-type binding() :: scalar() | list(scalar()) | bindings().
|
-type binding() :: scalar() | list(scalar()) | bindings().
|
||||||
|
@ -64,7 +66,7 @@
|
||||||
|
|
||||||
-type var_trans() ::
|
-type var_trans() ::
|
||||||
fun((Value :: term()) -> unicode:chardata())
|
fun((Value :: term()) -> unicode:chardata())
|
||||||
| fun((var(), Value :: term()) -> unicode:chardata()).
|
| fun((varname(), Value :: term()) -> unicode:chardata()).
|
||||||
|
|
||||||
-type parse_opts() :: #{
|
-type parse_opts() :: #{
|
||||||
strip_double_quote => boolean()
|
strip_double_quote => boolean()
|
||||||
|
@ -103,7 +105,7 @@ parse(String, Opts) ->
|
||||||
|
|
||||||
parse_split([Part, _PH, <<>>, Var]) ->
|
parse_split([Part, _PH, <<>>, Var]) ->
|
||||||
% Regular placeholder
|
% Regular placeholder
|
||||||
prepend(Part, [{var, parse_var(Var)}]);
|
prepend(Part, [{var, unicode:characters_to_list(Var), parse_accessor(Var)}]);
|
||||||
parse_split([Part, _PH = <<B1, $$, Rest/binary>>, <<"$">>, _]) ->
|
parse_split([Part, _PH = <<B1, $$, Rest/binary>>, <<"$">>, _]) ->
|
||||||
% Escaped literal, take all but the second byte, which is always `$`.
|
% Escaped literal, take all but the second byte, which is always `$`.
|
||||||
% Important to make a whole token starting with `$` so the `unparse/11`
|
% Important to make a whole token starting with `$` so the `unparse/11`
|
||||||
|
@ -117,7 +119,7 @@ prepend(<<>>, To) ->
|
||||||
prepend(Head, To) ->
|
prepend(Head, To) ->
|
||||||
[Head | To].
|
[Head | To].
|
||||||
|
|
||||||
parse_var(Var) ->
|
parse_accessor(Var) ->
|
||||||
case string:split(Var, <<".">>, all) of
|
case string:split(Var, <<".">>, all) of
|
||||||
[<<>>] ->
|
[<<>>] ->
|
||||||
?PH_VAR_THIS;
|
?PH_VAR_THIS;
|
||||||
|
@ -126,10 +128,9 @@ parse_var(Var) ->
|
||||||
Name
|
Name
|
||||||
end.
|
end.
|
||||||
|
|
||||||
-spec validate([var() | binary()], t()) ->
|
-spec validate([varname()], t()) ->
|
||||||
ok | {error, [_Error :: {var(), disallowed}]}.
|
ok | {error, [_Error :: {varname(), disallowed}]}.
|
||||||
validate(AllowedIn, Template) ->
|
validate(Allowed, Template) ->
|
||||||
Allowed = [try_parse_var(V) || V <- AllowedIn],
|
|
||||||
{_, Errors} = render(Template, #{}),
|
{_, Errors} = render(Template, #{}),
|
||||||
{Used, _} = lists:unzip(Errors),
|
{Used, _} = lists:unzip(Errors),
|
||||||
case lists:usort(Used) -- Allowed of
|
case lists:usort(Used) -- Allowed of
|
||||||
|
@ -139,11 +140,6 @@ validate(AllowedIn, Template) ->
|
||||||
{error, [{Var, disallowed} || Var <- Disallowed]}
|
{error, [{Var, disallowed} || Var <- Disallowed]}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
try_parse_var(Var) when is_binary(Var) ->
|
|
||||||
parse_var(Var);
|
|
||||||
try_parse_var(Name) when is_list(Name) ->
|
|
||||||
Name.
|
|
||||||
|
|
||||||
-spec trivial(t()) ->
|
-spec trivial(t()) ->
|
||||||
boolean().
|
boolean().
|
||||||
trivial(Template) ->
|
trivial(Template) ->
|
||||||
|
@ -156,7 +152,7 @@ unparse({'$tpl', Template}) ->
|
||||||
unparse(Template) ->
|
unparse(Template) ->
|
||||||
unicode:characters_to_list(lists:map(fun unparse_part/1, Template)).
|
unicode:characters_to_list(lists:map(fun unparse_part/1, Template)).
|
||||||
|
|
||||||
unparse_part({var, Name}) ->
|
unparse_part({var, Name, _Accessor}) ->
|
||||||
render_placeholder(Name);
|
render_placeholder(Name);
|
||||||
unparse_part(Part = <<"${", _/binary>>) ->
|
unparse_part(Part = <<"${", _/binary>>) ->
|
||||||
<<"$", Part/binary>>;
|
<<"$", Part/binary>>;
|
||||||
|
@ -164,7 +160,7 @@ unparse_part(Part) ->
|
||||||
Part.
|
Part.
|
||||||
|
|
||||||
render_placeholder(Name) ->
|
render_placeholder(Name) ->
|
||||||
"${" ++ lists:join($., Name) ++ "}".
|
"${" ++ Name ++ "}".
|
||||||
|
|
||||||
%% @doc Render a template with given bindings.
|
%% @doc Render a template with given bindings.
|
||||||
%% Returns a term with all placeholders replaced with values from bindings.
|
%% Returns a term with all placeholders replaced with values from bindings.
|
||||||
|
@ -172,17 +168,17 @@ render_placeholder(Name) ->
|
||||||
%% By default, all binding values are converted to strings using `to_string/1`
|
%% By default, all binding values are converted to strings using `to_string/1`
|
||||||
%% function. Option `var_trans` can be used to override this behaviour.
|
%% function. Option `var_trans` can be used to override this behaviour.
|
||||||
-spec render(t(), bindings()) ->
|
-spec render(t(), bindings()) ->
|
||||||
{term(), [_Error :: {var(), undefined}]}.
|
{term(), [_Error :: {varname(), undefined}]}.
|
||||||
render(Template, Bindings) ->
|
render(Template, Bindings) ->
|
||||||
render(Template, Bindings, #{}).
|
render(Template, Bindings, #{}).
|
||||||
|
|
||||||
-spec render(t(), bindings(), render_opts()) ->
|
-spec render(t(), bindings(), render_opts()) ->
|
||||||
{term(), [_Error :: {var(), undefined}]}.
|
{term(), [_Error :: {varname(), undefined}]}.
|
||||||
render(Template, Bindings, Opts) when is_list(Template) ->
|
render(Template, Bindings, Opts) when is_list(Template) ->
|
||||||
lists:mapfoldl(
|
lists:mapfoldl(
|
||||||
fun
|
fun
|
||||||
({var, Name}, EAcc) ->
|
({var, Name, Accessor}, EAcc) ->
|
||||||
{String, Errors} = render_binding(Name, Bindings, Opts),
|
{String, Errors} = render_binding(Name, Accessor, Bindings, Opts),
|
||||||
{String, Errors ++ EAcc};
|
{String, Errors ++ EAcc};
|
||||||
(String, EAcc) ->
|
(String, EAcc) ->
|
||||||
{String, EAcc}
|
{String, EAcc}
|
||||||
|
@ -193,8 +189,8 @@ render(Template, Bindings, Opts) when is_list(Template) ->
|
||||||
render({'$tpl', Template}, Bindings, Opts) ->
|
render({'$tpl', Template}, Bindings, Opts) ->
|
||||||
render_deep(Template, Bindings, Opts).
|
render_deep(Template, Bindings, Opts).
|
||||||
|
|
||||||
render_binding(Name, Bindings, Opts) ->
|
render_binding(Name, Accessor, Bindings, Opts) ->
|
||||||
case lookup_var(Name, Bindings) of
|
case lookup_var(Accessor, Bindings) of
|
||||||
{ok, Value} ->
|
{ok, Value} ->
|
||||||
{render_value(Name, Value, Opts), []};
|
{render_value(Name, Value, Opts), []};
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
|
@ -231,12 +227,12 @@ render_strict(Template, Bindings, Opts) ->
|
||||||
%% lists are not analyzed for "printability" and are treated as nested terms.
|
%% lists are not analyzed for "printability" and are treated as nested terms.
|
||||||
%% The result is a usual template, and can be fed to other functions in this
|
%% The result is a usual template, and can be fed to other functions in this
|
||||||
%% module.
|
%% module.
|
||||||
-spec parse_deep(unicode:chardata()) ->
|
-spec parse_deep(term()) ->
|
||||||
t().
|
t().
|
||||||
parse_deep(Term) ->
|
parse_deep(Term) ->
|
||||||
parse_deep(Term, #{}).
|
parse_deep(Term, #{}).
|
||||||
|
|
||||||
-spec parse_deep(unicode:chardata(), parse_opts()) ->
|
-spec parse_deep(term(), parse_opts()) ->
|
||||||
t().
|
t().
|
||||||
parse_deep(Term, Opts) ->
|
parse_deep(Term, Opts) ->
|
||||||
{'$tpl', parse_deep_term(Term, Opts)}.
|
{'$tpl', parse_deep_term(Term, Opts)}.
|
||||||
|
@ -305,7 +301,7 @@ unparse_deep(Term) ->
|
||||||
|
|
||||||
%%
|
%%
|
||||||
|
|
||||||
-spec lookup_var(var(), bindings()) ->
|
-spec lookup_var(accessor(), bindings()) ->
|
||||||
{ok, binding()} | {error, undefined}.
|
{ok, binding()} | {error, undefined}.
|
||||||
lookup_var(Var, Value) when Var == ?PH_VAR_THIS orelse Var == [] ->
|
lookup_var(Var, Value) when Var == ?PH_VAR_THIS orelse Var == [] ->
|
||||||
{ok, Value};
|
{ok, Value};
|
||||||
|
|
|
@ -88,14 +88,14 @@ render_strict(Template, Bindings, Opts) ->
|
||||||
%% #{parameters => '$n'}
|
%% #{parameters => '$n'}
|
||||||
%% ),
|
%% ),
|
||||||
%% Statement = <<"INSERT INTO table (id, name, age) VALUES ($1, $2, 42)">>,
|
%% Statement = <<"INSERT INTO table (id, name, age) VALUES ($1, $2, 42)">>,
|
||||||
%% RowTemplate = [{var, [...]}, ...]
|
%% RowTemplate = [{var, "...", [...]}, ...]
|
||||||
%% ```
|
%% ```
|
||||||
-spec parse_prepstmt(unicode:chardata(), parse_opts()) ->
|
-spec parse_prepstmt(unicode:chardata(), parse_opts()) ->
|
||||||
{unicode:chardata(), row_template()}.
|
{unicode:chardata(), row_template()}.
|
||||||
parse_prepstmt(String, Opts) ->
|
parse_prepstmt(String, Opts) ->
|
||||||
Template = emqx_connector_template:parse(String, maps:with(?TEMPLATE_PARSE_OPTS, Opts)),
|
Template = emqx_connector_template:parse(String, maps:with(?TEMPLATE_PARSE_OPTS, Opts)),
|
||||||
Statement = mk_prepared_statement(Template, Opts),
|
Statement = mk_prepared_statement(Template, Opts),
|
||||||
Placeholders = [Placeholder || Placeholder = {var, _} <- Template],
|
Placeholders = [Placeholder || Placeholder <- Template, element(1, Placeholder) == var],
|
||||||
{Statement, Placeholders}.
|
{Statement, Placeholders}.
|
||||||
|
|
||||||
mk_prepared_statement(Template, Opts) ->
|
mk_prepared_statement(Template, Opts) ->
|
||||||
|
@ -103,7 +103,7 @@ mk_prepared_statement(Template, Opts) ->
|
||||||
{Statement, _} =
|
{Statement, _} =
|
||||||
lists:mapfoldl(
|
lists:mapfoldl(
|
||||||
fun
|
fun
|
||||||
({var, _}, Acc) ->
|
(Var, Acc) when element(1, Var) == var ->
|
||||||
mk_replace(ParameterFormat, Acc);
|
mk_replace(ParameterFormat, Acc);
|
||||||
(String, Acc) ->
|
(String, Acc) ->
|
||||||
{String, Acc}
|
{String, Acc}
|
||||||
|
|
|
@ -47,7 +47,7 @@ t_render_var_trans(_) ->
|
||||||
{String, Errors} = emqx_connector_template:render(
|
{String, Errors} = emqx_connector_template:render(
|
||||||
Template,
|
Template,
|
||||||
Bindings,
|
Bindings,
|
||||||
#{var_trans => fun(Name, _) -> "<" ++ lists:join($., Name) ++ ">" end}
|
#{var_trans => fun(Name, _) -> "<" ++ Name ++ ">" end}
|
||||||
),
|
),
|
||||||
?assertEqual(
|
?assertEqual(
|
||||||
{<<"a:<a>,b:<b>,c:<c.prop>">>, []},
|
{<<"a:<a>,b:<b>,c:<c.prop>">>, []},
|
||||||
|
@ -59,7 +59,7 @@ t_render_path(_) ->
|
||||||
Template = emqx_connector_template:parse(<<"d.d1:${d.d1}">>),
|
Template = emqx_connector_template:parse(<<"d.d1:${d.d1}">>),
|
||||||
?assertEqual(
|
?assertEqual(
|
||||||
ok,
|
ok,
|
||||||
emqx_connector_template:validate([<<"d.d1">>], Template)
|
emqx_connector_template:validate(["d.d1"], Template)
|
||||||
),
|
),
|
||||||
?assertEqual(
|
?assertEqual(
|
||||||
{<<"d.d1:hi">>, []},
|
{<<"d.d1:hi">>, []},
|
||||||
|
@ -70,8 +70,8 @@ t_render_custom_ph(_) ->
|
||||||
Bindings = #{a => <<"a">>, b => <<"b">>},
|
Bindings = #{a => <<"a">>, b => <<"b">>},
|
||||||
Template = emqx_connector_template:parse(<<"a:${a},b:${b}">>),
|
Template = emqx_connector_template:parse(<<"a:${a},b:${b}">>),
|
||||||
?assertEqual(
|
?assertEqual(
|
||||||
{error, [{[<<"b">>], disallowed}]},
|
{error, [{"b", disallowed}]},
|
||||||
emqx_connector_template:validate([<<"a">>], Template)
|
emqx_connector_template:validate(["a"], Template)
|
||||||
),
|
),
|
||||||
?assertEqual(
|
?assertEqual(
|
||||||
<<"a:a,b:b">>,
|
<<"a:a,b:b">>,
|
||||||
|
@ -81,7 +81,7 @@ t_render_custom_ph(_) ->
|
||||||
t_render_this(_) ->
|
t_render_this(_) ->
|
||||||
Bindings = #{a => <<"a">>, b => [1, 2, 3]},
|
Bindings = #{a => <<"a">>, b => [1, 2, 3]},
|
||||||
Template = emqx_connector_template:parse(<<"this:${} / also:${.}">>),
|
Template = emqx_connector_template:parse(<<"this:${} / also:${.}">>),
|
||||||
?assertEqual(ok, emqx_connector_template:validate([?PH_VAR_THIS], Template)),
|
?assertEqual(ok, emqx_connector_template:validate(["."], Template)),
|
||||||
?assertEqual(
|
?assertEqual(
|
||||||
% NOTE: order of the keys in the JSON object depends on the JSON encoder
|
% NOTE: order of the keys in the JSON object depends on the JSON encoder
|
||||||
<<"this:{\"b\":[1,2,3],\"a\":\"a\"} / also:{\"b\":[1,2,3],\"a\":\"a\"}">>,
|
<<"this:{\"b\":[1,2,3],\"a\":\"a\"} / also:{\"b\":[1,2,3],\"a\":\"a\"}">>,
|
||||||
|
@ -95,21 +95,21 @@ t_render_missing_bindings(_) ->
|
||||||
),
|
),
|
||||||
?assertEqual(
|
?assertEqual(
|
||||||
{<<"a:,b:,c:,d:,e:">>, [
|
{<<"a:,b:,c:,d:,e:">>, [
|
||||||
{[<<"no">>, <<"such_atom_i_swear">>], undefined},
|
{"no.such_atom_i_swear", undefined},
|
||||||
{[<<"d">>, <<"d1">>], undefined},
|
{"d.d1", undefined},
|
||||||
{[<<"c">>], undefined},
|
{"c", undefined},
|
||||||
{[<<"b">>], undefined},
|
{"b", undefined},
|
||||||
{[<<"a">>], undefined}
|
{"a", undefined}
|
||||||
]},
|
]},
|
||||||
render_string(Template, Bindings)
|
render_string(Template, Bindings)
|
||||||
),
|
),
|
||||||
?assertError(
|
?assertError(
|
||||||
[
|
[
|
||||||
{[<<"no">>, <<"such_atom_i_swear">>], undefined},
|
{"no.such_atom_i_swear", undefined},
|
||||||
{[<<"d">>, <<"d1">>], undefined},
|
{"d.d1", undefined},
|
||||||
{[<<"c">>], undefined},
|
{"c", undefined},
|
||||||
{[<<"b">>], undefined},
|
{"b", undefined},
|
||||||
{[<<"a">>], undefined}
|
{"a", undefined}
|
||||||
],
|
],
|
||||||
render_strict_string(Template, Bindings)
|
render_strict_string(Template, Bindings)
|
||||||
).
|
).
|
||||||
|
@ -256,10 +256,10 @@ t_render_cql(_) ->
|
||||||
|
|
||||||
t_render_sql_custom_ph(_) ->
|
t_render_sql_custom_ph(_) ->
|
||||||
{PrepareStatement, RowTemplate} =
|
{PrepareStatement, RowTemplate} =
|
||||||
emqx_connector_template_sql:parse_prepstmt(<<"a:${a},b:${b}">>, #{parameters => '$n'}),
|
emqx_connector_template_sql:parse_prepstmt(<<"a:${a},b:${b.c}">>, #{parameters => '$n'}),
|
||||||
?assertEqual(
|
?assertEqual(
|
||||||
{error, [{[<<"b">>], disallowed}]},
|
{error, [{"b.c", disallowed}]},
|
||||||
emqx_connector_template:validate([<<"a">>], RowTemplate)
|
emqx_connector_template:validate(["a"], RowTemplate)
|
||||||
),
|
),
|
||||||
?assertEqual(<<"a:$1,b:$2">>, bin(PrepareStatement)).
|
?assertEqual(<<"a:$1,b:$2">>, bin(PrepareStatement)).
|
||||||
|
|
||||||
|
@ -296,8 +296,8 @@ t_render_tmpl_deep(_) ->
|
||||||
),
|
),
|
||||||
|
|
||||||
?assertEqual(
|
?assertEqual(
|
||||||
{error, [{V, disallowed} || V <- [[<<"b">>], [<<"c">>]]]},
|
{error, [{V, disallowed} || V <- ["b", "c"]]},
|
||||||
emqx_connector_template:validate([<<"a">>], Template)
|
emqx_connector_template:validate(["a"], Template)
|
||||||
),
|
),
|
||||||
|
|
||||||
?assertEqual(
|
?assertEqual(
|
||||||
|
|
|
@ -224,8 +224,8 @@ parse_user_properties(_) ->
|
||||||
%% invalid, discard
|
%% invalid, discard
|
||||||
undefined.
|
undefined.
|
||||||
|
|
||||||
render_simple_var([{var, Name}], Data, Default) ->
|
render_simple_var([{var, _Name, Accessor}], Data, Default) ->
|
||||||
case emqx_connector_template:lookup_var(Name, Data) of
|
case emqx_connector_template:lookup_var(Accessor, Data) of
|
||||||
{ok, Var} -> Var;
|
{ok, Var} -> Var;
|
||||||
%% cannot find the variable from Data
|
%% cannot find the variable from Data
|
||||||
{error, _} -> Default
|
{error, _} -> Default
|
||||||
|
|
Loading…
Reference in New Issue