Metadata-Version: 2.4
Name: csdl-explore
Version: 0.1.0
Summary: Terminal explorer for OData CSDL metadata
License-Expression: MIT
License-File: LICENSE
Keywords: csdl,metadata,odata,sap,successfactors,tui
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Libraries
Classifier: Topic :: Utilities
Requires-Python: >=3.10
Requires-Dist: httpx>=0.27.0
Requires-Dist: networkx>=3.0
Requires-Dist: rich>=13.0.0
Provides-Extra: dev
Requires-Dist: pytest>=7.0.0; extra == 'dev'
Provides-Extra: tui
Requires-Dist: textual[syntax]>=0.40.0; extra == 'tui'
Description-Content-Type: text/markdown

# CSDL Explorer

A terminal explorer for OData CSDL metadata. Parse any `$metadata` XML and discover entities, properties, relationships, and field attributes — then query live OData services directly from the terminal.

**Features:**
- Interactive Rich REPL with colored tables and visual trees
- Full Textual TUI with tree navigation, tabbed views, and split panes
- Live OData queries with visual query builder (filter, select, expand, orderby)
- SAP SuccessFactors auth support (Bearer, Basic, OAuth2 SAML)
- Picklist exploration with impact analysis
- Headless mode for scripting and AI assistants
- Search across entity names, property names, labels, and picklist values
- Entity comparison, custom field discovery, navigation graphs
- Switchable color themes

## The Problem

OData services expose their schema through `$metadata` but those XML documents can be enormous (10MB+, 700+ entities). This tool parses the CSDL and gives you fast, searchable access to every entity, property, navigation relationship, and annotation.

Particularly useful with **SAP SuccessFactors**, where documentation says "Worker Category" but the actual field is `customString17`.

## Installation

```bash
pip install csdl-explore
```

For the full Textual TUI (tree navigation, split panes, query builder):
```bash
pip install csdl-explore[tui]
```

Or from source:
```bash
git clone https://github.com/guinetik/csdl-explore
cd csdl-explore
pip install -e .        # Basic install
pip install -e ".[tui]" # With Textual TUI
```

## Quick Start

```bash
# Point at any OData $metadata XML file
csdl-explore metadata.xml

# Search for fields
csdl-explore metadata.xml search contract

# Show entity details
csdl-explore metadata.xml entity EmpJob

# Launch full TUI with tree navigation
csdl-explore metadata.xml --tui

# Query a live OData service
csdl-explore metadata.xml query EmpJob --select "userId,company" --top 5
```

## Usage

```bash
# Start interactive explorer (default)
csdl-explore metadata.xml

# Or with --file flag
csdl-explore --file metadata.xml entity EmpJob

# With connection settings
csdl-explore metadata.xml --base-url https://api.example.com --auth-type bearer --bearer-token TOKEN
```

## Interactive Mode

```
$ csdl-explore metadata.xml

╭─────────────────────────────────────────╮
│             CSDL Explorer               │
│         Loaded 735 entities             │
╰─────────────────────────────────────────╯

csdl> search contract
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Search Results (4)                             ┃
┣━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━┫
┃ Type   ┃ Entity    ┃ Match           ┃ Details ┃
┣━━━━━━━━╋━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━━━━━┫
┃ PROP   ┃ EmpJob    ┃ .contractType   ┃ String  ┃
┃ NAV    ┃ EmpJob    ┃ .contractTypeNav┃         ┃
┗━━━━━━━━┻━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━━━━━┛

csdl> tree EmpJob
EmpJob
├── Keys
│   ├── seqNumber Edm.Int64
│   ├── startDate Edm.DateTime
│   └── userId Edm.String
├── Properties (45)
│   ├── businessUnit Edm.String
│   ├── company Edm.String
│   └── ... and 42 more
├── Lookups (12)
│   ├── businessUnit -> FOBusinessUnit
│   └── ... and 9 more
├── Custom Fields (24)
│   ├── customString7 Edm.String
│   └── ... and 23 more
└── Navigation (8)
    ├── employmentNav -> EmpEmployment
    └── ... and 7 more
```

## Commands

### Metadata Exploration

| Command | Aliases | Description |
|---------|---------|-------------|
| `entities` | | List all entity types (multi-column on wide terminals) |
| `entity <name>` | `e` | Show all properties of an entity |
| `tree <name>` | `t` | Show entity as visual tree with relationships |
| `model [entities]` | | Show data model overview |
| `search <term>` | `s` | Search entities and properties |
| `custom <entity>` | `c` | Show custom fields (customStringXX) |
| `nav <entity>` | | Show navigation properties |
| `diff <e1> <e2>` | | Compare two entities |
| `path <entity>` | `paths` | Suggest JSON paths |
| `emp` | | List Emp* entities (SAP SuccessFactors) |
| `per` | | List Per* entities (SAP SuccessFactors) |

### Picklists

| Command | Aliases | Description |
|---------|---------|-------------|
| `picklists` | | List all picklists used across entities (JSON) |
| `picklist <name>` | `pk` | Fetch picklist values from live API (JSON) |
| `batch-picklists <entity>` | | Fetch all picklist values for an entity's fields |

### OData Queries

| Command | Description |
|---------|-------------|
| `query <entity>` | Execute an OData query against a live service |

**Query flags:**

| Flag | Description |
|------|-------------|
| `--select "<props>"` | Comma-separated properties to return |
| `--filter "<expr>"` | OData `$filter` expression |
| `--orderby "<prop>"` | Property to sort by |
| `--orderby-dir "asc\|desc"` | Sort direction (default: asc) |
| `--top <n>` | Result limit (default: 20) |
| `--expand "<navs>"` | Navigation properties to expand |
| `--asof-date "<date>"` | Point-in-time query |
| `--from-date "<date>"` | Date range start |
| `--to-date "<date>"` | Date range end |

**Example:**
```bash
csdl-explore metadata.xml query EmpJob \
  --select "userId,company,businessUnit" \
  --filter "company eq 'ACME'" \
  --top 10
```

## Options

| Option | Description |
|--------|-------------|
| `--file <file>` | Path to metadata XML file |
| `--tui` | Launch full Textual TUI |
| `--base-url <url>` | OData service base URL |
| `--auth-type <type>` | Auth type: `none`, `bearer`, `basic`, `oauth2` |
| `--bearer-token <token>` | Bearer token for API access |
| `--username <user>` | Username for basic auth |
| `--password <pass>` | Password for basic auth |
| `--format <fmt>` | Output format: `table` (default), `json`, `json-compact`, `csv` |
| `--wide` | Show full column widths (no truncation) |
| `--filter <pattern>` | Filter properties by name glob pattern (e.g. `"custom*"`) |
| `--json-only` | JSON output only, no banner (for agents/scripts) |

Connection settings can also be loaded from a `.env` file placed alongside the metadata XML, or from environment variables (`SAP_BASE_URL`, `SAP_AUTH_TYPE`, `SAP_BEARER_TOKEN`, etc.).

### Exit Codes

| Code | Meaning |
|------|---------|
| `0` | Success |
| `1` | General error |
| `2` | Invalid input (bad args, missing params) |
| `3` | Network error (auth failure, HTTP error) |
| `4` | Not found (entity/picklist doesn't exist) |

## Full Textual TUI

For the best experience on large monitors, use the Textual TUI:

```bash
pip install csdl-explore[tui]
csdl-explore metadata.xml --tui
```

Features:
- **Tree navigation** - Browse entities by category (Emp*, Per*, alphabetical)
- **Split pane view** - Entity tree on left, tabbed details on right
- **Global search** - Search across all metadata from the sidebar
- **Fuzzy filter** - Type in any table to filter rows (fzf-style)
- **Entity tabs** - Details, Properties table, and Query sub-tabs per entity
- **Picklist tabs** - Overview, entity usage, impact analysis, and live value fetching
- **Query builder** - Visual form for OData queries with auth configuration
- **Results viewer** - Syntax-highlighted JSON/XML results with file export
- **Navigation graph** - Visualize entity relationships
- **Switchable themes** - Vercel dark, Classic, and more

**Keyboard shortcuts:**

| Key | Action |
|-----|--------|
| `/` | Focus search |
| `Escape` | Clear search |
| `t` | Toggle tree sidebar |
| `Ctrl+T` | Cycle theme |
| `Ctrl+W` | Close current tab |
| `q` | Quit |
| `?` | Show help |

## Headless Mode (for AI/Scripts)

All commands work without interactive mode, making it easy for AI assistants and scripts to discover fields:

```bash
csdl-explore metadata.xml search benefit
csdl-explore metadata.xml entity EmpJob
csdl-explore metadata.xml diff EmpCompensation EmpPayCompRecurring
csdl-explore metadata.xml tree EmpJob
csdl-explore metadata.xml picklists
csdl-explore metadata.xml query EmpJob --select "userId" --top 5
```

## Python API

```python
from csdl_explore import CSDLExplorer
from pathlib import Path

# Load from file
explorer = CSDLExplorer.from_file(Path("metadata.xml"))

# Search
results = explorer.search("worker")
for r in results:
    print(f"{r.entity}.{r.property}: {r.prop_type}")

# Get entity details
entity = explorer.get_entity("EmpJob")
for prop in entity.properties.values():
    print(f"{prop.name}: {prop.type} (label={prop.label})")

# Get custom fields
for prop in explorer.get_custom_fields("EmpJob"):
    print(f"{prop.name}: {prop.label} picklist={prop.picklist}")

# Compare entities
comp = explorer.compare_entities("EmpCompensation", "EmpPayCompRecurring")
print(f"Only in first: {comp.only_in_entity1[:5]}")

# Picklist usage across all entities
usage = explorer.get_picklist_usage()
for picklist, entities in usage.items():
    print(f"{picklist}: used by {entities}")
```

## Supported OData Services

Any OData service that exposes CSDL `$metadata` should work. Tested with:
- **SAP SuccessFactors** (full annotation support: labels, picklists, CRUD flags)
- **SAP S/4HANA OData**
- Standard OData v2/v3 services

The parser auto-detects annotation namespaces, so vendor-specific attributes (like `sap:label`, `sap:filterable`) are extracted automatically.

## Project Structure

```
csdl-explore/
├── pyproject.toml
├── README.md
└── src/
    └── csdl_explore/
        ├── __init__.py         # Package exports
        ├── cli.py              # CLI entry point & command dispatch
        ├── parser.py           # CSDL metadata parser
        ├── explorer.py         # High-level exploration API
        ├── formatters.py       # Pure data transforms (no UI imports)
        ├── themes.py           # Textual themes + Rich color palettes
        ├── repl.py             # Rich-based interactive REPL
        ├── sap_client.py       # Async OData HTTP client & auth
        ├── app.py              # Textual TUI application
        └── widgets/
            ├── entity_pane.py      # Entity tab container
            ├── details_tab.py      # Entity details sub-tab
            ├── properties_tab.py   # Filterable properties table
            ├── query_tab.py        # OData query sub-tab
            ├── query_builder.py    # Visual query form
            ├── connection_panel.py # Auth configuration panel
            ├── results_viewer.py   # Query results + export
            ├── picklist_pane.py    # Picklist tab container
            ├── entity_tree.py      # Sidebar tree widget
            ├── global_search.py    # Unified metadata search
            ├── filter_bar.py       # fzf-style filter bar
            ├── filterable_table.py # Reusable filterable DataTable
            ├── auth_modal.py       # Credential input modal
            ├── record_view_modal.py# Row detail viewer
            ├── nav_graph.py        # Navigation graph visualization
            └── welcome_tab.py      # Welcome screen
```

## License

MIT
