Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add struct support for Java API #1768

Merged
merged 1 commit into from
Jul 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 28 additions & 2 deletions tools/java_api/src/jni/kuzu_java.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ void javaMapToCPPMap(
jobject entry = env->CallObjectMethod(iter, next);
jstring key = (jstring)env->CallObjectMethod(entry, entryGetKey);
jobject value = env->CallObjectMethod(entry, entryGetValue);
const char* keyStr = env->GetStringUTFChars(key, NULL);
const char* keyStr = env->GetStringUTFChars(key, JNI_FALSE);
Value* v = getValue(env, value);
std::shared_ptr<Value> value_ptr(v);
cppMap.insert({keyStr, value_ptr});
Expand Down Expand Up @@ -753,7 +753,7 @@ JNIEXPORT jlong JNICALL Java_com_kuzudb_KuzuNative_kuzu_1value_1create_1value(
v = new Value(static_cast<double>(value));
} else if (env->IsInstanceOf(val, env->FindClass("java/lang/String"))) {
jstring value = static_cast<jstring>(val);
const char* str = env->GetStringUTFChars(value, NULL);
const char* str = env->GetStringUTFChars(value, JNI_FALSE);
v = new Value(str);
env->ReleaseStringUTFChars(value, str);
} else if (env->IsInstanceOf(val, env->FindClass("com/kuzudb/KuzuInternalID"))) {
Expand Down Expand Up @@ -1060,3 +1060,29 @@ JNIEXPORT jstring JNICALL Java_com_kuzudb_KuzuNative_kuzu_1rel_1val_1to_1string(
jstring ret = env->NewStringUTF(result_string.c_str());
return ret;
}

JNIEXPORT jstring JNICALL Java_com_kuzudb_KuzuNative_kuzu_1value_1get_1struct_1field_1name(
JNIEnv* env, jclass, jobject thisSV, jlong index) {
auto* sv = getValue(env, thisSV);
auto dataType = sv->getDataType();
auto fieldNames = StructType::getFieldNames(&dataType);
if (index >= fieldNames.size() || index < 0) {
return nullptr;
}
auto name = fieldNames[index];
return env->NewStringUTF(name.c_str());
}

JNIEXPORT jlong JNICALL Java_com_kuzudb_KuzuNative_kuzu_1value_1get_1struct_1index(
JNIEnv* env, jclass, jobject thisSV, jstring field_name) {
auto* sv = getValue(env, thisSV);
const char* field_name_cstr = env->GetStringUTFChars(field_name, JNI_FALSE);
auto dataType = sv->getDataType();
auto index = StructType::getFieldIdx(&dataType, field_name_cstr);
env->ReleaseStringUTFChars(field_name, field_name_cstr);
if (index == INVALID_STRUCT_FIELD_IDX) {
return -1;
} else {
return static_cast<jlong>(index);
}
}
3 changes: 3 additions & 0 deletions tools/java_api/src/main/java/com/kuzudb/KuzuNative.java
Original file line number Diff line number Diff line change
Expand Up @@ -221,4 +221,7 @@ protected static native long kuzu_data_type_create(

protected static native String kuzu_rel_val_to_string(KuzuValue rel_val);

protected static native String kuzu_value_get_struct_field_name(KuzuValue struct_val, long index);

protected static native long kuzu_value_get_struct_index(KuzuValue struct_val, String field_name);
}
10 changes: 0 additions & 10 deletions tools/java_api/src/main/java/com/kuzudb/KuzuValue.java
Original file line number Diff line number Diff line change
Expand Up @@ -71,16 +71,6 @@ public <T> T getValue() throws KuzuObjectRefDestroyedException {
return KuzuNative.kuzu_value_get_value(this);
}

public long getListSize() throws KuzuObjectRefDestroyedException {
checkNotDestroyed();
return KuzuNative.kuzu_value_get_list_size(this);
}

public KuzuValue getListElement(long index) throws KuzuObjectRefDestroyedException {
checkNotDestroyed();
return KuzuNative.kuzu_value_get_list_element(this, index);
}

public KuzuDataType getDataType() throws KuzuObjectRefDestroyedException {
checkNotDestroyed();
return KuzuNative.kuzu_value_get_data_type(this);
Expand Down
13 changes: 13 additions & 0 deletions tools/java_api/src/main/java/com/kuzudb/KuzuValueListUtil.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.kuzudb;

public class KuzuValueListUtil {
public static long getListSize(KuzuValue value) throws KuzuObjectRefDestroyedException {
value.checkNotDestroyed();
return KuzuNative.kuzu_value_get_list_size(value);
}

public static KuzuValue getListElement(KuzuValue value, long index) throws KuzuObjectRefDestroyedException {
value.checkNotDestroyed();
return KuzuNative.kuzu_value_get_list_element(value, index);
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.kuzudb;

public class KuzuNodeValue {
public class KuzuValueNodeUtil {
public static KuzuInternalID getID(KuzuValue value) throws KuzuObjectRefDestroyedException {
value.checkNotDestroyed();
return KuzuNative.kuzu_node_val_get_id(value);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.kuzudb;

public class KuzuRelValue {
public class KuzuValueRelUtil {
public static KuzuInternalID getSrcID(KuzuValue value) throws KuzuObjectRefDestroyedException {
value.checkNotDestroyed();
return KuzuNative.kuzu_rel_val_get_src_id(value);
Expand Down
35 changes: 35 additions & 0 deletions tools/java_api/src/main/java/com/kuzudb/KuzuValueStructUtil.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.kuzudb;

public class KuzuValueStructUtil {
public static long getNumFields(KuzuValue value) throws KuzuObjectRefDestroyedException {
value.checkNotDestroyed();
return KuzuNative.kuzu_value_get_list_size(value);
}

public static long getIndexByFieldName(KuzuValue value, String fieldName) throws KuzuObjectRefDestroyedException {
value.checkNotDestroyed();
return KuzuNative.kuzu_value_get_struct_index(value, fieldName);
}

public static String getFieldNameByIndex(KuzuValue value, long index) throws KuzuObjectRefDestroyedException {
value.checkNotDestroyed();
return KuzuNative.kuzu_value_get_struct_field_name(value, index);
}

public static KuzuValue getValueByFieldName(KuzuValue value, String fieldName) throws KuzuObjectRefDestroyedException {
value.checkNotDestroyed();
long index = getIndexByFieldName(value, fieldName);
if (index < 0) {
return null;
}
return getValueByIndex(value, index);
}

public static KuzuValue getValueByIndex(KuzuValue value, long index) throws KuzuObjectRefDestroyedException {
value.checkNotDestroyed();
if (index < 0 || index >= getNumFields(value)) {
return null;
}
return KuzuNative.kuzu_value_get_list_element(value, index);
}
}
140 changes: 115 additions & 25 deletions tools/java_api/src/test/java/com/kuzudb/test/ValueTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ void ValueGetListSize() throws KuzuObjectRefDestroyedException {

assertTrue(value.isOwnedByCPP());
assertFalse(value.isNull());
assertEquals(value.getListSize(), 2);
assertEquals(KuzuValueListUtil.getListSize(value), 2);

value.destroy();
flatTuple.destroy();
Expand All @@ -279,19 +279,19 @@ void ValueGetListElement() throws KuzuObjectRefDestroyedException {
KuzuValue value = flatTuple.getValue(0);
assertTrue(value.isOwnedByCPP());
assertFalse(value.isNull());
assertEquals(value.getListSize(), 2);
assertEquals(KuzuValueListUtil.getListSize(value), 2);

KuzuValue listElement = value.getListElement(0);
KuzuValue listElement = KuzuValueListUtil.getListElement(value, 0);
assertTrue(listElement.isOwnedByCPP());
assertTrue(listElement.getValue().equals(10L));
listElement.destroy();

listElement = value.getListElement(1);
listElement = KuzuValueListUtil.getListElement(value, 1);
assertTrue(listElement.isOwnedByCPP());
assertTrue(listElement.getValue().equals(5L));
listElement.destroy();

listElement = value.getListElement(222);
listElement = KuzuValueListUtil.getListElement(value, 222);
assertNull(listElement);

value.destroy();
Expand Down Expand Up @@ -547,7 +547,7 @@ void NodeValGetID() throws KuzuObjectRefDestroyedException {
assertTrue(value.isOwnedByCPP());
assertFalse(value.isNull());

KuzuInternalID id = KuzuNodeValue.getID(value);
KuzuInternalID id = KuzuValueNodeUtil.getID(value);
assertEquals(id.table_id, 0);
assertEquals(id.offset, 0);
value.destroy();
Expand All @@ -566,7 +566,7 @@ void NodeValGetLabelName() throws KuzuObjectRefDestroyedException {
assertTrue(value.isOwnedByCPP());
assertFalse(value.isNull());

String label = KuzuNodeValue.getLabelName(value);
String label = KuzuValueNodeUtil.getLabelName(value);
assertEquals(label, "person");
value.destroy();
flatTuple.destroy();
Expand All @@ -581,28 +581,28 @@ void NodeValGetProperty() throws KuzuObjectRefDestroyedException {
KuzuFlatTuple flatTuple = result.getNext();
KuzuValue value = flatTuple.getValue(0);
assertTrue(value.isOwnedByCPP());
String propertyName = KuzuNodeValue.getPropertyNameAt(value, 0);
String propertyName = KuzuValueNodeUtil.getPropertyNameAt(value, 0);
assertTrue(propertyName.equals("ID"));
propertyName = KuzuNodeValue.getPropertyNameAt(value, 1);
propertyName = KuzuValueNodeUtil.getPropertyNameAt(value, 1);
assertTrue(propertyName.equals("fName"));
propertyName = KuzuNodeValue.getPropertyNameAt(value, 2);
propertyName = KuzuValueNodeUtil.getPropertyNameAt(value, 2);
assertTrue(propertyName.equals("gender"));
propertyName = KuzuNodeValue.getPropertyNameAt(value, 3);
propertyName = KuzuValueNodeUtil.getPropertyNameAt(value, 3);
assertTrue(propertyName.equals("isStudent"));

KuzuValue propertyValue = KuzuNodeValue.getPropertyValueAt(value, 0);
KuzuValue propertyValue = KuzuValueNodeUtil.getPropertyValueAt(value, 0);
long propertyValueID = propertyValue.getValue();
assertEquals(propertyValueID, 0);
propertyValue.destroy();
propertyValue = KuzuNodeValue.getPropertyValueAt(value, 1);
propertyValue = KuzuValueNodeUtil.getPropertyValueAt(value, 1);
String propertyValuefName = propertyValue.getValue();
assertTrue(propertyValuefName.equals("Alice"));
propertyValue.destroy();
propertyValue = KuzuNodeValue.getPropertyValueAt(value, 2);
propertyValue = KuzuValueNodeUtil.getPropertyValueAt(value, 2);
long propertyValueGender = propertyValue.getValue();
assertEquals(propertyValueGender, 1);
propertyValue.destroy();
propertyValue = KuzuNodeValue.getPropertyValueAt(value, 3);
propertyValue = KuzuValueNodeUtil.getPropertyValueAt(value, 3);
boolean propertyValueIsStudent = propertyValue.getValue();
assertEquals(propertyValueIsStudent, true);
propertyValue.destroy();
Expand All @@ -620,7 +620,7 @@ void NodeValToString() throws KuzuObjectRefDestroyedException {
KuzuFlatTuple flatTuple = result.getNext();
KuzuValue value = flatTuple.getValue(0);
assertTrue(value.isOwnedByCPP());
String str = KuzuNodeValue.toString(value);
String str = KuzuValueNodeUtil.toString(value);
assertEquals(str, "{_ID: 1:0, _LABEL: organisation, ID: 1, name: ABFsUni, orgCode: 325, mark: 3.700000, " +
"score: -2, history: 10 years 5 months 13 hours 24 us, licenseValidInterval: 3 years " +
"5 days, rating: 1.000000, state: {revenue: 138, location: ['toronto', 'montr,eal'], " +
Expand All @@ -641,18 +641,18 @@ void RelValGetIDsAndLabel() throws KuzuObjectRefDestroyedException {
assertTrue(value.isOwnedByCPP());
assertFalse(value.isNull());

KuzuInternalID srcId = KuzuRelValue.getSrcID(value);
KuzuInternalID srcId = KuzuValueRelUtil.getSrcID(value);
assertEquals(srcId.table_id, 0);
assertEquals(srcId.offset, 0);

KuzuInternalID dstId = KuzuRelValue.getDstID(value);
KuzuInternalID dstId = KuzuValueRelUtil.getDstID(value);
assertEquals(dstId.table_id, 0);
assertEquals(dstId.offset, 1);

String label = KuzuRelValue.getLabelName(value);
String label = KuzuValueRelUtil.getLabelName(value);
assertTrue(label.equals("knows"));

long size = KuzuRelValue.getPropertySize(value);
long size = KuzuValueRelUtil.getPropertySize(value);
assertEquals(size, 4);

value.destroy();
Expand All @@ -669,16 +669,16 @@ void RelValGetProperty() throws KuzuObjectRefDestroyedException {
KuzuValue value = flatTuple.getValue(0);
assertTrue(value.isOwnedByCPP());

String propertyName = KuzuRelValue.getPropertyNameAt(value, 0);
String propertyName = KuzuValueRelUtil.getPropertyNameAt(value, 0);
assertEquals(propertyName, "year");

propertyName = KuzuRelValue.getPropertyNameAt(value, 1);
propertyName = KuzuValueRelUtil.getPropertyNameAt(value, 1);
assertEquals(propertyName, "grading");

propertyName = KuzuRelValue.getPropertyNameAt(value, 2);
propertyName = KuzuValueRelUtil.getPropertyNameAt(value, 2);
assertEquals(propertyName, "rating");

KuzuValue propertyValue = KuzuRelValue.getPropertyValueAt(value, 0);
KuzuValue propertyValue = KuzuValueRelUtil.getPropertyValueAt(value, 0);
long propertyValueYear = propertyValue.getValue();
assertEquals(propertyValueYear, 2015);

Expand All @@ -696,11 +696,101 @@ void RelValToString() throws KuzuObjectRefDestroyedException {
KuzuFlatTuple flatTuple = result.getNext();
KuzuValue value = flatTuple.getValue(0);
assertTrue(value.isOwnedByCPP());
String str = KuzuRelValue.toString(value);
String str = KuzuValueRelUtil.toString(value);
assertEquals(str, "(0:2)-{_LABEL: workAt, _ID: 5:0, year: 2015, grading: [3.800000,2.500000], " +
"rating: 8.200000}->(1:1)");
value.destroy();
flatTuple.destroy();
result.destroy();
}

@Test
void StructValGetNumFields() throws KuzuObjectRefDestroyedException {
KuzuQueryResult result = conn.query("MATCH (m:movies) WHERE m.name=\"Roma\" RETURN m.description");
assertTrue(result.isSuccess());
assertTrue(result.hasNext());
KuzuFlatTuple flatTuple = result.getNext();
KuzuValue value = flatTuple.getValue(0);
assertTrue(value.isOwnedByCPP());
assertEquals(KuzuValueStructUtil.getNumFields(value), 4);
value.destroy();
flatTuple.destroy();
result.destroy();
}

@Test
void StructValGetIndexByFieldName() throws KuzuObjectRefDestroyedException {
KuzuQueryResult result = conn.query("MATCH (m:movies) WHERE m.name=\"Roma\" RETURN m.description");
assertTrue(result.isSuccess());
assertTrue(result.hasNext());
KuzuFlatTuple flatTuple = result.getNext();
KuzuValue value = flatTuple.getValue(0);
assertTrue(value.isOwnedByCPP());
assertEquals(KuzuValueStructUtil.getIndexByFieldName(value, "NOT_EXIST"), -1);

assertEquals(KuzuValueStructUtil.getIndexByFieldName(value, "rating"), 0);
assertEquals(KuzuValueStructUtil.getIndexByFieldName(value, "views"), 1);
assertEquals(KuzuValueStructUtil.getIndexByFieldName(value, "release"), 2);
assertEquals(KuzuValueStructUtil.getIndexByFieldName(value, "film"), 3);
value.destroy();
flatTuple.destroy();
result.destroy();
}

@Test
void StructValGetFieldNameByIndex() throws KuzuObjectRefDestroyedException {
KuzuQueryResult result = conn.query("MATCH (m:movies) WHERE m.name=\"Roma\" RETURN m.description");
assertTrue(result.isSuccess());
assertTrue(result.hasNext());
KuzuFlatTuple flatTuple = result.getNext();
KuzuValue value = flatTuple.getValue(0);
assertTrue(value.isOwnedByCPP());
assertNull(KuzuValueStructUtil.getFieldNameByIndex(value, 1024));
assertNull(KuzuValueStructUtil.getFieldNameByIndex(value, -1));
assertEquals(KuzuValueStructUtil.getFieldNameByIndex(value, 0), "rating");
assertEquals(KuzuValueStructUtil.getFieldNameByIndex(value, 1), "views");
assertEquals(KuzuValueStructUtil.getFieldNameByIndex(value, 2), "release");
assertEquals(KuzuValueStructUtil.getFieldNameByIndex(value, 3), "film");
value.destroy();
flatTuple.destroy();
result.destroy();
}

@Test
void StructValGetValueByFieldName() throws KuzuObjectRefDestroyedException {
KuzuQueryResult result = conn.query("MATCH (m:movies) WHERE m.name=\"Roma\" RETURN m.description ORDER BY m.name");
assertTrue(result.isSuccess());
assertTrue(result.hasNext());
KuzuFlatTuple flatTuple = result.getNext();
KuzuValue value = flatTuple.getValue(0);
assertTrue(value.isOwnedByCPP());
KuzuValue fieldValue = KuzuValueStructUtil.getValueByFieldName(value, "NOT_EXIST");
assertNull(fieldValue);
fieldValue = KuzuValueStructUtil.getValueByFieldName(value, "rating");
assertEquals(fieldValue.getValue(), 1223.0);
fieldValue.destroy();
value.destroy();
flatTuple.destroy();
result.destroy();
}

@Test
void StructValGetValueByIndex() throws KuzuObjectRefDestroyedException {
KuzuQueryResult result = conn.query("MATCH (m:movies) WHERE m.name=\"Roma\" RETURN m.description ORDER BY m.name");
assertTrue(result.isSuccess());
assertTrue(result.hasNext());
KuzuFlatTuple flatTuple = result.getNext();
KuzuValue value = flatTuple.getValue(0);
assertTrue(value.isOwnedByCPP());
KuzuValue fieldValue = KuzuValueStructUtil.getValueByIndex(value, 1024);
assertNull(fieldValue);
fieldValue = KuzuValueStructUtil.getValueByIndex(value, -1);
assertNull(fieldValue);
fieldValue = KuzuValueStructUtil.getValueByIndex(value, 0);
assertEquals(fieldValue.getValue(), 1223.0);
fieldValue.destroy();
value.destroy();
flatTuple.destroy();
result.destroy();
}
}
Loading