diff --git a/app/src/main/java/org/gnucash/android/db/adapter/BooksDbAdapter.java b/app/src/main/java/org/gnucash/android/db/adapter/BooksDbAdapter.java index 2260652f3..61e43cf06 100644 --- a/app/src/main/java/org/gnucash/android/db/adapter/BooksDbAdapter.java +++ b/app/src/main/java/org/gnucash/android/db/adapter/BooksDbAdapter.java @@ -23,9 +23,11 @@ import android.database.sqlite.SQLiteStatement; import android.net.Uri; import android.support.annotation.NonNull; +import android.util.Log; import org.gnucash.android.R; import org.gnucash.android.app.GnuCashApplication; +import org.gnucash.android.db.DatabaseHelper; import org.gnucash.android.db.DatabaseSchema.BookEntry; import org.gnucash.android.model.Book; import org.gnucash.android.ui.settings.PreferenceActivity; @@ -190,11 +192,70 @@ public NoActiveBookFoundException(String message) { } } - /** Sets the first book in the database as active. */ + /** Tries to fix the books database. */ public void fixBooksDatabase() { + Log.w(LOG_TAG, "Looking for books to set as active..."); + if (getRecordsCount() <= 0) { + Log.w(LOG_TAG, "No books found in the database. Recovering books records..."); + recoverBookRecords(); + } + setFirstBookAsActive(); + } + + /** + * Restores the records in the book database. + * + * Does so by looking for database files from books. + */ + private void recoverBookRecords() { + for (String dbName : getBookDatabases()) { + Book book = new Book(getRootAccountUID(dbName)); + book.setUID(dbName); + book.setDisplayName(generateDefaultBookName()); + addRecord(book); + Log.w(LOG_TAG, "Recovered book record: " + book.getUID()); + } + } + + /** + * Returns the root account UID from the database with name dbName. + */ + private String getRootAccountUID(String dbName) { + Context context = GnuCashApplication.getAppContext(); + DatabaseHelper databaseHelper = new DatabaseHelper(context, dbName); + SQLiteDatabase db = databaseHelper.getReadableDatabase(); + AccountsDbAdapter accountsDbAdapter = new AccountsDbAdapter(db, + new TransactionsDbAdapter(db, new SplitsDbAdapter(db))); + String uid = accountsDbAdapter.getOrCreateGnuCashRootAccountUID(); + db.close(); + return uid; + } + + /** + * Sets the first book in the database as active. + */ + private void setFirstBookAsActive() { Book firstBook = getAllRecords().get(0); firstBook.setActive(true); - BooksDbAdapter.getInstance().addRecord(firstBook); + addRecord(firstBook); + Log.w(LOG_TAG, "Book " + firstBook.getUID() + " set as active."); + } + + /** + * Returns a list of database names corresponding to book databases. + */ + private List getBookDatabases() { + List bookDatabases = new ArrayList<>(); + for (String database : GnuCashApplication.getAppContext().databaseList()) { + if (isBookDatabase(database)) { + bookDatabases.add(database); + } + } + return bookDatabases; + } + + private boolean isBookDatabase(String databaseName) { + return databaseName.matches("[a-z0-9]{32}"); // UID regex } public @NonNull List getAllBookUIDs(){ diff --git a/app/src/test/java/org/gnucash/android/test/unit/db/BooksDbAdapterTest.java b/app/src/test/java/org/gnucash/android/test/unit/db/BooksDbAdapterTest.java index 28594cb6f..b02a9bd7e 100644 --- a/app/src/test/java/org/gnucash/android/test/unit/db/BooksDbAdapterTest.java +++ b/app/src/test/java/org/gnucash/android/test/unit/db/BooksDbAdapterTest.java @@ -179,6 +179,22 @@ public void recoverFromNoActiveBookFound() { assertThat(mBooksDbAdapter.getActiveBookUID()).isEqualTo(book1.getUID()); } + /** + * Tests the recovery from an empty books database. + */ + @Test + public void recoverFromEmptyDatabase() { + createNewBookWithDefaultAccounts(); + mBooksDbAdapter.deleteAllRecords(); + assertThat(mBooksDbAdapter.getRecordsCount()).isZero(); + + mBooksDbAdapter.fixBooksDatabase(); + + // Should've recovered the one from setUp() plus the one created above + assertThat(mBooksDbAdapter.getRecordsCount()).isEqualTo(2); + mBooksDbAdapter.getActiveBookUID(); // should not throw exception + } + /** * Creates a new database with default accounts * @return The book UID for the new database