Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
89 commits
Select commit Hold shift + click to select a range
007940e
refactor(python): fix signals logger name
Einswilli Jun 3, 2026
6372fef
refactor(python): fix transaction logger name
Einswilli Jun 3, 2026
61c5777
feat(python): implement logging from RYX_LOG_LEVEL env var
Einswilli Jun 3, 2026
8bd95ed
feat(python): add logging for bulk operations
Einswilli Jun 3, 2026
c4c3c18
feat(python): add logging for caching operations
Einswilli Jun 3, 2026
fb184e8
feat(python): wire CLI debug/verbose flags to logging
Einswilli Jun 3, 2026
3017d15
feat(python): add debug logs for CRUD operations
Einswilli Jun 3, 2026
15f7985
feat(python): log raw parameterized query executions
Einswilli Jun 3, 2026
8a24030
feat(python): log select_related execution
Einswilli Jun 3, 2026
8c600e9
feat(python): log global router configuration
Einswilli Jun 3, 2026
56a1379
feat(python): initialize Rust tracing from Python module
Einswilli Jun 3, 2026
7deb521
feat(query): add debug trace during query compilation
Einswilli Jun 3, 2026
3a7db91
feat(query): add debug trace during lookup registration
Einswilli Jun 3, 2026
a55960b
feat(rs): add init_tracing and call it on init
Einswilli Jun 3, 2026
6e35d39
chore: update dependencies and Lockfile for tracing
Einswilli Jun 3, 2026
eb9cddc
feat(logging): support silencing via NO_LOG/OFF/SILENT in RYX_LOG_LEVEL
Einswilli Jun 3, 2026
73c862e
feat(migrations): extract standalone helpers and add database alias s…
Einswilli Jun 3, 2026
a9709da
feat(cli): add --alias option to makemigrations command
Einswilli Jun 3, 2026
74e0e2e
feat(cli): support --no-interactive and configure migration directory…
Einswilli Jun 3, 2026
615d71d
feat(migrations): implement file-based migrations, database tracking,…
Einswilli Jun 3, 2026
06f5d85
feat(cli): add color and formatting utilities for CLI output
Einswilli Jun 3, 2026
5f19f05
feat(migrations): inject model references in operations and auto-impo…
Einswilli Jun 3, 2026
9794404
refactor(cli): use new style module in makemigrations output
Einswilli Jun 3, 2026
9281c54
refactor(cli): cleanup imports and apply styling in migrate command
Einswilli Jun 3, 2026
d1dd73e
feat(migrations): implement flat discovery, per-alias operation routi…
Einswilli Jun 3, 2026
b0b0a3d
docs: update CLI documentation for new flags and colored output
Einswilli Jun 3, 2026
00a7482
docs: overhaul migrations documentation with multi-DB and file format…
Einswilli Jun 3, 2026
e7dd698
docs: update API reference with multi-DB migration examples
Einswilli Jun 3, 2026
c049549
refactor(cli): update module docstring with new flags and examples
Einswilli Jun 3, 2026
52d4137
refactor(cli): apply styling and recursive discovery to showmigrations
Einswilli Jun 3, 2026
1eec993
refactor(cli): apply styling and recursive discovery to sqlmigrate
Einswilli Jun 3, 2026
13c2477
docs(migrations): rewrite autodetect module docstring for new format
Einswilli Jun 3, 2026
df49e97
docs(migrations): update runner module docstring for flat discovery
Einswilli Jun 3, 2026
25e7042
Merge remote-tracking branch 'upstream/master' into new_design
Einswilli Jun 3, 2026
8b82eca
feat(rs): add database() method to Model trait for multi-DB routing
Einswilli Jun 3, 2026
a90b6b8
feat(macro): support #[database] attribute for Model derive
Einswilli Jun 3, 2026
ccbea45
feat(rs): add YAML-serializable migration operations
Einswilli Jun 3, 2026
b1635b2
feat(rs): extract DDL generator to dedicated module
Einswilli Jun 3, 2026
89bbb22
feat(rs): add YAML migration file discovery and I/O
Einswilli Jun 3, 2026
54cad0c
feat(rs): add Rust-native autodetector for migrations
Einswilli Jun 3, 2026
8eab4ad
feat(rs): add file-based migration runner with live fallback
Einswilli Jun 3, 2026
73d172d
refactor(rs): restructure migration module with submodules and Serial…
Einswilli Jun 3, 2026
4092851
feat(cli): add ANSI color helpers for Rust CLI
Einswilli Jun 3, 2026
719043e
feat(cli): add clap-based CLI binary for migrations
Einswilli Jun 3, 2026
f97950d
feat(rs): export cli module
Einswilli Jun 3, 2026
3ec99d3
chore: add clap workspace dependency
Einswilli Jun 3, 2026
13f6756
chore(rs): add clap dependency and binary target
Einswilli Jun 3, 2026
a7b4955
test(rs): enable live mode in full pipeline test
Einswilli Jun 3, 2026
5ddfeb8
test(rs): enable live mode in migration tests
Einswilli Jun 3, 2026
0c68f79
test(rs): enable live mode in relation tests
Einswilli Jun 3, 2026
38926c7
chore: update Cargo.lock
Einswilli Jun 3, 2026
0c9511f
docs(rust): rewrite migrations guide with YAML format, CLI, multi-DB …
Einswilli Jun 3, 2026
a5bd9af
docs(rust): update quick start with live mode and file-based migratio…
Einswilli Jun 3, 2026
27884f9
docs(rust): update comparison table with CLI and multi-DB entries
Einswilli Jun 3, 2026
c8a1f9b
feat(query): support schema parameter in AST and build_plan
Einswilli Jun 6, 2026
71d7e19
feat(query): add schema method to QuerySet
Einswilli Jun 6, 2026
335826d
feat(migrations): support multi-schema states and diffing
Einswilli Jun 6, 2026
2bbb32b
feat(migrations): implement PostgreSQL schema qualification
Einswilli Jun 6, 2026
e10a32c
feat(migrations): serialize schema parameter in migration operations
Einswilli Jun 6, 2026
72fdfcf
feat(migrations): implement schema mapping in Autodetector
Einswilli Jun 6, 2026
c3c2fc0
feat(migrations): query PostgreSQL schema metadata in introspection
Einswilli Jun 6, 2026
063fb80
feat(migrations): run DDL statements with schema qualification
Einswilli Jun 6, 2026
2ccaa05
feat(cli): support schema flag in CLI commands
Einswilli Jun 6, 2026
94ec56f
test(migrations): add unit tests for PostgreSQL multi-schema support
Einswilli Jun 6, 2026
2889700
test(python): scope clean_tables fixture to integration tests only
Einswilli Jun 6, 2026
98fc65d
test(rs): add PostgreSQL multi-schema integration test
Einswilli Jun 6, 2026
fd8f7f2
test(python): add PostgreSQL multi-schema integration test
Einswilli Jun 6, 2026
02e366d
docs: add development summary for PostgreSQL multi-schema support
Einswilli Jun 6, 2026
bbbddf4
docs(readme): update Rust version badge to 1.93+ and add PostgreSQL s…
Einswilli Jun 6, 2026
1e2f6fb
docs(advanced): add PostgreSQL Multi-Schema navigation link
Einswilli Jun 6, 2026
cc40d0e
docs(multi-db): add cross-reference to PostgreSQL Multi-Schema
Einswilli Jun 6, 2026
71d7cb2
docs(python/migrations): add --schema CLI flag and PostgreSQL schemas…
Einswilli Jun 6, 2026
889f16f
docs(rust/migrations): add schema support to MigrationRunner and DDLG…
Einswilli Jun 6, 2026
a9421dd
docs(advanced): add PostgreSQL Multi-Schema documentation
Einswilli Jun 6, 2026
1af7f62
fix(lookups): ensure registry initialization before access in registe…
Einswilli Jun 7, 2026
a757a70
docs(cli): rewrite CLI documentation with configuration, plugins, and…
Einswilli Jun 8, 2026
88996c2
docs(python/migrations): rename --alias to --database for migrate com…
Einswilli Jun 8, 2026
3c006df
docs(rust/migrations): update CLI reference with --database for migra…
Einswilli Jun 8, 2026
7be4dda
docs(performance): remove specific numbers and LaTeX notation for acc…
Einswilli Jun 8, 2026
48b1b0a
docs(intro): update description to dual-language ORM, fix version bad…
Einswilli Jun 8, 2026
3fef7ad
docs(api-reference): expand to complete Python API surface with examples
Einswilli Jun 8, 2026
60d1172
docs(field-reference): expand to complete field reference with valida…
Einswilli Jun 8, 2026
d1541b1
docs(rust/queryset): clarify ObjectsManager as canonical entry point
Einswilli Jun 8, 2026
a2c813c
docs(rust/quick-start): update all examples to use ObjectsManager
Einswilli Jun 8, 2026
1030acb
docs(rust/index): add ObjectsManager explanation and update compariso…
Einswilli Jun 8, 2026
167f2c0
docs(sidebar): add configuration-and-routing, postgres-multi-schema, …
Einswilli Jun 8, 2026
249b0ba
docs(advanced): add configuration and routing documentation
Einswilli Jun 8, 2026
a7d291b
docs(rust): add Rust API reference documentation
Einswilli Jun 8, 2026
545bcfa
docs(readme): update description, add feature map, and modernize Rust…
Einswilli Jun 8, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 90 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@ once_cell = "1"
toml = "0.8"
serde_yaml = "0.9"

# CLI (ryx-rs binary)
clap = { version = "4", features = ["derive"] }

# tracing: structured, async-aware logging. We instrument every SQL execution
# so users can enable RUST_LOG=ryx=debug for full query visibility.
tracing = "0.1"
Expand Down
31 changes: 27 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<h1 align="center">Ryx ORM</h1>

<p align="center">
<strong>Django-style ORM Python and Rust. Powered by Rust.</strong>
<strong>Django-style ORM for Python and Rust. Powered by a shared Rust SQL engine.</strong>
</p>

<p align="center">
Expand All @@ -28,7 +28,7 @@

```python
import ryx
from ryx import Model, CharField, Q
from ryx import Model, BooleanField, CharField, IntField, Q

class Post(Model):
title = CharField(max_length=200)
Expand All @@ -41,6 +41,7 @@ posts = await Post.objects.filter(Q(active=True) | Q(views__gte=1000))

```rust
use ryx_rs::model;
use ryx_rs::{ObjectsManager, Q};

#[model]
struct Post {
Expand All @@ -50,7 +51,8 @@ struct Post {
active: bool,
}

let posts = Post::objects()
let posts = ObjectsManager::<Post>::new()
.all()
.filter(Q::or(Q::new("active", true), Q::new("views__gte", 1000)))
.all().await?;
```
Expand All @@ -68,6 +70,26 @@ Full docs, guides, API reference: **[ryx.alldotpy.com](https://ryx.alldotpy.com)

- [Python quick start](https://ryx.alldotpy.com/getting-started/quick-start)
- [Rust quick start](https://ryx.alldotpy.com/getting-started/installation)
- [API reference](https://ryx.alldotpy.com/reference/api-reference)
- [CLI](https://ryx.alldotpy.com/advanced/cli)
- [Configuration and routing](https://ryx.alldotpy.com/advanced/configuration-and-routing)

## Feature Map

| Area | Python API | Rust API |
|---|---|---|
| **Models** | `Model`, `Field`, `Meta`, hooks | `#[model]`, `Model`, `FromRow`, metadata |
| **Fields** | Auto, integer, numeric, text, date/time, JSON, array, binary, relation fields | Macro-derived field metadata |
| **Queries** | Lazy async `QuerySet`, `Q`, lookups, transforms, joins, values, annotations | `QuerySet<T>`, `Q`, lookups, values, annotations |
| **CRUD** | `create`, `save`, `get`, `first`, `count`, `update`, `delete`, `refresh_from_db` | `InsertBuilder`, `all`, `get`, `first`, `count`, `update`, `delete` |
| **Bulk/streaming** | `bulk_create`, `bulk_update`, `bulk_delete`, chunked/keyset stream | streaming chunks through `QueryStream` |
| **Transactions** | `async with transaction()` with savepoints | `transaction(|tx| async move { ... })` |
| **Migrations** | autodetect, DDL generation, runner, CLI | state diffing, DDL generation, runner |
| **Multi-db** | aliases, `.using()`, `Meta.database`, router, env/config auto-init | aliases, `.using()`, config init |
| **PostgreSQL schemas** | `.schema()`, schema-aware migrations | `.schema()` |
| **Caching** | `MemoryCache`, `QuerySet.cache()`, invalidation helpers | cache backend and cached queryset |
| **Signals/hooks** | pre/post save/delete/update and model hooks | not part of Rust surface |
| **Raw SQL** | raw fetch/execute and parameterized helpers | backend/query crates |

## Comparison

Expand All @@ -76,8 +98,9 @@ Full docs, guides, API reference: **[ryx.alldotpy.com](https://ryx.alldotpy.com)
| **API style** | Schema-first | Verbose builders | **Django-like** |
| **Q objects (OR/AND/NOT)** | ❌ | ❌ | ✅ |
| **Lookups** | Basic | Basic | **30+** |
| **select_related** | ❌ | ✅ (Eager) | |
| **select_related** | ❌ | ✅ (Eager) | Rust API; Python currently uses explicit `.join()` |
| **Migrations** | Diesel CLI | sea-orm-cli | **Built-in** |
| **PostgreSQL schemas** | ❌ | ❌ | ✅ |
| **Backends** | PG · MySQL · SQLite | PG · MySQL · SQLite | **PG · MySQL · SQLite** |

## Architecture
Expand Down
106 changes: 106 additions & 0 deletions RYK.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
## Goal
- Complete multi-schema support for PostgreSQL across migration, query, and CLI layers in both Rust and Python, then add comprehensive tests.

## Constraints & Preferences
- Models are **schema-agnostic** — no `#[schema]` on models. Schema is specified at query time (`.schema("name")` on QuerySet) or migration time (`.schema("name")` on runner).
- `schema=""` (default) means the backend's default schema (public for PG, ignored for MySQL/SQLite). No qualification in SQL when unset → 100% backward compat.
- Composite key `(schema, table_name)` everywhere: `diff_states`, introspection, DDL generation.
- `CREATE SCHEMA IF NOT EXISTS` is automatic in the runner (when schema is non-empty and backend supports it).
- Schema support is **PostgreSQL only** — MySQL/SQLite treat schema field as no-op (`supports_schemas()` returns `false` for non-PG).
- Performance: `Option<Symbol>` in QueryNode (not `Option<String>`), `supports_schemas()` is a `const fn`, qualification done once per SQL compile (not per row).
- Rust `gen` is reserved in edition 2024 — use `ddl_gen` instead of `gen` as variable name.

## Progress
### Done
- **Rust — Backend.supports_schemas()** added to `ryx-query/src/backend.rs` as a `const fn`.
- **Rust — TableState.schema**, **SchemaChange.schema**, **ChangeKind::CreateSchema** — all core types updated. `diff_states()` rewritten with composite key `(schema, name)`.
- **Rust — DDLGenerator.schema** with `in_schema()` builder, `qn()` helper, `create_schema()`. All DDL methods (`create_table`, `drop_table`, `add_column`, `drop_column`, `alter_column`, `create_index`, `drop_index`, `add_check_constraint`, `add_foreign_key`) use `self.qn()`. `generate()` handles `CreateSchema` in zeroth pass.
- **Rust — Operations** (`operations.rs`): `CreateSchema` variant, `schema: String` on all table operations, `schema()` accessor.
- **Rust — Autodetect** (`autodetect.rs`): `ModelEntry.schema`, `build_target()` schema apply, `changes_to_operations()` emits `CreateSchema` + schema pass-through.
- **Rust — Runner** (`runner.rs`): `FileRunner.schema`, `.schema()` builder, schema-aware `run_live()`, `plan_live()`, `apply_files()`, schema override per operation in `apply_files()`/`plan_files()`. `operation_to_sql()` handles `CreateSchema`.
- **Rust — Introspection**: PostgreSQL uses `table_schema = '{schema}'`, MySQL/SQLite set `schema: ""`.
- **Rust — Query layer** (`ryx-query/src/ast.rs`): `QueryNode.schema` (`Option<Symbol>`), `with_schema()` builder. Compiler (`compilr.rs`): `write_table_ref()` / `write_join_table_ref()` helpers, all compile functions (`SELECT`, `COUNT`, `DELETE`, `UPDATE`, `INSERT`, `JOIN`) use schema qualification. Plan hash includes `node.schema`.
- **Rust — QuerySet** (`ryx-rs/src/queryset.rs`): `.schema()` builder method.
- **Rust — CLI** (`ryx-rs/src/main.rs`): `--schema` flag on `Migrate` and `Sqlmigrate` subcommands, passed to `FileRunner.schema()` and `DDLGenerator.in_schema()`.
- **Python — state.py**: `TableState.schema`, `ChangeKind.CREATE_SCHEMA`, `SchemaChange.schema`, `diff_states()` composite key + CreateSchema detection. `to_json()`/`from_json()` schema-aware.
- **Python — ddl.py**: `DDLGenerator.schema` parameter, `_qn()` helper, `create_schema()`. All DDL methods use `_qn()` for table references. `generate_schema_ddl()` creates per-table schema DDLGenerator.
- **Python — autodetect.py**: `schema: str` on all operation types (`CreateTable`, `AddField`, `AlterField`, `CreateIndex`), `to_python()` serialization includes schema, `apply_migration_to_state()` preserves schema on tables, `_changes_to_operations()` passes schema from changes.
- **Python — runner.py**: `_schema` on `MigrationRunner`, `.schema()` builder, `_create_ddl()` helper, schema-aware `_operation_to_ddl()`, `_ddl_for_change()`, `_introspect_schema()`, `_get_tables()`, `_get_columns()`, `_apply_meta_extras()`, `_ensure_m2m_table()`.
- **Python — query layer**: `QuerySet.schema()` method adds `("schema", name)` op to ops list. Rust `build_plan()` in `ryx-python/src/plan.rs` handles `"schema"` op via `node.with_schema()`.
- **Python — CLI**: `--schema` flag on `migrate`, `sqlmigrate`, `inspectdb` commands in `ryx-python/ryx/__main__.py`, `ryx-python/ryx/cli/commands/migrate.py`, `sqlmigrate.py`, `inspectdb.py`.
- **Rust unit tests** — **30 new multi-schema tests added** (75 unit total):
- migration.rs: 7 multi-schema diff tests (CreateSchema detection, same table different schemas, empty/noop/mixed)
- ddl.rs: 20 schema-qualified DDL tests (create_schema, create_table, alter, drop, index, FK, constraint, MySQL/SQLite ignore, backward compat)
- operations.rs: 7 operation schema tests (all variants)
- compilr.rs: 12 schema query tests (SELECT/COUNT/DELETE/UPDATE/INSERT/JOIN with schema, MySQL/SQLite ignore, plan hash differential)
- **Python unit tests** — **42 new tests added**:
- test_migration_state.py: 11 tests (diff_states composite key, CreateSchema detection, serialization)
- test_migration_ddl.py: 17 tests (create_schema, qualified names, all DDL methods, backward compat)
- test_migration_autodetect.py: 10 tests (operation schema fields, to_python, apply_migration_to_state, AddField schema inheritance)
- **Rust integration test**: `ryx-rs/tests/multi_schema_test.rs` — full multi-schema pipeline: migrate tenant1, migrate tenant2, verify table isolation across schemas, insert/query data independently, cleanup. Uses `PG_TEST_URL` env var (defaults to `postgres://einswilli@localhost/ryx_integration_test`). Passes.
- **Python integration test**: `ryx-python/tests/integration/test_multi_schema.py` — same pipeline, runs in subprocess to avoid conftest's SQLite pool. Overrides `setup_database` and `clean_tables` fixtures. Passes.

### In Progress
- (none — feature complete)

### Blocked
- Python `_handle_no_migration_files` interactive prompt blocks automated migration testing (no `live` flag). Tests work around it by monkeypatching `input()`.

## Key Decisions
- **Schema at query/migration time, not on model**: Models stay agnostic → one model works in N schemas without duplication.
- **Empty string = no schema = backward compat**: All existing code continues to work unchanged. Schema qualification only activates when explicitly set.
- **`Option<Symbol>` vs `Option<String>` in QueryNode**: `Option<Symbol>` for interned performance, `None` = no qualification.
- **Composite key `(schema, name)` everywhere**: Enables correct diff across schemas. No schema = empty string matches "no schema" (no `CreateSchema` emitted).
- **`CREATE SCHEMA IF NOT EXISTS` is automatic**: Runner creates schema before tables when schema is non-empty and backend supports schemas. Not part of migration files (idempotent).
- **Per-op schema override**: Each operation can carry its own schema, allowing mixed-schema migration files (unlikely but supported).
- **Temporary DDLGenerator per change**: Used in `generate()`, `apply_files()`, `plan_files()` to switch schema context. Acceptable cost since migration ops are rare.
- **Python QuerySet delegates schema to Rust FFI**: `("schema", name)` op is stored in ops list and handled by Rust `build_plan()`. This means all SQL compilation is schema-aware with zero additional Python overhead.
- **Integration tests run in subprocess for Python**: The `ryx` package auto-initializes the pool from `ryx.toml` at import time. Python's conftest also inits a SQLite pool. PG tests must run separately via subprocess with `RYX_AUTO_INITIALIZE=0`.

## Next Steps
1. Add `live=True` flag to Python `MigrationRunner` to skip interactive prompt in tests (feature gap).
2. Documentation update: multi-schema section in migrations.mdx, `.schema()` API reference.

## Critical Context
- **Rust integration tests**: 76 unit + 2 integration (SQLite full pipeline + PG multi-schema).
- **Python integration tests**: 42 unit + 1 integration (PG multi-schema via subprocess).
- `diff_states()` matches tables by `(schema, name)` composite key. Two tables with same name in different schemas are treated as different tables. `CreateSchema` is emitted for schemas with non-empty string.
- `DDLGenerator.qn()` produces `"schema"."table"` when schema is non-empty and backend supports schemas. For MySQL/SQLite, `supports_schemas()` → `false` eliminates qualification at compile time.
- `QueryNode.with_schema(schema)` interns the schema name as `Symbol`. The compiler's `write_table_ref()` checks `node.backend.supports_schemas()` at compile time.
- Python `QuerySet.schema()` adds an op that the Rust FFI `build_plan()` converts to `node.with_schema()`. The same Rust compiler handles qualification.
- `__main__.py` has two parser code paths: the old argparse-based `_build_parser()` and the new registry-based `build_parser()`. `--schema` was added only to `_build_parser()` for now.
- `inspectdb.py` hardcodes `table_schema = 'public'` for PostgreSQL introspection (the `--schema` flag passes through to the runner layer).
- Integration test requires a running PostgreSQL on localhost:5432 with user `einswilli` (no password) and a `ryx_integration_test` database.
- Python `ryx` package has `ryx/__init__.py:_auto_setup()` that reads `ryx.toml` and initializes the pool at `import ryx` time. Set `RYX_AUTO_INITIALIZE=0` to prevent this.
- Python conftest adds `setup_database` (session-scoped, SQLite) and `clean_tables` (autouse, async) to all integration tests. PG tests must override both.

## Relevant Files
- **Rust modified**:
- `ryx-query/src/ast.rs`: `QueryNode.schema` + `with_schema()`.
- `ryx-query/src/compiler/compilr.rs`: `write_table_ref()`, `write_join_table_ref()`, all compile functions updated, plan hash includes schema.
- `ryx-query/src/backend.rs`: `supports_schemas()` const fn.
- `ryx-rs/src/migration.rs`: core types, `diff_states()`, introspection, test helpers, 7 new schema diff tests.
- `ryx-rs/src/migration/ddl.rs`: `DDLGenerator.in_schema()`, `qn()`, `create_schema()`, `generate()` zeroth pass, 20 new DDL schema tests.
- `ryx-rs/src/migration/operations.rs`: `CreateSchema` variant, `schema` on all ops, `schema()` accessor, 7 new operation schema tests.
- `ryx-rs/src/migration/autodetect.rs`: `ModelEntry.schema`, `build_target()` schema, `changes_to_operations()` CreateSchema.
- `ryx-rs/src/migration/runner.rs`: `FileRunner.schema`, `.schema()` builder, schema-aware run/plan/apply.
- `ryx-rs/src/queryset.rs`: `.schema()` builder method.
- `ryx-rs/src/main.rs`: `--schema` on Migrate/Sqlmigrate.
- **Python modified**:
- `ryx-python/ryx/migrations/state.py`: `TableState.schema`, `ChangeKind.CREATE_SCHEMA`, `SchemaChange.schema`, `diff_states()` composite key, `to_json()`/`from_json()` schema-aware.
- `ryx-python/ryx/migrations/ddl.py`: `DDLGenerator.schema`, `_qn()`, `create_schema()`, all DDL methods qualified, `generate_schema_ddl()` per-table schema.
- `ryx-python/ryx/migrations/autodetect.py`: `schema` on all operation types, `to_python()` includes schema, `apply_migration_to_state()` preserves schema.
- `ryx-python/ryx/migrations/runner.py`: `_schema`, `.schema()` builder, `_create_ddl()`, all internal methods schema-aware.
- `ryx-python/ryx/queryset.py`: `.schema()` method.
- `ryx-python/src/plan.rs`: `"schema"` op handler.
- `ryx-python/ryx/__main__.py`: `--schema` on migrate/sqlmigrate/inspectdb.
- `ryx-python/ryx/cli/commands/migrate.py`: `--schema` flag + pass to runner.
- `ryx-python/ryx/cli/commands/sqlmigrate.py`: `--schema` flag + DDLGenerator schema.
- `ryx-python/ryx/cli/commands/inspectdb.py`: `--schema` flag + schema-aware introspection.
- **Test files**:
- `ryx-rs/src/migration/operations.rs`: 7 new schema tests.
- `ryx-python/tests/unit/test_migration_state.py`: 11 new tests.
- `ryx-python/tests/unit/test_migration_ddl.py`: 17 new tests.
- `ryx-python/tests/unit/test_migration_autodetect.py`: 10 new tests.
- `ryx-rs/tests/multi_schema_test.rs`: PG multi-schema integration test.
- `ryx-python/tests/integration/test_multi_schema.py`: Python PG multi-schema integration test.
Loading
Loading