METAMODEL-1165: Fixed - added default_table alias table
authorKasper Sørensen <i.am.kasper.sorensen@gmail.com>
Thu, 2 Nov 2017 03:57:57 +0000 (20:57 -0700)
committerKasper Sørensen <i.am.kasper.sorensen@gmail.com>
Thu, 2 Nov 2017 03:57:57 +0000 (20:57 -0700)
Closes #165

45 files changed:
CHANGES.md
cassandra/src/main/java/org/apache/metamodel/cassandra/CassandraDataContext.java
core/src/main/java/org/apache/metamodel/AbstractDataContext.java
core/src/main/java/org/apache/metamodel/MetaModelHelper.java
core/src/main/java/org/apache/metamodel/QueryPostprocessDataContext.java
core/src/main/java/org/apache/metamodel/QueryPostprocessDelegate.java
core/src/main/java/org/apache/metamodel/create/AbstractTableCreationBuilder.java
core/src/main/java/org/apache/metamodel/query/SelectItem.java
core/src/main/java/org/apache/metamodel/schema/AliasTable.java [new file with mode: 0644]
core/src/main/java/org/apache/metamodel/schema/CompositeSchema.java
core/src/main/java/org/apache/metamodel/schema/DefaultTableAliasedSchema.java [new file with mode: 0644]
core/src/main/java/org/apache/metamodel/schema/MutableSchema.java
core/src/main/java/org/apache/metamodel/schema/WrappingSchema.java [new file with mode: 0644]
core/src/main/java/org/apache/metamodel/schema/WrappingTable.java [new file with mode: 0644]
core/src/test/java/org/apache/metamodel/MockDataContext.java
core/src/test/java/org/apache/metamodel/MockUpdateableDataContext.java
core/src/test/java/org/apache/metamodel/QueryPostprocessDataContextTest.java
core/src/test/java/org/apache/metamodel/intercept/InterceptableDataContextTest.java
core/src/test/java/org/apache/metamodel/query/FilterItemTest.java
couchdb/src/main/java/org/apache/metamodel/couchdb/CouchDbDataContext.java
csv/src/main/java/org/apache/metamodel/csv/CsvSchema.java
csv/src/main/java/org/apache/metamodel/csv/CsvUpdateCallback.java
csv/src/test/java/org/apache/metamodel/csv/CsvDataContextTest.java
csv/src/test/java/org/apache/metamodel/intercept/InterceptionCsvIntegrationTest.java
dynamodb/src/main/java/org/apache/metamodel/dynamodb/DynamoDbDataContext.java
elasticsearch/native/src/main/java/org/apache/metamodel/elasticsearch/nativeclient/ElasticSearchDataContext.java
elasticsearch/rest/src/main/java/org/apache/metamodel/elasticsearch/rest/ElasticSearchRestDataContext.java
excel/src/main/java/org/apache/metamodel/excel/ExcelDataContext.java
excel/src/main/java/org/apache/metamodel/excel/ExcelTableCreationBuilder.java
excel/src/test/java/org/apache/metamodel/excel/ExcelDataContextTest.java
excel/src/test/java/org/apache/metamodel/excel/ExcelUpdateCallbackTest.java
fixedwidth/src/main/java/org/apache/metamodel/fixedwidth/FixedWidthDataContext.java
fixedwidth/src/test/java/org/apache/metamodel/fixedwidth/FixedWidthDataContextTest.java
hbase/src/main/java/org/apache/metamodel/hbase/HBaseDataContext.java
json/src/main/java/org/apache/metamodel/json/JsonDataContext.java
mongodb/mongo2/src/main/java/org/apache/metamodel/mongodb/mongo2/MongoDbDataContext.java
mongodb/mongo3/src/main/java/org/apache/metamodel/mongodb/mongo3/MongoDbDataContext.java
neo4j/src/main/java/org/apache/metamodel/neo4j/Neo4jDataContext.java
pojo/src/main/java/org/apache/metamodel/pojo/PojoDataContext.java
pojo/src/test/java/org/apache/metamodel/pojo/PojoDataContextTest.java
salesforce/src/main/java/org/apache/metamodel/salesforce/SalesforceDataContext.java
sugarcrm/src/main/java/org/apache/metamodel/sugarcrm/SugarCrmDataContext.java
xml/src/main/java/org/apache/metamodel/xml/XmlDomDataContext.java
xml/src/main/java/org/apache/metamodel/xml/XmlSaxDataContext.java
xml/src/test/java/org/apache/metamodel/xml/XmlDomDataContextTest.java

index b2ea491..ddd3c9a 100644 (file)
@@ -9,6 +9,7 @@
  * [METAMODEL-1139] - Employed Java 8 functional types (java.util.function) in favor of (now deprecated) Ref, Action, Func. 
  * [METAMODEL-1140] - Allowed SalesforceDataContext without a security token.
  * [METAMODEL-1141] - Added RFC 4180 compliant CSV parsing.
+ * [METAMODEL-1165] - Added a convenient alias table "default_table" for single-table data stores.
  * [METAMODEL-1144] - Optimized evaluation of conditional client-side JOIN statements.
  * [METAMODEL-1145] - Fixed bug with modelling JDBC table relationships when there are multiple keys involved in the relationship.
  * [METAMODEL-1151] - Added DataContextFactory classes for instantiating DataContexts of many types based on properties.
index 08d3fd9..88c4b67 100644 (file)
@@ -87,6 +87,7 @@ public class CassandraDataContext extends QueryPostprocessDataContext implements
      *            and column model of the ElasticSearch index.
      */
     public CassandraDataContext(Cluster cluster, String keySpace, SimpleTableDef... tableDefs) {
+        super(false);
         this.cassandraCluster = cluster;
         this.keySpaceName = keySpace;
         this.tableDefs = tableDefs;
index 475add4..c098167 100644 (file)
@@ -34,10 +34,11 @@ import org.apache.metamodel.query.parser.QueryParser;
 import org.apache.metamodel.schema.Column;
 import org.apache.metamodel.schema.Schema;
 import org.apache.metamodel.schema.Table;
+import org.apache.metamodel.schema.TableType;
 
 /**
- * Abstract implementation of the DataContext interface. Provides convenient
- * implementations of all trivial and datastore-independent methods.
+ * Abstract implementation of the DataContext interface. Provides convenient implementations of all trivial and
+ * datastore-independent methods.
  */
 public abstract class AbstractDataContext implements DataContext {
 
@@ -58,9 +59,8 @@ public abstract class AbstractDataContext implements DataContext {
     }
 
     /**
-     * Method invoked when schemas have been refreshed using
-     * {@link #refreshSchemas()}. Can be overridden to add callback
-     * functionality in subclasses.
+     * Method invoked when schemas have been refreshed using {@link #refreshSchemas()}. Can be overridden to add
+     * callback functionality in subclasses.
      */
     protected void onSchemaCacheRefreshed() {
     }
@@ -72,7 +72,7 @@ public abstract class AbstractDataContext implements DataContext {
     public final List<Schema> getSchemas() throws MetaModelException {
         List<String> schemaNames = getSchemaNames();
         List<Schema> schemas = new ArrayList<>();
-        for (final String name: schemaNames) {
+        for (final String name : schemaNames) {
             final Schema schema = _schemaCache.get(getSchemaCacheKey(name));
             if (schema == null) {
                 final Schema newSchema = getSchemaByName(name);
@@ -128,7 +128,7 @@ public abstract class AbstractDataContext implements DataContext {
                 result = schemas.get(0);
             } else {
                 int highestTableCount = -1;
-                for (Schema schema: schemas) {
+                for (Schema schema : schemas) {
                     String name = schema.getName();
                     if (schema != null) {
                         name = name.toLowerCase();
@@ -299,13 +299,10 @@ public abstract class AbstractDataContext implements DataContext {
     /**
      * Searches for a particular column within a schema
      * 
-     * @param schemaNameSearch
-     *            the schema name to use for search
-     * @param columnNameOriginal
-     *            the original column name
-     * @param columnNameSearch
-     *            the column name as it should be searched for (either the same
-     *            as original, or lower case in case of case-insensitive search)
+     * @param schemaNameSearch the schema name to use for search
+     * @param columnNameOriginal the original column name
+     * @param columnNameSearch the column name as it should be searched for (either the same as original, or lower case
+     *            in case of case-insensitive search)
      * @return
      */
     private Column searchColumn(String schemaNameSearch, String columnNameOriginal, String columnNameSearch) {
@@ -365,7 +362,7 @@ public abstract class AbstractDataContext implements DataContext {
             }
         }
 
-        if (table == null && tableNames.size() == 1) {
+        if (table == null && schema.getTables().stream().filter(t -> t.getType() != TableType.ALIAS).count() == 1) {
             table = schema.getTables().get(0);
         }
 
@@ -536,9 +533,8 @@ public abstract class AbstractDataContext implements DataContext {
     }
 
     /**
-     * Gets schema names from the non-abstract implementation. These schema
-     * names will be cached except if the {@link #refreshSchemas()} method is
-     * called.
+     * Gets schema names from the non-abstract implementation. These schema names will be cached except if the
+     * {@link #refreshSchemas()} method is called.
      * 
      * @return an array of schema names.
      */
@@ -552,14 +548,11 @@ public abstract class AbstractDataContext implements DataContext {
     protected abstract String getDefaultSchemaName();
 
     /**
-     * Gets a specific schema from the non-abstract implementation. This schema
-     * object will be cached except if the {@link #refreshSchemas()} method is
-     * called.
+     * Gets a specific schema from the non-abstract implementation. This schema object will be cached except if the
+     * {@link #refreshSchemas()} method is called.
      * 
-     * @param name
-     *            the name of the schema to get
-     * @return a schema object representing the named schema, or null if no such
-     *         schema exists.
+     * @param name the name of the schema to get
+     * @return a schema object representing the named schema, or null if no such schema exists.
      */
     protected abstract Schema getSchemaByNameInternal(String name);
 }
\ No newline at end of file
index 4c705ff..2b547da 100644 (file)
  */
 package org.apache.metamodel;
 
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
 import java.util.Map.Entry;
+import java.util.Set;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
-
 import org.apache.metamodel.data.CachingDataSetHeader;
 import org.apache.metamodel.data.DataSet;
 import org.apache.metamodel.data.DataSetHeader;
@@ -51,6 +60,8 @@ import org.apache.metamodel.schema.ColumnType;
 import org.apache.metamodel.schema.Schema;
 import org.apache.metamodel.schema.SuperColumnType;
 import org.apache.metamodel.schema.Table;
+import org.apache.metamodel.schema.WrappingSchema;
+import org.apache.metamodel.schema.WrappingTable;
 import org.apache.metamodel.util.AggregateBuilder;
 import org.apache.metamodel.util.CollectionUtils;
 import org.apache.metamodel.util.ObjectComparator;
@@ -58,18 +69,17 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 /**
- * This class contains various helper functionality to common tasks in
- * MetaModel, eg.:
+ * This class contains various helper functionality to common tasks in MetaModel, eg.:
  * 
  * <ul>
  * <li>Easy-access for traversing common schema items</li>
- * <li>Manipulate data in memory. These methods are primarily used to enable
- * queries for non-queryable data sources like CSV files and spreadsheets.</li>
+ * <li>Manipulate data in memory. These methods are primarily used to enable queries for non-queryable data sources like
+ * CSV files and spreadsheets.</li>
  * <li>Query rewriting, traversing and manipulation.</li>
  * </ul>
  * 
- * The class is mainly intended for internal use within the framework
- * operations, but is kept stable, so it can also be used by framework users.
+ * The class is mainly intended for internal use within the framework operations, but is kept stable, so it can also be
+ * used by framework users.
  */
 public final class MetaModelHelper {
 
@@ -80,8 +90,7 @@ public final class MetaModelHelper {
     }
 
     /**
-     * Creates an array of tables where all occurences of tables in the provided
-     * list of tables and columns are included
+     * Creates an array of tables where all occurences of tables in the provided list of tables and columns are included
      */
     public static Table[] getTables(Collection<Table> tableList, Iterable<Column> columnList) {
         HashSet<Table> set = new HashSet<Table>();
@@ -119,8 +128,7 @@ public final class MetaModelHelper {
     /**
      * Converts a list of columns to a corresponding array of tables
      * 
-     * @param columns
-     *            the columns that the tables will be extracted from
+     * @param columns the columns that the tables will be extracted from
      * @return an array containing the tables of the provided columns.
      */
     public static Table[] getTables(Iterable<Column> columns) {
@@ -135,8 +143,7 @@ public final class MetaModelHelper {
     }
 
     /**
-     * Creates a subset array of columns, where only columns that are contained
-     * within the specified table are included.
+     * Creates a subset array of columns, where only columns that are contained within the specified table are included.
      * 
      * @param table
      * @param columns
@@ -157,8 +164,7 @@ public final class MetaModelHelper {
     }
 
     /**
-     * Creates a subset array of columns, where only columns that are contained
-     * within the specified table are included.
+     * Creates a subset array of columns, where only columns that are contained within the specified table are included.
      * 
      * @param table
      * @param columns
@@ -185,7 +191,6 @@ public final class MetaModelHelper {
         // do a nested loop join, no matter what
         Iterator<DataSet> dsIter = Arrays.asList(fromDataSets).iterator();
 
-
         DataSet joined = dsIter.next();
 
         while (dsIter.hasNext()) {
@@ -198,8 +203,7 @@ public final class MetaModelHelper {
     }
 
     /**
-     * Executes a simple nested loop join. The innerLoopDs will be copied in an
-     * in-memory dataset.
+     * Executes a simple nested loop join. The innerLoopDs will be copied in an in-memory dataset.
      *
      */
     public static InMemoryDataSet nestedLoopJoin(DataSet innerLoopDs, DataSet outerLoopDs,
@@ -225,8 +229,8 @@ public final class MetaModelHelper {
                 Object[] joinedRowObjects = new Object[outerRow.getValues().length + innerRow.getValues().length];
 
                 System.arraycopy(outerRow.getValues(), 0, joinedRowObjects, 0, outerRow.getValues().length);
-                System.arraycopy(innerRow.getValues(), 0, joinedRowObjects, outerRow.getValues().length, innerRow
-                        .getValues().length);
+                System.arraycopy(innerRow.getValues(), 0, joinedRowObjects, outerRow.getValues().length,
+                        innerRow.getValues().length);
 
                 Row joinedRow = new DefaultRow(jointHeader, joinedRowObjects);
 
@@ -240,8 +244,8 @@ public final class MetaModelHelper {
     }
 
     /**
-     * Filters the FilterItems such that only the FilterItems are returned,
-     * which contain SelectItems that are contained in selectItemList
+     * Filters the FilterItems such that only the FilterItems are returned, which contain SelectItems that are contained
+     * in selectItemList
      * 
      * @param filters
      * @param selectItemList
@@ -293,8 +297,8 @@ public final class MetaModelHelper {
 
         for (SelectItem selectItem : selectItems) {
             if (selectItem.getScalarFunction() != null) {
-                if (!dataSetSelectItems.contains(selectItem) && dataSetSelectItems.contains(selectItem.replaceFunction(
-                        null))) {
+                if (!dataSetSelectItems.contains(selectItem)
+                        && dataSetSelectItems.contains(selectItem.replaceFunction(null))) {
                     scalarFunctionSelectItemsToEvaluate.add(selectItem);
                 }
             }
@@ -304,8 +308,8 @@ public final class MetaModelHelper {
             return new SubSelectionDataSet(selectItems, dataSet);
         }
 
-        final ScalarFunctionDataSet scalaFunctionDataSet = new ScalarFunctionDataSet(
-                scalarFunctionSelectItemsToEvaluate, dataSet);
+        final ScalarFunctionDataSet scalaFunctionDataSet =
+                new ScalarFunctionDataSet(scalarFunctionSelectItemsToEvaluate, dataSet);
         return new SubSelectionDataSet(selectItems, scalaFunctionDataSet);
     }
 
@@ -318,9 +322,8 @@ public final class MetaModelHelper {
         if (groupByItems != null && groupByItems.size() > 0) {
             Map<Row, Map<SelectItem, List<Object>>> uniqueRows = new HashMap<Row, Map<SelectItem, List<Object>>>();
 
-            final List<SelectItem> groupBySelects = groupByItems.stream()
-                    .map(gbi -> gbi.getSelectItem())
-                    .collect(Collectors.toList());
+            final List<SelectItem> groupBySelects =
+                    groupByItems.stream().map(gbi -> gbi.getSelectItem()).collect(Collectors.toList());
             final DataSetHeader groupByHeader = new CachingDataSetHeader(groupBySelects);
 
             // Creates a list of SelectItems that have aggregate functions
@@ -413,13 +416,10 @@ public final class MetaModelHelper {
     }
 
     /**
-     * Applies aggregate values to a dataset. This method is to be invoked AFTER
-     * any filters have been applied.
+     * Applies aggregate values to a dataset. This method is to be invoked AFTER any filters have been applied.
      * 
-     * @param workSelectItems
-     *            all select items included in the processing of the query
-     *            (including those originating from other clauses than the
-     *            SELECT clause).
+     * @param workSelectItems all select items included in the processing of the query (including those originating from
+     *            other clauses than the SELECT clause).
      * @param dataSet
      * @return
      */
@@ -595,12 +595,10 @@ public final class MetaModelHelper {
     }
 
     /**
-     * Examines a query and extracts an array of FromItem's that refer
-     * (directly) to tables (hence Joined FromItems and SubQuery FromItems are
-     * traversed but not included).
+     * Examines a query and extracts an array of FromItem's that refer (directly) to tables (hence Joined FromItems and
+     * SubQuery FromItems are traversed but not included).
      * 
-     * @param q
-     *            the query to examine
+     * @param q the query to examine
      * @return an array of FromItem's that refer directly to tables
      */
     public static FromItem[] getTableFromItems(Query q) {
@@ -633,16 +631,12 @@ public final class MetaModelHelper {
     }
 
     /**
-     * Executes a single row query, like "SELECT COUNT(*), MAX(SOME_COLUMN) FROM
-     * MY_TABLE" or similar.
+     * Executes a single row query, like "SELECT COUNT(*), MAX(SOME_COLUMN) FROM MY_TABLE" or similar.
      * 
-     * @param dataContext
-     *            the DataContext object to use for executing the query
-     * @param query
-     *            the query to execute
+     * @param dataContext the DataContext object to use for executing the query
+     * @param query the query to execute
      * @return a row object representing the single row returned from the query
-     * @throws MetaModelException
-     *             if less or more than one Row is returned from the query
+     * @throws MetaModelException if less or more than one Row is returned from the query
      */
     public static Row executeSingleRowQuery(DataContext dataContext, Query query) throws MetaModelException {
         DataSet dataSet = dataContext.executeQuery(query);
@@ -662,12 +656,9 @@ public final class MetaModelHelper {
     /**
      * Performs a left join (aka left outer join) operation on two datasets.
      * 
-     * @param ds1
-     *            the left dataset
-     * @param ds2
-     *            the right dataset
-     * @param onConditions
-     *            the conditions to join by
+     * @param ds1 the left dataset
+     * @param ds2 the right dataset
+     * @param onConditions the conditions to join by
      * @return the left joined result dataset
      */
     public static DataSet getLeftJoin(DataSet ds1, DataSet ds2, FilterItem[] onConditions) {
@@ -679,7 +670,7 @@ public final class MetaModelHelper {
         }
         List<SelectItem> si1 = ds1.getSelectItems();
         List<SelectItem> si2 = ds2.getSelectItems();
-        List<SelectItem> selectItems = Stream.concat(si1.stream(),si2.stream()).collect(Collectors.toList());
+        List<SelectItem> selectItems = Stream.concat(si1.stream(), si2.stream()).collect(Collectors.toList());
         List<Row> resultRows = new ArrayList<Row>();
         List<Row> ds2data = readDataSetFull(ds2);
         if (ds2data.isEmpty()) {
@@ -698,9 +689,9 @@ public final class MetaModelHelper {
             List<Row> ds1rows = new ArrayList<Row>();
             ds1rows.add(ds1row);
 
-            DataSet carthesianProduct = getCarthesianProduct(new DataSet[] { new InMemoryDataSet(
-                    new CachingDataSetHeader(si1), ds1rows), new InMemoryDataSet(new CachingDataSetHeader(si2),
-                            ds2data) }, onConditions);
+            DataSet carthesianProduct =
+                    getCarthesianProduct(new DataSet[] { new InMemoryDataSet(new CachingDataSetHeader(si1), ds1rows),
+                            new InMemoryDataSet(new CachingDataSetHeader(si2), ds2data) }, onConditions);
             List<Row> carthesianRows = readDataSetFull(carthesianProduct);
             if (carthesianRows.size() > 0) {
                 resultRows.addAll(carthesianRows);
@@ -723,12 +714,9 @@ public final class MetaModelHelper {
     /**
      * Performs a right join (aka right outer join) operation on two datasets.
      * 
-     * @param ds1
-     *            the left dataset
-     * @param ds2
-     *            the right dataset
-     * @param onConditions
-     *            the conditions to join by
+     * @param ds1 the left dataset
+     * @param ds2 the right dataset
+     * @param onConditions the conditions to join by
      * @return the right joined result dataset
      */
     public static DataSet getRightJoin(DataSet ds1, DataSet ds2, FilterItem[] onConditions) {
@@ -756,9 +744,7 @@ public final class MetaModelHelper {
 
     public static DataSet getDistinct(DataSet dataSet) {
         List<SelectItem> selectItems = dataSet.getSelectItems();
-        List<GroupByItem> groupByItems = selectItems.stream()
-                .map(GroupByItem::new)
-                .collect(Collectors.toList());
+        List<GroupByItem> groupByItems = selectItems.stream().map(GroupByItem::new).collect(Collectors.toList());
 
         return getGrouped(selectItems, dataSet, groupByItems);
     }
@@ -836,11 +822,10 @@ public final class MetaModelHelper {
     }
 
     /**
-     * Determines if a query contains {@link ScalarFunction}s in any clause of
-     * the query EXCEPT for the SELECT clause. This is a handy thing to
-     * determine because decorating with {@link ScalarFunctionDataSet} only
-     * gives you select-item evaluation so if the rest of the query is pushed to
-     * an underlying datastore, then it may create issues.
+     * Determines if a query contains {@link ScalarFunction}s in any clause of the query EXCEPT for the SELECT clause.
+     * This is a handy thing to determine because decorating with {@link ScalarFunctionDataSet} only gives you
+     * select-item evaluation so if the rest of the query is pushed to an underlying datastore, then it may create
+     * issues.
      * 
      * @param query
      * @return
@@ -883,4 +868,23 @@ public final class MetaModelHelper {
 
         return false;
     }
+
+    public static Table resolveTable(FromItem fromItem) {
+        final Table table = fromItem.getTable();
+        return resolveUnderlyingTable(table);
+    }
+
+    public static Table resolveUnderlyingTable(Table table) {
+        while (table instanceof WrappingTable) {
+            table = ((WrappingTable) table).getWrappedTable();
+        }
+        return table;
+    }
+
+    public static Schema resolveUnderlyingSchema(Schema schema) {
+        while (schema instanceof WrappingSchema) {
+            schema = ((WrappingSchema) schema).getWrappedSchema();
+        }
+        return schema;
+    }
 }
\ No newline at end of file
index cbd97d3..c77479b 100644 (file)
@@ -50,6 +50,7 @@ import org.apache.metamodel.query.SelectClause;
 import org.apache.metamodel.query.SelectItem;
 import org.apache.metamodel.schema.Column;
 import org.apache.metamodel.schema.ColumnType;
+import org.apache.metamodel.schema.DefaultTableAliasedSchema;
 import org.apache.metamodel.schema.MutableColumn;
 import org.apache.metamodel.schema.MutableRelationship;
 import org.apache.metamodel.schema.MutableSchema;
@@ -63,24 +64,37 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 /**
- * Abstract DataContext for data sources that do not support SQL queries
- * natively.
+ * Abstract DataContext for data sources that do not support SQL queries natively.
  * 
- * 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
- * the datasets client-side.
+ * 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 the datasets client-side.
  */
 public abstract class QueryPostprocessDataContext extends AbstractDataContext implements HasReadTypeConverters {
 
     private static final Logger logger = LoggerFactory.getLogger(QueryPostprocessDataContext.class);
 
+    public static final String SYSTEM_PROPERTY_CREATE_DEFAULT_TABLE_ALIAS = "metamodel.alias.default.table";
     public static final String INFORMATION_SCHEMA_NAME = "information_schema";
 
-    private final Map<Column, TypeConverter<?, ?>> _converters;
+    private final Map<Column, TypeConverter<?, ?>> converters;
+    private final boolean singleTableDatastore;
 
     public QueryPostprocessDataContext() {
+        this(true);
+    }
+
+    /**
+     * 
+     * @param singleTableDatastore a flag that, if set to true, indicates that this DataContext contains just a single
+     *            table. This information will be used to optimize and provide convenience for the implementation. An
+     *            additional {@link Table} of type {@link TableType#ALIAS} with the name "default_table" will be
+     *            automatically added in addition to the single table. That again makes for convenient querying of the
+     *            single table using a predictable name/alias.
+     */
+    public QueryPostprocessDataContext(boolean singleTableDatastore) {
         super();
-        _converters = new HashMap<Column, TypeConverter<?, ?>>();
+        this.singleTableDatastore = singleTableDatastore;
+        this.converters = new HashMap<Column, TypeConverter<?, ?>>();
     }
 
     @Override
@@ -112,7 +126,7 @@ public abstract class QueryPostprocessDataContext extends AbstractDataContext im
         if (singleFromItem && noGrouping) {
 
             final FromItem fromItem = query.getFromClause().getItem(0);
-            final Table table = fromItem.getTable();
+            final Table table = MetaModelHelper.resolveTable(fromItem);
             if (table != null) {
 
                 // check for SELECT COUNT(*) queries
@@ -128,7 +142,7 @@ public abstract class QueryPostprocessDataContext extends AbstractDataContext im
                                 logger.debug(
                                         "DataContext did not return any count query results. Proceeding with manual counting.");
                             } else {
-                                List<Row> data = new ArrayList<Row>(1);
+                                final List<Row> data = new ArrayList<Row>(1);
                                 final DataSetHeader header = new SimpleDataSetHeader(new SelectItem[] { selectItem });
                                 data.add(new DefaultRow(header, new Object[] { count }));
                                 return new InMemoryDataSet(header, data);
@@ -151,8 +165,8 @@ public abstract class QueryPostprocessDataContext extends AbstractDataContext im
                                 if (table != null) {
                                     if (isMainSchemaTable(table)) {
                                         final Object operand = whereItem.getOperand();
-                                        final Row row = executePrimaryKeyLookupQuery(table, selectItems, column,
-                                                operand);
+                                        final Row row =
+                                                executePrimaryKeyLookupQuery(table, selectItems, column, operand);
                                         if (row == null) {
                                             logger.debug(
                                                     "DataContext did not return any GET query results. Proceeding with manual lookup.");
@@ -192,8 +206,8 @@ public abstract class QueryPostprocessDataContext extends AbstractDataContext im
 
         // we can now exclude the select items imposed by the WHERE clause (and
         // should, to make the aggregation process faster)
-        workSelectItems = CollectionUtils.concat(true, selectItems, groupBySelectItems, havingSelectItems,
-                orderBySelectItems);
+        workSelectItems =
+                CollectionUtils.concat(true, selectItems, groupBySelectItems, havingSelectItems, orderBySelectItems);
 
         if (groupByItems.size() > 0) {
             dataSet = MetaModelHelper.getGrouped(workSelectItems, dataSet, groupByItems);
@@ -216,8 +230,7 @@ public abstract class QueryPostprocessDataContext extends AbstractDataContext im
     }
 
     /**
-     * Determines if all the select items are 'simple' meaning that they just
-     * represent scans of values in columns.
+     * Determines if all the select items are 'simple' meaning that they just represent scans of values in columns.
      *
      * @param clause
      * @return
@@ -235,17 +248,13 @@ public abstract class QueryPostprocessDataContext extends AbstractDataContext im
     }
 
     /**
-     * Executes a simple count query, if possible. This method is provided to
-     * allow subclasses to optimize count queries since they are quite common
-     * and often a datastore can retrieve the count using some specialized means
-     * which is much more performant than counting all records manually.
+     * Executes a simple count query, if possible. This method is provided to allow subclasses to optimize count queries
+     * since they are quite common and often a datastore can retrieve the count using some specialized means which is
+     * much more performant than counting all records manually.
      * 
-     * @param table
-     *            the table on which the count is requested.
-     * @param whereItems
-     *            a (sometimes empty) list of WHERE items.
-     * @param functionApproximationAllowed
-     *            whether approximation is allowed or not.
+     * @param table the table on which the count is requested.
+     * @param whereItems a (sometimes empty) list of WHERE items.
+     * @param functionApproximationAllowed whether approximation is allowed or not.
      * @return the count of the particular table, or null if not available.
      */
     protected Number executeCountQuery(Table table, List<FilterItem> whereItems, boolean functionApproximationAllowed) {
@@ -253,20 +262,14 @@ public abstract class QueryPostprocessDataContext extends AbstractDataContext im
     }
 
     /**
-     * Executes a query which obtains a row by primary key (as defined by
-     * {@link Column#isPrimaryKey()}). This method is provided to allow
-     * subclasses to optimize lookup queries since they are quite common and
-     * often a datastore can retrieve the row using some specialized means which
-     * is much more performant than scanning all records manually.
+     * Executes a query which obtains a row by primary key (as defined by {@link Column#isPrimaryKey()}). This method is
+     * provided to allow subclasses to optimize lookup queries since they are quite common and often a datastore can
+     * retrieve the row using some specialized means which is much more performant than scanning all records manually.
      * 
-     * @param table
-     *            the table on which the lookup is requested.
-     * @param selectItems
-     *            the items to select from the lookup query.
-     * @param primaryKeyColumn
-     *            the column that is the primary key
-     * @param keyValue
-     *            the primary key value that is specified in the lookup query.
+     * @param table the table on which the lookup is requested.
+     * @param selectItems the items to select from the lookup query.
+     * @param primaryKeyColumn the column that is the primary key
+     * @param keyValue the primary key value that is specified in the lookup query.
      * @return the row if the particular table, or null if not available.
      */
     protected Row executePrimaryKeyLookupQuery(Table table, List<SelectItem> selectItems, Column primaryKeyColumn,
@@ -279,7 +282,7 @@ public abstract class QueryPostprocessDataContext extends AbstractDataContext im
         JoinType joinType = fromItem.getJoin();
         if (fromItem.getTable() != null) {
             // We need to materialize a single table
-            final Table table = fromItem.getTable();
+            final Table table = MetaModelHelper.resolveTable(fromItem);
             final List<SelectItem> selectItemsToMaterialize = new ArrayList<SelectItem>();
 
             for (final SelectItem selectItem : selectItems) {
@@ -319,13 +322,13 @@ public abstract class QueryPostprocessDataContext extends AbstractDataContext im
 
             // materialize left side
             final List<SelectItem> leftOn = Arrays.asList(fromItem.getLeftOn());
-            fromItemDataSets[0] = materializeFromItem(fromItem.getLeftSide(),
-                    CollectionUtils.concat(true, selectItems, leftOn));
+            fromItemDataSets[0] =
+                    materializeFromItem(fromItem.getLeftSide(), CollectionUtils.concat(true, selectItems, leftOn));
 
             // materialize right side
             final List<SelectItem> rightOn = Arrays.asList(fromItem.getRightOn());
-            fromItemDataSets[1] = materializeFromItem(fromItem.getRightSide(),
-                    CollectionUtils.concat(true, selectItems, rightOn));
+            fromItemDataSets[1] =
+                    materializeFromItem(fromItem.getRightSide(), CollectionUtils.concat(true, selectItems, rightOn));
 
             final FilterItem[] onConditions = new FilterItem[leftOn.size()];
             for (int i = 0; i < onConditions.length; i++) {
@@ -385,8 +388,8 @@ public abstract class QueryPostprocessDataContext extends AbstractDataContext im
 
         final DataSet dataSet;
         if (INFORMATION_SCHEMA_NAME.equals(schemaName)) {
-            DataSet informationDataSet = materializeInformationSchemaTable(table,
-                    buildWorkingSelectItems(selectItems, whereItems));
+            DataSet informationDataSet =
+                    materializeInformationSchemaTable(table, buildWorkingSelectItems(selectItems, whereItems));
             informationDataSet = MetaModelHelper.getFiltered(informationDataSet, whereItems);
             informationDataSet = MetaModelHelper.getSelection(selectItems, informationDataSet);
             informationDataSet = MetaModelHelper.getPaged(informationDataSet, firstRow, maxRows);
@@ -396,7 +399,7 @@ public abstract class QueryPostprocessDataContext extends AbstractDataContext im
 
             // conversion is done at materialization time, since it enables
             // the refined types to be used also in eg. where clauses.
-            dataSet = new ConvertedDataSetInterceptor(_converters).intercept(tableDataSet);
+            dataSet = new ConvertedDataSetInterceptor(converters).intercept(tableDataSet);
         }
 
         return dataSet;
@@ -418,13 +421,11 @@ public abstract class QueryPostprocessDataContext extends AbstractDataContext im
     }
 
     /**
-     * Determines if the subclass of this class can materialize
-     * {@link SelectItem}s with the given {@link ScalarFunction}. Usually scalar
-     * functions are applied by MetaModel on the client side, but when possible
-     * they can also be handled by e.g.
-     * {@link #materializeMainSchemaTable(Table, List, int, int)} and
-     * {@link #materializeMainSchemaTable(Table, List, List, int, int)} in which
-     * case MetaModel will not evaluate it client-side.
+     * Determines if the subclass of this class can materialize {@link SelectItem}s with the given
+     * {@link ScalarFunction}. Usually scalar functions are applied by MetaModel on the client side, but when possible
+     * they can also be handled by e.g. {@link #materializeMainSchemaTable(Table, List, int, int)} and
+     * {@link #materializeMainSchemaTable(Table, List, List, int, int)} in which case MetaModel will not evaluate it
+     * client-side.
      * 
      * @param function
      * @return
@@ -458,15 +459,18 @@ public abstract class QueryPostprocessDataContext extends AbstractDataContext im
     @Override
     protected final Schema getSchemaByNameInternal(final String name) throws MetaModelException {
         final String mainSchemaName = getMainSchemaName();
-        if (name == null) {
-            if (mainSchemaName == null) {
-                return getMainSchema();
-            }
+        if (name == null && mainSchemaName != null) {
             return null;
         }
 
-        if (name.equalsIgnoreCase(mainSchemaName)) {
-            return getMainSchema();
+        if (name == null || name.equalsIgnoreCase(mainSchemaName)) {
+            final Schema mainSchema = getMainSchema();
+            final boolean createAliasTable = singleTableDatastore
+                    && Boolean.parseBoolean(System.getProperty(SYSTEM_PROPERTY_CREATE_DEFAULT_TABLE_ALIAS, "true"));
+            if (createAliasTable) {
+                return DefaultTableAliasedSchema.wrapIfAppropriate(mainSchema);
+            }
+            return mainSchema;
         } else if (name.equals(INFORMATION_SCHEMA_NAME)) {
             return getInformationSchema();
         }
@@ -528,9 +532,8 @@ public abstract class QueryPostprocessDataContext extends AbstractDataContext im
 
     private DataSet materializeInformationSchemaTable(final Table table, final List<SelectItem> selectItems) {
         final String tableName = table.getName();
-        final List<SelectItem> columnSelectItems = table.getColumns().stream()
-                .map(SelectItem::new)
-                .collect(Collectors.toList());
+        final List<SelectItem> columnSelectItems =
+                table.getColumns().stream().map(SelectItem::new).collect(Collectors.toList());
         final SimpleDataSetHeader header = new SimpleDataSetHeader(columnSelectItems);
         final List<Table> tables = getDefaultSchema().getTables();
         final List<Row> data = new ArrayList<Row>();
@@ -591,15 +594,14 @@ public abstract class QueryPostprocessDataContext extends AbstractDataContext im
     }
 
     /**
-     * Adds a {@link TypeConverter} to this DataContext's query engine (Query
-     * Postprocessor) for read operations. Note that this method should NOT be
-     * invoked directly by consuming code. Rather use
-     * {@link Converters#addTypeConverter(DataContext, Column, TypeConverter)}
-     * to ensure conversion on both reads and writes.
+     * Adds a {@link TypeConverter} to this DataContext's query engine (Query Postprocessor) for read operations. Note
+     * that this method should NOT be invoked directly by consuming code. Rather use
+     * {@link Converters#addTypeConverter(DataContext, Column, TypeConverter)} to ensure conversion on both reads and
+     * writes.
      */
     @Override
     public void addConverter(Column column, TypeConverter<?, ?> converter) {
-        _converters.put(column, converter);
+        converters.put(column, converter);
     }
 
     /**
@@ -613,10 +615,9 @@ public abstract class QueryPostprocessDataContext extends AbstractDataContext im
     protected abstract String getMainSchemaName() throws MetaModelException;
 
     /**
-     * Execute a simple one-table query against a table in the main schema of
-     * the subclasses of this class. This default implementation will delegate
-     * to {@link #materializeMainSchemaTable(Table, List, int, int)} and apply
-     * WHERE item filtering afterwards.
+     * Execute a simple one-table query against a table in the main schema of the subclasses of this class. This default
+     * implementation will delegate to {@link #materializeMainSchemaTable(Table, List, int, int)} and apply WHERE item
+     * filtering afterwards.
      * 
      * @param table
      * @param selectItems
@@ -644,9 +645,8 @@ public abstract class QueryPostprocessDataContext extends AbstractDataContext im
     }
 
     /**
-     * Executes a simple one-table query against a table in the main schema of
-     * the subclasses of this class. This default implementation will delegate
-     * to {@link #materializeMainSchemaTable(Table, List, int, int)}.
+     * Executes a simple one-table query against a table in the main schema of the subclasses of this class. This
+     * default implementation will delegate to {@link #materializeMainSchemaTable(Table, List, int, int)}.
      *
      * @param table
      * @param selectItems
@@ -654,10 +654,9 @@ public abstract class QueryPostprocessDataContext extends AbstractDataContext im
      * @param maxRows
      * @return
      */
-    protected DataSet materializeMainSchemaTableSelect(Table table, List<SelectItem> selectItems, int firstRow, int maxRows) {
-        List<Column> columns = selectItems.stream()
-                .map(si -> si.getColumn())
-                .collect(Collectors.toList());
+    protected DataSet materializeMainSchemaTableSelect(Table table, List<SelectItem> selectItems, int firstRow,
+            int maxRows) {
+        List<Column> columns = selectItems.stream().map(si -> si.getColumn()).collect(Collectors.toList());
 
         DataSet dataSet = materializeMainSchemaTable(table, columns, firstRow, maxRows);
 
@@ -667,9 +666,8 @@ public abstract class QueryPostprocessDataContext extends AbstractDataContext im
     }
 
     /**
-     * Executes a simple one-table query against a table in the main schema of
-     * the subclasses of this class. This default implementation will delegate
-     * to {@link #materializeMainSchemaTable(Table, List, int)} and apply a
+     * Executes a simple one-table query against a table in the main schema of the subclasses of this class. This
+     * default implementation will delegate to {@link #materializeMainSchemaTable(Table, List, int)} and apply a
      * {@link FirstRowDataSet} if necessary.
      * 
      * @param table
@@ -693,16 +691,11 @@ public abstract class QueryPostprocessDataContext extends AbstractDataContext im
     }
 
     /**
-     * Executes a simple one-table query against a table in the main schema of
-     * the subclasses of this class.
+     * Executes a simple one-table query against a table in the main schema of the subclasses of this class.
      * 
-     * @param table
-     *            the table to query
-     * @param columns
-     *            the columns of the table to query
-     * @param maxRows
-     *            the maximum amount of rows needed or -1 if all rows are
-     *            wanted.
+     * @param table the table to query
+     * @param columns the columns of the table to query
+     * @param maxRows the maximum amount of rows needed or -1 if all rows are wanted.
      * @return a dataset with the raw table/column content.
      */
     protected abstract DataSet materializeMainSchemaTable(Table table, List<Column> columns, int maxRows);
index 9e0e4dc..1c94ff9 100644 (file)
@@ -18,7 +18,7 @@
  */
 package org.apache.metamodel;
 
-import org.apache.metamodel.schema.Schema;
+import org.apache.metamodel.schema.MutableSchema;
 
 /**
  * A simple subclass of {@link QueryPostprocessDataContext} which provides less
@@ -27,6 +27,10 @@ import org.apache.metamodel.schema.Schema;
  */
 public abstract class QueryPostprocessDelegate extends
                QueryPostprocessDataContext {
+    
+    public QueryPostprocessDelegate() {
+        super(false);
+    }
 
        @Override
        protected String getMainSchemaName() throws MetaModelException {
@@ -35,7 +39,7 @@ public abstract class QueryPostprocessDelegate extends
        }
 
        @Override
-       protected Schema getMainSchema() throws MetaModelException {
+       protected MutableSchema getMainSchema() throws MetaModelException {
                throw new UnsupportedOperationException(
                                "QueryPostprocessDelegate cannot perform schema exploration");
        }
index 1833120..7ca7216 100644 (file)
@@ -18,6 +18,7 @@
  */
 package org.apache.metamodel.create;
 
+import org.apache.metamodel.MetaModelHelper;
 import org.apache.metamodel.UpdateCallback;
 import org.apache.metamodel.schema.Column;
 import org.apache.metamodel.schema.ColumnType;
@@ -50,7 +51,7 @@ public abstract class AbstractTableCreationBuilder<U extends UpdateCallback> imp
                     + schema);
         }
         _updateCallback = updateCallback;
-        _schema = schema;
+        _schema = MetaModelHelper.resolveUnderlyingSchema(schema);
         _table = new MutableTable(name, TableType.TABLE, schema);
     }
 
index df4b995..fec900d 100644 (file)
@@ -25,6 +25,7 @@ import org.apache.metamodel.schema.Column;
 import org.apache.metamodel.schema.ColumnType;
 import org.apache.metamodel.schema.Schema;
 import org.apache.metamodel.schema.Table;
+import org.apache.metamodel.schema.TableType;
 import org.apache.metamodel.util.BaseObject;
 import org.apache.metamodel.util.EqualsBuilder;
 import org.slf4j.Logger;
@@ -35,12 +36,11 @@ import org.slf4j.LoggerFactory;
  * <ul>
  * <li>column SELECTs (selects a column from a table)</li>
  * <li>column function SELECTs (aggregates the values of a column)</li>
- * <li>expression SELECTs (retrieves data based on an expression (only supported
- * for JDBC datastores)</li>
- * <li>expression function SELECTs (retrieves databased on a function and an
- * expression, only COUNT(*) is supported for non-JDBC datastores))</li>
- * <li>SELECTs from subqueries (works just like column selects, but in stead of
- * pointing to a column, it retrieves data from the select item of a subquery)</li>
+ * <li>expression SELECTs (retrieves data based on an expression (only supported for JDBC datastores)</li>
+ * <li>expression function SELECTs (retrieves databased on a function and an expression, only COUNT(*) is supported for
+ * non-JDBC datastores))</li>
+ * <li>SELECTs from subqueries (works just like column selects, but in stead of pointing to a column, it retrieves data
+ * from the select item of a subquery)</li>
  * </ul>
  * 
  * @see SelectClause
@@ -98,8 +98,8 @@ public class SelectItem extends BaseObject implements QueryItem, Cloneable {
     }
 
     public static boolean isCountAllItem(SelectItem item) {
-        if (item != null && item.getAggregateFunction() != null && item.getAggregateFunction().toString().equals("COUNT")
-                && item.getExpression() == "*") {
+        if (item != null && item.getAggregateFunction() != null
+                && item.getAggregateFunction().toString().equals("COUNT") && item.getExpression() == "*") {
             return true;
         }
         return false;
@@ -115,8 +115,7 @@ public class SelectItem extends BaseObject implements QueryItem, Cloneable {
     }
 
     /**
-     * Creates a SelectItem that uses a function on a column, for example
-     * SUM(price) or MAX(age)
+     * Creates a SelectItem that uses a function on a column, for example SUM(price) or MAX(age)
      * 
      * @param function
      * @param column
@@ -137,8 +136,7 @@ public class SelectItem extends BaseObject implements QueryItem, Cloneable {
     }
 
     /**
-     * Creates a SelectItem that references a column from a particular
-     * {@link FromItem}, for example a.price or p.age
+     * Creates a SelectItem that references a column from a particular {@link FromItem}, for example a.price or p.age
      * 
      * @param column
      * @param fromItem
@@ -147,7 +145,7 @@ public class SelectItem extends BaseObject implements QueryItem, Cloneable {
         this(null, column, fromItem);
         if (fromItem != null) {
             Table fromItemTable = fromItem.getTable();
-            if (fromItemTable != null) {
+            if (fromItemTable != null && fromItemTable.getType() != TableType.ALIAS) {
                 Table columnTable = column.getTable();
                 if (columnTable != null && !columnTable.equals(fromItemTable)) {
                     throw new IllegalArgumentException("Column's table '" + columnTable.getName()
@@ -158,8 +156,8 @@ public class SelectItem extends BaseObject implements QueryItem, Cloneable {
     }
 
     /**
-     * Creates a SelectItem that uses a function on a column from a particular
-     * {@link FromItem}, for example SUM(a.price) or MAX(p.age)
+     * Creates a SelectItem that uses a function on a column from a particular {@link FromItem}, for example
+     * SUM(a.price) or MAX(p.age)
      * 
      * @param function
      * @param column
@@ -173,9 +171,8 @@ public class SelectItem extends BaseObject implements QueryItem, Cloneable {
     }
 
     /**
-     * Creates a SelectItem that uses a function with parameters on a column
-     * from a particular {@link FromItem}, for example
-     * MAP_VALUE('path.to.value', doc)
+     * Creates a SelectItem that uses a function with parameters on a column from a particular {@link FromItem}, for
+     * example MAP_VALUE('path.to.value', doc)
      * 
      * @param function
      * @param functionParameters
@@ -190,8 +187,7 @@ public class SelectItem extends BaseObject implements QueryItem, Cloneable {
     }
 
     /**
-     * Creates a SelectItem based on an expression. All expression-based
-     * SelectItems must have aliases.
+     * Creates a SelectItem based on an expression. All expression-based SelectItems must have aliases.
      * 
      * @param expression
      * @param alias
@@ -201,8 +197,7 @@ public class SelectItem extends BaseObject implements QueryItem, Cloneable {
     }
 
     /**
-     * Creates a SelectItem based on a function and an expression. All
-     * expression-based SelectItems must have aliases.
+     * Creates a SelectItem based on a function and an expression. All expression-based SelectItems must have aliases.
      * 
      * @param function
      * @param expression
@@ -219,8 +214,7 @@ public class SelectItem extends BaseObject implements QueryItem, Cloneable {
      * Creates a SelectItem that references another select item in a subquery
      * 
      * @param subQuerySelectItem
-     * @param subQueryFromItem
-     *            the FromItem that holds the sub-query
+     * @param subQueryFromItem the FromItem that holds the sub-query
      */
     public SelectItem(SelectItem subQuerySelectItem, FromItem subQueryFromItem) {
         this(null, subQueryFromItem, null, null, null, subQuerySelectItem, null, false);
@@ -242,7 +236,7 @@ public class SelectItem extends BaseObject implements QueryItem, Cloneable {
         return this;
     }
 
-    public boolean hasFunction(){
+    public boolean hasFunction() {
         return _function != null;
     }
 
@@ -270,11 +264,9 @@ public class SelectItem extends BaseObject implements QueryItem, Cloneable {
     }
 
     /**
-     * @return if this is a function based SelectItem where function calculation
-     *         is allowed to be approximated (if the datastore type has an
-     *         approximate calculation method). Approximated function results
-     *         are as the name implies not exact, but might be valuable as an
-     *         optimization in some cases.
+     * @return if this is a function based SelectItem where function calculation is allowed to be approximated (if the
+     *         datastore type has an approximate calculation method). Approximated function results are as the name
+     *         implies not exact, but might be valuable as an optimization in some cases.
      */
     public boolean isFunctionApproximationAllowed() {
         return _functionApproximationAllowed;
@@ -289,9 +281,8 @@ public class SelectItem extends BaseObject implements QueryItem, Cloneable {
     }
 
     /**
-     * Tries to infer the {@link ColumnType} of this {@link SelectItem}. For
-     * expression based select items, this is not possible, and the method will
-     * return null.
+     * Tries to infer the {@link ColumnType} of this {@link SelectItem}. For expression based select items, this is not
+     * possible, and the method will return null.
      * 
      * @return
      */
@@ -313,9 +304,9 @@ public class SelectItem extends BaseObject implements QueryItem, Cloneable {
     }
 
     /**
-     * Returns an "expression" that this select item represents. Expressions are
-     * not necesarily portable across {@link DataContext} implementations, but
-     * may be useful for utilizing database-specific behaviour in certain cases.
+     * Returns an "expression" that this select item represents. Expressions are not necesarily portable across
+     * {@link DataContext} implementations, but may be useful for utilizing database-specific behaviour in certain
+     * cases.
      * 
      * @return
      */
@@ -341,23 +332,19 @@ public class SelectItem extends BaseObject implements QueryItem, Cloneable {
     }
 
     /**
-     * @return the name that this SelectItem can be referenced with, if
-     *         referenced from a super-query. This will usually be the alias,
-     *         but if there is no alias, then the column name will be used.
+     * @return the name that this SelectItem can be referenced with, if referenced from a super-query. This will usually
+     *         be the alias, but if there is no alias, then the column name will be used.
      */
     public String getSuperQueryAlias() {
         return getSuperQueryAlias(true);
     }
 
     /**
-     * @return the name that this SelectItem can be referenced with, if
-     *         referenced from a super-query. This will usually be the alias,
-     *         but if there is no alias, then the column name will be used.
+     * @return the name that this SelectItem can be referenced with, if referenced from a super-query. This will usually
+     *         be the alias, but if there is no alias, then the column name will be used.
      * 
-     * @param includeQuotes
-     *            indicates whether or not the output should include quotes, if
-     *            the select item's column has quotes associated (typically
-     *            true, but false if used for presentation)
+     * @param includeQuotes indicates whether or not the output should include quotes, if the select item's column has
+     *            quotes associated (typically true, but false if used for presentation)
      */
     public String getSuperQueryAlias(boolean includeQuotes) {
         if (_alias != null) {
@@ -391,8 +378,7 @@ public class SelectItem extends BaseObject implements QueryItem, Cloneable {
     }
 
     /**
-     * @return an alias that can be used in WHERE, GROUP BY and ORDER BY clauses
-     *         in the same query
+     * @return an alias that can be used in WHERE, GROUP BY and ORDER BY clauses in the same query
      */
     public String getSameQueryAlias(boolean includeSchemaInColumnPath) {
         if (_column != null) {
@@ -476,32 +462,38 @@ public class SelectItem extends BaseObject implements QueryItem, Cloneable {
     }
 
     private String getToStringColumnPrefix(boolean includeSchemaInColumnPath) {
-        final StringBuilder sb = new StringBuilder();
         if (_fromItem != null && _fromItem.getAlias() != null) {
-            sb.append(_fromItem.getAlias());
-            sb.append('.');
+            return _fromItem.getAlias() + '.';
+        }
+
+        final Table table;
+        if (_fromItem != null && _fromItem.getTable() != null) {
+            table = _fromItem.getTable();
         } else {
-            final Table table = _column.getTable();
-            String tableLabel;
-            if (_query == null) {
-                tableLabel = null;
-            } else {
-                tableLabel = _query.getFromClause().getAlias(table);
-            }
-            if (table != null) {
-                if (tableLabel == null) {
-                    tableLabel = table.getQuotedName();
-                    if (includeSchemaInColumnPath) {
-                        Schema schema = table.getSchema();
-                        if (schema != null) {
-                            tableLabel = schema.getQuotedName() + "." + tableLabel;
-                        }
-                    }
+            table = _column.getTable();
+        }
+        if (table == null) {
+            return "";
+        }
+
+        final StringBuilder sb = new StringBuilder();
+        String tableLabel;
+        if (_query == null) {
+            tableLabel = null;
+        } else {
+            tableLabel = _query.getFromClause().getAlias(table);
+        }
+        if (tableLabel == null) {
+            tableLabel = table.getQuotedName();
+            if (includeSchemaInColumnPath) {
+                Schema schema = table.getSchema();
+                if (schema != null) {
+                    sb.append(schema.getQuotedName() + ".");
                 }
-                sb.append(tableLabel);
-                sb.append('.');
             }
         }
+        sb.append(tableLabel);
+        sb.append('.');
         return sb.toString();
     }
 
@@ -561,13 +553,10 @@ public class SelectItem extends BaseObject implements QueryItem, Cloneable {
     }
 
     /**
-     * Creates a clone of the {@link SelectItem} for use within a cloned
-     * {@link Query}.
+     * Creates a clone of the {@link SelectItem} for use within a cloned {@link Query}.
      * 
-     * @param clonedQuery
-     *            a new {@link Query} object that represents the clone-to-be of
-     *            a query. It is expected that {@link FromItem}s have already
-     *            been cloned in this {@link Query}.
+     * @param clonedQuery a new {@link Query} object that represents the clone-to-be of a query. It is expected that
+     *            {@link FromItem}s have already been cloned in this {@link Query}.
      * @return
      */
     protected SelectItem clone(Query clonedQuery) {
@@ -592,8 +581,7 @@ public class SelectItem extends BaseObject implements QueryItem, Cloneable {
     }
 
     /**
-     * Creates a copy of the {@link SelectItem}, with a different
-     * {@link FunctionType}.
+     * Creates a copy of the {@link SelectItem}, with a different {@link FunctionType}.
      * 
      * @param function
      * @return
@@ -604,8 +592,7 @@ public class SelectItem extends BaseObject implements QueryItem, Cloneable {
     }
 
     /**
-     * Creates a copy of the {@link SelectItem}, with a different
-     * {@link #isFunctionApproximationAllowed()} flag set.
+     * Creates a copy of the {@link SelectItem}, with a different {@link #isFunctionApproximationAllowed()} flag set.
      * 
      * @param functionApproximationAllowed
      * @return
@@ -616,13 +603,11 @@ public class SelectItem extends BaseObject implements QueryItem, Cloneable {
     }
 
     /**
-     * Investigates whether or not this SelectItem references a particular
-     * column. This will search for direct references and indirect references
-     * via subqueries.
+     * Investigates whether or not this SelectItem references a particular column. This will search for direct
+     * references and indirect references via subqueries.
      * 
      * @param column
-     * @return a boolean that is true if the specified column is referenced by
-     *         this SelectItem and false otherwise.
+     * @return a boolean that is true if the specified column is referenced by this SelectItem and false otherwise.
      */
     public boolean isReferenced(Column column) {
         if (column != null) {
diff --git a/core/src/main/java/org/apache/metamodel/schema/AliasTable.java b/core/src/main/java/org/apache/metamodel/schema/AliasTable.java
new file mode 100644 (file)
index 0000000..8be55dd
--- /dev/null
@@ -0,0 +1,82 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.metamodel.schema;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Represents a virtual table that acts as an alias for another table.
+ */
+public class AliasTable extends AbstractTable implements WrappingTable {
+
+    private static final long serialVersionUID = 1L;
+
+    private final String name;
+    private final Schema schema;
+    private final Table aliasedTable;
+
+    public AliasTable(String name, Schema schema, Table aliasedTable) {
+        this.name = name;
+        this.schema = schema;
+        this.aliasedTable = aliasedTable;
+    }
+    
+    @Override
+    public Table getWrappedTable() {
+        return aliasedTable;
+    }
+
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public List<Column> getColumns() {
+        return aliasedTable.getColumns();
+    }
+
+    @Override
+    public Schema getSchema() {
+        return schema;
+    }
+
+    @Override
+    public TableType getType() {
+        return TableType.ALIAS;
+    }
+
+    @Override
+    public Collection<Relationship> getRelationships() {
+        return Collections.emptyList();
+    }
+
+    @Override
+    public String getRemarks() {
+        return null;
+    }
+
+    @Override
+    public String getQuote() {
+        return null;
+    }
+
+}
index b48f14b..cbaa801 100644 (file)
@@ -71,6 +71,7 @@ public class CompositeSchema extends AbstractSchema {
     public List<Table> getTables() {
         return delegates.stream()
                 .flatMap(delegate -> delegate.getTables().stream())
+                .filter(table -> table.getType() != TableType.ALIAS)
                 .collect(Collectors.toList());
     }
 
diff --git a/core/src/main/java/org/apache/metamodel/schema/DefaultTableAliasedSchema.java b/core/src/main/java/org/apache/metamodel/schema/DefaultTableAliasedSchema.java
new file mode 100644 (file)
index 0000000..9cccc3a
--- /dev/null
@@ -0,0 +1,89 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.metamodel.schema;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A special purpose {@link Schema} wrapper which exposes an {@link AliasTable} "default_table" for convenience when the
+ * table count is 1.
+ */
+public class DefaultTableAliasedSchema extends AbstractSchema implements WrappingSchema {
+
+    private static final long serialVersionUID = 1L;
+
+    public static final String DEFAULT_TABLE_NAME = "default_table";
+
+    public static Schema wrapIfAppropriate(Schema schema) {
+        if (schema.getTableCount() > 1) {
+            return schema;
+        } else {
+            return new DefaultTableAliasedSchema(schema);
+        }
+    }
+
+    private static AliasTable createTable(Schema schema, Table delegateTable) {
+        return new AliasTable(DEFAULT_TABLE_NAME, schema, delegateTable);
+    }
+
+    private final Schema wrappedSchema;
+
+    private DefaultTableAliasedSchema(Schema wrappedSchema) {
+        this.wrappedSchema = wrappedSchema;
+    }
+
+    @Override
+    public Schema getWrappedSchema() {
+        return wrappedSchema;
+    }
+
+    @Override
+    public String getName() {
+        return wrappedSchema.getName();
+    }
+
+    @Override
+    public List<Table> getTables() {
+        List<Table> tables = wrappedSchema.getTables();
+
+        // ensure table size is 1
+        if (tables.size() != 1) {
+            return tables;
+        }
+
+        // ensure no name clashes
+        if (DEFAULT_TABLE_NAME.equals(tables.get(0).getName())) {
+            return tables;
+        }
+
+        // ensure mutability
+        if (!(tables instanceof ArrayList)) {
+            tables = new ArrayList<>(tables);
+        }
+
+        tables.add(createTable(this, tables.get(0)));
+        return tables;
+    }
+
+    @Override
+    public String getQuote() {
+        return wrappedSchema.getQuote();
+    }
+}
index 1dbc0c0..b80f5f2 100644 (file)
@@ -36,11 +36,11 @@ public class MutableSchema extends AbstractSchema implements Serializable,
        private static final long serialVersionUID = 4465197783868238863L;
 
        private String _name;
-       private final List<MutableTable> _tables;
+       private final List<Table> _tables;
 
        public MutableSchema() {
                super();
-               _tables = new ArrayList<MutableTable>();
+               _tables = new ArrayList<Table>();
        }
 
        public MutableSchema(String name) {
@@ -48,7 +48,7 @@ public class MutableSchema extends AbstractSchema implements Serializable,
                _name = name;
        }
 
-       public MutableSchema(String name, MutableTable... tables) {
+       public MutableSchema(String name, Table... tables) {
                this(name);
                setTables(tables);
        }
@@ -69,17 +69,17 @@ public class MutableSchema extends AbstractSchema implements Serializable,
        }
 
 
-       public MutableSchema setTables(Collection<? extends MutableTable> tables) {
+       public MutableSchema setTables(Collection<? extends Table> tables) {
            clearTables();
-               for (MutableTable table : tables) {
+               for (Table table : tables) {
                        _tables.add(table);
                }
                return this;
        }
 
-       public MutableSchema setTables(MutableTable... tables) {
+       public MutableSchema setTables(Table... tables) {
            clearTables();
-               for (MutableTable table : tables) {
+               for (Table table : tables) {
                        _tables.add(table);
                }
                return this;
@@ -90,7 +90,7 @@ public class MutableSchema extends AbstractSchema implements Serializable,
            return this;
        }
 
-       public MutableSchema addTable(MutableTable table) {
+       public MutableSchema addTable(Table table) {
                _tables.add(table);
                return this;
        }
diff --git a/core/src/main/java/org/apache/metamodel/schema/WrappingSchema.java b/core/src/main/java/org/apache/metamodel/schema/WrappingSchema.java
new file mode 100644 (file)
index 0000000..f1809e5
--- /dev/null
@@ -0,0 +1,33 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.metamodel.schema;
+
+/**
+ * Sub-interface for {@link Schema}s that wrap other {@link Schema}s, typically to apply some client-side enhancement
+ * logic.
+ */
+public interface WrappingSchema extends Schema {
+
+    /**
+     * Gets the {@link Schema} that is wrapped by this {@link WrappingSchema}.
+     * 
+     * @return
+     */
+    public Schema getWrappedSchema();
+}
diff --git a/core/src/main/java/org/apache/metamodel/schema/WrappingTable.java b/core/src/main/java/org/apache/metamodel/schema/WrappingTable.java
new file mode 100644 (file)
index 0000000..b147a2f
--- /dev/null
@@ -0,0 +1,33 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.metamodel.schema;
+
+/**
+ * Sub-interface for {@link Table}s that wrap other {@link Table}s, typically to apply some client-side enhancement
+ * logic.
+ */
+public interface WrappingTable extends Table {
+
+    /**
+     * Gets the {@link Table} that is wrapped by this {@link WrappingTable}.
+     * 
+     * @return
+     */
+    public Table getWrappedTable();
+}
index 0c217f2..0a6cd72 100644 (file)
@@ -45,6 +45,7 @@ public class MockDataContext extends QueryPostprocessDataContext {
     private final String _value;
 
     public MockDataContext(String schemaName, String tableName, String value) {
+        super(true);
         _schemaName = schemaName;
         _tableName = tableName;
         _value = value;
index 4e6563a..4d06d5a 100644 (file)
@@ -51,8 +51,13 @@ public class MockUpdateableDataContext extends QueryPostprocessDataContext imple
 
     private final MutableTable _table;
     private final MutableSchema _schema;
-
+    
     public MockUpdateableDataContext() {
+        this(true);
+    }
+
+    public MockUpdateableDataContext(boolean addDefaultTableAlias) {
+        super(addDefaultTableAlias);
         _values.add(new Object[] { "1", "hello" });
         _values.add(new Object[] { "2", "there" });
         _values.add(new Object[] { "3", "world" });
@@ -70,6 +75,9 @@ public class MockUpdateableDataContext extends QueryPostprocessDataContext imple
 
     @Override
     protected DataSet materializeMainSchemaTable(Table table, List<Column> columns, int maxRows) {
+        if (table != _table) {
+            throw new IllegalArgumentException("Unknown table: " + table);
+        }
 
         List<Row> rows = new ArrayList<Row>();
         List<SelectItem> items = columns.stream().map(SelectItem::new).collect(Collectors.toList());
@@ -112,6 +120,9 @@ public class MockUpdateableDataContext extends QueryPostprocessDataContext imple
             @Override
             public RowDeletionBuilder deleteFrom(Table table) throws IllegalArgumentException, IllegalStateException,
                     UnsupportedOperationException {
+                if (table != _table) {
+                    throw new IllegalArgumentException("Unknown table: " + table);
+                }
                 return new AbstractRowDeletionBuilder(table) {
                     @Override
                     public void execute() throws MetaModelException {
@@ -123,6 +134,9 @@ public class MockUpdateableDataContext extends QueryPostprocessDataContext imple
             @Override
             public RowInsertionBuilder insertInto(Table table) throws IllegalArgumentException, IllegalStateException,
                     UnsupportedOperationException {
+                if (table != _table) {
+                    throw new IllegalArgumentException("Unknown table: " + table);
+                }
                 return new AbstractRowInsertionBuilder<UpdateCallback>(this, table) {
 
                     @Override
index f6352d4..04cfae9 100644 (file)
@@ -60,6 +60,70 @@ public class QueryPostprocessDataContextTest extends MetaModelTestCase {
     private final Table table1 = schema.getTableByName(TABLE_CONTRIBUTOR);
     private final Table table2 = schema.getTableByName(TABLE_ROLE);
 
+    public void testSchemaTraversalWithAliasTable() {
+        final MockUpdateableDataContext dc = new MockUpdateableDataContext();
+        
+        final Column column = dc.getColumnByQualifiedLabel("foo");
+        assertEquals("table", column.getTable().getName());
+    }
+    
+    public void testNoAliasTableWhenSystemPropertySet() {
+        System.setProperty(QueryPostprocessDataContext.SYSTEM_PROPERTY_CREATE_DEFAULT_TABLE_ALIAS, "false");
+        try {
+            final MockUpdateableDataContext dc = new MockUpdateableDataContext();
+            final List<Table> tables = dc.getDefaultSchema().getTables();
+            assertEquals(1, tables.size());
+            
+            assertEquals("table", tables.get(0).getName());
+        } finally {
+            System.clearProperty(QueryPostprocessDataContext.SYSTEM_PROPERTY_CREATE_DEFAULT_TABLE_ALIAS);
+        }
+    }
+
+    public void testNoAliasTableWhenConstructorArgSet() {
+        final MockUpdateableDataContext dc = new MockUpdateableDataContext(false);
+        final List<Table> tables = dc.getDefaultSchema().getTables();
+        assertEquals(1, tables.size());
+
+        assertEquals("table", tables.get(0).getName());
+    }
+    
+    public void testAliasTableQueries() {
+        final MockUpdateableDataContext dc = new MockUpdateableDataContext();
+        final List<Table> tables = dc.getDefaultSchema().getTables();
+        assertEquals(2, tables.size());
+
+        final Query q0 = dc.query().from(tables.get(0)).selectAll().toQuery();
+        assertEquals("SELECT table.foo, table.bar FROM schema.table", q0.toSql());
+
+        final Query q1 = dc.parseQuery("SELECT * FROM default_table d");
+        assertEquals("SELECT d.foo, d.bar FROM schema.default_table d", q1.toSql());
+
+        final Query q2 = dc.parseQuery("SELECT * FROM default_table");
+        assertEquals("SELECT default_table.foo, default_table.bar FROM schema.default_table", q2.toSql());
+
+        final DataSet dataSet0 = dc.executeQuery(q0);
+        final DataSet dataSet1 = dc.executeQuery(q1);
+        final DataSet dataSet2 = dc.executeQuery(q2);
+
+        Arrays.asList(dataSet0, dataSet1, dataSet2).forEach(ds -> {
+            assertTrue(ds.next());
+            assertEquals("Row[values=[1, hello]]", ds.getRow().toString());
+            assertTrue(ds.next());
+            assertEquals("Row[values=[2, there]]", ds.getRow().toString());
+            assertTrue(ds.next());
+            assertFalse(ds.next());
+            ds.close();
+        });
+
+        assertEquals("Row[values=[3]]", MetaModelHelper
+                .executeSingleRowQuery(dc, dc.parseQuery("SELECT COUNT(*) FROM default_table")).toString());
+        assertEquals("Row[values=[1]]",
+                MetaModelHelper
+                        .executeSingleRowQuery(dc, dc.parseQuery("SELECT COUNT(*) FROM default_table WHERE foo = '2'"))
+                        .toString());
+    }
+
     public void testQueryMaxRows0() throws Exception {
         final MockDataContext dc = new MockDataContext("sch", "tab", "1");
         final Table table = dc.getDefaultSchema().getTable(0);
@@ -83,7 +147,8 @@ public class QueryPostprocessDataContextTest extends MetaModelTestCase {
                 for (int i = 0; i < columns.size(); i++) {
                     values[i] = columns.get(i).getColumnNumber();
                 }
-                DataSetHeader header = new SimpleDataSetHeader(columns.stream().map(SelectItem::new).collect(Collectors.toList()));
+                DataSetHeader header =
+                        new SimpleDataSetHeader(columns.stream().map(SelectItem::new).collect(Collectors.toList()));
                 DefaultRow row = new DefaultRow(header, values);
                 return new InMemoryDataSet(row);
             }
@@ -118,8 +183,8 @@ public class QueryPostprocessDataContextTest extends MetaModelTestCase {
     public void testAggregateQueryRegularWhereClause() throws Exception {
         MockDataContext dc = new MockDataContext("sch", "tab", "1");
         Table table = dc.getDefaultSchema().getTable(0);
-        assertSingleRowResult("Row[values=[3]]", dc.query().from(table).selectCount().where("baz").eq("world")
-                .execute());
+        assertSingleRowResult("Row[values=[3]]",
+                dc.query().from(table).selectCount().where("baz").eq("world").execute());
     }
 
     public void testApplyFunctionToNullValues() throws Exception {
@@ -247,8 +312,7 @@ public class QueryPostprocessDataContextTest extends MetaModelTestCase {
 
         Query query = dc.query().from(table).select("foo").select(FunctionType.TO_NUMBER, "foo").select("bar")
                 .select(FunctionType.TO_STRING, "bar").select(FunctionType.TO_NUMBER, "bar").toQuery();
-        assertEquals(
-                "SELECT tab.foo, TO_NUMBER(tab.foo), tab.bar, TO_STRING(tab.bar), TO_NUMBER(tab.bar) FROM sch.tab",
+        assertEquals("SELECT tab.foo, TO_NUMBER(tab.foo), tab.bar, TO_STRING(tab.bar), TO_NUMBER(tab.bar) FROM sch.tab",
                 query.toSql());
 
         DataSet ds = dc.executeQuery(query);
@@ -343,7 +407,8 @@ public class QueryPostprocessDataContextTest extends MetaModelTestCase {
                     }
                     return createDataSet(selectItems, data);
                 } else if (table == table2) {
-                    List<SelectItem> selectItems = table2.getColumns().stream().map(SelectItem::new).collect(Collectors.toList());
+                    List<SelectItem> selectItems =
+                            table2.getColumns().stream().map(SelectItem::new).collect(Collectors.toList());
                     List<Object[]> data = new ArrayList<Object[]>();
                     data.add(new Object[] { 1, 1, "founder" });
                     data.add(new Object[] { 1, 1, "developer" });
@@ -409,22 +474,20 @@ public class QueryPostprocessDataContextTest extends MetaModelTestCase {
                         + "Relationship[primaryTable=columns,primaryColumns=[name],foreignTable=relationships,foreignColumns=[foreign_column]]]",
                 Arrays.toString(informationSchema.getRelationships().toArray()));
         Table tablesTable = informationSchema.getTableByName("tables");
-        assertEquals(
-                "[Column[name=name,columnNumber=0,type=VARCHAR,nullable=false,nativeType=null,columnSize=null], "
-                        + "Column[name=type,columnNumber=1,type=VARCHAR,nullable=true,nativeType=null,columnSize=null], "
-                        + "Column[name=num_columns,columnNumber=2,type=INTEGER,nullable=true,nativeType=null,columnSize=null], "
-                        + "Column[name=remarks,columnNumber=3,type=VARCHAR,nullable=true,nativeType=null,columnSize=null]]",
+        assertEquals("[Column[name=name,columnNumber=0,type=VARCHAR,nullable=false,nativeType=null,columnSize=null], "
+                + "Column[name=type,columnNumber=1,type=VARCHAR,nullable=true,nativeType=null,columnSize=null], "
+                + "Column[name=num_columns,columnNumber=2,type=INTEGER,nullable=true,nativeType=null,columnSize=null], "
+                + "Column[name=remarks,columnNumber=3,type=VARCHAR,nullable=true,nativeType=null,columnSize=null]]",
                 Arrays.toString(tablesTable.getColumns().toArray()));
         Table columnsTable = informationSchema.getTableByName("columns");
-        assertEquals(
-                "[Column[name=name,columnNumber=0,type=VARCHAR,nullable=false,nativeType=null,columnSize=null], "
-                        + "Column[name=type,columnNumber=1,type=VARCHAR,nullable=true,nativeType=null,columnSize=null], "
-                        + "Column[name=native_type,columnNumber=2,type=VARCHAR,nullable=true,nativeType=null,columnSize=null], "
-                        + "Column[name=size,columnNumber=3,type=INTEGER,nullable=true,nativeType=null,columnSize=null], "
-                        + "Column[name=nullable,columnNumber=4,type=BOOLEAN,nullable=true,nativeType=null,columnSize=null], "
-                        + "Column[name=indexed,columnNumber=5,type=BOOLEAN,nullable=true,nativeType=null,columnSize=null], "
-                        + "Column[name=table,columnNumber=6,type=VARCHAR,nullable=false,nativeType=null,columnSize=null], "
-                        + "Column[name=remarks,columnNumber=7,type=VARCHAR,nullable=true,nativeType=null,columnSize=null]]",
+        assertEquals("[Column[name=name,columnNumber=0,type=VARCHAR,nullable=false,nativeType=null,columnSize=null], "
+                + "Column[name=type,columnNumber=1,type=VARCHAR,nullable=true,nativeType=null,columnSize=null], "
+                + "Column[name=native_type,columnNumber=2,type=VARCHAR,nullable=true,nativeType=null,columnSize=null], "
+                + "Column[name=size,columnNumber=3,type=INTEGER,nullable=true,nativeType=null,columnSize=null], "
+                + "Column[name=nullable,columnNumber=4,type=BOOLEAN,nullable=true,nativeType=null,columnSize=null], "
+                + "Column[name=indexed,columnNumber=5,type=BOOLEAN,nullable=true,nativeType=null,columnSize=null], "
+                + "Column[name=table,columnNumber=6,type=VARCHAR,nullable=false,nativeType=null,columnSize=null], "
+                + "Column[name=remarks,columnNumber=7,type=VARCHAR,nullable=true,nativeType=null,columnSize=null]]",
                 Arrays.toString(columnsTable.getColumns().toArray()));
         Table relationshipsTable = informationSchema.getTableByName("relationships");
         assertEquals(
@@ -639,8 +702,8 @@ public class QueryPostprocessDataContextTest extends MetaModelTestCase {
     public void testCompiledQueryParameterInWhereClause() throws Exception {
         DataContext dc = getDataContext();
         QueryParameter param1 = new QueryParameter();
-        CompiledQuery compiledQuery = dc.query().from(table1).select("name").where(COLUMN_CONTRIBUTOR_COUNTRY)
-                .eq(param1).compile();
+        CompiledQuery compiledQuery =
+                dc.query().from(table1).select("name").where(COLUMN_CONTRIBUTOR_COUNTRY).eq(param1).compile();
         try {
             assertEquals(1, compiledQuery.getParameters().size());
             assertSame(param1, compiledQuery.getParameters().get(0));
@@ -675,8 +738,8 @@ public class QueryPostprocessDataContextTest extends MetaModelTestCase {
         final DataContext dc = getDataContext();
 
         final QueryParameter param1 = new QueryParameter();
-        final Query subQuery = dc.query().from(table1).select("name").where(COLUMN_CONTRIBUTOR_COUNTRY).eq(param1)
-                .toQuery();
+        final Query subQuery =
+                dc.query().from(table1).select("name").where(COLUMN_CONTRIBUTOR_COUNTRY).eq(param1).toQuery();
 
         final FromItem subQueryFromItem = new FromItem(subQuery);
         final Query query = new Query().select(new SelectItem(subQuery.getSelectClause().getItem(0), subQueryFromItem))
@@ -766,8 +829,8 @@ public class QueryPostprocessDataContextTest extends MetaModelTestCase {
         Query q = new Query();
         q.from(table1);
         q.select(table1.getColumns());
-        SelectItem countrySelectItem = q.getSelectClause().getSelectItem(
-                table1.getColumnByName(COLUMN_CONTRIBUTOR_COUNTRY));
+        SelectItem countrySelectItem =
+                q.getSelectClause().getSelectItem(table1.getColumnByName(COLUMN_CONTRIBUTOR_COUNTRY));
         q.where(new FilterItem(countrySelectItem, OperatorType.EQUALS_TO, "denmark"));
 
         DataSet data = dc.executeQuery(q);
@@ -1019,7 +1082,7 @@ public class QueryPostprocessDataContextTest extends MetaModelTestCase {
             }
 
             @Override
-            protected Schema getMainSchema() throws MetaModelException {
+            protected MutableSchema getMainSchema() throws MetaModelException {
                 MutableSchema schema = new MutableSchema(getMainSchemaName());
                 MutableTable table = new MutableTable("tabl").setSchema(schema);
                 return schema.addTable(table.addColumn(new MutableColumn("col").setTable(table)));
@@ -1058,7 +1121,7 @@ public class QueryPostprocessDataContextTest extends MetaModelTestCase {
             }
 
             @Override
-            protected Schema getMainSchema() throws MetaModelException {
+            protected MutableSchema getMainSchema() throws MetaModelException {
                 MutableSchema schema = new MutableSchema(getMainSchemaName());
                 MutableTable table = new MutableTable("tabl").setSchema(schema);
                 table.addColumn(new MutableColumn("col1").setTable(table).setPrimaryKey(true));
index 446577d..59e1b82 100644 (file)
@@ -22,6 +22,7 @@ import java.util.Arrays;
 import java.util.List;
 
 import org.apache.metamodel.DataContext;
+import org.apache.metamodel.MetaModelHelper;
 import org.apache.metamodel.MockUpdateableDataContext;
 import org.apache.metamodel.data.DataSet;
 import org.apache.metamodel.data.MaxRowsDataSet;
@@ -34,81 +35,77 @@ import junit.framework.TestCase;
 
 public class InterceptableDataContextTest extends TestCase {
 
-       private final MockUpdateableDataContext delegateDataContext = new MockUpdateableDataContext();
-       private final Table table = delegateDataContext.getDefaultSchema()
-                       .getTables().get(0);
-
-       public void testInterceptSchema() throws Exception {
-               // without an interceptor
-               {
-                       DataContext dc = new InterceptableDataContext(delegateDataContext);
-
-                       Schema schema = dc.getDefaultSchema();
-                       List<Schema> schemas = dc.getSchemas();
-
-                       assertEquals("schema", schema.getName());
-                       assertEquals(MutableSchema.class, schema.getClass());
-                       assertEquals("[information_schema, schema]",
-                                       Arrays.toString(dc.getSchemaNames().toArray()));
-                       assertEquals(2, schemas.size());
-                       assertEquals("information_schema", schemas.get(0).getName());
-                       assertEquals("schema", schemas.get(1).getName());
-               }
-
-               // with an interceptor
-               {
-                       DataContext dc = new InterceptableDataContext(delegateDataContext)
-                                       .addSchemaInterceptor(new SchemaInterceptor() {
-                                               @Override
-                                               public Schema intercept(Schema input) {
-                                                       return new MutableSchema(input.getName() + " foo!");
-                                               }
-                                       });
-
-                       Schema schema = dc.getDefaultSchema();
-                       List<Schema> schemas = dc.getSchemas();
-
-                       assertEquals("schema foo!", schema.getName());
-                       assertEquals(MutableSchema.class, schema.getClass());
-                       assertEquals("[information_schema foo!, schema foo!]",
-                                       Arrays.toString(dc.getSchemaNames().toArray()));
-                       assertEquals(2, schemas.size());
-                       assertEquals("information_schema foo!", schemas.get(0).getName());
-                       assertEquals("schema foo!", schemas.get(1).getName());
-               }
-       }
-
-       public void testInterceptDataSet() throws Exception {
-               DataContext dc = new InterceptableDataContext(delegateDataContext)
-                               .addDataSetInterceptor(new DataSetInterceptor() {
-                                       @Override
-                                       public DataSet intercept(DataSet dataSet) {
-                                               return new MaxRowsDataSet(dataSet, 1);
-                                       }
-                               });
-
-               DataSet ds = dc.query().from(table).select("foo").execute();
-               assertEquals(MaxRowsDataSet.class, ds.getClass());
-               assertEquals(1, ds.toObjectArrays().size());
-       }
-
-       public void testInterceptQuery() throws Exception {
-
-               DataContext dc = new InterceptableDataContext(delegateDataContext)
-                               .addQueryInterceptor(new QueryInterceptor() {
-                                       @Override
-                                       public Query intercept(Query input) {
-                                               return input.select(table.getColumnByName("foo"));
-                                       }
-                               }).addQueryInterceptor(new QueryInterceptor() {
-                                       @Override
-                                       public Query intercept(Query input) {
-                                               return input.select(table.getColumnByName("bar"));
-
-                                       }
-                               });
-
-               DataSet ds = dc.executeQuery(new Query().from(table));
-               assertEquals("[table.foo, table.bar]", Arrays.toString(ds.getSelectItems().toArray()));
-       }
+    private final MockUpdateableDataContext delegateDataContext = new MockUpdateableDataContext();
+    private final Table table = delegateDataContext.getDefaultSchema().getTables().get(0);
+
+    public void testInterceptSchema() throws Exception {
+        // without an interceptor
+        {
+            DataContext dc = new InterceptableDataContext(delegateDataContext);
+
+            Schema schema = dc.getDefaultSchema();
+            List<Schema> schemas = dc.getSchemas();
+
+            assertEquals("schema", schema.getName());
+            assertEquals(MutableSchema.class, MetaModelHelper.resolveUnderlyingSchema(schema).getClass());
+            assertEquals("[information_schema, schema]", Arrays.toString(dc.getSchemaNames().toArray()));
+            assertEquals(2, schemas.size());
+            assertEquals("information_schema", schemas.get(0).getName());
+            assertEquals("schema", schemas.get(1).getName());
+        }
+
+        // with an interceptor
+        {
+            DataContext dc =
+                    new InterceptableDataContext(delegateDataContext).addSchemaInterceptor(new SchemaInterceptor() {
+                        @Override
+                        public Schema intercept(Schema input) {
+                            return new MutableSchema(input.getName() + " foo!");
+                        }
+                    });
+
+            Schema schema = dc.getDefaultSchema();
+            List<Schema> schemas = dc.getSchemas();
+
+            assertEquals("schema foo!", schema.getName());
+            assertEquals(MutableSchema.class, schema.getClass());
+            assertEquals("[information_schema foo!, schema foo!]", Arrays.toString(dc.getSchemaNames().toArray()));
+            assertEquals(2, schemas.size());
+            assertEquals("information_schema foo!", schemas.get(0).getName());
+            assertEquals("schema foo!", schemas.get(1).getName());
+        }
+    }
+
+    public void testInterceptDataSet() throws Exception {
+        DataContext dc =
+                new InterceptableDataContext(delegateDataContext).addDataSetInterceptor(new DataSetInterceptor() {
+                    @Override
+                    public DataSet intercept(DataSet dataSet) {
+                        return new MaxRowsDataSet(dataSet, 1);
+                    }
+                });
+
+        DataSet ds = dc.query().from(table).select("foo").execute();
+        assertEquals(MaxRowsDataSet.class, ds.getClass());
+        assertEquals(1, ds.toObjectArrays().size());
+    }
+
+    public void testInterceptQuery() throws Exception {
+
+        DataContext dc = new InterceptableDataContext(delegateDataContext).addQueryInterceptor(new QueryInterceptor() {
+            @Override
+            public Query intercept(Query input) {
+                return input.select(table.getColumnByName("foo"));
+            }
+        }).addQueryInterceptor(new QueryInterceptor() {
+            @Override
+            public Query intercept(Query input) {
+                return input.select(table.getColumnByName("bar"));
+
+            }
+        });
+
+        DataSet ds = dc.executeQuery(new Query().from(table));
+        assertEquals("[table.foo, table.bar]", Arrays.toString(ds.getSelectItems().toArray()));
+    }
 }
index 9053625..ab549b0 100644 (file)
  */
 package org.apache.metamodel.query;
 
-import com.google.common.collect.Lists;
-import junit.framework.TestCase;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.stream.Collectors;
 
 import org.apache.metamodel.DataContext;
 import org.apache.metamodel.MetaModelException;
@@ -36,15 +39,12 @@ import org.apache.metamodel.schema.ColumnType;
 import org.apache.metamodel.schema.MutableColumn;
 import org.apache.metamodel.schema.MutableSchema;
 import org.apache.metamodel.schema.MutableTable;
-import org.apache.metamodel.schema.Schema;
 import org.apache.metamodel.schema.Table;
 import org.apache.metamodel.schema.TableType;
 
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.stream.Collectors;
+import com.google.common.collect.Lists;
+
+import junit.framework.TestCase;
 
 public class FilterItemTest extends TestCase {
 
@@ -400,7 +400,7 @@ public class FilterItemTest extends TestCase {
             }
 
             @Override
-            protected Schema getMainSchema() throws MetaModelException {
+            protected MutableSchema getMainSchema() throws MetaModelException {
                 return schema;
             }
         };
index 9da47b9..7b11cb7 100644 (file)
@@ -81,16 +81,19 @@ public class CouchDbDataContext extends QueryPostprocessDataContext implements U
     }
 
     public CouchDbDataContext(CouchDbInstance couchDbInstance) {
+        super(false);
         _couchDbInstance = couchDbInstance;
         _schemaBuilder = new CouchDbInferentialSchemaBuilder();
     }
 
     public CouchDbDataContext(CouchDbInstance couchDbInstance, String... databaseNames) {
+        super(false);
         _couchDbInstance = couchDbInstance;
         _schemaBuilder = new CouchDbInferentialSchemaBuilder(databaseNames);
     }
 
     public CouchDbDataContext(CouchDbInstance couchDbInstance, SimpleTableDef... tableDefs) {
+        super(false);
         _couchDbInstance = couchDbInstance;
         _schemaBuilder = new CouchDbSimpleTableDefSchemaBuilder(tableDefs);
     }
index 28a9812..fb1119f 100644 (file)
@@ -56,7 +56,7 @@ final class CsvSchema extends AbstractSchema {
        public String getQuote() {
                return null;
        }
-
+       
        @Override
        public List<Table> getTables() {
                if (_table == null) {
index 6aa9529..6e35a00 100644 (file)
@@ -29,6 +29,7 @@ import java.nio.charset.Charset;
 
 import org.apache.metamodel.AbstractUpdateCallback;
 import org.apache.metamodel.MetaModelException;
+import org.apache.metamodel.MetaModelHelper;
 import org.apache.metamodel.UpdateCallback;
 import org.apache.metamodel.create.TableCreationBuilder;
 import org.apache.metamodel.delete.RowDeletionBuilder;
@@ -62,7 +63,7 @@ final class CsvUpdateCallback extends AbstractUpdateCallback implements UpdateCa
     @Override
     public TableCreationBuilder createTable(Schema schema, String name) throws IllegalArgumentException,
             IllegalStateException {
-        return new CsvCreateTableBuilder(this, schema, name);
+        return new CsvCreateTableBuilder(this, MetaModelHelper.resolveUnderlyingSchema(schema), name);
     }
 
     @Override
index 029a179..23a140f 100644 (file)
@@ -26,8 +26,6 @@ import java.util.Map;
 
 import javax.swing.table.TableModel;
 
-import junit.framework.TestCase;
-
 import org.apache.metamodel.DataContext;
 import org.apache.metamodel.QueryPostprocessDataContext;
 import org.apache.metamodel.UpdateCallback;
@@ -52,6 +50,8 @@ import org.apache.metamodel.schema.naming.CustomColumnNamingStrategy;
 import org.apache.metamodel.util.FileHelper;
 import org.apache.metamodel.util.MutableRef;
 
+import junit.framework.TestCase;
+
 public class CsvDataContextTest extends TestCase {
 
     private final CsvConfiguration semicolonConfiguration = new CsvConfiguration(
@@ -65,7 +65,7 @@ public class CsvDataContextTest extends TestCase {
                 FileHelper.DEFAULT_ENCODING, CsvConfiguration.DEFAULT_SEPARATOR_CHAR, CsvConfiguration.NOT_A_CHAR,
                 CsvConfiguration.DEFAULT_ESCAPE_CHAR);
         final CsvDataContext dc = new CsvDataContext(file, csvConfiguration);
-        assertEquals(1, dc.getDefaultSchema().getTableCount());
+        assertEquals(2, dc.getDefaultSchema().getTableCount());
 
         dc.executeUpdate(new UpdateScript() {
 
@@ -80,7 +80,7 @@ public class CsvDataContextTest extends TestCase {
         CsvDataContext dc1 = new CsvDataContext(file, csvConfiguration);
 
         List<Table> tables = dc1.getDefaultSchema().getTables();
-        assertEquals(1, tables.size());
+        assertEquals(2, tables.size());
         
         Table table = tables.get(0);
         assertEquals("testEmptyFileNoColumnHeaderLine.csv", table.getName());
@@ -98,7 +98,7 @@ public class CsvDataContextTest extends TestCase {
         FileHelper.copy(new File("src/test/resources/empty_file.csv"), file);
 
         final CsvDataContext dc = new CsvDataContext(file);
-        assertEquals(1, dc.getDefaultSchema().getTableCount());
+        assertEquals(2, dc.getDefaultSchema().getTableCount());
 
         final Table table1 = dc.getDefaultSchema().getTables().get(0);
         assertEquals("testEmptyFileNoColumnHeaderLine.csv", table1.getName());
@@ -125,8 +125,8 @@ public class CsvDataContextTest extends TestCase {
 
         assertEquals("\"bar\",\"baz\"", FileHelper.readFileAsString(file));
 
-        // still the table count should only be 1
-        assertEquals(1, dc.getDefaultSchema().getTableCount());
+        // still the table count should only be 2
+        assertEquals(2, dc.getDefaultSchema().getTableCount());
     }
 
     public void testAppendToFileWithoutLineBreak() throws Exception {
@@ -179,7 +179,7 @@ public class CsvDataContextTest extends TestCase {
     public void testEmptyFileNoHeaderLine() throws Exception {
         DataContext dc = new CsvDataContext(new File("src/test/resources/empty_file.csv"), new CsvConfiguration(
                 CsvConfiguration.NO_COLUMN_NAME_LINE));
-        assertEquals(1, dc.getDefaultSchema().getTableCount());
+        assertEquals(2, dc.getDefaultSchema().getTableCount());
 
         Table table = dc.getDefaultSchema().getTables().get(0);
         assertEquals("empty_file.csv", table.getName());
@@ -188,7 +188,7 @@ public class CsvDataContextTest extends TestCase {
 
     public void testUnexistingHeaderLine() throws Exception {
         DataContext dc = new CsvDataContext(new File("src/test/resources/csv_people.csv"), new CsvConfiguration(20));
-        assertEquals(1, dc.getDefaultSchema().getTableCount());
+        assertEquals(2, dc.getDefaultSchema().getTableCount());
 
         Table table = dc.getDefaultSchema().getTables().get(0);
         assertEquals("csv_people.csv", table.getName());
@@ -322,7 +322,7 @@ public class CsvDataContextTest extends TestCase {
         assertEquals(2, dc.getSchemas().size());
         Schema schema = dc.getDefaultSchema();
         assertEquals("resources", schema.getName());
-        assertEquals(1, schema.getTableCount());
+        assertEquals(2, schema.getTableCount());
         Table table = schema.getTables().get(0);
         assertEquals("csv_people.csv", table.getName());
 
@@ -353,7 +353,7 @@ public class CsvDataContextTest extends TestCase {
         assertEquals(2, dc.getSchemas().size());
         Schema schema = dc.getDefaultSchema();
         assertEquals("resources", schema.getName());
-        assertEquals(1, schema.getTableCount());
+        assertEquals(2, schema.getTableCount());
         Table table = schema.getTables().get(0);
         assertEquals("csv_people.csv", table.getName());
 
@@ -383,7 +383,7 @@ public class CsvDataContextTest extends TestCase {
         assertEquals(2, dc.getSchemas().size());
         Schema schema = dc.getDefaultSchema();
         assertEquals("resources", schema.getName());
-        assertEquals(1, schema.getTableCount());
+        assertEquals(2, schema.getTableCount());
         Table table = schema.getTables().get(0);
         assertEquals("csv_people.csv", table.getName());
 
@@ -625,7 +625,6 @@ public class CsvDataContextTest extends TestCase {
             public void run(UpdateCallback cb) {
                 Table table = cb.createTable(schema, "foobar").withColumn("foo").withColumn("bar").execute();
                 tableRef.set(table);
-                assertEquals(schema, table.getSchema());
                 assertEquals(schema.getTables().get(0), table);
                 assertTrue(file.exists());
 
index 06c1822..3033c7f 100644 (file)
@@ -67,7 +67,7 @@ public class InterceptionCsvIntegrationTest extends TestCase {
                        }
                });
 
-               assertEquals("[table]",
+               assertEquals("[table, default_table]",
                                Arrays.toString(dc.getDefaultSchema().getTableNames().toArray()));
                Table table = dc.getDefaultSchema().getTables().get(0);
                assertEquals("[col1, col2, foobar]",
index 504769d..74c22ff 100644 (file)
@@ -104,6 +104,7 @@ public class DynamoDbDataContext extends QueryPostprocessDataContext implements
     }
 
     private DynamoDbDataContext(AmazonDynamoDB client, SimpleTableDef[] tableDefs, boolean shutdownOnClose) {
+        super(false);
         _dynamoDb = client;
         _tableDefs = (tableDefs == null ? new SimpleTableDef[0] : tableDefs);
         _shutdownOnClose = shutdownOnClose;
index 83d89c7..d2dfe4b 100644 (file)
@@ -113,6 +113,7 @@ public class ElasticSearchDataContext extends QueryPostprocessDataContext implem
      *            and column model of the ElasticSearch index.
      */
     public ElasticSearchDataContext(Client client, String indexName, SimpleTableDef... tableDefinitions) {
+        super(false);
         if (client == null) {
             throw new IllegalArgumentException("ElasticSearch Client cannot be null");
         }
index 8d89c05..c5a5696 100644 (file)
@@ -123,6 +123,7 @@ public class ElasticSearchRestDataContext extends QueryPostprocessDataContext im
      *            and column model of the ElasticSearch index.
      */
     public ElasticSearchRestDataContext(JestClient client, String indexName, SimpleTableDef... tableDefinitions) {
+        super(false);
         if (client == null) {
             throw new IllegalArgumentException("ElasticSearch Client cannot be null");
         }
index 713fbe8..b5e6fca 100644 (file)
@@ -79,6 +79,7 @@ public final class ExcelDataContext extends QueryPostprocessDataContext implemen
      * @param configuration
      */
     public ExcelDataContext(File file, ExcelConfiguration configuration) {
+        super(true);
         if (file == null) {
             throw new IllegalArgumentException("File cannot be null");
         }
@@ -93,6 +94,7 @@ public final class ExcelDataContext extends QueryPostprocessDataContext implemen
     }
 
     public ExcelDataContext(Resource resource, ExcelConfiguration configuration) {
+        super(true);
         if (resource == null) {
             throw new IllegalArgumentException("Resource cannot be null");
         }
index 2d68a69..2ad863f 100644 (file)
@@ -54,7 +54,7 @@ final class ExcelTableCreationBuilder extends AbstractTableCreationBuilder<Excel
             }
         }
 
-        final MutableSchema schema = (MutableSchema) table.getSchema();
+        final MutableSchema schema = (MutableSchema) getSchema();
         schema.addTable((MutableTable) table);
         return table;
     }
index 844522e..2990417 100644 (file)
@@ -80,7 +80,7 @@ public class ExcelDataContextTest extends TestCase {
         ExcelDataContext dc = new ExcelDataContext(file);
 
         assertNull(dc.getSpreadsheetReaderDelegateClass());
-        assertEquals(1, dc.getDefaultSchema().getTableCount());
+        assertEquals(2, dc.getDefaultSchema().getTableCount());
 
         Table table = dc.getDefaultSchema().getTables().get(0);
         assertEquals("sheet", table.getName());
@@ -92,7 +92,7 @@ public class ExcelDataContextTest extends TestCase {
     public void testEmptyFileNoHeaderLine() throws Exception {
         DataContext dc = new ExcelDataContext(copyOf("src/test/resources/empty_file.xls"), new ExcelConfiguration(
                 ExcelConfiguration.NO_COLUMN_NAME_LINE, false, false));
-        assertEquals(1, dc.getDefaultSchema().getTableCount());
+        assertEquals(2, dc.getDefaultSchema().getTableCount());
 
         Table table = dc.getDefaultSchema().getTables().get(0);
         assertEquals("sheet", table.getName());
@@ -102,7 +102,7 @@ public class ExcelDataContextTest extends TestCase {
     public void testUnexistingHeaderLine() throws Exception {
         DataContext dc = new ExcelDataContext(copyOf("src/test/resources/xls_people.xls"), new ExcelConfiguration(20,
                 true, false));
-        assertEquals(1, dc.getDefaultSchema().getTableCount());
+        assertEquals(2, dc.getDefaultSchema().getTableCount());
 
         Table table = dc.getDefaultSchema().getTables().get(0);
         assertEquals("xls_people", table.getName());
@@ -359,7 +359,7 @@ public class ExcelDataContextTest extends TestCase {
         assertEquals(2, schemas.length);
         Schema schema = schemas[1];
         assertEquals("testGetSchemas-xls_people.xls", schema.getName());
-        assertEquals(1, schema.getTableCount());
+        assertEquals(2, schema.getTableCount());
         Table table = schema.getTables().get(0);
         assertEquals("xls_people", table.getName());
 
@@ -399,7 +399,7 @@ public class ExcelDataContextTest extends TestCase {
         File file = copyOf("src/test/resources/xls_missing_values.xls");
         DataContext dc = new ExcelDataContext(file);
         Schema schema = dc.getDefaultSchema();
-        assertEquals(1, schema.getTableCount());
+        assertEquals(2, schema.getTableCount());
 
         Table table = schema.getTables().get(0);
         assertEquals("[Column[name=a,columnNumber=0,type=VARCHAR,nullable=true,nativeType=null,columnSize=null], "
@@ -423,7 +423,7 @@ public class ExcelDataContextTest extends TestCase {
         File file = copyOf("src/test/resources/xls_missing_column_header.xls");
         DataContext dc = new ExcelDataContext(file);
         Schema schema = dc.getDefaultSchema();
-        assertEquals(1, schema.getTableCount());
+        assertEquals(2, schema.getTableCount());
 
         Table table = schema.getTables().get(0);
         assertEquals("[Column[name=a,columnNumber=0,type=VARCHAR,nullable=true,nativeType=null,columnSize=null], "
@@ -447,7 +447,7 @@ public class ExcelDataContextTest extends TestCase {
         File file = copyOf("src/test/resources/formulas.xlsx");
         ExcelDataContext dc = new ExcelDataContext(file);
 
-        assertEquals("[sh1]", Arrays.toString(dc.getDefaultSchema().getTableNames().toArray()));
+        assertEquals("[sh1, default_table]", Arrays.toString(dc.getDefaultSchema().getTableNames().toArray()));
         assertEquals(XlsxSpreadsheetReaderDelegate.class, dc.getSpreadsheetReaderDelegateClass());
 
         Table table = dc.getDefaultSchema().getTableByName("sh1");
@@ -618,7 +618,7 @@ public class ExcelDataContextTest extends TestCase {
                 Table table1 = cb.createTable(schema, "my_table_1").withColumn("foo").withColumn("bar")
                         .withColumn("baz").execute();
 
-                assertEquals(1, schema.getTableCount());
+                assertEquals(2, schema.getTableCount());
                 assertSame(table1.getSchema(), schema);
                 assertSame(table1, schema.getTables().get(0));
 
@@ -689,12 +689,12 @@ public class ExcelDataContextTest extends TestCase {
             }
         });
 
-        assertEquals("[my_table_2]", Arrays.toString(schema.getTableNames().toArray()));
+        assertEquals("[my_table_2]", schema.getTableNames().toString());
 
         dc.refreshSchemas();
 
-        assertEquals("[my_table_2]", Arrays.toString(dc.getDefaultSchema().getTableNames().toArray()));
-        assertEquals(1, dc.getDefaultSchema().getTableCount());
+        assertEquals("[my_table_2, default_table]", dc.getDefaultSchema().getTableNames().toString());
+        assertEquals(2, dc.getDefaultSchema().getTableCount());
     }
 
     public void testGetStyles() throws Exception {
index a181248..6a18e98 100644 (file)
@@ -83,7 +83,7 @@ public class ExcelUpdateCallbackTest extends TestCase {
                // read to check results
                {
                        ExcelDataContext dc = new ExcelDataContext(file);
-                       assertEquals("[foobar]",
+                       assertEquals("[foobar, default_table]",
                                        Arrays.toString(dc.getDefaultSchema().getTableNames().toArray()));
 
                        Table table = dc.getDefaultSchema().getTableByName("foobar");
index aac5ada..022649e 100644 (file)
@@ -51,11 +51,13 @@ public class FixedWidthDataContext extends QueryPostprocessDataContext {
     private final FixedWidthConfiguration _configuration;
 
     public FixedWidthDataContext(File file, FixedWidthConfiguration configuration) {
+        super(true);
         _resource = new FileResource(file);
         _configuration = configuration;
     }
 
     public FixedWidthDataContext(Resource resource, FixedWidthConfiguration configuration) {
+        super(true);
         _resource = resource;
         _configuration = configuration;
     }
index 16f2c5b..713b48d 100644 (file)
@@ -35,7 +35,7 @@ public class FixedWidthDataContextTest extends TestCase {
     public void testEmptyFile() throws Exception {
         DataContext dc = new FixedWidthDataContext(new File("src/test/resources/empty_file.txt"),
                 new FixedWidthConfiguration(10));
-        assertEquals(1, dc.getDefaultSchema().getTableCount());
+        assertEquals(2, dc.getDefaultSchema().getTableCount());
 
         Table table = dc.getDefaultSchema().getTables().get(0);
         assertEquals("empty_file.txt", table.getName());
@@ -45,7 +45,7 @@ public class FixedWidthDataContextTest extends TestCase {
     public void testEmptyFileNoHeaderLine() throws Exception {
         DataContext dc = new FixedWidthDataContext(new File("src/test/resources/empty_file.txt"),
                 new FixedWidthConfiguration(FixedWidthConfiguration.NO_COLUMN_NAME_LINE, "UTF8", 10));
-        assertEquals(1, dc.getDefaultSchema().getTableCount());
+        assertEquals(2, dc.getDefaultSchema().getTableCount());
 
         Table table = dc.getDefaultSchema().getTables().get(0);
         assertEquals("empty_file.txt", table.getName());
@@ -55,7 +55,7 @@ public class FixedWidthDataContextTest extends TestCase {
     public void testUnexistingHeaderLine() throws Exception {
         DataContext dc = new FixedWidthDataContext(new File("src/test/resources/example_simple1.txt"),
                 new FixedWidthConfiguration(20, "UTF8", 10));
-        assertEquals(1, dc.getDefaultSchema().getTableCount());
+        assertEquals(2, dc.getDefaultSchema().getTableCount());
 
         Table table = dc.getDefaultSchema().getTables().get(0);
         assertEquals("example_simple1.txt", table.getName());
@@ -73,7 +73,7 @@ public class FixedWidthDataContextTest extends TestCase {
         Schema schema = dc.getDefaultSchema();
         assertEquals("Schema[name=resources]", schema.toString());
 
-        assertEquals(1, schema.getTableCount());
+        assertEquals(2, schema.getTableCount());
 
         Table table = schema.getTableByName("example_simple1.txt");
         assertEquals("Table[name=example_simple1.txt,type=TABLE,remarks=null]", table.toString());
@@ -106,7 +106,7 @@ public class FixedWidthDataContextTest extends TestCase {
         Schema schema = dc.getDefaultSchema();
         assertEquals("Schema[name=resources]", schema.toString());
 
-        assertEquals(1, schema.getTableCount());
+        assertEquals(2, schema.getTableCount());
 
         Table table = schema.getTableByName("example_simple1.txt");
         assertEquals("Table[name=example_simple1.txt,type=TABLE,remarks=null]", table.toString());
index 55e4f41..46866b7 100644 (file)
@@ -69,6 +69,7 @@ public class HBaseDataContext extends QueryPostprocessDataContext {
      * @param configuration
      */
     public HBaseDataContext(HBaseConfiguration configuration) {
+        super(false);
         Configuration config = createConfig(configuration);
         _configuration = configuration;
         _connection = createConnection(config);
@@ -81,6 +82,7 @@ public class HBaseDataContext extends QueryPostprocessDataContext {
      * @param connection
      */
     public HBaseDataContext(HBaseConfiguration configuration, Connection connection) {
+        super(false);
         _configuration = configuration;
         _connection = connection;
     }
index b0e923f..b129614 100644 (file)
@@ -70,6 +70,7 @@ public class JsonDataContext extends QueryPostprocessDataContext implements Docu
     }
 
     public JsonDataContext(Resource resource, SchemaBuilder schemaBuilder) {
+        super(false);
         _resource = resource;
         _schemaBuilder = schemaBuilder;
     }
index d5d0432..898e3b4 100644 (file)
@@ -97,6 +97,7 @@ public class MongoDbDataContext extends QueryPostprocessDataContext implements U
      *            ).
      */
     public MongoDbDataContext(DB mongoDb, SimpleTableDef... tableDefs) {
+        super(false);
         _mongoDb = mongoDb;
         _tableDefs = tableDefs;
         _schema = null;
index 9bdec81..c7a7487 100644 (file)
@@ -99,6 +99,7 @@ public class MongoDbDataContext extends QueryPostprocessDataContext implements U
      *            ).
      */
     public MongoDbDataContext(MongoDatabase mongoDb, SimpleTableDef... tableDefs) {
+        super(false);
         _mongoDb = mongoDb;
         _tableDefs = tableDefs;
         _schema = null;
index 2a598b5..00d0b5a 100644 (file)
@@ -72,6 +72,7 @@ public class Neo4jDataContext extends QueryPostprocessDataContext implements Dat
     private String _serviceRoot = "/db/data";
 
     public Neo4jDataContext(String hostname, int port, String username, String password, SimpleTableDef... tableDefs) {
+        super(false);
         _httpHost = new HttpHost(hostname, port);
         final CloseableHttpClient httpClient = HttpClientBuilder.create().build();
         _requestWrapper = new Neo4jRequestWrapper(httpClient, _httpHost, username, password, _serviceRoot);
@@ -80,6 +81,7 @@ public class Neo4jDataContext extends QueryPostprocessDataContext implements Dat
 
     public Neo4jDataContext(String hostname, int port, String username, String password, String serviceRoot,
             SimpleTableDef... tableDefs) {
+        super(false);
         _httpHost = new HttpHost(hostname, port);
         final CloseableHttpClient httpClient = HttpClientBuilder.create().build();
         _requestWrapper = new Neo4jRequestWrapper(httpClient, _httpHost, username, password, _serviceRoot);
@@ -88,6 +90,7 @@ public class Neo4jDataContext extends QueryPostprocessDataContext implements Dat
     }
 
     public Neo4jDataContext(String hostname, int port, String username, String password) {
+        super(false);
         _httpHost = new HttpHost(hostname, port);
         final CloseableHttpClient httpClient = HttpClientBuilder.create().build();
         _requestWrapper = new Neo4jRequestWrapper(httpClient, _httpHost, username, password, _serviceRoot);
@@ -95,6 +98,7 @@ public class Neo4jDataContext extends QueryPostprocessDataContext implements Dat
     }
 
     public Neo4jDataContext(String hostname, int port, String username, String password, String serviceRoot) {
+        super(false);
         _httpHost = new HttpHost(hostname, port);
         final CloseableHttpClient httpClient = HttpClientBuilder.create().build();
         _requestWrapper = new Neo4jRequestWrapper(httpClient, _httpHost, username, password, _serviceRoot);
@@ -103,12 +107,14 @@ public class Neo4jDataContext extends QueryPostprocessDataContext implements Dat
     }
 
     public Neo4jDataContext(String hostname, int port, CloseableHttpClient httpClient) {
+        super(false);
         _httpHost = new HttpHost(hostname, port);
         _requestWrapper = new Neo4jRequestWrapper(httpClient, _httpHost, _serviceRoot);
         _tableDefs = detectTableDefs();
     }
 
     public Neo4jDataContext(String hostname, int port, CloseableHttpClient httpClient, String serviceRoot) {
+        super(false);
         _httpHost = new HttpHost(hostname, port);
         _requestWrapper = new Neo4jRequestWrapper(httpClient, _httpHost, _serviceRoot);
         _tableDefs = detectTableDefs();
@@ -116,6 +122,7 @@ public class Neo4jDataContext extends QueryPostprocessDataContext implements Dat
     }
 
     public Neo4jDataContext(String hostname, int port, CloseableHttpClient httpClient, SimpleTableDef... tableDefs) {
+        super(false);
         _httpHost = new HttpHost(hostname, port);
         _requestWrapper = new Neo4jRequestWrapper(httpClient, _httpHost, _serviceRoot);
         _tableDefs = tableDefs;
@@ -123,6 +130,7 @@ public class Neo4jDataContext extends QueryPostprocessDataContext implements Dat
 
     public Neo4jDataContext(String hostname, int port, CloseableHttpClient httpClient, String serviceRoot,
             SimpleTableDef... tableDefs) {
+        super(false);
         _httpHost = new HttpHost(hostname, port);
         _requestWrapper = new Neo4jRequestWrapper(httpClient, _httpHost, _serviceRoot);
         _tableDefs = tableDefs;
index 09b6494..0df0d3e 100644 (file)
@@ -94,6 +94,7 @@ public class PojoDataContext extends QueryPostprocessDataContext implements Upda
      * @param tables
      */
     public PojoDataContext(String schemaName, List<TableDataProvider<?>> tables) {
+        super(true);
         if (schemaName == null) {
             throw new IllegalArgumentException("Schema name cannot be null");
         }
index 97f1a9f..d520556 100644 (file)
@@ -113,7 +113,7 @@ public class PojoDataContextTest extends TestCase {
         final PojoDataContext dc = new PojoDataContext("foo", tableDataProvider);
 
         final Schema schema = dc.getDefaultSchema();
-        assertEquals(1, schema.getTableCount());
+        assertEquals(2, schema.getTableCount());
         final Table table = schema.getTable(0);
         assertEquals("foo.bar", table.getQualifiedLabel());
 
@@ -200,7 +200,7 @@ public class PojoDataContextTest extends TestCase {
             }
         });
 
-        assertEquals(1, schema.getTableCount());
+        assertEquals(2, schema.getTableCount());
 
         ds = dc.query().from("yo!").select("foo", "bar").execute();
         assertTrue(ds.next());
index 671693e..98b70e3 100644 (file)
@@ -71,6 +71,7 @@ public class SalesforceDataContext extends QueryPostprocessDataContext implement
     private final PartnerConnection _connection;
 
     public SalesforceDataContext(String endpoint, String username, String password, String securityToken) {
+        super(false);
         try {
             final ConnectorConfig config = new ConnectorConfig();
             config.setUsername(username);
@@ -86,6 +87,7 @@ public class SalesforceDataContext extends QueryPostprocessDataContext implement
     }
 
     public SalesforceDataContext(String username, String password, String securityToken) {
+        super(false);
         try {
             _connection =
                     Connector.newConnection(username, securityToken == null ? password : password + securityToken);
@@ -95,6 +97,7 @@ public class SalesforceDataContext extends QueryPostprocessDataContext implement
     }
 
     public SalesforceDataContext(String username, String password) {
+        super(false);
         try {
             _connection = Connector.newConnection(username, password);
         } catch (ConnectionException e) {
@@ -109,6 +112,7 @@ public class SalesforceDataContext extends QueryPostprocessDataContext implement
      * 
      */
     public SalesforceDataContext(PartnerConnection connection) {
+        super(false);
         if (connection == null) {
             throw new IllegalArgumentException("connection cannot be null");
         }
index 9abe5da..9b68fe0 100644 (file)
@@ -72,6 +72,7 @@ public class SugarCrmDataContext extends QueryPostprocessDataContext implements
      */
     public SugarCrmDataContext(String sugarCrmBaseUrl, final String username, String password,
             final String applicationName) {
+        super(false);
         if (sugarCrmBaseUrl.endsWith("/")) {
             // remove trailing slashes
             sugarCrmBaseUrl = sugarCrmBaseUrl.substring(0, sugarCrmBaseUrl.length() - 1);
index aab6fca..b35b630 100644 (file)
@@ -112,6 +112,7 @@ public class XmlDomDataContext extends QueryPostprocessDataContext {
      * @param autoFlattenTables
      */
     public XmlDomDataContext(String schemaName, Document document, boolean autoFlattenTables) {
+        super(false);
         _autoFlattenTables = autoFlattenTables;
         _schemaName = schemaName;
         _schema = new MutableSchema(_schemaName);
@@ -133,6 +134,7 @@ public class XmlDomDataContext extends QueryPostprocessDataContext {
      *             if the file does not exist
      */
     public XmlDomDataContext(Resource resource, boolean autoFlattenTables) throws IllegalArgumentException {
+        super(false);
         _inputSourceRef = createInputSourceRef(resource);
         _schemaName = resource.getName();
         _autoFlattenTables = autoFlattenTables;
@@ -143,6 +145,7 @@ public class XmlDomDataContext extends QueryPostprocessDataContext {
     }
 
     public XmlDomDataContext(InputSource inputSource, String schemaName, boolean autoFlattenTables) {
+        super(false);
         _inputSourceRef = new ImmutableRef<InputSource>(inputSource);
         _schemaName = schemaName;
         _autoFlattenTables = autoFlattenTables;
index ac0a699..98b956d 100644 (file)
@@ -88,6 +88,7 @@ public class XmlSaxDataContext extends QueryPostprocessDataContext {
      * @see XmlSaxTableDef
      */
     public XmlSaxDataContext(Supplier<InputSource> inputSourceRef, Collection<XmlSaxTableDef> tableDefs) {
+        super(false);
         _inputSourceRef = inputSourceRef;
         _tableDefs = tableDefs;
         _valueXpaths = new HashMap<XmlSaxTableDef, Map<String, String>>();
index b5a7a02..2c23d35 100644 (file)
@@ -39,6 +39,7 @@ import org.apache.metamodel.query.Query;
 import org.apache.metamodel.schema.Relationship;
 import org.apache.metamodel.schema.Schema;
 import org.apache.metamodel.schema.Table;
+import org.apache.metamodel.util.ResourceException;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 
@@ -55,7 +56,7 @@ public class XmlDomDataContextTest extends TestCase {
             Schema schema = dataContext.getSchemaByName("xml_input_eobjects.xml");
             assertEquals("Schema[name=xml_input_eobjects.xml]", schema.toString());
             assertEquals(5, schema.getTableCount());
-        } catch (IllegalArgumentException e) {
+        } catch (ResourceException e) {
             // If the network is not accessible omit the test
             if (!(e.getCause() instanceof UnknownHostException)) {
                 throw e;