You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@age.apache.org by de...@apache.org on 2023/08/18 22:47:50 UTC

[age] branch PG14 updated: Added toBooleanList() (#1165)

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

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


The following commit(s) were added to refs/heads/PG14 by this push:
     new dfffee2a Added toBooleanList() (#1165)
dfffee2a is described below

commit dfffee2ae40d924cdfe9c538889a9b97b7a745ca
Author: Matheus Farias de Oliveira Matsumoto <83...@users.noreply.github.com>
AuthorDate: Fri Aug 18 19:47:45 2023 -0300

    Added toBooleanList() (#1165)
    
    - 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.
    - Created regression tests for it.
---
 age--1.3.0.sql                 |  8 ++++
 regress/expected/expr.out      | 81 ++++++++++++++++++++++++++++++++++++++++
 regress/sql/expr.sql           | 48 ++++++++++++++++++++++++
 src/backend/utils/adt/agtype.c | 85 ++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 222 insertions(+)

diff --git a/age--1.3.0.sql b/age--1.3.0.sql
index 90097a7e..3a911627 100644
--- a/age--1.3.0.sql
+++ b/age--1.3.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 1cdfaddb..3c0e487b 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 815a731a..40ac4140 100644
--- a/src/backend/utils/adt/agtype.c
+++ b/src/backend/utils/adt/agtype.c
@@ -5200,6 +5200,91 @@ 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++)
+	{
+		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)