diff --git a/src/main/java/org/alfresco/opencmis/search/CMISQueryParser.java b/src/main/java/org/alfresco/opencmis/search/CMISQueryParser.java index 6e2d45b4b9..929854f4bd 100644 --- a/src/main/java/org/alfresco/opencmis/search/CMISQueryParser.java +++ b/src/main/java/org/alfresco/opencmis/search/CMISQueryParser.java @@ -143,7 +143,7 @@ public class CMISQueryParser CommonTree queryNode = (CommonTree) parser.query().getTree(); CommonTree sourceNode = (CommonTree) queryNode.getFirstChildWithType(CMISParser.SOURCE); - Source source = buildSource(sourceNode, joinSupport, factory); + Source source = buildSource(sourceNode, joinSupport, factory, JoinType.NONE); Map selectors = source.getSelectors(); ArrayList columns = buildColumns(queryNode, factory, selectors, options.getQuery()); @@ -1391,7 +1391,7 @@ public class CMISQueryParser } @SuppressWarnings("unchecked") - private Source buildSource(CommonTree source, CapabilityJoin joinSupport, QueryModelFactory factory) + private Source buildSource(CommonTree source, CapabilityJoin joinSupport, QueryModelFactory factory, JoinType lhsJoin) { if (source.getChildCount() == 1) { @@ -1404,7 +1404,7 @@ public class CMISQueryParser throw new UnsupportedOperationException("Joins are not supported"); } CommonTree tableSourceNode = (CommonTree) singleTableNode.getFirstChildWithType(CMISParser.SOURCE); - return buildSource(tableSourceNode, joinSupport, factory); + return buildSource(tableSourceNode, joinSupport, factory, JoinType.NONE); } if (singleTableNode.getType() != CMISParser.TABLE_REF) @@ -1432,7 +1432,9 @@ public class CMISQueryParser + typeDef.getTypeId()); } } - return factory.createSelector(typeDef.getAlfrescoClass(), alias); + Source lhs = factory.createSelector(typeDef.getAlfrescoClass(), alias); + lhs.setJoinType(lhsJoin); + return lhs; } else { if (joinSupport == CapabilityJoin.NONE) @@ -1466,15 +1468,20 @@ public class CMISQueryParser } Source lhs = factory.createSelector(typeDef.getAlfrescoClass(), alias); + if(lhsJoin == JoinType.NONE) + { + lhs.setJoinType(JoinType.INNER); + } + else + { + lhs.setJoinType(lhsJoin); + } List list = (List) (source.getChildren()); for (CommonTree joinNode : list) { if (joinNode.getType() == CMISParser.JOIN) { - CommonTree rhsSource = (CommonTree) joinNode.getFirstChildWithType(CMISParser.SOURCE); - Source rhs = buildSource(rhsSource, joinSupport, factory); - JoinType joinType = JoinType.INNER; CommonTree joinTypeNode = (CommonTree) joinNode.getFirstChildWithType(CMISParser.LEFT); if (joinTypeNode != null) @@ -1482,11 +1489,14 @@ public class CMISQueryParser joinType = JoinType.LEFT; } - if ((joinType == JoinType.LEFT) && (joinSupport == CapabilityJoin.INNERONLY)) + if ((joinType == JoinType.LEFT) && (joinSupport != CapabilityJoin.INNERANDOUTER)) { throw new UnsupportedOperationException("Outer joins are not supported"); } + CommonTree rhsSource = (CommonTree) joinNode.getFirstChildWithType(CMISParser.SOURCE); + Source rhs = buildSource(rhsSource, joinSupport, factory, joinType); + Constraint joinCondition = null; CommonTree joinConditionNode = (CommonTree) joinNode.getFirstChildWithType(CMISParser.ON); if (joinConditionNode != null) diff --git a/src/main/java/org/alfresco/repo/search/impl/querymodel/Join.java b/src/main/java/org/alfresco/repo/search/impl/querymodel/Join.java index a36c672adf..0d591c1724 100644 --- a/src/main/java/org/alfresco/repo/search/impl/querymodel/Join.java +++ b/src/main/java/org/alfresco/repo/search/impl/querymodel/Join.java @@ -43,12 +43,6 @@ public interface Join extends Source */ public Source getRight(); - /** - * Get the join type - * @return JoinType - */ - public JoinType getJoinType(); - /** * Get the join condition. * Not all constraints are valid join conditions diff --git a/src/main/java/org/alfresco/repo/search/impl/querymodel/JoinType.java b/src/main/java/org/alfresco/repo/search/impl/querymodel/JoinType.java index f6ed531093..42db10d5fe 100644 --- a/src/main/java/org/alfresco/repo/search/impl/querymodel/JoinType.java +++ b/src/main/java/org/alfresco/repo/search/impl/querymodel/JoinType.java @@ -42,5 +42,9 @@ public enum JoinType /** * Right (outer) join */ - RIGHT + RIGHT, + /** + * No Join + */ + NONE } diff --git a/src/main/java/org/alfresco/repo/search/impl/querymodel/Source.java b/src/main/java/org/alfresco/repo/search/impl/querymodel/Source.java index b6e206fa13..6ee6792153 100644 --- a/src/main/java/org/alfresco/repo/search/impl/querymodel/Source.java +++ b/src/main/java/org/alfresco/repo/search/impl/querymodel/Source.java @@ -40,4 +40,8 @@ public interface Source public Selector getSelector(String name); public List> getSelectorGroups(FunctionEvaluationContext functionContext); + + public JoinType getJoinType(); + + public void setJoinType(JoinType joinType); } diff --git a/src/main/java/org/alfresco/repo/search/impl/querymodel/impl/BaseJoin.java b/src/main/java/org/alfresco/repo/search/impl/querymodel/impl/BaseJoin.java index 0108004df9..0e6e1c4b99 100644 --- a/src/main/java/org/alfresco/repo/search/impl/querymodel/impl/BaseJoin.java +++ b/src/main/java/org/alfresco/repo/search/impl/querymodel/impl/BaseJoin.java @@ -194,7 +194,7 @@ public class BaseJoin implements Join } } - if ((getJoinType() == JoinType.INNER) && (lhsSelector != null) && (rhsSelector != null)) + if ( ((getJoinType() == JoinType.INNER) || (getJoinType() == JoinType.LEFT)) && (lhsSelector != null) && (rhsSelector != null)) { TOADD: for (Set toAddTo : left) @@ -247,4 +247,10 @@ public class BaseJoin implements Join return answer; } + + @Override + public void setJoinType(JoinType joinType) + { + this.joinType = joinType; + } } diff --git a/src/main/java/org/alfresco/repo/search/impl/querymodel/impl/BaseSelector.java b/src/main/java/org/alfresco/repo/search/impl/querymodel/impl/BaseSelector.java index ec0e1f0c34..19bbe1de9b 100644 --- a/src/main/java/org/alfresco/repo/search/impl/querymodel/impl/BaseSelector.java +++ b/src/main/java/org/alfresco/repo/search/impl/querymodel/impl/BaseSelector.java @@ -33,6 +33,7 @@ import java.util.Map; import java.util.Set; import org.alfresco.repo.search.impl.querymodel.FunctionEvaluationContext; +import org.alfresco.repo.search.impl.querymodel.JoinType; import org.alfresco.repo.search.impl.querymodel.Selector; import org.alfresco.service.namespace.QName; @@ -44,6 +45,8 @@ public class BaseSelector implements Selector private QName type; private String alias; + + private JoinType joinType = JoinType.NONE; public BaseSelector(QName type, String alias) { @@ -51,32 +54,41 @@ public class BaseSelector implements Selector this.alias = alias; } - /* - * (non-Javadoc) - * - * @see org.alfresco.repo.search.impl.querymodel.Selector#getAlias() - */ + @Override public String getAlias() { return alias; } - /* - * (non-Javadoc) - * - * @see org.alfresco.repo.search.impl.querymodel.Selector#getType() - */ + + + @Override + public JoinType getJoinType() + { + return joinType; + } + + @Override + public void setJoinType(JoinType joinType) + { + this.joinType = joinType; + } + + @Override public QName getType() { return type; } + + public String toString() { StringBuilder builder = new StringBuilder(); builder.append("BaseSelector["); builder.append("alias=").append(getAlias()).append(", "); - builder.append("type=").append(getType()); + builder.append("type=").append(getType()).append(", "); + builder.append("joinType=").append(getJoinType()); builder.append("]"); return builder.toString(); } diff --git a/src/main/java/org/alfresco/repo/search/impl/querymodel/impl/lucene/LuceneSelector.java b/src/main/java/org/alfresco/repo/search/impl/querymodel/impl/lucene/LuceneSelector.java index 1f2f62b510..e526781897 100644 --- a/src/main/java/org/alfresco/repo/search/impl/querymodel/impl/lucene/LuceneSelector.java +++ b/src/main/java/org/alfresco/repo/search/impl/querymodel/impl/lucene/LuceneSelector.java @@ -31,6 +31,7 @@ import java.util.Set; import org.alfresco.repo.search.adaptor.lucene.LuceneQueryParserAdaptor; import org.alfresco.repo.search.impl.querymodel.Argument; import org.alfresco.repo.search.impl.querymodel.FunctionEvaluationContext; +import org.alfresco.repo.search.impl.querymodel.JoinType; import org.alfresco.repo.search.impl.querymodel.impl.BaseSelector; import org.alfresco.service.namespace.QName; @@ -55,8 +56,18 @@ public class LuceneSelector extends BaseSelector impl */ public Q addComponent(Set selectors, Map functionArgs, LuceneQueryBuilderContext luceneContext, FunctionEvaluationContext functionContext) throws E { - LuceneQueryParserAdaptor lqpa = luceneContext.getLuceneQueryParserAdaptor(); - return lqpa.getFieldQuery("CLASS", getType().toString()); + LuceneQueryParserAdaptor lqpa = luceneContext.getLuceneQueryParserAdaptor(); + switch(getJoinType()) + { + case INNER: + case NONE: + return lqpa.getFieldQuery("CLASS", getType().toString()); + case LEFT: + return lqpa.getMatchAllNodesQuery(); + case RIGHT: + default: + throw new IllegalArgumentException(); + } } diff --git a/src/test/resources/org/alfresco/repo/search/impl/parsers/cmis_test.gunit b/src/test/resources/org/alfresco/repo/search/impl/parsers/cmis_test.gunit index 0a9089d1ca..61e5bbcaab 100644 --- a/src/test/resources/org/alfresco/repo/search/impl/parsers/cmis_test.gunit +++ b/src/test/resources/org/alfresco/repo/search/impl/parsers/cmis_test.gunit @@ -17,6 +17,15 @@ query: "SELECT cmis:name,, cmis:typeId FROM cmis:document" FAIL "SELECT * FROM *" FAIL +"SELECT * from cmis:document d JOIN cm:titled t ON d.cmis:objectId = t.cmis:objectId" -> + "(QUERY ALL_COLUMNS (SOURCE (TABLE_REF cmis:document d) (JOIN (SOURCE (TABLE_REF cm:titled t)) (ON (COLUMN_REF cmis:objectId d) = (COLUMN_REF cmis:objectId t)))))" +"SELECT * from cmis:document d LEFT OUTER JOIN cm:titled t ON d.cmis:objectId = t.cmis:objectId" -> + "(QUERY ALL_COLUMNS (SOURCE (TABLE_REF cmis:document d) (JOIN (SOURCE (TABLE_REF cm:titled t)) LEFT (ON (COLUMN_REF cmis:objectId d) = (COLUMN_REF cmis:objectId t)))))" +"SELECT * from cmis:document d JOIN cm:titled t ON d.cmis:objectId = t.cmis:objectId LEFT OUTER JOIN cm:ownable o ON d.cmis:objectId = o.cmis:objectId" -> + "(QUERY ALL_COLUMNS (SOURCE (TABLE_REF cmis:document d) (JOIN (SOURCE (TABLE_REF cm:titled t)) (ON (COLUMN_REF cmis:objectId d) = (COLUMN_REF cmis:objectId t))) (JOIN (SOURCE (TABLE_REF cm:ownable o)) LEFT (ON (COLUMN_REF cmis:objectId d) = (COLUMN_REF cmis:objectId o)))))" +"SELECT d.*, t.*, o.* from cmis:document d JOIN cm:titled t ON d.cmis:objectId = t.cmis:objectId LEFT OUTER JOIN cm:ownable o ON d.cmis:objectId = o.cmis:objectId" -> + "(QUERY (COLUMNS (ALL_COLUMNS d) (ALL_COLUMNS t) (ALL_COLUMNS o)) (SOURCE (TABLE_REF cmis:document d) (JOIN (SOURCE (TABLE_REF cm:titled t)) (ON (COLUMN_REF cmis:objectId d) = (COLUMN_REF cmis:objectId t))) (JOIN (SOURCE (TABLE_REF cm:ownable o)) LEFT (ON (COLUMN_REF cmis:objectId d) = (COLUMN_REF cmis:objectId o)))))" + "SELECT * from FOLDER JOIN RELATIONSHIP ON FOLDER.ID = RELATIONSHIP.ID" OK "SELECT * from FOLDER F JOIN RELATIONSHIP RL ON F.ID = RL.ID" OK "SELECT * from DOCUMENT D JOIN DOCUMENT DD ON (D.ID = DD.ID)" FAIL