Skip to content

Add CRUD functionality that works with the CLI#40

Merged
mors119 merged 1 commit into
FrilLab:mainfrom
mors119:feature/cli-basic-feat
Jun 3, 2026
Merged

Add CRUD functionality that works with the CLI#40
mors119 merged 1 commit into
FrilLab:mainfrom
mors119:feature/cli-basic-feat

Conversation

@mors119
Copy link
Copy Markdown
Collaborator

@mors119 mors119 commented Jun 3, 2026

Summary

Add CRUD functionality that works with the CLI

Closes #11
Closes #13
Closes #14
Closes #15
Closes #16
Closes #17
Closes #18
Closes #19

Type of Change

  • feat
  • fix
  • docs
  • refactor
  • test
  • chore

Required

  • cargo check passes
  • cargo fmt --check passes
  • cargo clippy --workspace --all-targets -- -D warnings passes
  • cargo test passes

Checklist

  • Code builds successfully
  • Tests pass
  • Documentation updated

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced a new CLI tool with note management capabilities: add, list, update, and delete operations for managing notes with file location and content tracking.
  • Tests

    • Added test coverage for note deletion and update operations.
  • Chores

    • Updated dependency versions for improved stability.
    • Restructured workspace configuration.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jun 3, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

This PR completes CRUD operations on the core NoteService (delete and update), builds a new CLI crate with argument parsing and command handlers, and connects the CLI to the service layer. The workspace configuration is corrected to reference the properly-spelled frilvault-cli package.

Changes

CLI Commands and Core CRUD Operations

Layer / File(s) Summary
Core service delete and update operations
crates/frilvault-core/src/note/service.rs, crates/frilvault-core/src/storage/yaml_repository.rs
NoteService adds delete_note and update_note methods that load notes, modify state, and persist via a new replace_notes repository method. Helper methods load_notes and save_notes centralize the load-modify-save pattern.
Core service CRUD test validation
crates/frilvault-core/src/tests/note_service_test.rs
Two tests verify delete_note removes a note and update_note modifies content and updated_at timestamp, both checking persisted state.
CLI crate initialization
apps/frilvault-cli/Cargo.toml
New CLI package declares dependencies on clap (derive), anyhow, uuid, and the local frilvault-core crate.
CLI argument parsing and command structures
apps/frilvault-cli/src/cli/mod.rs, apps/frilvault-cli/src/cli/add.rs, apps/frilvault-cli/src/cli/delete.rs, apps/frilvault-cli/src/cli/list.rs, apps/frilvault-cli/src/cli/update.rs
Clap-derived command structs for Add, Delete, List, and Update subcommands with long-form flags. Top-level Cli struct and Commands enum route subcommands to handlers.
CLI command handlers and service factory
apps/frilvault-cli/src/command/mod.rs, apps/frilvault-cli/src/command/add.rs, apps/frilvault-cli/src/command/delete.rs, apps/frilvault-cli/src/command/list.rs, apps/frilvault-cli/src/command/update.rs
Each execute function creates a note service via create_note_service, calls the appropriate service method, prints results, and returns Ok(()). List displays note details; add, delete, update confirm state changes.
CLI main function and command dispatch
apps/frilvault-cli/src/main.rs
main() parses arguments via Cli::parse(), matches the subcommand, and invokes the corresponding command module's execute function.
Workspace member path correction and library exports
Cargo.toml, crates/frilvault-core/src/lib.rs, crates/frilvault-core/Cargo.toml
Workspace members list corrected from frivault-cli to frilvault-cli and reformatted to multiline. Core lib.rs exports note module with wildcard re-export. serde_yml bumped to 0.0.13.
Vault annotation for main.rs
.vault/src/main.rs.yml
YAML note metadata links to CLI entrypoint at line 10, column 5 with creation and update timestamps.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • FrilLab/frilvault#38: This PR extends the core NoteService and YamlNoteRepository introduced in PR #38 with delete and update operations, then implements a CLI that exercises all four CRUD endpoints.

Poem

🐰 A rabbit's note: four commands now take flight,
Add, list, update, delete—CLI shines bright!
Core service dances through load-modify-save,
With tests standing guard over note-keeping brave!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main objective: adding CRUD functionality accessible via CLI, which directly aligns with the changeset's comprehensive implementation of create, read, update, delete operations for the CLI.
Linked Issues check ✅ Passed All linked coding requirements are met: storage [#11], note service CRUD operations [#13,#14,#15,#16], and all CLI commands [#17,#18,#19] with add, list, delete, and update implementations.
Out of Scope Changes check ✅ Passed All changes directly support the linked issues; the old CLI crate removal, core library updates, and workspace refactoring are necessary infrastructure changes enabling the new functionality.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
crates/frilvault-core/src/lib.rs (1)

9-9: 💤 Low value

Consider keeping explicit re-exports instead of a glob.

pub use note::* widens the public API surface and will silently re-export any future item added to note, making the crate's public contract harder to reason about. Named re-exports keep the surface intentional.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/frilvault-core/src/lib.rs` at line 9, Replace the glob re-export "pub
use note::*" with explicit named re-exports from the note module to avoid
widening the public API surface; locate the glob in lib.rs and list each public
type/function/const from the note module (e.g., pub use note::{...}) so future
additions to note won't be exported implicitly—update the export statement to
enumerate the current public items of note and add/remove names as the module
evolves.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.vault/src/main.rs.yml:
- Around line 1-10: The .vault/src/main.rs.yml note file is currently tracked
which may be accidental; decide whether it should be private or a checked-in
fixture and act accordingly: if it should be private, add a rule to .gitignore
to exclude `.vault/src/` or `.vault/src/main.rs.yml` (or re-enable the existing
notes ignore), or move the file into an explicit examples/ or fixtures/
directory; if it is an intentional artifact (e.g., test fixture or anchor note
like id 4c019c16-fbed-4374-99a4-7b508c1f801e), commit a short README or comment
near `.vault/src/main.rs.yml` explaining its purpose and update process to
prevent accidental edits and churn.

In `@crates/frilvault-core/src/note/service.rs`:
- Around line 56-75: update_note currently silently succeeds when no note
matches note_id; change it so that after loading notes (in update_note) you
search for the note with notes.iter_mut().find(|note| note.id == note_id) and if
not found return a FrilVaultError::NoteNotFound (instead of proceeding to save).
Move the existing TODO out of the found-branch into the else-path that returns
the error, and only call self.save_notes(...) when the note was actually
updated; apply the same not-found error behavior in delete_note so both
functions consistently return FrilVaultError::NoteNotFound when the target id is
missing.

---

Nitpick comments:
In `@crates/frilvault-core/src/lib.rs`:
- Line 9: Replace the glob re-export "pub use note::*" with explicit named
re-exports from the note module to avoid widening the public API surface; locate
the glob in lib.rs and list each public type/function/const from the note module
(e.g., pub use note::{...}) so future additions to note won't be exported
implicitly—update the export statement to enumerate the current public items of
note and add/remove names as the module evolves.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: d2fbd69f-9313-4ac9-a3ff-36e8f62dd6f8

📥 Commits

Reviewing files that changed from the base of the PR and between bb7cd3f and e1f51dc.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (21)
  • .vault/src/main.rs.yml
  • Cargo.toml
  • apps/frilvault-cli/Cargo.toml
  • apps/frilvault-cli/src/cli/add.rs
  • apps/frilvault-cli/src/cli/delete.rs
  • apps/frilvault-cli/src/cli/list.rs
  • apps/frilvault-cli/src/cli/mod.rs
  • apps/frilvault-cli/src/cli/update.rs
  • apps/frilvault-cli/src/command/add.rs
  • apps/frilvault-cli/src/command/delete.rs
  • apps/frilvault-cli/src/command/list.rs
  • apps/frilvault-cli/src/command/mod.rs
  • apps/frilvault-cli/src/command/update.rs
  • apps/frilvault-cli/src/main.rs
  • apps/frivault-cli/Cargo.toml
  • apps/frivault-cli/src/main.rs
  • crates/frilvault-core/Cargo.toml
  • crates/frilvault-core/src/lib.rs
  • crates/frilvault-core/src/note/service.rs
  • crates/frilvault-core/src/storage/yaml_repository.rs
  • crates/frilvault-core/src/tests/note_service_test.rs
💤 Files with no reviewable changes (2)
  • apps/frivault-cli/src/main.rs
  • apps/frivault-cli/Cargo.toml

Comment thread .vault/src/main.rs.yml
Comment on lines +1 to +10
notes:
- id: "4c019c16-fbed-4374-99a4-7b508c1f801e"
source_file: src/main.rs
anchor:
type: Line
line: 10
column: 5
content: new content
created_at: "2026-06-03T15:06:39.025847Z"
updated_at: "2026-06-03T15:09:37.992766Z" No newline at end of file
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check if .vault/ is in .gitignore

if [ -f .gitignore ]; then
  echo "=== Checking .gitignore for .vault/ ==="
  rg -n '\.vault' .gitignore || echo "No .vault/ entry found in .gitignore"
else
  echo ".gitignore file not found"
fi

echo ""
echo "=== Other .vault files in the repository ==="
fd -H -t f . .vault/

Repository: FrilLab/frilvault

Length of output: 220


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== .gitignore relevant lines ==="
if [ -f .gitignore ]; then
  rg -n 'vault|\.vault' .gitignore || true
  echo ""
  echo "=== Full .gitignore (bounded) ==="
  # Print only around the vault lines to keep output small
  rg -n 'vault|\.vault' .gitignore | cut -d: -f1 | head -n 20 | while read -r ln; do
    start=$((ln-3)); end=$((ln+3))
    sed -n "${start},${end}p" .gitignore
    echo "----"
  done
else
  echo ".gitignore not found"
fi

echo ""
echo "=== Check whether .vault/src/ is ignored by git ==="
git ls-files --others -i --exclude-standard -- .vault/src/ || true

echo ""
echo "=== Show what exists under .vault/ ==="
fd -H -t f .vault || true

Repository: FrilLab/frilvault

Length of output: 529


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Check if .vault/src/main.rs.yml is tracked ==="
git ls-files -- .vault/src/main.rs.yml || true

echo ""
echo "=== Check ignore status for .vault/src/main.rs.yml (git check-ignore) ==="
git check-ignore -v -- .vault/src/main.rs.yml || echo "git reports: not ignored"

echo ""
echo "=== Check ignore status for the directory .vault/src/ ==="
git check-ignore -v -- .vault/src/ || echo "git reports: .vault/src/ not ignored"

echo ""
echo "=== List .vault files known to git (tracked only) ==="
git ls-files -- '*.yml' -- .vault || true

echo ""
echo "=== List .vault files on disk (bounded) ==="
# Avoid large output; just show the file we know about if present
if [ -f .vault/src/main.rs.yml ]; then
  echo "Found: .vault/src/main.rs.yml"
fi

Repository: FrilLab/frilvault

Length of output: 562


Clarify whether committing .vault/src/main.rs.yml is intentional (it is tracked and not ignored)

  • .gitignore only ignores .vault/cache and .vault/index (notes are commented out), and .vault/src/main.rs.yml is tracked and not excluded by git.
  • If .vault/src/* is meant to be user-specific/private, add the proper ignore rule (or move it to examples//fixtures/).
  • If it’s an intentional checked-in artifact (e.g., note/anchor fixture), add a brief README/comment explaining purpose and how updates should be handled to avoid churn/merge conflicts.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.vault/src/main.rs.yml around lines 1 - 10, The .vault/src/main.rs.yml note
file is currently tracked which may be accidental; decide whether it should be
private or a checked-in fixture and act accordingly: if it should be private,
add a rule to .gitignore to exclude `.vault/src/` or `.vault/src/main.rs.yml`
(or re-enable the existing notes ignore), or move the file into an explicit
examples/ or fixtures/ directory; if it is an intentional artifact (e.g., test
fixture or anchor note like id 4c019c16-fbed-4374-99a4-7b508c1f801e), commit a
short README or comment near `.vault/src/main.rs.yml` explaining its purpose and
update process to prevent accidental edits and churn.

Comment on lines +56 to 75
pub fn update_note(
&self,
source_file: impl AsRef<Path>,
note_id: Uuid,
content: String,
) -> FrilVaultResult<()> {
let source_file = source_file.as_ref();

let mut notes = self.load_notes(source_file)?;

if let Some(note) = notes.iter_mut().find(|note| note.id == note_id) {
// TODO: FrilVaultError::NoteNotFound
note.content = content;
note.updated_at = Utc::now();
}

self.save_notes(source_file, notes)?;

Ok(note_file.notes)
Ok(())
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

update_note silently succeeds when the note is missing.

When no note matches note_id, the if let Some(...) block is skipped and the method still calls save_notes and returns Ok(()). The downstream CLI handler (apps/frilvault-cli/src/command/update.rs) then prints "Note updated" even though nothing changed, which misleads the user. The // TODO: FrilVaultError::NoteNotFound is also misplaced: it sits inside the found branch, but the not-found error should be raised in the else path.

🛠️ Suggested handling for the not-found case
-        if let Some(note) = notes.iter_mut().find(|note| note.id == note_id) {
-            // TODO: FrilVaultError::NoteNotFound
-            note.content = content;
-            note.updated_at = Utc::now();
-        }
-
-        self.save_notes(source_file, notes)?;
+        let note = notes
+            .iter_mut()
+            .find(|note| note.id == note_id)
+            .ok_or(/* FrilVaultError::NoteNotFound */)?;
+
+        note.content = content;
+        note.updated_at = Utc::now();
+
+        self.save_notes(source_file, notes)?;

Want me to open an issue to track adding a FrilVaultError::NoteNotFound variant and wiring it into both update_note and delete_note?

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/frilvault-core/src/note/service.rs` around lines 56 - 75, update_note
currently silently succeeds when no note matches note_id; change it so that
after loading notes (in update_note) you search for the note with
notes.iter_mut().find(|note| note.id == note_id) and if not found return a
FrilVaultError::NoteNotFound (instead of proceeding to save). Move the existing
TODO out of the found-branch into the else-path that returns the error, and only
call self.save_notes(...) when the note was actually updated; apply the same
not-found error behavior in delete_note so both functions consistently return
FrilVaultError::NoteNotFound when the target id is missing.

@mors119 mors119 merged commit 2417e94 into FrilLab:main Jun 3, 2026
3 checks passed
@mors119 mors119 deleted the feature/cli-basic-feat branch June 3, 2026 15:27
@coderabbitai coderabbitai Bot mentioned this pull request Jun 3, 2026
9 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant