From 93545c6fbf1244fbd96ecfc50e1115dbdc25f9ae Mon Sep 17 00:00:00 2001 From: Damyan Ivanov Date: Thu, 18 Mar 2021 19:09:34 +0200 Subject: [PATCH] migrate to surrogate IDs for all database objects along with foreign keys etc --- .../net.ktnx.mobileledger.db.DB/59.json | 849 ++++++++++++++++++ .../async/UpdateTransactionsTask.java | 8 +- .../net/ktnx/mobileledger/dao/AccountDAO.java | 39 +- .../net/ktnx/mobileledger/dao/BaseDAO.java | 15 +- .../net/ktnx/mobileledger/dao/ProfileDAO.java | 34 + .../ktnx/mobileledger/dao/TransactionDAO.java | 6 +- .../net/ktnx/mobileledger/db/Account.java | 34 +- .../db/AccountAutocompleteAdapter.java | 19 +- .../ktnx/mobileledger/db/AccountValue.java | 42 +- .../java/net/ktnx/mobileledger/db/DB.java | 2 +- .../java/net/ktnx/mobileledger/db/Option.java | 16 +- .../net/ktnx/mobileledger/db/Profile.java | 25 +- .../net/ktnx/mobileledger/db/Transaction.java | 36 +- .../mobileledger/db/TransactionAccount.java | 31 +- .../net/ktnx/mobileledger/model/Data.java | 25 +- .../mobileledger/model/LedgerTransaction.java | 16 +- .../model/MobileLedgerProfile.java | 79 +- .../net/ktnx/mobileledger/ui/MainModel.java | 10 +- .../AccountSummaryAdapter.java | 4 +- .../ui/activity/MainActivity.java | 6 +- .../ui/activity/SplashActivity.java | 8 +- .../NewTransactionActivity.java | 14 +- .../new_transaction/NewTransactionModel.java | 6 +- .../ui/profiles/ProfileDetailActivity.java | 2 +- .../ui/profiles/ProfileDetailFragment.java | 9 +- .../net/ktnx/mobileledger/utils/MLDB.java | 2 +- app/src/main/res/raw/db_59.sql | 70 ++ 27 files changed, 1185 insertions(+), 222 deletions(-) create mode 100644 app/schemas/net.ktnx.mobileledger.db.DB/59.json create mode 100644 app/src/main/java/net/ktnx/mobileledger/dao/ProfileDAO.java create mode 100644 app/src/main/res/raw/db_59.sql diff --git a/app/schemas/net.ktnx.mobileledger.db.DB/59.json b/app/schemas/net.ktnx.mobileledger.db.DB/59.json new file mode 100644 index 00000000..3ebd83f9 --- /dev/null +++ b/app/schemas/net.ktnx.mobileledger.db.DB/59.json @@ -0,0 +1,849 @@ +{ + "formatVersion": 1, + "database": { + "version": 59, + "identityHash": "a56d86c03528ece865d81fd8171c819f", + "entities": [ + { + "tableName": "templates", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT NOT NULL, `regular_expression` TEXT NOT NULL, `test_text` TEXT, `transaction_description` TEXT, `transaction_description_match_group` INTEGER, `transaction_comment` TEXT, `transaction_comment_match_group` INTEGER, `date_year` INTEGER, `date_year_match_group` INTEGER, `date_month` INTEGER, `date_month_match_group` INTEGER, `date_day` INTEGER, `date_day_match_group` INTEGER, `is_fallback` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "regularExpression", + "columnName": "regular_expression", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "testText", + "columnName": "test_text", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "transactionDescription", + "columnName": "transaction_description", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "transactionDescriptionMatchGroup", + "columnName": "transaction_description_match_group", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "transactionComment", + "columnName": "transaction_comment", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "transactionCommentMatchGroup", + "columnName": "transaction_comment_match_group", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "dateYear", + "columnName": "date_year", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "dateYearMatchGroup", + "columnName": "date_year_match_group", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "dateMonth", + "columnName": "date_month", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "dateMonthMatchGroup", + "columnName": "date_month_match_group", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "dateDay", + "columnName": "date_day", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "dateDayMatchGroup", + "columnName": "date_day_match_group", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "isFallback", + "columnName": "is_fallback", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "template_accounts", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `template_id` INTEGER NOT NULL, `acc` TEXT, `position` INTEGER NOT NULL, `acc_match_group` INTEGER, `currency` INTEGER, `currency_match_group` INTEGER, `amount` REAL, `amount_match_group` INTEGER, `comment` TEXT, `comment_match_group` INTEGER, `negate_amount` INTEGER, FOREIGN KEY(`template_id`) REFERENCES `templates`(`id`) ON UPDATE RESTRICT ON DELETE CASCADE , FOREIGN KEY(`currency`) REFERENCES `currencies`(`id`) ON UPDATE RESTRICT ON DELETE RESTRICT )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "templateId", + "columnName": "template_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "accountName", + "columnName": "acc", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "position", + "columnName": "position", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "accountNameMatchGroup", + "columnName": "acc_match_group", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "currency", + "columnName": "currency", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "currencyMatchGroup", + "columnName": "currency_match_group", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "amount", + "columnName": "amount", + "affinity": "REAL", + "notNull": false + }, + { + "fieldPath": "amountMatchGroup", + "columnName": "amount_match_group", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "accountComment", + "columnName": "comment", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "accountCommentMatchGroup", + "columnName": "comment_match_group", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "negateAmount", + "columnName": "negate_amount", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "fk_template_accounts_template", + "unique": false, + "columnNames": [ + "template_id" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `fk_template_accounts_template` ON `${TABLE_NAME}` (`template_id`)" + }, + { + "name": "fk_template_accounts_currency", + "unique": false, + "columnNames": [ + "currency" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `fk_template_accounts_currency` ON `${TABLE_NAME}` (`currency`)" + } + ], + "foreignKeys": [ + { + "table": "templates", + "onDelete": "CASCADE", + "onUpdate": "RESTRICT", + "columns": [ + "template_id" + ], + "referencedColumns": [ + "id" + ] + }, + { + "table": "currencies", + "onDelete": "RESTRICT", + "onUpdate": "RESTRICT", + "columns": [ + "currency" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "currencies", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT NOT NULL, `position` TEXT NOT NULL, `has_gap` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "position", + "columnName": "position", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "hasGap", + "columnName": "has_gap", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "accounts", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `profile_id` INTEGER NOT NULL, `level` INTEGER NOT NULL, `name` TEXT NOT NULL, `name_upper` TEXT NOT NULL, `parent_name` TEXT, `expanded` INTEGER NOT NULL DEFAULT 1, `amounts_expanded` INTEGER NOT NULL DEFAULT 0, `generation` INTEGER NOT NULL DEFAULT 0, FOREIGN KEY(`profile_id`) REFERENCES `profiles`(`id`) ON UPDATE RESTRICT ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "profileId", + "columnName": "profile_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "level", + "columnName": "level", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "nameUpper", + "columnName": "name_upper", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "parentName", + "columnName": "parent_name", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "expanded", + "columnName": "expanded", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "1" + }, + { + "fieldPath": "amountsExpanded", + "columnName": "amounts_expanded", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + }, + { + "fieldPath": "generation", + "columnName": "generation", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "un_account_name", + "unique": true, + "columnNames": [ + "profile_id", + "name" + ], + "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `un_account_name` ON `${TABLE_NAME}` (`profile_id`, `name`)" + }, + { + "name": "fk_account_profile", + "unique": false, + "columnNames": [ + "profile_id" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `fk_account_profile` ON `${TABLE_NAME}` (`profile_id`)" + } + ], + "foreignKeys": [ + { + "table": "profiles", + "onDelete": "CASCADE", + "onUpdate": "RESTRICT", + "columns": [ + "profile_id" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "profiles", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT NOT NULL, `url` TEXT NOT NULL, `use_authentication` INTEGER NOT NULL, `auth_user` TEXT, `auth_password` TEXT, `order_no` INTEGER NOT NULL, `permit_posting` INTEGER NOT NULL, `theme` INTEGER NOT NULL DEFAULT -1, `preferred_accounts_filter` TEXT, `future_dates` INTEGER NOT NULL, `api_version` INTEGER NOT NULL, `show_commodity_by_default` INTEGER NOT NULL, `default_commodity` TEXT, `show_comments_by_default` INTEGER NOT NULL DEFAULT 1, `detected_version_pre_1_19` INTEGER NOT NULL, `detected_version_major` INTEGER NOT NULL, `detected_version_minor` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "url", + "columnName": "url", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "useAuthentication", + "columnName": "use_authentication", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "authUser", + "columnName": "auth_user", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "authPassword", + "columnName": "auth_password", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "orderNo", + "columnName": "order_no", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "permitPosting", + "columnName": "permit_posting", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "theme", + "columnName": "theme", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "-1" + }, + { + "fieldPath": "preferredAccountsFilter", + "columnName": "preferred_accounts_filter", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "futureDates", + "columnName": "future_dates", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "apiVersion", + "columnName": "api_version", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "showCommodityByDefault", + "columnName": "show_commodity_by_default", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "defaultCommodity", + "columnName": "default_commodity", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "showCommentsByDefault", + "columnName": "show_comments_by_default", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "1" + }, + { + "fieldPath": "detectedVersionPre_1_19", + "columnName": "detected_version_pre_1_19", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "detectedVersionMajor", + "columnName": "detected_version_major", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "detectedVersionMinor", + "columnName": "detected_version_minor", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "options", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profile` INTEGER NOT NULL, `name` TEXT NOT NULL, `value` TEXT, PRIMARY KEY(`profile`, `name`))", + "fields": [ + { + "fieldPath": "profile", + "columnName": "profile", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "value", + "columnName": "value", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "profile", + "name" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "account_values", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `account_id` INTEGER NOT NULL, `currency` TEXT NOT NULL DEFAULT '', `value` REAL NOT NULL, `generation` INTEGER NOT NULL DEFAULT 0, FOREIGN KEY(`account_id`) REFERENCES `accounts`(`id`) ON UPDATE RESTRICT ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "account_id", + "columnName": "account_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "currency", + "columnName": "currency", + "affinity": "TEXT", + "notNull": true, + "defaultValue": "''" + }, + { + "fieldPath": "value", + "columnName": "value", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "generation", + "columnName": "generation", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "un_account_values", + "unique": true, + "columnNames": [ + "account_id", + "currency" + ], + "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `un_account_values` ON `${TABLE_NAME}` (`account_id`, `currency`)" + }, + { + "name": "fk_account_value_acc", + "unique": false, + "columnNames": [ + "account_id" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `fk_account_value_acc` ON `${TABLE_NAME}` (`account_id`)" + } + ], + "foreignKeys": [ + { + "table": "accounts", + "onDelete": "CASCADE", + "onUpdate": "RESTRICT", + "columns": [ + "account_id" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "description_history", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`description` TEXT NOT NULL COLLATE NOCASE, `description_upper` TEXT NOT NULL, `generation` INTEGER NOT NULL DEFAULT 0, PRIMARY KEY(`description`))", + "fields": [ + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "descriptionUpper", + "columnName": "description_upper", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "generation", + "columnName": "generation", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + } + ], + "primaryKey": { + "columnNames": [ + "description" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "transactions", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `profile_id` INTEGER NOT NULL, `data_hash` TEXT NOT NULL, `year` INTEGER NOT NULL, `month` INTEGER NOT NULL, `day` INTEGER NOT NULL, `description` TEXT NOT NULL COLLATE NOCASE, `comment` TEXT, `generation` INTEGER NOT NULL, FOREIGN KEY(`profile_id`) REFERENCES `profiles`(`id`) ON UPDATE RESTRICT ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "profileId", + "columnName": "profile_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "dataHash", + "columnName": "data_hash", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "year", + "columnName": "year", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "month", + "columnName": "month", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "day", + "columnName": "day", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "comment", + "columnName": "comment", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "generation", + "columnName": "generation", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "un_transactions_data_hash", + "unique": true, + "columnNames": [ + "profile_id", + "data_hash" + ], + "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `un_transactions_data_hash` ON `${TABLE_NAME}` (`profile_id`, `data_hash`)" + }, + { + "name": "idx_transaction_description", + "unique": false, + "columnNames": [ + "description" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `idx_transaction_description` ON `${TABLE_NAME}` (`description`)" + }, + { + "name": "fk_transaction_profile", + "unique": false, + "columnNames": [ + "profile_id" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `fk_transaction_profile` ON `${TABLE_NAME}` (`profile_id`)" + } + ], + "foreignKeys": [ + { + "table": "profiles", + "onDelete": "CASCADE", + "onUpdate": "RESTRICT", + "columns": [ + "profile_id" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "transaction_accounts", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `transaction_id` INTEGER NOT NULL, `order_no` INTEGER NOT NULL, `account_name` TEXT NOT NULL, `currency` TEXT NOT NULL DEFAULT '', `amount` REAL NOT NULL, `comment` TEXT, `generation` INTEGER NOT NULL DEFAULT 0, FOREIGN KEY(`transaction_id`) REFERENCES `transactions`(`id`) ON UPDATE RESTRICT ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "transactionId", + "columnName": "transaction_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "orderNo", + "columnName": "order_no", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "accountName", + "columnName": "account_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "currency", + "columnName": "currency", + "affinity": "TEXT", + "notNull": true, + "defaultValue": "''" + }, + { + "fieldPath": "amount", + "columnName": "amount", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "comment", + "columnName": "comment", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "generation", + "columnName": "generation", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "fk_tran_acc_trans", + "unique": false, + "columnNames": [ + "transaction_id" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `fk_tran_acc_trans` ON `${TABLE_NAME}` (`transaction_id`)" + }, + { + "name": "un_transaction_accounts", + "unique": true, + "columnNames": [ + "transaction_id", + "order_no" + ], + "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `un_transaction_accounts` ON `${TABLE_NAME}` (`transaction_id`, `order_no`)" + } + ], + "foreignKeys": [ + { + "table": "transactions", + "onDelete": "CASCADE", + "onUpdate": "RESTRICT", + "columns": [ + "transaction_id" + ], + "referencedColumns": [ + "id" + ] + } + ] + } + ], + "views": [], + "setupQueries": [ + "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'a56d86c03528ece865d81fd8171c819f')" + ] + } +} \ No newline at end of file diff --git a/app/src/main/java/net/ktnx/mobileledger/async/UpdateTransactionsTask.java b/app/src/main/java/net/ktnx/mobileledger/async/UpdateTransactionsTask.java index 43de7402..b6e9c3ed 100644 --- a/app/src/main/java/net/ktnx/mobileledger/async/UpdateTransactionsTask.java +++ b/app/src/main/java/net/ktnx/mobileledger/async/UpdateTransactionsTask.java @@ -1,5 +1,5 @@ /* - * Copyright © 2020 Damyan Ivanov. + * Copyright © 2021 Damyan Ivanov. * This file is part of MoLe. * MoLe is free software: you can distribute it and/or modify it * under the term of the GNU General Public License as published by @@ -34,7 +34,7 @@ public class UpdateTransactionsTask extends AsyncTask { protected String doInBackground(MainModel[] model) { final MobileLedgerProfile profile = Data.getProfile(); - String profile_uuid = profile.getUuid(); + long profile_id = profile.getId(); Data.backgroundTaskStarted(); try { String sql; @@ -45,7 +45,7 @@ public class UpdateTransactionsTask extends AsyncTask { if (accFilter == null) { sql = "SELECT id, year, month, day FROM transactions WHERE profile=? ORDER BY " + "year desc, month desc, day desc, id desc"; - params = new String[]{profile_uuid}; + params = new String[]{String.valueOf(profile_id)}; } else { @@ -55,7 +55,7 @@ public class UpdateTransactionsTask extends AsyncTask { "and ta.account_name LIKE ?||'%' AND ta" + ".amount <> 0 ORDER BY tr.year desc, tr.month desc, tr.day desc, tr.id " + "desc"; - params = new String[]{profile_uuid, accFilter}; + params = new String[]{String.valueOf(profile_id), accFilter}; } debug("UTT", sql); diff --git a/app/src/main/java/net/ktnx/mobileledger/dao/AccountDAO.java b/app/src/main/java/net/ktnx/mobileledger/dao/AccountDAO.java index 31aafbf2..bb8d4ec2 100644 --- a/app/src/main/java/net/ktnx/mobileledger/dao/AccountDAO.java +++ b/app/src/main/java/net/ktnx/mobileledger/dao/AccountDAO.java @@ -33,8 +33,16 @@ import java.util.List; @Dao public abstract class AccountDAO extends BaseDAO { + static public List unbox(List list) { + ArrayList result = new ArrayList<>(list.size()); + for (AccountNameContainer item : list) { + result.add(item.name); + } + + return result; + } @Insert - public abstract void insertSync(Account item); + public abstract long insertSync(Account item); @Update public abstract void updateSync(Account item); @@ -45,40 +53,31 @@ public abstract class AccountDAO extends BaseDAO { @Query("SELECT * FROM accounts") public abstract LiveData> getAll(); - @Query("SELECT * FROM accounts WHERE profile = :profileUUID AND name = :accountName") - public abstract LiveData getByName(@NonNull String profileUUID, - @NonNull String accountName); - -// not useful for now + // not useful for now // @Transaction // @Query("SELECT * FROM patterns") // List getPatternsWithAccounts(); + @Query("SELECT * FROM accounts WHERE profile_id = :profileId AND name = :accountName") + public abstract LiveData getByName(long profileId, @NonNull String accountName); - static public List unbox(List list) { - ArrayList result = new ArrayList<>(list.size()); - for (AccountNameContainer item : list) { - result.add(item.name); - } - - return result; - } @Query("SELECT name, CASE WHEN name_upper LIKE :term||'%%' THEN 1 " + " WHEN name_upper LIKE '%%:'||:term||'%%' THEN 2 " + " WHEN name_upper LIKE '%% '||:term||'%%' THEN 3 " + " ELSE 9 END AS ordering " + "FROM accounts " + - "WHERE profile=:profileUUID AND name_upper LIKE '%%'||:term||'%%' " + + "WHERE profile_id=:profileId AND name_upper LIKE '%%'||:term||'%%' " + "ORDER BY ordering, name_upper, rowid ") - public abstract LiveData> lookupInProfileByName( - @NonNull String profileUUID, @NonNull String term); + public abstract LiveData> lookupInProfileByName(long profileId, + @NonNull + String term); @Query("SELECT name, CASE WHEN name_upper LIKE :term||'%%' THEN 1 " + " WHEN name_upper LIKE '%%:'||:term||'%%' THEN 2 " + " WHEN name_upper LIKE '%% '||:term||'%%' THEN 3 " + " ELSE 9 END AS ordering " + "FROM accounts " + - "WHERE profile=:profileUUID AND name_upper LIKE '%%'||:term||'%%' " + + "WHERE profile_id=:profileId AND name_upper LIKE '%%'||:term||'%%' " + "ORDER BY ordering, name_upper, rowid ") - public abstract List lookupInProfileByNameSync( - @NonNull String profileUUID, @NonNull String term); + public abstract List lookupInProfileByNameSync(long profileId, + @NonNull String term); @Query("SELECT DISTINCT name, CASE WHEN name_upper LIKE :term||'%%' THEN 1 " + " WHEN name_upper LIKE '%%:'||:term||'%%' THEN 2 " + diff --git a/app/src/main/java/net/ktnx/mobileledger/dao/BaseDAO.java b/app/src/main/java/net/ktnx/mobileledger/dao/BaseDAO.java index 0bcb3e48..b68ea515 100644 --- a/app/src/main/java/net/ktnx/mobileledger/dao/BaseDAO.java +++ b/app/src/main/java/net/ktnx/mobileledger/dao/BaseDAO.java @@ -24,12 +24,12 @@ import android.os.Looper; import androidx.annotation.Nullable; abstract class BaseDAO { - abstract void insertSync(T item); - public void insert(T item, @Nullable Runnable onDone) { + abstract long insertSync(T item); + public void insert(T item, @Nullable OnInsertedReceiver receiver) { AsyncTask.execute(() -> { - insertSync(item); - if (onDone != null) - new Handler(Looper.getMainLooper()).post(onDone); + long id = insertSync(item); + if (receiver != null) + new Handler(Looper.getMainLooper()).post(() -> receiver.onInsert(id)); }); } @@ -49,6 +49,7 @@ abstract class BaseDAO { new Handler(Looper.getMainLooper()).post(onDone); }); } - - + interface OnInsertedReceiver { + void onInsert(long id); + } } diff --git a/app/src/main/java/net/ktnx/mobileledger/dao/ProfileDAO.java b/app/src/main/java/net/ktnx/mobileledger/dao/ProfileDAO.java new file mode 100644 index 00000000..ac51ecc2 --- /dev/null +++ b/app/src/main/java/net/ktnx/mobileledger/dao/ProfileDAO.java @@ -0,0 +1,34 @@ +/* + * Copyright © 2021 Damyan Ivanov. + * This file is part of MoLe. + * MoLe is free software: you can distribute it and/or modify it + * under the term of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your opinion), any later version. + * + * MoLe is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License terms for details. + * + * You should have received a copy of the GNU General Public License + * along with MoLe. If not, see . + */ + +package net.ktnx.mobileledger.dao; + +import androidx.room.Dao; + +import net.ktnx.mobileledger.db.Profile; + +@Dao +abstract class ProfileDAO extends BaseDAO { + @Override + abstract long insertSync(Profile item); + + @Override + abstract void updateSync(Profile item); + + @Override + abstract void deleteSync(Profile item); +} diff --git a/app/src/main/java/net/ktnx/mobileledger/dao/TransactionDAO.java b/app/src/main/java/net/ktnx/mobileledger/dao/TransactionDAO.java index 0bee7713..81c5df67 100644 --- a/app/src/main/java/net/ktnx/mobileledger/dao/TransactionDAO.java +++ b/app/src/main/java/net/ktnx/mobileledger/dao/TransactionDAO.java @@ -42,7 +42,7 @@ public abstract class TransactionDAO extends BaseDAO { return result; } @Insert - public abstract void insertSync(Transaction item); + public abstract long insertSync(Transaction item); @Update public abstract void updateSync(Transaction item); @@ -57,8 +57,8 @@ public abstract class TransactionDAO extends BaseDAO { // @Transaction // @Query("SELECT * FROM patterns") // List getPatternsWithAccounts(); - @Query("SELECT * FROM transactions WHERE profile = :profileUUID AND id = :id") - public abstract LiveData getById(@NonNull String profileUUID, long id); + @Query("SELECT * FROM transactions WHERE id = :id") + public abstract LiveData getById(long id); @Query("SELECT DISTINCT description, CASE WHEN description_upper LIKE :term||'%%' THEN 1 " + " WHEN description_upper LIKE '%%:'||:term||'%%' THEN 2 " + diff --git a/app/src/main/java/net/ktnx/mobileledger/db/Account.java b/app/src/main/java/net/ktnx/mobileledger/db/Account.java index d0eb1ae0..59c164b0 100644 --- a/app/src/main/java/net/ktnx/mobileledger/db/Account.java +++ b/app/src/main/java/net/ktnx/mobileledger/db/Account.java @@ -20,14 +20,25 @@ package net.ktnx.mobileledger.db; import androidx.annotation.NonNull; import androidx.room.ColumnInfo; import androidx.room.Entity; +import androidx.room.ForeignKey; +import androidx.room.Index; +import androidx.room.PrimaryKey; -@Entity(tableName = "accounts", primaryKeys = {"profile", "name"}) +@Entity(tableName = "accounts", + indices = {@Index(name = "un_account_name", unique = true, value = {"profile_id", "name"}), + @Index(name = "fk_account_profile", value = "profile_id") + }, foreignKeys = { + @ForeignKey(entity = Profile.class, parentColumns = "id", childColumns = "profile_id", + onDelete = ForeignKey.CASCADE, onUpdate = ForeignKey.RESTRICT) +}) public class Account { @ColumnInfo - int level; + @PrimaryKey(autoGenerate = true) + long id; + @ColumnInfo(name = "profile_id") + long profileId; @ColumnInfo - @NonNull - private String profile; + int level; @ColumnInfo @NonNull private String name; @@ -42,12 +53,17 @@ public class Account { private boolean amountsExpanded = false; @ColumnInfo(defaultValue = "0") private int generation; - @NonNull - public String getProfile() { - return profile; + public long getId() { + return id; + } + public void setId(long id) { + this.id = id; + } + public long getProfileId() { + return profileId; } - public void setProfile(@NonNull String profile) { - this.profile = profile; + public void setProfileId(long profileId) { + this.profileId = profileId; } @NonNull public String getName() { diff --git a/app/src/main/java/net/ktnx/mobileledger/db/AccountAutocompleteAdapter.java b/app/src/main/java/net/ktnx/mobileledger/db/AccountAutocompleteAdapter.java index 6cf1dc8c..42bf4c6b 100644 --- a/app/src/main/java/net/ktnx/mobileledger/db/AccountAutocompleteAdapter.java +++ b/app/src/main/java/net/ktnx/mobileledger/db/AccountAutocompleteAdapter.java @@ -34,16 +34,16 @@ public class AccountAutocompleteAdapter extends ArrayAdapter { private final AccountFilter filter = new AccountFilter(); private final AccountDAO dao = DB.get() .getAccountDAO(); - private String profileUUID; + private long profileId; public AccountAutocompleteAdapter(Context context) { super(context, android.R.layout.simple_dropdown_item_1line, new ArrayList<>()); } public AccountAutocompleteAdapter(Context context, @NonNull MobileLedgerProfile profile) { this(context); - profileUUID = profile.getUuid(); + profileId = profile.getId(); } - public void setProfileUUID(String profileUUID) { - this.profileUUID = profileUUID; + public void setProfileId(long profileId) { + this.profileId = profileId; } @NonNull @Override @@ -73,12 +73,11 @@ public class AccountAutocompleteAdapter extends ArrayAdapter { } Logger.debug("acc", String.format("Looking for account '%s'", constraint)); - final List matches = AccountDAO.unbox( - (profileUUID == null) ? dao.lookupByNameSync(String.valueOf(constraint) - .toUpperCase()) - : dao.lookupInProfileByNameSync(profileUUID, - String.valueOf(constraint) - .toUpperCase())); + final List matches = AccountDAO.unbox((profileId == 0) ? dao.lookupByNameSync( + String.valueOf(constraint) + .toUpperCase()) : dao.lookupInProfileByNameSync(profileId, + String.valueOf(constraint) + .toUpperCase())); results.values = matches; results.count = matches.size(); diff --git a/app/src/main/java/net/ktnx/mobileledger/db/AccountValue.java b/app/src/main/java/net/ktnx/mobileledger/db/AccountValue.java index f41b0e73..0b39c475 100644 --- a/app/src/main/java/net/ktnx/mobileledger/db/AccountValue.java +++ b/app/src/main/java/net/ktnx/mobileledger/db/AccountValue.java @@ -20,20 +20,24 @@ package net.ktnx.mobileledger.db; import androidx.annotation.NonNull; import androidx.room.ColumnInfo; import androidx.room.Entity; +import androidx.room.ForeignKey; +import androidx.room.Index; +import androidx.room.PrimaryKey; -/* -create table account_values(profile varchar not null, account varchar not null, currency varchar -not null default '', value decimal not null, generation integer default 0 ); -create unique index un_account_values on account_values(profile,account,currency); - */ -@Entity(tableName = "account_values", primaryKeys = {"profile", "account", "currency"}) + +@Entity(tableName = "account_values", indices = { + @Index(name = "un_account_values", unique = true, value = {"account_id", "currency"}), + @Index(name = "fk_account_value_acc", value = "account_id") +}, foreignKeys = { + @ForeignKey(entity = Account.class, parentColumns = "id", childColumns = "account_id", + onDelete = ForeignKey.CASCADE, onUpdate = ForeignKey.RESTRICT) +}) public class AccountValue { @ColumnInfo - @NonNull - private String profile; + @PrimaryKey(autoGenerate = true) + long id; @ColumnInfo - @NonNull - private String account; + private long account_id; @NonNull @ColumnInfo(defaultValue = "") private String currency = ""; @@ -41,19 +45,17 @@ public class AccountValue { private float value; @ColumnInfo(defaultValue = "0") private int generation = 0; - @NonNull - public String getProfile() { - return profile; + public long getId() { + return id; } - public void setProfile(@NonNull String profile) { - this.profile = profile; + public void setId(long id) { + this.id = id; } - @NonNull - public String getAccount() { - return account; + public long getAccount_id() { + return account_id; } - public void setAccount(@NonNull String account) { - this.account = account; + public void setAccount_id(long account_id) { + this.account_id = account_id; } @NonNull public String getCurrency() { diff --git a/app/src/main/java/net/ktnx/mobileledger/db/DB.java b/app/src/main/java/net/ktnx/mobileledger/db/DB.java index 32e8b216..7dcb0897 100644 --- a/app/src/main/java/net/ktnx/mobileledger/db/DB.java +++ b/app/src/main/java/net/ktnx/mobileledger/db/DB.java @@ -50,7 +50,7 @@ import static net.ktnx.mobileledger.utils.Logger.debug; Transaction.class, TransactionAccount.class }) abstract public class DB extends RoomDatabase { - public static final int REVISION = 58; + public static final int REVISION = 59; public static final String DB_NAME = "MoLe.db"; private static DB instance; public static DB get() { diff --git a/app/src/main/java/net/ktnx/mobileledger/db/Option.java b/app/src/main/java/net/ktnx/mobileledger/db/Option.java index 2b8f6a3c..180295b3 100644 --- a/app/src/main/java/net/ktnx/mobileledger/db/Option.java +++ b/app/src/main/java/net/ktnx/mobileledger/db/Option.java @@ -21,22 +21,20 @@ import androidx.annotation.NonNull; import androidx.room.ColumnInfo; import androidx.room.Entity; -@Entity(tableName = "options", primaryKeys = {"profile", "name"}) +@Entity(tableName = "options", primaryKeys = {"profile_id", "name"}) public class Option { - @NonNull - @ColumnInfo - private String profile = "invalid"; + @ColumnInfo(name = "profile_id") + private long profileId; @NonNull @ColumnInfo private String name = ""; @ColumnInfo private String value; - @NonNull - public String getProfile() { - return profile; + public long getProfileId() { + return profileId; } - public void setProfile(@NonNull String profile) { - this.profile = profile; + public void setProfile(long profileId) { + this.profileId = profileId; } @NonNull public String getName() { diff --git a/app/src/main/java/net/ktnx/mobileledger/db/Profile.java b/app/src/main/java/net/ktnx/mobileledger/db/Profile.java index 1ed8a21b..d2330380 100644 --- a/app/src/main/java/net/ktnx/mobileledger/db/Profile.java +++ b/app/src/main/java/net/ktnx/mobileledger/db/Profile.java @@ -20,21 +20,13 @@ package net.ktnx.mobileledger.db; import androidx.annotation.NonNull; import androidx.room.ColumnInfo; import androidx.room.Entity; +import androidx.room.PrimaryKey; -/* - create table profiles(uuid varchar not null primary key, name not null, url not null, - use_authentication boolean not null, auth_user varchar, auth_password varchar, order_no - integer, permit_posting boolean default 0, theme integer default -1, preferred_accounts_filter - varchar, future_dates integer, api_version integer, show_commodity_by_default boolean default - 0, default_commodity varchar, show_comments_by_default boolean default 1, - detected_version_pre_1_19 boolean, detected_version_major integer, detected_version_minor - integer); -*/ -@Entity(tableName = "profiles", primaryKeys = {"uuid"}) +@Entity(tableName = "profiles") public class Profile { - @NonNull @ColumnInfo - private String uuid = "invalid"; + @PrimaryKey(autoGenerate = true) + private long id; @NonNull @ColumnInfo private String name = ""; @@ -71,12 +63,11 @@ public class Profile { private int detectedVersionMajor; @ColumnInfo(name = "detected_version_minor") private int detectedVersionMinor; - @NonNull - public String getUuid() { - return uuid; + public long getId() { + return id; } - public void setUuid(@NonNull String uuid) { - this.uuid = uuid; + public void setId(long id) { + this.id = id; } @NonNull public String getName() { diff --git a/app/src/main/java/net/ktnx/mobileledger/db/Transaction.java b/app/src/main/java/net/ktnx/mobileledger/db/Transaction.java index f6808f94..d67cedf5 100644 --- a/app/src/main/java/net/ktnx/mobileledger/db/Transaction.java +++ b/app/src/main/java/net/ktnx/mobileledger/db/Transaction.java @@ -20,7 +20,11 @@ package net.ktnx.mobileledger.db; import androidx.annotation.NonNull; import androidx.room.ColumnInfo; import androidx.room.Entity; +import androidx.room.ForeignKey; import androidx.room.Index; +import androidx.room.PrimaryKey; + +import org.jetbrains.annotations.NotNull; /* create table transactions(profile varchar not null, id integer not null, data_hash varchar not @@ -29,16 +33,20 @@ collate NOCASE not null, comment varchar, generation integer default 0, primary create unique index un_transactions_data_hash on transactions(profile,data_hash); create index idx_transaction_description on transactions(description); */ -@Entity(tableName = "transactions", primaryKeys = {"profile", "id"}, indices = { - @Index(name = "un_transactions_data_hash", unique = true, value = {"profile", "data_hash"}), - @Index(name = "idx_transaction_description", value = "description") +@Entity(tableName = "transactions", foreignKeys = { + @ForeignKey(entity = Profile.class, parentColumns = "id", childColumns = "profile_id", + onDelete = ForeignKey.CASCADE, onUpdate = ForeignKey.RESTRICT) +}, indices = {@Index(name = "un_transactions_data_hash", unique = true, + value = {"profile_id", "data_hash"}), + @Index(name = "idx_transaction_description", value = "description"), + @Index(name = "fk_transaction_profile", value = "profile_id") }) public class Transaction { @ColumnInfo - @NonNull - private String profile; - @ColumnInfo - private int id; + @PrimaryKey(autoGenerate = true) + long id; + @ColumnInfo(name = "profile_id") + private long profileId; @ColumnInfo(name = "data_hash") @NonNull private String dataHash; @@ -55,22 +63,22 @@ public class Transaction { private String comment; @ColumnInfo private int generation = 0; - public String getProfile() { - return profile; + public long getProfileId() { + return profileId; } - public void setProfile(String profile) { - this.profile = profile; + public void setProfileId(long profileId) { + this.profileId = profileId; } - public int getId() { + public long getId() { return id; } - public void setId(int id) { + public void setId(long id) { this.id = id; } public String getDataHash() { return dataHash; } - public void setDataHash(String dataHash) { + public void setDataHash(@NotNull String dataHash) { this.dataHash = dataHash; } public int getYear() { diff --git a/app/src/main/java/net/ktnx/mobileledger/db/TransactionAccount.java b/app/src/main/java/net/ktnx/mobileledger/db/TransactionAccount.java index 6d51fec9..730a866a 100644 --- a/app/src/main/java/net/ktnx/mobileledger/db/TransactionAccount.java +++ b/app/src/main/java/net/ktnx/mobileledger/db/TransactionAccount.java @@ -22,19 +22,20 @@ import androidx.room.ColumnInfo; import androidx.room.Entity; import androidx.room.ForeignKey; import androidx.room.Index; +import androidx.room.PrimaryKey; -@Entity(tableName = "transaction_accounts", primaryKeys = {"profile", "transaction_id", "order_no"}, - foreignKeys = {@ForeignKey(entity = Transaction.class, parentColumns = {"profile", "id"}, - childColumns = {"profile", "transaction_id"}, - onDelete = ForeignKey.CASCADE, onUpdate = ForeignKey.RESTRICT), - @ForeignKey(entity = Account.class, parentColumns = {"profile", "name"}, - childColumns = {"profile", "account_name"}, - onDelete = ForeignKey.CASCADE, onUpdate = ForeignKey.RESTRICT) - }, indices = {@Index(name = "fk_tran_acc_prof_acc", value = {"profile", "account_name"})}) +@Entity(tableName = "transaction_accounts", foreignKeys = { + @ForeignKey(entity = Transaction.class, parentColumns = {"id"}, + childColumns = {"transaction_id"}, onDelete = ForeignKey.CASCADE, + onUpdate = ForeignKey.RESTRICT), +}, indices = {@Index(name = "fk_tran_acc_trans", value = {"transaction_id"}), + @Index(name = "un_transaction_accounts", unique = true, + value = {"transaction_id", "order_no"}) +}) public class TransactionAccount { @ColumnInfo - @NonNull - private String profile; + @PrimaryKey(autoGenerate = true) + private long id; @ColumnInfo(name = "transaction_id") private int transactionId; @ColumnInfo(name = "order_no") @@ -51,13 +52,13 @@ public class TransactionAccount { private String comment; @ColumnInfo(defaultValue = "0") private int generation = 0; - @NonNull - public String getProfile() { - return profile; + public long getId() { + return id; } - public void setProfile(@NonNull String profile) { - this.profile = profile; + public void setId(long id) { + this.id = id; } + @NonNull public int getTransactionId() { return transactionId; } diff --git a/app/src/main/java/net/ktnx/mobileledger/model/Data.java b/app/src/main/java/net/ktnx/mobileledger/model/Data.java index c0f4ceba..3520711b 100644 --- a/app/src/main/java/net/ktnx/mobileledger/model/Data.java +++ b/app/src/main/java/net/ktnx/mobileledger/model/Data.java @@ -94,11 +94,11 @@ public final class Data { backgroundTasksRunning.postValue(cnt > 0); } public static void setCurrentProfile(@NonNull MobileLedgerProfile newProfile) { - MLDB.setOption(MLDB.OPT_PROFILE_UUID, newProfile.getUuid()); + MLDB.setLongOption(MLDB.OPT_PROFILE_ID, newProfile.getId()); profile.setValue(newProfile); } public static void postCurrentProfile(@NonNull MobileLedgerProfile newProfile) { - MLDB.setOption(MLDB.OPT_PROFILE_UUID, newProfile.getUuid()); + MLDB.setLongOption(MLDB.OPT_PROFILE_ID, newProfile.getId()); profile.postValue(newProfile); } public static int getProfileIndex(MobileLedgerProfile profile) { @@ -116,15 +116,14 @@ public final class Data { } } @SuppressWarnings("WeakerAccess") - public static int getProfileIndex(String profileUUID) { + public static int getProfileIndex(long profileId) { try (LockHolder ignored = profilesLocker.lockForReading()) { List prList = profiles.getValue(); if (prList == null) throw new AssertionError(); for (int i = 0; i < prList.size(); i++) { MobileLedgerProfile p = prList.get(i); - if (p.getUuid() - .equals(profileUUID)) + if (p.getId() == profileId) return i; } @@ -132,13 +131,13 @@ public final class Data { } } public static int retrieveCurrentThemeIdFromDb() { - String profileUUID = MLDB.getOption(MLDB.OPT_PROFILE_UUID, null); - if (profileUUID == null) + long profileId = MLDB.getLongOption(MLDB.OPT_PROFILE_ID, 0); + if (profileId == 0) return -1; SQLiteDatabase db = App.getDatabase(); try (Cursor c = db.rawQuery("SELECT theme from profiles where uuid=?", - new String[]{profileUUID})) + new String[]{String.valueOf(profileId)})) { if (c.moveToNext()) return c.getInt(0); @@ -147,18 +146,18 @@ public final class Data { return -1; } @Nullable - public static MobileLedgerProfile getProfile(String profileUUID) { + public static MobileLedgerProfile getProfile(long profileId) { MobileLedgerProfile profile; try (LockHolder readLock = profilesLocker.lockForReading()) { List prList = profiles.getValue(); if ((prList == null) || prList.isEmpty()) { readLock.close(); try (LockHolder ignored = profilesLocker.lockForWriting()) { - profile = MobileLedgerProfile.loadAllFromDB(profileUUID); + profile = MobileLedgerProfile.loadAllFromDB(profileId); } } else { - int i = getProfileIndex(profileUUID); + int i = getProfileIndex(profileId); if (i == -1) i = 0; profile = prList.get(i); @@ -218,8 +217,8 @@ public final class Data { if (currentProfile != null) return currentProfile; - String profileUUID = MLDB.getOption(MLDB.OPT_PROFILE_UUID, null); - MobileLedgerProfile startupProfile = getProfile(profileUUID); + long profileId = MLDB.getLongOption(MLDB.OPT_PROFILE_ID, 0); + MobileLedgerProfile startupProfile = getProfile(profileId); if (startupProfile != null) setCurrentProfile(startupProfile); Logger.debug("profile", "initProfile() returning " + startupProfile); diff --git a/app/src/main/java/net/ktnx/mobileledger/model/LedgerTransaction.java b/app/src/main/java/net/ktnx/mobileledger/model/LedgerTransaction.java index e566ca8f..2eba45e9 100644 --- a/app/src/main/java/net/ktnx/mobileledger/model/LedgerTransaction.java +++ b/app/src/main/java/net/ktnx/mobileledger/model/LedgerTransaction.java @@ -1,5 +1,5 @@ /* - * Copyright © 2020 Damyan Ivanov. + * Copyright © 2021 Damyan Ivanov. * This file is part of MoLe. * MoLe is free software: you can distribute it and/or modify it * under the term of the GNU General Public License as published by @@ -52,12 +52,12 @@ public class LedgerTransaction { return res; return Float.compare(o1.getAmount(), o2.getAmount()); }; - private final String profile; + private final long profile; private final Integer id; + private final List accounts; private SimpleDate date; private String description; private String comment; - private final List accounts; private String dataHash; private boolean dataLoaded; public LedgerTransaction(Integer id, String dateString, String description) @@ -66,7 +66,7 @@ public class LedgerTransaction { } public LedgerTransaction(Integer id, SimpleDate date, String description, MobileLedgerProfile profile) { - this.profile = profile.getUuid(); + this.profile = profile.getId(); this.id = id; this.date = date; this.description = description; @@ -83,8 +83,8 @@ public class LedgerTransaction { public LedgerTransaction(int id) { this(id, (SimpleDate) null, null); } - public LedgerTransaction(int id, String profileUUID) { - this.profile = profileUUID; + public LedgerTransaction(int id, long profileId) { + this.profile = profileId; this.id = id; this.date = null; this.description = null; @@ -170,7 +170,7 @@ public class LedgerTransaction { try (Cursor cTr = db.rawQuery( "SELECT year, month, day, description, comment from transactions WHERE profile=? " + - "AND id=?", new String[]{profile, String.valueOf(id)})) + "AND id=?", new String[]{String.valueOf(profile), String.valueOf(id)})) { if (cTr.moveToFirst()) { date = new SimpleDate(cTr.getInt(0), cTr.getInt(1), cTr.getInt(2)); @@ -182,7 +182,7 @@ public class LedgerTransaction { try (Cursor cAcc = db.rawQuery( "SELECT account_name, amount, currency, comment FROM " + "transaction_accounts WHERE profile=? AND transaction_id = ?", - new String[]{profile, String.valueOf(id)})) + new String[]{String.valueOf(profile), String.valueOf(id)})) { while (cAcc.moveToNext()) { // debug("transactions", diff --git a/app/src/main/java/net/ktnx/mobileledger/model/MobileLedgerProfile.java b/app/src/main/java/net/ktnx/mobileledger/model/MobileLedgerProfile.java index b8085765..fddacf67 100644 --- a/app/src/main/java/net/ktnx/mobileledger/model/MobileLedgerProfile.java +++ b/app/src/main/java/net/ktnx/mobileledger/model/MobileLedgerProfile.java @@ -51,7 +51,7 @@ import static net.ktnx.mobileledger.utils.Logger.debug; public final class MobileLedgerProfile { // N.B. when adding new fields, update the copy-constructor below - private final String uuid; + private final long id; private String name; private boolean permitPosting; private boolean showCommentsByDefault; @@ -71,11 +71,11 @@ public final class MobileLedgerProfile { private HledgerVersion detectedVersion; // N.B. when adding new fields, update the copy-constructor below transient private AccountAndTransactionListSaver accountAndTransactionListSaver; - public MobileLedgerProfile(String uuid) { - this.uuid = uuid; + public MobileLedgerProfile(long id) { + this.id = id; } public MobileLedgerProfile(MobileLedgerProfile origin) { - uuid = origin.uuid; + id = origin.id; name = origin.name; permitPosting = origin.permitPosting; showCommentsByDefault = origin.showCommentsByDefault; @@ -97,11 +97,11 @@ public final class MobileLedgerProfile { } // loads all profiles into Data.profiles // returns the profile with the given UUID - public static MobileLedgerProfile loadAllFromDB(@Nullable String currentProfileUUID) { + public static MobileLedgerProfile loadAllFromDB(long currentProfileId) { MobileLedgerProfile result = null; ArrayList list = new ArrayList<>(); SQLiteDatabase db = App.getDatabase(); - try (Cursor cursor = db.rawQuery("SELECT uuid, name, url, use_authentication, auth_user, " + + try (Cursor cursor = db.rawQuery("SELECT id, name, url, use_authentication, auth_user, " + "auth_password, permit_posting, theme, order_no, " + "preferred_accounts_filter, future_dates, api_version, " + "show_commodity_by_default, default_commodity, " + @@ -110,7 +110,7 @@ public final class MobileLedgerProfile { "profiles order by order_no", null)) { while (cursor.moveToNext()) { - MobileLedgerProfile item = new MobileLedgerProfile(cursor.getString(0)); + MobileLedgerProfile item = new MobileLedgerProfile(cursor.getLong(0)); item.setName(cursor.getString(1)); item.setUrl(cursor.getString(2)); item.setAuthEnabled(cursor.getInt(3) == 1); @@ -141,8 +141,7 @@ public final class MobileLedgerProfile { } } list.add(item); - if (item.getUuid() - .equals(currentProfileUUID)) + if (item.getId() == currentProfileId) result = item; } } @@ -156,7 +155,7 @@ public final class MobileLedgerProfile { int orderNo = 0; for (MobileLedgerProfile p : Objects.requireNonNull(Data.profiles.getValue())) { db.execSQL("update profiles set order_no=? where uuid=?", - new Object[]{orderNo, p.getUuid()}); + new Object[]{orderNo, p.getId()}); p.orderNo = orderNo; orderNo++; } @@ -194,7 +193,7 @@ public final class MobileLedgerProfile { return false; MobileLedgerProfile p = (MobileLedgerProfile) obj; - if (!uuid.equals(p.uuid)) + if (id != p.id) return false; if (!name.equals(p.name)) return false; @@ -281,8 +280,8 @@ public final class MobileLedgerProfile { public void setPostingPermitted(boolean permitPosting) { this.permitPosting = permitPosting; } - public String getUuid() { - return uuid; + public long getId() { + return id; } public String getName() { return name; @@ -334,14 +333,14 @@ public final class MobileLedgerProfile { // "url=%s, permit_posting=%s, authEnabled=%s, " + // "themeHue=%d", uuid, name, url, // permitPosting ? "TRUE" : "FALSE", authEnabled ? "TRUE" : "FALSE", themeHue)); - db.execSQL("REPLACE INTO profiles(uuid, name, permit_posting, url, " + + db.execSQL("REPLACE INTO profiles(id, name, permit_posting, url, " + "use_authentication, auth_user, auth_password, theme, order_no, " + "preferred_accounts_filter, future_dates, api_version, " + "show_commodity_by_default, default_commodity, show_comments_by_default," + "detected_version_pre_1_19, detected_version_major, " + "detected_version_minor) " + "VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", - new Object[]{uuid, name, permitPosting, url, authEnabled, + new Object[]{id, name, permitPosting, url, authEnabled, authEnabled ? authUserName : null, authEnabled ? authPassword : null, themeHue, orderNo, preferredAccountsFilter, futureDates.toInt(), apiVersion.toInt(), @@ -368,13 +367,13 @@ public final class MobileLedgerProfile { params.add(acc.isExpanded() ? 1 : 0); } sql += " where profile=? and name=?"; - params.add(uuid); + params.add(id); params.add(acc.getName()); db.execSQL(sql, params.toArray()); db.execSQL("insert into accounts(profile, name, name_upper, parent_name, level, " + "expanded, generation) select ?,?,?,?,?,0,? where (select changes() = 0)", - new Object[]{uuid, acc.getName(), acc.getName().toUpperCase(), acc.getParentName(), + new Object[]{id, acc.getName(), acc.getName().toUpperCase(), acc.getParentName(), acc.getLevel(), generation }); // debug("accounts", String.format("Stored account '%s' in DB [%s]", acc.getName(), uuid)); @@ -401,7 +400,7 @@ public final class MobileLedgerProfile { db.execSQL("replace into account_values(profile, account, " + "currency, value, generation) values(?, ?, ?, ?, ?);", - new Object[]{uuid, name, Misc.emptyIsNull(currency), amount, generation}); + new Object[]{id, name, Misc.emptyIsNull(currency), amount, generation}); } public void storeTransaction(SQLiteDatabase db, int generation, LedgerTransaction tr) { tr.fillDataHash(); @@ -410,12 +409,12 @@ public final class MobileLedgerProfile { db.execSQL("UPDATE transactions SET year=?, month=?, day=?, description=?, comment=?, " + "data_hash=?, generation=? WHERE profile=? AND id=?", new Object[]{d.year, d.month, d.day, tr.getDescription(), tr.getComment(), - tr.getDataHash(), generation, uuid, tr.getId() + tr.getDataHash(), generation, id, tr.getId() }); db.execSQL("INSERT INTO transactions(profile, id, year, month, day, description, " + "comment, data_hash, generation) " + "select ?,?,?,?,?,?,?,?,? WHERE (select changes() = 0)", - new Object[]{uuid, tr.getId(), tr.getDate().year, tr.getDate().month, + new Object[]{id, tr.getId(), tr.getDate().year, tr.getDate().month, tr.getDate().day, tr.getDescription(), tr.getComment(), tr.getDataHash(), generation }); @@ -427,12 +426,12 @@ public final class MobileLedgerProfile { "WHERE profile=? AND transaction_id=? AND order_no=?", new Object[]{item.getAccountName(), item.getAmount(), Misc.nullIsEmpty(item.getCurrency()), item.getComment(), - generation, uuid, tr.getId(), accountOrderNo + generation, id, tr.getId(), accountOrderNo }); db.execSQL("INSERT INTO transaction_accounts(profile, transaction_id, " + "order_no, account_name, amount, currency, comment, generation) " + "select ?, ?, ?, ?, ?, ?, ?, ? WHERE (select changes() = 0)", - new Object[]{uuid, tr.getId(), accountOrderNo, item.getAccountName(), + new Object[]{id, tr.getId(), accountOrderNo, item.getAccountName(), item.getAmount(), Misc.nullIsEmpty(item.getCurrency()), item.getComment(), generation }); @@ -444,7 +443,7 @@ public final class MobileLedgerProfile { public String getOption(String name, String default_value) { SQLiteDatabase db = App.getDatabase(); try (Cursor cursor = db.rawQuery("select value from options where profile = ? and name=?", - new String[]{uuid, name})) + new String[]{String.valueOf(id), name})) { if (cursor.moveToFirst()) { String result = cursor.getString(0); @@ -489,23 +488,23 @@ public final class MobileLedgerProfile { public void setOption(String name, String value) { debug("profile", String.format("setting option %s=%s", name, value)); DbOpQueue.add("insert or replace into options(profile, name, value) values(?, ?, ?);", - new String[]{uuid, name, value}); + new String[]{String.valueOf(id), name, value}); } public void setLongOption(String name, long value) { setOption(name, String.valueOf(value)); } public void removeFromDB() { SQLiteDatabase db = App.getDatabase(); - debug("db", String.format("removing profile %s from DB", uuid)); + debug("db", String.format(Locale.ROOT, "removing profile %d from DB", id)); db.beginTransactionNonExclusive(); try { - Object[] uuid_param = new Object[]{uuid}; - db.execSQL("delete from transaction_accounts where profile=?", uuid_param); - db.execSQL("delete from transactions where profile=?", uuid_param); - db.execSQL("delete from account_values where profile=?", uuid_param); - db.execSQL("delete from accounts where profile=?", uuid_param); - db.execSQL("delete from options where profile=?", uuid_param); - db.execSQL("delete from profiles where uuid=?", uuid_param); + Object[] id_param = new Object[]{id}; + db.execSQL("delete from transaction_accounts where profile=?", id_param); + db.execSQL("delete from transactions where profile=?", id_param); + db.execSQL("delete from account_values where profile=?", id_param); + db.execSQL("delete from accounts where profile=?", id_param); + db.execSQL("delete from options where profile=?", id_param); + db.execSQL("delete from profiles where uuid=?", id_param); db.setTransactionSuccessful(); } finally { @@ -513,7 +512,7 @@ public final class MobileLedgerProfile { } } public LedgerTransaction loadTransaction(int transactionId) { - LedgerTransaction tr = new LedgerTransaction(transactionId, this.uuid); + LedgerTransaction tr = new LedgerTransaction(transactionId, this.id); tr.loadData(App.getDatabase()); return tr; @@ -532,7 +531,7 @@ public final class MobileLedgerProfile { public int getNextTransactionsGeneration(SQLiteDatabase db) { int generation = 1; try (Cursor c = db.rawQuery("SELECT generation FROM transactions WHERE profile=? LIMIT 1", - new String[]{uuid})) + new String[]{String.valueOf(id)})) { if (c.moveToFirst()) { generation = c.getInt(0) + 1; @@ -543,7 +542,7 @@ public final class MobileLedgerProfile { private int getNextAccountsGeneration(SQLiteDatabase db) { int generation = 1; try (Cursor c = db.rawQuery("SELECT generation FROM accounts WHERE profile=? LIMIT 1", - new String[]{uuid})) + new String[]{String.valueOf(id)})) { if (c.moveToFirst()) { generation = c.getInt(0) + 1; @@ -554,24 +553,24 @@ public final class MobileLedgerProfile { private void deleteNotPresentAccounts(SQLiteDatabase db, int generation) { Logger.debug("db/benchmark", "Deleting obsolete accounts"); db.execSQL("DELETE FROM account_values WHERE profile=? AND generation <> ?", - new Object[]{uuid, generation}); + new Object[]{id, generation}); db.execSQL("DELETE FROM accounts WHERE profile=? AND generation <> ?", - new Object[]{uuid, generation}); + new Object[]{id, generation}); Logger.debug("db/benchmark", "Done deleting obsolete accounts"); } private void deleteNotPresentTransactions(SQLiteDatabase db, int generation) { Logger.debug("db/benchmark", "Deleting obsolete transactions"); db.execSQL("DELETE FROM transaction_accounts WHERE profile=? AND generation <> ?", - new Object[]{uuid, generation}); + new Object[]{id, generation}); db.execSQL("DELETE FROM transactions WHERE profile=? AND generation <> ?", - new Object[]{uuid, generation}); + new Object[]{id, generation}); Logger.debug("db/benchmark", "Done deleting obsolete transactions"); } public void wipeAllData() { SQLiteDatabase db = App.getDatabase(); db.beginTransaction(); try { - String[] pUuid = new String[]{uuid}; + String[] pUuid = new String[]{String.valueOf(id)}; db.execSQL("delete from options where profile=?", pUuid); db.execSQL("delete from accounts where profile=?", pUuid); db.execSQL("delete from account_values where profile=?", pUuid); diff --git a/app/src/main/java/net/ktnx/mobileledger/ui/MainModel.java b/app/src/main/java/net/ktnx/mobileledger/ui/MainModel.java index 44a6f303..813e3a00 100644 --- a/app/src/main/java/net/ktnx/mobileledger/ui/MainModel.java +++ b/app/src/main/java/net/ktnx/mobileledger/ui/MainModel.java @@ -1,5 +1,5 @@ /* - * Copyright © 2020 Damyan Ivanov. + * Copyright © 2021 Damyan Ivanov. * This file is part of MoLe. * MoLe is free software: you can distribute it and/or modify it * under the term of the GNU General Public License as published by @@ -286,7 +286,7 @@ public class MainModel extends ViewModel { @Override public void run() { Logger.debug("async-acc", "AccountListLoader::run() entered"); - String profileUUID = profile.getUuid(); + long profileId = profile.getId(); ArrayList list = new ArrayList<>(); HashMap map = new HashMap<>(); @@ -296,7 +296,7 @@ public class MainModel extends ViewModel { SQLiteDatabase db = App.getDatabase(); Logger.debug("async-acc", "AccountListLoader::run() connected to DB"); - try (Cursor cursor = db.rawQuery(sql, new String[]{profileUUID})) { + try (Cursor cursor = db.rawQuery(sql, new String[]{String.valueOf(profileId)})) { Logger.debug("async-acc", "AccountListLoader::run() executed query"); while (cursor.moveToNext()) { if (isInterrupted()) @@ -305,7 +305,7 @@ public class MainModel extends ViewModel { final String accName = cursor.getString(0); // debug("accounts", // String.format("Read account '%s' from DB [%s]", accName, -// profileUUID)); +// profileId)); String parentName = LedgerAccount.extractParentName(accName); LedgerAccount parent; if (parentName != null) { @@ -326,7 +326,7 @@ public class MainModel extends ViewModel { try (Cursor c2 = db.rawQuery( "SELECT value, currency FROM account_values WHERE profile = ?" + " " + - "AND account = ?", new String[]{profileUUID, accName})) + "AND account = ?", new String[]{String.valueOf(profileId), accName})) { while (c2.moveToNext()) { acc.addAmount(c2.getFloat(0), c2.getString(1)); diff --git a/app/src/main/java/net/ktnx/mobileledger/ui/account_summary/AccountSummaryAdapter.java b/app/src/main/java/net/ktnx/mobileledger/ui/account_summary/AccountSummaryAdapter.java index b8e4c303..20b72915 100644 --- a/app/src/main/java/net/ktnx/mobileledger/ui/account_summary/AccountSummaryAdapter.java +++ b/app/src/main/java/net/ktnx/mobileledger/ui/account_summary/AccountSummaryAdapter.java @@ -169,7 +169,7 @@ public class AccountSummaryAdapter model.updateDisplayedAccounts(); DbOpQueue.add("update accounts set expanded=? where name=? and profile=?", - new Object[]{mAccount.isExpanded(), mAccount.getName(), profile.getUuid() + new Object[]{mAccount.isExpanded(), mAccount.getName(), profile.getId() }); } @@ -192,7 +192,7 @@ public class AccountSummaryAdapter return; DbOpQueue.add("update accounts set amounts_expanded=? where name=? and profile=?", - new Object[]{mAccount.amountsExpanded(), mAccount.getName(), profile.getUuid() + new Object[]{mAccount.amountsExpanded(), mAccount.getName(), profile.getId() }); } diff --git a/app/src/main/java/net/ktnx/mobileledger/ui/activity/MainActivity.java b/app/src/main/java/net/ktnx/mobileledger/ui/activity/MainActivity.java index c4d5c24a..25efe111 100644 --- a/app/src/main/java/net/ktnx/mobileledger/ui/activity/MainActivity.java +++ b/app/src/main/java/net/ktnx/mobileledger/ui/activity/MainActivity.java @@ -347,13 +347,13 @@ public class MainActivity extends ProfileThemedActivity implements FabManager.Fa continue; final ShortcutInfo.Builder builder = - new ShortcutInfo.Builder(this, "new_transaction_" + p.getUuid()); + new ShortcutInfo.Builder(this, "new_transaction_" + p.getId()); ShortcutInfo si = builder.setShortLabel(p.getName()) .setIcon(Icon.createWithResource(this, R.drawable.thick_plus_icon)) .setIntent(new Intent(Intent.ACTION_VIEW, null, this, - NewTransactionActivity.class).putExtra("profile_uuid", - p.getUuid())) + NewTransactionActivity.class).putExtra("profile_id", + p.getId())) .setRank(i) .build(); shortcuts.add(si); diff --git a/app/src/main/java/net/ktnx/mobileledger/ui/activity/SplashActivity.java b/app/src/main/java/net/ktnx/mobileledger/ui/activity/SplashActivity.java index 4205c80b..2a238adc 100644 --- a/app/src/main/java/net/ktnx/mobileledger/ui/activity/SplashActivity.java +++ b/app/src/main/java/net/ktnx/mobileledger/ui/activity/SplashActivity.java @@ -1,5 +1,5 @@ /* - * Copyright © 2020 Damyan Ivanov. + * Copyright © 2021 Damyan Ivanov. * This file is part of MoLe. * MoLe is free software: you can distribute it and/or modify it * under the term of the GNU General Public License as published by @@ -100,10 +100,10 @@ public class SplashActivity extends CrashReportingActivity { private static class DatabaseInitTask extends AsyncTask { @Override protected Void doInBackground(Void... voids) { - MobileLedgerProfile.loadAllFromDB(null); + MobileLedgerProfile.loadAllFromDB(0); - String profileUUID = MLDB.getOption(MLDB.OPT_PROFILE_UUID, null); - MobileLedgerProfile startupProfile = Data.getProfile(profileUUID); + long profileId = MLDB.getLongOption(MLDB.OPT_PROFILE_ID, 0); + MobileLedgerProfile startupProfile = Data.getProfile(profileId); if (startupProfile != null) Data.postCurrentProfile(startupProfile); return null; diff --git a/app/src/main/java/net/ktnx/mobileledger/ui/new_transaction/NewTransactionActivity.java b/app/src/main/java/net/ktnx/mobileledger/ui/new_transaction/NewTransactionActivity.java index ce97d985..469e773e 100644 --- a/app/src/main/java/net/ktnx/mobileledger/ui/new_transaction/NewTransactionActivity.java +++ b/app/src/main/java/net/ktnx/mobileledger/ui/new_transaction/NewTransactionActivity.java @@ -115,10 +115,10 @@ public class NewTransactionActivity extends ProfileThemedActivity } @Override protected void initProfile() { - String profileUUID = getIntent().getStringExtra("profile_uuid"); + long profileId = getIntent().getLongExtra("profile_id", 0); - if (profileUUID != null) { - mProfile = Data.getProfile(profileUUID); + if (profileId != 0) { + mProfile = Data.getProfile(profileId); if (mProfile == null) finish(); Data.setCurrentProfile(mProfile); @@ -378,9 +378,9 @@ public class NewTransactionActivity extends ProfileThemedActivity } @Override public boolean onRow(@NonNull Cursor cursor) { - final String profileUUID = cursor.getString(0); + final long profileId = cursor.getLong(0); final int transactionId = cursor.getInt(1); - runOnUiThread(() -> model.loadTransactionIntoModel(profileUUID, transactionId)); + runOnUiThread(() -> model.loadTransactionIntoModel(profileId, transactionId)); return false; // limit 1, by the way } @Override @@ -409,9 +409,9 @@ public class NewTransactionActivity extends ProfileThemedActivity } @Override public boolean onRow(@NonNull Cursor cursor) { - final String profileUUID = cursor.getString(0); + final long profileId = cursor.getLong(0); final int transactionId = cursor.getInt(1); - runOnUiThread(() -> model.loadTransactionIntoModel(profileUUID, + runOnUiThread(() -> model.loadTransactionIntoModel(profileId, transactionId)); return false; } diff --git a/app/src/main/java/net/ktnx/mobileledger/ui/new_transaction/NewTransactionModel.java b/app/src/main/java/net/ktnx/mobileledger/ui/new_transaction/NewTransactionModel.java index 7333561c..641a9b7b 100644 --- a/app/src/main/java/net/ktnx/mobileledger/ui/new_transaction/NewTransactionModel.java +++ b/app/src/main/java/net/ktnx/mobileledger/ui/new_transaction/NewTransactionModel.java @@ -461,15 +461,15 @@ public class NewTransactionModel extends ViewModel { return tr; } - void loadTransactionIntoModel(String profileUUID, int transactionId) { + void loadTransactionIntoModel(long profileId, int transactionId) { List newList = new ArrayList<>(); Item.resetIdDispenser(); LedgerTransaction tr; - MobileLedgerProfile profile = Data.getProfile(profileUUID); + MobileLedgerProfile profile = Data.getProfile(profileId); if (profile == null) throw new RuntimeException(String.format( "Unable to find profile %s, which is supposed to contain transaction %d", - profileUUID, transactionId)); + profileId, transactionId)); tr = profile.loadTransaction(transactionId); TransactionHead head = new TransactionHead(tr.getDescription()); diff --git a/app/src/main/java/net/ktnx/mobileledger/ui/profiles/ProfileDetailActivity.java b/app/src/main/java/net/ktnx/mobileledger/ui/profiles/ProfileDetailActivity.java index 8afdefc1..d860a678 100644 --- a/app/src/main/java/net/ktnx/mobileledger/ui/profiles/ProfileDetailActivity.java +++ b/app/src/main/java/net/ktnx/mobileledger/ui/profiles/ProfileDetailActivity.java @@ -65,7 +65,7 @@ public class ProfileDetailActivity extends CrashReportingActivity { index)); debug("profiles", String.format(Locale.ENGLISH, "Editing profile %s (%s); hue=%d", - profile.getName(), profile.getUuid(), profile.getThemeHue())); + profile.getName(), profile.getId(), profile.getThemeHue())); } } diff --git a/app/src/main/java/net/ktnx/mobileledger/ui/profiles/ProfileDetailFragment.java b/app/src/main/java/net/ktnx/mobileledger/ui/profiles/ProfileDetailFragment.java index 13a8b55a..f5b48aef 100644 --- a/app/src/main/java/net/ktnx/mobileledger/ui/profiles/ProfileDetailFragment.java +++ b/app/src/main/java/net/ktnx/mobileledger/ui/profiles/ProfileDetailFragment.java @@ -62,7 +62,6 @@ import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.Objects; -import java.util.UUID; import static net.ktnx.mobileledger.utils.Logger.debug; @@ -111,7 +110,7 @@ public class ProfileDetailFragment extends Fragment { builder.setTitle(mProfile.getName()); builder.setMessage(R.string.remove_profile_dialog_message); builder.setPositiveButton(R.string.Remove, (dialog, which) -> { - debug("profiles", String.format("[fragment] removing profile %s", mProfile.getUuid())); + debug("profiles", String.format("[fragment] removing profile %s", mProfile.getId())); mProfile.removeFromDB(); ArrayList oldList = Data.profiles.getValue(); if (oldList == null) @@ -431,9 +430,7 @@ public class ProfileDetailFragment extends Fragment { // debug("profiles", String.format("Selected item is %d", mProfile.getThemeHue())); final MobileLedgerProfile currentProfile = Data.getProfile(); - if (mProfile.getUuid() - .equals(currentProfile.getUuid())) - { + if (mProfile.getId() == currentProfile.getId()) { Data.setCurrentProfile(mProfile); } @@ -442,7 +439,7 @@ public class ProfileDetailFragment extends Fragment { viewAdapter.notifyItemChanged(pos); } else { - mProfile = new MobileLedgerProfile(String.valueOf(UUID.randomUUID())); + mProfile = new MobileLedgerProfile(0); model.updateProfile(mProfile); mProfile.storeInDB(); final ArrayList newList = new ArrayList<>(profiles); diff --git a/app/src/main/java/net/ktnx/mobileledger/utils/MLDB.java b/app/src/main/java/net/ktnx/mobileledger/utils/MLDB.java index e11044de..2a9dca89 100644 --- a/app/src/main/java/net/ktnx/mobileledger/utils/MLDB.java +++ b/app/src/main/java/net/ktnx/mobileledger/utils/MLDB.java @@ -35,7 +35,7 @@ public final class MLDB { public static final String DESCRIPTION_HISTORY_TABLE = "description_history"; public static final String OPT_LAST_SCRAPE = "last_scrape"; @NonNls - public static final String OPT_PROFILE_UUID = "profile_uuid"; + public static final String OPT_PROFILE_ID = "profile_id"; private static final String NO_PROFILE = "-"; @SuppressWarnings("unused") static public int getIntOption(String name, int default_value) { diff --git a/app/src/main/res/raw/db_59.sql b/app/src/main/res/raw/db_59.sql new file mode 100644 index 00000000..67c9beb7 --- /dev/null +++ b/app/src/main/res/raw/db_59.sql @@ -0,0 +1,70 @@ +-- Copyright © 2021 Damyan Ivanov. +-- This file is part of MoLe. +-- MoLe is free software: you can distribute it and/or modify it +-- under the term of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your opinion), any later version. +-- +-- MoLe is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License terms for details. +-- +-- You should have received a copy of the GNU General Public License +-- along with MoLe. If not, see . + +-- migrate from revision 58 to revision 59 + +CREATE TABLE profiles_new ( +id INTEGER NOT NULL PRIMARY KEY, +uuid text, +name TEXT NOT NULL, +url TEXT NOT NULL, +use_authentication INTEGER NOT NULL, +auth_user TEXT, +auth_password TEXT, +order_no INTEGER NOT NULL, +permit_posting INTEGER NOT NULL, +theme INTEGER NOT NULL DEFAULT -1, +preferred_accounts_filter TEXT, +future_dates INTEGER NOT NULL, +api_version INTEGER NOT NULL, +show_commodity_by_default INTEGER NOT NULL, +default_commodity TEXT, +show_comments_by_default INTEGER NOT NULL DEFAULT 1, +detected_version_pre_1_19 INTEGER NOT NULL, +detected_version_major INTEGER NOT NULL, +detected_version_minor INTEGER NOT NULL); + +insert into profiles_new( + uuid, name, url, use_authentication, auth_user, auth_password, + order_no, permit_posting, theme, preferred_accounts_filter, future_dates, api_version, + show_commodity_by_default, default_commodity, show_comments_by_default, detected_version_pre_1_19, + detected_version_major, detected_version_minor) +select uuid, name, url, use_authentication, auth_user, auth_password, + order_no, permit_posting, theme, preferred_accounts_filter, future_dates, api_version, + show_commodity_by_default, default_commodity, show_comments_by_default, detected_version_pre_1_19, + detected_version_major, detected_version_minor +from profiles; + +create table accounts_new( +id integer primary key not null, +profile_id integer not null references profiles_new(id) on delete cascade on update restrict, +level INTEGER NOT NULL, +name TEXT NOT NULL, +name_upper TEXT NOT NULL, +parent_name TEXT, +expanded INTEGER NOT NULL DEFAULT 1, +amounts_expanded INTEGER NOT NULL DEFAULT 0, +generation INTEGER NOT NULL DEFAULT 0); + +insert into accounts_new(profile_id, level, name, name_upper, parent_name, expanded, amounts_expanded, generation) +select p.id, a.level, a.name, a.name_upper, a.parent_name, a.expanded, a.amounts_expanded, a.generation +from profiles_new p +join accounts a on a.profile=p.uuid; + +drop table accounts; +alter table accounts_new rename to accounts; + +drop table profiles; +alter table profiles_new rename to profiles; \ No newline at end of file -- 2.39.2