This is an automated email from the ASF dual-hosted git repository.

jgemignani pushed a commit to branch PG15
in repository https://gitbox.apache.org/repos/asf/age.git

commit def28f9ef5e80e5e2901b495c8739cca908e202d
Author: Matheus Farias de Oliveira Matsumoto 
<[email protected]>
AuthorDate: Fri Aug 18 19:38:53 2023 -0300

    Implemented the toBooleanList() function (#1014)
    
    - Essentially the same as openCypher's toBooleanList() function: 
https://neo4j.com/docs/cypher-manual/current/functions/list/#functions-tobooleanlist
    - The toBooleanList() function converts a list of values and returns a list 
of boolean values.
    - If any values are not convertible to boolean they will be null in the 
list returned.
    - Also created the regression tests for it.
---
 age--1.4.0.sql                 |  8 ++++
 regress/expected/expr.out      | 81 +++++++++++++++++++++++++++++++++++++
 regress/sql/expr.sql           | 48 ++++++++++++++++++++++
 src/backend/utils/adt/agtype.c | 92 ++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 229 insertions(+)

diff --git a/age--1.4.0.sql b/age--1.4.0.sql
index 90097a7e..3a911627 100644
--- a/age--1.4.0.sql
+++ b/age--1.4.0.sql
@@ -3507,6 +3507,14 @@ RETURNS NULL ON NULL INPUT
 PARALLEL SAFE
 AS 'MODULE_PATHNAME';
 
+CREATE FUNCTION ag_catalog.age_tobooleanlist(variadic "any")
+RETURNS agtype
+LANGUAGE c
+IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
 CREATE FUNCTION ag_catalog.age_tofloat(variadic "any")
 RETURNS agtype
 LANGUAGE c
diff --git a/regress/expected/expr.out b/regress/expected/expr.out
index c4c16506..52bf0b6c 100644
--- a/regress/expected/expr.out
+++ b/regress/expected/expr.out
@@ -2827,6 +2827,87 @@ ERROR:  function ag_catalog.age_toboolean() does not 
exist
 LINE 2:     RETURN toBoolean()
                    ^
 HINT:  No function matches the given name and argument types. You might need 
to add explicit type casts.
+-- toBooleanList()
+SELECT * FROM cypher('expr', $$
+    RETURN toBooleanList([true, false, true])
+$$) AS (toBooleanList agtype);
+    tobooleanlist    
+---------------------
+ [true, false, true]
+(1 row)
+
+SELECT * FROM cypher('expr', $$
+    RETURN toBooleanList(["true", "false", "true"])
+$$) AS (toBooleanList agtype);
+    tobooleanlist    
+---------------------
+ [true, false, true]
+(1 row)
+
+SELECT * FROM cypher('expr', $$
+    RETURN toBooleanList(["True", "False", "True"])
+$$) AS (toBooleanList agtype);
+    tobooleanlist    
+---------------------
+ [true, false, true]
+(1 row)
+
+-- should return null
+SELECT * FROM cypher('expr', $$
+    RETURN toBooleanList([])
+$$) AS (toBooleanList agtype);
+ tobooleanlist 
+---------------
+ 
+(1 row)
+
+SELECT * FROM cypher('expr', $$
+    RETURN toBooleanList([null, null, null])
+$$) AS (toBooleanList agtype);
+   tobooleanlist    
+--------------------
+ [null, null, null]
+(1 row)
+
+SELECT * FROM cypher('expr', $$
+    RETURN toBooleanList(["Hello", "world!"])
+$$) AS (toBooleanList agtype);
+ tobooleanlist 
+---------------
+ [null, null]
+(1 row)
+
+SELECT * FROM cypher('expr', $$
+    RETURN toBooleanList([["A", "B"], ["C", "D"]])
+$$) AS (toBooleanList agtype);
+ tobooleanlist 
+---------------
+ [null, null]
+(1 row)
+
+SELECT * FROM cypher('expr', $$
+    RETURN toBooleanList([0,1,2,3,4])
+$$) AS (toBooleanList agtype);
+         tobooleanlist          
+--------------------------------
+ [null, null, null, null, null]
+(1 row)
+
+-- should fail
+SELECT * FROM cypher('expr', $$
+    RETURN toBooleanList(fail)
+$$) AS (toBooleanList agtype);
+ERROR:  could not find rte for fail
+LINE 2:     RETURN toBooleanList(fail)
+                                 ^
+SELECT * FROM cypher('expr', $$
+    RETURN toBooleanList("fail")
+$$) AS (toBooleanList agtype);
+ERROR:  toBooleanList() argument must resolve to a list or null
+SELECT * FROM cypher('expr', $$
+    RETURN toBooleanList(123)
+$$) AS (toBooleanList agtype);
+ERROR:  toBooleanList() argument must resolve to a list or null
 -- toFloat()
 SELECT * FROM cypher('expr', $$
     RETURN toFloat(1)
diff --git a/regress/sql/expr.sql b/regress/sql/expr.sql
index 82421d9d..4788fe25 100644
--- a/regress/sql/expr.sql
+++ b/regress/sql/expr.sql
@@ -1269,6 +1269,54 @@ $$) AS (toBoolean agtype);
 SELECT * FROM cypher('expr', $$
     RETURN toBoolean()
 $$) AS (toBoolean agtype);
+
+-- toBooleanList()
+SELECT * FROM cypher('expr', $$
+    RETURN toBooleanList([true, false, true])
+$$) AS (toBooleanList agtype);
+
+SELECT * FROM cypher('expr', $$
+    RETURN toBooleanList(["true", "false", "true"])
+$$) AS (toBooleanList agtype);
+
+SELECT * FROM cypher('expr', $$
+    RETURN toBooleanList(["True", "False", "True"])
+$$) AS (toBooleanList agtype);
+
+-- should return null
+SELECT * FROM cypher('expr', $$
+    RETURN toBooleanList([])
+$$) AS (toBooleanList agtype);
+
+SELECT * FROM cypher('expr', $$
+    RETURN toBooleanList([null, null, null])
+$$) AS (toBooleanList agtype);
+
+SELECT * FROM cypher('expr', $$
+    RETURN toBooleanList(["Hello", "world!"])
+$$) AS (toBooleanList agtype);
+
+SELECT * FROM cypher('expr', $$
+    RETURN toBooleanList([["A", "B"], ["C", "D"]])
+$$) AS (toBooleanList agtype);
+
+SELECT * FROM cypher('expr', $$
+    RETURN toBooleanList([0,1,2,3,4])
+$$) AS (toBooleanList agtype);
+
+-- should fail
+SELECT * FROM cypher('expr', $$
+    RETURN toBooleanList(fail)
+$$) AS (toBooleanList agtype);
+
+SELECT * FROM cypher('expr', $$
+    RETURN toBooleanList("fail")
+$$) AS (toBooleanList agtype);
+
+SELECT * FROM cypher('expr', $$
+    RETURN toBooleanList(123)
+$$) AS (toBooleanList agtype);
+
 -- toFloat()
 SELECT * FROM cypher('expr', $$
     RETURN toFloat(1)
diff --git a/src/backend/utils/adt/agtype.c b/src/backend/utils/adt/agtype.c
index 0fd458aa..ea254016 100644
--- a/src/backend/utils/adt/agtype.c
+++ b/src/backend/utils/adt/agtype.c
@@ -5199,6 +5199,98 @@ Datum age_toboolean(PG_FUNCTION_ARGS)
     PG_RETURN_POINTER(agtype_value_to_agtype(&agtv_result));
 }
 
+PG_FUNCTION_INFO_V1(age_tobooleanlist);
+/*
+ * Converts a list of values and returns a list of boolean values. 
+ * If any values are not convertible to boolean they will be null in the list 
returned.
+ */
+Datum age_tobooleanlist(PG_FUNCTION_ARGS)
+{
+    agtype *agt_arg = NULL;
+    agtype_in_state agis_result;
+    agtype_value *elem;
+    agtype_value bool_elem;
+    char *string = NULL;
+    int count;
+    int i;
+
+    /* check for null */
+    if (PG_ARGISNULL(0))
+        PG_RETURN_NULL();
+
+    agt_arg = AG_GET_ARG_AGTYPE_P(0);
+    /* check for an array */
+    if (!AGT_ROOT_IS_ARRAY(agt_arg) || AGT_ROOT_IS_SCALAR(agt_arg))
+        ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                        errmsg("toBooleanList() argument must resolve to a 
list or null")));
+
+    count = AGT_ROOT_COUNT(agt_arg);
+
+    /* if we have an empty list or only one element in the list, return null */
+    if (count == 0)
+        PG_RETURN_NULL();
+    
+    /* clear the result structure */
+    MemSet(&agis_result, 0, sizeof(agtype_in_state));
+
+    /* push the beginning of the array */
+    agis_result.res = push_agtype_value(&agis_result.parse_state,
+                                        WAGT_BEGIN_ARRAY, NULL);
+
+    /* iterate through the list */
+    for (i = 0; i < count; i++)
+    {
+        // TODO: check element's type, it's value, and convert it to boolean 
if possible.
+        elem = get_ith_agtype_value_from_container(&agt_arg->root, i);
+        bool_elem.type = AGTV_BOOL;
+
+        switch (elem->type)
+        {
+        case AGTV_STRING:
+            
+            string = elem->val.string.val;
+
+            if (pg_strcasecmp(string, "true") == 0)
+            {
+                bool_elem.val.boolean = true;
+                agis_result.res = push_agtype_value(&agis_result.parse_state, 
WAGT_ELEM, &bool_elem);
+            }
+            else if (pg_strcasecmp(string, "false") == 0)
+            {
+                bool_elem.val.boolean = false;
+                agis_result.res = push_agtype_value(&agis_result.parse_state, 
WAGT_ELEM, &bool_elem);
+            }
+            else
+            {
+                bool_elem.type = AGTV_NULL;
+                agis_result.res = push_agtype_value(&agis_result.parse_state, 
WAGT_ELEM, &bool_elem);
+            }
+            
+            break;
+        
+        case AGTV_BOOL:
+            
+            bool_elem.val.boolean = elem->val.boolean;
+            agis_result.res = push_agtype_value(&agis_result.parse_state, 
WAGT_ELEM, &bool_elem);
+
+            break;
+        
+        default:
+            
+            bool_elem.type = AGTV_NULL;
+            agis_result.res = push_agtype_value(&agis_result.parse_state, 
WAGT_ELEM, &bool_elem);
+            
+            break;
+        }
+    }
+
+    /* push the end of the array */
+    agis_result.res = push_agtype_value(&agis_result.parse_state,
+                                        WAGT_END_ARRAY, NULL);
+
+    PG_RETURN_POINTER(agtype_value_to_agtype(agis_result.res));
+}
+
 PG_FUNCTION_INFO_V1(age_tofloat);
 
 Datum age_tofloat(PG_FUNCTION_ARGS)

Reply via email to