Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DB: migrate to unique IDs for groups #1333

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
162 changes: 127 additions & 35 deletions app/src/main/java/protect/card_locker/DBHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,12 @@
public class DBHelper extends SQLiteOpenHelper {
public static final String DATABASE_NAME = "Catima.db";
public static final int ORIGINAL_DATABASE_VERSION = 1;
public static final int DATABASE_VERSION = 16;
public static final int DATABASE_VERSION = 17;

public static class LoyaltyCardDbGroups {
public static final String TABLE = "groups";
public static final String ID = "_id";
public static final String NAME = "name";
public static final String ORDER = "orderId";
}

Expand Down Expand Up @@ -87,7 +88,8 @@ public DBHelper(Context context) {
public void onCreate(SQLiteDatabase db) {
// create table for card groups
db.execSQL("CREATE TABLE " + LoyaltyCardDbGroups.TABLE + "(" +
LoyaltyCardDbGroups.ID + " TEXT primary key not null," +
LoyaltyCardDbGroups.ID + " INTEGER primary key autoincrement," +
LoyaltyCardDbGroups.NAME + " TEXT unique not null," +
LoyaltyCardDbGroups.ORDER + " INTEGER DEFAULT '0')");

// create table for cards
Expand All @@ -112,7 +114,7 @@ public void onCreate(SQLiteDatabase db) {
// create associative table for cards in groups
db.execSQL("CREATE TABLE " + LoyaltyCardDbIdsGroups.TABLE + "(" +
LoyaltyCardDbIdsGroups.cardID + " INTEGER," +
LoyaltyCardDbIdsGroups.groupID + " TEXT," +
LoyaltyCardDbIdsGroups.groupID + " INTEGER," +
"primary key (" + LoyaltyCardDbIdsGroups.cardID + "," + LoyaltyCardDbIdsGroups.groupID + "))");

// create FTS search table
Expand Down Expand Up @@ -321,6 +323,84 @@ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("ALTER TABLE " + LoyaltyCardDbIds.TABLE
+ " ADD COLUMN " + LoyaltyCardDbIds.VALID_FROM + " INTEGER");
}

if (oldVersion < 17 && newVersion >= 17) {
// SQLite doesn't support modify column
// So we need to create temp columns
// https://www.sqlite.org/faq.html#q11
db.beginTransaction();

db.execSQL("CREATE TEMPORARY TABLE tmpDbGroups (" +
LoyaltyCardDbGroups.ID + " INTEGER primary key autoincrement," +
LoyaltyCardDbGroups.NAME + " TEXT not null," +
LoyaltyCardDbGroups.ORDER + " INTEGER DEFAULT '0' )");

db.execSQL("INSERT INTO tmpDbGroups (" +
LoyaltyCardDbGroups.NAME + ", " +
LoyaltyCardDbGroups.ORDER + ")" +
" SELECT " +
LoyaltyCardDbGroups.ID + ", " +
LoyaltyCardDbGroups.ORDER +
" FROM " + LoyaltyCardDbGroups.TABLE);

db.execSQL("DROP TABLE " + LoyaltyCardDbGroups.TABLE);

db.execSQL("CREATE TEMPORARY TABLE tmpDbIdsGroups (" +
LoyaltyCardDbIdsGroups.cardID + " INTEGER," +
LoyaltyCardDbIdsGroups.groupID + " TEXT," +
" primary key (" +
LoyaltyCardDbIdsGroups.cardID + ", " +
LoyaltyCardDbIdsGroups.groupID + "))");

db.execSQL("INSERT INTO tmpDbIdsGroups (" +
LoyaltyCardDbIdsGroups.cardID + ", " +
LoyaltyCardDbIdsGroups.groupID + ")" +
" SELECT " +
LoyaltyCardDbIdsGroups.cardID + ", " +
LoyaltyCardDbIdsGroups.groupID +
" FROM " + LoyaltyCardDbIdsGroups.TABLE);

db.execSQL("DROP TABLE " + LoyaltyCardDbIdsGroups.TABLE);

db.execSQL("CREATE TABLE " + LoyaltyCardDbGroups.TABLE + "(" +
LoyaltyCardDbGroups.ID + " INTEGER primary key autoincrement," +
LoyaltyCardDbGroups.NAME + " TEXT not null," +
LoyaltyCardDbGroups.ORDER + " INTEGER DEFAULT '0' )");

db.execSQL("INSERT INTO " + LoyaltyCardDbGroups.TABLE + "(" +
LoyaltyCardDbGroups.ID + ", " +
LoyaltyCardDbGroups.NAME + ", " +
LoyaltyCardDbGroups.ORDER + ")" +
" SELECT " +
LoyaltyCardDbGroups.ID + ", " +
LoyaltyCardDbGroups.NAME + ", " +
LoyaltyCardDbGroups.ORDER +
" FROM tmpDbGroups");

db.execSQL("CREATE TABLE " + LoyaltyCardDbIdsGroups.TABLE + "(" +
LoyaltyCardDbIdsGroups.cardID + " INTEGER," +
LoyaltyCardDbIdsGroups.groupID + " INTEGER," +
" primary key (" +
LoyaltyCardDbIdsGroups.cardID + ", " +
LoyaltyCardDbIdsGroups.groupID + "))");

db.execSQL("INSERT INTO " + LoyaltyCardDbIdsGroups.TABLE + "(" +
LoyaltyCardDbIdsGroups.cardID + ", " +
LoyaltyCardDbIdsGroups.groupID + ")" +
" SELECT " +
"idsGroups." + LoyaltyCardDbIdsGroups.cardID + ", " +
"groups." + LoyaltyCardDbGroups.ID +
" FROM tmpDbIdsGroups AS idsGroups JOIN " +
LoyaltyCardDbGroups.TABLE + " AS groups ON " +
"idsGroups." + LoyaltyCardDbIdsGroups.groupID + "=" +
"groups." + LoyaltyCardDbGroups.NAME);

db.execSQL("DROP TABLE tmpDbGroups");
db.execSQL("DROP TABLE tmpDbIdsGroups");

db.setTransactionSuccessful();
db.endTransaction();
}
}

private static ContentValues generateFTSContentValues(final int id, final String store, final String note) {
Expand Down Expand Up @@ -534,7 +614,7 @@ public static List<Group> getLoyaltyCardGroups(SQLiteDatabase database, final in
Cursor data = database.rawQuery("select * from " + LoyaltyCardDbGroups.TABLE + " g " +
" LEFT JOIN " + LoyaltyCardDbIdsGroups.TABLE + " ig ON ig." + LoyaltyCardDbIdsGroups.groupID + " = g." + LoyaltyCardDbGroups.ID +
" where " + LoyaltyCardDbIdsGroups.cardID + "=?" +
" ORDER BY " + LoyaltyCardDbIdsGroups.groupID, withArgs(id));
" ORDER BY " + LoyaltyCardDbGroups.NAME, withArgs(id));

List<Group> groups = new ArrayList<>();

Expand Down Expand Up @@ -602,14 +682,14 @@ public static int getArchivedCardsCount(SQLiteDatabase database) {
whereAttrs(LoyaltyCardDbIds.ARCHIVE_STATUS), withArgs(1));
}

public static int getArchivedCardsCount(SQLiteDatabase database, final String groupName) {
public static int getArchivedCardsCount(SQLiteDatabase database, final int groupId) {
Cursor data = database.rawQuery(
"select * from " + LoyaltyCardDbIds.TABLE + " c " +
" LEFT JOIN " + LoyaltyCardDbIdsGroups.TABLE + " cg " +
" ON c." + LoyaltyCardDbIds.ID + " = cg." + LoyaltyCardDbIdsGroups.cardID +
" where " + LoyaltyCardDbIds.ARCHIVE_STATUS + " = 1" +
" AND " + LoyaltyCardDbIdsGroups.groupID + "= ?",
withArgs(groupName)
withArgs(groupId)
);

int count = data.getCount();
Expand Down Expand Up @@ -717,7 +797,7 @@ public static int getLoyaltyCardCount(SQLiteDatabase database) {
*/
public static Cursor getGroupCursor(SQLiteDatabase database) {
return database.rawQuery("select * from " + LoyaltyCardDbGroups.TABLE +
" ORDER BY " + LoyaltyCardDbGroups.ORDER + " ASC," + LoyaltyCardDbGroups.ID + " COLLATE NOCASE ASC", null, null);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Altonss why did you remove COLLATE NOCASE?

" ORDER BY " + LoyaltyCardDbGroups.ORDER + " ASC," + LoyaltyCardDbGroups.NAME + " ASC", null, null);
}

public static List<Group> getGroups(SQLiteDatabase database) {
Expand Down Expand Up @@ -747,16 +827,29 @@ public static void reorderGroups(SQLiteDatabase database, final List<Group> grou
contentValues.put(LoyaltyCardDbGroups.ORDER, order);

database.update(LoyaltyCardDbGroups.TABLE, contentValues,
whereAttrs(LoyaltyCardDbGroups.ID),
withArgs(group._id));
whereAttrs(LoyaltyCardDbGroups.ID), withArgs(group._id));

order++;
}
}

public static Group getGroup(SQLiteDatabase database, final String groupName) {
public static Group getGroup(SQLiteDatabase database, final int groupId) {
Cursor data = database.query(LoyaltyCardDbGroups.TABLE, null,
whereAttrs(LoyaltyCardDbGroups.ID), withArgs(groupName), null, null, null);
whereAttrs(LoyaltyCardDbGroups.ID), withArgs(groupId), null, null, null);

Group group = null;
if (data.getCount() == 1) {
data.moveToFirst();
group = Group.toGroup(data);
}
data.close();

return group;
}

public static Group getGroupByName(SQLiteDatabase database, String groupName) {
Cursor data = database.query(LoyaltyCardDbGroups.TABLE, null,
whereAttrs(LoyaltyCardDbGroups.NAME), withArgs(groupName), null, null, null);

Group group = null;
if (data.getCount() == 1) {
Expand All @@ -772,9 +865,9 @@ public static int getGroupCount(SQLiteDatabase database) {
return (int) DatabaseUtils.queryNumEntries(database, LoyaltyCardDbGroups.TABLE);
}

public static List<Integer> getGroupCardIds(SQLiteDatabase database, final String groupName) {
public static List<Integer> getGroupCardIds(SQLiteDatabase database, final int groupId) {
Cursor data = database.query(LoyaltyCardDbIdsGroups.TABLE, withArgs(LoyaltyCardDbIdsGroups.cardID),
whereAttrs(LoyaltyCardDbIdsGroups.groupID), withArgs(groupName), null, null, null);
whereAttrs(LoyaltyCardDbIdsGroups.groupID), withArgs(groupId), null, null, null);
List<Integer> cardIds = new ArrayList<>();

if (!data.moveToFirst()) {
Expand All @@ -793,36 +886,37 @@ public static List<Integer> getGroupCardIds(SQLiteDatabase database, final Strin
}

public static long insertGroup(SQLiteDatabase database, final String name) {
if (name.isEmpty()) return -1;
if (name.isEmpty() || getGroupByName(database, name) != null) return -1;

ContentValues contentValues = new ContentValues();
contentValues.put(LoyaltyCardDbGroups.ID, name);
contentValues.put(LoyaltyCardDbGroups.NAME, name);
contentValues.put(LoyaltyCardDbGroups.ORDER, getGroupCount(database));
return database.insert(LoyaltyCardDbGroups.TABLE, null, contentValues);
}

public static boolean updateGroup(SQLiteDatabase database, final String groupName, final String newName) {
if (newName.isEmpty()) return false;
public static long insertGroup(SQLiteDatabase database, final int groupId, final String name) {
if (name.isEmpty() || getGroup(database, groupId) != null || getGroupByName(database, name) != null) return -1;

ContentValues contentValues = new ContentValues();
contentValues.put(LoyaltyCardDbGroups.ID, groupId);
contentValues.put(LoyaltyCardDbGroups.NAME, name);
contentValues.put(LoyaltyCardDbGroups.ORDER, getGroupCount(database));
return database.insert(LoyaltyCardDbGroups.TABLE, null, contentValues);
}

public static boolean updateGroup(SQLiteDatabase database, final int groupId, final String newName) {
if (newName.isEmpty() || getGroupByName(database, newName) != null) return false;

boolean success = false;

ContentValues groupContentValues = new ContentValues();
groupContentValues.put(LoyaltyCardDbGroups.ID, newName);

ContentValues lookupContentValues = new ContentValues();
lookupContentValues.put(LoyaltyCardDbIdsGroups.groupID, newName);
groupContentValues.put(LoyaltyCardDbGroups.NAME, newName);

database.beginTransaction();
try {
// Update group name
int groupsChanged = database.update(LoyaltyCardDbGroups.TABLE, groupContentValues,
whereAttrs(LoyaltyCardDbGroups.ID),
withArgs(groupName));

// Also update lookup tables
database.update(LoyaltyCardDbIdsGroups.TABLE, lookupContentValues,
whereAttrs(LoyaltyCardDbIdsGroups.groupID),
withArgs(groupName));
whereAttrs(LoyaltyCardDbGroups.ID), withArgs(groupId));

if (groupsChanged == 1) {
database.setTransactionSuccessful();
Expand All @@ -836,20 +930,18 @@ public static boolean updateGroup(SQLiteDatabase database, final String groupNam
return success;
}

public static boolean deleteGroup(SQLiteDatabase database, final String groupName) {
public static boolean deleteGroup(SQLiteDatabase database, final int groupId) {
boolean success = false;

database.beginTransaction();
try {
// Delete group
int groupsDeleted = database.delete(LoyaltyCardDbGroups.TABLE,
whereAttrs(LoyaltyCardDbGroups.ID),
withArgs(groupName));
whereAttrs(LoyaltyCardDbGroups.ID), withArgs(groupId));

// And delete lookup table entries associated with this group
database.delete(LoyaltyCardDbIdsGroups.TABLE,
whereAttrs(LoyaltyCardDbIdsGroups.groupID),
withArgs(groupName));
whereAttrs(LoyaltyCardDbIdsGroups.groupID), withArgs(groupId));

if (groupsDeleted == 1) {
database.setTransactionSuccessful();
Expand All @@ -865,9 +957,9 @@ public static boolean deleteGroup(SQLiteDatabase database, final String groupNam
return success;
}

public static int getGroupCardCount(SQLiteDatabase database, final String groupName) {
public static int getGroupCardCount(SQLiteDatabase database, final int groupId) {
return (int) DatabaseUtils.queryNumEntries(database, LoyaltyCardDbIdsGroups.TABLE,
whereAttrs(LoyaltyCardDbIdsGroups.groupID), withArgs(groupName));
whereAttrs(LoyaltyCardDbIdsGroups.groupID), withArgs(groupId));
}

static private String whereAttrs(String... attrs) {
Expand Down
29 changes: 7 additions & 22 deletions app/src/main/java/protect/card_locker/Group.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,36 +5,21 @@
import androidx.annotation.Nullable;

public class Group {
public final String _id;
public final int _id;
public final String name;
public final int order;

public Group(final String _id, final int order) {
public Group(final int _id, final String name, final int order) {
this._id = _id;
this.name = name;
this.order = order;
}

public static Group toGroup(Cursor cursor) {
String _id = cursor.getString(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbGroups.ID));
int _id = cursor.getInt(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbGroups.ID));
String name = cursor.getString(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbGroups.NAME));
int order = cursor.getInt(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbGroups.ORDER));

return new Group(_id, order);
}

@Override
public boolean equals(@Nullable Object obj) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we sure we lo longer need .equals() and .hashCode()? I think the default implementation is platform-dependent and would usually not consider objects equal if their fields are, only if they are the same object in memory. But I'm not familiar enough with the codebase to be sure that matters.

if (obj == null) {
return false;
}
if (!(obj instanceof Group)) {
return false;
}
Group anotherGroup = (Group) obj;
return _id.equals(anotherGroup._id) && order == anotherGroup.order;
}

@Override
public int hashCode() {
String combined = _id + "_" + order;
return combined.hashCode();
return new Group(_id, name, order);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public GroupCursorAdapter.GroupListItemViewHolder onCreateViewHolder(@NonNull Vi
public void onBindViewHolder(GroupListItemViewHolder inputHolder, Cursor inputCursor) {
Group group = Group.toGroup(inputCursor);

inputHolder.mName.setText(group._id);
inputHolder.mName.setText(group.name);

int groupCardCount = DBHelper.getGroupCardCount(mDatabase, group._id);
int archivedCardCount = DBHelper.getArchivedCardsCount(mDatabase, group._id);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity implements
String cardId;
String barcodeId;
String barcodeType;
String addGroup;
Integer addGroup;

Uri importLoyaltyCardUri = null;

Expand Down Expand Up @@ -246,7 +246,7 @@ private void extractIntentFields(Intent intent) {
cardId = b != null ? b.getString(BUNDLE_CARDID) : null;
barcodeId = b != null ? b.getString(BUNDLE_BARCODEID) : null;
barcodeType = b != null ? b.getString(BUNDLE_BARCODETYPE) : null;
addGroup = b != null ? b.getString(BUNDLE_ADDGROUP) : null;
addGroup = b != null ? b.getInt(BUNDLE_ADDGROUP) : null;

importLoyaltyCardUri = intent.getData();

Expand Down Expand Up @@ -816,15 +816,15 @@ public void onResume() {
LayoutChipChoiceBinding chipChoiceBinding = LayoutChipChoiceBinding
.inflate(LayoutInflater.from(groupsChips.getContext()), groupsChips, false);
Chip chip = chipChoiceBinding.getRoot();
chip.setText(group._id);
chip.setText(group.name);
chip.setTag(group);

if (group._id.equals(addGroup)) {
if (group._id == addGroup) {
chip.setChecked(true);
} else {
chip.setChecked(false);
for (Group loyaltyCardGroup : loyaltyCardGroups) {
if (loyaltyCardGroup._id.equals(group._id)) {
if (loyaltyCardGroup._id == group._id) {
chip.setChecked(true);
break;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,7 @@ private void showInfoDialog() {
if (loyaltyCardGroups.size() > 0) {
List<String> groupNames = new ArrayList<>();
for (Group group : loyaltyCardGroups) {
groupNames.add(group._id);
groupNames.add(group.name);
}

padSpannableString(infoText);
Expand Down
Loading