# 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.