package com.rapidftr.repository; import android.content.ContentValues; import android.database.Cursor; import android.util.Log; import com.google.inject.Inject; import com.google.inject.name.Named; import com.rapidftr.RapidFtrApplication; import com.rapidftr.adapter.pagination.ViewAllChildrenPaginatedScrollListener; import com.rapidftr.database.Database; import com.rapidftr.database.DatabaseSession; import com.rapidftr.model.Child; import com.rapidftr.model.History; import com.rapidftr.model.User; import com.rapidftr.utils.RapidFtrDateTime; import lombok.Cleanup; import org.json.JSONException; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import static com.rapidftr.database.Database.BooleanColumn; import static com.rapidftr.database.Database.BooleanColumn.falseValue; import static com.rapidftr.database.Database.ChildTableColumn.*; public class ChildRepository implements Repository<Child> { protected final String userName; protected final DatabaseSession session; private PaginatedSearchQueryBuilder paginatedSearchQueryBuilder; private RapidFtrApplication applicationInstance; @Inject public ChildRepository(@Named("USER_NAME") String userName, DatabaseSession session, RapidFtrApplication applicationInstance) { this.userName = userName; this.session = session; this.applicationInstance = applicationInstance; } @Override public Child get(String id) throws JSONException { @Cleanup Cursor cursor = session.rawQuery("SELECT child_json, synced FROM children WHERE id = ?", new String[]{id}); if (cursor.moveToNext()) { return childFrom(cursor); } else { throw new NullPointerException(id); } } @Override public boolean exists(String childId) { @Cleanup Cursor cursor = session.rawQuery("SELECT child_json FROM children WHERE id = ?", new String[]{childId == null ? "" : childId}); return cursor.moveToNext() && cursor.getCount() > 0; } @Override public int size() { @Cleanup Cursor cursor = session.rawQuery("SELECT COUNT(1) FROM children WHERE child_owner = ?", new String[]{userName}); return cursor.moveToNext() ? cursor.getInt(0) : 0; } @Override public List<Child> getRecordsBetween(int fromPageNumber, int pageNumber) throws JSONException { String sql = String.format( "SELECT child_json, synced FROM children WHERE child_owner='%s' ORDER BY id LIMIT %d OFFSET %d", userName, pageNumber - fromPageNumber, fromPageNumber); Log.d("QUERY LIMIT", String.format(sql)); @Cleanup Cursor cursor = session.rawQuery(sql, null); return toChildren(cursor); } @Override public List<Child> allCreatedByCurrentUser() throws JSONException { return new ArrayList<Child>(); } @Override public List<Child> getRecordsForFirstPage() throws JSONException { String sql = String.format( "SELECT child_json, synced FROM children WHERE child_owner='%s' ORDER BY id LIMIT %d", userName, ViewAllChildrenPaginatedScrollListener.FIRST_PAGE); @Cleanup Cursor cursor = session.rawQuery(sql, null); return toChildren(cursor); } @Override public ArrayList<String> getRecordIdsByOwner() throws JSONException { ArrayList<String> ids = new ArrayList<String>(); @Cleanup Cursor cursor = session.rawQuery("SELECT _id FROM children WHERE child_owner = ? ", new String[]{userName}); while (cursor.moveToNext()) { ids.add(cursor.getString(0)); } return ids; } public void deleteChildrenByOwner() throws JSONException { session.execSQL("DELETE FROM children WHERE child_owner = '" + userName + "';"); } @Override public void createOrUpdate(Child child) throws JSONException { if (exists(child.getUniqueId())) { Child existingChild = get(child.getUniqueId()); child.addHistory(History.buildHistoryBetween(applicationInstance, existingChild, child)); } else { User currentUser = applicationInstance.getCurrentUser(); child.addHistory(History.buildCreationHistory(child, currentUser)); } child.setLastUpdatedAt(getTimeStamp()); createOrUpdateWithoutHistory(child); } @Override public void createOrUpdateWithoutHistory(Child child) throws JSONException { ContentValues values = new ContentValues(); values.put(Database.ChildTableColumn.owner.getColumnName(), child.getCreatedBy()); values.put(id.getColumnName(), child.getUniqueId()); values.put(content.getColumnName(), child.getJsonString()); values.put(synced.getColumnName(), child.isSynced()); values.put(created_at.getColumnName(), child.getCreatedAt()); populateInternalColumns(child, values); session.replaceOrThrow(Database.child.getTableName(), null, values); } private void populateInternalColumns(Child child, ContentValues values) { values.put(internal_id.getColumnName(), child.optString("_id")); values.put(internal_rev.getColumnName(), child.optString("_rev")); } @Override public List<Child> toBeSynced() throws JSONException { @Cleanup Cursor cursor = session.rawQuery("SELECT child_json, synced FROM children WHERE synced = ?", new String[]{falseValue.getColumnValue()}); return toChildren(cursor); } @Override public List<Child> currentUsersUnsyncedRecords() throws JSONException { @Cleanup Cursor cursor = session.rawQuery("SELECT child_json, synced FROM children WHERE synced = ? AND child_owner = ?", new String[]{falseValue.getColumnValue(), userName}); return toChildren(cursor); } @Override // TODO remove this method - we no longer want to work out what to updateWithoutHistory by comparing _revs public HashMap<String, String> getAllIdsAndRevs() throws JSONException { HashMap<String, String> idRevs = new HashMap<String, String>(); @Cleanup Cursor cursor = session.rawQuery("SELECT " + Database.ChildTableColumn.internal_id.getColumnName() + ", " + Database.ChildTableColumn.internal_rev.getColumnName() + " FROM " + Database.child.getTableName(), null); while (cursor.moveToNext()) { idRevs.put(cursor.getString(0), cursor.getString(1)); } return idRevs; } @Override public void close() { try { session.close(); } catch (IOException e) { throw new RuntimeException(e); } } protected List<Child> toChildren(Cursor cursor) throws JSONException { List<Child> children = new ArrayList<Child>(); while (cursor.moveToNext()) { children.add(childFrom(cursor)); } return children; } private Child childFrom(Cursor cursor) throws JSONException { int contentColumnIndex = cursor.getColumnIndex(content.getColumnName()); int syncedColumnIndex = cursor.getColumnIndex(synced.getColumnName()); return new Child(cursor.getString(contentColumnIndex), BooleanColumn.from(cursor.getString(syncedColumnIndex)).toBoolean()); } protected String getTimeStamp() { return RapidFtrDateTime.now().defaultFormat(); } public List<Child> getChildrenByIds(ArrayList<String> listOfIds) throws JSONException { ArrayList<Child> children = new ArrayList<Child>(); for (String childId : listOfIds) { children.add(get(childId)); } return children; } public List<Child> getAllWithInternalIds(List<String> internalIds) throws JSONException { List<Child> children = new ArrayList<Child>(); for (String internalId : internalIds) { @Cleanup Cursor cursor = session.rawQuery("SELECT child_json, synced FROM children WHERE _id = ?", new String[]{internalId}); if (cursor.moveToNext()) children.add(childFrom(cursor)); } return children; } public List<Child> getFirstPageOfChildrenMatchingString(String searchKey) throws JSONException { paginatedSearchQueryBuilder = new PaginatedSearchQueryBuilder( applicationInstance, searchKey); @Cleanup Cursor cursor = session.rawQuery(paginatedSearchQueryBuilder.queryForMatchingChildrenFirstPage(), null); return toChildren(cursor); } public List<Child> getChildrenMatchingStringBetween( String searchKey, int fromPageNumber, int toPageNumber) throws JSONException { paginatedSearchQueryBuilder = new PaginatedSearchQueryBuilder(applicationInstance, searchKey); Log.d("QUERY LIMIT", paginatedSearchQueryBuilder.queryForMatchingChildrenBetweenPages(fromPageNumber, toPageNumber)); @Cleanup Cursor cursor = session.rawQuery(paginatedSearchQueryBuilder.queryForMatchingChildrenBetweenPages( fromPageNumber, toPageNumber), null); return toChildren(cursor); } }