Skip to content

Commit

Permalink
feat: update Replica methods to return list of Operations
Browse files Browse the repository at this point in the history
  • Loading branch information
illya-laifu committed Sep 3, 2024
1 parent ad055dc commit 29fba96
Show file tree
Hide file tree
Showing 6 changed files with 82 additions and 90 deletions.
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,5 @@ This submodule contains bindings to the Taskchampion
# TODO

- There is no good way to describe functions that accept interface (e.g. `Replica::new` accepts any of the storage implementations, but Python bindings lack such mechanisms), currently, `Replica::new` just constructs the SqliteStorage from the params passed into the constructor.
- Currently Task class is just a reflection of the rust's `Task` struct, but constructing the standalone `TaskMut` is impossible, as Pyo3 bindings do not allow lifetimes (python has no alternatives to them). Would be nice to expand the `Task` class to include the methods from `TaskMut` and convert into the mutable state and back when they are called.
- It is possible to convert `WorkingSet` into a python iterator (you can iterate over it via `for item in <blah>:` or `next(<blah>)`), but that needs a way to store the current state.

- Possible integration with Github Workflows for deployment.
7 changes: 2 additions & 5 deletions src/replica.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,16 +38,13 @@ impl Replica {
/// Create a new task
/// The task must not already exist.
pub fn create_task(&mut self, uuid: String) -> anyhow::Result<(Task, Operation)> {
pub fn create_task(&mut self, uuid: String) -> anyhow::Result<(Task, Vec<Operation>)> {
let mut ops = TCOperations::new();
let task = self
.0
.create_task(Uuid::parse_str(&uuid)?, &mut ops)
.map(|t| Task(t))?;
Ok((
task,
Operation(ops.get(0).expect("Missing Operation").clone()),
))
Ok((task, ops.iter().map(|op| Operation(op.clone())).collect()))
}

/// Get a list of all tasks in the replica.
Expand Down
83 changes: 43 additions & 40 deletions src/task/task.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,24 +184,24 @@ impl Task {
Ok(ops.iter().map(|op| Operation(op.clone())).collect())
}

pub fn set_description(&mut self, description: String) -> anyhow::Result<Operation> {
pub fn set_description(&mut self, description: String) -> anyhow::Result<Vec<Operation>> {
let mut ops: Vec<TCOperation> = Vec::new();

self.0.set_description(description, &mut ops).expect("");

Ok(ops.get(0).map(|op| Operation(op.clone())).unwrap())
Ok(ops.iter().map(|op| Operation(op.clone())).collect())
}

pub fn set_priority(&mut self, priority: String) -> anyhow::Result<Operation> {
pub fn set_priority(&mut self, priority: String) -> anyhow::Result<Vec<Operation>> {
let mut ops: Vec<TCOperation> = Vec::new();

self.0.set_priority(priority, &mut ops).expect("");

Ok(ops.get(0).map(|op| Operation(op.clone())).unwrap())
Ok(ops.iter().map(|op| Operation(op.clone())).collect())
}

#[pyo3(signature=(entry=None))]
pub fn set_entry(&mut self, entry: Option<String>) -> anyhow::Result<Operation> {
pub fn set_entry(&mut self, entry: Option<String>) -> anyhow::Result<Vec<Operation>> {
let mut ops: Vec<TCOperation> = Vec::new();

let timestamp = entry.map(|time| {
Expand All @@ -212,11 +212,11 @@ impl Task {

self.0.set_entry(timestamp, &mut ops).expect("");

Ok(ops.get(0).map(|op| Operation(op.clone())).unwrap())
Ok(ops.iter().map(|op| Operation(op.clone())).collect())
}

#[pyo3(signature=(wait=None))]
pub fn set_wait(&mut self, wait: Option<String>) -> anyhow::Result<Operation> {
pub fn set_wait(&mut self, wait: Option<String>) -> anyhow::Result<Vec<Operation>> {
let mut ops: Vec<TCOperation> = Vec::new();

let timestamp = wait.map(|time| {
Expand All @@ -227,11 +227,11 @@ impl Task {

self.0.set_wait(timestamp, &mut ops).expect("");

Ok(ops.get(0).map(|op| Operation(op.clone())).unwrap())
Ok(ops.iter().map(|op| Operation(op.clone())).collect())
}

#[pyo3(signature=(modified=None))]
pub fn set_modified(&mut self, modified: Option<String>) -> anyhow::Result<Operation> {
pub fn set_modified(&mut self, modified: Option<String>) -> anyhow::Result<Vec<Operation>> {
let mut ops: Vec<TCOperation> = Vec::new();

let timestamp = modified.map(|time| {
Expand All @@ -242,62 +242,62 @@ impl Task {

self.0.set_wait(timestamp, &mut ops).expect("");

Ok(ops.get(0).map(|op| Operation(op.clone())).unwrap())
Ok(ops.iter().map(|op| Operation(op.clone())).collect())
}

#[pyo3(signature=(property, value=None))]
pub fn set_value(
&mut self,
property: String,
value: Option<String>,
) -> anyhow::Result<Operation> {
) -> anyhow::Result<Vec<Operation>> {
let mut ops: Vec<TCOperation> = Vec::new();
self.0.set_value(property, value, &mut ops).expect("");

Ok(ops.get(0).map(|op| Operation(op.clone())).unwrap())
Ok(ops.iter().map(|op| Operation(op.clone())).collect())
}

pub fn start(&mut self) -> anyhow::Result<Operation> {
pub fn start(&mut self) -> anyhow::Result<Vec<Operation>> {
let mut ops: Vec<TCOperation> = Vec::new();

self.0.start(&mut ops).expect("");

Ok(ops.get(0).map(|op| Operation(op.clone())).unwrap())
Ok(ops.iter().map(|op| Operation(op.clone())).collect())
}

pub fn stop(&mut self) -> anyhow::Result<Operation> {
pub fn stop(&mut self) -> anyhow::Result<Vec<Operation>> {
let mut ops: Vec<TCOperation> = Vec::new();

self.0.stop(&mut ops).expect("");

Ok(ops.get(0).map(|op| Operation(op.clone())).unwrap())
Ok(ops.iter().map(|op| Operation(op.clone())).collect())
}

pub fn done(&mut self) -> anyhow::Result<Operation> {
pub fn done(&mut self) -> anyhow::Result<Vec<Operation>> {
let mut ops: Vec<TCOperation> = Vec::new();

self.0.done(&mut ops).expect("");

Ok(ops.get(0).map(|op| Operation(op.clone())).unwrap())
Ok(ops.iter().map(|op| Operation(op.clone())).collect())
}

pub fn add_tag(&mut self, tag: &Tag) -> anyhow::Result<Operation> {
pub fn add_tag(&mut self, tag: &Tag) -> anyhow::Result<Vec<Operation>> {
let mut ops: Vec<TCOperation> = Vec::new();

self.0.add_tag(&tag.0, &mut ops).expect("");

Ok(ops.get(0).map(|op| Operation(op.clone())).unwrap())
Ok(ops.iter().map(|op| Operation(op.clone())).collect())
}

pub fn remove_tag(&mut self, tag: &Tag) -> anyhow::Result<Operation> {
pub fn remove_tag(&mut self, tag: &Tag) -> anyhow::Result<Vec<Operation>> {
let mut ops: Vec<TCOperation> = Vec::new();

self.0.remove_tag(&tag.0, &mut ops).expect("");

Ok(ops.get(0).map(|op| Operation(op.clone())).unwrap())
Ok(ops.iter().map(|op| Operation(op.clone())).collect())
}

pub fn add_annotation(&mut self, ann: &Annotation) -> anyhow::Result<Operation> {
pub fn add_annotation(&mut self, ann: &Annotation) -> anyhow::Result<Vec<Operation>> {
let mut ops: Vec<TCOperation> = Vec::new();
let mut annotation = Annotation::new();

Expand All @@ -306,78 +306,81 @@ impl Task {

self.0.add_annotation(annotation.0, &mut ops).expect("");

Ok(ops.get(0).map(|op| Operation(op.clone())).unwrap())
Ok(ops.iter().map(|op| Operation(op.clone())).collect())
}

pub fn remove_annotation(&mut self, timestamp: DateTime<Utc>) -> anyhow::Result<Operation> {
pub fn remove_annotation(
&mut self,
timestamp: DateTime<Utc>,
) -> anyhow::Result<Vec<Operation>> {
let mut ops: Vec<TCOperation> = Vec::new();

self.0.remove_annotation(timestamp, &mut ops).expect("");

Ok(ops.get(0).map(|op| Operation(op.clone())).unwrap())
Ok(ops.iter().map(|op| Operation(op.clone())).collect())
}

#[pyo3(signature=(due=None))]
pub fn set_due(&mut self, due: Option<DateTime<Utc>>) -> anyhow::Result<Operation> {
pub fn set_due(&mut self, due: Option<DateTime<Utc>>) -> anyhow::Result<Vec<Operation>> {
let mut ops: Vec<TCOperation> = Vec::new();

self.0.set_due(due, &mut ops).expect("");

Ok(ops.get(0).map(|op| Operation(op.clone())).unwrap())
Ok(ops.iter().map(|op| Operation(op.clone())).collect())
}

pub fn set_uda(
&mut self,
namespace: String,
key: String,
value: String,
) -> anyhow::Result<Operation> {
) -> anyhow::Result<Vec<Operation>> {
let mut ops: Vec<TCOperation> = Vec::new();

self.0.set_uda(namespace, key, value, &mut ops).expect("");

Ok(ops.get(0).map(|op| Operation(op.clone())).unwrap())
Ok(ops.iter().map(|op| Operation(op.clone())).collect())
}

pub fn remove_uda(&mut self, namespace: String, key: String) -> anyhow::Result<Operation> {
pub fn remove_uda(&mut self, namespace: String, key: String) -> anyhow::Result<Vec<Operation>> {
let mut ops: Vec<TCOperation> = Vec::new();

self.0.remove_uda(namespace, key, &mut ops).expect("");

Ok(ops.get(0).map(|op| Operation(op.clone())).unwrap())
Ok(ops.iter().map(|op| Operation(op.clone())).collect())
}

pub fn set_legacy_uda(&mut self, key: String, value: String) -> anyhow::Result<Operation> {
pub fn set_legacy_uda(&mut self, key: String, value: String) -> anyhow::Result<Vec<Operation>> {
let mut ops: Vec<TCOperation> = Vec::new();

self.0.set_legacy_uda(key, value, &mut ops).expect("");

Ok(ops.get(0).map(|op| Operation(op.clone())).unwrap())
Ok(ops.iter().map(|op| Operation(op.clone())).collect())
}

pub fn remove_legacy_uda(&mut self, key: String) -> anyhow::Result<Operation> {
pub fn remove_legacy_uda(&mut self, key: String) -> anyhow::Result<Vec<Operation>> {
let mut ops: Vec<TCOperation> = Vec::new();

self.0.remove_legacy_uda(key, &mut ops).expect("");

Ok(ops.get(0).map(|op| Operation(op.clone())).unwrap())
Ok(ops.iter().map(|op| Operation(op.clone())).collect())
}

pub fn add_dependency(&mut self, dep: String) -> anyhow::Result<Operation> {
pub fn add_dependency(&mut self, dep: String) -> anyhow::Result<Vec<Operation>> {
let mut ops: Vec<TCOperation> = Vec::new();
let dep_uuid = Uuid::parse_str(&dep).expect("couldn't parse UUID");

self.0.add_dependency(dep_uuid, &mut ops).expect("");

Ok(ops.get(0).map(|op| Operation(op.clone())).unwrap())
Ok(ops.iter().map(|op| Operation(op.clone())).collect())
}

pub fn remove_dependency(&mut self, dep: String) -> anyhow::Result<Operation> {
pub fn remove_dependency(&mut self, dep: String) -> anyhow::Result<Vec<Operation>> {
let mut ops: Vec<TCOperation> = Vec::new();
let dep_uuid = Uuid::parse_str(&dep).expect("couldn't parse UUID");

self.0.remove_dependency(dep_uuid, &mut ops).expect("");

Ok(ops.get(0).map(|op| Operation(op.clone())).unwrap())
Ok(ops.iter().map(|op| Operation(op.clone())).collect())
}
}
49 changes: 21 additions & 28 deletions taskchampion.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ class Replica:
def __init__(self, path: str, create_if_missing: bool): ...
@staticmethod
def new_inmemory(): ...
def create_task(self, uuid: str) -> tuple["Task", "Operation"]: ...
def create_task(self, uuid: str) -> tuple["Task", list["Operation"]]: ...
def all_task_uuids(self) -> list[str]: ...
def all_tasks(self) -> dict[str, "Task"]: ...

Expand Down Expand Up @@ -73,42 +73,35 @@ class Task:
def get_dependencies(self) -> list[str]: ...
def get_value(self, property: str) -> Optional[str]: ...
def set_status(self, status: "Status") -> list["Operation"]: ...
def set_description(self, description: str) -> Optional["Operation"]: ...
def set_priority(self, priority: str) -> Optional["Operation"]: ...
def set_entry(self, entry: Optional[str]) -> Optional["Operation"]: ...
def set_wait(self, wait: Optional[str]) -> Optional["Operation"]: ...

def set_modified(
self, modified: Optional[str]) -> Optional["Operation"]: ...
def set_description(self, description: str) -> list["Operation"]: ...
def set_priority(self, priority: str) -> list["Operation"]: ...
def set_entry(self, entry: Optional[str]) -> list["Operation"]: ...
def set_wait(self, wait: Optional[str]) -> list["Operation"]: ...
def set_modified(self, modified: Optional[str]) -> list["Operation"]: ...

def set_value(
self, property: str, value: Optional[str]
) -> Optional["Operation"]: ...
def start(self) -> Optional["Operation"]: ...
def stop(self) -> Optional["Operation"]: ...
def done(self) -> Optional["Operation"]: ...
def add_tag(self, tag: "Tag") -> Optional["Operation"]: ...
def remove_tag(self, tag: "Tag") -> Optional["Operation"]: ...
def start(self) -> list["Operation"]: ...
def stop(self) -> list["Operation"]: ...
def done(self) -> list["Operation"]: ...
def add_tag(self, tag: "Tag") -> list["Operation"]: ...
def remove_tag(self, tag: "Tag") -> list["Operation"]: ...

def add_annotation(
self, annotation: "Annotation") -> Optional["Operation"]: ...
self, annotation: "Annotation") -> list["Operation"]: ...
def remove_annotation(
self, annotation: "Annotation") -> Optional["Operation"]: ...

def set_due(self, due: Optional[datetime]) -> Optional["Operation"]: ...

def set_uda(
self, namespace: str, key: str, value: str
) -> Optional["Operation"]: ...
self, annotation: "Annotation") -> list["Operation"]: ...

def remove_uda(self, namespace: str,
key: str) -> Optional["Operation"]: ...
def set_legacy_uda(
self, key: str, value: str) -> Optional["Operation"]: ...
def set_due(self, due: Optional[datetime]) -> list["Operation"]: ...
def set_uda(self, namespace: str, key: str,
value: str) -> list["Operation"]: ...

def remove_legacy_uda(self, key: str) -> Optional["Operation"]: ...
def add_dependency(self, uuid: str) -> Optional["Operation"]: ...
def remove_dependency(self, uuid: str) -> Optional["Operation"]: ...
def remove_uda(self, namespace: str, key: str) -> list["Operation"]: ...
def set_legacy_uda(self, key: str, value: str) -> list["Operation"]: ...
def remove_legacy_uda(self, key: str) -> list["Operation"]: ...
def add_dependency(self, uuid: str) -> list["Operation"]: ...
def remove_dependency(self, uuid: str) -> list["Operation"]: ...


class WorkingSet:
Expand Down
Loading

0 comments on commit 29fba96

Please sign in to comment.