# config-easy

[![Crates.io](https://img.shields.io/crates/v/config-easy.svg)](https://crates.io/crates/config-easy)
[![Documentation](https://docs.rs/config-easy/badge.svg)](https://docs.rs/config-easy)
[![License](https://img.shields.io/crates/l/config-easy.svg)](https://gitlab.com/tw-libraries/rust/config-easy)
[![Rust Edition](https://img.shields.io/badge/edition-2024-blue.svg)](https://doc.rust-lang.org/edition-guide/rust-2024/)

`config-easy` is a small Rust crate for displaying and editing key/value settings stored in a SQLite table.

It is intended for command-line applications that want a simple interactive configuration menu, usually shown when the application is run with a `--config` option.

Applications remain responsible for schema creation, default values, typed configuration structs, CLI parsing, and app-specific behavior.

## Install

```toml
[dependencies]
config-easy = "0.1"
rusqlite = "0.32"
```

## Default Schema

```sql
CREATE TABLE IF NOT EXISTS settings (
    key TEXT PRIMARY KEY,
    value TEXT NOT NULL
);
```

## Basic Usage

```rust
let connection = rusqlite::Connection::open("app.db")?;

config_easy::run(&connection)?;
```

This uses:

- table: `settings`
- key column: `key`
- value column: `value`
- order by: `key`

## Builder Usage

```rust
config_easy::builder(&connection)
    .table("settings")
    .key_column("key")
    .value_column("value")
    .order_by("key")
    .run()?;
```

Table and column names are validated as simple SQL identifiers before being interpolated into SQL. Values are always bound as SQL parameters.

Valid identifiers are non-empty, start with an ASCII letter or `_`, and contain only ASCII letters, numbers, and `_`.

## Secret Values

```rust
config_easy::builder(&connection)
    .secret_keys(["my_api_key"])
    .run()?;
```

Non-empty secret values are displayed as `********`. Empty secret values are displayed as empty. The underlying value is not changed unless the user selects that setting and enters a new value.

## Validation

```rust
config_easy::builder(&connection)
    .validator(|key, value| {
        if key == "log_level" && !["debug", "info", "warn", "error"].contains(&value) {
            return Err(std::io::Error::new(
                std::io::ErrorKind::InvalidInput,
                "expected one of debug, info, warn, error",
            )
            .into());
        }

        Ok(())
    })
    .run()?;
```

Validation runs before a setting is updated.

Input values are trimmed before validation and saving.

## Custom Actions

```rust
config_easy::builder(&connection)
    .action("r", "reset delta link", |conn| {
        conn.execute("DELETE FROM sync_state WHERE key = 'delta_link'", [])?;
        println!("Delta link reset.");
        Ok(())
    })
    .run()?;
```

Custom actions are displayed in the prompt and run when their key is selected. Action keys cannot be empty, numeric, duplicated, `q`, or `quit`.

## Deliberately Not Included

- Creating the settings table
- Seeding default settings
- Parsing values into app-specific types
- CLI argument parsing
- Encryption or secure secret storage
- App-specific maintenance logic
