Skip to content

Commit 033a067

Browse files
authored
Merge pull request #755 from rivaldi8/cl-555-books-db-empty
Recover from empty books database
2 parents fa8f90d + 0e4e1ce commit 033a067

3 files changed

Lines changed: 106 additions & 8 deletions

File tree

app/src/main/java/org/gnucash/android/app/GnuCashApplication.java

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ public static void initializeDatabaseAdapters() {
150150
mDbHelper = new DatabaseHelper(getAppContext(),
151151
mBooksDbAdapter.getActiveBookUID());
152152
} catch (BooksDbAdapter.NoActiveBookFoundException e) {
153-
fixBooksDatabase();
153+
mBooksDbAdapter.fixBooksDatabase();
154154
mDbHelper = new DatabaseHelper(getAppContext(),
155155
mBooksDbAdapter.getActiveBookUID());
156156
}
@@ -174,13 +174,6 @@ public static void initializeDatabaseAdapters() {
174174
mBudgetsDbAdapter = new BudgetsDbAdapter(mainDb, mBudgetAmountsDbAdapter, mRecurrenceDbAdapter);
175175
}
176176

177-
/** Sets the first book in the database as active. */
178-
private static void fixBooksDatabase() {
179-
Book firstBook = BooksDbAdapter.getInstance().getAllRecords().get(0);
180-
firstBook.setActive(true);
181-
BooksDbAdapter.getInstance().addRecord(firstBook);
182-
}
183-
184177
public static AccountsDbAdapter getAccountsDbAdapter() {
185178
return mAccountsDbAdapter;
186179
}

app/src/main/java/org/gnucash/android/db/adapter/BooksDbAdapter.java

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,11 @@
2323
import android.database.sqlite.SQLiteStatement;
2424
import android.net.Uri;
2525
import android.support.annotation.NonNull;
26+
import android.util.Log;
2627

2728
import org.gnucash.android.R;
2829
import org.gnucash.android.app.GnuCashApplication;
30+
import org.gnucash.android.db.DatabaseHelper;
2931
import org.gnucash.android.db.DatabaseSchema.BookEntry;
3032
import org.gnucash.android.model.Book;
3133
import org.gnucash.android.ui.settings.PreferenceActivity;
@@ -190,6 +192,72 @@ public NoActiveBookFoundException(String message) {
190192
}
191193
}
192194

195+
/** Tries to fix the books database. */
196+
public void fixBooksDatabase() {
197+
Log.w(LOG_TAG, "Looking for books to set as active...");
198+
if (getRecordsCount() <= 0) {
199+
Log.w(LOG_TAG, "No books found in the database. Recovering books records...");
200+
recoverBookRecords();
201+
}
202+
setFirstBookAsActive();
203+
}
204+
205+
/**
206+
* Restores the records in the book database.
207+
*
208+
* Does so by looking for database files from books.
209+
*/
210+
private void recoverBookRecords() {
211+
for (String dbName : getBookDatabases()) {
212+
Book book = new Book(getRootAccountUID(dbName));
213+
book.setUID(dbName);
214+
book.setDisplayName(generateDefaultBookName());
215+
addRecord(book);
216+
Log.w(LOG_TAG, "Recovered book record: " + book.getUID());
217+
}
218+
}
219+
220+
/**
221+
* Returns the root account UID from the database with name dbName.
222+
*/
223+
private String getRootAccountUID(String dbName) {
224+
Context context = GnuCashApplication.getAppContext();
225+
DatabaseHelper databaseHelper = new DatabaseHelper(context, dbName);
226+
SQLiteDatabase db = databaseHelper.getReadableDatabase();
227+
AccountsDbAdapter accountsDbAdapter = new AccountsDbAdapter(db,
228+
new TransactionsDbAdapter(db, new SplitsDbAdapter(db)));
229+
String uid = accountsDbAdapter.getOrCreateGnuCashRootAccountUID();
230+
db.close();
231+
return uid;
232+
}
233+
234+
/**
235+
* Sets the first book in the database as active.
236+
*/
237+
private void setFirstBookAsActive() {
238+
Book firstBook = getAllRecords().get(0);
239+
firstBook.setActive(true);
240+
addRecord(firstBook);
241+
Log.w(LOG_TAG, "Book " + firstBook.getUID() + " set as active.");
242+
}
243+
244+
/**
245+
* Returns a list of database names corresponding to book databases.
246+
*/
247+
private List<String> getBookDatabases() {
248+
List<String> bookDatabases = new ArrayList<>();
249+
for (String database : GnuCashApplication.getAppContext().databaseList()) {
250+
if (isBookDatabase(database)) {
251+
bookDatabases.add(database);
252+
}
253+
}
254+
return bookDatabases;
255+
}
256+
257+
private boolean isBookDatabase(String databaseName) {
258+
return databaseName.matches("[a-z0-9]{32}"); // UID regex
259+
}
260+
193261
public @NonNull List<String> getAllBookUIDs(){
194262
List<String> bookUIDs = new ArrayList<>();
195263
try (Cursor cursor = mDb.query(true, mTableName, new String[]{BookEntry.COLUMN_UID},

app/src/test/java/org/gnucash/android/test/unit/db/BooksDbAdapterTest.java

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636

3737
import javax.xml.parsers.ParserConfigurationException;
3838

39+
import static junit.framework.Assert.fail;
3940
import static org.assertj.core.api.Assertions.assertThat;
4041

4142
/**
@@ -158,6 +159,42 @@ public void testGeneratedDisplayNames_shouldBeUnique(){
158159
assertThat(generatedName).isEqualTo("Book 4");
159160
}
160161

162+
@Test
163+
public void recoverFromNoActiveBookFound() {
164+
Book book1 = new Book(BaseModel.generateUID());
165+
book1.setActive(false);
166+
mBooksDbAdapter.addRecord(book1);
167+
168+
Book book2 = new Book(BaseModel.generateUID());
169+
book2.setActive(false);
170+
mBooksDbAdapter.addRecord(book2);
171+
172+
try {
173+
mBooksDbAdapter.getActiveBookUID();
174+
fail("There shouldn't be any active book.");
175+
} catch (BooksDbAdapter.NoActiveBookFoundException e) {
176+
mBooksDbAdapter.fixBooksDatabase();
177+
}
178+
179+
assertThat(mBooksDbAdapter.getActiveBookUID()).isEqualTo(book1.getUID());
180+
}
181+
182+
/**
183+
* Tests the recovery from an empty books database.
184+
*/
185+
@Test
186+
public void recoverFromEmptyDatabase() {
187+
createNewBookWithDefaultAccounts();
188+
mBooksDbAdapter.deleteAllRecords();
189+
assertThat(mBooksDbAdapter.getRecordsCount()).isZero();
190+
191+
mBooksDbAdapter.fixBooksDatabase();
192+
193+
// Should've recovered the one from setUp() plus the one created above
194+
assertThat(mBooksDbAdapter.getRecordsCount()).isEqualTo(2);
195+
mBooksDbAdapter.getActiveBookUID(); // should not throw exception
196+
}
197+
161198
/**
162199
* Creates a new database with default accounts
163200
* @return The book UID for the new database

0 commit comments

Comments
 (0)