diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/DBHelper.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/DBHelper.java index 490ff380..f8f51ee6 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/DBHelper.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/DBHelper.java @@ -21,6 +21,7 @@ import java.util.Objects; import de.greenrobot.dao.Property; import de.greenrobot.dao.query.Query; import de.greenrobot.dao.query.QueryBuilder; +import de.greenrobot.dao.query.WhereCondition; import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.devices.AbstractSampleProvider; import nodomain.freeyourgadget.gadgetbridge.devices.DeviceCoordinator; @@ -445,12 +446,26 @@ public class DBHelper { Property tsToProperty = ActivityDescriptionDao.Properties.TimestampTo; Property userIdProperty = ActivityDescriptionDao.Properties.UserId; QueryBuilder qb = session.getActivityDescriptionDao().queryBuilder(); - qb.where(userIdProperty.eq(user.getId()), tsFromProperty.ge(tsFrom)) - .where(tsToProperty.le(tsTo)); + qb.where(userIdProperty.eq(user.getId()), isAtLeastPartiallyInRange(qb, tsFromProperty, tsToProperty, tsFrom, tsTo)); List descriptions = qb.build().list(); return descriptions; } + /** + * Returns a condition that matches when the range of the entity (tsFromProperty..tsToProperty) + * is completely or partially inside the range tsFrom..tsTo. + * @param qb the query builder to use + * @param tsFromProperty the property indicating the start of the entity's range + * @param tsToProperty the property indicating the end of the entity's range + * @param tsFrom the timestamp indicating the start of the range to match + * @param tsTo the timestamp indicating the end of the range to match + * @param the query builder's type parameter + * @return the range WhereCondition + */ + private static WhereCondition isAtLeastPartiallyInRange(QueryBuilder qb, Property tsFromProperty, Property tsToProperty, int tsFrom, int tsTo) { + return qb.and(tsFromProperty.lt(tsTo), tsToProperty.gt(tsFrom)); + } + @NonNull public static ActivityDescription createActivityDescription(@NonNull User user, int tsFrom, int tsTo, @NonNull DaoSession session) { ActivityDescription desc = new ActivityDescription(); diff --git a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/database/EntitiesTest.java b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/database/EntitiesTest.java index 9a1918e0..53ea77d1 100644 --- a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/database/EntitiesTest.java +++ b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/database/EntitiesTest.java @@ -131,14 +131,14 @@ public class EntitiesTest { ActivityDescriptionDao descDao = daoSession.getActivityDescriptionDao(); assertEquals(0, descDao.count()); - List list = DBHelper.findActivityDecriptions(user, 0, 10, daoSession); + List list = DBHelper.findActivityDecriptions(user, 10, 100, daoSession); assertTrue(list.isEmpty()); - ActivityDescription desc = DBHelper.createActivityDescription(user, 0, 10, daoSession); + ActivityDescription desc = DBHelper.createActivityDescription(user, 10, 100, daoSession); assertNotNull(desc); assertEquals(user, desc.getUser()); - assertEquals(0, desc.getTimestampFrom()); - assertEquals(10, desc.getTimestampTo()); + assertEquals(10, desc.getTimestampFrom()); + assertEquals(100, desc.getTimestampTo()); List tagList = desc.getTagList(); assertEquals(0, tagList.size()); @@ -148,12 +148,60 @@ public class EntitiesTest { t1.setDescription("Table tennis training for Olympia"); tagList.add(t1); - list = DBHelper.findActivityDecriptions(user, 0, 10, daoSession); + list = DBHelper.findActivityDecriptions(user, 10, 100, daoSession); assertEquals(1, list.size()); ActivityDescription desc1 = list.get(0); assertEquals(desc, desc1); assertEquals(1, desc1.getTagList().size()); + // check for partial range overlaps + list = DBHelper.findActivityDecriptions(user, 20, 80, daoSession); + assertEquals(1, list.size()); + + list = DBHelper.findActivityDecriptions(user, 5, 120, daoSession); + assertEquals(1, list.size()); + + list = DBHelper.findActivityDecriptions(user, 20, 120, daoSession); + assertEquals(1, list.size()); + + list = DBHelper.findActivityDecriptions(user, 5, 80, daoSession); + assertEquals(1, list.size()); + + // Now with a second, adjacent ActivityDescription + ActivityDescription desc2 = DBHelper.createActivityDescription(user, 101, 200, daoSession); + + list = DBHelper.findActivityDecriptions(user, 10, 100, daoSession); + assertEquals(1, list.size()); + + list = DBHelper.findActivityDecriptions(user, 20, 80, daoSession); + assertEquals(1, list.size()); + + list = DBHelper.findActivityDecriptions(user, 5, 120, daoSession); + assertEquals(2, list.size()); + + list = DBHelper.findActivityDecriptions(user, 20, 120, daoSession); + assertEquals(2, list.size()); + + list = DBHelper.findActivityDecriptions(user, 5, 80, daoSession); + assertEquals(1, list.size()); + + // Now with a third, partially overlapping ActivityDescription + ActivityDescription desc3 = DBHelper.createActivityDescription(user, 5, 15, daoSession); + + list = DBHelper.findActivityDecriptions(user, 10, 100, daoSession); + assertEquals(2, list.size()); + + list = DBHelper.findActivityDecriptions(user, 20, 80, daoSession); + assertEquals(1, list.size()); + + list = DBHelper.findActivityDecriptions(user, 5, 120, daoSession); + assertEquals(3, list.size()); + + list = DBHelper.findActivityDecriptions(user, 20, 120, daoSession); + assertEquals(2, list.size()); + + list = DBHelper.findActivityDecriptions(user, 5, 80, daoSession); + assertEquals(2, list.size()); } }