Skip to content

Commit

Permalink
Make sure non-recurring tasks get an INSTANCE_ORIGINAL_TIME of 0. Imp…
Browse files Browse the repository at this point in the history
…lements #577

This resulted in a minor SRP-ish refactoring to separate steps of instance value creation.
  • Loading branch information
dmfs committed Dec 13, 2017
1 parent a6c5e6a commit 1ef85c5
Show file tree
Hide file tree
Showing 24 changed files with 973 additions and 346 deletions.
2 changes: 2 additions & 0 deletions opentasks-provider/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,7 @@ dependencies {
androidTestImplementation 'com.android.support.test:rules:0.5'
testImplementation 'org.robolectric:robolectric:' + ROBOLECTRIC_VERSION
testImplementation 'junit:junit:4.12'
testImplementation 'org.mockito:mockito-core:2.10.0'
testImplementation 'org.dmfs:jems-testing:' + JEMS_VERSION
testImplementation 'org.hamcrest:hamcrest-all:1.3'
}
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ public void testInsertTaskWithStartAndDue()
new Assert<>(task, new TimeData(start, due)),
new AssertRelated<>(new InstanceTable(mAuthority), Instances.TASK_ID, task, new AllOf(
new EqArg(Instances.INSTANCE_START, start.getTimestamp()),
new EqArg(Instances.INSTANCE_ORIGINAL_TIME, start.getTimestamp()),
new EqArg(Instances.INSTANCE_ORIGINAL_TIME, 0),
new EqArg(Instances.INSTANCE_DUE, due.getTimestamp()),
new EqArg(Instances.INSTANCE_START_SORTING, start.shiftTimeZone(TimeZone.getDefault()).getInstance()),
new EqArg(Instances.INSTANCE_DUE_SORTING, due.shiftTimeZone(TimeZone.getDefault()).getInstance()),
Expand Down Expand Up @@ -269,7 +269,7 @@ public void testInsertTaskWithStartAndDueMovedForward()
new Assert<>(task, new TimeData(startNew, dueNew)),
new AssertRelated<>(new InstanceTable(mAuthority), Instances.TASK_ID, task, new AllOf(
new EqArg(Instances.INSTANCE_START, startNew.getTimestamp()),
new EqArg(Instances.INSTANCE_ORIGINAL_TIME, startNew.getTimestamp()),
new EqArg(Instances.INSTANCE_ORIGINAL_TIME, 0),
new EqArg(Instances.INSTANCE_DUE, dueNew.getTimestamp()),
new EqArg(Instances.INSTANCE_START_SORTING, startNew.shiftTimeZone(TimeZone.getDefault()).getInstance()),
new EqArg(Instances.INSTANCE_DUE_SORTING, dueNew.shiftTimeZone(TimeZone.getDefault()).getInstance()),
Expand Down Expand Up @@ -304,7 +304,7 @@ public void testInsertTaskWithStartAndDueMovedBackwards()
new Assert<>(task, new TimeData(startNew, dueNew)),
new AssertRelated<>(new InstanceTable(mAuthority), Instances.TASK_ID, task, new AllOf(
new EqArg(Instances.INSTANCE_START, startNew.getTimestamp()),
new EqArg(Instances.INSTANCE_ORIGINAL_TIME, startNew.getTimestamp()),
new EqArg(Instances.INSTANCE_ORIGINAL_TIME, 0),
new EqArg(Instances.INSTANCE_DUE, dueNew.getTimestamp()),
new EqArg(Instances.INSTANCE_START_SORTING, startNew.shiftTimeZone(TimeZone.getDefault()).getInstance()),
new EqArg(Instances.INSTANCE_DUE_SORTING, dueNew.shiftTimeZone(TimeZone.getDefault()).getInstance()),
Expand Down Expand Up @@ -335,7 +335,7 @@ public void testInsertTaskWithStartAndDueAddedAfterwards()
new Assert<>(task, new TimeData(start, due)),
new AssertRelated<>(new InstanceTable(mAuthority), Instances.TASK_ID, task, new AllOf(
new EqArg(Instances.INSTANCE_START, start.getTimestamp()),
new EqArg(Instances.INSTANCE_ORIGINAL_TIME, start.getTimestamp()),
new EqArg(Instances.INSTANCE_ORIGINAL_TIME, 0),
new EqArg(Instances.INSTANCE_DUE, due.getTimestamp()),
new EqArg(Instances.INSTANCE_START_SORTING, start.shiftTimeZone(TimeZone.getDefault()).getInstance()),
new EqArg(Instances.INSTANCE_DUE_SORTING, due.shiftTimeZone(TimeZone.getDefault()).getInstance()),
Expand Down Expand Up @@ -371,7 +371,7 @@ public void testInsertWithStartAndDuration()
new EqArg(Instances.INSTANCE_DURATION, durationMillis),
new EqArg(Instances.INSTANCE_START_SORTING, start.shiftTimeZone(TimeZone.getDefault()).getInstance()),
new EqArg(Instances.INSTANCE_DUE_SORTING, start.addDuration(duration).shiftTimeZone(TimeZone.getDefault()).getInstance()),
new EqArg(Instances.INSTANCE_ORIGINAL_TIME, start.getTimestamp()),
new EqArg(Instances.INSTANCE_ORIGINAL_TIME, 0),
new EqArg(Tasks.TZ, "UTC")
))
));
Expand Down Expand Up @@ -407,7 +407,7 @@ public void testInsertWithStartAndDurationChangeTimeZone()
new EqArg(Instances.INSTANCE_DURATION, durationMillis),
new EqArg(Instances.INSTANCE_START_SORTING, start.shiftTimeZone(TimeZone.getDefault()).getInstance()),
new EqArg(Instances.INSTANCE_DUE_SORTING, start.addDuration(duration).shiftTimeZone(TimeZone.getDefault()).getInstance()),
new EqArg(Instances.INSTANCE_ORIGINAL_TIME, start.getTimestamp()),
new EqArg(Instances.INSTANCE_ORIGINAL_TIME, 0),
new EqArg(Tasks.TZ, "America/New_York")
))
));
Expand Down Expand Up @@ -447,7 +447,7 @@ public void testUpdateDue() throws Exception
new EqArg(Instances.INSTANCE_DURATION, due2.getTimestamp() - start.getTimestamp()),
new EqArg(Instances.INSTANCE_START_SORTING, start.shiftTimeZone(TimeZone.getDefault()).getInstance()),
new EqArg(Instances.INSTANCE_DUE_SORTING, due2.shiftTimeZone(TimeZone.getDefault()).getInstance()),
new EqArg(Instances.INSTANCE_ORIGINAL_TIME, start.getTimestamp()),
new EqArg(Instances.INSTANCE_ORIGINAL_TIME, 0),
new EqArg(Tasks.TZ, "UTC")
))
));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;

import org.dmfs.jems.function.BiFunction;
import org.dmfs.jems.iterable.composite.Diff;
import org.dmfs.jems.iterable.decorators.Mapped;
import org.dmfs.jems.pair.Pair;
Expand All @@ -33,8 +32,7 @@
import org.dmfs.provider.tasks.utils.InstanceValuesIterable;
import org.dmfs.provider.tasks.utils.Limited;
import org.dmfs.provider.tasks.utils.Range;
import org.dmfs.provider.tasks.utils.SingleValueFunction;
import org.dmfs.provider.tasks.utils.WithTaskId;
import org.dmfs.provider.tasks.processors.tasks.instancedata.TaskRelated;
import org.dmfs.tasks.contract.TaskContract;

import java.util.Locale;
Expand Down Expand Up @@ -136,7 +134,7 @@ private void createInstances(SQLiteDatabase db, TaskAdapter taskAdapter, long id
// TODO: only limit future instances
for (Single<ContentValues> values : new Limited<>(INSTANCE_COUNT_LIMIT, new InstanceValuesIterable(taskAdapter)))
{
db.insert(TaskDatabaseHelper.Tables.INSTANCES, "", new WithTaskId(id, values).value());
db.insert(TaskDatabaseHelper.Tables.INSTANCES, "", new TaskRelated(id, values).value());
}
}

Expand Down Expand Up @@ -181,16 +179,12 @@ private void updateInstances(SQLiteDatabase db, TaskAdapter taskAdapter, long id
// TODO: once we actually support recurrence we should only count future instances

Iterable<Pair<Optional<ContentValues>, Optional<Integer>>> diff = new Diff<>(
new Mapped<>(new SingleValueFunction<ContentValues>(), new Limited<>(INSTANCE_COUNT_LIMIT, new InstanceValuesIterable(taskAdapter))),
new Mapped<>(Single::value, new Limited<>(INSTANCE_COUNT_LIMIT, new InstanceValuesIterable(taskAdapter))),
new Range(existingInstances.getCount()),
new BiFunction<ContentValues, Integer, Integer>()
(newInstanceValues, cursorRow) ->
{
@Override
public Integer value(ContentValues newInstanceValues, Integer cursorRow)
{
existingInstances.moveToPosition(cursorRow);
return (int) (existingInstances.getLong(startIdx) - newInstanceValues.getAsLong(TaskContract.Instances.INSTANCE_ORIGINAL_TIME));
}
existingInstances.moveToPosition(cursorRow);
return (int) (existingInstances.getLong(startIdx) - newInstanceValues.getAsLong(TaskContract.Instances.INSTANCE_ORIGINAL_TIME));
});

// sync the instances table with the new instances
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Copyright 2017 dmfs GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.dmfs.provider.tasks.processors.tasks.instancedata;

import android.content.ContentValues;

import org.dmfs.jems.single.Single;
import org.dmfs.jems.single.decorators.DelegatingSingle;
import org.dmfs.optional.Optional;
import org.dmfs.provider.tasks.utils.Zipped;
import org.dmfs.rfc5545.DateTime;

import java.util.TimeZone;


/**
* A {@link Single} of date and time {@link ContentValues} of an instance.
*
* @author Marten Gajda
*/
public final class Dated extends DelegatingSingle<ContentValues>
{

public Dated(Optional<DateTime> dateTime, String timeStampColumn, String sortingColumn, Single<ContentValues> delegate)
{
super(new Zipped<>(
dateTime,
delegate,
(dateTime1, values) ->
{
// add timestamp and sorting
values.put(timeStampColumn, dateTime1.getTimestamp());
values.put(sortingColumn, dateTime1.isAllDay() ? dateTime1.getInstance() : dateTime1.shiftTimeZone(TimeZone.getDefault()).getInstance());
return values;
}));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,26 @@
* limitations under the License.
*/

package org.dmfs.provider.tasks.utils;
package org.dmfs.provider.tasks.processors.tasks.instancedata;

import android.content.ContentValues;

import org.dmfs.jems.function.Function;
import org.dmfs.jems.single.Single;
import org.dmfs.jems.single.decorators.DelegatingSingle;
import org.dmfs.optional.Optional;
import org.dmfs.rfc5545.DateTime;
import org.dmfs.tasks.contract.TaskContract;


/**
* A {@link Function} returning the value of a {@link Single}.
* A decorator to a {@link Single} of {@link ContentValues} adding due data.
*
* @author Marten Gajda
*/
public final class SingleValueFunction<T> implements Function<Single<T>, T>
public final class DueDated extends DelegatingSingle<ContentValues>
{
@Override
public T value(Single<T> single)
public DueDated(Optional<DateTime> due, Single<ContentValues> delegate)
{
return single.value();
super(new Dated(due, TaskContract.Instances.INSTANCE_DUE, TaskContract.Instances.INSTANCE_DUE_SORTING, delegate));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* Copyright 2017 dmfs GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.dmfs.provider.tasks.processors.tasks.instancedata;

import android.content.ContentValues;

import org.dmfs.jems.single.Single;
import org.dmfs.optional.NullSafe;
import org.dmfs.optional.composite.Zipped;
import org.dmfs.tasks.contract.TaskContract;


/**
* A decorator for {@link Single}s of Instance {@link ContentValues} which populates the {@link TaskContract.Instances#INSTANCE_DURATION} field based on the
* already populated {@link TaskContract.Instances#INSTANCE_START} and {@link TaskContract.Instances#INSTANCE_DUE} fields.
*
* @author Marten Gajda
*/
public final class Enduring implements Single<ContentValues>
{
private final Single<ContentValues> mDelegate;


public Enduring(Single<ContentValues> delegate)
{
mDelegate = delegate;
}


@Override
public ContentValues value()
{
ContentValues values = mDelegate.value();
// just store the difference between due and start, if both are present, otherwise store null
values.put(TaskContract.Instances.INSTANCE_DURATION,
new Zipped<>(
new NullSafe<>(values.getAsLong(TaskContract.Instances.INSTANCE_START)),
new NullSafe<>(values.getAsLong(TaskContract.Instances.INSTANCE_DUE)),
(start, due) -> due - start)
.value(null));
return values;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* Copyright 2017 dmfs GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.dmfs.provider.tasks.processors.tasks.instancedata;

import android.content.ContentValues;

import org.dmfs.iterables.elementary.Seq;
import org.dmfs.jems.optional.decorators.Mapped;
import org.dmfs.jems.single.Single;
import org.dmfs.optional.NullSafe;
import org.dmfs.optional.Optional;
import org.dmfs.optional.adapters.FirstPresent;
import org.dmfs.rfc5545.DateTime;
import org.dmfs.tasks.contract.TaskContract;


/**
* A decorator for {@link Single}s of Instance {@link ContentValues} which populates the {@link TaskContract.Instances#INSTANCE_ORIGINAL_TIME} field based on
* the given {@link Optional} original start and the already populated {@link TaskContract.Instances#INSTANCE_START} and {@link
* TaskContract.Instances#INSTANCE_DUE} fields.
*
* @author Marten Gajda
*/
public final class Overridden implements Single<ContentValues>
{
private final Optional<DateTime> mOriginalTime;
private final Single<ContentValues> mDelegate;


public Overridden(Optional<DateTime> originalTime, Single<ContentValues> delegate)
{
mOriginalTime = originalTime;
mDelegate = delegate;
}


@Override
public ContentValues value()
{
ContentValues values = mDelegate.value();
values.put(TaskContract.Instances.INSTANCE_ORIGINAL_TIME, new FirstPresent<>(new Seq<>(
new Mapped<>(DateTime::getTimestamp, mOriginalTime),
new NullSafe<>(values.getAsLong(TaskContract.Instances.INSTANCE_START)),
new NullSafe<>(values.getAsLong(TaskContract.Instances.INSTANCE_DUE))))
.value(null));
return values;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Copyright 2017 dmfs GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.dmfs.provider.tasks.processors.tasks.instancedata;

import android.content.ContentValues;

import org.dmfs.jems.single.Single;
import org.dmfs.jems.single.decorators.DelegatingSingle;
import org.dmfs.optional.Optional;
import org.dmfs.rfc5545.DateTime;
import org.dmfs.tasks.contract.TaskContract;


/**
* A decorator to a {@link Single} of {@link ContentValues} adding start data.
*
* @author Marten Gajda
*/
public final class StartDated extends DelegatingSingle<ContentValues>
{
public StartDated(Optional<DateTime> start, Single<ContentValues> delegate)
{
super(new Dated(start, TaskContract.Instances.INSTANCE_START, TaskContract.Instances.INSTANCE_START_SORTING, delegate));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* limitations under the License.
*/

package org.dmfs.provider.tasks.utils;
package org.dmfs.provider.tasks.processors.tasks.instancedata;

import android.content.ContentValues;

Expand All @@ -27,13 +27,13 @@
*
* @author Marten Gajda
*/
public final class WithTaskId implements Single<ContentValues>
public final class TaskRelated implements Single<ContentValues>
{
private final long mTaskId;
private final Single<ContentValues> mDelegate;


public WithTaskId(long taskId, Single<ContentValues> delegate)
public TaskRelated(long taskId, Single<ContentValues> delegate)
{
mTaskId = taskId;
mDelegate = delegate;
Expand Down
Loading

0 comments on commit 1ef85c5

Please sign in to comment.