Просмотр исходного кода

chore: move template modules to `emqx_utils`

Even though most of the time these modules will be used by
connectors, there are exceptions (namely, `emqx_rule_engine`).
Besides, they are general enough to land there, more so given
that `emqx_placeholder` is already there.
Andrew Mayorov 2 лет назад
Родитель
Сommit
8e4585d64f

+ 13 - 13
apps/emqx_auth/src/emqx_authn/emqx_authn_utils.erl

@@ -108,22 +108,22 @@ check_password_from_selected_map(Algorithm, Selected, Password) ->
     end.
 
 parse_deep(Template) ->
-    Result = emqx_connector_template:parse_deep(Template),
+    Result = emqx_template:parse_deep(Template),
     handle_disallowed_placeholders(Result, {deep, Template}).
 
 parse_str(Template) ->
-    Result = emqx_connector_template:parse(Template),
+    Result = emqx_template:parse(Template),
     handle_disallowed_placeholders(Result, {string, Template}).
 
 parse_sql(Template, ReplaceWith) ->
-    {Statement, Result} = emqx_connector_template_sql:parse_prepstmt(
+    {Statement, Result} = emqx_template_sql:parse_prepstmt(
         Template,
         #{parameters => ReplaceWith, strip_double_quote => true}
     ),
     {Statement, handle_disallowed_placeholders(Result, {string, Template})}.
 
 handle_disallowed_placeholders(Template, Source) ->
-    case emqx_connector_template:validate(?ALLOWED_VARS, Template) of
+    case emqx_template:validate(?ALLOWED_VARS, Template) of
         ok ->
             Template;
         {error, Disallowed} ->
@@ -139,14 +139,14 @@ handle_disallowed_placeholders(Template, Source) ->
             Result = prerender_disallowed_placeholders(Template),
             case Source of
                 {string, _} ->
-                    emqx_connector_template:parse(Result);
+                    emqx_template:parse(Result);
                 {deep, _} ->
-                    emqx_connector_template:parse_deep(Result)
+                    emqx_template:parse_deep(Result)
             end
     end.
 
 prerender_disallowed_placeholders(Template) ->
-    {Result, _} = emqx_connector_template:render(Template, #{}, #{
+    {Result, _} = emqx_template:render(Template, #{}, #{
         var_trans => fun(Name, _) ->
             % NOTE
             % Rendering disallowed placeholders in escaped form, which will then
@@ -162,7 +162,7 @@ prerender_disallowed_placeholders(Template) ->
 render_deep(Template, Credential) ->
     % NOTE
     % Ignoring errors here, undefined bindings will be replaced with empty string.
-    {Term, _Errors} = emqx_connector_template:render(
+    {Term, _Errors} = emqx_template:render(
         Template,
         mapping_credential(Credential),
         #{var_trans => fun to_string/2}
@@ -172,7 +172,7 @@ render_deep(Template, Credential) ->
 render_str(Template, Credential) ->
     % NOTE
     % Ignoring errors here, undefined bindings will be replaced with empty string.
-    {String, _Errors} = emqx_connector_template:render(
+    {String, _Errors} = emqx_template:render(
         Template,
         mapping_credential(Credential),
         #{var_trans => fun to_string/2}
@@ -182,7 +182,7 @@ render_str(Template, Credential) ->
 render_urlencoded_str(Template, Credential) ->
     % NOTE
     % Ignoring errors here, undefined bindings will be replaced with empty string.
-    {String, _Errors} = emqx_connector_template:render(
+    {String, _Errors} = emqx_template:render(
         Template,
         mapping_credential(Credential),
         #{var_trans => fun to_urlencoded_string/2}
@@ -192,7 +192,7 @@ render_urlencoded_str(Template, Credential) ->
 render_sql_params(ParamList, Credential) ->
     % NOTE
     % Ignoring errors here, undefined bindings will be replaced with empty string.
-    {Row, _Errors} = emqx_connector_template:render(
+    {Row, _Errors} = emqx_template:render(
         ParamList,
         mapping_credential(Credential),
         #{var_trans => fun to_sql_valaue/2}
@@ -322,10 +322,10 @@ to_urlencoded_string(Name, Value) ->
     emqx_http_lib:uri_encode(to_string(Name, Value)).
 
 to_string(Name, Value) ->
-    emqx_connector_template:to_string(render_var(Name, Value)).
+    emqx_template:to_string(render_var(Name, Value)).
 
 to_sql_valaue(Name, Value) ->
-    emqx_connector_sql:to_sql_value(render_var(Name, Value)).
+    emqx_utils_sql:to_sql_value(render_var(Name, Value)).
 
 render_var(_, undefined) ->
     % NOTE

+ 2 - 2
apps/emqx_auth/src/emqx_authz/emqx_authz_rule.erl

@@ -184,7 +184,7 @@ compile_topic({eq, Topic}) ->
     {eq, emqx_topic:words(bin(Topic))};
 compile_topic(Topic) ->
     Template = emqx_authz_utils:parse_str(Topic, [?VAR_USERNAME, ?VAR_CLIENTID]),
-    case emqx_connector_template:is_const(Template) of
+    case emqx_template:is_const(Template) of
         true -> emqx_topic:words(bin(Topic));
         false -> {pattern, Template}
     end.
@@ -302,7 +302,7 @@ match_who(_, _) ->
 match_topics(_ClientInfo, _Topic, []) ->
     false;
 match_topics(ClientInfo, Topic, [{pattern, PatternFilter} | Filters]) ->
-    TopicFilter = bin(emqx_connector_template:render_strict(PatternFilter, ClientInfo)),
+    TopicFilter = bin(emqx_template:render_strict(PatternFilter, ClientInfo)),
     match_topic(emqx_topic:words(Topic), emqx_topic:words(TopicFilter)) orelse
         match_topics(ClientInfo, Topic, Filters);
 match_topics(ClientInfo, Topic, [TopicFilter | Filters]) ->

+ 13 - 13
apps/emqx_auth/src/emqx_authz/emqx_authz_utils.erl

@@ -110,15 +110,15 @@ update_config(Path, ConfigRequest) ->
     }).
 
 parse_deep(Template, PlaceHolders) ->
-    Result = emqx_connector_template:parse_deep(Template),
+    Result = emqx_template:parse_deep(Template),
     handle_disallowed_placeholders(Result, {deep, Template}, PlaceHolders).
 
 parse_str(Template, PlaceHolders) ->
-    Result = emqx_connector_template:parse(Template),
+    Result = emqx_template:parse(Template),
     handle_disallowed_placeholders(Result, {string, Template}, PlaceHolders).
 
 parse_sql(Template, ReplaceWith, PlaceHolders) ->
-    {Statement, Result} = emqx_connector_template_sql:parse_prepstmt(
+    {Statement, Result} = emqx_template_sql:parse_prepstmt(
         Template,
         #{parameters => ReplaceWith, strip_double_quote => true}
     ),
@@ -126,7 +126,7 @@ parse_sql(Template, ReplaceWith, PlaceHolders) ->
     {Statement, FResult}.
 
 handle_disallowed_placeholders(Template, Source, Allowed) ->
-    case emqx_connector_template:validate(Allowed, Template) of
+    case emqx_template:validate(Allowed, Template) of
         ok ->
             Template;
         {error, Disallowed} ->
@@ -142,14 +142,14 @@ handle_disallowed_placeholders(Template, Source, Allowed) ->
             Result = prerender_disallowed_placeholders(Template, Allowed),
             case Source of
                 {string, _} ->
-                    emqx_connector_template:parse(Result);
+                    emqx_template:parse(Result);
                 {deep, _} ->
-                    emqx_connector_template:parse_deep(Result)
+                    emqx_template:parse_deep(Result)
             end
     end.
 
 prerender_disallowed_placeholders(Template, Allowed) ->
-    {Result, _} = emqx_connector_template:render(Template, #{}, #{
+    {Result, _} = emqx_template:render(Template, #{}, #{
         var_trans => fun(Name, _) ->
             % NOTE
             % Rendering disallowed placeholders in escaped form, which will then
@@ -165,7 +165,7 @@ prerender_disallowed_placeholders(Template, Allowed) ->
 render_deep(Template, Values) ->
     % NOTE
     % Ignoring errors here, undefined bindings will be replaced with empty string.
-    {Term, _Errors} = emqx_connector_template:render(
+    {Term, _Errors} = emqx_template:render(
         Template,
         client_vars(Values),
         #{var_trans => fun to_string/2}
@@ -175,7 +175,7 @@ render_deep(Template, Values) ->
 render_str(Template, Values) ->
     % NOTE
     % Ignoring errors here, undefined bindings will be replaced with empty string.
-    {String, _Errors} = emqx_connector_template:render(
+    {String, _Errors} = emqx_template:render(
         Template,
         client_vars(Values),
         #{var_trans => fun to_string/2}
@@ -185,7 +185,7 @@ render_str(Template, Values) ->
 render_urlencoded_str(Template, Values) ->
     % NOTE
     % Ignoring errors here, undefined bindings will be replaced with empty string.
-    {String, _Errors} = emqx_connector_template:render(
+    {String, _Errors} = emqx_template:render(
         Template,
         client_vars(Values),
         #{var_trans => fun to_urlencoded_string/2}
@@ -195,7 +195,7 @@ render_urlencoded_str(Template, Values) ->
 render_sql_params(ParamList, Values) ->
     % NOTE
     % Ignoring errors here, undefined bindings will be replaced with empty string.
-    {Row, _Errors} = emqx_connector_template:render(
+    {Row, _Errors} = emqx_template:render(
         ParamList,
         client_vars(Values),
         #{var_trans => fun to_sql_value/2}
@@ -270,10 +270,10 @@ to_urlencoded_string(Name, Value) ->
     emqx_http_lib:uri_encode(to_string(Name, Value)).
 
 to_string(Name, Value) ->
-    emqx_connector_template:to_string(render_var(Name, Value)).
+    emqx_template:to_string(render_var(Name, Value)).
 
 to_sql_value(Name, Value) ->
-    emqx_connector_sql:to_sql_value(render_var(Name, Value)).
+    emqx_utils_sql:to_sql_value(render_var(Name, Value)).
 
 render_var(_, undefined) ->
     % NOTE

+ 2 - 2
apps/emqx_auth/test/emqx_authz/emqx_authz_rule_SUITE.erl

@@ -69,8 +69,8 @@ set_special_configs(_App) ->
 t_compile(_) ->
     % NOTE
     % Some of the following testcase are relying on the internal representation of
-    % `emqx_connector_template:t()`. If the internal representation is changed, these
-    % testcases may fail.
+    % `emqx_template:t()`. If the internal representation is changed, these testcases
+    % may fail.
     ?assertEqual({deny, all, all, [['#']]}, emqx_authz_rule:compile({deny, all})),
 
     ?assertEqual(

+ 2 - 2
apps/emqx_bridge_http/src/emqx_bridge_http_connector.erl

@@ -535,7 +535,7 @@ maybe_parse_template(Key, Conf) ->
     end.
 
 parse_template(String) ->
-    emqx_connector_template:parse(String).
+    emqx_template:parse(String).
 
 process_request(
     #{
@@ -573,7 +573,7 @@ render_headers(HeaderTks, Msg) ->
 
 render_template(Template, Msg) ->
     % NOTE: ignoring errors here, missing variables will be rendered as `"undefined"`.
-    {String, _Errors} = emqx_connector_template:render(Template, Msg),
+    {String, _Errors} = emqx_template:render(Template, Msg),
     String.
 
 render_template_string(Template, Msg) ->

+ 1 - 1
apps/emqx_bridge_http/test/emqx_bridge_http_connector_tests.erl

@@ -84,7 +84,7 @@ is_wrapped(_Other) ->
     false.
 
 untmpl(Tpl) ->
-    iolist_to_binary(emqx_connector_template:render_strict(Tpl, #{})).
+    iolist_to_binary(emqx_template:render_strict(Tpl, #{})).
 
 is_unwrapped_headers(Headers) ->
     lists:all(fun is_unwrapped_header/1, Headers).

+ 0 - 159
apps/emqx_connector/src/emqx_connector_sql.erl

@@ -1,159 +0,0 @@
-%%--------------------------------------------------------------------
-%% Copyright (c) 2022-2023 EMQ Technologies Co., Ltd. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%%     http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%--------------------------------------------------------------------
-
--module(emqx_connector_sql).
-
--export([get_statement_type/1]).
--export([parse_insert/1]).
-
--export([to_sql_value/1]).
--export([to_sql_string/2]).
-
--export([escape_sql/1]).
--export([escape_cql/1]).
--export([escape_mysql/1]).
-
--export_type([value/0]).
-
--type statement_type() :: select | insert | delete.
--type value() :: null | binary() | number() | boolean() | [value()].
-
--dialyzer({no_improper_lists, [escape_mysql/4, escape_prepend/4]}).
-
--spec get_statement_type(iodata()) -> statement_type() | {error, unknown}.
-get_statement_type(Query) ->
-    KnownTypes = #{
-        <<"select">> => select,
-        <<"insert">> => insert,
-        <<"delete">> => delete
-    },
-    case re:run(Query, <<"^\\s*([a-zA-Z]+)">>, [{capture, all_but_first, binary}]) of
-        {match, [Token]} ->
-            maps:get(string:lowercase(Token), KnownTypes, {error, unknown});
-        _ ->
-            {error, unknown}
-    end.
-
-%% @doc Parse an INSERT SQL statement into its INSERT part and the VALUES part.
-%% SQL = <<"INSERT INTO \"abc\" (c1, c2, c3) VALUES (${a}, ${b}, ${c.prop})">>
-%% {ok, {<<"INSERT INTO \"abc\" (c1, c2, c3)">>, <<"(${a}, ${b}, ${c.prop})">>}}
--spec parse_insert(iodata()) ->
-    {ok, {_Statement :: binary(), _Rows :: binary()}} | {error, not_insert_sql}.
-parse_insert(SQL) ->
-    case re:split(SQL, "((?i)values)", [{return, binary}]) of
-        [Part1, _, Part3] ->
-            case string:trim(Part1, leading) of
-                <<"insert", _/binary>> = InsertSQL ->
-                    {ok, {InsertSQL, Part3}};
-                <<"INSERT", _/binary>> = InsertSQL ->
-                    {ok, {InsertSQL, Part3}};
-                _ ->
-                    {error, not_insert_sql}
-            end;
-        _ ->
-            {error, not_insert_sql}
-    end.
-
-%% @doc Convert an Erlang term to a value that can be used primarily in
-%% prepared SQL statements.
--spec to_sql_value(term()) -> value().
-to_sql_value(undefined) -> null;
-to_sql_value(List) when is_list(List) -> List;
-to_sql_value(Bin) when is_binary(Bin) -> Bin;
-to_sql_value(Num) when is_number(Num) -> Num;
-to_sql_value(Bool) when is_boolean(Bool) -> Bool;
-to_sql_value(Atom) when is_atom(Atom) -> atom_to_binary(Atom, utf8);
-to_sql_value(Map) when is_map(Map) -> emqx_utils_json:encode(Map).
-
-%% @doc Convert an Erlang term to a string that can be interpolated in literal
-%% SQL statements. The value is escaped if necessary.
--spec to_sql_string(term(), Options) -> iodata() when
-    Options :: #{
-        escaping => cql | mysql | sql
-    }.
-to_sql_string(String, #{escaping := mysql}) when is_binary(String) ->
-    try
-        escape_mysql(String)
-    catch
-        throw:invalid_utf8 ->
-            [<<"0x">>, binary:encode_hex(String)]
-    end;
-to_sql_string(Term, #{escaping := mysql}) ->
-    maybe_escape(Term, fun escape_mysql/1);
-to_sql_string(Term, #{escaping := cql}) ->
-    maybe_escape(Term, fun escape_cql/1);
-to_sql_string(Term, #{}) ->
-    maybe_escape(Term, fun escape_sql/1).
-
--spec maybe_escape(_Value, fun((binary()) -> iodata())) -> iodata().
-maybe_escape(undefined, _EscapeFun) ->
-    <<"NULL">>;
-maybe_escape(Str, EscapeFun) when is_binary(Str) ->
-    EscapeFun(Str);
-maybe_escape(Str, EscapeFun) when is_list(Str) ->
-    case unicode:characters_to_binary(Str) of
-        Bin when is_binary(Bin) ->
-            EscapeFun(Bin);
-        Otherwise ->
-            error(Otherwise)
-    end;
-maybe_escape(Val, EscapeFun) when is_atom(Val) orelse is_map(Val) ->
-    EscapeFun(emqx_connector_template:to_string(Val));
-maybe_escape(Val, _EscapeFun) ->
-    emqx_connector_template:to_string(Val).
-
--spec escape_sql(binary()) -> iodata().
-escape_sql(S) ->
-    % NOTE
-    % This is a bit misleading: currently, escaping logic in `escape_sql/1` likely
-    % won't work with pgsql since it does not support C-style escapes by default.
-    % https://www.postgresql.org/docs/14/sql-syntax-lexical.html#SQL-SYNTAX-CONSTANTS
-    ES = binary:replace(S, [<<"\\">>, <<"'">>], <<"\\">>, [global, {insert_replaced, 1}]),
-    [$', ES, $'].
-
--spec escape_cql(binary()) -> iodata().
-escape_cql(S) ->
-    ES = binary:replace(S, <<"'">>, <<"'">>, [global, {insert_replaced, 1}]),
-    [$', ES, $'].
-
--spec escape_mysql(binary()) -> iodata().
-escape_mysql(S0) ->
-    % https://dev.mysql.com/doc/refman/8.0/en/string-literals.html
-    [$', escape_mysql(S0, 0, 0, S0), $'].
-
-%% NOTE
-%% This thing looks more complicated than needed because it's optimized for as few
-%% intermediate memory (re)allocations as possible.
-escape_mysql(<<$', Rest/binary>>, I, Run, Src) ->
-    escape_prepend(I, Run, Src, [<<"\\'">> | escape_mysql(Rest, I + Run + 1, 0, Src)]);
-escape_mysql(<<$\\, Rest/binary>>, I, Run, Src) ->
-    escape_prepend(I, Run, Src, [<<"\\\\">> | escape_mysql(Rest, I + Run + 1, 0, Src)]);
-escape_mysql(<<0, Rest/binary>>, I, Run, Src) ->
-    escape_prepend(I, Run, Src, [<<"\\0">> | escape_mysql(Rest, I + Run + 1, 0, Src)]);
-escape_mysql(<<_/utf8, Rest/binary>> = S, I, Run, Src) ->
-    CWidth = byte_size(S) - byte_size(Rest),
-    escape_mysql(Rest, I, Run + CWidth, Src);
-escape_mysql(<<>>, 0, _, Src) ->
-    Src;
-escape_mysql(<<>>, I, Run, Src) ->
-    binary:part(Src, I, Run);
-escape_mysql(_, _I, _Run, _Src) ->
-    throw(invalid_utf8).
-
-escape_prepend(_RunI, 0, _Src, Tail) ->
-    Tail;
-escape_prepend(I, Run, Src, Tail) ->
-    [binary:part(Src, I, Run) | Tail].

+ 7 - 7
apps/emqx_mysql/src/emqx_mysql.erl

@@ -46,7 +46,7 @@
     default_port => ?MYSQL_DEFAULT_PORT
 }).
 
--type template() :: {unicode:chardata(), emqx_connector_template:str()}.
+-type template() :: {unicode:chardata(), emqx_template:str()}.
 -type state() ::
     #{
         pool_name := binary(),
@@ -387,16 +387,16 @@ parse_prepare_sql(Config) ->
     #{query_templates => Templates}.
 
 parse_prepare_sql(Key, Query, Acc) ->
-    Template = emqx_connector_template_sql:parse_prepstmt(Query, #{parameters => '?'}),
+    Template = emqx_template_sql:parse_prepstmt(Query, #{parameters => '?'}),
     AccNext = Acc#{{Key, prepstmt} => Template},
     parse_batch_sql(Key, Query, AccNext).
 
 parse_batch_sql(Key, Query, Acc) ->
-    case emqx_connector_sql:get_statement_type(Query) of
+    case emqx_utils_sql:get_statement_type(Query) of
         insert ->
-            case emqx_connector_sql:parse_insert(Query) of
+            case emqx_utils_sql:parse_insert(Query) of
                 {ok, {Insert, Params}} ->
-                    RowTemplate = emqx_connector_template_sql:parse(Params),
+                    RowTemplate = emqx_template_sql:parse(Params),
                     Acc#{{Key, batch} => {Insert, RowTemplate}};
                 {error, Reason} ->
                     ?SLOG(error, #{
@@ -427,7 +427,7 @@ proc_sql_params(TypeOrKey, SQLOrData, Params, #{query_templates := Templates}) -
             {SQLOrData, Params};
         {_InsertPart, RowTemplate} ->
             % NOTE: ignoring errors here, missing variables are set to `null`.
-            {Row, _Errors} = emqx_connector_template_sql:render_prepstmt(RowTemplate, SQLOrData),
+            {Row, _Errors} = emqx_template_sql:render_prepstmt(RowTemplate, SQLOrData),
             {TypeOrKey, Row}
     end.
 
@@ -438,7 +438,7 @@ on_batch_insert(InstId, BatchReqs, {InsertPart, RowTemplate}, State) ->
 
 render_row(RowTemplate, Data) ->
     % NOTE: ignoring errors here, missing variables are set to "NULL".
-    {Row, _Errors} = emqx_connector_template_sql:render(RowTemplate, Data, #{escaping => mysql}),
+    {Row, _Errors} = emqx_template_sql:render(RowTemplate, Data, #{escaping => mysql}),
     Row.
 
 on_sql_query(

+ 3 - 3
apps/emqx_postgresql/src/emqx_postgresql.erl

@@ -52,7 +52,7 @@
     default_port => ?PGSQL_DEFAULT_PORT
 }).
 
--type template() :: {unicode:chardata(), emqx_connector_template_sql:row_template()}.
+-type template() :: {unicode:chardata(), emqx_template_sql:row_template()}.
 -type state() ::
     #{
         pool_name := binary(),
@@ -428,12 +428,12 @@ parse_prepare_sql(Config) ->
     #{query_templates => Templates}.
 
 parse_prepare_sql(Key, Query, Acc) ->
-    Template = emqx_connector_template_sql:parse_prepstmt(Query, #{parameters => '$n'}),
+    Template = emqx_template_sql:parse_prepstmt(Query, #{parameters => '$n'}),
     Acc#{Key => Template}.
 
 render_prepare_sql_row(RowTemplate, Data) ->
     % NOTE: ignoring errors here, missing variables will be replaced with `null`.
-    {Row, _Errors} = emqx_connector_template_sql:render_prepstmt(RowTemplate, Data),
+    {Row, _Errors} = emqx_template_sql:render_prepstmt(RowTemplate, Data),
     Row.
 
 init_prepare(State = #{query_templates := Templates}) when map_size(Templates) == 0 ->

+ 2 - 2
apps/emqx_prometheus/src/emqx_prometheus.erl

@@ -114,8 +114,8 @@ handle_info(_Msg, State) ->
 push_to_push_gateway(Uri, Headers, JobName) when is_list(Headers) ->
     [Name, Ip] = string:tokens(atom_to_list(node()), "@"),
     % NOTE: allowing errors here to keep rough backward compatibility
-    {JobName1, Errors} = emqx_connector_template:render(
-        emqx_connector_template:parse(JobName),
+    {JobName1, Errors} = emqx_template:render(
+        emqx_template:parse(JobName),
         #{<<"name">> => Name, <<"host">> => Ip}
     ),
     _ =

+ 10 - 10
apps/emqx_rule_engine/src/emqx_rule_actions.erl

@@ -71,7 +71,7 @@ pre_process_action_args(
 ) ->
     Args#{
         preprocessed_tmpl => #{
-            topic => emqx_connector_template:parse(Topic),
+            topic => emqx_template:parse(Topic),
             qos => parse_vars(QoS),
             retain => parse_vars(Retain),
             payload => parse_payload(Payload),
@@ -119,8 +119,8 @@ republish(
     }
 ) ->
     % NOTE: rendering missing bindings as string "undefined"
-    {TopicString, _Errors1} = emqx_connector_template:render(TopicTemplate, Selected),
-    {PayloadString, _Errors2} = emqx_connector_template:render(PayloadTemplate, Selected),
+    {TopicString, _Errors1} = emqx_template:render(TopicTemplate, Selected),
+    {PayloadString, _Errors2} = emqx_template:render(PayloadTemplate, Selected),
     Topic = iolist_to_binary(TopicString),
     Payload = iolist_to_binary(PayloadString),
     QoS = render_simple_var(QoSTemplate, Selected, 0),
@@ -202,13 +202,13 @@ safe_publish(RuleId, Topic, QoS, Flags, Payload, PubProps) ->
     emqx_metrics:inc_msg(Msg).
 
 parse_vars(Data) when is_binary(Data) ->
-    emqx_connector_template:parse(Data);
+    emqx_template:parse(Data);
 parse_vars(Data) ->
     {const, Data}.
 
 parse_mqtt_properties(MQTTPropertiesTemplate) ->
     maps:map(
-        fun(_Key, V) -> emqx_connector_template:parse(V) end,
+        fun(_Key, V) -> emqx_template:parse(V) end,
         MQTTPropertiesTemplate
     ).
 
@@ -220,13 +220,13 @@ parse_user_properties(<<"${pub_props.'User-Property'}">>) ->
     ?ORIGINAL_USER_PROPERTIES;
 parse_user_properties(<<"${", _/binary>> = V) ->
     %% use a variable
-    emqx_connector_template:parse(V);
+    emqx_template:parse(V);
 parse_user_properties(_) ->
     %% invalid, discard
     undefined.
 
 render_simple_var([{var, _Name, Accessor}], Data, Default) ->
-    case emqx_connector_template:lookup_var(Accessor, Data) of
+    case emqx_template:lookup_var(Accessor, Data) of
         {ok, Var} -> Var;
         %% cannot find the variable from Data
         {error, _} -> Default
@@ -236,8 +236,8 @@ render_simple_var({const, Val}, _Data, _Default) ->
 
 parse_payload(Payload) ->
     case string:is_empty(Payload) of
-        false -> emqx_connector_template:parse(Payload);
-        true -> emqx_connector_template:parse("${.}")
+        false -> emqx_template:parse(Payload);
+        true -> emqx_template:parse("${.}")
     end.
 
 render_pub_props(UserPropertiesTemplate, Selected, Env) ->
@@ -259,7 +259,7 @@ render_mqtt_properties(MQTTPropertiesTemplate, Selected, Env) ->
             fun(K, Template, Acc) ->
                 try
                     V = unicode:characters_to_binary(
-                        emqx_connector_template:render_strict(Template, Selected)
+                        emqx_template:render_strict(Template, Selected)
                     ),
                     Acc#{K => V}
                 catch

+ 3 - 3
apps/emqx_connector/src/emqx_connector_template.erl

@@ -14,9 +14,7 @@
 %% limitations under the License.
 %%--------------------------------------------------------------------
 
--module(emqx_connector_template).
-
--include_lib("emqx/include/emqx_placeholder.hrl").
+-module(emqx_template).
 
 -export([parse/1]).
 -export([parse/2]).
@@ -76,6 +74,8 @@
     var_trans => var_trans()
 }.
 
+-define(PH_VAR_THIS, '$this').
+
 -define(RE_PLACEHOLDER, "\\$\\{[.]?([a-zA-Z0-9._]*)\\}").
 -define(RE_ESCAPE, "\\$\\{(\\$)\\}").
 

+ 18 - 18
apps/emqx_connector/src/emqx_connector_template_sql.erl

@@ -14,7 +14,7 @@
 %% limitations under the License.
 %%--------------------------------------------------------------------
 
--module(emqx_connector_template_sql).
+-module(emqx_template_sql).
 
 -export([parse/1]).
 -export([parse/2]).
@@ -27,15 +27,15 @@
 
 -export_type([row_template/0]).
 
--type template() :: emqx_connector_template:t().
--type row_template() :: [emqx_connector_template:placeholder()].
--type bindings() :: emqx_connector_template:bindings().
+-type template() :: emqx_template:t().
+-type row_template() :: [emqx_template:placeholder()].
+-type bindings() :: emqx_template:bindings().
 
--type values() :: [emqx_connector_sql:value()].
+-type values() :: [emqx_utils_sql:value()].
 
 -type parse_opts() :: #{
     parameters => '$n' | ':n' | '?',
-    % Inherited from `emqx_connector_template:parse_opts()`
+    % Inherited from `emqx_template:parse_opts()`
     strip_double_quote => boolean()
 }.
 
@@ -57,7 +57,7 @@ parse(String) ->
 -spec parse(unicode:chardata(), parse_opts()) ->
     template().
 parse(String, Opts) ->
-    emqx_connector_template:parse(String, Opts).
+    emqx_template:parse(String, Opts).
 
 %% @doc Render an SQL statement template given a set of bindings.
 %% Interpolation generally follows the SQL syntax, strings are escaped according to the
@@ -65,8 +65,8 @@ parse(String, Opts) ->
 -spec render(template(), bindings(), render_opts()) ->
     {unicode:chardata(), [_Error]}.
 render(Template, Bindings, Opts) ->
-    emqx_connector_template:render(Template, Bindings, #{
-        var_trans => fun(Value) -> emqx_connector_sql:to_sql_string(Value, Opts) end
+    emqx_template:render(Template, Bindings, #{
+        var_trans => fun(Value) -> emqx_utils_sql:to_sql_string(Value, Opts) end
     }).
 
 %% @doc Render an SQL statement template given a set of bindings.
@@ -74,8 +74,8 @@ render(Template, Bindings, Opts) ->
 -spec render_strict(template(), bindings(), render_opts()) ->
     unicode:chardata().
 render_strict(Template, Bindings, Opts) ->
-    emqx_connector_template:render_strict(Template, Bindings, #{
-        var_trans => fun(Value) -> emqx_connector_sql:to_sql_string(Value, Opts) end
+    emqx_template:render_strict(Template, Bindings, #{
+        var_trans => fun(Value) -> emqx_utils_sql:to_sql_string(Value, Opts) end
     }).
 
 %% @doc Parse an SQL statement string into a prepared statement and a row template.
@@ -83,7 +83,7 @@ render_strict(Template, Bindings, Opts) ->
 %% during the execution of the prepared statement.
 %% Example:
 %% ```
-%% {Statement, RowTemplate} = emqx_connector_template_sql:parse_prepstmt(
+%% {Statement, RowTemplate} = emqx_template_sql:parse_prepstmt(
 %%     "INSERT INTO table (id, name, age) VALUES (${id}, ${name}, 42)",
 %%     #{parameters => '$n'}
 %% ),
@@ -93,7 +93,7 @@ render_strict(Template, Bindings, Opts) ->
 -spec parse_prepstmt(unicode:chardata(), parse_opts()) ->
     {unicode:chardata(), row_template()}.
 parse_prepstmt(String, Opts) ->
-    Template = emqx_connector_template:parse(String, maps:with(?TEMPLATE_PARSE_OPTS, Opts)),
+    Template = emqx_template:parse(String, maps:with(?TEMPLATE_PARSE_OPTS, Opts)),
     Statement = mk_prepared_statement(Template, Opts),
     Placeholders = [Placeholder || Placeholder <- Template, element(1, Placeholder) == var],
     {Statement, Placeholders}.
@@ -123,15 +123,15 @@ mk_replace(':n', N) ->
 %% @doc Render a row template into a list of SQL values.
 %% An _SQL value_ is a vaguely defined concept here, it is something that's considered
 %% compatible with the protocol of the database being used. See the definition of
-%% `emqx_connector_sql:value()` for more details.
+%% `emqx_utils_sql:value()` for more details.
 -spec render_prepstmt(template(), bindings()) ->
     {values(), [_Error]}.
 render_prepstmt(Template, Bindings) ->
-    Opts = #{var_trans => fun emqx_connector_sql:to_sql_value/1},
-    emqx_connector_template:render(Template, Bindings, Opts).
+    Opts = #{var_trans => fun emqx_utils_sql:to_sql_value/1},
+    emqx_template:render(Template, Bindings, Opts).
 
 -spec render_prepstmt_strict(template(), bindings()) ->
     values().
 render_prepstmt_strict(Template, Bindings) ->
-    Opts = #{var_trans => fun emqx_connector_sql:to_sql_value/1},
-    emqx_connector_template:render_strict(Template, Bindings, Opts).
+    Opts = #{var_trans => fun emqx_utils_sql:to_sql_value/1},
+    emqx_template:render_strict(Template, Bindings, Opts).

+ 6 - 4
apps/emqx_utils/src/emqx_utils_sql.erl

@@ -80,7 +80,7 @@ to_sql_value(Map) when is_map(Map) -> emqx_utils_json:encode(Map).
 
 %% @doc Convert an Erlang term to a string that can be interpolated in literal
 %% SQL statements. The value is escaped if necessary.
--spec to_sql_string(term(), Options) -> iodata() when
+-spec to_sql_string(term(), Options) -> unicode:chardata() when
     Options :: #{
         escaping => cql | mysql | sql
     }.
@@ -98,7 +98,9 @@ to_sql_string(Term, #{escaping := cql}) ->
 to_sql_string(Term, #{}) ->
     maybe_escape(Term, fun escape_sql/1).
 
--spec maybe_escape(_Value, fun((binary()) -> iodata())) -> iodata().
+-spec maybe_escape(_Value, fun((binary()) -> iodata())) -> unicode:chardata().
+maybe_escape(undefined, _EscapeFun) ->
+    <<"NULL">>;
 maybe_escape(Str, EscapeFun) when is_binary(Str) ->
     EscapeFun(Str);
 maybe_escape(Str, EscapeFun) when is_list(Str) ->
@@ -109,9 +111,9 @@ maybe_escape(Str, EscapeFun) when is_list(Str) ->
             error(Otherwise)
     end;
 maybe_escape(Val, EscapeFun) when is_atom(Val) orelse is_map(Val) ->
-    EscapeFun(emqx_utils_conv:bin(Val));
+    EscapeFun(emqx_template:to_string(Val));
 maybe_escape(Val, _EscapeFun) ->
-    emqx_utils_conv:bin(Val).
+    emqx_template:to_string(Val).
 
 -spec escape_sql(binary()) -> iodata().
 escape_sql(S) ->

+ 48 - 48
apps/emqx_connector/test/emqx_connector_template_SUITE.erl

@@ -14,7 +14,7 @@
 %% limitations under the License.
 %%--------------------------------------------------------------------
 
--module(emqx_connector_template_SUITE).
+-module(emqx_template_SUITE).
 
 -compile(export_all).
 -compile(nowarn_export_all).
@@ -33,7 +33,7 @@ t_render(_) ->
         l => [0, 1, 1000],
         u => "utf-8 is ǝɹǝɥ"
     },
-    Template = emqx_connector_template:parse(
+    Template = emqx_template:parse(
         <<"a:${a},b:${b},c:${c},d:${d},d1:${d.d1},l:${l},u:${u}">>
     ),
     ?assertEqual(
@@ -43,8 +43,8 @@ t_render(_) ->
 
 t_render_var_trans(_) ->
     Bindings = #{a => <<"1">>, b => 1, c => #{prop => 1.0}},
-    Template = emqx_connector_template:parse(<<"a:${a},b:${b},c:${c.prop}">>),
-    {String, Errors} = emqx_connector_template:render(
+    Template = emqx_template:parse(<<"a:${a},b:${b},c:${c.prop}">>),
+    {String, Errors} = emqx_template:render(
         Template,
         Bindings,
         #{var_trans => fun(Name, _) -> "<" ++ Name ++ ">" end}
@@ -56,10 +56,10 @@ t_render_var_trans(_) ->
 
 t_render_path(_) ->
     Bindings = #{d => #{d1 => <<"hi">>}},
-    Template = emqx_connector_template:parse(<<"d.d1:${d.d1}">>),
+    Template = emqx_template:parse(<<"d.d1:${d.d1}">>),
     ?assertEqual(
         ok,
-        emqx_connector_template:validate(["d.d1"], Template)
+        emqx_template:validate(["d.d1"], Template)
     ),
     ?assertEqual(
         {<<"d.d1:hi">>, []},
@@ -68,10 +68,10 @@ t_render_path(_) ->
 
 t_render_custom_ph(_) ->
     Bindings = #{a => <<"a">>, b => <<"b">>},
-    Template = emqx_connector_template:parse(<<"a:${a},b:${b}">>),
+    Template = emqx_template:parse(<<"a:${a},b:${b}">>),
     ?assertEqual(
         {error, [{"b", disallowed}]},
-        emqx_connector_template:validate(["a"], Template)
+        emqx_template:validate(["a"], Template)
     ),
     ?assertEqual(
         <<"a:a,b:b">>,
@@ -80,8 +80,8 @@ t_render_custom_ph(_) ->
 
 t_render_this(_) ->
     Bindings = #{a => <<"a">>, b => [1, 2, 3]},
-    Template = emqx_connector_template:parse(<<"this:${} / also:${.}">>),
-    ?assertEqual(ok, emqx_connector_template:validate(["."], Template)),
+    Template = emqx_template:parse(<<"this:${} / also:${.}">>),
+    ?assertEqual(ok, emqx_template:validate(["."], Template)),
     ?assertEqual(
         % 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\"}">>,
@@ -90,7 +90,7 @@ t_render_this(_) ->
 
 t_render_missing_bindings(_) ->
     Bindings = #{no => #{}},
-    Template = emqx_connector_template:parse(
+    Template = emqx_template:parse(
         <<"a:${a},b:${b},c:${c},d:${d.d1},e:${no.such_atom_i_swear}">>
     ),
     ?assertEqual(
@@ -116,33 +116,33 @@ t_render_missing_bindings(_) ->
 
 t_unparse(_) ->
     TString = <<"a:${a},b:${b},c:$${c},d:{${d.d1}},e:${$}{e},lit:${$}{$}">>,
-    Template = emqx_connector_template:parse(TString),
+    Template = emqx_template:parse(TString),
     ?assertEqual(
         TString,
-        unicode:characters_to_binary(emqx_connector_template:unparse(Template))
+        unicode:characters_to_binary(emqx_template:unparse(Template))
     ).
 
 t_const(_) ->
     ?assertEqual(
         true,
-        emqx_connector_template:is_const(emqx_connector_template:parse(<<"">>))
+        emqx_template:is_const(emqx_template:parse(<<"">>))
     ),
     ?assertEqual(
         false,
-        emqx_connector_template:is_const(
-            emqx_connector_template:parse(<<"a:${a},b:${b},c:${$}{c}">>)
+        emqx_template:is_const(
+            emqx_template:parse(<<"a:${a},b:${b},c:${$}{c}">>)
         )
     ),
     ?assertEqual(
         true,
-        emqx_connector_template:is_const(
-            emqx_connector_template:parse(<<"a:${$}{a},b:${$}{b}">>)
+        emqx_template:is_const(
+            emqx_template:parse(<<"a:${$}{a},b:${$}{b}">>)
         )
     ).
 
 t_render_partial_ph(_) ->
     Bindings = #{a => <<"1">>, b => 1, c => 1.0, d => #{d1 => <<"hi">>}},
-    Template = emqx_connector_template:parse(<<"a:$a,b:b},c:{c},d:${d">>),
+    Template = emqx_template:parse(<<"a:$a,b:b},c:{c},d:${d">>),
     ?assertEqual(
         <<"a:$a,b:b},c:{c},d:${d">>,
         render_strict_string(Template, Bindings)
@@ -150,7 +150,7 @@ t_render_partial_ph(_) ->
 
 t_parse_escaped(_) ->
     Bindings = #{a => <<"1">>, b => 1, c => "VAR"},
-    Template = emqx_connector_template:parse(<<"a:${a},b:${$}{b},c:${$}{${c}},lit:${$}{$}">>),
+    Template = emqx_template:parse(<<"a:${a},b:${$}{b},c:${$}{${c}},lit:${$}{$}">>),
     ?assertEqual(
         <<"a:1,b:${b},c:${VAR},lit:${$}">>,
         render_strict_string(Template, Bindings)
@@ -158,7 +158,7 @@ t_parse_escaped(_) ->
 
 t_parse_escaped_dquote(_) ->
     Bindings = #{a => <<"1">>, b => 1},
-    Template = emqx_connector_template:parse(<<"a:\"${a}\",b:\"${$}{b}\"">>, #{
+    Template = emqx_template:parse(<<"a:\"${a}\",b:\"${$}{b}\"">>, #{
         strip_double_quote => true
     }),
     ?assertEqual(
@@ -169,30 +169,30 @@ t_parse_escaped_dquote(_) ->
 t_parse_sql_prepstmt(_) ->
     Bindings = #{a => <<"1">>, b => 1, c => 1.0, d => #{d1 => <<"hi">>}},
     {PrepareStatement, RowTemplate} =
-        emqx_connector_template_sql:parse_prepstmt(<<"a:${a},b:${b},c:${c},d:${d}">>, #{
+        emqx_template_sql:parse_prepstmt(<<"a:${a},b:${b},c:${c},d:${d}">>, #{
             parameters => '?'
         }),
     ?assertEqual(<<"a:?,b:?,c:?,d:?">>, bin(PrepareStatement)),
     ?assertEqual(
         {[<<"1">>, 1, 1.0, <<"{\"d1\":\"hi\"}">>], _Errors = []},
-        emqx_connector_template_sql:render_prepstmt(RowTemplate, Bindings)
+        emqx_template_sql:render_prepstmt(RowTemplate, Bindings)
     ).
 
 t_parse_sql_prepstmt_n(_) ->
     Bindings = #{a => undefined, b => true, c => atom, d => #{d1 => 42.1337}},
     {PrepareStatement, RowTemplate} =
-        emqx_connector_template_sql:parse_prepstmt(<<"a:${a},b:${b},c:${c},d:${d}">>, #{
+        emqx_template_sql:parse_prepstmt(<<"a:${a},b:${b},c:${c},d:${d}">>, #{
             parameters => '$n'
         }),
     ?assertEqual(<<"a:$1,b:$2,c:$3,d:$4">>, bin(PrepareStatement)),
     ?assertEqual(
         [null, true, <<"atom">>, <<"{\"d1\":42.1337}">>],
-        emqx_connector_template_sql:render_prepstmt_strict(RowTemplate, Bindings)
+        emqx_template_sql:render_prepstmt_strict(RowTemplate, Bindings)
     ).
 
 t_parse_sql_prepstmt_colon(_) ->
     {PrepareStatement, _RowTemplate} =
-        emqx_connector_template_sql:parse_prepstmt(<<"a=${a},b=${b},c=${c},d=${d}">>, #{
+        emqx_template_sql:parse_prepstmt(<<"a=${a},b=${b},c=${c},d=${d}">>, #{
             parameters => ':n'
         }),
     ?assertEqual(<<"a=:1,b=:2,c=:3,d=:4">>, bin(PrepareStatement)).
@@ -200,9 +200,9 @@ t_parse_sql_prepstmt_colon(_) ->
 t_parse_sql_prepstmt_partial_ph(_) ->
     Bindings = #{a => <<"1">>, b => 1, c => 1.0, d => #{d1 => <<"hi">>}},
     {PrepareStatement, RowTemplate} =
-        emqx_connector_template_sql:parse_prepstmt(<<"a:$a,b:b},c:{c},d:${d">>, #{parameters => '?'}),
+        emqx_template_sql:parse_prepstmt(<<"a:$a,b:b},c:{c},d:${d">>, #{parameters => '?'}),
     ?assertEqual(<<"a:$a,b:b},c:{c},d:${d">>, bin(PrepareStatement)),
-    ?assertEqual([], emqx_connector_template_sql:render_prepstmt_strict(RowTemplate, Bindings)).
+    ?assertEqual([], emqx_template_sql:render_prepstmt_strict(RowTemplate, Bindings)).
 
 t_render_sql(_) ->
     Bindings = #{
@@ -213,14 +213,14 @@ t_render_sql(_) ->
         n => undefined,
         u => "utf8's cool 🐸"
     },
-    Template = emqx_connector_template:parse(<<"a:${a},b:${b},c:${c},d:${d},n:${n},u:${u}">>),
+    Template = emqx_template:parse(<<"a:${a},b:${b},c:${c},d:${d},n:${n},u:${u}">>),
     ?assertMatch(
         {_String, _Errors = []},
-        emqx_connector_template_sql:render(Template, Bindings, #{})
+        emqx_template_sql:render(Template, Bindings, #{})
     ),
     ?assertEqual(
         <<"a:'1',b:1,c:1.0,d:'{\"d1\":\"hi\"}',n:NULL,u:'utf8\\'s cool 🐸'"/utf8>>,
-        bin(emqx_connector_template_sql:render_strict(Template, Bindings, #{}))
+        bin(emqx_template_sql:render_strict(Template, Bindings, #{}))
     ).
 
 t_render_mysql(_) ->
@@ -236,7 +236,7 @@ t_render_mysql(_) ->
         g => "utf8's cool 🐸",
         h => imgood
     },
-    Template = emqx_connector_template_sql:parse(
+    Template = emqx_template_sql:parse(
         <<"a:${a},b:${b},c:${c},d:${d},e:${e},f:${f},g:${g},h:${h}">>
     ),
     ?assertEqual(
@@ -245,7 +245,7 @@ t_render_mysql(_) ->
             "e:'\\\\\\0💩',f:0x6E6F6E2D75746638DCC900,g:'utf8\\'s cool 🐸',"/utf8,
             "h:'imgood'"
         >>,
-        bin(emqx_connector_template_sql:render_strict(Template, Bindings, #{escaping => mysql}))
+        bin(emqx_template_sql:render_strict(Template, Bindings, #{escaping => mysql}))
     ).
 
 t_render_cql(_) ->
@@ -257,18 +257,18 @@ t_render_cql(_) ->
         c => 1.0,
         d => #{d1 => <<"someone's phone">>}
     },
-    Template = emqx_connector_template:parse(<<"a:${a},b:${b},c:${c},d:${d}">>),
+    Template = emqx_template:parse(<<"a:${a},b:${b},c:${c},d:${d}">>),
     ?assertEqual(
         <<"a:'1''''2',b:1,c:1.0,d:'{\"d1\":\"someone''s phone\"}'">>,
-        bin(emqx_connector_template_sql:render_strict(Template, Bindings, #{escaping => cql}))
+        bin(emqx_template_sql:render_strict(Template, Bindings, #{escaping => cql}))
     ).
 
 t_render_sql_custom_ph(_) ->
     {PrepareStatement, RowTemplate} =
-        emqx_connector_template_sql:parse_prepstmt(<<"a:${a},b:${b.c}">>, #{parameters => '$n'}),
+        emqx_template_sql:parse_prepstmt(<<"a:${a},b:${b.c}">>, #{parameters => '$n'}),
     ?assertEqual(
         {error, [{"b.c", disallowed}]},
-        emqx_connector_template:validate(["a"], RowTemplate)
+        emqx_template:validate(["a"], RowTemplate)
     ),
     ?assertEqual(<<"a:$1,b:$2">>, bin(PrepareStatement)).
 
@@ -276,57 +276,57 @@ t_render_sql_strip_double_quote(_) ->
     Bindings = #{a => <<"a">>, b => <<"b">>},
 
     %% no strip_double_quote option: "${key}" -> "value"
-    {PrepareStatement1, RowTemplate1} = emqx_connector_template_sql:parse_prepstmt(
+    {PrepareStatement1, RowTemplate1} = emqx_template_sql:parse_prepstmt(
         <<"a:\"${a}\",b:\"${b}\"">>,
         #{parameters => '$n'}
     ),
     ?assertEqual(<<"a:\"$1\",b:\"$2\"">>, bin(PrepareStatement1)),
     ?assertEqual(
         [<<"a">>, <<"b">>],
-        emqx_connector_template_sql:render_prepstmt_strict(RowTemplate1, Bindings)
+        emqx_template_sql:render_prepstmt_strict(RowTemplate1, Bindings)
     ),
 
     %% strip_double_quote = true:  "${key}" -> value
-    {PrepareStatement2, RowTemplate2} = emqx_connector_template_sql:parse_prepstmt(
+    {PrepareStatement2, RowTemplate2} = emqx_template_sql:parse_prepstmt(
         <<"a:\"${a}\",b:\"${b}\"">>,
         #{parameters => '$n', strip_double_quote => true}
     ),
     ?assertEqual(<<"a:$1,b:$2">>, bin(PrepareStatement2)),
     ?assertEqual(
         [<<"a">>, <<"b">>],
-        emqx_connector_template_sql:render_prepstmt_strict(RowTemplate2, Bindings)
+        emqx_template_sql:render_prepstmt_strict(RowTemplate2, Bindings)
     ).
 
 t_render_tmpl_deep(_) ->
     Bindings = #{a => <<"1">>, b => 1, c => 1.0, d => #{d1 => <<"hi">>}},
 
-    Template = emqx_connector_template:parse_deep(
+    Template = emqx_template:parse_deep(
         #{<<"${a}">> => [<<"$${b}">>, "c", 2, 3.0, '${d}', {[<<"${c}">>, <<"${$}{d}">>], 0}]}
     ),
 
     ?assertEqual(
         {error, [{V, disallowed} || V <- ["b", "c"]]},
-        emqx_connector_template:validate(["a"], Template)
+        emqx_template:validate(["a"], Template)
     ),
 
     ?assertEqual(
         #{<<"1">> => [<<"$1">>, "c", 2, 3.0, '${d}', {[<<"1.0">>, <<"${d}">>], 0}]},
-        emqx_connector_template:render_strict(Template, Bindings)
+        emqx_template:render_strict(Template, Bindings)
     ).
 
 t_unparse_tmpl_deep(_) ->
     Term = #{<<"${a}">> => [<<"$${b}">>, "c", 2, 3.0, '${d}', {[<<"${c}">>], <<"${$}{d}">>, 0}]},
-    Template = emqx_connector_template:parse_deep(Term),
-    ?assertEqual(Term, emqx_connector_template:unparse(Template)).
+    Template = emqx_template:parse_deep(Term),
+    ?assertEqual(Term, emqx_template:unparse(Template)).
 
 %%
 
 render_string(Template, Bindings) ->
-    {String, Errors} = emqx_connector_template:render(Template, Bindings),
+    {String, Errors} = emqx_template:render(Template, Bindings),
     {bin(String), Errors}.
 
 render_strict_string(Template, Bindings) ->
-    bin(emqx_connector_template:render_strict(Template, Bindings)).
+    bin(emqx_template:render_strict(Template, Bindings)).
 
 bin(String) ->
     unicode:characters_to_binary(String).