
com.redhat.lightblue.assoc.ResultDoc Maven / Gradle / Ivy
/*
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.assoc;
import java.io.Serializable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;
import java.util.Collection;
import java.util.Set;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.redhat.lightblue.metadata.DocId;
import com.redhat.lightblue.metadata.CompositeMetadata;
import com.redhat.lightblue.metadata.ResolvedReferenceField;
import com.redhat.lightblue.eval.QueryEvaluator;
import com.redhat.lightblue.util.JsonDoc;
import com.redhat.lightblue.util.KeyValueCursor;
import com.redhat.lightblue.util.Path;
import com.redhat.lightblue.util.MutablePath;
/**
* A result document of a particular entity type. This contains the
* document, the unique id, the query plan node corresponding to this
* document, and the references to other documents. During
* construction, all reference instances are collected, and a
* DocReference list is constructed using those references. Subsequent
* stages of execution attach new documents to those references.
*/
public class ResultDoc implements Serializable {
private static final long serialVersionUID=1l;
private static final Logger LOGGER=LoggerFactory.getLogger(ResultDoc.class);
private final JsonDoc doc;
private final DocId id;
private final QueryPlanNode node;
private final Map> children=new HashMap<>();
private final Map parents=new HashMap<>();
public ResultDoc(JsonDoc doc,
DocId id,
QueryPlanNode node) {
this.node=node;
this.doc=doc;
this.id=id;
gatherChildren();
}
public DocId getId() {
return id;
}
public JsonDoc getDoc() {
return doc;
}
/**
* Returns the query plan node for this document
*/
public QueryPlanNode getQueryPlanNode() {
return node;
}
/**
* Returns the metadata for this document
*/
public CompositeMetadata getMetadata() {
return node.getMetadata();
}
public List getChildren(QueryPlanNode dest) {
return getChildren(dest.getMetadata());
}
public List getChildren(CompositeMetadata destMd) {
return children.get(destMd);
}
public Map> getChildren() {
return children;
}
/**
* Returns all child references to a given node for all the docs in the list
*/
public static List getChildren(List docs,QueryPlanNode dest) {
List ret=new ArrayList<>();
for(ResultDoc x:docs) {
List l=x.getChildren(dest);
if(l!=null)
ret.addAll(l);
}
return ret;
}
public Map getParentDocs() {
return parents;
}
/**
* Sets the parent document reference of this document that is coming from parentNode
*/
public void setParentDoc(QueryPlanNode parentNode,ChildDocReference ref) {
parents.put(parentNode.getMetadata(),ref);
}
/**
* Iterates through all destination nodes in query plan, finds all
* references corresponding to those destination nodes, and
* initializes a reference for each
*/
private void gatherChildren() {
CompositeMetadata thisMd=node.getMetadata();
Set childPaths=thisMd.getChildPaths();
if(childPaths!=null) {
for(Path childEntityPath:childPaths) {
LOGGER.debug("Gathering children for {}",childEntityPath);
ResolvedReferenceField ref=thisMd.getChildReference(childEntityPath);
CompositeMetadata destMd=ref.getReferencedMetadata();
List refList=new ArrayList<>();
// Get the resolved reference for this field
LOGGER.debug("Resolved reference for {}:{}",destMd.getEntityPath(),ref);
// We cut the last segment, it is "ref"
Path entityRelativeFieldName=thisMd.getEntityRelativeFieldName(ref);
Path p=entityRelativeFieldName.prefix(-1);
LOGGER.debug("Getting instances of {} (reference was {})",p,entityRelativeFieldName);
// p points to the object containing the reference field
// It could be empty, if the reference is at the root level
if(p.isEmpty()) {
refList.add(new ChildDocReference(this,entityRelativeFieldName));
} else {
LOGGER.debug("Iterating {} in {}",p,doc);
KeyValueCursor cursor=doc.getAllNodes(p);
while(cursor.hasNext()) {
cursor.next();
JsonNode nodeWithRef=cursor.getCurrentValue();
LOGGER.debug("Checking field {}:{}",cursor.getCurrentKey(),nodeWithRef);
if(nodeWithRef instanceof ArrayNode) {
int size=((ArrayNode)nodeWithRef).size();
MutablePath elem=cursor.getCurrentKey().mutableCopy();
int ix=elem.numSegments();
elem.push(0);
elem.push(ref.getName());
for(int i=0;i parentDocs,
List childDocs,
List edgeClauses,
CompositeMetadata root) {
// We have to find a list of childDocs for every reference in a parent doc
LOGGER.debug("Associating {} parent docs",parentDocs.size());
if(!childDocs.isEmpty()&&!parentDocs.isEmpty()) {
QueryPlanNode childDocsNode=childDocs.get(0).node;
QueryPlanNode parentDocsNode=parentDocs.get(0).node;
LOGGER.debug("Initializing query processor with parent:{} child:{}",parentDocsNode,childDocsNode);
ResolvedFieldBinding.BindResult bindingInfo;
QueryEvaluator qeval;
if(edgeClauses!=null&&!edgeClauses.isEmpty()) {
bindingInfo=ResolvedFieldBinding.bind(edgeClauses,childDocsNode,root);
qeval=QueryEvaluator.getInstance(bindingInfo == null ? null : bindingInfo.getRelativeQuery(),
childDocsNode.getMetadata());
} else {
bindingInfo=null;
qeval=QueryEvaluator.MATCH_ALL_EVALUATOR;
}
for(ResultDoc parentDoc:parentDocs) {
LOGGER.debug("Processing parent doc {}",parentDoc.id);
List references=parentDoc.getChildren(childDocsNode);
if(bindingInfo!=null) {
for(DocReference reference:references) {
if(reference instanceof ChildDocReference) {
for(ResolvedFieldBinding binding:bindingInfo.getBindings())
binding.refresh((ChildDocReference)reference);
for(ResultDoc childDoc:childDocs) {
if(qeval.evaluate(childDoc.doc).getResult())
((ChildDocReference)reference).getChildren().add(childDoc);
}
}
}
}
}
}
}
public String toString() {
return "Doc:"+id+" children:"+children;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy