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

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


The following commit(s) were added to refs/heads/master by this push:
     new 4274f108 Added the toStringList() function (#1084)
4274f108 is described below

commit 4274f1083b23057a599d67f11b0ad91b9aae991d
Author: Marcos Silva <[email protected]>
AuthorDate: Tue Aug 8 15:34:19 2023 -0300

    Added the toStringList() function (#1084)
    
    - This function is inspired by the "tostringlist" function in 
OpenCypher.https://neo4j.com/docs/cypher-manual/current/functions/list/#functions-tostringlist
    - toStringList() converts a list of values and returns a list of string 
values. If any values are not convertible to string they will be null in the 
list returned.
    - A list containing the converted elements; depending on the input value a 
converted value is either a string value or null.
    - Also added the regression tests
---
 age--1.3.0.sql                 |   8 ++++
 regress/expected/expr.out      |  63 ++++++++++++++++++++++++++
 regress/sql/expr.sql           |  27 +++++++++++
 src/backend/utils/adt/agtype.c | 100 +++++++++++++++++++++++++++++++++++++++++
 4 files changed, 198 insertions(+)

diff --git a/age--1.3.0.sql b/age--1.3.0.sql
index 8bfa9a93..2b0ddef5 100644
--- a/age--1.3.0.sql
+++ b/age--1.3.0.sql
@@ -3546,6 +3546,14 @@ RETURNS NULL ON NULL INPUT
 PARALLEL SAFE
 AS 'MODULE_PATHNAME';
 
+CREATE FUNCTION ag_catalog.age_tostringlist(variadic "any")
+RETURNS agtype
+LANGUAGE c
+IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
 CREATE FUNCTION ag_catalog.age_size(variadic "any")
 RETURNS agtype
 LANGUAGE c
diff --git a/regress/expected/expr.out b/regress/expected/expr.out
index 94c8d180..1d36b8bd 100644
--- a/regress/expected/expr.out
+++ b/regress/expected/expr.out
@@ -3284,6 +3284,69 @@ ERROR:  function ag_catalog.age_tostring() does not exist
 LINE 1: SELECT * FROM cypher('expr', $$ RETURN toString() $$) AS (re...
                                                ^
 HINT:  No function matches the given name and argument types. You might need 
to add explicit type casts.
+-- toStringList() --
+SELECT * FROM cypher('expr', $$ 
+    RETURN toStringList([5, 10, 7.8, 9, 1.3]) 
+$$) AS (toStringList agtype);
+          tostringlist          
+--------------------------------
+ ["5", "10", "7.8", "9", "1.3"]
+(1 row)
+
+SELECT * FROM cypher('expr', $$ 
+    RETURN toStringList(['test', 89, 'again', 7.1, 9]) 
+$$) AS (toStringList agtype);
+            tostringlist             
+-------------------------------------
+ ["test", "89", "again", "7.1", "9"]
+(1 row)
+
+SELECT * FROM cypher('expr', $$ 
+    RETURN toStringList([null, false, true, 'string']) 
+$$) AS (toStringList agtype);
+         tostringlist         
+------------------------------
+ [null, null, null, "string"]
+(1 row)
+
+SELECT * FROM cypher('expr', $$ 
+    RETURN toStringList([9.123456789, 5.123, 1.12345, 0.123123]) 
+$$) AS (toStringList agtype);
+                  tostringlist                   
+-------------------------------------------------
+ ["9.123456789", "5.123", "1.12345", "0.123123"]
+(1 row)
+
+-- should return null
+SELECT * FROM cypher('expr', $$ 
+    RETURN toStringList([null]) 
+$$) AS (toStringList agtype);
+ tostringlist 
+--------------
+ [null]
+(1 row)
+
+SELECT * FROM cypher('expr', $$ 
+    RETURN toStringList([true, false, true, true]) 
+$$) AS (toStringList agtype);
+       tostringlist       
+--------------------------
+ [null, null, null, null]
+(1 row)
+
+-- should fail
+SELECT * FROM cypher('expr', $$ 
+    RETURN toStringList([['a', b]]) 
+$$) AS (toStringList agtype);
+ERROR:  could not find rte for b
+LINE 2:     RETURN toStringList([['a', b]]) 
+                                       ^
+SELECT * FROM cypher('expr', $$ 
+    RETURN toStringList([test]) 
+$$) AS (toStringList agtype);
+ERROR:  could not find rte for test
+LINE 2:     RETURN toStringList([test]) 
+                                 ^
 --
 -- reverse(string)
 --
diff --git a/regress/sql/expr.sql b/regress/sql/expr.sql
index d4a7efbd..6894172c 100644
--- a/regress/sql/expr.sql
+++ b/regress/sql/expr.sql
@@ -1441,6 +1441,33 @@ SELECT * FROM age_toString(agtype_in(null));
 -- should fail
 SELECT * FROM age_toString();
 SELECT * FROM cypher('expr', $$ RETURN toString() $$) AS (results agtype);
+-- toStringList() --
+SELECT * FROM cypher('expr', $$ 
+    RETURN toStringList([5, 10, 7.8, 9, 1.3]) 
+$$) AS (toStringList agtype);
+SELECT * FROM cypher('expr', $$ 
+    RETURN toStringList(['test', 89, 'again', 7.1, 9]) 
+$$) AS (toStringList agtype);
+SELECT * FROM cypher('expr', $$ 
+    RETURN toStringList([null, false, true, 'string']) 
+$$) AS (toStringList agtype);
+SELECT * FROM cypher('expr', $$ 
+    RETURN toStringList([9.123456789, 5.123, 1.12345, 0.123123]) 
+$$) AS (toStringList agtype);
+-- should return null
+SELECT * FROM cypher('expr', $$ 
+    RETURN toStringList([null]) 
+$$) AS (toStringList agtype);
+SELECT * FROM cypher('expr', $$ 
+    RETURN toStringList([true, false, true, true]) 
+$$) AS (toStringList agtype);
+-- should fail
+SELECT * FROM cypher('expr', $$ 
+    RETURN toStringList([['a', b]]) 
+$$) AS (toStringList agtype);
+SELECT * FROM cypher('expr', $$ 
+    RETURN toStringList([test]) 
+$$) AS (toStringList agtype);
 
 --
 -- reverse(string)
diff --git a/src/backend/utils/adt/agtype.c b/src/backend/utils/adt/agtype.c
index c9541922..06166ec7 100644
--- a/src/backend/utils/adt/agtype.c
+++ b/src/backend/utils/adt/agtype.c
@@ -31,6 +31,7 @@
 #include "postgres.h"
 
 #include <math.h>
+#include <float.h>
 
 #include "access/genam.h"
 #include "access/heapam.h"
@@ -6196,6 +6197,105 @@ Datum age_tostring(PG_FUNCTION_ARGS)
     PG_RETURN_POINTER(agtype_value_to_agtype(&agtv_result));
 }
 
+PG_FUNCTION_INFO_V1(age_tostringlist);
+/*
+ * toStringList() converts a list of values and returns a list of String 
values. 
+ * If any values are not convertible to string point they will be null in the 
list returned.
+ */
+Datum age_tostringlist(PG_FUNCTION_ARGS)
+{
+    agtype *agt_arg = NULL;
+    agtype_in_state agis_result;
+    agtype_value *elem;
+    agtype_value string_elem;
+    int count;
+    int i;
+    float float_num;
+    char buffer[64];
+
+    /* 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("toStringList() 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 string if 
possible.
+        elem = get_ith_agtype_value_from_container(&agt_arg->root, i);
+        string_elem.type = AGTV_STRING;
+
+        switch (elem->type)
+        {
+        case AGTV_STRING:
+
+            if(!elem)
+            {
+                string_elem.type = AGTV_NULL;
+
+                agis_result.res = push_agtype_value(&agis_result.parse_state, 
WAGT_ELEM, &string_elem);
+            }
+
+            string_elem.val.string.val = elem->val.string.val;
+            string_elem.val.string.len = elem->val.string.len;
+
+            agis_result.res = push_agtype_value(&agis_result.parse_state, 
WAGT_ELEM, &string_elem);
+
+            break;
+
+        case AGTV_FLOAT:
+
+            float_num = elem->val.float_value;
+            sprintf(buffer, "%.*g", DBL_DIG, elem->val.float_value);
+            string_elem.val.string.val = pstrdup(buffer);
+            string_elem.val.string.len = strlen(buffer);
+
+            agis_result.res = push_agtype_value(&agis_result.parse_state, 
WAGT_ELEM, &string_elem);
+
+            break; 
+
+        case AGTV_INTEGER:
+
+            sprintf(buffer, "%d", elem->val.int_value);
+            string_elem.val.string.val = pstrdup(buffer);
+            string_elem.val.string.len = strlen(buffer);
+
+            agis_result.res = push_agtype_value(&agis_result.parse_state, 
WAGT_ELEM, &string_elem);
+
+            break;
+
+        default:
+
+            string_elem.type = AGTV_NULL;
+            agis_result.res = push_agtype_value(&agis_result.parse_state, 
WAGT_ELEM, &string_elem);
+
+            break;
+        }
+    }
+    agis_result.res = push_agtype_value(&agis_result.parse_state, 
WAGT_END_ARRAY, NULL);
+
+    PG_RETURN_POINTER(agtype_value_to_agtype(agis_result.res));
+}
+
 static agtype_iterator *get_next_list_element(agtype_iterator *it,
                            agtype_container *agtc, agtype_value *elem)
 {

Reply via email to