GremlinQueryCreator.java

// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

package com.azure.spring.data.gremlin.query.query;

import com.azure.spring.data.gremlin.mapping.GremlinPersistentProperty;
import com.azure.spring.data.gremlin.query.criteria.Criteria;
import com.azure.spring.data.gremlin.query.criteria.CriteriaType;
import com.azure.spring.data.gremlin.query.paramerter.GremlinParameterAccessor;
import org.springframework.data.domain.Sort;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.repository.query.parser.AbstractQueryCreator;
import org.springframework.data.repository.query.parser.Part;
import org.springframework.data.repository.query.parser.PartTree;
import org.springframework.lang.NonNull;
import org.springframework.util.Assert;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

public class GremlinQueryCreator extends AbstractQueryCreator<GremlinQuery, Criteria> {

    private final MappingContext<?, GremlinPersistentProperty> mappingContext;
    private static final Map<Part.Type, CriteriaType> CRITERIA_MAP;

    static {
        final Map<Part.Type, CriteriaType> map = new HashMap<>();

        map.put(Part.Type.AFTER, CriteriaType.AFTER);
        map.put(Part.Type.BEFORE, CriteriaType.BEFORE);
        map.put(Part.Type.BETWEEN, CriteriaType.BETWEEN);
        map.put(Part.Type.SIMPLE_PROPERTY, CriteriaType.IS_EQUAL);
        map.put(Part.Type.EXISTS, CriteriaType.EXISTS);

        CRITERIA_MAP = Collections.unmodifiableMap(map);
    }

    public GremlinQueryCreator(@NonNull PartTree partTree, @NonNull GremlinParameterAccessor accessor,
                               @NonNull MappingContext<?, GremlinPersistentProperty> mappingContext) {
        super(partTree, accessor);

        this.mappingContext = mappingContext;
    }

    @Override // Note (panli): side effect here, this method will change the iterator status of parameters.
    protected Criteria create(@NonNull Part part, @NonNull Iterator<Object> parameters) {
        final Part.Type type = part.getType();
        final String subject = this.mappingContext.getPersistentPropertyPath(part.getProperty()).toDotPath();
        final List<Object> values = new ArrayList<>();

        if (!CRITERIA_MAP.containsKey(type)) {
            throw new UnsupportedOperationException("Unsupported keyword: " + type.toString());
        }

        for (int i = 0; i < part.getNumberOfArguments(); i++) {
            Assert.isTrue(parameters.hasNext(), "should not reach the end of iterator");
            values.add(parameters.next());
        }

        return Criteria.getUnaryInstance(CRITERIA_MAP.get(type), subject, values);
    }

    @Override
    protected Criteria and(@NonNull Part part, @NonNull Criteria base, @NonNull Iterator<Object> parameters) {
        final Criteria right = this.create(part, parameters);

        return Criteria.getBinaryInstance(CriteriaType.AND, base, right);
    }

    @Override
    protected Criteria or(@NonNull Criteria base, @NonNull Criteria criteria) {
        return Criteria.getBinaryInstance(CriteriaType.OR, base, criteria);
    }

    @Override
    protected GremlinQuery complete(@NonNull Criteria criteria, @NonNull Sort sort) {
        return new GremlinQuery(criteria);
    }
}