Skip to content

Commit

Permalink
Implement array to string function (#3320)
Browse files Browse the repository at this point in the history
  • Loading branch information
acquamarin committed Apr 19, 2024
1 parent fffccec commit 9a1eba9
Show file tree
Hide file tree
Showing 11 changed files with 143 additions and 9 deletions.
1 change: 1 addition & 0 deletions src/function/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ add_subdirectory(arithmetic)
add_subdirectory(cast)
add_subdirectory(pattern)
add_subdirectory(table)
add_subdirectory(list)

add_library(kuzu_function
OBJECT
Expand Down
2 changes: 1 addition & 1 deletion src/function/function_collection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ FunctionCollection* FunctionCollection::getFunctions() {
SCALAR_FUNCTION(ListSumFunction), SCALAR_FUNCTION(ListProductFunction),
SCALAR_FUNCTION(ListDistinctFunction), SCALAR_FUNCTION(ListUniqueFunction),
SCALAR_FUNCTION(ListAnyValueFunction), SCALAR_FUNCTION(ListReverseFunction),
SCALAR_FUNCTION(SizeFunction),
SCALAR_FUNCTION(SizeFunction), SCALAR_FUNCTION(ListToStringFunction),

// Cast functions
SCALAR_FUNCTION(CastToDateFunction), SCALAR_FUNCTION_ALIAS(CastToDateFunction),
Expand Down
7 changes: 7 additions & 0 deletions src/function/list/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
add_library(kuzu_list_function
OBJECT
list_to_string_function.cpp)

set(ALL_OBJECT_FILES
${ALL_OBJECT_FILES} $<TARGET_OBJECTS:kuzu_list_function>
PARENT_SCOPE)
25 changes: 25 additions & 0 deletions src/function/list/list_to_string_function.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#include "function/list/functions/list_to_string_function.h"

#include "common/type_utils.h"

namespace kuzu {
namespace function {

void ListToString::operation(common::list_entry_t& input, common::ku_string_t& delim,
common::ku_string_t& result, common::ValueVector& inputVector,
common::ValueVector& /*delimVector*/, common::ValueVector& resultVector) {
std::string resultStr = "";
auto dataVector = common::ListVector::getDataVector(&inputVector);
for (auto i = 0u; i < input.size - 1; i++) {
resultStr += common::TypeUtils::entryToString(dataVector->dataType,
common::ListVector::getListValuesWithOffset(&inputVector, input, i), dataVector);
resultStr += delim.getAsString();
}
resultStr += common::TypeUtils::entryToString(dataVector->dataType,
common::ListVector::getListValuesWithOffset(&inputVector, input, input.size - 1),
dataVector);
common::StringVector::addString(&resultVector, result, resultStr);
}

} // namespace function
} // namespace kuzu
11 changes: 11 additions & 0 deletions src/function/vector_list_functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "function/list/functions/list_slice_function.h"
#include "function/list/functions/list_sort_function.h"
#include "function/list/functions/list_sum_function.h"
#include "function/list/functions/list_to_string_function.h"
#include "function/list/functions/list_unique_function.h"
#include "function/scalar_function.h"

Expand Down Expand Up @@ -924,5 +925,15 @@ function_set ListReverseFunction::getFunctionSet() {
return result;
}

function_set ListToStringFunction::getFunctionSet() {
function_set result;
result.push_back(std::make_unique<ScalarFunction>(name,
std::vector<LogicalTypeID>{LogicalTypeID::LIST, LogicalTypeID::STRING},
LogicalTypeID::STRING,
ScalarFunction::BinaryExecListStructFunction<list_entry_t, ku_string_t, ku_string_t,
ListToString>));
return result;
}

} // namespace function
} // namespace kuzu
16 changes: 16 additions & 0 deletions src/include/function/list/functions/list_to_string_function.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#pragma once

#include "common/types/ku_string.h"
#include "common/vector/value_vector.h"

namespace kuzu {
namespace function {

struct ListToString {
static void operation(common::list_entry_t& input, common::ku_string_t& delim,
common::ku_string_t& result, common::ValueVector& inputVector,
common::ValueVector& /*delimVector*/, common::ValueVector& resultVector);
};

} // namespace function
} // namespace kuzu
13 changes: 9 additions & 4 deletions src/include/function/list/functions/list_unique_function.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,23 @@ struct ValueEquality {

using ValueSet = std::unordered_set<common::Value, ValueHashFunction, ValueEquality>;

using duplicateValueHandler = std::function<void(const std::string&)>;
using uniqueValueHandler = std::function<void(common::ValueVector& dataVector, uint64_t pos)>;
using duplicate_value_handler = std::function<void(const std::string&)>;
using unique_value_handler = std::function<void(common::ValueVector& dataVector, uint64_t pos)>;
using null_value_handler = std::function<void()>;

struct ListUnique {
static uint64_t appendListElementsToValueSet(common::list_entry_t& input,
common::ValueVector& inputVector, duplicateValueHandler duplicateValHandler = nullptr,
uniqueValueHandler uniqueValueHandler = nullptr) {
common::ValueVector& inputVector, duplicate_value_handler duplicateValHandler = nullptr,
unique_value_handler uniqueValueHandler = nullptr,
null_value_handler nullValueHandler = nullptr) {
ValueSet uniqueKeys;
auto dataVector = common::ListVector::getDataVector(&inputVector);
auto val = common::Value::createDefaultValue(dataVector->dataType);
for (auto i = 0u; i < input.size; i++) {
if (dataVector->isNull(input.offset + i)) {
if (nullValueHandler != nullptr) {
nullValueHandler();
}
continue;
}
auto entryVal = common::ListVector::getListValuesWithOffset(&inputVector, input, i);
Expand Down
6 changes: 6 additions & 0 deletions src/include/function/list/vector_list_functions.h
Original file line number Diff line number Diff line change
Expand Up @@ -129,5 +129,11 @@ struct ListReverseFunction {
static function_set getFunctionSet();
};

struct ListToStringFunction {
static constexpr const char* name = "LIST_TO_STRING";

static function_set getFunctionSet();
};

} // namespace function
} // namespace kuzu
14 changes: 10 additions & 4 deletions src/include/function/map/functions/map_creation_function.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,17 @@
namespace kuzu {
namespace function {

static void duplicateValueHandler(const std::string& key) {
throw common::RuntimeException{common::stringFormat("Found duplicate key: {} in map.", key)};
}

static void nullValueHandler() {
throw common::RuntimeException("Null value key is not allowed in map.");
}

static void validateKeys(common::list_entry_t& keyEntry, common::ValueVector& keyVector) {
ListUnique::appendListElementsToValueSet(keyEntry, keyVector, [](const std::string& key) {
throw common::RuntimeException{
common::stringFormat("Found duplicate key: {} in map.", key)};
});
ListUnique::appendListElementsToValueSet(keyEntry, keyVector, duplicateValueHandler,
nullptr /* uniqueValueHandler */, nullValueHandler);
}

struct MapCreation {
Expand Down
52 changes: 52 additions & 0 deletions test/test_files/tinysnb/function/list.test
Original file line number Diff line number Diff line change
Expand Up @@ -2130,3 +2130,55 @@ Ad
-STATEMENT Return list_product(["ok"]);
---- error
Binder exception: Unsupported inner data type for LIST_PRODUCT: STRING

-LOG ListToStringInt128
-STATEMENT RETURN LIST_TO_STRING([CAST(5, 'INT128'), CAST(7, 'INT128'), CAST(10, 'INT128')], '--')
---- 1
5--7--10

-LOG ListToStringInt64
-STATEMENT RETURN LIST_TO_STRING([CAST(255, 'INT64'), CAST(-51, 'INT64'), CAST(3132, 'INT64')], '--')
---- 1
255---51--3132

-LOG ListToStringBOOL
-STATEMENT RETURN LIST_TO_STRING([true, false, false, true], '/')
---- 1
True/False/False/True

-LOG ListToStringUUID
-STATEMENT MATCH (p:person) return list_to_string(collect(p.u), '*')
---- 1
a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11*a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a12*a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a13*a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a14*a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a15*a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a16*a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a17*a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a18

-LOG ListToStringDate
-STATEMENT MATCH (p:person) return list_to_string(collect(p.birthdate), '+')
---- 1
1900-01-01+1900-01-01+1940-06-22+1950-07-23+1980-10-26+1980-10-26+1980-10-26+1990-11-27

-LOG ListToStringTimestamp
-STATEMENT MATCH (p:person) return list_to_string(collect(p.registerTime), '==')
---- 1
2011-08-20 11:25:30==2008-11-03 15:25:30.000526==1911-08-20 02:32:21==2031-11-30 12:25:30==1976-12-23 11:21:42==1972-07-31 13:22:30.678559==1976-12-23 04:41:42==2023-02-21 13:25:30

-LOG ListToStringList
-STATEMENT MATCH (p:person) return list_to_string(p.workedHours, ',')
---- 8
10,5
12,8
4,5
1,9
2
3,4,5,6,7
1
10,11,12,3,4,5,6,7

-LOG ListToStringStruct
-STATEMENT MATCH (o:organisation) return list_to_string(collect(o.state), '|')
---- 1
{revenue: 138, location: ['toronto','montr,eal'], stock: {price: [96,56], volume: 1000}}|{revenue: 152, location: ["vanco,uver north area"], stock: {price: [15,78,671], volume: 432}}|{revenue: 558, location: ['very long city name','new york'], stock: {price: [22], volume: 99}}

-LOG ListToStringArray
-STATEMENT MATCH (p:person) return list_to_string(collect(p.grades), '/')
---- 1
[96,54,86,92]/[98,42,93,88]/[91,75,21,95]/[76,88,99,89]/[96,59,65,88]/[80,78,34,83]/[43,83,67,43]/[77,64,100,54]
5 changes: 5 additions & 0 deletions test/test_files/tinysnb/projection/single_label.test
Original file line number Diff line number Diff line change
Expand Up @@ -667,6 +667,11 @@ Runtime exception: Found duplicate key: {a: 5, b: 3} in map.
---- error
Runtime exception: Found duplicate key: 0 in map.

-LOG MapWithNullKey
-STATEMENT RETURN map([cast(5, 'int128'), NULL, cast(5, 'int128')], [20, 34, 50]);
---- error
Runtime exception: Null value key is not allowed in map.

-LOG ReturnMapLiteralWithProp
-STATEMENT MATCH (p:person) RETURN map([p.ID, p.age], [p.fName, p.fName]);
---- 8
Expand Down

0 comments on commit 9a1eba9

Please sign in to comment.