/*
* (C) Copyright 2008-2010 Nuxeo SA (http://nuxeo.com/) and others.
*
* 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.
*
* Contributors:
* Florent Guillaume
*/
package org.nuxeo.ecm.platform.tag;
import java.util.List;
import org.nuxeo.ecm.core.query.QueryFilter;
import org.nuxeo.ecm.core.query.QueryParseException;
import org.nuxeo.ecm.core.storage.sql.ColumnType;
import org.nuxeo.ecm.core.storage.sql.Model;
import org.nuxeo.ecm.core.storage.sql.Session.PathResolver;
import org.nuxeo.ecm.core.storage.sql.jdbc.NXQLQueryMaker;
import org.nuxeo.ecm.core.storage.sql.jdbc.SQLInfo;
import org.nuxeo.ecm.core.storage.sql.jdbc.db.Column;
import org.nuxeo.ecm.core.storage.sql.jdbc.db.Join;
import org.nuxeo.ecm.core.storage.sql.jdbc.db.Select;
import org.nuxeo.ecm.core.storage.sql.jdbc.db.Table;
/**
* Query Maker specialized for tagging queries that need joins.
*/
public class TagQueryMaker extends NXQLQueryMaker {
/** The NXTAG query type. */
public static final String NXTAG = "NXTAG";
public static final String SCHEMA_TAG = "tag";
public static final String SCHEMA_RELATION = "relation";
public static final String PROPERTY_SOURCE = "source";
public static final String PROPERTY_TARGET = "target";
/**
* Makes sure the Tag table is joined with the relation target instead of the hierarchy id.
*/
public static final String TAG_IS_TARGET = "TAGISTARGET: ";
/**
* Adds a COUNT() on the relation source, to count documents.
*/
public static final String COUNT_SOURCE = "COUNTSOURCE: ";
protected String type;
protected Table relationTable;
protected Column firstSelectedColumn;
@Override
public String getName() {
return NXTAG;
}
@Override
public boolean accepts(String queryType) {
return queryType.equals(NXTAG);
}
@Override
public Query buildQuery(SQLInfo sqlInfo, Model model, PathResolver pathResolver, String query,
QueryFilter queryFilter, Object... params) {
if (query.startsWith(TAG_IS_TARGET)) {
type = TAG_IS_TARGET;
} else if (query.startsWith(COUNT_SOURCE)) {
type = COUNT_SOURCE;
// SELECT "TAG"."LABEL" AS "_C1",
// COUNT(DISTINCT "RELATION"."SOURCE") AS "_C2"
// FROM "HIERARCHY"
// JOIN "RELATION" ON "HIERARCHY"."ID" = "RELATION"."ID"
// JOIN "DUBLINCORE" ON "HIERARCHY"."ID" = "DUBLINCORE"."ID"
// JOIN "TAG" ON "RELATION"."TARGET" = "TAG"."ID"
// WHERE "HIERARCHY"."PRIMARYTYPE" IN ('Tagging')
// AND ("RELATION"."SOURCE" = '47c4c0f7...') -- or IN ()
// AND ("DUBLINCORE"."CREATOR" = 'Administrator')
// GROUP BY "_C1"
} else {
throw new QueryParseException("Bad query: " + query);
}
query = query.substring(type.length());
return super.buildQuery(sqlInfo, model, pathResolver, query, queryFilter, params);
}
/**
* Adds an initial join on the Relation table, and records it.
*/
@Override
protected void fixInitialJoins() {
relationTable = getFragmentTable(dataHierTable, SCHEMA_RELATION, SCHEMA_RELATION, -1, false);
}
/**
* Patches the Tag join to join on the relation target instead of the hierarchy id.
*/
@Override
protected void addJoin(int kind, String alias, Table table, String column, Table contextTable,
String contextColumn, String name, int index, String primaryType) {
if (table.getKey().equals(SCHEMA_TAG)) {
kind = Join.INNER;
contextTable = relationTable;
contextColumn = PROPERTY_TARGET;
}
super.addJoin(kind, alias, table, column, contextTable, contextColumn, name, index, null);
}
@Override
protected String getSelectColName(Column col) {
String name = super.getSelectColName(col);
if (firstSelectedColumn == null) {
firstSelectedColumn = col;
}
if (type == COUNT_SOURCE && col.getTable().getKey().equals(SCHEMA_RELATION)
&& col.getKey().equals(PROPERTY_SOURCE)) {
name = String.format("COUNT(DISTINCT %s)", name);
}
return name;
}
@Override
protected void fixWhatColumns(List<Column> whatColumns) {
if (type == COUNT_SOURCE) {
// 2nd col is a COUNT -> different type
Column targetCol = whatColumns.remove(1);
Column countCol = new Column(targetCol.getTable(), null, ColumnType.INTEGER, null);
whatColumns.add(countCol);
}
}
@Override
protected void fixSelect(Select select) {
if (type == COUNT_SOURCE) {
// add a GROUP BY on first col
String name;
if (dialect.needsOriginalColumnInGroupBy()) {
name = firstSelectedColumn.getFullQuotedName();
} else {
name = dialect.openQuote() + COL_ALIAS_PREFIX + "1" + dialect.closeQuote();
}
select.setGroupBy(name);
}
}
}