sql-cli 1.71.3

SQL query tool for CSV/JSON with both interactive TUI and non-interactive CLI modes - perfect for exploration and automation
Documentation
# VimSearchAdapter: Lessons from a Failed Redux Pattern

## What Was Supposed to Happen

VimSearchAdapter was meant to be our first proper Redux-style component:
- **Listen to events** - Subscribe to key press events
- **Dispatch actions** - Send search actions to state manager
- **No direct dependencies** - Work only through state container
- **Clean separation** - UI logic separate from search logic

## What Actually Happened

### 1. Direct Dependencies Everywhere
```rust
pub fn handle_key(
    &mut self,
    key: KeyCode,
    dataview: &DataView,        // Direct DataView dependency!
    viewport: &mut ViewportManager,  // Direct ViewportManager!
    buffer: &dyn BufferAPI,     // Direct Buffer dependency!
) -> bool
```

### 2. No Event Subscription
Instead of subscribing to events:
```rust
// What we should have:
impl StateSubscriber for VimSearchAdapter {
    fn on_event(&mut self, event: StateEvent) {
        match event {
            StateEvent::KeyPress(key) => self.handle_key_event(key),
            // ...
        }
    }
}
```

We got direct method calls from TUI:
```rust
// What we actually have:
if self.vim_search_adapter.borrow().is_active() {
    self.vim_search_adapter.borrow_mut().exit_navigation();
}
```

### 3. Adapter Became Another Layer
Instead of being an adapter that decouples, it became another layer that adds complexity:
```
TUI → VimSearchAdapter → VimSearchManager
         ↓                    ↓
      Buffer              DataView
      ViewportManager
```

## Why It Failed

### 1. Started with Wrong Approach
- Added as a RefCell field in TUI instead of independent component
- Immediately given direct access to UI components
- No clear action/event system to work with

### 2. Incremental Coupling
- Each feature added more direct dependencies
- "Just pass the buffer for now" → permanent coupling
- "We'll refactor later" → technical debt

### 3. Missing Infrastructure
- No proper event bus/dispatcher
- No action system for state changes
- No clear state management pattern

## The Pattern We Keep Repeating

1. **Start with good intentions** - "Let's make this decoupled"
2. **Take shortcuts** - "Just pass Buffer directly for now"
3. **Add more coupling** - "Also needs DataView and ViewportManager"
4. **Never refactor** - "It works, let's move on"
5. **End up with mess** - Multiple layers of coupling

## What We Should Have Done

### 1. Built Infrastructure First
```rust
// Event system
enum SearchEvent {
    Start,
    UpdatePattern(String),
    NextMatch,
    PreviousMatch,
    Exit,
}

// Action dispatcher
impl AppStateContainer {
    pub fn dispatch_search(&mut self, event: SearchEvent) {
        // Handle search state changes
    }
}
```

### 2. Made Adapter Truly Independent
```rust
struct VimSearchAdapter {
    state: Rc<RefCell<AppStateContainer>>,
}

impl VimSearchAdapter {
    pub fn handle_key(&mut self, key: KeyCode) {
        let mut state = self.state.borrow_mut();
        match key {
            KeyCode::Char('n') => state.dispatch_search(SearchEvent::NextMatch),
            // ...
        }
    }
}
```

### 3. Kept UI Separate
- TUI only renders based on state
- Adapter only changes state
- No direct UI manipulation

## The Real Problem

**We keep adding abstraction layers without fixing the fundamental coupling.**

Each new layer (Adapter, Manager, etc.) still takes the same dependencies:
- Buffer
- DataView  
- ViewportManager

This just moves the coupling around instead of eliminating it.

## Solution Going Forward

1. **Stop adding layers** - Fix the root coupling issues
2. **Route through AppStateContainer** - Everything goes through state
3. **No direct UI access** - Components change state, UI renders state
4. **Event-driven** - Components subscribe to events, not direct calls

## Key Takeaway

**Adding an "Adapter" doesn't decouple anything if the adapter itself is tightly coupled.**

The VimSearchAdapter became just another tightly coupled component in the chain, proving that the name "Adapter" doesn't make something an adapter - the architecture does.