Skip to content

Commit

Permalink
implemented AndroidOqlTemplate as OQL decorator for
Browse files Browse the repository at this point in the history
AndroidSqliteTemplate.
  • Loading branch information
jdavo committed Jun 14, 2012
1 parent 4763620 commit e17c664
Show file tree
Hide file tree
Showing 14 changed files with 486 additions and 38 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,19 +30,13 @@
*/
public class AndroidSQLiteTemplate implements JdbcOperations {
private SQLiteDatabase sqLiteDatabase;
private final DomainClassAnalyzer domainClassAnalyzer = new DomainClassAnalyzer();
protected final DomainClassAnalyzer domainClassAnalyzer = new DomainClassAnalyzer();
private final CursorAdapter cursorAdapter = new CursorAdapter();

public AndroidSQLiteTemplate(SQLiteDatabase sqLiteDatabase) {
this.sqLiteDatabase = sqLiteDatabase;
}

public Object mapQueryParameter(Object value, Class<?> clazz,
String columnName) {
return this.domainClassAnalyzer.mapQueryParameter(value, clazz,
columnName);
}

@Override
public long insert(Object object) {
ContentValues values = domainClassAnalyzer.createContentValues(object);
Expand Down Expand Up @@ -256,6 +250,11 @@ public <T> List<T> query(String sql, CursorRowMapper<T> cursorRowMapper,
sql = replaceParametersInStatement(sql, args);
return executeForList(sql, cursorRowMapper);
}

public Object mapQueryParameter(Object value, Class<?> clazz, String columnName)
{
return this.domainClassAnalyzer.mapQueryParameterByColumnName(value, clazz, columnName);
}

private <T> T executeForSingleObject(String sql,
CursorExtractor<T> cursorExtractor) {
Expand Down
17 changes: 12 additions & 5 deletions src/com/perfectworldprogramming/mobile/orm/CursorAdapter.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import com.perfectworldprogramming.mobile.orm.annotations.Transient;
import com.perfectworldprogramming.mobile.orm.exception.DataAccessException;
import com.perfectworldprogramming.mobile.orm.exception.ExtraResultsException;
import com.perfectworldprogramming.mobile.orm.exception.InvalidCursorExtractorException;
import com.perfectworldprogramming.mobile.orm.exception.InvalidCursorException;
import com.perfectworldprogramming.mobile.orm.exception.InvalidCursorRowMapperException;
import com.perfectworldprogramming.mobile.orm.interfaces.ColumnTypeMapper;
import com.perfectworldprogramming.mobile.orm.interfaces.CursorExtractor;
Expand Down Expand Up @@ -63,7 +63,7 @@ public <T> List<T> adaptListFromCursor(Cursor cursor, CursorRowMapper<T> cursorR
List<T> values = new ArrayList<T>();
if (cursor != null) {
if (cursor.moveToFirst()) {
do {
do {
try {
T newInstance = cursorRowMapper.mapRow(cursor, cursor.getPosition());
values.add(newInstance);
Expand Down Expand Up @@ -108,7 +108,7 @@ public <T> T adaptFromCursor(Cursor cursor, Class<T> clazz) {
}

/**
* Checks that the cursor is not bbeforeFirst or afterLast positions but does not move
* Checks that the cursor is not {@code beforeFirst} or {@code afterLast} positions but does not move
* or close the cursor.
* @param cursor
* @param clazz
Expand All @@ -118,7 +118,7 @@ public <T> T adaptFromCursor(Cursor cursor, Class<T> clazz) {
public <T> T adaptCurrentFromCursor(Cursor cursor, Class<T> clazz) {
T newInstance = null;
if (cursor != null) {
if (!cursor.isBeforeFirst() &&!cursor.isAfterLast()) {
if (!cursor.isBeforeFirst() && !cursor.isAfterLast()) {
newInstance = getSingleObjectValuesFromCursor(cursor, clazz);
}
}
Expand Down Expand Up @@ -163,7 +163,7 @@ public <T> T adaptFromCursor(Cursor cursor, CursorExtractor<T> cursorExtractor)
try {
result = cursorExtractor.extractData(cursor);
} catch (IllegalStateException ise) {
throw new InvalidCursorExtractorException(cursorExtractor.getClass());
throw new InvalidCursorException(cursorExtractor.getClass());
} finally {
if (!cursor.isClosed()) {
cursor.close();
Expand Down Expand Up @@ -219,17 +219,24 @@ private <T> void setFieldValue(Field fieldToSet, T object, Cursor cursor) {
|| ((fieldToSet.getModifiers()&Modifier.STATIC)!=0)) {
return;
}
final String value;
final ColumnTypeMapper<?> mapper;
if (fieldToSet.isAnnotationPresent(PrimaryKey.class) ) {
mapper = PrimaryKeyMapper.INSTANCE;
value = fieldToSet.getAnnotation(PrimaryKey.class).value();
}
else if (fieldToSet.isAnnotationPresent(Column.class)){
mapper = fieldToSet.getAnnotation(Column.class).type().getMapper();
value = fieldToSet.getAnnotation(Column.class).value();
}
else
{
throw new DataAccessException("Invalid type, cannot find field "+fieldToSet.getName()+" on type "+object.getClass().getName());
}
if(-1==cursor.getColumnIndex(value))
{
throw new InvalidCursorException(object.getClass());
}
mapper.databaseToModel(cursor, fieldToSet, object);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.perfectworldprogramming.mobile.orm.exception;

public class InvalidCursorException extends DataAccessException {

private static final long serialVersionUID = 323422738996859681L;

public InvalidCursorException(Class<? extends Object> clazz) {
super("Invalid Cursor: "+ clazz.getName() + ". Possible reasons are 1) query does not contain all the fields, 2) query is using the wrong tables, 3) Not navigating through the Cursor correctly, either by the cursor is empty, or has past the end of the results.");
}

}
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
package com.perfectworldprogramming.mobile.orm.exception;

public class InvalidCursorExtractorException extends DataAccessException {
public class InvalidCursorExtractorException extends InvalidCursorException {

private static final long serialVersionUID = 323422738996859681L;

public InvalidCursorExtractorException(Class<? extends Object> class1) {
super("Invalid CursorExtractor: " + class1.getName() + ". Possible reasons are 1) query does not contain all the fields, 2) query is using the wrong tables, 3) Not navigating through the Cursor correctly, either by the cursor is empty, or has past the end of the results.");
super(class1);
//super("Invalid CursorExtractor: " + class1.getName() + ". Possible reasons are 1) query does not contain all the fields, 2) query is using the wrong tables, 3) Not navigating through the Cursor correctly, either by the cursor is empty, or has past the end of the results.");
}

}
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package com.perfectworldprogramming.mobile.orm.exception;

public class InvalidCursorRowMapperException extends DataAccessException {
public class InvalidCursorRowMapperException extends InvalidCursorException {

private static final long serialVersionUID = 1L;

public InvalidCursorRowMapperException(Class<? extends Object> class1) {
super("Invalid CursorRowMapper: " + class1.getName() + ". Possible reasons are 1) query does not contain all the fields, 2) query is using the wrong tables, 3) Not navigating through the Cursor correctly, either by the cursor is empty, or has past the end of the results.");
super(class1);
//super("Invalid CursorRowMapper: " + class1.getName() + ". Possible reasons are 1) query does not contain all the fields, 2) query is using the wrong tables, 3) Not navigating through the Cursor correctly, either by the cursor is empty, or has past the end of the results.");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.perfectworldprogramming.mobile.orm.exception;

import java.lang.reflect.Field;

public class TransientFieldException extends DataAccessException {

private static final long serialVersionUID = -442347181326281845L;

public TransientFieldException(Field field) {
super("Cannot persist transient field " + field.getName());
}
}
119 changes: 119 additions & 0 deletions src/com/perfectworldprogramming/mobile/orm/oql/AndroidOqlTemplate.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
package com.perfectworldprogramming.mobile.orm.oql;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import android.database.sqlite.SQLiteDatabase;

import com.perfectworldprogramming.mobile.orm.AndroidSQLiteTemplate;
import com.perfectworldprogramming.mobile.orm.interfaces.CursorExtractor;
import com.perfectworldprogramming.mobile.orm.interfaces.CursorRowMapper;

/**
* Decorates the {@link AndroidSQLiteTemplate} with operations which refer to the domain
* object rather than database, allowing data access to be persistence agnostic.
* @author David O'Meara <[email protected]>
* @since 14/06/2012
*
*/
public class AndroidOqlTemplate extends AndroidSQLiteTemplate
{
public AndroidOqlTemplate(SQLiteDatabase sqLiteDatabase) {
super(sqLiteDatabase);
}

public long insert(String oql, OqlParameter... args)
{
return super.insert(QueryParser.parse(oql, getTypes(args)), convertParams(args));
}

public void update(String oql, OqlParameter... args)
{
//super.update(oql, args);
super.update(QueryParser.parse(oql, getTypes(args)), convertParams(args));
}

public void delete(String oql, OqlParameter... args)
{
//super.delete(oql, args);
super.delete(QueryParser.parse(oql, getTypes(args)), convertParams(args));
}

public int queryForInt(String oql, OqlParameter... args)
{
//return super.queryForInt(oql, args);
return super.queryForInt(QueryParser.parse(oql, getTypes(args)), convertParams(args));
}

public long queryForLong(String oql, OqlParameter... args)
{
//return super.queryForLong(oql, args);
return super.queryForLong(QueryParser.parse(oql, getTypes(args)), convertParams(args));
}

public String queryForString(String oql, OqlParameter... args)
{
//return super.queryForString(oql, args);
return super.queryForString(QueryParser.parse(oql, getTypes(args)), convertParams(args));
}

public <T> T queryForObject(String oql, CursorRowMapper<T> cursorRowMapper, OqlParameter... args)
{
//return super.queryForObject(oql, cursorRowMapper, args);
return super.queryForObject(QueryParser.parse(oql, getTypes(args)), cursorRowMapper, convertParams(args));
}

public <T> T queryForObject(String oql, Class<T> clazz, OqlParameter... args)
{
//return super.queryForObject(oql, clazz, args);
return super.queryForObject(QueryParser.parse(oql, getTypes(args)), clazz, convertParams(args));
}

public <T> T queryForObject(String oql, CursorExtractor<T> cursorExtractor, OqlParameter... args)
{
//return super.queryForObject(oql, cursorExtractor, args);
return super.queryForObject(QueryParser.parse(oql, getTypes(args)), cursorExtractor, convertParams(args));
}

public <T> List<T> query(String oql, Class<T> clazz, OqlParameter... args)
{
//return super.query(oql, clazz, args);
return super.query(QueryParser.parse(oql, getTypes(args)), clazz, convertParams(args));
}

public <T> List<T> query(String oql, CursorRowMapper<T> cursorRowMapper, OqlParameter... args)
{
//return super.query(oql, cursorRowMapper, args);
return super.query(QueryParser.parse(oql, getTypes(args)), cursorRowMapper, convertParams(args));
}

@Override
public Object mapQueryParameter(Object value, Class<?> clazz, String fieldName)
{
return this.domainClassAnalyzer.mapQueryParameterByFieldName(value, clazz, fieldName);
}

private List<Class<?>> getTypes(OqlParameter... args)
{
Set<Class<?>> types = new HashSet<Class<?>>();
for(OqlParameter arg:args)
{
types.add(arg.getDomainClass());
}
List<Class<?>> result = new ArrayList<Class<?>>(types.size());
result.addAll(types);
return result;
}
private Object[] convertParams(OqlParameter... args)
{
Object[] result = new Object[args.length];
for(int i=0;i<args.length;i++)
{
result[i] = this.mapQueryParameter(args[i].getDomainValue(), args[i].getDomainClass(), args[i].getFieldName());
}
return result;
}

}
34 changes: 34 additions & 0 deletions src/com/perfectworldprogramming/mobile/orm/oql/OqlParameter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.perfectworldprogramming.mobile.orm.oql;

/**
* Immutable class containing the Domain layer representation of a value to be persisted.
* @author David O'Meara <[email protected]>
* @since 14/06/2012
*
*/
public final class OqlParameter
{
public OqlParameter(Class<?> domainClass, String fieldName, Object domainValue)
{
this.domainClass = domainClass;
this.fieldName = fieldName;
this.domainValue = domainValue;
}

public Class<?> getDomainClass()
{
return domainClass;
}
public String getFieldName()
{
return fieldName;
}
public Object getDomainValue()
{
return domainValue;
}

private final Class<?> domainClass;
private final String fieldName;
private final Object domainValue;
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.perfectworldprogramming.mobile.orm.reflection;
package com.perfectworldprogramming.mobile.orm.oql;

import java.lang.reflect.Field;
import java.util.List;
Expand All @@ -10,6 +10,7 @@
import com.perfectworldprogramming.mobile.orm.annotations.PrimaryKey;
import com.perfectworldprogramming.mobile.orm.exception.DataAccessException;
import com.perfectworldprogramming.mobile.orm.exception.FieldNotFoundException;
import com.perfectworldprogramming.mobile.orm.reflection.DomainClassAnalyzer;
/**
* Allows SQL to refer to domain classes and fields, which are then converted to SQL.
* Queries place matchable tokens in square brackets and refer to either a direct field or a qualified field
Expand Down
Loading

0 comments on commit e17c664

Please sign in to comment.