diff --git a/.classpath b/.classpath index dc5f793..bc15cad 100644 --- a/.classpath +++ b/.classpath @@ -10,5 +10,8 @@ + + + diff --git a/.gitignore b/.gitignore index 3735cba..4ed9c2c 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,5 @@ classes/ dist/ docs/ *.class -*~ \ No newline at end of file +*~ +docs/ diff --git a/build.xml b/build.xml index a670095..2fe85a5 100644 --- a/build.xml +++ b/build.xml @@ -9,6 +9,7 @@ + @@ -90,20 +91,20 @@ - + - + diff --git a/src/java/meetup/beeno/ScanByIndex.java b/src/java/meetup/beeno/ScanByIndex.java index e6af5b3..2f38830 100644 --- a/src/java/meetup/beeno/ScanByIndex.java +++ b/src/java/meetup/beeno/ScanByIndex.java @@ -11,6 +11,7 @@ import meetup.beeno.mapping.EntityInfo; import meetup.beeno.mapping.IndexMapping; +import meetup.beeno.mapping.MappingException; import meetup.beeno.util.HUtil; import meetup.beeno.util.PBUtil; @@ -151,9 +152,10 @@ protected ResultScanner getIndexScanner(String tablename, * for the query. * @param expressions * @return + * @throws MappingException */ protected Criteria.PropertyExpression selectIndexedExpression(EntityInfo info, - List expressions) { + List expressions) throws MappingException { // first look for a direct match expression for (Criteria.Expression e : expressions) { if (e instanceof Criteria.RequireExpression) @@ -168,8 +170,9 @@ protected Criteria.PropertyExpression selectIndexedExpression(EntityInfo info, log.warn("No index found for expression property: "+propExpr.getProperty()); } } - - return null; + // not property match found + // notifying user to avoid returning wrong result set + throw new MappingException(info.getClass(), "Can't find property " + expressions); } diff --git a/test/java/meetup/beeno/BasicOrmPersistanceTest.java b/test/java/meetup/beeno/BasicOrmPersistanceTest.java new file mode 100644 index 0000000..13a89c6 --- /dev/null +++ b/test/java/meetup/beeno/BasicOrmPersistanceTest.java @@ -0,0 +1,148 @@ +package meetup.beeno; + +import static org.junit.Assert.*; + +import java.util.List; + +import junit.framework.Assert; + +import meetup.beeno.Criteria; +import meetup.beeno.EntityService; +import meetup.beeno.HBaseException; +import meetup.beeno.Query; +import meetup.beeno.mapping.MappingException; +import meetup.beeno.util.HUtil; + +import org.apache.hadoop.hbase.HBaseConfiguration; +import org.apache.hadoop.hbase.HColumnDescriptor; +import org.apache.hadoop.hbase.HTableDescriptor; +import org.apache.hadoop.hbase.TableNotFoundException; +import org.apache.hadoop.hbase.client.HBaseAdmin; +import org.apache.hadoop.hbase.client.HTable; +import org.apache.hadoop.hbase.client.HTablePool; +import org.apache.hadoop.hbase.util.Bytes; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +/* + * Commands to create the correspondign hbase schema in HBase Shell + * create 'test_simple-by_photoId', '__idx__', 'props' + * create 'test_simple', 'props' + * Note: This is not required. The test case creates the corresponding tables automatically. + */ + +public class BasicOrmPersistanceTest { + + private static HUtil _hUtil; + + @BeforeClass + public static void setUpBeforeClass() throws Exception { + + HBaseConfiguration conf = new HBaseConfiguration(); + conf.set("hbase.master", "localhost"); + HTablePool pool = new HTablePool(conf, 10); + + _hUtil = new HUtil(); + _hUtil.setPool(pool); + + HBaseAdmin admin = new HBaseAdmin(conf); + + // drop tables + try { + admin.disableTable("test_simple-by_photoId"); + admin.deleteTable("test_simple-by_photoId"); + } catch (TableNotFoundException e) { + // silently swallow + } + try { + admin.disableTable("test_simple"); + admin.deleteTable("test_simple"); + } catch (TableNotFoundException e) { + // silently swallow + } + + // create tables + HTableDescriptor by_photoId_idx = new HTableDescriptor( + "test_simple-by_photoId"); + by_photoId_idx.addFamily(new HColumnDescriptor("__idx__")); + by_photoId_idx.addFamily(new HColumnDescriptor("props")); + admin.createTable(by_photoId_idx); + + // create tables & index + HTableDescriptor test_simple = new HTableDescriptor("test_simple"); + test_simple.addFamily(new HColumnDescriptor("props")); + admin.createTable(test_simple); + } + + @AfterClass + public static void tearDownAfterClass() throws Exception { + } + + @Before + public void setUp() throws Exception { + + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testCreationAndCriteriaRetrieval() throws HBaseException { + + EntityService service = EntityService + .create(SimpleEntity.class); + + for (int i = 0; i < 10; i++) { + SimpleEntity se = new SimpleEntity(); + se.setId("r:" + System.currentTimeMillis()); + se.setStringProperty("superman"); + se.setDoubleProperty(12.1111D); + se.setPhotoIdProperty("PHOTOID" + i); + service.save(se); + } + + // query rows + Query query = service.query().using(Criteria.eq("photoIdProperty", "PHOTOID5")); + List items = query.execute(); + for (SimpleEntity e : items) { + System.out.println("items: " + ((SimpleEntity) e).getId()); + } + assertEquals(1, items.size()); + } + + @Test + public void testCreationAndNonExistantCriteriaRetrieval() throws HBaseException { + + EntityService service = EntityService.create(SimpleEntity.class); + + // query rows + try{ + Query query = service.query().using(Criteria.eq("IDONTEXISTFORSURE", "PHOTOID5")); + List items = query.execute(); + fail("Should have gotten a QueryException for the missing properties."); + } catch(QueryException e){ + //Sweet! Got our expected exception. + } + } + + @Test + public void testCreationOfMixedExistingAndNonExistantCriteriaRetrieval() throws HBaseException { + + EntityService service = EntityService.create(SimpleEntity.class); + + // query rows + try{ + Query query = service.query().using(Criteria.eq("IDONTEXISTFORSURE", "PHOTOID5")).where(Criteria.eq("photoIdProperty", "PHOTOID5")); + List items = query.execute(); + fail("Should have gotten a QueryException for the missing properties."); + } catch(QueryException e){ + //Sweet! Got our expected exception. + } + } + + +} diff --git a/test/java/meetup/beeno/SimpleEntity.java b/test/java/meetup/beeno/SimpleEntity.java new file mode 100644 index 0000000..1f279f0 --- /dev/null +++ b/test/java/meetup/beeno/SimpleEntity.java @@ -0,0 +1,64 @@ +package meetup.beeno; + +import meetup.beeno.HEntity; +import meetup.beeno.HIndex; +import meetup.beeno.HProperty; +import meetup.beeno.HRowKey; + +/** + * Simple entity class with mapped properties + */ +@HEntity(name="test_simple") +public class SimpleEntity { + String id; + String stringProperty; + int intProperty; + float floatProperty; + double doubleProperty; + long updated = System.currentTimeMillis(); + String photoId; + + public SimpleEntity() { + } + + @HRowKey + public String getId() { return this.id; } + public void setId(String id) { this.id = id; } + + @HProperty(family="props", name="stringcol") + public String getStringProperty() { return stringProperty; } + public void setStringProperty( String stringProperty ) { + this.stringProperty = stringProperty; + } + + @HProperty(family="props", name="photoId", indexes = {@HIndex(date_col="props:updated", date_invert=true)}) + public String getPhotoIdProperty() { return photoId; } + public void setPhotoIdProperty( String photoId ) { + this.photoId = photoId; + } + + @HProperty(family="props", name="intcol") + public int getIntProperty() { return intProperty; } + public void setIntProperty( int intProperty ) { + this.intProperty = intProperty; + } + + @HProperty(family="props", name="floatcol") + public float getFloatProperty() { return floatProperty; } + public void setFloatProperty( float floatProperty ) { + this.floatProperty = floatProperty; + } + + @HProperty(family="props", name="doublecol") + public double getDoubleProperty() { return doubleProperty; } + public void setDoubleProperty( double doubleProperty ) { + this.doubleProperty = doubleProperty; + } + + @HProperty(family="props", name="updated") + public long getUpdated() { return updated; } + public void setUpdated( long updateTime ) { + this.updated = updateTime; + } +} +