Skip to content

Commit 446a623

Browse files
authored
Add support for nested type in java API (#4720)
1 parent 9d0583d commit 446a623

10 files changed

Lines changed: 823 additions & 246 deletions

File tree

src/jni/kuzu_java.cpp

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
#endif
88

99
// This header is generated at build time. See CMakeLists.txt.
10+
#include <vector>
11+
1012
#include "com_kuzudb_Native.h"
1113
#include "common/constants.h"
1214
#include "common/exception/exception.h"
@@ -796,6 +798,37 @@ JNIEXPORT void JNICALL Java_com_kuzudb_Native_kuzu_1value_1destroy(JNIEnv* env,
796798
delete v;
797799
}
798800

801+
JNIEXPORT jobject JNICALL Java_com_kuzudb_Native_kuzu_1create_1list___3Lcom_kuzudb_Value_2(
802+
JNIEnv* env, jclass, jobjectArray listValues) {
803+
jsize len = env->GetArrayLength(listValues);
804+
if (len == 0) {
805+
return nullptr;
806+
}
807+
808+
std::vector<std::unique_ptr<Value>> children;
809+
for (jsize i = 0; i < len; ++i) {
810+
Value* element = getValue(env, env->GetObjectArrayElement(listValues, i));
811+
children.emplace_back(element->copy());
812+
}
813+
LogicalType childType = children[0]->getDataType().copy();
814+
815+
Value* listValue = new Value(LogicalType::LIST(std::move(childType)), std::move(children));
816+
return createJavaObject(env, listValue, J_C_Value, J_C_Value_F_v_ref);
817+
}
818+
819+
JNIEXPORT jobject JNICALL Java_com_kuzudb_Native_kuzu_1create_1list__Lcom_kuzudb_DataType_2J(
820+
JNIEnv* env, jclass, jobject dataType, jlong numElements) {
821+
LogicalType* logicalType = getDataType(env, dataType);
822+
823+
std::vector<std::unique_ptr<Value>> children;
824+
for (jlong i = 0; i < numElements; ++i) {
825+
children.emplace_back(std::make_unique<Value>(Value::createDefaultValue(*logicalType)));
826+
}
827+
828+
Value* listValue = new Value(LogicalType::LIST(logicalType->copy()), std::move(children));
829+
return createJavaObject(env, listValue, J_C_Value, J_C_Value_F_v_ref);
830+
}
831+
799832
JNIEXPORT jlong JNICALL Java_com_kuzudb_Native_kuzu_1value_1get_1list_1size(JNIEnv* env, jclass,
800833
jobject thisValue) {
801834
Value* v = getValue(env, thisValue);
@@ -1124,6 +1157,71 @@ JNIEXPORT jstring JNICALL Java_com_kuzudb_Native_kuzu_1rel_1val_1to_1string(JNIE
11241157
return ret;
11251158
}
11261159

1160+
JNIEXPORT jobject JNICALL Java_com_kuzudb_Native_kuzu_1create_1map(JNIEnv* env, jclass,
1161+
jobjectArray keys, jobjectArray values) {
1162+
jsize len = env->GetArrayLength(keys);
1163+
KU_ASSERT(env->GetArrayLength(values) == len);
1164+
KU_ASSERT(len > 0);
1165+
1166+
std::optional<LogicalType> keyType;
1167+
std::optional<LogicalType> valueType;
1168+
1169+
std::vector<std::unique_ptr<Value>> children;
1170+
for (jsize i = 0; i < len; ++i) {
1171+
auto key = getValue(env, env->GetObjectArrayElement(keys, i))->copy();
1172+
auto value = getValue(env, env->GetObjectArrayElement(values, i))->copy();
1173+
1174+
if (!keyType.has_value()) {
1175+
keyType = key->getDataType().copy();
1176+
valueType = value->getDataType().copy();
1177+
} else {
1178+
KU_ASSERT(valueType.has_value());
1179+
if (key->getDataType() != *keyType || value->getDataType() != *valueType) {
1180+
return nullptr;
1181+
}
1182+
}
1183+
1184+
std::vector<StructField> structFields;
1185+
structFields.emplace_back(InternalKeyword::MAP_KEY, keyType->copy());
1186+
structFields.emplace_back(InternalKeyword::MAP_VALUE, valueType->copy());
1187+
1188+
decltype(children) structVals;
1189+
structVals.emplace_back(std::move(key));
1190+
structVals.emplace_back(std::move(value));
1191+
children.emplace_back(std::make_unique<Value>(LogicalType::STRUCT(std::move(structFields)),
1192+
std::move(structVals)));
1193+
}
1194+
1195+
KU_ASSERT(keyType.has_value());
1196+
KU_ASSERT(valueType.has_value());
1197+
Value* mapValue = new Value(LogicalType::MAP(std::move(*keyType), std::move(*valueType)),
1198+
std::move(children));
1199+
return createJavaObject(env, mapValue, J_C_Value, J_C_Value_F_v_ref);
1200+
}
1201+
1202+
JNIEXPORT jobject JNICALL Java_com_kuzudb_Native_kuzu_1create_1struct(JNIEnv* env, jclass,
1203+
jobjectArray fieldNames, jobjectArray fieldValues) {
1204+
jsize len = env->GetArrayLength(fieldNames);
1205+
KU_ASSERT(env->GetArrayLength(fieldValues) == len);
1206+
KU_ASSERT(len > 0);
1207+
1208+
std::vector<std::unique_ptr<Value>> children;
1209+
auto structFields = std::vector<StructField>{};
1210+
for (jsize i = 0; i < len; ++i) {
1211+
auto fieldName = std::string(env->GetStringUTFChars(
1212+
reinterpret_cast<jstring>(env->GetObjectArrayElement(fieldNames, i)), JNI_FALSE));
1213+
auto fieldValue = getValue(env, env->GetObjectArrayElement(fieldValues, i))->copy();
1214+
auto fieldType = fieldValue->getDataType().copy();
1215+
1216+
structFields.emplace_back(std::move(fieldName), std::move(fieldType));
1217+
children.push_back(std::move(fieldValue));
1218+
}
1219+
1220+
Value* structValue =
1221+
new Value(LogicalType::STRUCT(std::move(structFields)), std::move(children));
1222+
return createJavaObject(env, structValue, J_C_Value, J_C_Value_F_v_ref);
1223+
}
1224+
11271225
JNIEXPORT jstring JNICALL Java_com_kuzudb_Native_kuzu_1value_1get_1struct_1field_1name(JNIEnv* env,
11281226
jclass, jobject thisSV, jlong index) {
11291227
auto* sv = getValue(env, thisSV);
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
package com.kuzudb;
2+
3+
public class KuzuList implements AutoCloseable {
4+
private Value listVal;
5+
6+
/**
7+
* @return Gets the underlying Value for the list
8+
*/
9+
public Value getValue() {
10+
return listVal;
11+
}
12+
13+
/**
14+
* Construct a list from a value
15+
*
16+
* @param value the value to construct the list from
17+
*/
18+
public KuzuList(Value value) {
19+
listVal = value;
20+
}
21+
22+
/**
23+
* Construct a list literal from an array of values
24+
*
25+
* @param values: the array to construct the list from
26+
*/
27+
public KuzuList(Value[] values) {
28+
listVal = Native.kuzu_create_list(values);
29+
}
30+
31+
/**
32+
* Construct a list of a specific size populated with the default element
33+
*
34+
* @param numElements: the size of the list to construct
35+
*/
36+
public KuzuList(DataType type, long numElements) {
37+
listVal = Native.kuzu_create_list(type, numElements);
38+
}
39+
40+
/**
41+
* Get the size of the list.
42+
*
43+
* @return The size of the list.
44+
* @throws ObjectRefDestroyedException If the list has been destroyed.
45+
*/
46+
public long getListSize() throws ObjectRefDestroyedException {
47+
listVal.checkNotDestroyed();
48+
return Native.kuzu_value_get_list_size(listVal);
49+
}
50+
51+
/**
52+
* Get the element at the given index from the given list.
53+
*
54+
* @param index: The index of the element.
55+
* @return The element at the given index from the given list.
56+
* @throws ObjectRefDestroyedException If the list has been destroyed.
57+
*/
58+
public Value getListElement(long index) throws ObjectRefDestroyedException {
59+
listVal.checkNotDestroyed();
60+
return Native.kuzu_value_get_list_element(listVal, index);
61+
}
62+
63+
/**
64+
* Gets the elements the list as a Java array. This will be truncated if the
65+
* size of the list doesn't fit in a 32-bit integer.
66+
*
67+
* @return the list as a Java array
68+
* @throws ObjectRefDestroyedException
69+
*/
70+
public Value[] toArray() throws ObjectRefDestroyedException {
71+
int arraySize = ((Long) getListSize()).intValue();
72+
Value[] ret = new Value[arraySize];
73+
for (int i = 0; i < arraySize; ++i) {
74+
ret[i] = getListElement(i);
75+
}
76+
return ret;
77+
}
78+
79+
/**
80+
* Closes this object, relinquishing the underlying value
81+
*
82+
* @throws ObjectRefDestroyedException
83+
*/
84+
public void close() throws ObjectRefDestroyedException {
85+
listVal.close();
86+
}
87+
}
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
package com.kuzudb;
2+
3+
public class KuzuMap implements AutoCloseable {
4+
private Value mapVal;
5+
6+
/**
7+
* @return Gets the underlying Value for the map
8+
*/
9+
public Value getValue() {
10+
return mapVal;
11+
}
12+
13+
/**
14+
* Construct a map from a value
15+
*
16+
* @param value the value to construct the map from
17+
*/
18+
public KuzuMap(Value value) {
19+
mapVal = value;
20+
}
21+
22+
/**
23+
* Construct a map literal from a given set of keys/values. The length of the
24+
* key/value arrays must be the same.
25+
*
26+
* @param keys: The keys in the map
27+
* @param values: The values in the map
28+
*/
29+
public KuzuMap(Value[] keys, Value[] values) throws ObjectRefDestroyedException {
30+
if (keys.length != values.length) {
31+
mapVal = null;
32+
return;
33+
}
34+
if (keys.length == 0) {
35+
mapVal = null;
36+
return;
37+
}
38+
mapVal = Native.kuzu_create_map(keys, values);
39+
}
40+
41+
private Value getMapKeyOrValue(long index, boolean isKey) throws ObjectRefDestroyedException {
42+
if (index < 0 || index >= getNumFields()) {
43+
return null;
44+
}
45+
Value structValue = Native.kuzu_value_get_list_element(mapVal, index);
46+
Value keyOrValue = new KuzuList(structValue).getListElement(isKey ? 0 : 1);
47+
structValue.close();
48+
return keyOrValue;
49+
}
50+
51+
/**
52+
* @return The number of fields in the map.
53+
* @throws ObjectRefDestroyedException If the map has been destroyed.
54+
*/
55+
public long getNumFields() throws ObjectRefDestroyedException {
56+
if (mapVal == null) {
57+
return 0;
58+
}
59+
return Native.kuzu_value_get_list_size(mapVal);
60+
}
61+
62+
/**
63+
* Get the key at the given index.
64+
*
65+
* @param index: The index of the key.
66+
* @return The key.
67+
* @throws ObjectRefDestroyedException If the map has been destroyed.
68+
*/
69+
public Value getKey(long index) throws ObjectRefDestroyedException {
70+
return getMapKeyOrValue(index, true);
71+
}
72+
73+
/**
74+
* Get the value at the given index.
75+
*
76+
* @param index: The index of the value.
77+
* @return The value.
78+
* @throws ObjectRefDestroyedException If the map value has been destroyed.
79+
*/
80+
public Value getValue(long index) throws ObjectRefDestroyedException {
81+
return getMapKeyOrValue(index, false);
82+
}
83+
84+
/**
85+
* Closes this object, relinquishing the underlying value
86+
*
87+
* @throws ObjectRefDestroyedException
88+
*/
89+
public void close() throws ObjectRefDestroyedException {
90+
mapVal.close();
91+
}
92+
}

0 commit comments

Comments
 (0)