Skip to content

Instantly share code, notes, and snippets.

@rhoadster91
Last active May 26, 2016 14:20
Show Gist options
  • Select an option

  • Save rhoadster91/102e3e2b398d58837e94af08db779a65 to your computer and use it in GitHub Desktop.

Select an option

Save rhoadster91/102e3e2b398d58837e94af08db779a65 to your computer and use it in GitHub Desktop.
Class to help you put all data from one SQLite table to another during database migration. You can selectively choose which columns to migrate. Currently supports columns that are of type String, Int, Long, Double, Float, but adding a new type is easy: just add a new Parser<YourType> in the supportedParsers list.
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.database.sqlite.SQLiteStatement;
import android.util.Log;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class DatabaseMigrator {
private abstract static class Parser<T> {
Class<T> classOfT;
Parser(Class<T> classOfT) {
this.classOfT = classOfT;
}
public abstract T get(Cursor c, int index);
public abstract void bind(SQLiteStatement statement, int index, Object value);
}
static List<Parser> supportedParsers = new ArrayList<>();
static {
supportedParsers.add(new Parser<Integer>(Integer.class) {
@Override
public Integer get(Cursor c, int index) {
return c.getInt(index);
}
@Override
public void bind(SQLiteStatement statement, int index, Object value) {
Long val = new Long(((Integer)value).longValue());
statement.bindLong(index, val);
}
});
supportedParsers.add(new Parser<Long>(Long.class){
@Override
public Long get(Cursor c, int index) {
return c.getLong(index);
}
@Override
public void bind(SQLiteStatement statement, int index, Object value) {
statement.bindLong(index, (Long) value);
}
});
supportedParsers.add(new Parser<String>(String.class){
@Override
public String get(Cursor c, int index) {
return c.getString(index);
}
@Override
public void bind(SQLiteStatement statement, int index, Object value) {
statement.bindString(index, (String) value);
}
});
supportedParsers.add(new Parser<Double>(Double.class){
@Override
public Double get(Cursor c, int index) {
return c.getDouble(index);
}
@Override
public void bind(SQLiteStatement statement, int index, Object value) {
statement.bindDouble(index, (Double) value);
}
});
supportedParsers.add(new Parser<Float>(Float.class){
@Override
public Float get(Cursor c, int index) {
return c.getFloat(index);
}
@Override
public void bind(SQLiteStatement statement, int index, Object value) {
Double val = new Double(((Float)value).doubleValue());
statement.bindDouble(index, val);
}
});
}
public static void migrate(SQLiteDatabase db, String oldTable, String newTable, List<Triplet> triplets) {
Cursor c = getAllValues(db, oldTable, getCollectionAsArray(TripletUtils.getColumns(triplets, TripletUtils.TYPE_OLD)));
if(c.moveToFirst()) {
do {
Object []values = getObjectsFromCursor(c, TripletUtils.getClasses(triplets));
String argsSymbol = getCollectionAsArgsSymbol(values);
String insertStatement = "INSERT INTO " + newTable + "(" + getCollectionAsString(TripletUtils.getColumns(triplets, TripletUtils.TYPE_NEW)) + ") VALUES(" + argsSymbol + ")";
SQLiteStatement mStatement = db.compileStatement(insertStatement);
insert(mStatement, TripletUtils.getClasses(triplets), values);
} while (c.moveToNext());
}
c.close();
}
protected static Object [] getObjectsFromCursor(Cursor c, List<Class> classes) {
Object []objects = new Object[c.getColumnCount()];
for(int i = 0; i < c.getColumnCount(); i++) {
objects[i] = getAs(i, c, classes.get(i));
}
return objects;
}
protected static void bindValues(SQLiteStatement mStatement, Object []values, List<Class> newClasses) {
mStatement.clearBindings();
for(int i = 0; i < values.length; i++) {
bindAs(mStatement, i+1, values[i], newClasses.get(i));
}
}
private static Object getAs(int index, Cursor c, Class clazz) {
Object obj = null;
for(Parser parser : supportedParsers) {
if(parser.classOfT == clazz) {
obj = parser.get(c, index);
}
}
return obj;
}
private static void bindAs(SQLiteStatement mStatement, int index, Object value, Class clazz) {
if(value==null) {
mStatement.bindNull(index);
return;
}
for(Parser<?> parser : supportedParsers) {
if(parser.classOfT == clazz) {
parser.bind(mStatement, index, value);
}
}
}
private static Cursor getAllValues(SQLiteDatabase db, String table, String []columns) {
return db.query(table, columns, null, null, null, null, null);
}
private static void insert(SQLiteStatement mStatement, List<Class> newClasses, Object[] values) {
try {
bindValues(mStatement, values, newClasses);
mStatement.executeInsert();
} catch (SQLiteException sqle) {
sqle.printStackTrace();
} catch (Throwable t) {
t.printStackTrace();
}
}
public static List<Triplet> createMap(Triplet... triplets) {
if(triplets==null || triplets.length == 0) {
throw new IllegalArgumentException("There should be even non-zero number of columns");
}
List<Triplet> tripletList = new ArrayList<>();
for(Triplet triplet : triplets) {
tripletList.add(triplet);
}
return tripletList;
}
private static String getCollectionAsString(Collection<String> set) {
StringBuilder sb = new StringBuilder();
int i = 0;
for(String str : set) {
sb.append(str);
if(i != set.size()-1) {
sb.append(", ");
}
i++;
}
return sb.toString();
}
private static String []getCollectionAsArray(Collection<String> set) {
String []strings = new String[set.size()];
int i = 0;
for(String str : set) {
strings[i] = str;
i++;
}
return strings;
}
private static String getCollectionAsArgsSymbol(Object []values) {
StringBuilder sb = new StringBuilder();
for(int i = 0; i < values.length-1; i++) {
sb.append("?,");
}
sb.append("?");
return sb.toString();
}
public static class Triplet {
String oldName;
String newName;
Class dataType;
public Triplet(String oldName, String newName, Class dataType) {
this.oldName = oldName;
this.newName = newName;
this.dataType = dataType;
}
}
private static class TripletUtils {
public static final int TYPE_OLD = 1;
public static final int TYPE_NEW = 2;
public static List<String> getColumns(List<Triplet> triplets, int type) {
List<String> columns = new ArrayList<>();
for(Triplet triplet : triplets) {
columns.add(type == TYPE_OLD?triplet.oldName:triplet.newName);
}
return columns;
}
public static List<Class> getClasses(List<Triplet> triplets) {
List<Class> classes = new ArrayList<>();
for(Triplet triplet : triplets) {
classes.add(triplet.dataType);
}
return classes;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment