|
|
@@ -83,5 +83,89 @@ render_message(undefined = _PayloadTemplate, Message) ->
|
|
|
render_message(PayloadTemplate, Message) ->
|
|
|
%% Note: mongo expects a map as a document, so the rendered result
|
|
|
%% must be JSON-serializable
|
|
|
- Rendered = emqx_plugin_libs_rule:proc_tmpl(PayloadTemplate, Message),
|
|
|
- emqx_utils_json:decode(Rendered, [return_maps]).
|
|
|
+ format_data(PayloadTemplate, Message).
|
|
|
+
|
|
|
+%% The following function was originally copied over from
|
|
|
+%% https://github.com/emqx/emqx-enterprise/commit/50e3628129720f13f544053600ca1502731e29e0.
|
|
|
+%% The rule engine has support for producing fields that are date tuples
|
|
|
+%% (produced by the SQL language's built-in functions mongo_date/0,
|
|
|
+%% mongo_date/1 and mongo_date/2) which the MongoDB driver recognizes and
|
|
|
+%% converts to the MongoDB ISODate type
|
|
|
+%% (https://www.compose.com/articles/understanding-dates-in-compose-mongodb/).
|
|
|
+%% For this to work we have to replace the tuple values with references, make
|
|
|
+%% an instance of the template, convert the instance to map with the help of
|
|
|
+%% emqx_utils_json:decode and then finally replace the references with the
|
|
|
+%% corresponding tuples in the resulting map.
|
|
|
+format_data(PayloadTks, Msg) ->
|
|
|
+ % Check the Message for any tuples that need to be extracted before running the template though a json parser
|
|
|
+ PreparedTupleMap = create_mapping_of_references_to_tuple_values(Msg),
|
|
|
+ case maps:size(PreparedTupleMap) of
|
|
|
+ % If no tuples were found simply proceed with the json decoding and be done with it
|
|
|
+ 0 ->
|
|
|
+ emqx_utils_json:decode(emqx_plugin_libs_rule:proc_tmpl(PayloadTks, Msg), [return_maps]);
|
|
|
+ _ ->
|
|
|
+ % If tuples were found, replace the tuple values with the references created, run
|
|
|
+ % the modified message through the json parser, and then at the end replace the
|
|
|
+ % references with the actual tuple values.
|
|
|
+ ProcessedMessage = replace_message_values_with_references(Msg, PreparedTupleMap),
|
|
|
+ DecodedMap = emqx_utils_json:decode(
|
|
|
+ emqx_plugin_libs_rule:proc_tmpl(PayloadTks, ProcessedMessage), [return_maps]
|
|
|
+ ),
|
|
|
+ populate_map_with_tuple_values(PreparedTupleMap, DecodedMap)
|
|
|
+ end.
|
|
|
+
|
|
|
+replace_message_values_with_references(RawMessage, TupleMap) ->
|
|
|
+ % Iterate over every created reference/value pair and inject the reference into the message
|
|
|
+ maps:fold(
|
|
|
+ fun(Reference, OriginalValue, OriginalMessage) ->
|
|
|
+ % Iterate over the Message, which is a map, and look for the element which
|
|
|
+ % matches the Value in the map which holds the references/original values and replace
|
|
|
+ % with the reference
|
|
|
+ maps:fold(
|
|
|
+ fun(Key, Value, NewMap) ->
|
|
|
+ case Value == OriginalValue of
|
|
|
+ true ->
|
|
|
+ %% Wrap the reference in a string to make it JSON-serializable
|
|
|
+ StringRef = io_lib:format("\"~s\"", [Reference]),
|
|
|
+ WrappedRef = erlang:iolist_to_binary(StringRef),
|
|
|
+ maps:put(Key, WrappedRef, NewMap);
|
|
|
+ false ->
|
|
|
+ maps:put(Key, Value, NewMap)
|
|
|
+ end
|
|
|
+ end,
|
|
|
+ #{},
|
|
|
+ OriginalMessage
|
|
|
+ )
|
|
|
+ end,
|
|
|
+ RawMessage,
|
|
|
+ TupleMap
|
|
|
+ ).
|
|
|
+
|
|
|
+create_mapping_of_references_to_tuple_values(Message) ->
|
|
|
+ maps:fold(
|
|
|
+ fun
|
|
|
+ (_Key, Value, TupleMap) when is_tuple(Value) ->
|
|
|
+ Ref0 = emqx_guid:to_hexstr(emqx_guid:gen()),
|
|
|
+ Ref = <<"MONGO_DATE_REF_", Ref0/binary>>,
|
|
|
+ maps:put(Ref, Value, TupleMap);
|
|
|
+ (_Key, _Value, TupleMap) ->
|
|
|
+ TupleMap
|
|
|
+ end,
|
|
|
+ #{},
|
|
|
+ Message
|
|
|
+ ).
|
|
|
+
|
|
|
+populate_map_with_tuple_values(TupleMap, MapToMap) ->
|
|
|
+ MappingFun =
|
|
|
+ fun
|
|
|
+ (_Key, Value) when is_map(Value) ->
|
|
|
+ populate_map_with_tuple_values(TupleMap, Value);
|
|
|
+ (_Key, Value) ->
|
|
|
+ case maps:is_key(Value, TupleMap) of
|
|
|
+ true ->
|
|
|
+ maps:get(Value, TupleMap);
|
|
|
+ false ->
|
|
|
+ Value
|
|
|
+ end
|
|
|
+ end,
|
|
|
+ maps:map(MappingFun, MapToMap).
|