METAMODEL-1122: Fixed
authorKasper Sørensen <i.am.kasper.sorensen@gmail.com>
Sun, 9 Oct 2016 06:57:36 +0000 (23:57 -0700)
committerKasper Sørensen <i.am.kasper.sorensen@gmail.com>
Sun, 9 Oct 2016 06:57:36 +0000 (23:57 -0700)
Fixes #130

CHANGES.md
cassandra/.gitignore
cassandra/src/main/java/org/apache/metamodel/cassandra/CassandraDataContext.java
cassandra/src/test/java/org/apache/metamodel/cassandra/CassandraDataContextTest.java

index bda2372..5c0b893 100644 (file)
@@ -2,6 +2,7 @@
 
  * [METAMODEL-1118] - Fixed bug pertaining to cloning of FilterItem.LogicalOperator in compiled queries.
  * [METAMODEL-1111] - Added WHERE rewrite for Oracle when empty strings are considered as NULL.
+ * [METAMODEL-1122] - Optimized the way the Cassandra module executes primary key lookup queries.
  * [METAMODEL-1109] - Fixed diacritics/encoding issue with Fixed Width reader.
  * [METAMODEL-1115] - Added support for passing your own PartnerConnection object to the Salesforce.com connector.
  * [METAMODEL-1113] - Fixed support for ColumnNamingStrategy in CSV connector.
index 4e247ee..212512c 100644 (file)
@@ -2,3 +2,4 @@
 /target
 /.classpath
 /.project
+/.toDelete
index e99570b..3a1684e 100644 (file)
  */
 package org.apache.metamodel.cassandra;
 
-import com.datastax.driver.core.*;
-import com.datastax.driver.core.querybuilder.QueryBuilder;
-import com.datastax.driver.core.querybuilder.Select;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.UUID;
 
 import org.apache.metamodel.DataContext;
 import org.apache.metamodel.MetaModelException;
 import org.apache.metamodel.QueryPostprocessDataContext;
 import org.apache.metamodel.data.DataSet;
+import org.apache.metamodel.data.SimpleDataSetHeader;
 import org.apache.metamodel.query.FilterItem;
-import org.apache.metamodel.schema.*;
+import org.apache.metamodel.query.SelectItem;
+import org.apache.metamodel.schema.Column;
+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.util.SimpleTableDef;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
+import com.datastax.driver.core.Cluster;
+import com.datastax.driver.core.ColumnMetadata;
+import com.datastax.driver.core.DataType;
+import com.datastax.driver.core.KeyspaceMetadata;
+import com.datastax.driver.core.Metadata;
+import com.datastax.driver.core.ResultSet;
+import com.datastax.driver.core.Row;
+import com.datastax.driver.core.Statement;
+import com.datastax.driver.core.TableMetadata;
+import com.datastax.driver.core.querybuilder.QueryBuilder;
+import com.datastax.driver.core.querybuilder.Select;
+import com.datastax.driver.core.querybuilder.Select.Selection;
 
 /**
  * DataContext implementation for Apache Cassandra database.
@@ -145,6 +163,20 @@ public class CassandraDataContext extends QueryPostprocessDataContext implements
         final MutableSchema theSchema = new MutableSchema(getMainSchemaName());
         for (final SimpleTableDef tableDef : tableDefs) {
             final MutableTable table = tableDef.toTable().setSchema(theSchema);
+
+            final TableMetadata cassandraTable = cassandraCluster.getMetadata().getKeyspace(keySpaceName).getTable(table
+                    .getName());
+            if (cassandraTable != null) {
+                final List<ColumnMetadata> primaryKeys = cassandraTable.getPrimaryKey();
+                for (ColumnMetadata primaryKey : primaryKeys) {
+                    final MutableColumn column = (MutableColumn) table.getColumnByName(primaryKey.getName());
+                    if (column != null) {
+                        column.setPrimaryKey(true);
+                    }
+                    column.setNativeType(primaryKey.getType().getName().name());
+                }
+            }
+
             theSchema.addTable(table);
         }
         return theSchema;
@@ -162,7 +194,7 @@ public class CassandraDataContext extends QueryPostprocessDataContext implements
             query.limit(maxRows);
         }
         final ResultSet resultSet = cassandraCluster.connect().execute(query);
-        
+
         final Iterator<Row> response = resultSet.iterator();
         return new CassandraDataSet(response, columns);
     }
@@ -172,10 +204,34 @@ public class CassandraDataContext extends QueryPostprocessDataContext implements
     }
 
     @Override
+    protected org.apache.metamodel.data.Row executePrimaryKeyLookupQuery(Table table, List<SelectItem> selectItems,
+            Column primaryKeyColumn, Object keyValue) {
+        
+        if (primaryKeyColumn.getType() == ColumnType.UUID && keyValue instanceof String) {
+            keyValue = UUID.fromString(keyValue.toString());
+        }
+
+        Selection select = QueryBuilder.select();
+        for (SelectItem selectItem : selectItems) {
+            final Column column = selectItem.getColumn();
+            assert column != null;
+            select = select.column(column.getName());
+        }
+
+        final Statement statement = select.from(keySpaceName, table.getName()).where(QueryBuilder.eq(primaryKeyColumn
+                .getName(), keyValue));
+
+        final Row row = cassandraCluster.connect().execute(statement).one();
+
+        return CassandraUtils.toRow(row, new SimpleDataSetHeader(selectItems));
+    }
+
+    @Override
     protected Number executeCountQuery(Table table, List<FilterItem> whereItems, boolean functionApproximationAllowed) {
         if (!whereItems.isEmpty()) {
             // not supported - will have to be done by counting client-side
-            logger.debug("Not able to execute count query natively - resorting to query post-processing, which may be expensive");
+            logger.debug(
+                    "Not able to execute count query natively - resorting to query post-processing, which may be expensive");
             return null;
         }
         final Statement statement = QueryBuilder.select().countAll().from(keySpaceName, table.getName());
index 4921639..a9d9605 100644 (file)
@@ -32,6 +32,7 @@ import javax.swing.table.TableModel;
 import org.apache.metamodel.data.DataSet;
 import org.apache.metamodel.data.DataSetTableModel;
 import org.apache.metamodel.data.FilteredDataSet;
+import org.apache.metamodel.data.InMemoryDataSet;
 import org.apache.metamodel.query.Query;
 import org.apache.metamodel.query.parser.QueryParserException;
 import org.apache.metamodel.schema.ColumnType;
@@ -113,7 +114,7 @@ public class CassandraDataContextTest {
 
     @Test
     public void testWhereColumnEqualsValues() throws Exception {
-        DataSet ds = dc.query().from(testTableName).select("id").and("title").where("id").isEquals(firstRowId)
+        DataSet ds = dc.query().from(testTableName).select("id").and("title").where("title").isEquals(firstRowTitle)
                 .execute();
 
         assertEquals(FilteredDataSet.class, ds.getClass());
@@ -125,6 +126,21 @@ public class CassandraDataContextTest {
             ds.close();
         }
     }
+    
+    @Test
+    public void testPrimaryKeyLookup() throws Exception {
+        DataSet ds = dc.query().from(testTableName).select("id").and("title").where("id").isEquals(firstRowId)
+                .execute();
+
+        assertEquals(InMemoryDataSet.class, ds.getClass());
+        try {
+            assertTrue(ds.next());
+            assertEquals("Row[values=[" + firstRowId + ", " + firstRowTitle + "]]", ds.getRow().toString());
+            assertFalse(ds.next());
+        } finally {
+            ds.close();
+        }
+    }
 
     @Test
     public void testWhereColumnInValues() throws Exception {