1
Fork 0
mirror of https://github.com/thegeneralist01/archivr synced 2026-07-22 11:15:41 +02:00

feat(tags): slugify_segment, move_tag, entry_count, subtree_count, /move API

- Extract slugify_segment() from rename_tag and apply it in create_tag_path
  so new tags get proper slug normalization (spaces→hyphens, strip
  non-alphanumeric, collapse runs, trim edges) instead of raw input
- Add move_tag(conn, tag_uid, new_parent_uid) to database.rs:
  * transactional: updates parent_tag_id then cascades full_path to the
    entire subtree via a recursive CTE (same pattern as rename_tag)
  * rejects self-move, descendant-move, and path collisions
  * None parent_uid promotes the tag to root
- Fix cascade SQL in both rename_tag and move_tag: use prefix-anchored
  substr instead of REPLACE to avoid corrupting paths where the old
  prefix slug reappears at a non-overlapping position
- Add entry_count: i64 to TagNode (direct assignments per tag)
- Add subtree_count: i64 to TagNode (unique entries on tag or any
  descendant via recursive CTE + COUNT(DISTINCT)); COUNT(DISTINCT)
  ensures an entry tagged at both a parent and a child counts once
- Add POST /api/archives/:id/tags/:uid/move with MoveTagBody { parent_uid }
  (null = root; dedicated route so no Option<Option> needed)
- Unit tests: move_tag_*, cascade regression, entry count + subtree count
  correctness, subtree deduplication regression
This commit is contained in:
TheGeneralist 2026-07-19 10:56:59 +02:00
parent a4de506495
commit af9db0e50d
Signed by: thegeneralist01
SSH key fingerprint: SHA256:pp9qddbCNmVNoSjevdvQvM5z0DHN7LTa8qBMbcMq/R4
3 changed files with 2230 additions and 741 deletions

File diff suppressed because it is too large Load diff