ru.orangesoftware.financisto2.db.MyEntityManager.java Source code

Java tutorial

Introduction

Here is the source code for ru.orangesoftware.financisto2.db.MyEntityManager.java

Source

/*******************************************************************************
 * Copyright (c) 2010 Denis Solonenko.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Public License v2.0
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 *
 * Contributors:
 *     Denis Solonenko - initial API and implementation
 ******************************************************************************/
package ru.orangesoftware.financisto2.db;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.support.v4.util.LongSparseArray;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import ru.orangesoftware.financisto2.blotter.BlotterFilter;
import ru.orangesoftware.financisto2.datetime.Period;
import ru.orangesoftware.financisto2.filter.Criteria;
import ru.orangesoftware.financisto2.filter.WhereFilter;
import ru.orangesoftware.financisto2.model.Account;
import ru.orangesoftware.financisto2.model.Attribute;
import ru.orangesoftware.financisto2.model.Budget;
import ru.orangesoftware.financisto2.model.Category;
import ru.orangesoftware.financisto2.model.Currency;
import ru.orangesoftware.financisto2.model.MyEntity;
import ru.orangesoftware.financisto2.model.Payee;
import ru.orangesoftware.financisto2.model.Project;
import ru.orangesoftware.financisto2.model.SystemAttribute;
import ru.orangesoftware.financisto2.model.Transaction;
import ru.orangesoftware.financisto2.model.TransactionAttributeInfo;
import ru.orangesoftware.financisto2.model.TransactionInfo;
import ru.orangesoftware.financisto2.utils.MyPreferences;
import ru.orangesoftware.financisto2.utils.MyPreferences.AccountSortOrder;
import ru.orangesoftware.financisto2.utils.RecurUtils;
import ru.orangesoftware.financisto2.utils.RecurUtils.Recur;
import ru.orangesoftware.financisto2.utils.Utils;
import ru.orangesoftware.orb.EntityManager;
import ru.orangesoftware.orb.Expression;
import ru.orangesoftware.orb.Expressions;
import ru.orangesoftware.orb.Query;

import static ru.orangesoftware.financisto2.db.DatabaseHelper.ACCOUNT_TABLE;
import static ru.orangesoftware.financisto2.db.DatabaseHelper.ATTRIBUTES_TABLE;
import static ru.orangesoftware.financisto2.db.DatabaseHelper.AccountColumns;
import static ru.orangesoftware.financisto2.db.DatabaseHelper.BUDGET_TABLE;
import static ru.orangesoftware.financisto2.db.DatabaseHelper.CATEGORY_ATTRIBUTE_TABLE;
import static ru.orangesoftware.financisto2.db.DatabaseHelper.CURRENCY_TABLE;
import static ru.orangesoftware.financisto2.db.DatabaseHelper.TRANSACTION_ATTRIBUTE_TABLE;
import static ru.orangesoftware.financisto2.utils.StringUtil.capitalize;

class MyEntityManager extends EntityManager {

    public final Context context;

    MyEntityManager(Context context) {
        this.context = context;
    }

    private <T extends MyEntity> ArrayList<T> getAllEntitiesList(Class<T> clazz, boolean include0) {
        Query<T> q = createQuery(clazz);
        q.where(include0 ? Expressions.gte("id", 0) : Expressions.gt("id", 0));
        q.asc("title");
        Cursor c = q.execute();
        try {
            T e0 = null;
            ArrayList<T> list = new ArrayList<T>();
            while (c.moveToNext()) {
                T e = EntityManager.loadFromCursor(c, clazz);
                if (e.id == 0) {
                    e0 = e;
                } else {
                    list.add(e);
                }
            }
            if (e0 != null) {
                list.add(0, e0);
            }
            return list;
        } finally {
            c.close();
        }
    }

    private <T extends MyEntity> ArrayList<T> getAllEntitiesList(Class<T> clazz, boolean include0,
            boolean onlyActive) {
        Query<T> q = createQuery(clazz);
        Expression include0Ex = include0 ? Expressions.gte("id", 0) : Expressions.gt("id", 0);
        if (onlyActive) {
            q.where(Expressions.and(include0Ex, Expressions.eq("isActive", 1)));
        } else {
            q.where(include0Ex);
        }
        q.asc("title");
        Cursor c = q.execute();
        try {
            T e0 = null;
            ArrayList<T> list = new ArrayList<T>();
            while (c.moveToNext()) {
                T e = EntityManager.loadFromCursor(c, clazz);
                if (e.id == 0) {
                    e0 = e;
                } else {
                    list.add(e);
                }
            }
            if (e0 != null) {
                list.add(0, e0);
            }
            return list;
        } finally {
            c.close();
        }
    }

    /* ===============================================
     * TRANSACTION INFO
     * =============================================== */

    public TransactionInfo getTransactionInfo(long transactionId) {
        return get(TransactionInfo.class, transactionId);
    }

    public List<TransactionAttributeInfo> getAttributesForTransaction(long transactionId) {
        Query<TransactionAttributeInfo> q = createQuery(TransactionAttributeInfo.class).asc("name");
        q.where(Expressions.and(Expressions.eq("transactionId", transactionId), Expressions.gte("attributeId", 0)));
        Cursor c = q.execute();
        try {
            List<TransactionAttributeInfo> list = new LinkedList<TransactionAttributeInfo>();
            while (c.moveToNext()) {
                TransactionAttributeInfo ti = loadFromCursor(c, TransactionAttributeInfo.class);
                list.add(ti);
            }
            return list;
        } finally {
            c.close();
        }

    }

    public TransactionAttributeInfo getSystemAttributeForTransaction(SystemAttribute sa, long transactionId) {
        Query<TransactionAttributeInfo> q = createQuery(TransactionAttributeInfo.class);
        q.where(Expressions.and(Expressions.eq("transactionId", transactionId),
                Expressions.eq("attributeId", sa.id)));
        Cursor c = q.execute();
        try {
            if (c.moveToFirst()) {
                return loadFromCursor(c, TransactionAttributeInfo.class);
            }
            return null;
        } finally {
            c.close();
        }
    }

    /* ===============================================
     * ACCOUNT
     * =============================================== */

    public Account getAccount(long id) {
        return get(Account.class, id);
    }

    public Cursor getAccountsForTransaction(Transaction t) {
        return getAllAccounts(true, t.fromAccountId, t.toAccountId);
    }

    public Cursor getAllActiveAccounts() {
        return getAllAccounts(true);
    }

    public Cursor getAllAccounts() {
        return getAllAccounts(false);
    }

    private Cursor getAllAccounts(boolean isActiveOnly, long... includeAccounts) {
        AccountSortOrder sortOrder = MyPreferences.getAccountSortOrder(context);
        Query<Account> q = createQuery(Account.class);
        if (isActiveOnly) {
            int count = includeAccounts.length;
            if (count > 0) {
                Expression[] ee = new Expression[count + 1];
                for (int i = 0; i < count; i++) {
                    ee[i] = Expressions.eq("id", includeAccounts[i]);
                }
                ee[count] = Expressions.eq("isActive", 1);
                q.where(Expressions.or(ee));
            } else {
                q.where(Expressions.eq("isActive", 1));
            }
        }
        q.desc("isActive");
        if (sortOrder.asc) {
            q.asc(sortOrder.property);
        } else {
            q.desc(sortOrder.property);
        }
        return q.asc("title").execute();
    }

    public long saveAccount(Account account) {
        return saveOrUpdate(account);
    }

    public List<Account> getAllAccountsList() {
        return getAllAccountsList(false);
    }

    public List<Account> getAllAccountsList(boolean activeOnly) {
        List<Account> list = new ArrayList<Account>();
        Cursor c = getAllAccounts(activeOnly);
        try {
            while (c.moveToNext()) {
                Account a = EntityManager.loadFromCursor(c, Account.class);
                list.add(a);
            }
        } finally {
            c.close();
        }
        return list;
    }

    public LongSparseArray<Account> getAllAccountsMap() {
        LongSparseArray<Account> accountsMap = new LongSparseArray<Account>();
        List<Account> list = getAllAccountsList(false);
        for (Account account : list) {
            accountsMap.put(account.id, account);
        }
        return accountsMap;
    }

    /* ===============================================
     * CURRENCY
     * =============================================== */

    private static final String UPDATE_DEFAULT_FLAG = "update currency set is_default=0";

    public long saveOrUpdate(Currency currency) {
        SQLiteDatabase db = db();
        db.beginTransaction();
        try {
            if (currency.isDefault) {
                db.execSQL(UPDATE_DEFAULT_FLAG);
            }
            long id = super.saveOrUpdate(currency);
            db.setTransactionSuccessful();
            return id;
        } finally {
            db.endTransaction();
        }
    }

    public int deleteCurrency(long id) {
        String sid = String.valueOf(id);
        Currency c = load(Currency.class, id);
        writeDeleteLog(CURRENCY_TABLE, c.remoteKey);
        return db().delete(CURRENCY_TABLE, "_id=? AND NOT EXISTS (SELECT 1 FROM " + ACCOUNT_TABLE + " WHERE "
                + AccountColumns.CURRENCY_ID + "=?)", new String[] { sid, sid });
    }

    public Cursor getAllCurrencies(String sortBy) {
        Query<Currency> q = createQuery(Currency.class);
        return q.desc("isDefault").asc(sortBy).execute();
    }

    public List<Currency> getAllCurrenciesList() {
        return getAllCurrenciesList("name");
    }

    public List<Currency> getAllCurrenciesList(String sortBy) {
        Query<Currency> q = createQuery(Currency.class);
        return q.desc("isDefault").asc(sortBy).list();
    }

    public Map<String, Currency> getAllCurrenciesByTtitleMap() {
        return entitiesAsTitleMap(getAllCurrenciesList("name"));
    }

    /* ===============================================
     * TRANSACTIONS
     * =============================================== */

    //   public Cursor getBlotter(WhereFilter blotterFilter) {
    //      long t0 = System.currentTimeMillis();
    //      try {
    //         Query<TransactionInfo> q = createQuery(TransactionInfo.class);
    //         if (!blotterFilter.isEmpty()) {
    //            q.where(blotterFilter.toWhereExpression());
    //         }
    //         q.desc("dateTime");
    //         return q.list();
    //      } finally {
    //         Log.d("BLOTTER", "getBlotter executed in "+(System.currentTimeMillis()-t0)+"ms");
    //      }
    //   }
    //
    //   public Cursor getTransactions(WhereFilter blotterFilter) {
    //      return null;
    //   }

    //   public Cursor getAllProjects(boolean includeNoProject) {
    //      Query<Project> q = createQuery(Project.class);
    //      if (!includeNoProject) {
    //         q.where(Expressions.neq("id", 0));
    //      }
    //      return q.list();
    //   }

    public Project getProject(long id) {
        return get(Project.class, id);
    }

    public ArrayList<Project> getAllProjectsList(boolean includeNoProject) {
        return getAllEntitiesList(Project.class, includeNoProject);
    }

    public ArrayList<Project> getActiveProjectsList(boolean includeNoProject) {
        return getAllEntitiesList(Project.class, includeNoProject, true);
    }

    public Map<String, Project> getAllProjectsByTitleMap(boolean includeNoProject) {
        return entitiesAsTitleMap(getAllProjectsList(includeNoProject));
    }

    public LongSparseArray<Project> getAllProjectsByIdMap(boolean includeNoProject) {
        return entitiesAsIdMap(getAllProjectsList(includeNoProject));
    }

    //   public Category getCategoryByLeft(long left) {
    //      Query<Category> q = createQuery(Category.class);
    //      q.where(Expressions.eq("left", left));
    //      return q.uniqueResult();
    //   }
    //
    //   public Cursor getAllCategories(boolean includeNoCategory) {
    //      Query<CategoryInfo> q = createQuery(CategoryInfo.class);
    //      if (!includeNoCategory) {
    //         q.where(Expressions.neq("id", 0));
    //      }
    //      return q.list();
    //   }
    //   
    //   public Cursor getAllCategoriesWithoutSubtree(long id) {
    //      Category c = load(Category.class, id);
    //      Query<CategoryInfo> q = createQuery(CategoryInfo.class);
    //      q.where(Expressions.not(Expressions.and(
    //            Expressions.gte("left", c.left),
    //            Expressions.lte("right", c.right)
    //      )));
    //      return q.list();
    //   }

    public long insertBudget(Budget budget) {
        SQLiteDatabase db = db();
        db.beginTransaction();
        try {
            if (budget.id > 0) {
                deleteBudget(budget.id);
            }
            long id = 0;
            Recur recur = RecurUtils.createFromExtraString(budget.recur);
            Period[] periods = RecurUtils.periods(recur);
            for (int i = 0; i < periods.length; i++) {
                Period p = periods[i];
                budget.id = -1;
                budget.parentBudgetId = id;
                budget.recurNum = i;
                budget.startDate = p.start;
                budget.endDate = p.end;
                long bid = super.saveOrUpdate(budget);
                if (i == 0) {
                    id = bid;
                }
            }
            db.setTransactionSuccessful();
            return id;
        } finally {
            db.endTransaction();
        }
    }

    public void deleteBudget(long id) {
        SQLiteDatabase db = db();
        Budget b = load(Budget.class, id);
        writeDeleteLog(BUDGET_TABLE, b.remoteKey);
        db.delete(BUDGET_TABLE, "_id=?", new String[] { String.valueOf(id) });
        String sql = "select remote_key from " + BUDGET_TABLE + " where parent_budget_id=" + id + "";
        Cursor cursorCursor = db.rawQuery(sql, null);
        if (cursorCursor.moveToFirst()) {
            do {
                String rKey = cursorCursor.getString(0);
                writeDeleteLog(BUDGET_TABLE, rKey);
            } while (cursorCursor.moveToNext());
        }
        cursorCursor.close();
        db.delete(BUDGET_TABLE, "parent_budget_id=?", new String[] { String.valueOf(id) });
    }

    public void deleteBudgetOneEntry(long id) {
        SQLiteDatabase db = db();
        Budget b = load(Budget.class, id);
        writeDeleteLog(BUDGET_TABLE, b.remoteKey);
        db.delete(BUDGET_TABLE, "_id=?", new String[] { String.valueOf(id) });
    }

    public ArrayList<Budget> getAllBudgets(WhereFilter filter) {
        Query<Budget> q = createQuery(Budget.class);
        Criteria c = filter.get(BlotterFilter.DATETIME);
        if (c != null) {
            long start = c.getLongValue1();
            long end = c.getLongValue2();
            q.where(Expressions.and(Expressions.lte("startDate", end), Expressions.gte("endDate", start)));
        }
        Cursor cursor = q.execute();
        try {
            ArrayList<Budget> list = new ArrayList<Budget>();
            while (cursor.moveToNext()) {
                Budget b = MyEntityManager.loadFromCursor(cursor, Budget.class);
                list.add(b);
            }
            return list;
        } finally {
            cursor.close();
        }
    }

    public void deleteProject(long id) {
        SQLiteDatabase db = db();
        db.beginTransaction();
        try {
            delete(Project.class, id);
            ContentValues values = new ContentValues();
            values.put("project_id", 0);
            db.update("transactions", values, "project_id=?", new String[] { String.valueOf(id) });
            db.setTransactionSuccessful();
        } finally {
            db.endTransaction();
        }
    }

    public ArrayList<TransactionInfo> getAllScheduledTransactions() {
        Query<TransactionInfo> q = createQuery(TransactionInfo.class);
        q.where(Expressions.and(Expressions.eq("isTemplate", 2), Expressions.eq("parentId", 0)));
        return (ArrayList<TransactionInfo>) q.list();
    }

    public ArrayList<Category> getAllCategoriesList(boolean includeNoCategory) {
        return getAllEntitiesList(Category.class, includeNoCategory);
    }

    public Payee insertPayee(String payee) {
        if (Utils.isEmpty(payee)) {
            return Payee.EMPTY;
        } else {
            Payee p = getPayee(payee);
            if (p == null) {
                p = new Payee();
                p.title = payee;
                p.id = saveOrUpdate(p);
            }
            return p;
        }
    }

    public Payee getPayee(String payee) {
        Query<Payee> q = createQuery(Payee.class);
        q.where(Expressions.eq("title", payee));
        return q.uniqueResult();
    }

    public Cursor getAllPayees() {
        Query<Payee> q = createQuery(Payee.class);
        return q.asc("title").execute();
    }

    public List<Payee> getAllPayeeList() {
        return getAllEntitiesList(Payee.class, true);
    }

    public Map<String, Payee> getAllPayeeByTitleMap() {
        return entitiesAsTitleMap(getAllPayeeList());
    }

    public LongSparseArray<Payee> getAllPayeeByIdMap() {
        return entitiesAsIdMap(getAllPayeeList());
    }

    public Cursor getAllPayeesLike(CharSequence constraint) {
        Query<Payee> q = createQuery(Payee.class);
        q.where(Expressions.or(Expressions.like("title", "%" + constraint + "%"),
                Expressions.like("title", "%" + capitalize(constraint.toString()) + "%")));
        return q.asc("title").execute();
    }

    public List<Transaction> getSplitsForTransaction(long transactionId) {
        Query<Transaction> q = createQuery(Transaction.class);
        q.where(Expressions.eq("parentId", transactionId));
        return q.list();
    }

    public List<TransactionInfo> getSplitsInfoForTransaction(long transactionId) {
        Query<TransactionInfo> q = createQuery(TransactionInfo.class);
        q.where(Expressions.eq("parentId", transactionId));
        return q.list();
    }

    public List<TransactionInfo> getTransactionsForAccount(long accountId) {
        Query<TransactionInfo> q = createQuery(TransactionInfo.class);
        q.where(Expressions.and(Expressions.eq("fromAccount.id", accountId), Expressions.eq("parentId", 0)));
        q.desc("dateTime");
        return q.list();
    }

    public void reInsertCategory(Category c) {
        reInsert(c);
    }

    public Currency getHomeCurrency() {
        Query<Currency> q = createQuery(Currency.class);
        q.where(Expressions.eq("isDefault", "1")); //uh-oh
        Currency homeCurrency = q.uniqueResult();
        if (homeCurrency == null) {
            homeCurrency = Currency.EMPTY;
        }
        return homeCurrency;
    }

    private long writeDeleteLog(String tableName, String remoteKey) {
        if (remoteKey == null || remoteKey.length() == 0) {
            return 0;
        }
        ContentValues row = new ContentValues();
        row.put(DatabaseHelper.deleteLogColumns.TABLE_NAME, tableName);
        row.put(DatabaseHelper.deleteLogColumns.REMOTE_KEY, remoteKey);
        row.put(DatabaseHelper.deleteLogColumns.DELETED_ON, System.currentTimeMillis());
        return db().insert(DatabaseHelper.DELETE_LOG_TABLE, null, row);
    }

    private static <T extends MyEntity> Map<String, T> entitiesAsTitleMap(List<T> entities) {
        Map<String, T> map = new HashMap<String, T>();
        for (T e : entities) {
            map.put(e.title, e);
        }
        return map;
    }

    private static <T extends MyEntity> LongSparseArray<T> entitiesAsIdMap(List<T> entities) {
        LongSparseArray<T> map = new LongSparseArray<T>();
        for (T e : entities) {
            map.put(e.id, e);
        }
        return map;
    }

    public void deleteAttribute(long id) {
        SQLiteDatabase db = db();
        db.beginTransaction();
        try {
            Attribute attr = get(Attribute.class, id);
            String key = attr.remoteKey;
            String[] p = new String[] { String.valueOf(id) };
            db.delete(ATTRIBUTES_TABLE, DatabaseHelper.AttributeColumns.ID + "=?", p);
            db.delete(CATEGORY_ATTRIBUTE_TABLE, DatabaseHelper.CategoryAttributeColumns.ATTRIBUTE_ID + "=?", p);
            db.delete(TRANSACTION_ATTRIBUTE_TABLE, DatabaseHelper.TransactionAttributeColumns.ATTRIBUTE_ID + "=?",
                    p);
            db.setTransactionSuccessful();
            writeDeleteLog(ATTRIBUTES_TABLE, key);
        } finally {
            db.endTransaction();
        }
    }

    public Attribute getSystemAttribute(SystemAttribute a) {
        Attribute sa = get(Attribute.class, a.id);
        sa.name = context.getString(a.titleId);
        return sa;
    }

    public List<Attribute> getAllAttributes() {
        return createQuery(Attribute.class).where(Expressions.gt("id", 0)).asc("name").list();
    }

    public LongSparseArray<Attribute> getAllAttributesMap() {
        LongSparseArray<Attribute> array = new LongSparseArray<Attribute>();
        List<Attribute> attributes = getAllAttributes();
        for (Attribute attribute : attributes) {
            array.put(attribute.getId(), attribute);
        }
        return array;
    }
}