Skip to content

Add database configuration handling#8

Merged
Bechma merged 3 commits intocyberfabric:mainfrom
Bechma:main
Mar 5, 2026
Merged

Add database configuration handling#8
Bechma merged 3 commits intocyberfabric:mainfrom
Bechma:main

Conversation

@Bechma
Copy link
Copy Markdown
Collaborator

@Bechma Bechma commented Mar 5, 2026

Add module-level database configuration management with add, edit, and remove commands. Also, global database.

Summary by CodeRabbit

  • New Features

    • CLI commands to manage global and per-module database server configs (add/edit/remove).
    • Module-level DB management command added.
    • Module add now upserts (add or update) instead of failing on duplicates.
    • Added short flag -F for module features (comma-delimited).
    • Expanded tracing/telemetry configuration options.
  • Bug Fixes

    • Merging of module metadata now preserves config-provided overrides while respecting local values.
  • Refactor

    • Replaced generic DB/tracing config with strongly-typed config structures.

…d remove commands. Also, global database.

Signed-off-by: Bechma <19294519+Bechma@users.noreply.github.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 5, 2026

📝 Walkthrough

Walkthrough

Adds typed global/module DB and tracing config, CLI subcommands to manage global and per-module DB entries, deterministic module metadata merging with precedence rules, helpers for resolving workspace + config (DEFAULT_CONFIG_FILE and resolve_workspace_and_config), and integrates upsert behavior into module add.

Changes

Cohort / File(s) Summary
Core config types
crates/cli/src/config/app_config.rs
Replaces generic Value fields with strongly-typed DB and tracing types (GlobalDatabaseConfig, DbConnConfig, PoolCfg, TracingConfig, MetricsConfig, etc.), adds parsing helpers, patch/apply semantics, and defaulting/validation helpers.
Global DB CLI & helpers
crates/cli/src/config/db/mod.rs, crates/cli/src/config/mod.rs
New DbArgs CLI (Add/Edit/Rm) for global database.servers; adds load_config/save_config, validate_name, ensure_conn_payload, atomic write, and wiring into ConfigCommand.
Module-level DB CLI
crates/cli/src/config/modules/db.rs, crates/cli/src/config/modules/mod.rs
Adds ModuleDbArgs (Add/Edit/Rm), integrates into ModulesCommand::Db, validates module names/payloads, and persists per-module DB config changes.
Module add/upsert
crates/cli/src/config/modules/add.rs
Changes module add to upsert behavior, accepts -F short flag for features (comma-delimited), and uses upsert_module_config + merge_module_metadata instead of hard error on duplicates.
Metadata merge & resolution
crates/cli/src/common.rs, crates/cli/src/build/mod.rs, crates/cli/src/run/mod.rs, crates/cli/src/main.rs
Adds merge_module_metadata(ConfigModuleMetadata, ConfigModuleMetadata), DEFAULT_CONFIG_FILE, and BuildRunArgs::resolve_workspace_and_config; substitutes direct metadata assignment with merged result; refactors workspace/config resolution and boxes ConfigArgs in CLI enum.
Tests
crates/cli/src/common.rs (tests), crates/cli/src/config/modules/add.rs (tests)
Adds unit tests validating metadata merge/upsert behavior and override precedence.

Sequence Diagram(s)

sequenceDiagram
  participant User as CLI User
  participant CLI as cf-cli
  participant Config as AppConfig Loader
  participant FS as Filesystem
  participant Parser as module_parser

  User->>CLI: invoke command (e.g., `modules add` / `config db add`)
  CLI->>Config: load_config(config_path)
  Config->>FS: read config file
  FS-->>Config: config content
  Config->>Parser: parse module metadata (if applicable)
  Parser-->>CLI: return ConfigModuleMetadata(s)
  CLI->>CLI: merge_module_metadata(config_meta, local_meta)
  CLI->>Config: mutate AppConfig (upsert/patch/remove)
  Config->>FS: write tmp file and atomic replace
  FS-->>CLI: write success
  CLI-->>User: return status/message
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐰 I hopped through configs late and bright,
Merged metadata clean by moonlight,
Databases nested, tracing set free,
Upserts snug in the warren of tree,
Hooray — configs safe, and all's just right!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 17.02% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately describes the main change: adding database configuration handling across module-level and global scopes.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Copy link
Copy Markdown
Contributor

@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 (5)
crates/cli/src/config/app_config.rs (1)

337-354: Consider trimming whitespace in key-value parsing.

If a user provides --params "key = value", the key will be stored as "key " and value as " value". Trimming would improve robustness:

♻️ Suggested fix
         let (key, value) = pair
             .split_once('=')
             .ok_or_else(|| format!("invalid key=value pair '{pair}'"))?;
-        if key.trim().is_empty() {
+        let key = key.trim();
+        let value = value.trim();
+        if key.is_empty() {
             return Err(format!("invalid key=value pair '{pair}'"));
         }
-        params.insert(key.to_owned(), value.to_owned());
+        params.insert(key.to_owned(), value.to_owned());
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/cli/src/config/app_config.rs` around lines 337 - 354, The
parse_params_map function currently stores raw key and value without trimming,
so inputs like "key = value" keep surrounding spaces; update parse_params_map to
trim whitespace on both key and value (e.g., call .trim() on key and value
before validating/inserting), validate that the trimmed key is non-empty (use
the trimmed key for the empty check and the map insert), and insert the owned
trimmed strings into the BTreeMap so stored keys/values have no leading/trailing
spaces.
crates/cli/src/config/db/mod.rs (2)

153-161: Minor duplication with validate_module_name.

This function has the same logic as validate_module_name in modules/mod.rs. Consider extracting to a shared helper parameterized by the entity kind.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/cli/src/config/db/mod.rs` around lines 153 - 161, The validation logic
in validate_identifier duplicates validate_module_name; extract the shared logic
into a single helper (e.g., validate_name or validate_identifier_common) that
takes (value: &str, kind: &str) and performs the ASCII-alnum/'-'/ '_' check and
error formatting, replace the body of validate_identifier and modify
validate_module_name to call that helper, and update any callers to use the
unified helper to avoid duplication while preserving the exact error message
format.

135-151: Duplicate load_config and save_config implementations.

These functions are identical to those in crates/cli/src/config/modules/mod.rs (lines 125-152). Consider extracting them to a shared location (e.g., a utils module or the parent config module) to avoid code duplication.

♻️ Suggested structure

Move to crates/cli/src/config/mod.rs or a new crates/cli/src/config/utils.rs:

pub(crate) fn load_config(path: &Path) -> anyhow::Result<AppConfig> { ... }
pub(crate) fn save_config(path: &Path, config: &AppConfig) -> anyhow::Result<()> { ... }

Then import in both db/mod.rs and modules/mod.rs.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/cli/src/config/db/mod.rs` around lines 135 - 151, The load_config and
save_config functions are duplicated; extract them into a shared function in the
parent config module (e.g., config::load_config and config::save_config or
config::utils with pub(crate) visibility) and remove the duplicates in
db::mod.rs and modules::mod.rs; update both modules to call the shared functions
and ensure signatures remain fn load_config(path: &Path) ->
anyhow::Result<AppConfig> and fn save_config(path: &Path, config: &AppConfig) ->
anyhow::Result<()> so existing callers (including fs/serde_saphyr usage and the
temp-file/rename logic) continue to work.
crates/cli/src/config/modules/db.rs (1)

126-131: Duplicate ensure_conn_payload implementation.

This function is identical to the one in crates/cli/src/config/db/mod.rs (lines 128-133). Consider extracting to a shared location.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/cli/src/config/modules/db.rs` around lines 126 - 131, The function
ensure_conn_payload is duplicated; extract it into a single shared utility
module (e.g., a new config/utils or config/common module) and have both
crates/cli/src/config/modules/db.rs and crates/cli/src/config/db/mod.rs import
and call that one implementation instead of defining their own copies. Move the
implementation of ensure_conn_payload to the new shared module, export it (pub
fn ensure_conn_payload), update both files to use the shared path (use
...::ensure_conn_payload), remove the duplicate function definitions, and run
cargo build/tests to verify no symbol/visibility issues remain.
crates/cli/src/config/modules/add.rs (1)

134-241: Consider adding a test for upsert behavior.

The tests cover build_required_metadata well, but there's no test validating the upsert behavior when a module already exists in the config. Adding such a test would document the expected behavior (full replace vs. merge) and prevent regressions.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/cli/src/config/modules/add.rs` around lines 134 - 241, Add a unit test
in the existing tests module that verifies upsert behavior when adding a module
that already exists: create an initial ConfigModule (using ConfigModule and
ConfigModuleMetadata from the diff) in a fake/in-memory config, construct
AddArgs for the same module name (using AddArgs from the diff) with different
metadata, run the code-path that performs the add/upsert (the CLI add handler or
the function that applies build_required_metadata results into the config), and
assert the final config entry matches the expected upsert semantics (full
replace or merge) so future changes won't regress the intended behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@crates/cli/src/config/modules/add.rs`:
- Around line 43-53: The upsert currently overwrites an existing
ModuleConfig.metadata (in the block that checks
config.modules.get_mut(&self.module)), which discards prior custom fields;
instead merge the incoming metadata with the existing one—retrieve
existing.metadata (if Some) and combine fields with the new metadata rather than
replacing, or invoke the same merge logic used by get_config (e.g.,
merge_module_metadata) to preserve existing features/default_features and only
overwrite CLI-provided fields; update the branch that inserts/updates
ModuleConfig (and ModuleConfig::default() fallback) to perform this merge so
existing customizations are kept.

In `@crates/cli/src/config/modules/db.rs`:
- Around line 48-56: The current code uses
config.modules.entry(self.module.clone()).or_default(), which silently creates a
module when adding DB config; change this to first check for existence with
something like if !config.modules.contains_key(&self.module) { return Err(...) }
unless a new boolean flag (e.g. self.create / --create) is provided and true; if
create is true then insert a default module entry and proceed to set or patch
module_cfg.database (keep existing apply_patch logic), and update any
command/struct parsing to accept the new --create flag so callers can opt into
creating the module.

---

Nitpick comments:
In `@crates/cli/src/config/app_config.rs`:
- Around line 337-354: The parse_params_map function currently stores raw key
and value without trimming, so inputs like "key = value" keep surrounding
spaces; update parse_params_map to trim whitespace on both key and value (e.g.,
call .trim() on key and value before validating/inserting), validate that the
trimmed key is non-empty (use the trimmed key for the empty check and the map
insert), and insert the owned trimmed strings into the BTreeMap so stored
keys/values have no leading/trailing spaces.

In `@crates/cli/src/config/db/mod.rs`:
- Around line 153-161: The validation logic in validate_identifier duplicates
validate_module_name; extract the shared logic into a single helper (e.g.,
validate_name or validate_identifier_common) that takes (value: &str, kind:
&str) and performs the ASCII-alnum/'-'/ '_' check and error formatting, replace
the body of validate_identifier and modify validate_module_name to call that
helper, and update any callers to use the unified helper to avoid duplication
while preserving the exact error message format.
- Around line 135-151: The load_config and save_config functions are duplicated;
extract them into a shared function in the parent config module (e.g.,
config::load_config and config::save_config or config::utils with pub(crate)
visibility) and remove the duplicates in db::mod.rs and modules::mod.rs; update
both modules to call the shared functions and ensure signatures remain fn
load_config(path: &Path) -> anyhow::Result<AppConfig> and fn save_config(path:
&Path, config: &AppConfig) -> anyhow::Result<()> so existing callers (including
fs/serde_saphyr usage and the temp-file/rename logic) continue to work.

In `@crates/cli/src/config/modules/add.rs`:
- Around line 134-241: Add a unit test in the existing tests module that
verifies upsert behavior when adding a module that already exists: create an
initial ConfigModule (using ConfigModule and ConfigModuleMetadata from the diff)
in a fake/in-memory config, construct AddArgs for the same module name (using
AddArgs from the diff) with different metadata, run the code-path that performs
the add/upsert (the CLI add handler or the function that applies
build_required_metadata results into the config), and assert the final config
entry matches the expected upsert semantics (full replace or merge) so future
changes won't regress the intended behavior.

In `@crates/cli/src/config/modules/db.rs`:
- Around line 126-131: The function ensure_conn_payload is duplicated; extract
it into a single shared utility module (e.g., a new config/utils or
config/common module) and have both crates/cli/src/config/modules/db.rs and
crates/cli/src/config/db/mod.rs import and call that one implementation instead
of defining their own copies. Move the implementation of ensure_conn_payload to
the new shared module, export it (pub fn ensure_conn_payload), update both files
to use the shared path (use ...::ensure_conn_payload), remove the duplicate
function definitions, and run cargo build/tests to verify no symbol/visibility
issues remain.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f695777f-1cb9-4719-95ed-f830cbbb934e

📥 Commits

Reviewing files that changed from the base of the PR and between 795b72c and ae6d9b8.

📒 Files selected for processing (7)
  • crates/cli/src/common.rs
  • crates/cli/src/config/app_config.rs
  • crates/cli/src/config/db/mod.rs
  • crates/cli/src/config/mod.rs
  • crates/cli/src/config/modules/add.rs
  • crates/cli/src/config/modules/db.rs
  • crates/cli/src/config/modules/mod.rs

Signed-off-by: Bechma <19294519+Bechma@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

@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: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@crates/cli/src/config/modules/db.rs`:
- Around line 51-56: The error message references a nonexistent --create flag;
either remove that mention or implement the flag: add a boolean field named
create to AddArgs (or the relevant CLI args struct), wire it into the CLI
parser/derive so it appears in help, and update the calling logic that handles
the add command to respect this flag when a module is missing (the code path
checking config.modules and calling bail(...) should consult AddArgs::create to
create the module instead of bailing). Also update the message in the bail call
(or help text) to reflect the chosen approach and ensure context.config_path and
self.module remain used for clear feedback.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: cfa18e42-463f-4e49-85fe-3f7ef001add5

📥 Commits

Reviewing files that changed from the base of the PR and between ae6d9b8 and 47471c3.

📒 Files selected for processing (10)
  • crates/cli/src/build/mod.rs
  • crates/cli/src/common.rs
  • crates/cli/src/config/app_config.rs
  • crates/cli/src/config/db/mod.rs
  • crates/cli/src/config/mod.rs
  • crates/cli/src/config/modules/add.rs
  • crates/cli/src/config/modules/db.rs
  • crates/cli/src/config/modules/mod.rs
  • crates/cli/src/main.rs
  • crates/cli/src/run/mod.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • crates/cli/src/config/app_config.rs

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

@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.

🧹 Nitpick comments (1)
crates/cli/src/config/modules/db.rs (1)

45-65: Consider extracting shared Add/Edit mutation flow.

AddArgs::run and EditArgs::run repeat context resolution, config load, module fetch, patching, and save paths. A small shared helper would reduce future drift and keep behavior aligned.

Also applies to: 78-94

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/cli/src/config/modules/db.rs` around lines 45 - 65, Extract the shared
mutation flow from AddArgs::run and EditArgs::run into a small helper (e.g.,
apply_module_db_change) that takes the module name, the conn payload, and
path_config/context and encapsulates: validate_module_db_payload,
resolve_modules_context, load_config, get_module_cfg_mut, the
existing.apply_patch or set logic for module_cfg.database, and save_config; then
call that helper from both AddArgs::run and EditArgs::run to avoid duplicated
resolution/patch/save logic and keep behavior aligned.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@crates/cli/src/config/modules/db.rs`:
- Around line 45-65: Extract the shared mutation flow from AddArgs::run and
EditArgs::run into a small helper (e.g., apply_module_db_change) that takes the
module name, the conn payload, and path_config/context and encapsulates:
validate_module_db_payload, resolve_modules_context, load_config,
get_module_cfg_mut, the existing.apply_patch or set logic for
module_cfg.database, and save_config; then call that helper from both
AddArgs::run and EditArgs::run to avoid duplicated resolution/patch/save logic
and keep behavior aligned.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 177eb5af-fa04-4a32-82c9-9071b2c17a7a

📥 Commits

Reviewing files that changed from the base of the PR and between 47471c3 and 7da187a.

📒 Files selected for processing (1)
  • crates/cli/src/config/modules/db.rs

@Bechma Bechma merged commit b0da5bf into cyberfabric:main Mar 5, 2026
1 check passed
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.

1 participant