
com.hazelcast.internal.serialization.impl.GenericRecordQueryReader Maven / Gradle / Ivy
/*
* Copyright (c) 2008-2024, Hazelcast, Inc. All Rights Reserved.
*
* Licensed 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 com.hazelcast.internal.serialization.impl;
import com.hazelcast.internal.serialization.impl.portable.PortableInternalGenericRecord;
import com.hazelcast.internal.util.StringUtil;
import com.hazelcast.nio.serialization.FieldKind;
import com.hazelcast.query.extractor.ValueCallback;
import com.hazelcast.query.extractor.ValueCollector;
import com.hazelcast.query.extractor.ValueReader;
import com.hazelcast.query.extractor.ValueReadingException;
import com.hazelcast.query.impl.getters.ExtractorHelper;
import com.hazelcast.query.impl.getters.MultiResult;
import java.io.IOException;
import java.util.LinkedList;
import java.util.ListIterator;
import java.util.function.Consumer;
import static com.hazelcast.internal.serialization.impl.FieldOperations.fieldOperations;
import static com.hazelcast.query.impl.getters.ExtractorHelper.extractArgumentsFromAttributeName;
import static com.hazelcast.query.impl.getters.ExtractorHelper.extractAttributeNameNameWithoutArguments;
/**
* Reads a field or array of fields from a `InternalGenericRecord` according to given query `path`
*
* @see InternalGenericRecord
* Any format that exposes an `InternalGenericRecord` will benefit from hazelcast query.
* @see PortableInternalGenericRecord for Portable InternalGenericRecord
*
* Example queries
* "age"
* "engine.power"
* "child[0].age"
* "engine.wheel[0].pressure"
* "engine.wheel[any].pressure"
* "top500Companies[0].ceo"
* "company.employees[any]"
* "limbs[*].fingers"
*
* It also implements ValueReader to support reading into `ValueCallback` and `ValueCollector`
*/
public final class GenericRecordQueryReader implements ValueReader {
private final InternalGenericRecord rootRecord;
private final boolean useLazyDeserialization;
public GenericRecordQueryReader(InternalGenericRecord rootRecord) {
this(rootRecord, false);
}
public GenericRecordQueryReader(InternalGenericRecord rootRecord, boolean useLazyDeserialization) {
this.rootRecord = rootRecord;
this.useLazyDeserialization = useLazyDeserialization;
}
@SuppressWarnings("unchecked")
public void read(String path, ValueCallback callback) {
read(path, (ValueCollector) callback::onResult);
}
@SuppressWarnings("unchecked")
public void read(String path, ValueCollector collector) {
read(path, (Consumer) collector::addObject);
}
private void read(String path, Consumer consumer) {
try {
Object result = read(path);
if (result instanceof MultiResult multiResult) {
for (Object singleResult : multiResult.getResults()) {
consumer.accept(singleResult);
}
} else {
consumer.accept(result);
}
} catch (IOException e) {
throw new ValueReadingException(e.getMessage(), e);
} catch (RuntimeException e) {
throw new ValueReadingException(e.getMessage(), e);
}
}
@SuppressWarnings({"CyclomaticComplexity", "MethodLength", "NPathComplexity"})
public Object read(String fieldPath) throws IOException {
if (fieldPath == null) {
throw new IllegalArgumentException("field path can not be null");
}
if (fieldPath.endsWith(".")) {
throw new IllegalArgumentException("Malformed path " + fieldPath);
}
if (rootRecord.hasField(fieldPath)) {
return readLeaf(rootRecord, fieldPath);
}
LinkedList