diff --git a/nifi-commons/nifi-record-path/src/test/java/org/apache/nifi/record/path/TestRecordPath.java b/nifi-commons/nifi-record-path/src/test/java/org/apache/nifi/record/path/TestRecordPath.java
index a94338aed6dc..cd3517647b2a 100644
--- a/nifi-commons/nifi-record-path/src/test/java/org/apache/nifi/record/path/TestRecordPath.java
+++ b/nifi-commons/nifi-record-path/src/test/java/org/apache/nifi/record/path/TestRecordPath.java
@@ -17,13 +17,7 @@
package org.apache.nifi.record.path;
-import org.apache.nifi.json.JsonRecordSource;
-import org.apache.nifi.json.JsonSchemaInference;
-import org.apache.nifi.json.JsonTreeRowRecordReader;
-import org.apache.nifi.logging.ComponentLog;
import org.apache.nifi.record.path.exception.RecordPathException;
-import org.apache.nifi.schema.inference.TimeValueInference;
-import org.apache.nifi.serialization.MalformedRecordException;
import org.apache.nifi.serialization.SimpleRecordSchema;
import org.apache.nifi.serialization.record.DataType;
import org.apache.nifi.serialization.record.MapRecord;
@@ -31,2331 +25,3031 @@
import org.apache.nifi.serialization.record.RecordField;
import org.apache.nifi.serialization.record.RecordFieldType;
import org.apache.nifi.serialization.record.RecordSchema;
-import org.apache.nifi.serialization.record.type.ArrayDataType;
import org.apache.nifi.serialization.record.util.DataTypeUtils;
import org.apache.nifi.uuid5.Uuid5Util;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
-import org.mockito.Mockito;
+import org.junit.jupiter.api.function.Executable;
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
+import java.math.BigDecimal;
+import java.math.BigInteger;
import java.nio.charset.IllegalCharsetNameException;
import java.nio.charset.StandardCharsets;
import java.sql.Date;
+import java.sql.Time;
+import java.sql.Timestamp;
import java.time.Instant;
import java.time.LocalDateTime;
-import java.time.ZoneOffset;
+import java.time.ZoneId;
import java.time.ZonedDateTime;
-import java.util.ArrayList;
import java.util.Arrays;
import java.util.Base64;
-import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
+import java.util.TimeZone;
import java.util.UUID;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
+import java.util.stream.Stream;
+import static java.util.Map.entry;
+import static org.junit.jupiter.api.Assertions.assertAll;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-@SuppressWarnings("OptionalGetWithoutIsPresent")
+@SuppressWarnings({"SameParameterValue"})
public class TestRecordPath {
- private static final String USER_TIMEZONE_PROPERTY = "user.timezone";
+ private static final String USER_TIMEZONE_PROPERTY_NAME = "user.timezone";
+ private static final String INITIAL_USER_TIMEZONE = System.getProperty(USER_TIMEZONE_PROPERTY_NAME);
+ private static final TimeZone INITIAL_DEFAULT_TIMEZONE = TimeZone.getDefault();
- private static final String SYSTEM_TIMEZONE = System.getProperty(USER_TIMEZONE_PROPERTY);
-
- private static final String TEST_TIMEZONE = "America/Phoenix";
-
- private static final int TEST_OFFSET_HOURS = 2;
-
- private static final String TEST_TIMEZONE_OFFSET = String.format("GMT+0%d:00", TEST_OFFSET_HOURS);
+ private static final ZoneId TEST_ZONE_ID = ZoneId.of("America/Phoenix");
+ private static final TimeZone TEST_TIME_ZONE = TimeZone.getTimeZone(TEST_ZONE_ID);
@BeforeAll
public static void setTestTimezone() {
- System.setProperty(USER_TIMEZONE_PROPERTY, TEST_TIMEZONE);
+ System.setProperty(USER_TIMEZONE_PROPERTY_NAME, TEST_ZONE_ID.getId());
+ TimeZone.setDefault(TEST_TIME_ZONE);
}
@AfterAll
public static void setSystemTimezone() {
- if (SYSTEM_TIMEZONE != null) {
- System.setProperty(USER_TIMEZONE_PROPERTY, SYSTEM_TIMEZONE);
+ if (INITIAL_USER_TIMEZONE != null) {
+ System.setProperty(USER_TIMEZONE_PROPERTY_NAME, INITIAL_USER_TIMEZONE);
+ }
+ if (INITIAL_DEFAULT_TIMEZONE != null) {
+ TimeZone.setDefault(INITIAL_DEFAULT_TIMEZONE);
}
}
- @Test
- public void testCompile() {
- RecordPath.compile("/person/name/last");
- RecordPath.compile("/person[2]");
- RecordPath.compile("//person[2]");
- RecordPath.compile("/person/child[1]//sibling/name");
-
- // contains is a 'filter function' so can be used as the predicate
- RecordPath.compile("/name[contains(., 'hello')]");
+ private final Record record = createExampleRecord();
+ private final Record mainAccountRecord = record.getAsRecord("mainAccount", getAccountSchema());
- // substring is not a filter function so cannot be used as a predicate
- assertThrows(RecordPathException.class, () -> RecordPath.compile("/name[substring(., 1, 2)]"));
+ @Test
+ void supportsReferenceToRootRecord() {
+ final RecordPath recordPath = assertDoesNotThrow(() -> RecordPath.compile("/"));
- // substring is not a filter function so can be used as *part* of a predicate but not as the entire predicate
- RecordPath.compile("/name[substring(., 1, 2) = 'e']");
+ final FieldValue fieldValue = evaluateSingleFieldValue(recordPath, record);
+ assertEquals(Optional.empty(), fieldValue.getParent());
+ assertEquals(record, fieldValue.getValue());
}
@Test
- public void testChildField() {
- final Map 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 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());
+ void supportsReferenceToDirectChildField() {
+ final RecordPath recordPath = assertDoesNotThrow(() -> RecordPath.compile("/name"));
- 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());
+ final FieldValue fieldValue = evaluateSingleFieldValue(recordPath, record);
+ assertFieldValue(record, "name", "John Doe", fieldValue);
}
@Test
- public void testRootRecord() {
- final RecordSchema schema = new SimpleRecordSchema(getDefaultFields());
- final Map 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());
+ void supportsReferenceToNestedChildField() {
+ final RecordPath recordPath = assertDoesNotThrow(() -> RecordPath.compile("/mainAccount/balance"));
+
+ final FieldValue fieldValue = evaluateSingleFieldValue(recordPath, record);
+ assertFieldValue(mainAccountRecord, "balance", 123.45, fieldValue);
}
@Test
- public void testWildcardChild() {
- final Map 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 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 fieldValues = RecordPath.compile("/mainAccount/*").evaluate(record).getSelectedFields().collect(Collectors.toList());
- assertEquals(2, fieldValues.size());
-
- for (final FieldValue fieldValue : fieldValues) {
- assertEquals(accountRecord, fieldValue.getParentRecord().get());
- }
+ void supportsReferenceToSelf() {
+ final RecordPath recordPath = assertDoesNotThrow(() -> RecordPath.compile("/name/."));
- assertEquals("id", fieldValues.get(0).getField().getFieldName());
- assertEquals(1, fieldValues.get(0).getValue());
+ final FieldValue fieldValue = evaluateSingleFieldValue(recordPath, record);
+ assertFieldValue(record, "name", "John Doe", fieldValue);
+ }
- assertEquals("balance", fieldValues.get(1).getField().getFieldName());
- assertEquals(123.45D, fieldValues.get(1).getValue());
+ @Test
+ void supportsReferenceToParentField() {
+ final RecordPath recordPath = assertDoesNotThrow(() -> RecordPath.compile("/mainAccount/balance/.."));
- RecordPath.compile("/mainAccount/*[. > 100]").evaluate(record).getSelectedFields().forEach(field -> field.updateValue(122.44D));
- assertEquals(1, accountValues.get("id"));
- assertEquals(122.44D, accountValues.get("balance"));
+ final FieldValue fieldValue = evaluateSingleFieldValue(recordPath, record);
+ assertFieldValue(record, "mainAccount", record.getValue("mainAccount"), fieldValue);
}
@Test
- public void testWildcardWithArray() {
- final Map 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 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 fieldValues = RecordPath.compile("/*[0]").evaluate(record).getSelectedFields().collect(Collectors.toList());
- assertEquals(1, fieldValues.size());
-
- final FieldValue fieldValue = fieldValues.get(0);
- assertEquals("accounts", fieldValue.getField().getFieldName());
- assertEquals(record, fieldValue.getParentRecord().get());
- assertEquals(accountRecord, fieldValue.getValue());
-
- final Map updatedAccountValues = new HashMap<>(accountValues);
- updatedAccountValues.put("balance", 122.44D);
- final Record updatedAccountRecord = new MapRecord(getAccountSchema(), updatedAccountValues);
- RecordPath.compile("/*[0]").evaluate(record).getSelectedFields().forEach(field -> field.updateValue(updatedAccountRecord));
-
- final Object[] accountRecords = (Object[]) record.getValue("accounts");
- assertEquals(1, accountRecords.length);
- final Record recordToVerify = (Record) accountRecords[0];
- assertEquals(122.44D, recordToVerify.getValue("balance"));
- assertEquals(48, record.getValue("id"));
- assertEquals("John Doe", record.getValue("name"));
+ void supportsReferenceWithRelativePath() {
+ final RecordPath recordPath = assertDoesNotThrow(() -> RecordPath.compile("/mainAccount/././balance"));
+
+ final FieldValue fieldValue = evaluateSingleFieldValue(recordPath, record);
+ assertFieldValue(mainAccountRecord, "balance", 123.45, fieldValue);
}
@Test
- public void testDescendantField() {
- final Map 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 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 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());
+ void supportsReferenceStartingWithRelativePath() {
+ final RecordPath recordPath = assertDoesNotThrow(() -> RecordPath.compile("./../mainAccount"));
+
+ final FieldValue relativeParentPathContext = new StandardFieldValue(
+ record, recordFieldOf("root", recordTypeOf(record.getSchema())), null
+ );
+ final FieldValue relativePathContext = new StandardFieldValue(
+ "John Doe", recordFieldOf("name", RecordFieldType.STRING), relativeParentPathContext
+ );
+ // relative paths work on the context instead of base record; to showcase this we pass an empty record
+ final Record emptyRecord = new MapRecord(recordSchemaOf(), Collections.emptyMap());
+ final FieldValue fieldValue = evaluateSingleFieldValue(recordPath, emptyRecord, relativePathContext);
+ assertFieldValue(record, "mainAccount", record.getValue("mainAccount"), fieldValue);
}
@Test
- public void testDescendantFieldWithArrayOfRecords() throws IOException, MalformedRecordException {
- final String recordJson = """
- {
- "container" : {
- "id" : "0",
- "metadata" : {
- "filename" : "file1.pdf",
- "page.count" : "165"
- },
- "textElement" : null,
- "containers" : [ {
- "id" : "1",
- "title" : null,
- "metadata" : {
- "end.page" : 1,
- "start.page" : 1
- },
- "textElement" : {
- "text" : "Table of Contents",
- "metadata" : { }
- },
- "containers" : [ ]
- } ]
- }
- }
- """;
-
- final JsonSchemaInference schemaInference = new JsonSchemaInference(new TimeValueInference("MM/dd/yyyy", "HH:mm:ss", "MM/dd/yyyy HH:mm:ss"));
- final JsonRecordSource jsonRecordSource = new JsonRecordSource(new ByteArrayInputStream(recordJson.getBytes(StandardCharsets.UTF_8)));
- final RecordSchema schema = schemaInference.inferSchema(jsonRecordSource);
-
- final JsonTreeRowRecordReader reader = new JsonTreeRowRecordReader(new ByteArrayInputStream(recordJson.getBytes(StandardCharsets.UTF_8)), Mockito.mock(ComponentLog.class),
- schema, "MM/dd/yyyy", "HH:mm:ss", "MM/dd/yyyy HH:mm:ss");
- final Record record = reader.nextRecord();
-
- final List fieldValues = RecordPath.compile("//textElement[./text = 'Table of Contents']/metadata/insertion").evaluate(record).getSelectedFields().toList();
- assertEquals(1, fieldValues.size());
- fieldValues.getFirst().updateValue("Hello");
- record.incorporateInactiveFields();
-
- final Record container = (Record) record.getValue("container");
- final Object[] containers = (Object[]) container.getValue("containers");
- final Record textElement = (Record) (((Record) containers[0]).getValue("textElement"));
- final Record metadata = (Record) textElement.getValue("metadata");
- assertEquals("Hello", metadata.getValue("insertion"));
-
- final List metadataFields = metadata.getSchema().getFields();
- assertEquals(1, metadataFields.size());
- assertEquals("insertion", metadataFields.getFirst().getFieldName());
- }
+ public void supportsReferenceToEscapedFieldName() {
+ final RecordSchema schema = recordSchemaOf(
+ recordFieldOf("full,name", RecordFieldType.STRING)
+ );
+ final Record record = new MapRecord(schema, Map.of("full,name", "John Doe"));
- private Record createAccountRecord(final int id, final double balance) {
- final Map accountValues = new HashMap<>();
- accountValues.put("id", id);
- accountValues.put("balance", balance);
- return new MapRecord(getAccountSchema(), accountValues);
+ final FieldValue fieldValue = evaluateSingleFieldValue("/'full,name'", record);
+ assertFieldValue(record, "full,name", "John Doe", fieldValue);
}
@Test
- public void testParent() {
- final Record accountRecord = createAccountRecord(1, 123.45D);
+ void supportsWildcardReference() {
+ final RecordPath recordPath = assertDoesNotThrow(() -> RecordPath.compile("/mainAccount/*"));
- final RecordSchema schema = new SimpleRecordSchema(getDefaultFields());
- final Map 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 fieldValues = evaluateMultiFieldValue(recordPath, record);
+ final Record targetParent = mainAccountRecord;
+ assertAll(
+ () -> assertEquals(3, fieldValues.size()),
+ () -> assertFieldValue(targetParent, "id", 1, fieldValues.getFirst()),
+ () -> assertFieldValue(targetParent, "balance", 123.45, fieldValues.get(1)),
+ () -> assertFieldValue(targetParent, "address", getAddressRecord(targetParent), fieldValues.get(2))
+ );
+ }
- final List fieldValues = RecordPath.compile("//id/..").evaluate(record).getSelectedFields().collect(Collectors.toList());
- assertEquals(2, fieldValues.size());
+ @Test
+ void supportsReferenceToDescendant() {
+ final RecordPath recordPath = assertDoesNotThrow(() -> RecordPath.compile("//id"));
- final FieldValue first = fieldValues.get(0);
- final FieldValue second = fieldValues.get(1);
+ final Record record = reduceRecord(this.record, "id", "mainAccount", "accounts");
+ final Record mainAccountRecord = TestRecordPath.this.mainAccountRecord;
+ final Record[] accountRecords = (Record[]) record.getAsArray("accounts");
+ final List fieldValues = evaluateMultiFieldValue(recordPath, record);
+ assertAll(
+ () -> assertEquals(4, fieldValues.size()),
+ () -> assertFieldValue(record, "id", 48, fieldValues.getFirst()),
+ () -> assertFieldValue(mainAccountRecord, "id", 1, fieldValues.get(1)),
+ () -> assertFieldValue(accountRecords[0], "id", 6, fieldValues.get(2)),
+ () -> assertFieldValue(accountRecords[1], "id", 9, fieldValues.get(3))
+ );
+ }
- assertEquals(RecordFieldType.RECORD, first.getField().getDataType().getFieldType());
- assertEquals(RecordFieldType.RECORD, second.getField().getDataType().getFieldType());
+ @Test
+ void supportsReferenceToChildFieldOfDescendant() {
+ final RecordPath recordPath = assertDoesNotThrow(() -> RecordPath.compile("//address/city"));
- assertEquals(record, first.getValue());
- assertEquals(accountRecord, second.getValue());
+ final Record record = reduceRecord(this.record, "id", "mainAccount", "accounts");
+ final List fieldValues = evaluateMultiFieldValue(recordPath, record);
+ final Record mainAccountRecord = TestRecordPath.this.mainAccountRecord;
+ final Record[] accountRecords = (Record[]) record.getAsArray("accounts");
+ assertAll(
+ () -> assertEquals(3, fieldValues.size()),
+ () -> assertFieldValue(getAddressRecord(mainAccountRecord), "city", "Boston", fieldValues.getFirst()),
+ () -> assertFieldValue(getAddressRecord(accountRecords[0]), "city", "Las Vegas", fieldValues.get(1)),
+ () -> assertFieldValue(getAddressRecord(accountRecords[1]), "city", "Austin", fieldValues.get(2))
+ );
}
@Test
- public void testMapKey() {
- final RecordSchema schema = new SimpleRecordSchema(getDefaultFields());
-
- final Map attributes = new HashMap<>();
- attributes.put("city", "New York");
- attributes.put("state", "NY");
-
- final Map 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();
- assertEquals("attributes", fieldValue.getField().getFieldName());
- assertEquals("New York", fieldValue.getValue());
- assertEquals(record, fieldValue.getParentRecord().get());
+ void supportsReferenceToDescendantWithWildcard() {
+ final RecordPath recordPath = assertDoesNotThrow(() -> RecordPath.compile("/mainAccount//*"));
+
+ final List fieldValues = evaluateMultiFieldValue(recordPath, record);
+ final Record mainAccountRecord = TestRecordPath.this.mainAccountRecord;
+ final Record addressRecord = getAddressRecord(mainAccountRecord);
+ assertAll(
+ () -> assertEquals(5, fieldValues.size()),
+ () -> assertFieldValue(mainAccountRecord, "id", 1, fieldValues.getFirst()),
+ () -> assertFieldValue(mainAccountRecord, "balance", 123.45, fieldValues.get(1)),
+ () -> assertFieldValue(mainAccountRecord, "address", addressRecord, fieldValues.get(2)),
+ () -> assertFieldValue(addressRecord, "city", "Boston", fieldValues.get(3)),
+ () -> assertFieldValue(addressRecord, "state", "Massachusetts", fieldValues.get(4))
+ );
}
@Test
- public void testMapKeyReferencedWithCurrentField() {
- final RecordSchema schema = new SimpleRecordSchema(getDefaultFields());
-
- final Map attributes = new HashMap<>();
- attributes.put("city", "New York");
- attributes.put("state", "NY");
-
- final Map 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();
- assertEquals("attributes", fieldValue.getField().getFieldName());
- assertEquals("New York", fieldValue.getValue());
- assertEquals(record, fieldValue.getParentRecord().get());
+ void supportsReferenceToDescendantFieldsInRecordInsideArray() {
+ final RecordPath recordPath = assertDoesNotThrow(() -> RecordPath.compile("//city"));
+
+ final RecordSchema schema = recordSchemaOf(
+ recordFieldOf("array", arrayTypeOf(RecordFieldType.RECORD))
+ );
+ final Record addressRecord = createAddressRecord("Paris", "France");
+ final Record accountRecord = createAccountRecord();
+ final Record record = new MapRecord(schema, new HashMap<>(Map.of(
+ "array", new Record[]{accountRecord, addressRecord}
+ )));
+ final List fieldValues = evaluateMultiFieldValue(recordPath, record);
+ assertAll(
+ () -> assertEquals(2, fieldValues.size()),
+ () -> assertFieldValue(getAddressRecord(accountRecord), "city", "Boston", fieldValues.getFirst()),
+ () -> assertFieldValue(addressRecord, "city", "Paris", fieldValues.get(1))
+ );
}
@Test
- @SuppressWarnings("unchecked")
- public void testUpdateMap() {
- final RecordSchema schema = new SimpleRecordSchema(getDefaultFields());
-
- final Map attributes = new HashMap<>();
- attributes.put("city", "New York");
- attributes.put("state", "NY");
-
- final Map values = new HashMap<>();
- values.put("id", 48);
- values.put("name", "John Doe");
- values.put("attributes", attributes);
- final Record record = new MapRecord(schema, values);
-
- RecordPath.compile("/attributes['city']").evaluate(record).getSelectedFields().findFirst().get().updateValue("Boston");
- assertEquals("Boston", ((Map) record.getValue("attributes")).get("city"));
+ public void supportsToEscapeQuotesInLiterals() {
+ record.setValue("attributes", new HashMap<>(Map.of(
+ "Joe's Lama", "cute",
+ "Angela \"Mutti\" Merkel", "powerful"
+ )));
+
+ assertFieldValue(record, "attributes", "cute", evaluateSingleFieldValue("/attributes['Joe\\'s Lama']", record));
+ assertFieldValue(record, "attributes", "powerful", evaluateSingleFieldValue("/attributes[\"Angela \\\"Mutti\\\" Merkel\"]", record));
}
@Test
- public void testMapWildcard() {
- final RecordSchema schema = new SimpleRecordSchema(getDefaultFields());
+ public void supportsJavaEscapeSequencesInLiterals() {
+ record.setValue("attributes", new HashMap<>(Map.of(
+ " \t\r\n", "whitespace"
+ )));
- final Map attributes = new HashMap<>();
- attributes.put("city", "New York");
- attributes.put("state", "NY");
-
- final Map values = new HashMap<>();
- values.put("id", 48);
- values.put("name", "John Doe");
- values.put("attributes", attributes);
- final Record record = new MapRecord(schema, values);
+ assertFieldValue(record, "attributes", "whitespace", evaluateSingleFieldValue("/attributes[' \\t\\r\\n']", record));
+ }
- final List fieldValues = RecordPath.compile("/attributes[*]").evaluate(record).getSelectedFields().collect(Collectors.toList());
- assertEquals(2, fieldValues.size());
+ @Nested
+ class ArrayReferences {
+ private final String[] friendValues = (String[]) record.getAsArray("friends");
- assertEquals("New York", fieldValues.get(0).getValue());
- assertEquals("NY", fieldValues.get(1).getValue());
+ @Test
+ public void supportReferenceToSingleArrayIndex() {
+ final RecordPath recordPath = assertDoesNotThrow(() -> RecordPath.compile("/friends[0]"));
- for (final FieldValue fieldValue : fieldValues) {
- assertEquals("attributes", fieldValue.getField().getFieldName());
- assertEquals(record, fieldValue.getParentRecord().get());
+ final FieldValue fieldValue = evaluateSingleFieldValue(recordPath, record);
+ assertFieldValue(record, "friends", friendValues[0], fieldValue);
}
- RecordPath.compile("/attributes[*]").evaluate(record).getSelectedFields().forEach(field -> field.updateValue("Unknown"));
- assertEquals("Unknown", attributes.get("city"));
- assertEquals("Unknown", attributes.get("state"));
+ @Test
+ public void supportReferenceToMultipleArrayIndices() {
+ final RecordPath recordPath = assertDoesNotThrow(() -> RecordPath.compile("/friends[1, 3]"));
- RecordPath.compile("/attributes[*][fieldName(.) = 'attributes']").evaluate(record).getSelectedFields().forEach(field -> field.updateValue("Unknown"));
- assertEquals("Unknown", attributes.get("city"));
- assertEquals("Unknown", attributes.get("state"));
-
- }
+ String[] expectedValues = new String[]{friendValues[1], friendValues[3]};
+ final List fieldValues = evaluateMultiFieldValue(recordPath, record);
+ assertSingleFieldMultipleValueResult(record, "friends", expectedValues, fieldValues);
+ }
- @Test
- public void testMapMultiKey() {
- final RecordSchema schema = new SimpleRecordSchema(getDefaultFields());
+ @Test
+ public void supportReferenceToNegativeArrayIndex() {
+ final RecordPath recordPath = assertDoesNotThrow(() -> RecordPath.compile("/friends[-2]"));
- final Map attributes = new HashMap<>();
- attributes.put("city", "New York");
- attributes.put("state", "NY");
+ final FieldValue fieldValue = evaluateSingleFieldValue(recordPath, record);
+ assertFieldValue(record, "friends", friendValues[friendValues.length - 2], fieldValue);
+ }
- final Map values = new HashMap<>();
- values.put("id", 48);
- values.put("name", "John Doe");
- values.put("attributes", attributes);
- final Record record = new MapRecord(schema, values);
+ @Test
+ public void supportReferenceToRangeOfArrayIndices() {
+ final RecordPath recordPath = assertDoesNotThrow(() -> RecordPath.compile("/friends[1..2]"));
- final List fieldValues = RecordPath.compile("/attributes['city', 'state']").evaluate(record).getSelectedFields().collect(Collectors.toList());
- assertEquals(2, fieldValues.size());
+ String[] expectedValues = new String[]{friendValues[1], friendValues[2]};
+ final List fieldValues = evaluateMultiFieldValue(recordPath, record);
+ assertSingleFieldMultipleValueResult(record, "friends", expectedValues, fieldValues);
+ }
- assertEquals("New York", fieldValues.get(0).getValue());
- assertEquals("NY", fieldValues.get(1).getValue());
+ @Test
+ public void supportReferenceWithWildcardAsArrayIndex() {
+ final RecordPath recordPath = assertDoesNotThrow(() -> RecordPath.compile("/friends[*]"));
- for (final FieldValue fieldValue : fieldValues) {
- assertEquals("attributes", fieldValue.getField().getFieldName());
- assertEquals(record, fieldValue.getParentRecord().get());
+ final List fieldValues = evaluateMultiFieldValue(recordPath, record);
+ assertSingleFieldMultipleValueResult(record, "friends", friendValues, fieldValues);
}
- RecordPath.compile("/attributes['city', 'state']").evaluate(record).getSelectedFields().forEach(field -> field.updateValue("Unknown"));
- assertEquals("Unknown", attributes.get("city"));
- assertEquals("Unknown", attributes.get("state"));
- }
+ @Test
+ public void canReferenceSameArrayItemMultipleTimes() {
+ final RecordPath recordPath = assertDoesNotThrow(() -> RecordPath.compile("/friends[1, 1..1, -3]"));
- @Test
- public void testEscapedFieldName() {
- final List 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 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());
- }
+ String[] expectedValues = new String[]{friendValues[1], friendValues[1], friendValues[1]};
+ final List fieldValues = evaluateMultiFieldValue(recordPath, record);
+ assertSingleFieldMultipleValueResult(record, "friends", expectedValues, fieldValues);
+ }
- @Test
- public void testSingleArrayIndex() {
- final RecordSchema schema = new SimpleRecordSchema(getDefaultFields());
-
- final Map 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();
- assertEquals("numbers", fieldValue.getField().getFieldName());
- assertEquals(3, fieldValue.getValue());
- assertEquals(record, fieldValue.getParentRecord().get());
- }
+ @Test
+ public void supportReferenceWithCombinationOfArrayAccesses() {
+ final RecordPath recordPath = assertDoesNotThrow(() -> RecordPath.compile("/friends[1..2, 0, -1]"));
- @Test
- public void testSingleArrayRange() {
- final RecordSchema schema = new SimpleRecordSchema(getDefaultFields());
+ String[] expectedValues = new String[]{
+ friendValues[1], friendValues[2], friendValues[0], friendValues[friendValues.length - 1]
+ };
+ final List fieldValues = evaluateMultiFieldValue(recordPath, record);
+ assertSingleFieldMultipleValueResult(record, "friends", expectedValues, fieldValues);
+ }
- final Map 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);
+ @Test
+ public void canReferenceArrayItemsUsingRelativePath() {
+ final RecordPath recordPath = assertDoesNotThrow(() -> RecordPath.compile("/friends/.[3]"));
- final List fieldValues = RecordPath.compile("/numbers[0..1]").evaluate(record).getSelectedFields().collect(Collectors.toList());
- for (final FieldValue fieldValue : fieldValues) {
- assertEquals("numbers", fieldValue.getField().getFieldName());
- assertEquals(record, fieldValue.getParentRecord().get());
+ final FieldValue fieldValue = evaluateSingleFieldValue(recordPath, record);
+ assertFieldValue(record, "friends", friendValues[3], fieldValue);
}
- assertEquals(2, fieldValues.size());
- for (int i = 0; i < 1; i++) {
- assertEquals(i, fieldValues.get(0).getValue());
+ @Test
+ public void predicateCanBeAppliedOnSingleArrayItem() {
+ final RecordPath recordPath = assertDoesNotThrow(() -> RecordPath.compile("/friends[1][. = 'Jane']"));
+
+ final FieldValue fieldValue = evaluateSingleFieldValue(recordPath, record);
+ assertFieldValue(record, "friends", friendValues[1], fieldValue);
}
- }
+ @Test
+ public void predicateCanBeAppliedOnMultipleArrayItems() {
+ final RecordPath recordPath = assertDoesNotThrow(() -> RecordPath.compile("/friends[0, 1, 2][. != 'Jane']"));
- @Test
- public void testMultiArrayIndex() {
- final RecordSchema schema = new SimpleRecordSchema(getDefaultFields());
+ String[] expectedValues = new String[]{friendValues[0], friendValues[2]};
+ final List fieldValues = evaluateMultiFieldValue(recordPath, record);
+ assertSingleFieldMultipleValueResult(record, "friends", expectedValues, fieldValues);
+ }
- final Map 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);
+ @Test
+ public void supportsUpdatingArrayItem() {
+ final RecordPath recordPath = assertDoesNotThrow(() -> RecordPath.compile("/friends[0]"));
- final List 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) {
- assertEquals("numbers", fieldValue.getField().getFieldName());
- assertEquals(expectedValues[i++], fieldValue.getValue());
- assertEquals(record, fieldValue.getParentRecord().get());
+ final FieldValue fieldValue = evaluateSingleFieldValue(recordPath, record);
+ fieldValue.updateValue("Theo");
+
+ final FieldValue updatedFieldValue = evaluateSingleFieldValue(recordPath, record);
+ assertFieldValue(record, "friends", "Theo", updatedFieldValue);
}
- RecordPath.compile("/numbers[3,6, -1, -2]").evaluate(record).getSelectedFields().forEach(field -> field.updateValue(99));
- assertArrayEquals(new Object[] {0, 1, 2, 99, 4, 5, 99, 7, 99, 99}, (Object[]) values.get("numbers"));
- }
+ @Test
+ public void yieldsNoResultWhenArrayRangeCountsDown() {
+ final RecordPath recordPath = assertDoesNotThrow(() -> RecordPath.compile("/friends[3..2]"));
- @Test
- public void testMultiArrayIndexWithRanges() {
- final RecordSchema schema = new SimpleRecordSchema(getDefaultFields());
+ final List fieldValues = evaluateMultiFieldValue(recordPath, record);
+ assertEquals(List.of(), fieldValues);
+ }
- final Map 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);
+ @Test
+ public void yieldsNoResultWhenArrayIndexOutOfBounds() {
+ final RecordPath recordPath = assertDoesNotThrow(() -> RecordPath.compile("/friends[9001]"));
- List fieldValues = RecordPath.compile("/numbers[0, 2, 4..7, 9]").evaluate(record).getSelectedFields().collect(Collectors.toList());
- for (final FieldValue fieldValue : fieldValues) {
- assertEquals("numbers", fieldValue.getField().getFieldName());
- assertEquals(record, fieldValue.getParentRecord().get());
+ final List fieldValues = evaluateMultiFieldValue(recordPath, record);
+ assertEquals(List.of(), fieldValues);
}
+ }
- 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());
- }
+ @Nested
+ class MapReferences {
+ private final Map attributes = Map.of(
+ "key1", "value1",
+ "key2", "value2",
+ "key3", "value3"
+ );
- fieldValues = RecordPath.compile("/numbers[0..-1]").evaluate(record).getSelectedFields().collect(Collectors.toList());
- for (final FieldValue fieldValue : fieldValues) {
- assertEquals("numbers", fieldValue.getField().getFieldName());
- 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());
+ @BeforeEach
+ public void setUp() {
+ record.setValue("attributes", new LinkedHashMap<>(attributes));
}
+ @Test
+ public void supportReferenceToSingleMapKey() {
+ final RecordPath recordPath = assertDoesNotThrow(() -> RecordPath.compile("/attributes['key1']"));
- fieldValues = RecordPath.compile("/numbers[-1..-1]").evaluate(record).getSelectedFields().collect(Collectors.toList());
- for (final FieldValue fieldValue : fieldValues) {
- assertEquals("numbers", fieldValue.getField().getFieldName());
- 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());
- }
+ final FieldValue fieldValue = evaluateSingleFieldValue(recordPath, record);
+ assertFieldValue(record, "attributes", attributes.get("key1"), fieldValue);
- fieldValues = RecordPath.compile("/numbers[*]").evaluate(record).getSelectedFields().collect(Collectors.toList());
- for (final FieldValue fieldValue : fieldValues) {
- assertEquals("numbers", fieldValue.getField().getFieldName());
- assertEquals(record, fieldValue.getParentRecord().get());
+ fieldValue.updateValue("updatedKey");
+ final FieldValue updatedFieldValue = evaluateSingleFieldValue(recordPath, record);
+ assertFieldValue(record, "attributes", "updatedKey", updatedFieldValue);
}
- 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 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 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 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();
- assertEquals("numbers", fieldName);
- 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 supportReferenceToMultipleMapKeys() {
+ final RecordPath recordPath = assertDoesNotThrow(() -> RecordPath.compile("/attributes['key1', 'key3']"));
- @Test
- public void testRelativePath() {
- final Map 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 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 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());
-
- RecordPath.compile("/mainAccount/././balance/.").evaluate(record).getSelectedFields().forEach(field -> field.updateValue(123.44D));
- assertEquals(123.44D, accountValues.get("balance"));
- }
+ String[] expectedValues = new String[]{attributes.get("key1"), attributes.get("key3")};
+ final List fieldValues = evaluateMultiFieldValue(recordPath, record);
+ assertSingleFieldMultipleValueResult(record, "attributes", expectedValues, fieldValues);
+ }
- @Test
- public void testCompareToLiteral() {
- final RecordSchema schema = new SimpleRecordSchema(getDefaultFields());
- final Map 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 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 supportReferenceWithWildcardAsMapKey() {
+ final RecordPath recordPath = assertDoesNotThrow(() -> RecordPath.compile("/attributes[*]"));
- @Test
- public void testCompareToAbsolute() {
- final RecordSchema schema = new SimpleRecordSchema(getDefaultFields());
- final Map 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 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());
- }
+ final List fieldValues = evaluateMultiFieldValue(recordPath, record);
+ assertSingleFieldMultipleValueResult(record, "attributes", attributes.values().toArray(), fieldValues);
+ }
- @Test
- public void testCompareWithEmbeddedPaths() {
- final Map accountValues1 = new HashMap<>();
- accountValues1.put("id", 1);
- accountValues1.put("balance", 10_000.00D);
- final Record accountRecord1 = new MapRecord(getAccountSchema(), accountValues1);
-
- final Map 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 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 fieldValues = recordPath.evaluate(record).getSelectedFields().collect(Collectors.toList());
- assertEquals(1, fieldValues.size());
-
- final FieldValue fieldValue = fieldValues.get(0);
- assertEquals("accounts", fieldValue.getField().getFieldName());
- assertEquals(0, ((ArrayIndexFieldValue) fieldValue).getArrayIndex());
- assertEquals(record, fieldValue.getParentRecord().get());
- assertEquals(accountRecord1, fieldValue.getValue());
- }
+ @Test
+ public void canReferenceSameMapItemMultipleTimes() {
+ final RecordPath recordPath = assertDoesNotThrow(() -> RecordPath.compile("/attributes['key1', 'key3', 'key1']"));
- @Test
- public void testPredicateInMiddleOfPath() {
- final Map accountValues1 = new HashMap<>();
- accountValues1.put("id", 1);
- accountValues1.put("balance", 10_000.00D);
- final Record accountRecord1 = new MapRecord(getAccountSchema(), accountValues1);
-
- final Map 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 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 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());
- }
+ String[] expectedValues = new String[]{
+ attributes.get("key1"), attributes.get("key3"), attributes.get("key1")
+ };
+ final List fieldValues = evaluateMultiFieldValue(recordPath, record);
+ assertSingleFieldMultipleValueResult(record, "attributes", expectedValues, fieldValues);
+ }
- @Test
- public void testUpdateValueOnMatchingFields() {
- final Map accountValues1 = new HashMap<>();
- accountValues1.put("id", 1);
- accountValues1.put("balance", 10_000.00D);
- final Record accountRecord1 = new MapRecord(getAccountSchema(), accountValues1);
-
- final Map 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 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 canReferenceMapItemsUsingRelativePath() {
+ final RecordPath recordPath = assertDoesNotThrow(() -> RecordPath.compile("/attributes/.['key3']"));
- @Test
- public void testPredicateDoesNotIncludeFieldsThatDontHaveRelativePath() {
- final List 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 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 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 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());
- }
+ final FieldValue fieldValue = evaluateSingleFieldValue(recordPath, record);
+ assertFieldValue(record, "attributes", attributes.get("key3"), fieldValue);
+ }
- @Test
- public void testPredicateWithAbsolutePath() {
- final List 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 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 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 fieldValues = result.getSelectedFields().collect(Collectors.toList());
- assertEquals(1, fieldValues.size());
-
- final FieldValue fieldValue = fieldValues.get(0);
- assertEquals("address2", fieldValue.getField().getFieldName());
- }
+ @Test
+ public void predicateCanBeAppliedOnSingleMapItem() {
+ final RecordPath recordPath = assertDoesNotThrow(() -> RecordPath.compile("/attributes['key2'][. = 'value2']"));
- @Test
- public void testRelativePathOnly() {
- final RecordSchema schema = new SimpleRecordSchema(getDefaultFields());
- final Map 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 fieldValues = RecordPath.compile("./name").evaluate(record, 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());
- }
+ final FieldValue fieldValue = evaluateSingleFieldValue(recordPath, record);
+ assertFieldValue(record, "attributes", attributes.get("key2"), fieldValue);
+ }
- @Test
- public void testRelativePathAgainstNonRecordField() {
- final RecordSchema schema = new SimpleRecordSchema(getDefaultFields());
- final Map 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 fieldValues = RecordPath.compile(".").evaluate(record, 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"));
- }
+ @Test
+ public void predicateCanBeAppliedOnMultipleMapItems() {
+ final RecordPath recordPath = assertDoesNotThrow(() -> RecordPath.compile("/attributes['key1', 'key2', 'key3'][. != 'value2']"));
- @Test
- public void testSubstringFunction() {
- final List fields = new ArrayList<>();
- fields.add(new RecordField("id", RecordFieldType.INT.getDataType()));
- fields.add(new RecordField("name", RecordFieldType.STRING.getDataType()));
-
- final RecordSchema schema = new SimpleRecordSchema(fields);
-
- final Map values = new HashMap<>();
- values.put("id", 48);
- values.put("name", "John Doe");
- final Record record = new MapRecord(schema, values);
-
- final FieldValue fieldValue = RecordPath.compile("substring(/name, 0, 4)").evaluate(record).getSelectedFields().findFirst().get();
- assertEquals("John", fieldValue.getValue());
-
- assertEquals("John", RecordPath.compile("substring(/name, 0, -5)").evaluate(record).getSelectedFields().findFirst().get().getValue());
- assertEquals("", RecordPath.compile("substring(/name, 1000, 1005)").evaluate(record).getSelectedFields().findFirst().get().getValue());
- assertEquals("", RecordPath.compile("substring(/name, 4, 3)").evaluate(record).getSelectedFields().findFirst().get().getValue());
- assertEquals("John Doe", RecordPath.compile("substring(/name, 0, 10000)").evaluate(record).getSelectedFields().findFirst().get().getValue());
- assertEquals("", RecordPath.compile("substring(/name, -50, -1)").evaluate(record).getSelectedFields().findFirst().get().getValue());
- }
+ String[] expectedValues = new String[]{
+ attributes.get("key1"), attributes.get("key3")
+ };
+ final List fieldValues = evaluateMultiFieldValue(recordPath, record);
+ assertSingleFieldMultipleValueResult(record, "attributes", expectedValues, fieldValues);
+ }
- @Test
- public void testSubstringBeforeFunction() {
- final List fields = new ArrayList<>();
- fields.add(new RecordField("id", RecordFieldType.INT.getDataType()));
- fields.add(new RecordField("name", RecordFieldType.STRING.getDataType()));
+ @Test
+ public void supportsUpdatingMapItem() {
+ final RecordPath recordPath = assertDoesNotThrow(() -> RecordPath.compile("/attributes['key1']"));
- final RecordSchema schema = new SimpleRecordSchema(fields);
+ final FieldValue fieldValue = evaluateSingleFieldValue(recordPath, record);
+ fieldValue.updateValue("updatedKey");
- final Map values = new HashMap<>();
- values.put("id", 48);
- values.put("name", "John Doe");
- final Record record = new MapRecord(schema, values);
+ final FieldValue updatedFieldValue = evaluateSingleFieldValue(recordPath, record);
+ assertFieldValue(record, "attributes", "updatedKey", updatedFieldValue);
+ }
- assertEquals("John", RecordPath.compile("substringBefore(/name, ' ')").evaluate(record).getSelectedFields().findFirst().get().getValue());
- assertEquals("John Doe", RecordPath.compile("substringBefore(/name, 'XYZ')").evaluate(record).getSelectedFields().findFirst().get().getValue());
- assertEquals("John Doe", RecordPath.compile("substringBefore(/name, '')").evaluate(record).getSelectedFields().findFirst().get().getValue());
+ @Test
+ public void yieldsNullWhenMapKeyNotFound() {
+ final RecordPath recordPath = assertDoesNotThrow(() -> RecordPath.compile("/attributes['nope']"));
- assertEquals("John D", RecordPath.compile("substringBeforeLast(/name, 'o')").evaluate(record).getSelectedFields().findFirst().get().getValue());
- assertEquals("John Doe", RecordPath.compile("substringBeforeLast(/name, 'XYZ')").evaluate(record).getSelectedFields().findFirst().get().getValue());
- assertEquals("John Doe", RecordPath.compile("substringBeforeLast(/name, '')").evaluate(record).getSelectedFields().findFirst().get().getValue());
+ final FieldValue fieldValue = evaluateSingleFieldValue(recordPath, record);
+ assertFieldValue(record, "attributes", null, fieldValue);
+ }
}
- @Test
- public void testSubstringAfterFunction() {
- final List fields = new ArrayList<>();
- fields.add(new RecordField("id", RecordFieldType.INT.getDataType()));
- fields.add(new RecordField("name", RecordFieldType.STRING.getDataType()));
-
- final RecordSchema schema = new SimpleRecordSchema(fields);
-
- final Map values = new HashMap<>();
- values.put("id", 48);
- values.put("name", "John Doe");
- final Record record = new MapRecord(schema, values);
-
- assertEquals("hn Doe", RecordPath.compile("substringAfter(/name, 'o')").evaluate(record).getSelectedFields().findFirst().get().getValue());
- assertEquals("John Doe", RecordPath.compile("substringAfter(/name, 'XYZ')").evaluate(record).getSelectedFields().findFirst().get().getValue());
- assertEquals("John Doe", RecordPath.compile("substringAfter(/name, '')").evaluate(record).getSelectedFields().findFirst().get().getValue());
- assertEquals("n Doe", RecordPath.compile("substringAfter(/name, 'oh')").evaluate(record).getSelectedFields().findFirst().get().getValue());
-
- assertEquals("e", RecordPath.compile("substringAfterLast(/name, 'o')").evaluate(record).getSelectedFields().findFirst().get().getValue());
- assertEquals("John Doe", RecordPath.compile("substringAfterLast(/name, 'XYZ')").evaluate(record).getSelectedFields().findFirst().get().getValue());
- assertEquals("John Doe", RecordPath.compile("substringAfterLast(/name, '')").evaluate(record).getSelectedFields().findFirst().get().getValue());
- assertEquals("n Doe", RecordPath.compile("substringAfterLast(/name, 'oh')").evaluate(record).getSelectedFields().findFirst().get().getValue());
- }
+ @Nested
+ class FieldTypes {
+ @Test
+ public void supportsReferenceToFieldOfTypeBigInt() {
+ supportsRecordFieldType(
+ RecordFieldType.BIGINT,
+ List.of(
+ BigInteger.valueOf(5623351),
+ BigInteger.ZERO,
+ BigInteger.valueOf(Long.MIN_VALUE).subtract(BigInteger.ONE),
+ BigInteger.valueOf(Long.MAX_VALUE).add(BigInteger.ONE)
+
+ ),
+ List.of(
+ (short) 1, // SHORT
+ (byte) 2, // BYTE
+ 43, // INT
+ 47L // LONG
+ )
+ );
+ }
- @Test
- public void testContains() {
- final Record record = createSimpleRecord();
- assertEquals("John Doe", RecordPath.compile("/name[contains(., 'o')]").evaluate(record).getSelectedFields().findFirst().get().getValue());
- assertEquals(0L, RecordPath.compile("/name[contains(., 'x')]").evaluate(record).getSelectedFields().count());
+ @Test
+ public void supportsReferenceToFieldOfTypeBoolean() {
+ supportsRecordFieldType(
+ RecordFieldType.BOOLEAN,
+ List.of(
+ false,
+ true
+ )
+ );
+ }
- record.setValue("name", "John Doe 48");
- assertEquals("John Doe 48", RecordPath.compile("/name[contains(., /id)]").evaluate(record).getSelectedFields().findFirst().get().getValue());
- }
+ @Test
+ public void supportsReferenceToFieldOfTypeByte() {
+ supportsRecordFieldType(
+ RecordFieldType.BYTE,
+ List.of(
+ (byte) 0,
+ (byte) 1,
+ Byte.MIN_VALUE,
+ Byte.MAX_VALUE
+ )
+ );
+ }
- @Test
- public void testStartsWith() {
- final Record record = createSimpleRecord();
- assertEquals("John Doe", RecordPath.compile("/name[startsWith(., 'J')]").evaluate(record).getSelectedFields().findFirst().get().getValue());
- assertEquals(0L, RecordPath.compile("/name[startsWith(., 'x')]").evaluate(record).getSelectedFields().count());
- assertEquals("John Doe", RecordPath.compile("/name[startsWith(., '')]").evaluate(record).getSelectedFields().findFirst().get().getValue());
- }
+ @Test
+ public void supportsReferenceToFieldOfTypeChar() {
+ supportsRecordFieldType(
+ RecordFieldType.CHAR,
+ List.of(
+ '0',
+ 'a',
+ ' ',
+ Character.MIN_VALUE,
+ Character.MAX_VALUE
+ )
+ );
+ }
- @Test
- public void testEndsWith() {
- final Record record = createSimpleRecord();
- assertEquals("John Doe", RecordPath.compile("/name[endsWith(., 'e')]").evaluate(record).getSelectedFields().findFirst().get().getValue());
- assertEquals(0L, RecordPath.compile("/name[endsWith(., 'x')]").evaluate(record).getSelectedFields().count());
- assertEquals("John Doe", RecordPath.compile("/name[endsWith(., '')]").evaluate(record).getSelectedFields().findFirst().get().getValue());
- }
+ @Test
+ public void supportsReferenceToFieldOfTypeDate() {
+ supportsRecordFieldType(
+ RecordFieldType.DATE,
+ List.of(
+ Date.valueOf("2024-08-18")
+ ),
+ List.of(
+ Timestamp.valueOf("2024-08-18 09:45:27") // TIMESTAMP
+ )
+ );
+ }
- @Test
- public void testIsEmpty() {
- final Record record = createSimpleRecord();
- assertEquals("John Doe", RecordPath.compile("/name[isEmpty(../missing)]").evaluate(record).getSelectedFields().findFirst().get().getValue());
- assertEquals("John Doe", RecordPath.compile("/name[isEmpty(/missing)]").evaluate(record).getSelectedFields().findFirst().get().getValue());
- assertEquals(0L, RecordPath.compile("/name[isEmpty(../id)]").evaluate(record).getSelectedFields().count());
-
- record.setValue("missing", " ");
- assertEquals(0L, RecordPath.compile("/name[isEmpty(/missing)]").evaluate(record).getSelectedFields().count());
- }
+ @Test
+ public void supportsReferenceToFieldOfTypeDecimal() {
+ supportsRecordFieldType(
+ RecordFieldType.DECIMAL,
+ List.of(
+ BigDecimal.valueOf(1.234567890123456789),
+ BigDecimal.valueOf(0)
+ ),
+ List.of(
+ 2.4f, // FLOAT
+ 6.8d // DOUBLE
+ )
+ );
+ }
+ @Test
+ public void supportsReferenceToFieldOfTypeDouble() {
+ supportsRecordFieldType(
+ RecordFieldType.DOUBLE,
+ List.of(
+ 0d,
+ 1d,
+ 1.1d,
+ -1.1d,
+ Double.MIN_VALUE,
+ Double.MAX_VALUE,
+ Double.NaN
+ ),
+ List.of(
+ 2.4f // FLOAT
+ )
+ );
+ }
- @Test
- public void testIsBlank() {
- final Record record = createSimpleRecord();
- assertEquals("John Doe", RecordPath.compile("/name[isBlank(../missing)]").evaluate(record).getSelectedFields().findFirst().get().getValue());
-
- record.setValue("missing", " ");
- assertEquals("John Doe", RecordPath.compile("/name[isBlank(../missing)]").evaluate(record).getSelectedFields().findFirst().get().getValue());
- assertEquals("John Doe", RecordPath.compile("/name[isBlank(/missing)]").evaluate(record).getSelectedFields().findFirst().get().getValue());
- assertEquals(0L, RecordPath.compile("/name[isBlank(../id)]").evaluate(record).getSelectedFields().count());
- }
+ @Test
+ public void supportsReferenceToFieldOfTypeFloat() {
+ supportsRecordFieldType(
+ RecordFieldType.FLOAT,
+ List.of(
+ 0f,
+ 1f,
+ 1.1f,
+ -1.1f,
+ Float.MIN_VALUE,
+ Float.MAX_VALUE,
+ Float.NaN
+ )
+ );
+ }
- @Test
- public void testContainsRegex() {
- final List fields = new ArrayList<>();
- fields.add(new RecordField("id", RecordFieldType.INT.getDataType()));
- fields.add(new RecordField("name", RecordFieldType.STRING.getDataType()));
+ @Test
+ public void supportsReferenceToFieldOfTypeInt() {
+ supportsRecordFieldType(
+ RecordFieldType.INT,
+ List.of(
+ 0,
+ 1,
+ -1,
+ Integer.MIN_VALUE,
+ Integer.MAX_VALUE
+ ),
+ List.of(
+ (short) 2, // SHORT
+ (byte) 43 // BYTE
+ )
+ );
+ }
- final RecordSchema schema = new SimpleRecordSchema(fields);
+ @Test
+ public void supportsReferenceToFieldOfTypeLong() {
+ supportsRecordFieldType(
+ RecordFieldType.LONG,
+ List.of(
+ 1234567890L,
+ 0L,
+ ((long) Integer.MAX_VALUE) + 1L,
+ ((long) Integer.MIN_VALUE) - 1L,
+ Long.MIN_VALUE,
+ Long.MAX_VALUE
+
+ ),
+ List.of(
+ (short) 1, // SHORT
+ (byte) 2, // BYTE
+ 43 // INT
+ )
+ );
+ }
- final Map values = new HashMap<>();
- values.put("id", 48);
- values.put("name", "John Doe");
- final Record record = new MapRecord(schema, values);
+ @Test
+ public void supportsReferenceToFieldOfTypeShort() {
+ supportsRecordFieldType(
+ RecordFieldType.SHORT,
+ List.of(
+ (short) 2412,
+ (short) 0,
+ Short.MIN_VALUE,
+ Short.MAX_VALUE
+
+ ),
+ List.of(
+ (byte) 2 // BYTE
+ )
+ );
+ }
- assertEquals("John Doe", RecordPath.compile("/name[containsRegex(., 'o')]").evaluate(record).getSelectedFields().findFirst().get().getValue());
- assertEquals("John Doe", RecordPath.compile("/name[containsRegex(., '[xo]')]").evaluate(record).getSelectedFields().findFirst().get().getValue());
- assertEquals(0L, RecordPath.compile("/name[containsRegex(., 'x')]").evaluate(record).getSelectedFields().count());
- }
+ @Test
+ public void supportsReferenceToFieldOfTypeEnum() {
+ final List enumValues = List.of("alice", "Bob", "EVE");
- @Test
- public void testNot() {
- final List fields = new ArrayList<>();
- fields.add(new RecordField("id", RecordFieldType.INT.getDataType()));
- fields.add(new RecordField("name", RecordFieldType.STRING.getDataType()));
+ supportsRecordFieldType(
+ RecordFieldType.ENUM.getEnumDataType(enumValues),
+ enumValues
+ );
+ }
- final RecordSchema schema = new SimpleRecordSchema(fields);
+ @Test
+ public void supportsReferenceToFieldOfTypeString() {
+ supportsRecordFieldType(
+ RecordFieldType.STRING,
+ List.of(
+ "Test",
+ "X",
+ "",
+ " \n\r\t"
+ ),
+ List.of(
+ true, // BOOLEAN
+ (byte) 5, // BYTE
+ 'c', // CHAR
+ (short) 123, // SHORT
+ 0, // INT
+ BigInteger.TWO, // BIGINT
+ 44L, // LONG
+ 12.3f, // FLOAT
+ 0.79f, // DOUBLE
+ BigDecimal.valueOf(10.32547698), // DECIMAL
+ Date.valueOf("2024-08-18"), // DATE
+ Time.valueOf("09:45:27"), // TIME
+ Timestamp.valueOf("2024-08-18 09:45:27") // TIMESTAMP
+ // ENUM is represented as a String value and thus does not need to be tested
+ )
+ );
+ }
- final Map values = new HashMap<>();
- values.put("id", 48);
- values.put("name", "John Doe");
- final Record record = new MapRecord(schema, values);
+ @Test
+ public void supportsReferenceToFieldOfTypeTime() {
+ supportsRecordFieldType(
+ RecordFieldType.TIME,
+ List.of(
+ Time.valueOf("09:45:27")
+ ),
+ List.of(
+ Timestamp.valueOf("2024-08-18 09:45:27") // TIMESTAMP
+ )
+ );
+ }
- assertEquals("John Doe", RecordPath.compile("/name[not(contains(., 'x'))]").evaluate(record).getSelectedFields().findFirst().get().getValue());
- assertEquals(0L, RecordPath.compile("/name[not(. = 'John Doe')]").evaluate(record).getSelectedFields().count());
- assertEquals("John Doe", RecordPath.compile("/name[not(. = 'Jane Doe')]").evaluate(record).getSelectedFields().findFirst().get().getValue());
- }
+ @Test
+ public void supportsReferenceToFieldOfTypeTimestamp() {
+ supportsRecordFieldType(
+ RecordFieldType.TIMESTAMP,
+ List.of(
+ Timestamp.valueOf("2024-08-18 09:45:27")
+ )
+ );
+ }
- @Test
- public void testChainingFunctions() {
- final List fields = new ArrayList<>();
- fields.add(new RecordField("id", RecordFieldType.INT.getDataType()));
- fields.add(new RecordField("name", RecordFieldType.STRING.getDataType()));
+ @Test
+ public void supportsReferenceToFieldOfTypeUuid() {
+ supportsRecordFieldType(
+ RecordFieldType.UUID,
+ List.of(
+ UUID.randomUUID(),
+ UUID.fromString("cca14e57-c79e-4fb9-8235-afeb503380df"),
+ UUID.nameUUIDFromBytes(new byte[0])
+ )
+ );
+ }
- final RecordSchema schema = new SimpleRecordSchema(fields);
+ @Test
+ public void supportsReferenceToFieldOfTypeArray() {
+ supportsRecordFieldType(
+ arrayTypeOf(RecordFieldType.STRING),
+ List.of(
+ new String[0],
+ new String[]{"CAT"},
+ new String[]{"a", "b", "c", "x", "y", "z"}
+ )
+ );
+ }
- final Map values = new HashMap<>();
- values.put("id", 48);
- values.put("name", "John Doe");
- final Record record = new MapRecord(schema, values);
+ @Test
+ public void supportsReferenceToFieldOfTypeMap() {
+ supportsRecordFieldType(
+ mapTypeOf(RecordFieldType.INT),
+ List.of(
+ Map.of(),
+ Map.of("first", 1),
+ Map.of("a", 1, "b", 2, "c", 3)
+ )
+ );
+ }
- assertEquals("John Doe", RecordPath.compile("/name[contains(substringAfter(., 'o'), 'h')]").evaluate(record).getSelectedFields().findFirst().get().getValue());
- }
+ @Test
+ public void supportsReferenceToFieldOfTypeRecord() {
+ supportsRecordFieldType(
+ recordTypeOf(getAccountSchema()),
+ List.of(
+ createAccountRecord()
+ )
+ );
+ }
+ @Test
+ public void supportsReferenceToFieldOfTypeChoice() {
+ supportsRecordFieldType(
+ choiceTypeOf(
+ RecordFieldType.INT,
+ RecordFieldType.STRING,
+ recordTypeOf(getAccountSchema())
+ ),
+ List.of(
+ 25,
+ "Alice",
+ createAccountRecord()
+ )
+ );
+ }
+ private static void supportsRecordFieldType(
+ final RecordFieldType expectedType,
+ final List expectedUnchangedValues) {
+ supportsRecordFieldType(expectedType, expectedUnchangedValues, List.of());
+ }
- @Test
- public void testMatchesRegex() {
- final List fields = new ArrayList<>();
- fields.add(new RecordField("id", RecordFieldType.INT.getDataType()));
- fields.add(new RecordField("name", RecordFieldType.STRING.getDataType()));
+ private static void supportsRecordFieldType(
+ final RecordFieldType expectedType,
+ final List expectedUnchangedValues,
+ final List