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

dk.eobjects.metamodel.QueryPostprocessDataContextStrategy Maven / Gradle / Ivy

Go to download

The eobjects.dk MetaModel is a common domain model, query-engine and optimizer for different kinds of datastores.

The newest version!
/*
 * Copyright 2008 eobjects.dk
 *
 * 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 dk.eobjects.metamodel;

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

import dk.eobjects.metamodel.data.DataSet;
import dk.eobjects.metamodel.data.MaxRowsDataSetStrategyWrapper;
import dk.eobjects.metamodel.query.FilterItem;
import dk.eobjects.metamodel.query.FromItem;
import dk.eobjects.metamodel.query.GroupByItem;
import dk.eobjects.metamodel.query.JoinType;
import dk.eobjects.metamodel.query.OperatorType;
import dk.eobjects.metamodel.query.OrderByItem;
import dk.eobjects.metamodel.query.Query;
import dk.eobjects.metamodel.query.SelectItem;
import dk.eobjects.metamodel.schema.Column;
import dk.eobjects.metamodel.schema.Table;

/**
 * Abstract DataContextStrategy for data sources that do not support SQL
 * queries. Instead this superclass only requires that a subclass can
 * materialize a single table at a time. Then the query will be executed by post
 * processing data client-side.
 */
public abstract class QueryPostprocessDataContextStrategy implements
		IDataContextStrategy {

	public DataSet executeQuery(Query query) {
		List selectItems = query.getSelectClause().getItems();
		List fromItems = query.getFromClause().getItems();
		List whereItems = query.getWhereClause().getItems();
		List whereSelectItems = query.getWhereClause()
				.getEvaluatedSelectItems();
		List groupByItems = query.getGroupByClause().getItems();
		List havingSelectItems = query.getHavingClause()
				.getEvaluatedSelectItems();
		List havingItems = query.getHavingClause().getItems();
		List orderByItems = query.getOrderByClause().getItems();

		// Check for very simple queries with max rows property set (typically
		// preview), see Ticket #187
		previewTable: if (query.getMaxRows() != null && whereItems.isEmpty()
				&& groupByItems.isEmpty() && havingItems.isEmpty()
				&& orderByItems.isEmpty() && fromItems.size() == 1) {
			Table table = fromItems.get(0).getTable();
			if (table != null) {
				Column[] columns = new Column[selectItems.size()];
				int i = 0;
				for (Iterator it = selectItems.iterator(); it
						.hasNext();) {
					SelectItem item = it.next();
					if (item.getFunction() != null
							|| item.getExpression() != null) {
						break previewTable;
					}
					columns[i] = item.getColumn();
					i++;
				}

				DataSet dataSet = materializeTable(table, columns, query
						.getMaxRows());
				dataSet = MetaModelHelper.getSelection(selectItems, dataSet);
				return dataSet;
			}
		}

		// Materialize the tables in the from clause
		DataSet[] fromDataSets = new DataSet[fromItems.size()];
		for (int i = 0; i < fromDataSets.length; i++) {
			FromItem fromItem = fromItems.get(i);
			fromDataSets[i] = materializeFromItem(fromItem);
		}

		// Creates a list for all select items that are needed to execute query
		// (some may only be used as part of a filter, but not shown in result)
		List workSelectItems = collectSelectItems(selectItems,
				whereSelectItems, havingSelectItems);

		// Execute the query using the raw data
		DataSet dataSet = MetaModelHelper.getCarthesianProduct(fromDataSets,
				whereItems);
		if (groupByItems.size() > 0) {
			dataSet = MetaModelHelper.getGrouped(workSelectItems, dataSet,
					groupByItems);
		} else {
			dataSet = MetaModelHelper.getAggregated(workSelectItems, dataSet);
		}
		dataSet = MetaModelHelper.getFiltered(dataSet, havingItems);
		dataSet = MetaModelHelper.getOrdered(dataSet, orderByItems);
		dataSet = MetaModelHelper.getSelection(selectItems, dataSet);

		if (query.getMaxRows() != null) {
			dataSet = new DataSet(new MaxRowsDataSetStrategyWrapper(dataSet,
					query.getMaxRows()));
		}
		return dataSet;
	}

	public DataSet materializeFromItem(FromItem fromItem) {
		DataSet dataSet;
		JoinType joinType = fromItem.getJoin();
		if (fromItem.getTable() != null) {
			Table table = fromItem.getTable();
			Column[] columns = table.getColumns();
			Query query = fromItem.getQuery();
			if (query != null) {
				List selectItems = collectSelectItems(query
						.getSelectClause().getItems(), query.getWhereClause()
						.getEvaluatedSelectItems(), query.getHavingClause()
						.getEvaluatedSelectItems());
				List colsToMaterialize = new ArrayList();
				for (Iterator it = selectItems.iterator(); it
						.hasNext();) {
					SelectItem selectItem = it.next();
					Column column = selectItem.getColumn();
					if (column != null && column.getTable() != null
							&& column.getTable().equals(table)) {
						colsToMaterialize.add(column);
					}
				}
				selectItems = null;
				columns = colsToMaterialize
						.toArray(new Column[colsToMaterialize.size()]);
			}
			dataSet = materializeTable(table, columns, -1);
		} else if (joinType != null) {
			DataSet[] fromItemDataSets = new DataSet[2];
			fromItemDataSets[0] = materializeFromItem(fromItem.getLeftSide());
			fromItemDataSets[1] = materializeFromItem(fromItem.getRightSide());
			SelectItem[] leftOn = fromItem.getLeftOn();
			SelectItem[] rightOn = fromItem.getRightOn();
			FilterItem[] onConditions = new FilterItem[leftOn.length];
			for (int i = 0; i < onConditions.length; i++) {
				FilterItem whereItem = new FilterItem(leftOn[i],
						OperatorType.EQUALS_TO, rightOn[i]);
				onConditions[i] = whereItem;
			}
			if (joinType == JoinType.INNER) {
				dataSet = MetaModelHelper.getCarthesianProduct(
						fromItemDataSets, onConditions);
			} else if (joinType == JoinType.LEFT) {
				dataSet = MetaModelHelper.getLeftJoin(fromItemDataSets[0],
						fromItemDataSets[1], onConditions);
			} else if (joinType == JoinType.RIGHT) {
				dataSet = MetaModelHelper.getRightJoin(fromItemDataSets[0],
						fromItemDataSets[1], onConditions);
			} else {
				throw new IllegalArgumentException(
						"FromItem type not supported: " + fromItem);
			}
		} else if (fromItem.getSubQuery() != null) {
			dataSet = executeQuery(fromItem.getSubQuery());
		} else {
			throw new IllegalArgumentException("FromItem type not supported: "
					+ fromItem);
		}
		return dataSet;
	}

	private List collectSelectItems(
			List selectClauseItems,
			List whereClauseItems,
			List havingClauseItems) {
		ArrayList result = new ArrayList(
				selectClauseItems);
		for (SelectItem selectItem : whereClauseItems) {
			if (!result.contains(selectItem)) {
				result.add(selectItem);
			}
		}
		for (SelectItem selectItem : havingClauseItems) {
			if (!result.contains(selectItem)) {
				result.add(selectItem);
			}
		}
		return result;
	}

	/**
	 * Executes a simple one-table query.
	 * 
	 * @param table
	 * @param columns
	 * @param maxRows
	 *            the maximum amount of rows needed or -1 if all rows are
	 *            wanted.
	 * @return
	 */
	public abstract DataSet materializeTable(Table table, Column[] columns,
			int maxRows);
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy