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

com.redhat.lightblue.eval.ArrayProjector Maven / Gradle / Ivy

The newest version!
/*
 Copyright 2013 Red Hat, Inc. and/or its affiliates.

 This file is part of lightblue.

 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program.  If not, see .
 */
package com.redhat.lightblue.eval;

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

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.ArrayNode;

import com.redhat.lightblue.crud.CrudConstants;
import com.redhat.lightblue.metadata.ArrayField;
import com.redhat.lightblue.metadata.FieldTreeNode;
import com.redhat.lightblue.metadata.SimpleField;
import com.redhat.lightblue.query.ArrayProjection;
import com.redhat.lightblue.query.Sort;
import com.redhat.lightblue.query.SortKey;
import com.redhat.lightblue.query.CompositeSortKey;
import com.redhat.lightblue.util.Path;
import com.redhat.lightblue.util.JsonDoc;

/**
 * Base class for array projectors.
 */
public abstract class ArrayProjector extends Projector {

    private static final Logger LOGGER=LoggerFactory.getLogger(ArrayProjector.class);

    private final Path arrayFieldPattern;
    private final boolean include;
    private final Projector nestedProjector;
    private boolean lastMatch;
    private final Sort sort;
    private final SortFieldInfo[] sortFields;
    protected Projector decidingProjector;

    private final static class SortFieldInfo {
        final SimpleField field;
        final Path name;
        final boolean descending;

        SortFieldInfo(SimpleField field,Path name,boolean descending) {
            this.field=field;
            this.name=name;
            this.descending=descending;
        }
    }

    private final static class SortableElement implements Comparable {
        final Object[] keyValues;
        final JsonNode node;
        final SortFieldInfo[] sortFields;

        public SortableElement(JsonNode node,SortFieldInfo[] sortFields) {
            this.node=node;
            this.sortFields=sortFields;
            keyValues=new Object[sortFields.length];
            for(int i=0;i keys=((CompositeSortKey)sort).getKeys();
            SortFieldInfo[] arr=new SortFieldInfo[ keys.size() ];
            int i=0;
            for(SortKey key:keys) {
                arr[i]=getSortField(key.getField(),context,key.isDesc());
            }
            return arr;
        }
    }

    private SortFieldInfo getSortField(Path field,FieldTreeNode context,boolean descending) {
        FieldTreeNode fieldMd=context.resolve(field);
        if(! (fieldMd instanceof SimpleField) ) {
            throw new EvaluationError(CrudConstants.ERR_EXPECTED_VALUE+":"+field);
        }
        return new SortFieldInfo((SimpleField)fieldMd,field,descending);
    }

    public Sort getSort() {
        return sort;
    }

    /**
     * Any array inclusion/exclusion is an exact match of the projection
     */
    @Override
    public boolean exactMatch() {
        return true;
    }

    /**
     * Returns the nested projector if the last projection is a match
     */
    @Override
    public Projector getNestedProjector() {
        return lastMatch ? nestedProjector : null;
    }

    @Override
    public Projector getDecidingProjector() {
        return decidingProjector;
    }

    @Override
    public Boolean project(Path p, QueryEvaluationContext ctx) {
       decidingProjector=null;
       lastMatch = false;
       if (p.matchingPrefix(arrayFieldPattern)) {
           decidingProjector=this;
           return include ? Boolean.TRUE : Boolean.FALSE;
       }
       // Is this field pointing to an element of the array
       // It is so if 'p' has one more element than 'arrayFieldPattern', and
       // if it is a matching descendant
       if (p.numSegments() == arrayFieldPattern.numSegments() + 1 && p.matchingDescendant(arrayFieldPattern)) {
           Boolean ret=projectArray(p, ctx);
           if(ret!=null&&nestedProjector!=null) {
               decidingProjector=nestedProjector.getDecidingProjector();
           }
           return ret;
       }
       return null;
    }

    /**
     * Sorts the given array node using the sort criteria given in this ArrayProjector
     *
     * @param array The array node to sort
     * @param factory Json node factory
     *
     * If there is a sort criteria defined in this, the array elements are
     * sorted using that.
     *
     * @return A new ArrayNode containing the sorted elements, or if
     * there is no sort defined, the array itself
     */
    public ArrayNode sortArray(ArrayNode array,JsonNodeFactory factory) {
        if(sort==null) {
            return array;
        } else {
            List list=new ArrayList<>(array.size());
            for(Iterator itr=array.elements();itr.hasNext();) {
                list.add(new SortableElement(itr.next(),sortFields));
            }
            Collections.sort(list);
            ArrayNode newNode=factory.arrayNode();
            for(SortableElement x:list)
                newNode.add(x.node);
            return newNode;
        }
    }

    /**
     * Check if the array element matches. This is called after determining that
     * the path points to a field that can be interpreted by this projector.
     */
    protected abstract Boolean projectArray(Path p, QueryEvaluationContext ctx);
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy