Skip to content

Commit

Permalink
Recover book records if the database is found empty
Browse files Browse the repository at this point in the history
For some reason sometimes the books database is found empty at startup.
This tries to restore the database by recovering the book records.

Fixes http://crashes.to/s/d7c34870c8d
  • Loading branch information
rivaldi8 committed Dec 29, 2017
1 parent 6e3eec3 commit 0e4e1ce
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<String> getBookDatabases() {
List<String> 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<String> getAllBookUIDs(){
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 0e4e1ce

Please sign in to comment.