/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.nifi.record.path;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import org.apache.nifi.serialization.SimpleRecordSchema;
import org.apache.nifi.serialization.record.DataType;
import org.apache.nifi.serialization.record.MapRecord;
import org.apache.nifi.serialization.record.Record;
import org.apache.nifi.serialization.record.RecordField;
import org.apache.nifi.serialization.record.RecordFieldType;
import org.apache.nifi.serialization.record.RecordSchema;
import org.junit.Test;
public class TestRecordPath {
@Test
public void testCompile() {
System.out.println(RecordPath.compile("/person/name/last"));
System.out.println(RecordPath.compile("/person[2]"));
System.out.println(RecordPath.compile("//person[2]"));
System.out.println(RecordPath.compile("/person/child[1]//sibling/name"));
}
@Test
public void testChildField() {
final Map<String, Object> accountValues = new HashMap<>();
accountValues.put("id", 1);
accountValues.put("balance", 123.45D);
final Record accountRecord = new MapRecord(getAccountSchema(), accountValues);
final RecordSchema schema = new SimpleRecordSchema(getDefaultFields());
final Map<String, Object> values = new HashMap<>();
values.put("id", 48);
values.put("name", "John Doe");
values.put("mainAccount", accountRecord);
final Record record = new MapRecord(schema, values);
assertEquals(48, RecordPath.compile("/id").evaluate(record).getSelectedFields().findFirst().get().getValue());
assertEquals(record, RecordPath.compile("/id").evaluate(record).getSelectedFields().findFirst().get().getParentRecord().get());
assertEquals("John Doe", RecordPath.compile("/name").evaluate(record).getSelectedFields().findFirst().get().getValue());
assertEquals(record, RecordPath.compile("/name").evaluate(record).getSelectedFields().findFirst().get().getParentRecord().get());
assertEquals(accountRecord, RecordPath.compile("/mainAccount").evaluate(record).getSelectedFields().findFirst().get().getValue());
assertEquals(record, RecordPath.compile("/mainAccount").evaluate(record).getSelectedFields().findFirst().get().getParentRecord().get());
assertEquals(1, RecordPath.compile("/mainAccount/id").evaluate(record).getSelectedFields().findFirst().get().getValue());
assertEquals(accountRecord, RecordPath.compile("/mainAccount/id").evaluate(record).getSelectedFields().findFirst().get().getParentRecord().get());
assertEquals(123.45D, RecordPath.compile("/mainAccount/balance").evaluate(record).getSelectedFields().findFirst().get().getValue());
assertEquals(accountRecord, RecordPath.compile("/mainAccount/id").evaluate(record).getSelectedFields().findFirst().get().getParentRecord().get());
}
@Test
public void testRootRecord() {
final RecordSchema schema = new SimpleRecordSchema(getDefaultFields());
final Map<String, Object> values = new HashMap<>();
values.put("id", 48);
values.put("name", "John Doe");
final Record record = new MapRecord(schema, values);
final FieldValue fieldValue = RecordPath.compile("/").evaluate(record).getSelectedFields().findFirst().get();
assertEquals(Optional.empty(), fieldValue.getParent());
assertEquals(record, fieldValue.getValue());
}
@Test
public void testWildcardChild() {
final Map<String, Object> accountValues = new HashMap<>();
accountValues.put("id", 1);
accountValues.put("balance", 123.45D);
final Record accountRecord = new MapRecord(getAccountSchema(), accountValues);
final RecordSchema schema = new SimpleRecordSchema(getDefaultFields());
final Map<String, Object> values = new HashMap<>();
values.put("id", 48);
values.put("name", "John Doe");
values.put("mainAccount", accountRecord);
final Record record = new MapRecord(schema, values);
final List<FieldValue> fieldValues = RecordPath.compile("/mainAccount/*").evaluate(record).getSelectedFields().collect(Collectors.toList());
assertEquals(2, fieldValues.size());
for (final FieldValue fieldValue : fieldValues) {
assertEquals(accountRecord, fieldValue.getParentRecord().get());
}
assertEquals("id", fieldValues.get(0).getField().getFieldName());
assertEquals(1, fieldValues.get(0).getValue());
assertEquals("balance", fieldValues.get(1).getField().getFieldName());
assertEquals(123.45D, fieldValues.get(1).getValue());
}
@Test
public void testWildcardWithArray() {
final Map<String, Object> accountValues = new HashMap<>();
accountValues.put("id", 1);
accountValues.put("balance", 123.45D);
final Record accountRecord = new MapRecord(getAccountSchema(), accountValues);
final RecordSchema schema = new SimpleRecordSchema(getDefaultFields());
final Map<String, Object> values = new HashMap<>();
values.put("id", 48);
values.put("name", "John Doe");
values.put("accounts", new Object[] {accountRecord});
final Record record = new MapRecord(schema, values);
final List<FieldValue> fieldValues = RecordPath.compile("/*[0]").evaluate(record).getSelectedFields().collect(Collectors.toList());
assertEquals(1, fieldValues.size());
final FieldValue fieldValue = fieldValues.get(0);
assertTrue(fieldValue.getField().getFieldName().startsWith("accounts["));
assertEquals(record, fieldValue.getParentRecord().get());
assertEquals(accountRecord, fieldValue.getValue());
}
@Test
public void testDescendantField() {
final Map<String, Object> accountValues = new HashMap<>();
accountValues.put("id", 1);
accountValues.put("balance", 123.45D);
final Record accountRecord = new MapRecord(getAccountSchema(), accountValues);
final RecordSchema schema = new SimpleRecordSchema(getDefaultFields());
final Map<String, Object> values = new HashMap<>();
values.put("id", 48);
values.put("name", "John Doe");
values.put("mainAccount", accountRecord);
final Record record = new MapRecord(schema, values);
final List<FieldValue> fieldValues = RecordPath.compile("//id").evaluate(record).getSelectedFields().collect(Collectors.toList());
assertEquals(2, fieldValues.size());
final FieldValue first = fieldValues.get(0);
final FieldValue second = fieldValues.get(1);
assertEquals(RecordFieldType.INT, first.getField().getDataType().getFieldType());
assertEquals(RecordFieldType.INT, second.getField().getDataType().getFieldType());
assertEquals(48, first.getValue());
assertEquals(1, second.getValue());
}
@Test
public void testParent() {
final Map<String, Object> accountValues = new HashMap<>();
accountValues.put("id", 1);
accountValues.put("balance", 123.45D);
final Record accountRecord = new MapRecord(getAccountSchema(), accountValues);
final RecordSchema schema = new SimpleRecordSchema(getDefaultFields());
final Map<String, Object> values = new HashMap<>();
values.put("id", 48);
values.put("name", "John Doe");
values.put("mainAccount", accountRecord);
final Record record = new MapRecord(schema, values);
final List<FieldValue> fieldValues = RecordPath.compile("//id/..").evaluate(record).getSelectedFields().collect(Collectors.toList());
assertEquals(2, fieldValues.size());
final FieldValue first = fieldValues.get(0);
final FieldValue second = fieldValues.get(1);
assertEquals(RecordFieldType.RECORD, first.getField().getDataType().getFieldType());
assertEquals(RecordFieldType.RECORD, second.getField().getDataType().getFieldType());
assertEquals(record, first.getValue());
assertEquals(accountRecord, second.getValue());
}
@Test
public void testMapKey() {
final RecordSchema schema = new SimpleRecordSchema(getDefaultFields());
final Map<String, String> attributes = new HashMap<>();
attributes.put("city", "New York");
attributes.put("state", "NY");
final Map<String, Object> values = new HashMap<>();
values.put("id", 48);
values.put("name", "John Doe");
values.put("attributes", attributes);
final Record record = new MapRecord(schema, values);
final FieldValue fieldValue = RecordPath.compile("/attributes['city']").evaluate(record).getSelectedFields().findFirst().get();
assertTrue(fieldValue.getField().getFieldName().startsWith("attributes['"));
assertEquals("New York", fieldValue.getValue());
assertEquals(record, fieldValue.getParentRecord().get());
}
@Test
public void testMapWildcard() {
final RecordSchema schema = new SimpleRecordSchema(getDefaultFields());
final Map<String, String> attributes = new HashMap<>();
attributes.put("city", "New York");
attributes.put("state", "NY");
final Map<String, Object> values = new HashMap<>();
values.put("id", 48);
values.put("name", "John Doe");
values.put("attributes", attributes);
final Record record = new MapRecord(schema, values);
final List<FieldValue> fieldValues = RecordPath.compile("/attributes[*]").evaluate(record).getSelectedFields().collect(Collectors.toList());
assertEquals(2, fieldValues.size());
assertEquals("New York", fieldValues.get(0).getValue());
assertEquals("NY", fieldValues.get(1).getValue());
for (final FieldValue fieldValue : fieldValues) {
assertTrue(fieldValue.getField().getFieldName().startsWith("attributes['"));
assertEquals(record, fieldValue.getParentRecord().get());
}
}
@Test
public void testMapMultiKey() {
final RecordSchema schema = new SimpleRecordSchema(getDefaultFields());
final Map<String, String> attributes = new HashMap<>();
attributes.put("city", "New York");
attributes.put("state", "NY");
final Map<String, Object> values = new HashMap<>();
values.put("id", 48);
values.put("name", "John Doe");
values.put("attributes", attributes);
final Record record = new MapRecord(schema, values);
final List<FieldValue> fieldValues = RecordPath.compile("/attributes['city', 'state']").evaluate(record).getSelectedFields().collect(Collectors.toList());
assertEquals(2, fieldValues.size());
assertEquals("New York", fieldValues.get(0).getValue());
assertEquals("NY", fieldValues.get(1).getValue());
for (final FieldValue fieldValue : fieldValues) {
assertTrue(fieldValue.getField().getFieldName().startsWith("attributes['"));
assertEquals(record, fieldValue.getParentRecord().get());
}
}
@Test
public void testEscapedFieldName() {
final List<RecordField> fields = new ArrayList<>();
fields.add(new RecordField("id", RecordFieldType.INT.getDataType()));
fields.add(new RecordField("name,date", RecordFieldType.STRING.getDataType()));
final RecordSchema schema = new SimpleRecordSchema(fields);
final Map<String, Object> values = new HashMap<>();
values.put("id", 48);
values.put("name,date", "John Doe");
final Record record = new MapRecord(schema, values);
final FieldValue fieldValue = RecordPath.compile("/'name,date'").evaluate(record).getSelectedFields().findFirst().get();
assertEquals("name,date", fieldValue.getField().getFieldName());
assertEquals("John Doe", fieldValue.getValue());
assertEquals(record, fieldValue.getParentRecord().get());
}
@Test
public void testSingleArrayIndex() {
final RecordSchema schema = new SimpleRecordSchema(getDefaultFields());
final Map<String, Object> values = new HashMap<>();
values.put("id", 48);
values.put("numbers", new Object[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9});
final Record record = new MapRecord(schema, values);
final FieldValue fieldValue = RecordPath.compile("/numbers[3]").evaluate(record).getSelectedFields().findFirst().get();
assertTrue(fieldValue.getField().getFieldName().startsWith("numbers["));
assertEquals(3, fieldValue.getValue());
assertEquals(record, fieldValue.getParentRecord().get());
}
@Test
public void testSingleArrayRange() {
final RecordSchema schema = new SimpleRecordSchema(getDefaultFields());
final Map<String, Object> values = new HashMap<>();
values.put("id", 48);
values.put("numbers", new Object[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9});
final Record record = new MapRecord(schema, values);
final List<FieldValue> fieldValues = RecordPath.compile("/numbers[0..1]").evaluate(record).getSelectedFields().collect(Collectors.toList());
for (final FieldValue fieldValue : fieldValues) {
assertTrue(fieldValue.getField().getFieldName().startsWith("numbers["));
assertEquals(record, fieldValue.getParentRecord().get());
}
assertEquals(2, fieldValues.size());
for (int i = 0; i < 1; i++) {
assertEquals(i, fieldValues.get(0).getValue());
}
}
@Test
public void testMultiArrayIndex() {
final RecordSchema schema = new SimpleRecordSchema(getDefaultFields());
final Map<String, Object> values = new HashMap<>();
values.put("id", 48);
values.put("numbers", new Object[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9});
final Record record = new MapRecord(schema, values);
final List<FieldValue> fieldValues = RecordPath.compile("/numbers[3,6, -1, -2]").evaluate(record).getSelectedFields().collect(Collectors.toList());
int i = 0;
final int[] expectedValues = new int[] {3, 6, 9, 8};
for (final FieldValue fieldValue : fieldValues) {
assertTrue(fieldValue.getField().getFieldName().startsWith("numbers["));
assertEquals(expectedValues[i++], fieldValue.getValue());
assertEquals(record, fieldValue.getParentRecord().get());
}
}
@Test
public void testMultiArrayIndexWithRanges() {
final RecordSchema schema = new SimpleRecordSchema(getDefaultFields());
final Map<String, Object> values = new HashMap<>();
values.put("id", 48);
values.put("numbers", new Object[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9});
final Record record = new MapRecord(schema, values);
List<FieldValue> fieldValues = RecordPath.compile("/numbers[0, 2, 4..7, 9]").evaluate(record).getSelectedFields().collect(Collectors.toList());
for (final FieldValue fieldValue : fieldValues) {
assertTrue(fieldValue.getField().getFieldName().startsWith("numbers["));
assertEquals(record, fieldValue.getParentRecord().get());
}
int[] expectedValues = new int[] {0, 2, 4, 5, 6, 7, 9};
assertEquals(expectedValues.length, fieldValues.size());
for (int i = 0; i < expectedValues.length; i++) {
assertEquals(expectedValues[i], fieldValues.get(i).getValue());
}
fieldValues = RecordPath.compile("/numbers[0..-1]").evaluate(record).getSelectedFields().collect(Collectors.toList());
for (final FieldValue fieldValue : fieldValues) {
assertTrue(fieldValue.getField().getFieldName().startsWith("numbers["));
assertEquals(record, fieldValue.getParentRecord().get());
}
expectedValues = new int[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
assertEquals(expectedValues.length, fieldValues.size());
for (int i = 0; i < expectedValues.length; i++) {
assertEquals(expectedValues[i], fieldValues.get(i).getValue());
}
fieldValues = RecordPath.compile("/numbers[-1..-1]").evaluate(record).getSelectedFields().collect(Collectors.toList());
for (final FieldValue fieldValue : fieldValues) {
assertTrue(fieldValue.getField().getFieldName().startsWith("numbers["));
assertEquals(record, fieldValue.getParentRecord().get());
}
expectedValues = new int[] {9};
assertEquals(expectedValues.length, fieldValues.size());
for (int i = 0; i < expectedValues.length; i++) {
assertEquals(expectedValues[i], fieldValues.get(i).getValue());
}
fieldValues = RecordPath.compile("/numbers[*]").evaluate(record).getSelectedFields().collect(Collectors.toList());
for (final FieldValue fieldValue : fieldValues) {
assertTrue(fieldValue.getField().getFieldName().startsWith("numbers["));
assertEquals(record, fieldValue.getParentRecord().get());
}
expectedValues = new int[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
assertEquals(expectedValues.length, fieldValues.size());
for (int i = 0; i < expectedValues.length; i++) {
assertEquals(expectedValues[i], fieldValues.get(i).getValue());
}
fieldValues = RecordPath.compile("/xx[1,2,3]").evaluate(record).getSelectedFields().collect(Collectors.toList());
assertEquals(0, fieldValues.size());
}
@Test
public void testEqualsPredicate() {
final Map<String, Object> accountValues = new HashMap<>();
accountValues.put("id", 1);
accountValues.put("balance", 123.45D);
final Record accountRecord = new MapRecord(getAccountSchema(), accountValues);
final RecordSchema schema = new SimpleRecordSchema(getDefaultFields());
final Map<String, Object> values = new HashMap<>();
values.put("id", 48);
values.put("name", "John Doe");
values.put("mainAccount", accountRecord);
values.put("numbers", new Object[] {1, 2, 3, 4, 4, 4, 5});
final Record record = new MapRecord(schema, values);
List<FieldValue> fieldValues = RecordPath.compile("/numbers[0..-1][. = 4]").evaluate(record).getSelectedFields().collect(Collectors.toList());
assertEquals(3, fieldValues.size());
for (final FieldValue fieldValue : fieldValues) {
final String fieldName = fieldValue.getField().getFieldName();
assertTrue(Pattern.compile("numbers\\[\\d\\]").matcher(fieldName).matches());
assertEquals(RecordFieldType.INT, fieldValue.getField().getDataType().getFieldType());
assertEquals(4, fieldValue.getValue());
assertEquals(record, fieldValue.getParentRecord().get());
}
fieldValues = RecordPath.compile("//id[. = 48]").evaluate(record).getSelectedFields().collect(Collectors.toList());
assertEquals(1, fieldValues.size());
final FieldValue fieldValue = fieldValues.get(0);
assertEquals("id", fieldValue.getField().getFieldName());
assertEquals(RecordFieldType.INT.getDataType(), fieldValue.getField().getDataType());
assertEquals(48, fieldValue.getValue());
assertEquals(record, fieldValue.getParentRecord().get());
}
@Test
public void testRelativePath() {
final Map<String, Object> accountValues = new HashMap<>();
accountValues.put("id", 1);
accountValues.put("balance", 123.45D);
final Record accountRecord = new MapRecord(getAccountSchema(), accountValues);
final RecordSchema schema = new SimpleRecordSchema(getDefaultFields());
final Map<String, Object> values = new HashMap<>();
values.put("id", 48);
values.put("name", "John Doe");
values.put("mainAccount", accountRecord);
final Record record = new MapRecord(schema, values);
final List<FieldValue> fieldValues = RecordPath.compile("/mainAccount/././balance/.").evaluate(record).getSelectedFields().collect(Collectors.toList());
assertEquals(1, fieldValues.size());
final FieldValue fieldValue = fieldValues.get(0);
assertEquals(accountRecord, fieldValue.getParentRecord().get());
assertEquals(123.45D, fieldValue.getValue());
assertEquals("balance", fieldValue.getField().getFieldName());
}
@Test
public void testCompareToLiteral() {
final RecordSchema schema = new SimpleRecordSchema(getDefaultFields());
final Map<String, Object> values = new HashMap<>();
values.put("id", 48);
values.put("name", "John Doe");
values.put("numbers", new Object[] {0, 1, 2});
final Record record = new MapRecord(schema, values);
List<FieldValue> fieldValues = RecordPath.compile("/id[. > 42]").evaluate(record).getSelectedFields().collect(Collectors.toList());
assertEquals(1, fieldValues.size());
fieldValues = RecordPath.compile("/id[. < 42]").evaluate(record).getSelectedFields().collect(Collectors.toList());
assertEquals(0, fieldValues.size());
}
@Test
public void testCompareToAbsolute() {
final RecordSchema schema = new SimpleRecordSchema(getDefaultFields());
final Map<String, Object> values = new HashMap<>();
values.put("id", 48);
values.put("name", "John Doe");
values.put("numbers", new Object[] {0, 1, 2});
final Record record = new MapRecord(schema, values);
List<FieldValue> fieldValues = RecordPath.compile("/numbers[0..-1][. < /id]").evaluate(record).getSelectedFields().collect(Collectors.toList());
assertEquals(3, fieldValues.size());
fieldValues = RecordPath.compile("/id[. > /numbers[-1]]").evaluate(record).getSelectedFields().collect(Collectors.toList());
assertEquals(1, fieldValues.size());
}
@Test
public void testCompareWithEmbeddedPaths() {
final Map<String, Object> accountValues1 = new HashMap<>();
accountValues1.put("id", 1);
accountValues1.put("balance", 10_000.00D);
final Record accountRecord1 = new MapRecord(getAccountSchema(), accountValues1);
final Map<String, Object> accountValues2 = new HashMap<>();
accountValues2.put("id", 2);
accountValues2.put("balance", 48.02D);
final Record accountRecord2 = new MapRecord(getAccountSchema(), accountValues2);
final RecordSchema schema = new SimpleRecordSchema(getDefaultFields());
final Map<String, Object> values = new HashMap<>();
values.put("id", 48);
values.put("name", "John Doe");
values.put("accounts", new Object[] {accountRecord1, accountRecord2});
final Record record = new MapRecord(schema, values);
final RecordPath recordPath = RecordPath.compile("/accounts[0..-1][./balance > 100]");
List<FieldValue> fieldValues = recordPath.evaluate(record).getSelectedFields().collect(Collectors.toList());
assertEquals(1, fieldValues.size());
final FieldValue fieldValue = fieldValues.get(0);
assertEquals("accounts[0]", fieldValue.getField().getFieldName());
assertEquals(record, fieldValue.getParentRecord().get());
assertEquals(accountRecord1, fieldValue.getValue());
}
@Test
public void testPredicateInMiddleOfPath() {
final Map<String, Object> accountValues1 = new HashMap<>();
accountValues1.put("id", 1);
accountValues1.put("balance", 10_000.00D);
final Record accountRecord1 = new MapRecord(getAccountSchema(), accountValues1);
final Map<String, Object> accountValues2 = new HashMap<>();
accountValues2.put("id", 2);
accountValues2.put("balance", 48.02D);
final Record accountRecord2 = new MapRecord(getAccountSchema(), accountValues2);
final RecordSchema schema = new SimpleRecordSchema(getDefaultFields());
final Map<String, Object> values = new HashMap<>();
values.put("id", 48);
values.put("name", "John Doe");
values.put("accounts", new Object[] {accountRecord1, accountRecord2});
final Record record = new MapRecord(schema, values);
final RecordPath recordPath = RecordPath.compile("/accounts[0..-1][./balance > 100]/id");
List<FieldValue> fieldValues = recordPath.evaluate(record).getSelectedFields().collect(Collectors.toList());
assertEquals(1, fieldValues.size());
final FieldValue fieldValue = fieldValues.get(0);
assertEquals("id", fieldValue.getField().getFieldName());
assertEquals(accountRecord1, fieldValue.getParentRecord().get());
assertEquals(1, fieldValue.getValue());
}
@Test
public void testUpdateValueOnMatchingFields() {
final Map<String, Object> accountValues1 = new HashMap<>();
accountValues1.put("id", 1);
accountValues1.put("balance", 10_000.00D);
final Record accountRecord1 = new MapRecord(getAccountSchema(), accountValues1);
final Map<String, Object> accountValues2 = new HashMap<>();
accountValues2.put("id", 2);
accountValues2.put("balance", 48.02D);
final Record accountRecord2 = new MapRecord(getAccountSchema(), accountValues2);
final RecordSchema schema = new SimpleRecordSchema(getDefaultFields());
final Map<String, Object> values = new HashMap<>();
values.put("id", 48);
values.put("name", "John Doe");
values.put("accounts", new Object[] {accountRecord1, accountRecord2});
final Record record = new MapRecord(schema, values);
final RecordPath recordPath = RecordPath.compile("/accounts[0..-1][./balance > 100]/id");
recordPath.evaluate(record).getSelectedFields().findFirst().get().updateValue(100);
assertEquals(48, record.getValue("id"));
assertEquals(100, accountRecord1.getValue("id"));
assertEquals(2, accountRecord2.getValue("id"));
}
@Test
public void testPredicateDoesNotIncludeFieldsThatDontHaveRelativePath() {
final List<RecordField> addressFields = new ArrayList<>();
addressFields.add(new RecordField("city", RecordFieldType.STRING.getDataType()));
addressFields.add(new RecordField("state", RecordFieldType.STRING.getDataType()));
addressFields.add(new RecordField("zip", RecordFieldType.STRING.getDataType()));
final RecordSchema addressSchema = new SimpleRecordSchema(addressFields);
final List<RecordField> detailsFields = new ArrayList<>();
detailsFields.add(new RecordField("position", RecordFieldType.STRING.getDataType()));
detailsFields.add(new RecordField("managerName", RecordFieldType.STRING.getDataType()));
final RecordSchema detailsSchema = new SimpleRecordSchema(detailsFields);
final List<RecordField> fields = new ArrayList<>();
fields.add(new RecordField("name", RecordFieldType.STRING.getDataType()));
fields.add(new RecordField("address", RecordFieldType.RECORD.getRecordDataType(addressSchema)));
fields.add(new RecordField("details", RecordFieldType.RECORD.getRecordDataType(detailsSchema)));
final RecordSchema recordSchema = new SimpleRecordSchema(fields);
final Record record = new MapRecord(recordSchema, new HashMap<>());
record.setValue("name", "John Doe");
final Record addressRecord = new MapRecord(addressSchema, new HashMap<>());
addressRecord.setValue("city", "San Francisco");
addressRecord.setValue("state", "CA");
addressRecord.setValue("zip", "12345");
record.setValue("address", addressRecord);
final Record detailsRecord = new MapRecord(detailsSchema, new HashMap<>());
detailsRecord.setValue("position", "Developer");
detailsRecord.setValue("managerName", "Jane Doe");
record.setValue("details", detailsRecord);
final RecordPath recordPath = RecordPath.compile("/*[./state != 'NY']");
final RecordPathResult result = recordPath.evaluate(record);
final List<FieldValue> fieldValues = result.getSelectedFields().collect(Collectors.toList());
assertEquals(1, fieldValues.size());
final FieldValue fieldValue = fieldValues.get(0);
assertEquals("address", fieldValue.getField().getFieldName());
assertEquals("12345", RecordPath.compile("/*[./state != 'NY']/zip").evaluate(record).getSelectedFields().findFirst().get().getValue());
}
@Test
public void testPredicateWithAbsolutePath() {
final List<RecordField> addressFields = new ArrayList<>();
addressFields.add(new RecordField("city", RecordFieldType.STRING.getDataType()));
addressFields.add(new RecordField("state", RecordFieldType.STRING.getDataType()));
addressFields.add(new RecordField("zip", RecordFieldType.STRING.getDataType()));
final RecordSchema addressSchema = new SimpleRecordSchema(addressFields);
final List<RecordField> detailsFields = new ArrayList<>();
detailsFields.add(new RecordField("position", RecordFieldType.STRING.getDataType()));
detailsFields.add(new RecordField("preferredState", RecordFieldType.STRING.getDataType()));
final RecordSchema detailsSchema = new SimpleRecordSchema(detailsFields);
final List<RecordField> fields = new ArrayList<>();
fields.add(new RecordField("name", RecordFieldType.STRING.getDataType()));
fields.add(new RecordField("address1", RecordFieldType.RECORD.getRecordDataType(addressSchema)));
fields.add(new RecordField("address2", RecordFieldType.RECORD.getRecordDataType(addressSchema)));
fields.add(new RecordField("details", RecordFieldType.RECORD.getRecordDataType(detailsSchema)));
final RecordSchema recordSchema = new SimpleRecordSchema(fields);
final Record record = new MapRecord(recordSchema, new HashMap<>());
record.setValue("name", "John Doe");
final Record address1Record = new MapRecord(addressSchema, new HashMap<>());
address1Record.setValue("city", "San Francisco");
address1Record.setValue("state", "CA");
address1Record.setValue("zip", "12345");
record.setValue("address1", address1Record);
final Record address2Record = new MapRecord(addressSchema, new HashMap<>());
address2Record.setValue("city", "New York");
address2Record.setValue("state", "NY");
address2Record.setValue("zip", "01234");
record.setValue("address2", address2Record);
final Record detailsRecord = new MapRecord(detailsSchema, new HashMap<>());
detailsRecord.setValue("position", "Developer");
detailsRecord.setValue("preferredState", "NY");
record.setValue("details", detailsRecord);
final RecordPath recordPath = RecordPath.compile("/*[./state = /details/preferredState]");
final RecordPathResult result = recordPath.evaluate(record);
final List<FieldValue> fieldValues = result.getSelectedFields().collect(Collectors.toList());
assertEquals(1, fieldValues.size());
final FieldValue fieldValue = fieldValues.get(0);
assertEquals("address2", fieldValue.getField().getFieldName());
}
@Test
public void testRelativePathOnly() {
final RecordSchema schema = new SimpleRecordSchema(getDefaultFields());
final Map<String, Object> values = new HashMap<>();
values.put("id", 48);
values.put("name", "John Doe");
final Record record = new MapRecord(schema, values);
final FieldValue recordFieldValue = new StandardFieldValue(record, new RecordField("record", RecordFieldType.RECORD.getDataType()), null);
final List<FieldValue> fieldValues = RecordPath.compile("./name").evaluate(recordFieldValue).getSelectedFields().collect(Collectors.toList());
assertEquals(1, fieldValues.size());
final FieldValue fieldValue = fieldValues.get(0);
assertEquals("John Doe", fieldValue.getValue());
assertEquals(record, fieldValue.getParentRecord().get());
assertEquals("name", fieldValue.getField().getFieldName());
}
@Test
public void testRelativePathAgainstNonRecordField() {
final RecordSchema schema = new SimpleRecordSchema(getDefaultFields());
final Map<String, Object> values = new HashMap<>();
values.put("id", 48);
values.put("name", "John Doe");
final Record record = new MapRecord(schema, values);
final FieldValue recordFieldValue = new StandardFieldValue(record, new RecordField("root", RecordFieldType.RECORD.getRecordDataType(record.getSchema())), null);
final FieldValue nameFieldValue = new StandardFieldValue("John Doe", new RecordField("name", RecordFieldType.STRING.getDataType()), recordFieldValue);
final List<FieldValue> fieldValues = RecordPath.compile(".").evaluate(nameFieldValue).getSelectedFields().collect(Collectors.toList());
assertEquals(1, fieldValues.size());
final FieldValue fieldValue = fieldValues.get(0);
assertEquals("John Doe", fieldValue.getValue());
assertEquals(record, fieldValue.getParentRecord().get());
assertEquals("name", fieldValue.getField().getFieldName());
fieldValue.updateValue("Jane Doe");
assertEquals("Jane Doe", record.getValue("name"));
}
private List<RecordField> getDefaultFields() {
final List<RecordField> fields = new ArrayList<>();
fields.add(new RecordField("id", RecordFieldType.INT.getDataType()));
fields.add(new RecordField("name", RecordFieldType.STRING.getDataType()));
fields.add(new RecordField("attributes", RecordFieldType.MAP.getMapDataType(RecordFieldType.STRING.getDataType())));
fields.add(new RecordField("mainAccount", RecordFieldType.RECORD.getRecordDataType(getAccountSchema())));
fields.add(new RecordField("numbers", RecordFieldType.ARRAY.getArrayDataType(RecordFieldType.INT.getDataType())));
final DataType accountDataType = RecordFieldType.RECORD.getRecordDataType(getAccountSchema());
final DataType accountsType = RecordFieldType.ARRAY.getArrayDataType(accountDataType);
final RecordField accountsField = new RecordField("accounts", accountsType);
fields.add(accountsField);
return fields;
}
private RecordSchema getAccountSchema() {
final List<RecordField> accountFields = new ArrayList<>();
accountFields.add(new RecordField("id", RecordFieldType.INT.getDataType()));
accountFields.add(new RecordField("balance", RecordFieldType.DOUBLE.getDataType()));
final RecordSchema accountSchema = new SimpleRecordSchema(accountFields);
return accountSchema;
}
}