package com.ushahidi.android.app.util;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import android.content.ContentValues;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.util.Log;
import com.ushahidi.android.app.entities.IDbEntity;
public class DbUtils {
/** Column name for the ID column */
public static final String COLUMN_ID = "_id";
public static final int DATABASE_VERSION = 14;
public static final String DATABASE_NAME = "ushahidi_db";
/**
* SQL keywords. These should not be used for non-standard use, e.g. column
* names
*/
private static final String[] SQL_KEYWORDS = {
"from", "group", "select"
};
/** @return <code>true</code> if the supplied string is a SQL keyword. */
private static boolean isSqlRestricted(String string) {
for (String keyword : SQL_KEYWORDS) {
if (keyword.equalsIgnoreCase(string)) {
return true;
}
}
return false;
}
public static String getCreateStatement(Class<? extends IDbEntity> entityClass) {
if (entityClass.isPrimitive() || entityClass.isEnum()) {
throw new IllegalArgumentException(
"Cannot store primitive type or enum in separate table: " + entityClass);
}
StringBuilder bob = new StringBuilder();
for (Field intransientField : getFields(entityClass)) {
bob.append(", ");
String columnName = getColumnName(intransientField);
bob.append(columnName);
bob.append(" ");
bob.append(getColumnType(intransientField.getType()));
if (columnName.equalsIgnoreCase(COLUMN_ID)) {
bob.append(" PRIMARY KEY AUTOINCREMENT");
}
}
return "CREATE TABLE " + getTableName(entityClass) + " (" + bob.substring(2) + ");";
}
public static String getCreateTable(String tableName) {
if (tableName.isEmpty()) {
throw new IllegalArgumentException("Cannot create an empty table ");
}
return "CREATE TABLE " + tableName;
}
static String getColumnType(Class<?> clazz) {
if (clazz.equals(String.class)) {
return "TEXT";
}
if (clazz.equals(int.class) || clazz.equals(Integer.class) || clazz.equals(long.class)
|| clazz.equals(Long.class) || clazz.isEnum()) {
return "INTEGER";
}
throw new IllegalArgumentException("Unsupported column type: " + clazz);
}
public static String getColumnName(Field field) {
String columnName = field.getName();
if (isSqlRestricted(columnName)) {
columnName = "_" + columnName;
}
return columnName;
}
/**
* @return all fields of the supplied class which are not
* <code>transient</code>
*/
public static List<Field> getFields(Class<? extends IDbEntity> entityClass) {
List<Field> fields = new LinkedList<Field>();
for (Field declared : entityClass.getDeclaredFields()) {
if (!Modifier.isTransient(declared.getModifiers())) {
declared.setAccessible(true);
fields.add(declared);
}
}
return fields;
}
public static String getTableName(Class<? extends IDbEntity> entityClass) {
return entityClass.getSimpleName();
}
// @SuppressWarnings("unchecked")
// static <T extends DbEntity> Class<T> getTableClass(String tableName) {
// try {
// return (Class<T>) Class.forName(tableName.replace('_', '.'));
// } catch (ClassNotFoundException ex) {
// throw new IllegalArgumentException("Could not get class for table: " +
// tableName, ex);
// }
// }
public static Object getContentValue(IDbEntity entity, Field field) {
try {
return field.get(entity);
} catch (IllegalAccessException ex) {
throw new IllegalArgumentException(ex);
}
}
static void addContentValue(ContentValues values, IDbEntity entity, Field field,
boolean insertNulls) {
try {
Class<?> type = field.getType();
String key = getColumnName(field);
if (type.equals(int.class)) {
values.put(key, field.getInt(entity));
} else if (type.equals(Integer.class)) {
Object value = field.get(entity);
if (insertNulls || value != null) {
values.put(key, (Integer)value);
}
} else if (type.equals(long.class)) {
values.put(key, field.getLong(entity));
} else if (type.equals(Long.class)) {
Object value = field.get(entity);
if (insertNulls || value != null) {
values.put(key, (Long)value);
}
} else if (type.equals(String.class)) {
Object value = field.get(entity);
if (insertNulls || value != null) {
values.put(key, (String)value);
}
} else if (type.isEnum()) {
Object value = field.get(entity);
if (value != null) {
values.put(key, ((Enum<?>)value).ordinal());
} else if (insertNulls) {
values.put(key, (Integer)null);
}
} else if (type.equals(IDbEntity.class)) {
Object value = field.get(entity);
if (value != null) {
values.put(key, ((IDbEntity)value).getDbId());
} else if (insertNulls) {
values.put(key, (Integer)null);
}
} else
throw new IllegalArgumentException("Unable to add content value for class");
} catch (IllegalAccessException ex) {
throw new RuntimeException(ex);
}
}
/**
* Converts a {@link Cursor} into a {@link List}, and closes the
* {@link Cursor}
*
* @param cursor
* @return
*/
public static <T extends IDbEntity> List<T> asList(Class<T> entityClass, Cursor cursor) {
if (cursor == null) {
return Collections.emptyList();
} else {
ArrayList<T> results = new ArrayList<T>(cursor.getCount());
// Get all rows from the cursor, and convert them into POJOs
List<Field> fields = getFields(entityClass);
while (cursor.moveToNext()) {
T instance;
try {
instance = entityClass.newInstance();
} catch (Exception ex) {
throw new IllegalArgumentException("Unable to create instance of "
+ entityClass);
}
// set field values
for (Field field : fields) {
setFieldValue(instance, field, cursor);
}
results.add(instance);
}
cursor.close();
return results;
}
}
static <T extends IDbEntity> void setFieldValue(T instance, Field field, Cursor cursor) {
Class<?> type = field.getType();
Object value;
if (type.equals(int.class) || type.equals(Integer.class)) {
value = cursor.getInt(cursor.getColumnIndex(getColumnName(field)));
} else if (type.equals(long.class) || type.equals(Long.class)) {
value = cursor.getLong(cursor.getColumnIndex(getColumnName(field)));
} else if (type.equals(String.class)) {
value = cursor.getString(cursor.getColumnIndex(getColumnName(field)));
} else if (type.isEnum()) {
value = type.getEnumConstants()[cursor.getInt(cursor
.getColumnIndex(getColumnName(field)))];
} else
throw new IllegalArgumentException("Unsupported column type: " + type);
try {
field.set(instance, value);
} catch (Exception ex) {
throw new IllegalArgumentException("Could not set field " + field.getName() + " of "
+ instance.getClass());
}
}
public static String getWhereClause(Uri uri, String selection) {
List<String> pathSegments = uri.getPathSegments();
if (pathSegments.size() > 1) {
if (selection.length() > 0)
selection += " AND ";
selection += "_id=" + pathSegments.get(1);
}
return null;
}
public static String getTableName(Uri uri) {
return uri.getPathSegments().get(0);
}
public static String getUri(String baseUri, Class<? extends IDbEntity> entityClass) {
return baseUri + '/' + DbUtils.getTableName(entityClass);
}
public static ContentValues getValues(IDbEntity entity) {
return getValues(entity, true);
}
public static ContentValues getNonNullValues(IDbEntity entity) {
return getValues(entity, false);
}
static ContentValues getValues(IDbEntity entity, boolean insertNulls) {
List<Field> fields = DbUtils.getFields(entity.getClass());
ContentValues values = new ContentValues(fields.size());
for (Field field : fields) {
DbUtils.addContentValue(values, entity, field, insertNulls);
}
return values;
}
/**
* Converts an object value into a {@link String} value suitable for using
* as a <code>selectionArg</code> in a SQL WHERE statement.
*
* @param value
* @return
*/
public static String getValueAsSqlString(Object value) {
if (value == null) {
throw new IllegalArgumentException(
"I don't expect you can use NULL in this way... should be a special method for that.");
}
if (value instanceof String) {
return (String)value;
} else if (value instanceof Integer) {
return Integer.toString((Integer)value);
} else if (value instanceof Long) {
return Integer.toString((Integer)value);
} else if (value.getClass().isEnum()) {
return Integer.toString(((Enum<?>)value).ordinal());
} else
throw new IllegalArgumentException("Unsupported value type for where statement: "
+ value.getClass().getName());
}
/**
* Credits http://goo.gl/7kOpU
*
* @param db
* @param tableName
* @return
*/
public static List<String> getColumns(SQLiteDatabase db, String tableName) {
List<String> ar = null;
Cursor c = null;
try {
c = db.rawQuery("SELECT * FROM " + tableName + " LIMIT 1", null);
if (c != null) {
ar = new ArrayList<String>(Arrays.asList(c.getColumnNames()));
}
} catch (Exception e) {
Log.v(tableName, e.getMessage(), e);
e.printStackTrace();
} finally {
if (c != null)
c.close();
}
return ar;
}
public static String join(List<String> list, String delim) {
StringBuilder buf = new StringBuilder();
int num = list.size();
for (int i = 0; i < num; i++) {
if (i != 0)
buf.append(delim);
buf.append((String)list.get(i));
}
return buf.toString();
}
}