Concrete Commands
Overview
This page documents the first four concrete ICommand implementations for data mutation and meta operations. Each command has a reflect-cpp–serializable parameter struct and lives in src/Commands/. All commands are registered in the centralized createCommand() factory.
For the persistence command (SaveData), see SaveData Command.
Source files:
src/Commands/MoveByTimeRange.hpp/.cppsrc/Commands/CopyByTimeRange.hpp/.cppsrc/Commands/AddInterval.hpp/.cppsrc/Commands/ForEachKey.hpp/.cppsrc/Commands/Commands.test.cpp— Unit tests
All code lives in the commands namespace with no Qt dependency.
MoveByTimeRange
Moves entities within a [start_frame, end_frame] range from a source data object to a destination data object of the same type. The source object loses the moved entities.
Parameters
struct MoveByTimeRangeParams {
std::string source_key;
std::string destination_key;
int start_frame;
int end_frame;
};Supported Types
Requires the moveByEntityIds method, available on:
RaggedTimeSeries<T>(LineData, PointData, MaskData)DigitalEventSeries
DigitalIntervalSeries does not support move.
Undo
isUndoable() returns true. The command stores the set of moved EntityIds during execute() and moves them back from destination to source on undo().
Implementation Notes
The implementation uses std::visit with if constexpr and a requires clause to dispatch on the variant type. Because DataManager.hpp only forward-declares data types, the .cpp file must explicitly include the full headers for all supported types.
CopyByTimeRange
Copies entities within a [start_frame, end_frame] range from a source data object to a destination. The source remains unmodified.
Parameters
struct CopyByTimeRangeParams {
std::string source_key;
std::string destination_key;
int start_frame;
int end_frame;
};Supported Types
Requires the copyByEntityIds method, available on:
RaggedTimeSeries<T>(LineData, PointData, MaskData)DigitalEventSeriesDigitalIntervalSeries
Wider type support than MoveByTimeRange because DigitalIntervalSeries supports copy but not move.
Undo
Not undoable (default). Copy is non-destructive so undo is less critical.
AddInterval
Appends an interval to a DigitalIntervalSeries, optionally creating the series if it does not exist.
Parameters
struct AddIntervalParams {
std::string interval_key;
int start_frame;
int end_frame;
bool create_if_missing = true;
};When create_if_missing is true and the key does not exist in DataManager, the command creates an empty DigitalIntervalSeries with the default TimeKey("time").
Undo
Not undoable (default).
ForEachKey
A meta-command that iterates a list of string values, binds each to a template variable, and executes a sequence of sub-commands per item. This enables batch operations over multiple data keys using a single command descriptor.
Parameters
struct ForEachKeyParams {
std::vector<std::string> items;
std::string variable;
std::vector<CommandDescriptor> commands;
};Execution
For each item in items:
- Builds a substitution map:
{variable → item} - For each sub-command descriptor:
- Serializes the descriptor parameters to JSON
- Applies
substituteVariables()to resolve${variable}references - Deserializes back and creates the command via
createCommand() - Executes the command
- Stops on first error (if any sub-command fails)
Undo
isUndoable() returns true if any executed sub-command is undoable. Undo iterates the stored sub-commands in reverse order, calling undo() on each undoable command.
Example
{
"command_name": "ForEachKey",
"parameters": {
"items": ["w0", "w1", "w2"],
"variable": "whisker",
"commands": [
{
"command_name": "MoveByTimeRange",
"parameters": {
"source_key": "${whisker}_raw",
"destination_key": "${whisker}_labeled",
"start_frame": 100,
"end_frame": 200
}
}
]
}
}This expands to three MoveByTimeRange commands: one for w0_raw → w0_labeled, one for w1_raw → w1_labeled, and one for w2_raw → w2_labeled.
Tests
Tests live in Commands.test.cpp alongside the command sources.
| Test Group | Command | Sections |
|---|---|---|
| Factory | All four | Valid params → non-null, invalid → null |
| MoveByTimeRange execute | MoveByTimeRange |
Subset move, move all, move nothing, missing keys, type mismatch |
| MoveByTimeRange undo | MoveByTimeRange |
Undo restores source and destination |
| MoveByTimeRange DigitalEventSeries | MoveByTimeRange |
Move with DigitalEventSeries data |
| MoveByTimeRange serialization | MoveByTimeRange |
toJson() round-trip |
| CopyByTimeRange execute | CopyByTimeRange |
Subset copy, copy all, copy nothing |
| CopyByTimeRange DigitalIntervalSeries | CopyByTimeRange |
Copy with DigitalIntervalSeries data |
| CopyByTimeRange serialization | CopyByTimeRange |
toJson() round-trip |
| AddInterval execute | AddInterval |
Append, create_if_missing, error on missing, accumulate |
| AddInterval serialization | AddInterval |
toJson() round-trip |
| ForEachKey execute | ForEachKey |
Per-item execution, empty items, stop on error, unknown sub-command |
| ForEachKey undo | ForEachKey |
Undo reverses MoveByTimeRange sub-commands |
| ForEachKey serialization | ForEachKey |
toJson() round-trip |
See Also
- Command Architecture Design — Overall architecture and type definitions
- Core Types —
CommandResult,CommandContext,ICommand - getEntityIdsInRange — Query helpers used by Move/Copy commands
- Sequence Execution —
executeSequence()and variable substitution - Roadmap — Implementation progress