Skip to content

feat(op-work-packages): write-model + CreateService over a store#66

Merged
AdaWorldAPI merged 1 commit into
mainfrom
claude/beautiful-gates-dJo0u
Jul 1, 2026
Merged

feat(op-work-packages): write-model + CreateService over a store#66
AdaWorldAPI merged 1 commit into
mainfrom
claude/beautiful-gates-dJo0u

Conversation

@AdaWorldAPI

Copy link
Copy Markdown
Owner

What

The WorkPackage write path on top of the #64/#65 model, mirroring the op-journals service house pattern (error enum + Result alias + async Store trait + service + in-memory store).

  • NewWorkPackage — the create write-model / input DTO (Deserialize, so an API layer can parse a request body straight into it). Required NOT NULL columns + optional priority_id/assigned_to_id/parent_id/description; to_work_package() maps it onto a fresh domain entity.
  • WorkPackageStore — async persistence port (insert / get / list_for_project).
  • WorkPackageServicecreate (validate subject non-blank → build → persist, returns the entity with its assigned id), find (→ NotFound), list_for_project.
  • MemoryWorkPackageStore — in-memory impl for tests/prototyping.
  • WorkPackageError + WorkPackageResult (thiserror).

Tests

6 service tests (persist + id assignment, blank-subject rejection, optional-field mapping, NotFound, project filtering, write-model deserialize with optionals defaulting) + the 6 existing model tests = 12 pass.

Gate

cargo +1.95 fmt --check clean; op-work-packages is clippy-clean (0 warnings in this crate's own code). As on #64, -D warnings transitively surfaces the pre-existing op-core lints (should_implement_trait, unused imports/vars, unreachable patterns) already on mainop-core untouched here.

Deps

async-trait + thiserror (runtime), tokio (dev, for #[tokio::test]). Cargo.lock updated with the new edges only.

Branch note

Follows the merged #65; branch restarted from the new main (d716204) per the merged-branch rule, single follow-up commit, no overlap with the walled odoo-rs-transcode branch.

Follow-ups: an update path (set-attributes + lock_version bump + journal hook); op-canon class_id wiring on the model; the sqlx-backed WorkPackageStore in op-db.

🤖 Generated with Claude Code


Generated by Claude Code

Add the WorkPackage write path on top of the #64/#65 model, mirroring the
op-journals service house pattern.

- NewWorkPackage — the create write-model / input DTO (Deserialize, so an
  API layer can parse a request body). Required NOT NULL columns + optional
  priority/assignee/parent/description; to_work_package() maps it onto a
  fresh domain entity.
- WorkPackageStore — async persistence port (insert / get / list_for_project).
- WorkPackageService — create (validate subject non-blank -> build ->
  persist, returns the entity with its assigned id), find (NotFound),
  list_for_project.
- MemoryWorkPackageStore — in-memory impl for tests/prototyping.
- WorkPackageError + WorkPackageResult (thiserror).

6 service tests (persist+id, blank-subject rejection, optional-field
mapping, NotFound, project filter, write-model deserialize/default) + the 6
model tests = 12 pass. fmt clean; op-work-packages clippy-clean (0 warnings
in this crate; the transitive -D warnings op-core lints are pre-existing,
untouched).

Deps: async-trait + thiserror (runtime), tokio (dev, for #[tokio::test]).
@AdaWorldAPI AdaWorldAPI merged commit 832004a into main Jul 1, 2026
AdaWorldAPI pushed a commit that referenced this pull request Jul 1, 2026
Add the WorkPackage update write path on top of the #66 CreateService.

- UpdateWorkPackage — a sparse patch write-model (Deserialize); each Some
  field is applied, None leaves the value untouched. (Un-setting a nullable
  FK to NULL is a documented follow-up — needs Option<Option<_>>.)
- WorkPackageStore::update — persist changes to an existing row.
- WorkPackageService::update(id, expected_lock_version, changes) —
  optimistic locking: NotFound if absent, Conflict{expected,actual} if the
  caller's version is stale, Validation if the patch would blank the
  subject; on success applies the patch, bumps lock_version, refreshes
  updated_at, persists, returns the entity.
- WorkPackageError::Conflict variant.
- MemoryWorkPackageStore::update.

4 new update tests (apply+bump, stale-version conflict, NotFound, blank-
subject rejection) -> 16 tests pass. fmt clean; op-work-packages clippy-clean
(0 warnings in this crate; transitive op-core -D-warnings lints pre-existing).

Follow-up: emit a change event on create/update so the composition layer
can journal it (op-work-packages <-> op-journals), without coupling the
crate to op-journals.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants