Android Open Source - Android-Lib-Database Database






From Project

Back to project page Android-Lib-Database.

License

The source code is released under:

Apache License

If you think the Android project Android-Lib-Database listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

package android.lib.database;
/* w w w .  jav  a2 s. c om*/
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.lib.database.predicate.Predicate;
import android.lib.database.query.Delete;
import android.lib.database.query.Insert;
import android.lib.database.query.Query;
import android.lib.database.query.Select;
import android.lib.database.query.Update;
import android.text.TextUtils;

/**
 * Provides database abstraction layer APIs to handle SQLite operations: <code>SELECT</code>,
 * <code>UPDATE</code>, <code>INSERT</code>, <code>DELETE</code>.
 */
public class Database {
    private final SQLiteDatabase database;

    protected Database(final SQLiteDatabase database) {
        this.database = database;
    }

    /**
     * Creates a new instance of {@link Database} with the given <code>context</code>,
     * <code>name</code>, <code>version</code>.
     * @param context the context to use to open or create the database
     * @param name the file name of the database file, or null for an in-memory database
     * @param version the version number of the database (starting at 1); if the database is older,
     * {@link #onUpgrade(SQLiteDatabase, int, int)} will be used to upgrade the database;
     * if the database is newer, {@link #onDowngrade(SQLiteDatabase, int, int)} will be used to downgrade the database
     * @param tables the tables of the database to create in when the application runs for the first time.
     * For subsequent call, <code>tables</code> can be <code>null</code>.
     */
    protected Database(final Context context, final String name, final int version, final Class<?>... tables) {
        this(DatabaseOpenHelper.newInstance(context, name, version, tables).getWritableDatabase());
    }

    /**
     * Creates a new instance of {@link Database} with the given <code>context</code>, <code>name</code>.
     * @param context the context to use to open or create the database
     * @param name the file name of the database file, or null for an in-memory database
     * @param version the version number of the database (starting at 1); if the database is older,
     * {@link #onUpgrade(SQLiteDatabase, int, int)} will be used to upgrade the database;
     * if the database is newer, {@link #onDowngrade(SQLiteDatabase, int, int)} will be used to downgrade the database
     * @param tables the tables of the database to create in when the application runs for the first time.
     * For subsequent call, <code>tables</code> can be <code>null</code>.
     */
    protected Database(final Context context, final String name, final Class<?>... tables) {
        this(DatabaseOpenHelper.newInstance(context, name, tables).getWritableDatabase());
    }

    /**
     * Creates a new instance of {@link Database} with the given <code>context</code>, <code>version</code>.
     * @param context the context to use to open or create the database
     * @param name the file name of the database file, or null for an in-memory database
     * @param version the version number of the database (starting at 1); if the database is older,
     * {@link #onUpgrade(SQLiteDatabase, int, int)} will be used to upgrade the database;
     * if the database is newer, {@link #onDowngrade(SQLiteDatabase, int, int)} will be used to downgrade the database
     * @param tables the tables of the database to create in when the application runs for the first time.
     * For subsequent call, <code>tables</code> can be <code>null</code>.
     */
    protected Database(final Context context, final int version, final Class<?>... tables) {
        this(DatabaseOpenHelper.newInstance(context, version, tables).getWritableDatabase());
    }

    /**
     * Creates a new instance of {@link Database} with the given <code>context</code>.
     * @param context the context to use to open or create the database
     * @param name the file name of the database file, or null for an in-memory database
     * @param version the version number of the database (starting at 1); if the database is older,
     * {@link #onUpgrade(SQLiteDatabase, int, int)} will be used to upgrade the database;
     * if the database is newer, {@link #onDowngrade(SQLiteDatabase, int, int)} will be used to downgrade the database
     * @param tables the tables of the database to create in when the application runs for the first time.
     * For subsequent call, <code>tables</code> can be <code>null</code>.
     */
    protected Database(final Context context, final Class<?>... tables) {
        this(DatabaseOpenHelper.newInstance(context, tables).getWritableDatabase());
    }

    /**
     * Creates a new instance of {@link Database} with the given <code>context</code>,
     * <code>name</code>, <code>version</code>.
     * @param context the context to use to open or create the database
     * @param name the file name of the database file, or null for an in-memory database
     * @param version the version number of the database (starting at 1); if the database is older,
     * {@link #onUpgrade(SQLiteDatabase, int, int)} will be used to upgrade the database;
     * if the database is newer, {@link #onDowngrade(SQLiteDatabase, int, int)} will be used to downgrade the database
     * @param tables the tables of the database to create in when the application runs for the first time.
     * For subsequent call, <code>tables</code> can be <code>null</code>.
     */
    public static Database newInstance(final Context context, final String name, final int version, final Class<?>... tables) {
        return new Database(context, name, version, tables);
    }

    /**
     * Creates a new instance of {@link Database} with the given <code>context</code>, <code>name</code>.
     * @param context the context to use to open or create the database
     * @param name the file name of the database file, or null for an in-memory database
     * @param version the version number of the database (starting at 1); if the database is older,
     * {@link #onUpgrade(SQLiteDatabase, int, int)} will be used to upgrade the database;
     * if the database is newer, {@link #onDowngrade(SQLiteDatabase, int, int)} will be used to downgrade the database
     * @param tables the tables of the database to create in when the application runs for the first time.
     * For subsequent call, <code>tables</code> can be <code>null</code>.
     */
    public static Database newInstance(final Context context, final String name, final Class<?>... tables) {
        return new Database(context, name, tables);
    }

    /**
     * Creates a new instance of {@link Database} with the given <code>context</code>, <code>version</code>.
     * @param context the context to use to open or create the database
     * @param name the file name of the database file, or null for an in-memory database
     * @param version the version number of the database (starting at 1); if the database is older,
     * {@link #onUpgrade(SQLiteDatabase, int, int)} will be used to upgrade the database;
     * if the database is newer, {@link #onDowngrade(SQLiteDatabase, int, int)} will be used to downgrade the database
     * @param tables the tables of the database to create in when the application runs for the first time.
     * For subsequent call, <code>tables</code> can be <code>null</code>.
     */
    public static Database newInstance(final Context context, final int version, final Class<?>... tables) {
        return new Database(context, version, tables);
    }

    /**
     * Creates a new instance of {@link Database} with the given <code>context</code>.
     * @param context the context to use to open or create the database
     * @param name the file name of the database file, or null for an in-memory database
     * @param version the version number of the database (starting at 1); if the database is older,
     * {@link #onUpgrade(SQLiteDatabase, int, int)} will be used to upgrade the database;
     * if the database is newer, {@link #onDowngrade(SQLiteDatabase, int, int)} will be used to downgrade the database
     * @param tables the tables of the database to create in when the application runs for the first time.
     * For subsequent call, <code>tables</code> can be <code>null</code>.
     */
    public static Database newInstance(final Context context, final Class<?>... tables) {
        return new Database(context, tables);
    }

    /**
     * Creates database tables/columns/indices.
     * <p>Call this method on application first-run after installation.</p>
     * <p>This method should be called once per application installation.</p>
     * @param context the context to use to open the database.
     * @param the tables of the database to create.
     */
    public static void createTables(final Context context, final Class<?>... tables) {
        Database.newInstance(context, tables).close();
    }

    /**
     * Closes the database, and abort any uncommitted changes.
     * <p>This is a no-op if the database has already been closed before.</p>
     */
    public void close() {
        if (this.database.isOpen()) {
            if (this.database.inTransaction()) {
                this.database.endTransaction();
            }

            this.database.close();
        }
    }

    /**
     * Persists any uncommitted changes to the database.
     * <p>The current transaction, if any, will be closed when this method returns.
     * If necessary, call {@link #beginTransaction()} to start a new transaction.</p>
     * <p>This is no-op if there is no uncommitted changes</p>
     * @throws IllegalStateException if the database has been closed.
     */
    public void commit() throws IllegalStateException {
        if (this.database.isOpen()) {
            if (this.database.inTransaction()) {
                this.database.setTransactionSuccessful();
                this.database.endTransaction();
            }
        } else {
            throw new IllegalStateException("Database has been closed"); //$NON-NLS-1$
        }
    }

    /**
     * Rolls back any uncommitted changes of the database.
     * <p>The current transaction, if any, will be closed when this method returns.
     * If necessary, call {@link #beginTransaction()} to start a new transaction.</p>
     * <p>This is a no-op if there is no uncommitted changes.</p>
     * @throws IllegalStateException if the database has been closed.
     */
    public void rollback() throws IllegalStateException {
        if (this.database.isOpen()) {
            if (this.database.inTransaction()) {
                this.database.endTransaction();
            }
        } else {
            throw new IllegalStateException("Database has been closed"); //$NON-NLS-1$
        }
    }

    /**
     * Starts a new transaction.
     * <p>If a transaction has already been started and not closed yet,
     * a nested transaction will be started.</p>
     * @throws IllegalStateException if the database has been closed.
     */
    public void beginTransaction() {
        if (this.database.isOpen()) {
            this.database.beginTransaction();
        } else {
            throw new IllegalStateException("Database has been closed"); //$NON-NLS-1$
        }
    }

    /**
     * Executes a {@link Query} of type {@link Select} against the database and returns a list of object
     * of type <code>T</code> using the given {@link RowMapper}.
     * @param query the {@link Query} object containing
     * the raw SQL statement to be executed.
     * @param mapper the mapper to map {@link android.database.Cursor} to <code>T</code>.
     * @param <T> the type of the table object to cast the result set to.
     * @return the result set returned from the query execution.
     * @throws IllegalArgumentException if the column name is not found from the resulting <code>cursor</code>.
     * @throws UnsupportedTypeException if the type <code>T</code> contains fields of unsupported types.
     * @throws IllegalAccessException if the if the default constructor of <code>T</code> is not visible,
     * or the default constructor of the {@link TypeConverter} associated with any field of <code>T</code> is not visible.
     * @throws InstantiationException if the instance of <code>T</code> can not be created,
     * or the instance of the {@link TypeConverter} associated with any field of <code>T</code> can not be created.
     * @throws SQLException if the SQL string is invalid.
     */
    public <T> List<T> execute(final Query query, final RowMapper<T> mapper) throws IllegalArgumentException, IllegalAccessException, InstantiationException, UnsupportedTypeException, SQLException {
        final List<T> rows   = new ArrayList<T>();
        final Cursor  cursor = this.database.rawQuery(query.getRawSQL(), Database.getParameters(query));

        while (cursor.moveToNext()) {
            rows.add(mapper.mapRow(cursor));
        }

        return rows;
    }

    /**
     * Execute SQL <code>SELECT</code> statement against the database and returns the row matching
     * the given <code>id</code>, or <code>null</code> if there is no matching row.
     * @param table the table containing the data to retrieve from.
     * @param idColumn the name of the id column.
     * @param idValue an unique value to match the id column of a row.
     * @return the result set returned from the query execution,
     * or <code>null</code> if there is no matching row.
     * @throws IllegalArgumentException if the column name is not found from the resulting <code>cursor</code>.
     * @throws UnsupportedTypeException if the type <code>T</code> contains fields of unsupported types.
     * @throws IllegalAccessException if the if the default constructor of <code>T</code> is not visible,
     * or the default constructor of the {@link TypeConverter} associated with any field of <code>T</code> is not visible.
     * @throws InstantiationException if the instance of <code>T</code> can not be created,
     * or the instance of the {@link TypeConverter} associated with any field of <code>T</code> can not be created.
     * @throws SQLException if the SQL string is invalid.
     */
    public <T> T selectById(final Class<T> table, final String idColumn, final int idValue) throws IllegalArgumentException, IllegalAccessException, InstantiationException, UnsupportedTypeException, SQLException {
        final List<T> rows = this.execute(Query.select().columns().from(table).where(Predicate.equalTo(idColumn, Integer.valueOf(idValue), false, true)).build(), new RowMapper<T>(table));

        if (rows == null) {
            return null;
        }

        return rows.get(0);
    }

    /**
     * Executes SQL <code>INSERT</code> statement against the database.
     * @param row the data to insert into the database.
     * @throws UnsupportedTypeException if the type <code>T</code> contains fields of unsupported types.
     * @throws IllegalAccessException if the if the default constructor of <code>T</code> is not visible,
     * or the default constructor of the {@link TypeConverter} associated with any field of <code>T</code> is not visible.
     * @throws InstantiationException if the instance of <code>T</code> can not be created,
     * or the instance of the {@link TypeConverter} associated with any field of <code>T</code> can not be created.
     * @throws SQLException if the SQL string is invalid.
     */
    public <T> void insert(final T row) throws IllegalAccessException, InstantiationException, UnsupportedTypeException, SQLException {
        final Class<T>   clazz  = (Class<T>)row.getClass();
        final Insert     insert = Query.insert().into(clazz);
        final Set<Field> fields = new HashSet<Field>();

        for (final Field field : clazz.getFields()) {
            fields.add(field);
        }

        for (final Field field : clazz.getDeclaredFields()) {
            fields.add(field);
        }

        for (final Field field : fields) {
            field.setAccessible(true);

            final Column column = field.getAnnotation(Column.class);

            if (column != null && !column.autoIncrement()) {
                insert.set(TextUtils.isEmpty(column.value()) ? field.getName() : column.value(), Database.getColumnValue(row, field));
            }
        }

        this.execute(insert.build());
    }

    /**
     * Execute SQL <code>DELETE</code> statement against the database and deletes any rows with
     * the matching id value.
     * @param table the table to delete rows from.
     * @param idColumn the name of the id column.
     * @param idValue an unique value to match the id column of a row.
     * @throws SQLException if the SQL string is invalid .
     */
    public <T> void deleteById(final Class<T> table, final String idColumn, final int idValue) throws SQLException {
        this.execute(Query.delete().from(table).where(Predicate.equalTo(idColumn, Integer.valueOf(idValue), false, true)).build());
    }

    /**
     * Executes a {@link Query} of type {@link Update}, {@link Insert} or {@link Delete} against the database.
     * @param query the {@link Query} object to execute.
     * @throws SQLException if the SQL string is invalid .
     */
    public void execute(final Query query) throws SQLException {
        final String[] parameters = Database.getParameters(query);

        if (parameters == null) {
            this.database.execSQL(query.getRawSQL());
        } else {
            this.database.execSQL(query.getRawSQL(), parameters);
        }
    }

    private static String[] getParameters(final Query query) {
        final String[] parameters = query.getParameters().size() > 0 ? new String[query.getParameters().size()] : null;

        if (parameters != null) {
            for (int i = query.getParameters().size(); --i >= 0;) {
                final Object parameter = query.getParameters().get(i);

                parameters[i] = parameter == null ? null : query.getParameters().get(i).toString();
            }
        }

        return parameters;
    }

    private static <T> Object getColumnValue(final T row, final Field field)
                    throws UnsupportedTypeException,
                    IllegalAccessException,
                    InstantiationException {
        final Class<?>     type      = field.getType();
        final UseConverter converter = field.getAnnotation(UseConverter.class);

        if (converter == null) {
            if (type.equals(boolean.class) || type.equals(Boolean.class)) {
                return field.get(row);
            } else if (type.equals(byte.class) || type.equals(Byte.class)) {
                return field.get(row);
            } else if (type.equals(byte[].class) || type.equals(Byte[].class)) {
                return field.get(row);
            } else if (type.equals(double.class) || type.equals(Double.class)) {
                return field.get(row);
            } else if (type.equals(float.class) || type.equals(Float.class)) {
                return field.get(row);
            } else if (type.equals(int.class) || type.equals(Integer.class)) {
                return field.get(row);
            } else if (type.equals(long.class) || type.equals(Long.class)) {
                return field.get(row);
            } else if (type.equals(short.class) || type.equals(Short.class)) {
                return field.get(row);
            } else if (type.equals(String.class)) {
                return field.get(row);
            } else {
                throw new UnsupportedTypeException(String.format("%s is not of SQLite-compatible type", field.getName())); //$NON-NLS-1$
            }
        }

        final Class<?> fromType = converter.type();

        if (fromType.equals(boolean.class) || fromType.equals(Boolean.class)) {
            return ((TypeConverter<?, T>)converter.value().newInstance()).toDatabase((T)field.get(row));
        } else if (fromType.equals(byte.class) || fromType.equals(Byte.class)) {
            return ((TypeConverter<?, T>)converter.value().newInstance()).toDatabase((T)field.get(row));
        } else if (fromType.equals(byte[].class)) {
            return ((TypeConverter<?, T>)converter.value().newInstance()).toDatabase((T)field.get(row));
        } else if (fromType.equals(Byte[].class)) {
            return ((TypeConverter<?, T>)converter.value().newInstance()).toDatabase((T)field.get(row));
        } else if (fromType.equals(double.class) || fromType.equals(Double.class)) {
            return ((TypeConverter<?, T>)converter.value().newInstance()).toDatabase((T)field.get(row));
        } else if (fromType.equals(float.class) || fromType.equals(Float.class)) {
            return ((TypeConverter<?, T>)converter.value().newInstance()).toDatabase((T)field.get(row));
        } else if (fromType.equals(int.class) || fromType.equals(Integer.class)) {
            return ((TypeConverter<?, T>)converter.value().newInstance()).toDatabase((T)field.get(row));
        } else if (fromType.equals(long.class) || fromType.equals(Long.class)) {
            return ((TypeConverter<?, T>)converter.value().newInstance()).toDatabase((T)field.get(row));
        } else if (fromType.equals(short.class) || fromType.equals(Short.class)) {
            return ((TypeConverter<?, T>)converter.value().newInstance()).toDatabase((T)field.get(row));
        } else if (fromType.equals(String.class)) {
            return ((TypeConverter<?, T>)converter.value().newInstance()).toDatabase((T)field.get(row));
        } else {
            throw new UnsupportedTypeException(String.format("%s is not of SQLite-compatible type", field.getName())); //$NON-NLS-1$
        }
    }
}




Java Source Code List

android.lib.database.Column.java
android.lib.database.CompositeIndex.java
android.lib.database.DatabaseOpenHelper.java
android.lib.database.Database.java
android.lib.database.DateConverter.java
android.lib.database.Index.java
android.lib.database.JSONRowMapper.java
android.lib.database.RowMapper.java
android.lib.database.Table.java
android.lib.database.TypeConverter.java
android.lib.database.UniqueCompositeIndex.java
android.lib.database.UnsupportedTypeException.java
android.lib.database.UseConverter.java
android.lib.database.predicate.ManySidedPredicate.java
android.lib.database.predicate.Predicate.java
android.lib.database.predicate.ThreeSidedPredicate.java
android.lib.database.predicate.TwoSidedPredicate.java
android.lib.database.query.Delete.java
android.lib.database.query.Insert.java
android.lib.database.query.QueryBuilder.java
android.lib.database.query.Query.java
android.lib.database.query.Select.java
android.lib.database.query.Update.java