/* Copyright [2013-2014] eBay Software Foundation Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ /* Copyright 2012 eBay Software Foundation Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package com.ebay.cloud.cms.dal.search.impl.criteria; import java.util.ArrayList; import java.util.List; import com.ebay.cloud.cms.dal.search.ISearchField; import com.ebay.cloud.cms.dal.search.impl.field.AbstractSearchField; import com.ebay.cloud.cms.metadata.model.MetaField; import com.ebay.cloud.cms.metadata.model.MetaField.CardinalityEnum; import com.mongodb.BasicDBObject; import com.mongodb.DBObject; public abstract class AbstractFieldCriteriaHandler implements IFieldCriteriaHandler { /** * Build query objects * * @param criteria * @param query * @param atomQueryObject * @param checkFieldArray -- when the field on the criteria, decide to use $elemMatch or not. A couple of */ protected void buildCriteria(FieldSearchCriteria criteria, DBObject query, DBObject atomQueryObject) { String fullDbName = criteria.getFullDbName(); ISearchField searchField = criteria.getSearchField(); if (!(searchField instanceof AbstractSearchField)) { // GroupField : won't be array // AggregationField : won't be array query.put(fullDbName, atomQueryObject); return; } // AbstractSearchField AbstractSearchField asf = (AbstractSearchField) criteria.getSearchField(); MetaField metaField = asf.getRootField(); // inner property is an primitive type // embed handling : FIXME:: what about multiple layer of embedded(MANY)? We support only one layer of array for now String eleMatchName = asf.getRootFieldDbName(); String innerField = asf.getInnerField(); // 1. embed many if (criteria.isEmbeddedCardinalityMany() && criteria.isEmbeddedObject() && asf.getInnerProperty() == null) { // embed array String embedPath = asf.getEmbedPath(); String parentPath = embedPath.substring(0, embedPath.length() - 1); String key = asf.getRootFieldDbName(); if (useElemMatchName()) { key = asf.getRootFieldElemMatchDbName(); } query.put(parentPath, new BasicDBObject("$elemMatch", new BasicDBObject(key, atomQueryObject))); return; } // 2. for cardinality=MANY case if (useArrayElemMatch() && asf.getInnerProperty() == null && metaField.getCardinality() == CardinalityEnum.Many) { if (criteria.isEmbeddedObject()) { String embedPath = asf.getEmbedPath(); eleMatchName = embedPath + asf.getRootFieldDbName(); } // add $elemMatch query object if (innerField == null) { query.put(eleMatchName, new BasicDBObject("$elemMatch", atomQueryObject)); } else { query.put(eleMatchName, new BasicDBObject("$elemMatch", new BasicDBObject(innerField, atomQueryObject))); } return; } // 3. if not array handling, this is the default behavior query.put(fullDbName, atomQueryObject); } protected DBObject buildNegativeArrayCriteria(FieldSearchCriteria criteria, DBObject query) { String fullDbName = criteria.getFullDbName(); ISearchField searchField = criteria.getSearchField(); if (!(searchField instanceof AbstractSearchField)) { // GroupField : won't be array // AggregationField : won't be array return query; } AbstractSearchField asf = (AbstractSearchField) criteria.getSearchField(); MetaField metaField = asf.getRootField(); if (useArrayElemMatch() && asf.getInnerProperty() == null && metaField.getCardinality() == CardinalityEnum.Many) { // for array of not, $elemMatch will force the $exists=true. BasicDBObject or = new BasicDBObject(); List<DBObject> ors = new ArrayList<DBObject>(); // exists ors.add(new BasicDBObject(fullDbName, new BasicDBObject("$exists", false))); ors.add(new BasicDBObject(fullDbName, new BasicDBObject("$size", 0))); ors.add(query); or.put("$or", ors); return or; } return query; } protected abstract boolean useArrayElemMatch(); protected boolean useElemMatchName() { return true; } }