All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.hazelcast.jet.sql.impl.connector.keyvalue.KvMetadataResolver Maven / Gradle / Ivy

There is a newer version: 5.5.0
Show newest version
/*
 * Copyright 2024 Hazelcast Inc.
 *
 * Licensed under the Hazelcast Community License (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://hazelcast.com/hazelcast-community-license
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.hazelcast.jet.sql.impl.connector.keyvalue;

import com.hazelcast.internal.serialization.InternalSerializationService;
import com.hazelcast.sql.impl.QueryException;
import com.hazelcast.sql.impl.extract.QueryPath;
import com.hazelcast.sql.impl.schema.MappingField;
import com.hazelcast.sql.impl.schema.TableField;
import com.hazelcast.sql.impl.schema.map.MapTableField;
import com.hazelcast.sql.impl.type.QueryDataType;
import com.hazelcast.sql.impl.type.QueryDataType.QueryDataTypeField;

import javax.annotation.Nonnull;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.stream.Stream;

import static com.hazelcast.sql.impl.extract.QueryPath.KEY;
import static com.hazelcast.sql.impl.extract.QueryPath.VALUE;

/**
 * Interface for key-value resolution of fields for a particular
 * serialization type.
 */
public interface KvMetadataResolver {

    Stream supportedFormats();

    Stream resolveAndValidateFields(
            boolean isKey,
            List userFields,
            Map options,
            InternalSerializationService serializationService
    );

    KvMetadata resolveMetadata(
            boolean isKey,
            List resolvedFields,
            Map options,
            InternalSerializationService serializationService
    );

    static Map extractFields(List fields, boolean isKey) {
        Map fieldsByPath = new LinkedHashMap<>();
        for (MappingField field : fields) {
            QueryPath path = QueryPath.create(field.externalName());
            if (isKey != path.isKey()) {
                continue;
            }
            if (fieldsByPath.putIfAbsent(path, field) != null) {
                throw QueryException.error("Duplicate external name: " + path);
            }
        }
        return fieldsByPath;
    }

    static void maybeAddDefaultField(
            boolean isKey,
            @Nonnull List resolvedFields,
            @Nonnull List tableFields,
            @Nonnull QueryDataType type
    ) {
        // Add the default `__key` or `this` field as hidden, if not present in the field names
        String fieldName = isKey ? KEY : VALUE;
        if (resolvedFields.stream().noneMatch(field -> field.name().equals(fieldName))) {
            tableFields.add(new MapTableField(fieldName, type, true, QueryPath.create(fieldName)));
        }
    }

    /**
     * If {@code __key}/{@code this} is the only key/value field and has a custom type,
     * return type fields. Otherwise, return mapping fields without {@code __key} or {@code this}.
     */
    static Stream getFields(Map fields) {
        return getTopLevelType(fields)
                .map(type -> type.getObjectFields().stream().map(Field::new))
                .orElseGet(() -> fields.entrySet().stream().filter(e -> !e.getKey().isTopLevel()).map(Field::new));
    }

    /**
     * If {@code __key}/{@code this} is the only key/value field and has a custom type,
     * return its metadata.
     */
    static Optional getMetadata(Map fields) {
        return getTopLevelType(fields).map(QueryDataType::getObjectTypeMetadata);
    }

    /**
     * If {@code __key}/{@code this} is the only key/value field and has a custom type,
     * return its type.
     */
    static Optional getTopLevelType(Map fields) {
        if (fields.size() == 1) {
            Entry entry = fields.entrySet().iterator().next();
            if (entry.getKey().isTopLevel() && entry.getValue().type().isCustomType()) {
                return Optional.of(entry.getValue().type());
            }
        }
        return Optional.empty();
    }

    class Field {
        private final String name;
        private final QueryDataType type;

        public Field(Entry entry) {
            name = entry.getKey().getPath();
            type = entry.getValue().type();
        }

        public Field(TableField field) {
            name = field instanceof MapTableField
                    ? ((MapTableField) field).getPath().getPath() : field.getName();
            type = field.getType();
        }

        public Field(QueryDataTypeField field) {
            name = field.getName();
            type = field.getType();
        }

        public String name() {
            return name;
        }

        public QueryDataType type() {
            return type;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy