package com.code44.finance.data.providers; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.database.SQLException; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteException; import android.net.Uri; import android.provider.BaseColumns; import android.text.TextUtils; import com.code44.finance.data.db.Tables; public final class ProviderUtils { private ProviderUtils() { } @SuppressWarnings("UnusedDeclaration") public static int doArrayReplaceInTransaction(SQLiteDatabase db, String tableName, ContentValues[] valuesArray) { int count = 0; try { db.beginTransaction(); count = doArrayReplace(db, tableName, valuesArray); db.setTransactionSuccessful(); } catch (SQLiteException e) { e.printStackTrace(); throw e; } finally { db.endTransaction(); } return count; } public static int doArrayReplace(SQLiteDatabase db, String tableName, ContentValues[] valuesArray) { int count = 0; for (final ContentValues values : valuesArray) { doUpdateOrInsert(db, tableName, values, false); count++; } return count; } public static long doUpdateOrInsert(SQLiteDatabase db, String tableName, ContentValues values, boolean returnNewId) { // Get id columns final String idColumn = BaseColumns._ID; final String serverIdColumn = tableName + "_" + Tables.SUFFIX_ID; // Get ids final Long id = values.getAsLong(idColumn); final String serverId = values.getAsString(serverIdColumn); long newId = id != null ? id : 0; // Find value to check for update final boolean tryUpdate; final String columnToCheck; String valueToCheck; if (newId > 0) { // We have local ID. Will try to update. tryUpdate = true; columnToCheck = idColumn; valueToCheck = String.valueOf(newId); } else if (!TextUtils.isEmpty(serverId)) { // Have server ID. Will try to update. tryUpdate = true; columnToCheck = serverIdColumn; valueToCheck = serverId; } else { // No IDs. Will not try to update. tryUpdate = false; columnToCheck = ""; valueToCheck = ""; } // Update or insert if (!tryUpdate || db.update(tableName, values, columnToCheck + "=?", new String[]{valueToCheck}) == 0) { newId = db.insert(tableName, null, values); if (newId <= 0) { throw new SQLException("Failed to insert values " + values.toString() + " into " + tableName); } } // Get local ID if necessary if (newId == 0 && returnNewId && !TextUtils.isEmpty(serverId)) { newId = getLocalId(db, tableName, serverId); } return newId; } public static long getLocalId(SQLiteDatabase db, String tableName, String serverId) { long localId = 0; Cursor c = null; try { c = db.query(tableName, new String[]{BaseColumns._ID}, tableName + "_" + Tables.SUFFIX_ID + "=?", new String[]{serverId}, null, null, null); if (c != null && c.moveToFirst()) { localId = c.getLong(0); } } finally { if (c != null && !c.isClosed()) { c.close(); } } return localId; } public static void notifyChangeIfNecessary(Context context, Uri uri) { notifyUris(context, uri); } public static void notifyUris(Context context, Uri... uris) { if (uris == null) { return; } for (Uri uri : uris) { boolean notifyUriChanged = uri.getBooleanQueryParameter(QueryParameterKey.NOTIFY_URI_CHANGED.getKeyName(), true); if (notifyUriChanged) { context.getContentResolver().notifyChange(uri, null); } } } public static Uri withQueryParameter(Uri uri, QueryParameterKey parameterKey, String value) { return uri.buildUpon().appendQueryParameter(parameterKey.getKeyName(), value).build(); } public static enum QueryParameterKey { /** * Possible values: {@code "true"} and {@code "false"}. */ NOTIFY_URI_CHANGED("notifyUriChanged"), /** * Possible values: {@code "delete"}, {@code "undo"} and {@code "commit"}. */ DELETE_MODE("deleteMode"); private final String keyName; private QueryParameterKey(String keyName) { this.keyName = keyName; } public String getKeyName() { return keyName; } } }