All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.codeslap.persistence.SqliteAdapterImpl Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2013 CodeSlap
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.codeslap.persistence;

import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.text.TextUtils;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

/**
 * This is a persistence adapter that uses sqlite database as persistence engine.
 * This is useful to persist collections of beans. To save single objects (objects
 * that don't get repeated, singletons, or any data that don't fit into the tables
 * paradigm), use PreferencesAdapter.
 */
public class SqliteAdapterImpl implements SqlAdapter {

    // this expression is used when inserting rows in the many-to-many relation tables. It will basically
    // prevent a row from being inserted when the values already exist.
    private static final String HACK_INSERT_FORMAT = "CASE WHEN (SELECT COUNT(*) FROM %s WHERE %s = %s AND %s = %s) == 0 THEN %s ELSE NULL END";
    private static final String TAG = "sqliteImpl";

    private final DatabaseSpec mDatabaseSpec;
    private final SqliteDb mDbHelper;

    SqliteAdapterImpl(Context context, String name, String specId) {
        mDatabaseSpec = PersistenceConfig.getDatabaseSpec(specId);
        mDbHelper = SqliteDb.getInstance(context, name, mDatabaseSpec);
    }

    @Override
    public  T findFirst(T sample) {
        Class clazz = (Class) sample.getClass();
        ArrayList args = new ArrayList();
        String where = SQLHelper.getWhere(clazz, sample, args, null, mDatabaseSpec);
        Cursor query = mDbHelper.getDatabase().query(SQLHelper.getTableName(clazz), null, where, args.toArray(new String[args.size()]), null, null, null, "1");
        return findFirstFromCursor(clazz, query);
    }

    @Override
    public  T findFirst(Class clazz, String where, String[] whereArgs) {
        Cursor query = mDbHelper.getDatabase().query(SQLHelper.getTableName(clazz), null, where, whereArgs, null, null, null, "1");
        return findFirstFromCursor(clazz, query);
    }

    @Override
    public  List findAll(Class theClass) {
        T emptySample = null;
        try {
            emptySample = theClass.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return findAll(emptySample, null);
    }

    @Override
    public  List findAll(T where) {
        return findAll(where, null);
    }

    @Override
    public  List findAll(T where, G attachedTo) {
        return findAll((Class) where.getClass(), where, attachedTo, null);
    }

    @Override
    public  List findAll(Class clazz, String where, String[] whereArgs) {
        Cursor query = getCursorFindAllWhere(clazz, where, whereArgs);
        return findAllFromCursor(clazz, query);
    }

    @Override
    public  List findAll(T where, Constraint constraint) {
        Class clazz = (Class) where.getClass();
        return findAll(clazz, where, null, constraint);
    }

    @Override
    public  Object store(T bean) {
        return store(bean, null);
    }

    @Override
    public  Object store(T bean, G attachedTo) {
        if (bean == null) {
            return null;
        }
        Class theClass = bean.getClass();
        List transactions = new ArrayList();
        String sqlStatement = getSqlStatement(bean, new Node(theClass), attachedTo);
        if (sqlStatement != null) {
            String[] statements = sqlStatement.split(SQLHelper.STATEMENT_SEPARATOR);
            for (String statement : statements) {
                if (TextUtils.isEmpty(statement)) {
                    continue;
                }
                transactions.add(statement);
            }
        }
        executeTransactions(transactions);
        Field idField = SQLHelper.getPrimaryKeyField(theClass);
        // if it is autoincrement, we will try to populate the id field with the inserted id
        if (mDatabaseSpec.isAutoincrement(theClass)) {
            if(idField.getType() != Long.class && idField.getType() != long.class){
                throw new IllegalStateException("Your primary key is currently '" + idField.getType() + "' but 'long' was expected");
            }
            Cursor lastId = mDbHelper.getDatabase().query("sqlite_sequence", new String[]{"seq"}, "name = ?",
                    new String[]{SQLHelper.getTableName(theClass)}, null, null, null);
            if (lastId != null && lastId.moveToFirst()) {
                long id = lastId.getLong(0);
                lastId.close();
                if (idField != null) {
                    idField.setAccessible(true);
                    try {
                        idField.set(bean, id);
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    } catch (IllegalArgumentException e) {
                        e.printStackTrace();
                    }
                }
                return id;
            } else if (lastId != null) {
                lastId.close();
            }
        } else {
            try {
                idField.setAccessible(true);
                return idField.get(bean);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    @Override
    public  void storeCollection(List collection, ProgressListener listener) {
        storeCollection(collection, null, listener);
    }

    @Override
    public  void storeCollection(List collection, G attachedTo, ProgressListener listener) {
        if (listener != null) {
            listener.onProgressChange(0);
        }
        if (collection.isEmpty()) {
            return;
        }
        List transactions = new ArrayList();
        DatabaseSpec.Relationship relationship = mDatabaseSpec.getRelationship(collection.get(0).getClass());
        // if there is no listener, attached object, collection is too small or objects in the list have inner
        // relationships: insert them in a normal way, in which there will be a sql execution per object
        if (listener != null || attachedTo != null || collection.size() <= 1 || relationship != DatabaseSpec.Relationship.UNKNOWN) {
            int progress;
            int all = collection.size() + 1; // 1 == commit phase
            for (int i = 0, collectionSize = collection.size(); i < collectionSize; i++) {
                T object = collection.get(i);
                String sqlStatement = getSqlStatement(object, new Node(object.getClass()), attachedTo);
                if (sqlStatement == null) {
                    continue;
                }
                String[] statements = sqlStatement.split(SQLHelper.STATEMENT_SEPARATOR);
                Collections.addAll(transactions, statements);
                if (listener != null) {
                    progress = i * 100 / all;
                    listener.onProgressChange(progress);
                }
            }
        } else {
            // get current table size
            int count = count(collection.get(0).getClass());
            boolean tryToUpdate = count > 0;

            // if it reaches here, we can insert collection in a faster way by creating few sql statements
            StringBuilder builder = new StringBuilder();
            for (int i = 0, collectionSize = collection.size(), newItems = 0; i < collectionSize; i++) {
                T bean = collection.get(i);
                if (tryToUpdate) {
                    String updateStatement = getUpdateStatementIfPossible(bean);
                    if (!TextUtils.isEmpty(updateStatement)) {
                        String[] statements = updateStatement.split(SQLHelper.STATEMENT_SEPARATOR);
                        Collections.addAll(transactions, statements);
                        continue;
                    }
                }
                if (newItems % 400 == 0) {
                    if (newItems > 0) {
                        transactions.add(builder.append(";").toString());
                        builder = new StringBuilder();
                    }
                    builder.append(SQLHelper.getFastInsertSqlHeader(bean, mDatabaseSpec));
                } else {
                    builder.append(SQLHelper.getUnionInsertSql(bean, mDatabaseSpec));
                }
                newItems++;
            }
            if (builder.length() > 0) {
                String sql = builder.append(";").toString();
                transactions.add(sql);
            }
        }
        executeTransactions(transactions);
        if (listener != null) {
            listener.onProgressChange(100);
        }
    }

    @Override
    public  void storeUniqueCollection(List collection, ProgressListener listener) {
        if (collection.size() > 0) {
            try {
                Class theClass = (Class) collection.get(0).getClass();
                Field id = theClass.getDeclaredField("id");
                id.setAccessible(true);
                List allStored = findAll(theClass);
                for (T stored : allStored) {
                    boolean contained = false;
                    for (T object : collection) {
                        Object storedId = id.get(stored);
                        Object storedObject = id.get(object);
                        if (storedId != null && storedObject != null && storedId.equals(storedObject)) {
                            contained = true;
                            break;
                        }
                    }
                    if (!contained) {
                        delete(stored);
                    }
                }
            } catch (Exception ignored) {
                // not a big deal
            }
        }
        storeCollection(collection, listener);
    }

    @Override
    public  int update(T object, T sample) {
        if (object == null) {
            return 0;
        }
        ArrayList args = new ArrayList();
        String where = SQLHelper.getWhere(object.getClass(), sample, args, null, mDatabaseSpec);
        return update(object, where, args.toArray(new String[args.size()]));
    }

    @Override
    public  int update(T bean, String where, String[] whereArgs) {
        if (bean == null) {
            return 0;
        }
        int count = count(bean.getClass(), where, whereArgs);
        if (whereArgs != null) {
            for (String arg : whereArgs) {
                where = where.replaceFirst("\\?", String.format("'%s'", arg));
            }
        }
        String sqlStatement = SQLHelper.buildUpdateStatement(bean, where);
        String[] statements = sqlStatement.split(SQLHelper.STATEMENT_SEPARATOR);
        executeTransactions(Arrays.asList(statements));
        return count;
    }

    @Override
    public  int delete(T sample) {
        return delete(sample, false);
    }

    @Override
    public  int delete(T sample, boolean onCascade) {
        if (sample == null) {
            return -1;
        }
        ArrayList args = new ArrayList();
        String where = SQLHelper.getWhere(sample.getClass(), sample, args, null, mDatabaseSpec);
        String[] argsArray = args.toArray(new String[args.size()]);
        return delete(sample.getClass(), where, argsArray);
    }

    @Override
    public  int delete(Class theClass, String where, String[] whereArgs) {
        return delete(theClass, where, whereArgs, false);
    }

    @Override
    public  int delete(Class theClass, String where, String[] whereArgs, boolean onCascade) {
        DatabaseSpec.Relationship relationship = mDatabaseSpec.getRelationship(theClass);
        if (!relationship.equals(DatabaseSpec.Relationship.UNKNOWN)) {
            Field idField = SQLHelper.getPrimaryKeyField(theClass);
            idField.setAccessible(true);
            switch (relationship) {
                case HAS_MANY:
                    if (onCascade) {
                        HasMany hasMany = mDatabaseSpec.has(theClass);
                        List toDelete = findAll(theClass, where, whereArgs);
                        for (T object : toDelete) {
                            try {
                                Object objectId = idField.get(object);
                                Class containedClass = hasMany.getContainedClass();
                                String whereForeign = String.format("%s = '%s'", hasMany.getForeignKey(), String.valueOf(objectId));
                                delete(containedClass, whereForeign, null);
                            } catch (IllegalAccessException ignored) {
                            }
                        }
                    }
                    break;
                case MANY_TO_MANY:
                    List manyToManyList = mDatabaseSpec.getManyToMany(theClass);
                    for (ManyToMany manyToMany : manyToManyList) {
                        String foreignKey;
                        String foreignCurrentKey;
                        Class relationTable;
                        if (manyToMany.getFirstRelation() == theClass) {
                            foreignKey = manyToMany.getMainKey();
                            foreignCurrentKey = manyToMany.getSecondaryKey();
                            relationTable = manyToMany.getSecondRelation();
                        } else {
                            foreignKey = manyToMany.getSecondaryKey();
                            foreignCurrentKey = manyToMany.getMainKey();
                            relationTable = manyToMany.getFirstRelation();
                        }
                        List toRemove = findAll(theClass, where, whereArgs);
                        for (T object : toRemove) {
                            try {
                                Object objectId = idField.get(object);
                                String whereForeign = String.format("%s = '%s'", foreignKey, String.valueOf(objectId));

                                List ids = new ArrayList();
                                if (onCascade) {
                                    Cursor deletionCursor = mDbHelper.getDatabase().query(manyToMany.getTableName(), null, whereForeign, null, null, null, null);
                                    if (deletionCursor.moveToFirst()) {
                                        do {
                                            int index = deletionCursor.getColumnIndex(foreignCurrentKey);
                                            ids.add(deletionCursor.getString(index));
                                        } while (deletionCursor.moveToNext());
                                    }
                                    deletionCursor.close();
                                }

                                mDbHelper.getDatabase().delete(manyToMany.getTableName(), whereForeign, null);

                                for (String id : ids) {
                                    String whereRest = String.format("%s = '%s'", foreignCurrentKey, id);
                                    Cursor cursorRest = mDbHelper.getDatabase().query(manyToMany.getTableName(), null, whereRest, null, null, null, null);
                                    // this means there is no other relation with this object, so we can delete it on cascade :)
                                    if (cursorRest.getCount() == 0) {
                                        mDbHelper.getDatabase().delete(SQLHelper.getTableName(relationTable), SQLHelper._ID + " = ?", new String[]{id});
                                    }
                                }
                            } catch (IllegalAccessException ignored) {
                            }
                        }
                    }
                    break;
            }
        }

        return mDbHelper.getDatabase().delete(SQLHelper.getTableName(theClass), where, whereArgs);
    }

    @Override
    public void truncate(Class... classes) {
        for (Class theClass : classes) {
            String tableName = SQLHelper.getTableName(theClass);
            mDbHelper.getDatabase().delete(tableName, null, null);
            mDbHelper.getDatabase().delete("sqlite_sequence", "name LIKE ?", new String[]{tableName});
        }
    }

    @Override
    public  int count(T bean) {
        Cursor query = SQLHelper.getCursorFindAllWhere(mDbHelper.getDatabase(), bean.getClass(), bean, null, null, mDatabaseSpec);
        int count = query.getCount();
        query.close();
        return count;
    }

    @Override
    public  int count(Class clazz, String where, String[] whereArgs) {
        Cursor query = mDbHelper.getDatabase().query(SQLHelper.getTableName(clazz), null, where, whereArgs, null, null, null);
        int count = query.getCount();
        query.close();
        return count;
    }

    @Override
    public  int count(Class clazz) {
        Cursor query = SQLHelper.getCursorFindAllWhere(mDbHelper.getDatabase(), clazz, null, null, null, mDatabaseSpec);
        int count = query.getCount();
        query.close();
        return count;
    }

    private synchronized void executeTransactions(List transactions) {
        SQLiteDatabase database = mDbHelper.getDatabase();
        boolean activeTransaction = false;
        try {
            database.execSQL("BEGIN TRANSACTION;");
            activeTransaction = true;
        } catch (Exception e) {
            PersistenceLogManager.e(TAG, "Could not initiate transaction", e);
        }

        // try to execute the statements and commit if, and only if,
        // the BEGIN TRANSACTION; was successful
        if (activeTransaction) {
            for (String transaction : transactions) {
                try {
                    database.execSQL(transaction);
                } catch (Exception e) {
                    PersistenceLogManager.e(TAG, "Error executing transaction: " + transaction, e);
                }
            }
            try {
                database.execSQL("COMMIT;");
            } catch (Exception e) {
                // we are doomed; yes, we are. there was an active transaction and yet
                // transaction could not be committed.
                PersistenceLogManager.e(TAG, "Could not commit transaction", e);
            }
        }
    }

    private  List findAll(Class clazz, T where, G attachedTo, Constraint constraint) {
        Cursor query = SQLHelper.getCursorFindAllWhere(mDbHelper.getDatabase(), clazz, where, attachedTo, constraint, mDatabaseSpec);
        return findAllFromCursor(clazz, query);
    }

    private  List findAllFromCursor(Class clazz, Cursor query) {
        List beans = new ArrayList();
        if (query.moveToFirst()) {
            do {
                T bean = getBeanFromCursor(clazz, query, new Node(clazz));
                beans.add(bean);
            } while (query.moveToNext());
        }
        query.close();
        return beans;
    }

    private  Cursor getCursorFindAllWhere(Class clazz, String where, String[] args) {
        return mDbHelper.getDatabase().query(SQLHelper.getTableName(clazz), null, where, args, null, null, null, null);
    }

    private  String getSqlStatement(T bean, Node tree, G attachedTo) {
        String updateStatement = getUpdateStatementIfPossible(bean);
        if (!TextUtils.isEmpty(updateStatement)) {
            return updateStatement;
        }
        String mainInsertStatement = SQLHelper.getInsertStatement(bean, attachedTo, mDatabaseSpec);
        try {
            mainInsertStatement += getSqlInsertForChildrenOf(bean, tree);
        } catch (IllegalAccessException ignored) {
        }
        return mainInsertStatement;
    }

    private  String getUpdateStatementIfPossible(T bean) {
        // try to find the bean by id and if it exists, do not insert it, update it
        Class theClass = (Class) bean.getClass();
        // get its ID and make sure primary key is not null
        Field theId = SQLHelper.getPrimaryKeyField(theClass);
        theId.setAccessible(true);
        if (theId.getType() == String.class ||
                theId.getType() == Float.class ||
                theId.getType() == Double.class) {
            Object idValue = null;
            try {
                idValue = theId.get(bean);
            } catch (IllegalAccessException ignored) {
            }
            if (idValue == null) {
                throw new IllegalStateException("You cannot insert an object whose primary key is null and it is not int or long");
            }
        }
        String result = null;
        try {
            Object beanId = theId.get(bean);
            if (SQLHelper.hasData(theId.getType(), beanId)) {
                // create an object of the same type of the bean with the same id to search of it
                Constructor constructor = theClass.getConstructor();
                Object sample = constructor.newInstance();
                theId.set(sample, beanId);

                Object match = findFirst((T) sample);
                if (match != null) {
                    // if they are the same, do nothing...
                    if (bean.equals(match)) {
                        result = SQLHelper.STATEMENT_SEPARATOR;
                    } else {
                        // update the bean using the just created sample
                        result = SQLHelper.buildUpdateStatement(bean, match, mDatabaseSpec);
                    }
                }
            }
        } catch (Exception ignored) {
        }
        return result;
    }

    private  String getSqlInsertForChildrenOf(T bean, Node tree) throws IllegalAccessException {// bodom
        // get a list with the fields that are lists
        Class theClass = bean.getClass();
        Field[] fields = SQLHelper.getDeclaredFields(theClass);
        List collectionFields = new ArrayList();
        for (Field field : fields) {
            if (field.getType() == List.class) {
                collectionFields.add(field);
                field.setAccessible(true);
            }
        }

        String sqlStatement = "";
        for (Field field : collectionFields) {
            // get the generic type for this list field
            ParameterizedType stringListType = (ParameterizedType) field.getGenericType();
            Class collectionClass = (Class) stringListType.getActualTypeArguments()[0];
            Node child = new Node(collectionClass);
            if (!tree.addChild(child)) {
                continue;
            }
            switch (mDatabaseSpec.getRelationship(theClass, collectionClass)) {
                case MANY_TO_MANY: {
                    List list = (List) field.get(bean);
                    if (list != null) {
                        for (Object object : list) {
                            // get the insertion SQL
                            String partialSqlStatement = getSqlStatement(object, tree, null);
                            if (partialSqlStatement != null) {
                                sqlStatement += partialSqlStatement;
                            }
                            // insert items in the joined table
                            // get the table name and columns
                            String relationTableName = ManyToMany.buildTableName(theClass, collectionClass);
                            String mainForeignKey = SQLHelper.getTableName(theClass) + "_id";
                            String secondaryForeignKey = SQLHelper.getTableName(collectionClass) + "_id";

                            // get the value for the main bean ID
                            Object beanId;
                            if (mDatabaseSpec.isAutoincrement(theClass)) {
                                beanId = String.format(SQLHelper.SELECT_AUTOINCREMENT_FORMAT, SQLHelper.getTableName(theClass));
                            } else {
                                Field mainId = SQLHelper.getPrimaryKeyField(theClass);
                                mainId.setAccessible(true);
                                beanId = mainId.get(bean);
                            }

                            // get the value for the secondary bean ID
                            Object secondaryId;
                            if (mDatabaseSpec.isAutoincrement(collectionClass)) {
                                secondaryId = String.format(SQLHelper.SELECT_AUTOINCREMENT_FORMAT, SQLHelper.getTableName(collectionClass));
                            } else {
                                Field secondaryIdField = SQLHelper.getPrimaryKeyField(collectionClass);
                                secondaryIdField.setAccessible(true);
                                secondaryId = secondaryIdField.get(object);
                            }

                            // build the sql statement for the insertion of the many-to-many relation
                            String hack = String.format(HACK_INSERT_FORMAT, relationTableName, mainForeignKey,
                                    String.valueOf(beanId), secondaryForeignKey,
                                    String.valueOf(secondaryId), String.valueOf(beanId));
                            sqlStatement += String.format("INSERT OR IGNORE INTO %s (%s, %s) VALUES (%s, %s);%s",
                                    relationTableName, mainForeignKey, secondaryForeignKey,
                                    hack, String.valueOf(secondaryId), SQLHelper.STATEMENT_SEPARATOR);
                        }
                    }
                    break;
                }
                case HAS_MANY:
                    List list = (List) field.get(bean);
                    if (list == null) {
                        break;
                    }
                    for (Object object : list) {
                        // prepare the object by setting the foreign value
                        String partialSqlStatement = getSqlStatement(object, tree, bean);
                        if (partialSqlStatement != null) {
                            sqlStatement += partialSqlStatement;
                        }
                    }
                    break;
            }
            tree.removeChild(child);
        }
        return sqlStatement;
    }

    private  T findFirstFromCursor(Class clazz, Cursor query) {
        if (query.moveToFirst()) {
            T bean = getBeanFromCursor(clazz, query, new Node(clazz));
            query.close();
            return bean;
        }
        query.close();
        return null;
    }

    private  T getBeanFromCursor(Class theClass, Cursor query, Node tree) {
        T bean;
        try {
            Constructor constructor = theClass.getConstructor();
            bean = constructor.newInstance();
        } catch (Exception e) {
            throw new RuntimeException("Could not initialize object of type " + theClass + ", " + e.getMessage());
        }

        // get each field and put its value in a content values object
        Field[] fields = SQLHelper.getDeclaredFields(theClass);
        for (Field field : fields) {
            // get the column index
            String normalize = SQLHelper.getColumnName(field);
            int columnIndex = query.getColumnIndex(normalize);
            // get an object value depending on the type
            Class type = field.getType();
            Object value = null;
            if (columnIndex == -1 && type == List.class) {
                ParameterizedType stringListType = (ParameterizedType) field.getGenericType();
                Class collectionClass = (Class) stringListType.getActualTypeArguments()[0];
                Node node = new Node(collectionClass);
                if (tree.addChild(node)) {
                    switch (mDatabaseSpec.getRelationship(theClass, collectionClass)) {
                        case MANY_TO_MANY: {
                            Field collectionId = SQLHelper.getPrimaryKeyField(collectionClass);
                            // build a query that uses the joining table and the joined object
                            String collectionTableName = SQLHelper.getTableName(collectionClass);
                            String sql = new StringBuilder().append("SELECT * FROM ")
                                    .append(SQLHelper.getTableName(collectionClass))
                                    .append(" WHERE ")
                                    .append(SQLHelper.getIdColumn(collectionId))
                                    .append(" IN (SELECT ")
                                    .append(collectionTableName)
                                    .append(SQLHelper._ID)
                                    .append(" FROM ")
                                    .append(ManyToMany.buildTableName(theClass, collectionClass))
                                    .append(" WHERE ")
                                    .append(SQLHelper.getTableName(theClass))
                                    .append(SQLHelper._ID)
                                    .append(" = ?)").toString();
                            // execute the query
                            String[] selectionArgs = new String[1];
                            long id = query.getLong(query.getColumnIndex(SQLHelper._ID));
                            selectionArgs[0] = String.valueOf(id);
                            Cursor join = mDbHelper.getDatabase().rawQuery(sql, selectionArgs);
                            // set the result to the current field
                            List listValue = new ArrayList();
                            if (join.moveToFirst()) {
                                do {
                                    Object beanFromCursor = getBeanFromCursor(collectionClass, join, tree);
                                    listValue.add(beanFromCursor);
                                } while (join.moveToNext());
                            }
                            join.close();
                            value = listValue;
                        }
                        break;
                        case HAS_MANY:
                            // build a query that uses the joining table and the joined object
                            HasMany belongsTo = mDatabaseSpec.belongsTo(collectionClass);
                            Field throughField = belongsTo.getThroughField();
                            Object foreignValue = getValueFromCursor(throughField.getType(), belongsTo.getThroughColumnName(), query);
                            if (foreignValue != null) {
                                String sql = new StringBuilder().append("SELECT * FROM ")
                                        .append(SQLHelper.getTableName(collectionClass))
                                        .append(" WHERE ")
                                        .append(belongsTo.getForeignKey())
                                        .append(" = '")
                                        .append(foreignValue)
                                        .append("'").toString();
                                // execute the query and set the result to the current field
                                Cursor join = mDbHelper.getDatabase().rawQuery(sql, null);
                                List listValue = new ArrayList();
                                if (join.moveToFirst()) {
                                    do {
                                        Object beanFromCursor = getBeanFromCursor(collectionClass, join, tree);
                                        listValue.add(beanFromCursor);
                                    } while (join.moveToNext());
                                }
                                join.close();
                                value = listValue;
                            }
                            break;
                    }
                    tree.removeChild(node);
                }
            } else {// do not process collections here
                value = getValueFromCursor(type, SQLHelper.getColumnName(field), query);
            }
            try {
                if (value != null) {
                    field.setAccessible(true);
                    field.set(bean, value);
                }
            } catch (Exception e) {
                throw new RuntimeException(String.format("An error occurred setting value to \"%s\", (%s): %s%n", field, value, e.getMessage()));
            }
        }
        return bean;
    }

    private Object getValueFromCursor(Class type, String name, Cursor query) {
        try {
            // get the column index
            int columnIndex = query.getColumnIndex(name);
            // get an object value depending on the type
            Object value = null;
            if (type == int.class || type == Integer.class) {
                value = query.getInt(columnIndex);
            } else if (type == long.class || type == Long.class) {
                value = query.getLong(columnIndex);
            } else if (type == boolean.class || type == Boolean.class) {
                value = query.getInt(columnIndex) == 1;
            } else if (type == float.class || type == Float.class || type == double.class || type == Double.class) {
                value = query.getFloat(columnIndex);
            } else if (type == String.class) {
                value = query.getString(columnIndex);
            } else if (type == byte[].class || type == Byte[].class) {
                value = query.getBlob(columnIndex);
            }
            return value;
        } catch (Exception e) {
            throw new IllegalStateException("Error getting column " + name, e);
        }
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy