Skip to content

feat(wren): add type_mapping module and wren utils CLI + wren-generate-mdl skill#1513

Merged
goldmedal merged 4 commits intoCanner:feat/cli-0.2.0from
goldmedal:plan-type-mapping
Apr 4, 2026
Merged

feat(wren): add type_mapping module and wren utils CLI + wren-generate-mdl skill#1513
goldmedal merged 4 commits intoCanner:feat/cli-0.2.0from
goldmedal:plan-type-mapping

Conversation

@goldmedal
Copy link
Copy Markdown
Contributor

@goldmedal goldmedal commented Apr 3, 2026

Summary

  • Adds wren.type_mapping module with parse_type() and parse_types() for sqlglot-based SQL type normalization (no custom mapping table — sqlglot is source of truth, graceful fallback on unknown types)
  • Adds wren utils parse-type and wren utils parse-types CLI subcommands for single and batch type normalization from the command line
  • Adds cli-skills/wren-generate-mdl/SKILL.md — a 7-phase agent workflow skill for bootstrapping an MDL project from an existing database (schema discovery → type normalization → YAML scaffolding → validation → memory indexing)

Test plan

  • uv run pytest tests/unit/test_type_mapping.py -v — 18 tests passing (9 parse_type parametrized cases, 4 parse_types batch cases, 5 CLI integration tests)
  • wren utils parse-type --type "int8" --dialect postgresBIGINT
  • wren utils parse-types --dialect postgres with JSON on stdin → JSON with "type" fields added
  • uv run ruff format --check src/ && uv run ruff check src/ — clean

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added CLI utilities to normalize SQL types (single and batch) and underlying type-normalization functionality.
  • Documentation
    • Added end-to-end "Generate MDL" workflow documentation covering discovery, type normalization, scaffolding, validation, build, and memory indexing.
  • Tests
    • Added unit and CLI tests validating type normalization, batch processing, and CLI behaviors.

goldmedal and others added 2 commits April 2, 2026 15:40
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ner#1509)

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
@github-actions github-actions bot added the documentation Improvements or additions to documentation label Apr 3, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 3, 2026

📝 Walkthrough

Walkthrough

Adds SQL type normalization utilities, CLI subcommands, documentation for a Wren MDL generation workflow, CLI registration, and unit/integration tests enabling single and batch type parsing across SQL dialects using sqlglot.

Changes

Cohort / File(s) Summary
Type Normalization Core
wren/src/wren/type_mapping.py, wren/src/wren/utils_cli.py, wren/src/wren/cli.py
New type_mapping module with parse_type() and parse_types() using sqlglot. New utils Typer sub-app exposing parse-type and parse-types commands. Main CLI registers the utils sub-app.
Documentation
cli-skills/wren-generate-mdl/SKILL.md
New documentation describing an end-to-end CLI workflow to generate a Wren MDL project from a database, including phased steps, command mappings, and a checklist of disallowed shortcuts.
Tests
wren/tests/unit/test_type_mapping.py
New tests covering parse_type() and parse_types() behavior across dialects, edge cases (empty/unknown types), non-mutating batch processing, and CLI integration for both commands.

Sequence Diagram

sequenceDiagram
    participant User
    participant CLI as utils_cli<br/>(parse-type/parse-types)
    participant TypeMap as type_mapping
    participant sqlglot
    participant Output

    rect rgba(100, 200, 100, 0.5)
    Note over User,Output: Single Type Normalization Flow
    User->>CLI: wren utils parse-type "int8" --dialect postgres
    CLI->>TypeMap: parse_type("int8", "postgres")
    TypeMap->>sqlglot: parse & normalize type string
    sqlglot-->>TypeMap: DataType.sql() result
    TypeMap-->>CLI: Normalized type string
    CLI->>Output: Print result
    Output-->>User: "BIGINT"
    end

    rect rgba(150, 150, 200, 0.5)
    Note over User,Output: Batch Type Normalization Flow
    User->>CLI: wren utils parse-types --dialect postgres < data.json
    CLI->>CLI: Read JSON array from stdin/file
    CLI->>TypeMap: parse_types(columns, "postgres", type_field="raw_type")
    loop For each column dict
        TypeMap->>TypeMap: Clone dict & parse_type(raw_type)
        TypeMap->>sqlglot: Normalize type
        sqlglot-->>TypeMap: Normalized type
        TypeMap->>TypeMap: Add "type" field to clone
    end
    TypeMap-->>CLI: List of enriched dicts
    CLI->>Output: Print pretty JSON
    Output-->>User: JSON with original + "type" fields
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested labels

python

Suggested reviewers

  • douenergy

Poem

🐰 I hop through types both big and small,
sqlglot guides and answers my call,
parse one, parse many, neat and spry,
CLI commands that leap and fly,
Wren's types tidy—hip hooray! 🥕✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 35.29% 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 summarizes all three main changes: adding the type_mapping module, wren utils CLI subcommands, and the wren-generate-mdl skill documentation.

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

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

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

🧹 Nitpick comments (3)
cli-skills/wren-generate-mdl/SKILL.md (2)

148-155: Add language identifier to fenced code block.

This directory structure listing should have a language identifier. Using text or plaintext is appropriate for non-code content like file trees.

📝 Suggested fix
-```
+```text
 project/
 ├── wren_project.yml
 ├── models/
 ├── views/
 ├── relationships.yml
 └── instructions.md
 ```
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@cli-skills/wren-generate-mdl/SKILL.md` around lines 148 - 155, Update the
fenced code block in SKILL.md that shows the project directory tree to include a
language identifier (e.g., "text" or "plaintext") so the tree is rendered as
plain text; locate the fenced block containing the directory listing (the
triple-backtick block showing "project/ ├── wren_project.yml ...") and add the
language token immediately after the opening backticks (e.g., ```text).

101-101: Minor grammar: hyphenate compound modifier.

Per static analysis, "wren-core compatible" should be hyphenated when used as a compound adjective.

📝 Suggested fix
-**Goal:** Convert raw database types to wren-core compatible types.
+**Goal:** Convert raw database types to wren-core-compatible types.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@cli-skills/wren-generate-mdl/SKILL.md` at line 101, Update the compound
modifier in the Goal line by hyphenating "wren-core compatible": change the
sentence "**Goal:** Convert raw database types to wren-core compatible types."
so it reads "**Goal:** Convert raw database types to wren-core-compatible
types." to correct the compound adjective usage (locate the Goal header / the
sentence starting "Convert raw database types..." in SKILL.md).
wren/tests/unit/test_type_mapping.py (1)

81-87: Consider capturing stderr for debugging test failures.

The helper works correctly, but when tests fail, having stderr output would help diagnose issues.

💡 Optional: Add stderr assertion helper
 def _run_wren(*args: str, stdin: str | None = None) -> subprocess.CompletedProcess:
     return subprocess.run(
         [sys.executable, "-m", "wren.cli", *args],
         input=stdin,
         capture_output=True,
         text=True,
     )
+
+
+def _assert_success(result: subprocess.CompletedProcess) -> None:
+    """Assert command succeeded, printing stderr on failure."""
+    assert result.returncode == 0, f"Command failed with stderr: {result.stderr}"

Then use _assert_success(result) instead of assert result.returncode == 0 for better diagnostics.

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

In `@wren/tests/unit/test_type_mapping.py` around lines 81 - 87, Modify the test
helper _run_wren to capture stderr for easier debugging by passing
stderr=subprocess.STDOUT to subprocess.run (so stderr is included in the output)
and add a small assertion helper function named _assert_success(result) that
asserts result.returncode == 0 but on failure raises/asserts with the combined
output (result.stdout) so test failures show stderr; update tests to use
_assert_success(result) instead of bare returncode checks.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@wren/src/wren/utils_cli.py`:
- Around line 48-51: Wrap the JSON loading logic that uses
Path(input_file).read_text + json.loads and the json.load(sys.stdin) branch in
try/except blocks to catch json.JSONDecodeError, FileNotFoundError and
PermissionError (and a generic Exception fallback); when caught, print a clear,
user-friendly message to stderr (including the filename when available) and exit
with a non-zero status instead of letting the raw exception propagate. Ensure
you reference the existing symbols input_file, Path(input_file).read_text,
json.loads and json.load(sys.stdin) so the changes only modify error handling
around those calls.

---

Nitpick comments:
In `@cli-skills/wren-generate-mdl/SKILL.md`:
- Around line 148-155: Update the fenced code block in SKILL.md that shows the
project directory tree to include a language identifier (e.g., "text" or
"plaintext") so the tree is rendered as plain text; locate the fenced block
containing the directory listing (the triple-backtick block showing "project/
├── wren_project.yml ...") and add the language token immediately after the
opening backticks (e.g., ```text).
- Line 101: Update the compound modifier in the Goal line by hyphenating
"wren-core compatible": change the sentence "**Goal:** Convert raw database
types to wren-core compatible types." so it reads "**Goal:** Convert raw
database types to wren-core-compatible types." to correct the compound adjective
usage (locate the Goal header / the sentence starting "Convert raw database
types..." in SKILL.md).

In `@wren/tests/unit/test_type_mapping.py`:
- Around line 81-87: Modify the test helper _run_wren to capture stderr for
easier debugging by passing stderr=subprocess.STDOUT to subprocess.run (so
stderr is included in the output) and add a small assertion helper function
named _assert_success(result) that asserts result.returncode == 0 but on failure
raises/asserts with the combined output (result.stdout) so test failures show
stderr; update tests to use _assert_success(result) instead of bare returncode
checks.
🪄 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

Run ID: 45669067-b880-4c38-9fd6-1891ca27426d

📥 Commits

Reviewing files that changed from the base of the PR and between b086576 and f93a3d8.

📒 Files selected for processing (5)
  • cli-skills/wren-generate-mdl/SKILL.md
  • wren/src/wren/cli.py
  • wren/src/wren/type_mapping.py
  • wren/src/wren/utils_cli.py
  • wren/tests/unit/test_type_mapping.py

goldmedal and others added 2 commits April 3, 2026 22:57
Add sqlglot-based SQL type normalization available both as a Python
import and via the `wren utils parse-type` / `wren utils parse-types`
CLI commands. Also adds the `wren-generate-mdl` agent skill that guides
through schema discovery, type normalization, and MDL project scaffolding.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add error handling in parse-types CLI for invalid JSON and missing files
- Add _assert_success() helper to CLI tests for clearer failure diagnostics
- Use _assert_success() consistently across all CLI integration tests
- Fix SKILL.md: hyphenate "wren-core-compatible", add text lang to code fence

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@goldmedal goldmedal force-pushed the plan-type-mapping branch from d46c631 to 665fb8d Compare April 3, 2026 14:57
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 (2)
wren/src/wren/utils_cli.py (1)

48-59: Error handling implemented as requested, with one gap.

The JSON error handling addresses the previous review feedback. However, path.read_text() can also raise PermissionError if the file exists but isn't readable—this would surface as an unhandled exception.

🛡️ Optional: handle permission errors
     try:
         if input_file:
             path = Path(input_file)
             if not path.exists():
                 typer.echo(f"Error: file not found: {input_file}", err=True)
                 raise typer.Exit(1)
-            data = json.loads(path.read_text())
+            try:
+                data = json.loads(path.read_text())
+            except PermissionError:
+                typer.echo(f"Error: permission denied: {input_file}", err=True)
+                raise typer.Exit(1)
         else:
             data = json.load(sys.stdin)
     except json.JSONDecodeError as e:
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@wren/src/wren/utils_cli.py` around lines 48 - 59, The try/except around JSON
loading should also handle file read permission errors: when input_file is
provided and you call Path(...).read_text() inside the block (see variables
input_file and path and call to path.read_text()), catch PermissionError (or
broader OSError if you prefer) alongside json.JSONDecodeError, echo a clear
error via typer.echo (e.g., "Error: cannot read file: <path>: <error>") and then
raise typer.Exit(1) so permission issues don’t crash the CLI.
wren/tests/unit/test_type_mapping.py (1)

122-144: Good CLI integration coverage.

The tests validate both single and batch CLI commands, including stdin JSON input and field preservation in output.

Consider adding tests for error cases in a follow-up (e.g., invalid JSON input, missing --type or --dialect arguments) to ensure the CLI provides user-friendly error messages.

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

In `@wren/tests/unit/test_type_mapping.py` around lines 122 - 144, Add negative
CLI tests to wren/tests/unit/test_type_mapping.py to cover error cases: create
tests like test_cli_parse_types_invalid_json that calls
_run_wren("utils","parse-types","--dialect","postgres", stdin="not json") and
asserts non-zero exit and a helpful error message in stderr;
test_cli_parse_types_missing_dialect that calls _run_wren("utils","parse-types",
stdin=json.dumps([...])) and asserts the CLI fails with a clear "missing
--dialect" style message; and optionally test_cli_parse_types_missing_type or
other required-arg scenarios similarly, using _assert_success negation and
checking stderr text to ensure user-friendly errors from the parse-types
command.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@wren/src/wren/utils_cli.py`:
- Around line 48-59: The try/except around JSON loading should also handle file
read permission errors: when input_file is provided and you call
Path(...).read_text() inside the block (see variables input_file and path and
call to path.read_text()), catch PermissionError (or broader OSError if you
prefer) alongside json.JSONDecodeError, echo a clear error via typer.echo (e.g.,
"Error: cannot read file: <path>: <error>") and then raise typer.Exit(1) so
permission issues don’t crash the CLI.

In `@wren/tests/unit/test_type_mapping.py`:
- Around line 122-144: Add negative CLI tests to
wren/tests/unit/test_type_mapping.py to cover error cases: create tests like
test_cli_parse_types_invalid_json that calls
_run_wren("utils","parse-types","--dialect","postgres", stdin="not json") and
asserts non-zero exit and a helpful error message in stderr;
test_cli_parse_types_missing_dialect that calls _run_wren("utils","parse-types",
stdin=json.dumps([...])) and asserts the CLI fails with a clear "missing
--dialect" style message; and optionally test_cli_parse_types_missing_type or
other required-arg scenarios similarly, using _assert_success negation and
checking stderr text to ensure user-friendly errors from the parse-types
command.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 01b5f4c8-1c7b-4886-a4b9-294b99d5a89c

📥 Commits

Reviewing files that changed from the base of the PR and between f93a3d8 and 665fb8d.

📒 Files selected for processing (5)
  • cli-skills/wren-generate-mdl/SKILL.md
  • wren/src/wren/cli.py
  • wren/src/wren/type_mapping.py
  • wren/src/wren/utils_cli.py
  • wren/tests/unit/test_type_mapping.py
✅ Files skipped from review due to trivial changes (2)
  • wren/src/wren/type_mapping.py
  • cli-skills/wren-generate-mdl/SKILL.md

@goldmedal goldmedal changed the base branch from main to feat/cli-0.2.0 April 4, 2026 12:27
@goldmedal goldmedal merged commit d7e9834 into Canner:feat/cli-0.2.0 Apr 4, 2026
9 checks passed
@goldmedal goldmedal deleted the plan-type-mapping branch April 4, 2026 12:30
goldmedal added a commit that referenced this pull request Apr 4, 2026
…e-mdl skill (#1513)

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant