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

feat: add coalsce and coalsce_ne to builtin SQL functions

zmstone 1 год назад
Родитель
Сommit
55672473e5

+ 26 - 1
apps/emqx_rule_engine/src/emqx_rule_funcs.erl

@@ -39,7 +39,11 @@
     contains_topic/3,
     contains_topic_match/2,
     contains_topic_match/3,
-    null/0
+    null/0,
+    coalesce/1,
+    coalesce/2,
+    coalesce_ne/1,
+    coalesce_ne/2
 ]).
 
 %% Arithmetic Funcs
@@ -431,6 +435,27 @@ null() ->
 bytesize(IoList) ->
     erlang:iolist_size(IoList).
 
+%% @doc coalesce returns the first non-null value
+coalesce([]) -> null();
+coalesce([undefined | T]) -> coalesce(T);
+coalesce([H | _T]) -> H.
+
+%% @doc This is a short-cut of SQL `CASE WHEN is_null(A) THEN A ELSE B END'
+coalesce(A, B) ->
+    coalesce([A, B]).
+
+%% @doc coalesce_ne returns the first non-empty value.
+%% `undefined', `""', and `<<>>' are considered 'empty'.
+coalesce_ne([]) -> null();
+coalesce_ne([undefined | T]) -> coalesce_ne(T);
+coalesce_ne(["" | T]) -> coalesce_ne(T);
+coalesce_ne([<<>> | T]) -> coalesce_ne(T);
+coalesce_ne([H | _T]) -> H.
+
+%% @doc Same as coalesce/2, but considers a value null when it's empty string.
+coalesce_ne(A, B) ->
+    coalesce_ne([A, B]).
+
 %%------------------------------------------------------------------------------
 %% Arithmetic Funcs
 %%------------------------------------------------------------------------------

+ 20 - 0
apps/emqx_rule_engine/test/emqx_rule_funcs_SUITE.erl

@@ -333,6 +333,26 @@ t_is_array(_) ->
      || T <- [<<>>, a]
     ].
 
+t_coalesce(_) ->
+    ?assertEqual(undefined, emqx_rule_funcs:coalesce([])),
+    ?assertEqual(undefined, emqx_rule_funcs:coalesce([undefined, undefined, undefined])),
+    ?assertEqual(42, emqx_rule_funcs:coalesce([undefined, 42, undefined])),
+    ?assertEqual(hello, emqx_rule_funcs:coalesce([hello, undefined])),
+    ?assertEqual(world, emqx_rule_funcs:coalesce([world])),
+    ?assertEqual(hello, emqx_rule_funcs:coalesce(hello, world)),
+    ?assertEqual(world, emqx_rule_funcs:coalesce(undefined, world)),
+    ok.
+
+t_coalesce_ne(_) ->
+    ?assertEqual(undefined, emqx_rule_funcs:coalesce_ne([])),
+    ?assertEqual(undefined, emqx_rule_funcs:coalesce_ne([<<>>, undefined, ""])),
+    ?assertEqual(42, emqx_rule_funcs:coalesce_ne(["", 42, undefined])),
+    ?assertEqual(hello, emqx_rule_funcs:coalesce_ne([hello, <<>>])),
+    ?assertEqual(world, emqx_rule_funcs:coalesce_ne([world])),
+    ?assertEqual(hello, emqx_rule_funcs:coalesce_ne(hello, world)),
+    ?assertEqual(world, emqx_rule_funcs:coalesce_ne("", world)),
+    ok.
+
 %%------------------------------------------------------------------------------
 %% Test cases for arith op
 %%------------------------------------------------------------------------------