The previous logic duplicated the action of applying an operation to the
TaskDb with a "manual" application to the Task's local TaskMap. This
now uses the updated TaskMap fetched from the DB, which will help to
incorporate any other concurrent DB updates.
When adding a new task, the current task is empty, so there is no
context in which to evaluate DOM references. #2683 will address this in
a more robust fashion.
It's possible to call getDOM without a contextual task. Previously,
this was done by referencing a "dummy" task which necessitated a way to
distinguish such dummy tasks. This switches to using a pointer and
treating the NULL value as meaning there is no context.
Note that this cannot use `std::optional<&Task>`, as optional does not
support reference types.
getDOM takes an &Task that may be a reference to a dummy, or may be a
real task. The is_empty method replaces `task.data.size() == 0` as a
way to distinguish the two.
This edge case would happen if a user issued a following command
$ task 1 mod depends:
or
$ task 1 mod tags:
which would not perform as expected for tasks with non-empty depends /
tags attributes.
The problem under the hood is the fact that current synchronization
between 'tags" attribute and its constituent decomposed `tag_X`
attributes is performed in a way where the set of tags obtained from
`tag_X` attributes is taken as the source of truth.
If the legacy 'tags:' attribute was set to empty, the fixTags() method
would then restore its previous value from the `tag_X` attributes,
effectively leading to a no-op.
The same happens with dependencies. The fix here is to detect removal of
depends and tags attributes, and instead of setting the legacy
attributes to empty values, we iteratively remove all tags/dependencies.
Closes#2655.
The commit count has been inacurrate for some time, undercounting
(perhaps due to aggreessive caching), but also overcounting at times
(due to merges).