# Model/cache generation

`rzcli model gen` provides SQL schema parsing and model/cache skeleton generation:

```bash
rzcli model gen -s examples/model-cache/schema.sql -d target/generated
```

Generated files:

- `Cargo.toml`
- `src/lib.rs`
- `src/entity.rs`
- `src/repository.rs`
- `src/cache.rs`
- `README.md`

The generator emits entity structs, repository traits, SQLx repositories when requested, cache key helpers, and optional cache-aside repositories. It does not implement an ORM, own database credentials, migrations, transaction boundaries, or database introspection.

## MySQL/goctl default path

The default SQL parser supports a practical MySQL `CREATE TABLE` subset:

- column name and type
- `NOT NULL`
- inline `PRIMARY KEY`
- table-level `PRIMARY KEY`
- `UNIQUE KEY`
- `KEY` / `INDEX`
- `DEFAULT`
- `COMMENT`
- `AUTO_INCREMENT`
- charset/collation/table comment metadata
- composite unique and normal indexes

Default SQLx generation remains SQLite-compatible for backward compatibility and can include a cache-aside repository:

```bash
rzcli model gen -s examples/model-cache/schema.sql -d target/generated --with-sqlx --with-redis-cache
```

Use an explicit MySQL SQLx backend when the generated skeleton should carry `rs_zero::db::MySqlDatabasePool`:

```bash
rzcli model gen \
  -s examples/model-cache/schema.sql \
  -d target/generated \
  --with-sqlx \
  --sqlx-backend mysql \
  --with-redis-cache
```

The MySQL type mapper covers common goctl fixture types and practical MySQL types such as unsigned integers, `decimal`, `datetime`, `timestamp`, `date`, `json`, `blob`/`binary`, `text` and `varchar`.

## PostgreSQL path

PostgreSQL support is explicit:

```bash
rzcli model gen \
  -s tests/fixtures/postgres/model/user.sql \
  -d target/generated \
  --dialect postgres \
  --with-sqlx \
  --with-redis-cache
```

With `--dialect postgres --with-sqlx`, the default SQLx backend is PostgreSQL and generated repositories use `rs_zero::db::PostgresDatabasePool`. Use `--sqlx-backend postgres` when you want the backend choice to be visible in scripts.

The PostgreSQL parser covers the project fixture subset:

- quoted identifiers and schema-qualified table names
- `SERIAL` / `BIGSERIAL`
- `GENERATED ... AS IDENTITY`
- table-level `PRIMARY KEY` and `UNIQUE` constraints
- `CREATE INDEX`
- `COMMENT ON TABLE` and `COMMENT ON COLUMN`
- common PostgreSQL types: integer family, boolean, text/varchar, uuid, json/jsonb, numeric/decimal, timestamp/timestamptz, date and bytea

## Cache-aside repository

When both `--with-sqlx` and `--with-redis-cache` are enabled, generated `src/repository.rs` includes `Cached{Entity}Repository<S>`. It uses `rs_zero::cache::CacheAside<S>` for primary-key and unique-index lookups, invalidates related keys after `save` / `delete_by_*`, and leaves normal non-unique indexes as DB-backed `find_all_by_*` methods. Generated `src/cache.rs` also exposes `CacheKey` helpers plus aliases for `RedisCacheStore`, `RedisShardedCacheStore`, `LruCacheStore`, and `TwoLevelCacheStore`.

```rust
use rs_zero::cache::{CacheAside, CacheAsideConfig, LruCacheStore, TwoLevelCacheStore};
use rs_zero::cache::redis::{RedisCacheConfig, RedisCacheStore};
use user_model::repository::{CachedUserRepository, SqlxUserRepository};

let sql_repo = SqlxUserRepository::new(pool);
let l1 = LruCacheStore::new(10_000)?;
let l2 = RedisCacheStore::new(RedisCacheConfig::default())?;
let cache = CacheAside::new(TwoLevelCacheStore::new(l1, l2), CacheAsideConfig::default());
let repo = CachedUserRepository::new(sql_repo, cache, "user-service");
```

## Boundaries

Applications still own credentials, transaction boundaries, migration tooling, pool lifecycle and deployment configuration. Default tests do not connect to external MySQL, PostgreSQL, or Redis services.
