ferro-orm 0.16.3__tar.gz → 0.17.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/CHANGELOG.md +38 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/CONTEXT.md +20 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/Cargo.lock +79 -68
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/Cargo.toml +1 -1
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/PKG-INFO +1 -1
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/crates/ferro-ddl-lowering/src/lib.rs +7 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/crates/ferro-migrate/src/emit.rs +89 -10
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/crates/ferro-migrate/src/lib.rs +103 -1
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/crates/ferro-migrate/src/tests.rs +343 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/crates/ferro-schema-ir/src/lib.rs +263 -16
- ferro_orm-0.17.1/docs/adr/0007-reverse-relations-tested-not-traversed.md +62 -0
- ferro_orm-0.17.1/docs/adr/0008-predicate-negation-uniform-not.md +30 -0
- ferro_orm-0.17.1/docs/adr/0010-create-pass-owns-only-missing-tables.md +39 -0
- ferro_orm-0.17.1/docs/examples/existence_tests.py +195 -0
- ferro_orm-0.17.1/docs/examples/existence_tests_annotated.py +101 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/examples/predicates.py +42 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/examples/predicates_annotated.py +22 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/pages/api/queries.md +4 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/pages/concepts/architecture.md +1 -1
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/pages/faq.md +1 -1
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/pages/guide/migrations.md +3 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/pages/guide/queries.md +172 -4
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/pages/roadmap.md +2 -2
- ferro_orm-0.17.1/docs/plans/2026-07-18-016-existence-tests-design.md +161 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/pyproject.toml +1 -1
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/src/ferro/__init__.py +16 -4
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/src/ferro/columns.py +94 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/src/ferro/ir/compiler.py +5 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/src/ferro/models.py +4 -1
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/src/ferro/query/builder.py +48 -9
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/src/ferro/query/nodes.py +484 -24
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/src/ferro/query/wire.py +14 -7
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/src/introspect.rs +231 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/src/migrate.rs +51 -6
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/src/operations.rs +147 -29
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/src/query.rs +572 -4
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/src/schema.rs +13 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/fixtures/ir_vectors/README.md +7 -5
- ferro_orm-0.17.1/tests/fixtures/ir_vectors/query_account_exists_v7.json +40 -0
- ferro_orm-0.17.1/tests/fixtures/ir_vectors/query_account_scoped_exists_v7.json +74 -0
- ferro_orm-0.17.1/tests/fixtures/ir_vectors/query_owner_nested_exists_v7.json +47 -0
- ferro_orm-0.17.1/tests/fixtures/ir_vectors/query_owner_not_exists_v7.json +37 -0
- ferro_orm-0.16.3/tests/fixtures/ir_vectors/query_transaction_aggregate_v5.json → ferro_orm-0.17.1/tests/fixtures/ir_vectors/query_transaction_aggregate_v7.json +2 -2
- ferro_orm-0.16.3/tests/fixtures/ir_vectors/query_transaction_global_aggregate_v5.json → ferro_orm-0.17.1/tests/fixtures/ir_vectors/query_transaction_global_aggregate_v7.json +2 -2
- ferro_orm-0.16.3/tests/fixtures/ir_vectors/query_transaction_include_v5.json → ferro_orm-0.17.1/tests/fixtures/ir_vectors/query_transaction_include_v7.json +2 -2
- ferro_orm-0.16.3/tests/fixtures/ir_vectors/query_transaction_left_join_v5.json → ferro_orm-0.17.1/tests/fixtures/ir_vectors/query_transaction_left_join_v7.json +2 -2
- ferro_orm-0.16.3/tests/fixtures/ir_vectors/query_transaction_record_v5.json → ferro_orm-0.17.1/tests/fixtures/ir_vectors/query_transaction_record_v7.json +2 -2
- ferro_orm-0.16.3/tests/fixtures/ir_vectors/query_transaction_traversal_v5.json → ferro_orm-0.17.1/tests/fixtures/ir_vectors/query_transaction_traversal_v7.json +2 -2
- ferro_orm-0.16.3/tests/fixtures/ir_vectors/query_transaction_traversed_record_v5.json → ferro_orm-0.17.1/tests/fixtures/ir_vectors/query_transaction_traversed_record_v7.json +2 -2
- ferro_orm-0.16.3/tests/fixtures/ir_vectors/query_user_compound_v5.json → ferro_orm-0.17.1/tests/fixtures/ir_vectors/query_user_compound_v7.json +2 -2
- ferro_orm-0.17.1/tests/fixtures/ir_vectors/query_user_m2m_exists_v7.json +51 -0
- ferro_orm-0.17.1/tests/fixtures/ir_vectors/query_user_not_compound_v7.json +49 -0
- ferro_orm-0.17.1/tests/fixtures/ir_vectors/query_user_not_leaf_v7.json +44 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_auto_migrate.py +169 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_ir_vectors_contract.py +58 -7
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_migrate_plan.py +84 -0
- ferro_orm-0.17.1/tests/test_negation.py +226 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_query_builder.py +1 -1
- ferro_orm-0.17.1/tests/test_query_exists.py +707 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_query_joins.py +13 -1
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_query_wire_vectors.py +82 -10
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/.github/PERMISSIONS.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/.github/PYPI_CHECKLIST.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/.github/PYPI_SETUP.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/.github/generated/wheels.generated.yml +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/.github/pull_request_template.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/.github/workflows/ci.yml +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/.github/workflows/packaging-smoke.yml +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/.github/workflows/publish-docs.yml +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/.github/workflows/publish.yml +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/.github/workflows/release.yml +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/.gitignore +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/.pre-commit-config.yaml +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/.python-version +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/AGENTS.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/CONTRIBUTING.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/LICENSE +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/README.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/benchmarks/README.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/benchmarks/__init__.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/benchmarks/__main__.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/benchmarks/backends.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/benchmarks/baselines/postgres.json +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/benchmarks/baselines/sqlite.json +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/benchmarks/compare.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/benchmarks/harness.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/benchmarks/model.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/benchmarks/run.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/crates/ferro-ddl-lowering/Cargo.toml +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/crates/ferro-migrate/Cargo.toml +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/crates/ferro-migrate/src/order.rs +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/crates/ferro-schema-ir/Cargo.toml +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/adr/0001-resolved-epoch-registration.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/adr/0002-unified-column-fact-derivation.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/adr/0003-path-blind-db-type-validation.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/adr/0004-jsonb-postgres-only-canonical.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/adr/0005-jsonb-default-on-postgres.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/adr/0006-relation-traversal-inner-joins.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/adr/0007-materialization-plan-complete-instances.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/adr/0008-populated-relations-include.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/adr/0009-aggregate-projections-derived-grouping.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/agents/domain.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/agents/issue-tracker.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/agents/triage-labels.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/architecture-review-2026-07-08.html +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/brainstorms/2026-04-29-named-connections-role-routing-requirements.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/brainstorms/2026-05-08-typed-query-predicates-requirements.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/brainstorms/2026-05-13-configurable-column-storage-types-requirements.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/brainstorms/2026-05-14-autogenerate-support-for-db-type-requirements.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/brainstorms/2026-05-25-annotated-strenum-cold-hydration-requirements.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/brainstorms/2026-06-24-ir-p8-119-wire-automigrate-requirements.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/brainstorms/2026-06-25-ir-p8-120-parity-gate-requirements.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/brainstorms/2026-06-26-ir-p8.5-140-shared-lowering-requirements.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/brainstorms/2026-06-26-ir-p8.5-143-db-type-drop-requirements.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/brainstorms/2026-06-26-ir-p8.5-144-reconcile-indexes-requirements.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/brainstorms/2026-06-28-ir-p8.5-141-single-schema-ir-producer-requirements.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/brainstorms/2026-06-29-ir-p8.6-146-dialect-enum-unification-requirements.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/brainstorms/2026-06-29-ir-p8.6-153-create-path-ir-requirements.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/brainstorms/2026-06-30-ir-p8.6-155-deferred-annotations-requirements.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/brainstorms/2026-06-30-ir-p8.6-158-check-renderer-requirements.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/brainstorms/2026-07-01-ir-p8.6-154-datetime-tz-coarseness-requirements.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/brainstorms/2026-07-01-ir-p8.6-162-typed-save-bind-requirements.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/brainstorms/2026-07-01-ir-p8.6-165-blob-introspection-false-positive-requirements.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/brainstorms/2026-07-02-ff-c1-codec-plan-design.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/brainstorms/2026-07-06-upgrade-guide-consolidation-requirements.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/examples/aggregations.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/examples/aggregations_annotated.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/examples/multiple_databases.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/examples/mutations.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/examples/pagination.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/examples/partial_selects.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/examples/partial_selects_annotated.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/examples/populated_relations.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/examples/populated_relations_annotated.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/examples/quickstart.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/examples/quickstart_annotated.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/examples/raw_sql.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/examples/relationships.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/examples/relationships_annotated.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/examples/soft_deletes.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/examples/soft_deletes_annotated.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/examples/testing_conftest.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/examples/timestamps.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/examples/timestamps_annotated.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/examples/transactions.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/examples/traversal.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/examples/traversal_annotated.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/pages/api/connection.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/pages/api/exceptions.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/pages/api/fields.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/pages/api/migrations.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/pages/api/model.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/pages/api/raw-sql.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/pages/api/relationships.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/pages/api/transactions.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/pages/changelog.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/pages/concepts/backends.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/pages/concepts/identity-map.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/pages/concepts/performance.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/pages/concepts/query-typing.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/pages/concepts/type-safety.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/pages/contributing.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/pages/getting-started/installation.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/pages/getting-started/next-steps.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/pages/getting-started/quickstart.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/pages/guide/aggregations.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/pages/guide/connections.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/pages/guide/models-and-fields.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/pages/guide/mutations.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/pages/guide/raw-sql.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/pages/guide/relationships.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/pages/guide/transactions.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/pages/howto/migrate-from-sqlalchemy.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/pages/howto/multiple-databases.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/pages/howto/pagination.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/pages/howto/soft-deletes.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/pages/howto/testing.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/pages/howto/timestamps.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/pages/howto/upgrade-guide.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/pages/index.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/pages/stylesheets/extra.css +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/pages/why-ferro.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/plans/2026-04-24-001-refactor-multi-db-backend-architecture-plan.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/plans/2026-04-29-001-typed-null-binds-plan.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/plans/2026-04-29-002-feat-named-connections-plan.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/plans/2026-05-07-001-refactor-generic-model-connection-plan.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/plans/2026-05-08-001-feat-typed-query-predicates-plan.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/plans/2026-05-13-001-feat-configurable-column-storage-types-plan.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/plans/2026-05-25-001-fix-annotated-strenum-cold-hydration-plan.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/plans/2026-06-19-001-ir-first-roadmap.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/plans/2026-06-24-001-feat-ir-p8-119-wire-automigrate-plan.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/plans/2026-06-25-001-feat-ir-p8-120-parity-gate-plan.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/plans/2026-06-26-001-feat-ir-p8.5-140-shared-lowering-plan.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/plans/2026-06-26-002-feat-ir-p8.5-143-db-type-drop-plan.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/plans/2026-06-26-003-feat-ir-p8.5-144-reconcile-indexes-plan.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/plans/2026-06-28-001-feat-ir-p8.5-141-single-schema-ir-producer-plan.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/plans/2026-06-29-001-refactor-ir-p8.6-153-create-path-unification-plan.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/plans/2026-06-29-002-refactor-ir-p8.6-146-dialect-enum-unification-plan.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/plans/2026-06-30-001-refactor-ir-p8.6-158-check-renderer-plan.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/plans/2026-06-30-002-fix-ir-p8.6-155-deferred-annotations-plan.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/plans/2026-07-01-001-feat-ir-p8.6-162-typed-save-bind-plan.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/plans/2026-07-01-002-fix-ir-p8.6-154-datetime-tz-coarseness-plan.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/plans/2026-07-01-003-fix-ir-p8.6-165-blob-introspection-plan.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/plans/2026-07-02-001-fable-fixes-roadmap.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/plans/2026-07-02-002-feat-ff-a-172-typed-exceptions-plan.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/plans/2026-07-02-003-ff-c-native-decode-design.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/plans/2026-07-02-004-ff-c-c2-catalog-cache-design.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/plans/2026-07-02-005-ff-d-identity-routing-design.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/plans/2026-07-02-006-ff-d-identity-routing-plan.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/plans/2026-07-03-007-ff-e-registry-identity-design.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/plans/2026-07-03-008-ff-e-registry-identity-plan.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/plans/2026-07-06-009-ff-f-query-builder-1.0-design.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/plans/2026-07-06-010-ff-f-query-builder-1.0-plan.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/plans/2026-07-06-011-ff-g-hardening-design.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/plans/2026-07-06-012-ff-g-hardening-plan.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/plans/2026-07-06-013-ff-g2-operations-dedup-design.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/plans/2026-07-06-014-ff-g2-operations-dedup-plan.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/plans/2026-07-06-015-docs-upgrade-guide-consolidation-plan.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/plans/ir-first-migration-guide.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/plans/ir-first-release-checklist.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/rfc/ir-contracts-v1.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/solutions/README.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/solutions/architecture-patterns/ir-first-lowering-consolidation-audit.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/solutions/architecture-patterns/ir-first-merge-readiness-review.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/solutions/issues/pydantic-slots-missing-after-ferro-hydration.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/solutions/issues/python-3.14-deferred-annotation-typeerror-swallow.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/solutions/issues/sa-pk-column-nullable-divergence.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/solutions/issues/sa-vs-rust-unique-constraint-shape.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/solutions/issues/self-fk-evicts-component-from-create-order.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/solutions/issues/sqlite-integer-decimal-hydrates-as-none.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/solutions/issues/sqlite-null-hydrates-as-int-zero.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/solutions/issues/typed-where-null-panics-is-null.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/solutions/patterns/configurable-column-storage-types.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/solutions/patterns/cross-emitter-ddl-parity.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/solutions/patterns/ddl-on-live-engine.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/solutions/patterns/derived-type-and-naming-decision-table.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/solutions/patterns/foreign-key-index.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/solutions/patterns/index-unique-redundancy.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/solutions/patterns/ir-invariants.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/solutions/patterns/persistence-state.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/solutions/patterns/shadow-fk-columns.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/solutions/patterns/sqlite-alembic-reconnect-hydration-tests.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/docs/solutions/patterns/typed-null-binds.md +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/justfile +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/scripts/demo_queries.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/scripts/demo_queries_pre_v012.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/src/backend.rs +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/src/codec.rs +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/src/codec_plan.rs +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/src/connection.rs +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/src/errors.rs +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/src/ferro/_annotation_utils.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/src/ferro/_bind_payload.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/src/ferro/_core.pyi +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/src/ferro/_deprecations.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/src/ferro/_shadow_fk_types.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/src/ferro/base.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/src/ferro/composite_indexes.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/src/ferro/composite_uniques.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/src/ferro/exceptions.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/src/ferro/fields.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/src/ferro/ir/__init__.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/src/ferro/metaclass.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/src/ferro/migrations/__init__.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/src/ferro/migrations/alembic.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/src/ferro/py.typed +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/src/ferro/query/__init__.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/src/ferro/query/rows.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/src/ferro/raw.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/src/ferro/registry.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/src/ferro/relations/__init__.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/src/ferro/relations/descriptors.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/src/ferro/session.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/src/ferro/state.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/src/hydration.rs +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/src/lib.rs +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/src/naming_ffi.rs +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/src/schema_bind.rs +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/src/state.rs +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/__init__.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/conftest.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/db_backends.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/fixtures/ir_vectors/codec_registry_core_v1.json +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/fixtures/ir_vectors/schema_invoice_baseline_v1.json +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/fixtures/ir_vectors/schema_phase1_fixture_models_v1.json +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/fixtures/ir_vectors/schema_raw_str_pk_autoincrement_v1.json +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/static_fixtures/bad_includes.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/static_fixtures/bad_predicates.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/static_fixtures/bad_projections.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/static_fixtures/good_includes.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/static_fixtures/good_predicates.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/static_fixtures/good_projections.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_aggregation.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_alembic_autogenerate.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_alembic_bridge.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_alembic_db_type.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_alembic_nullability.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_alembic_type_mapping.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_annotation_utils.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_bulk_create_chunking.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_bulk_install.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_bulk_update.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_catalog_cache.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_codec_plan.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_column_specs.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_compiled_query.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_composite_index.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_composite_unique.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_connection.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_connection_redaction.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_constraints.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_cross_emitter_parity.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_crud.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_db_backends.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_db_type_cross_emitter_parity.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_db_type_integration.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_db_type_typing.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_db_type_validation.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_deletion.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_deprecations.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_docs_examples.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_documentation_features.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_enum_cold_hydration.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_exception_mapping.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_exceptions.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_field_wrapper.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_fk_target_pk.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_generation_counter_dirty_tracking.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_global_aggregates.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_grouped_aggregates.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_helpers.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_hydration.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_hydration_equivalence.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_identity_memory.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_identity_refresh.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_identity_scoped_invalidation.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_identity_weakref.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_import_budget.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_include.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_metaclass_internals.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_metadata.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_model_identity.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_models.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_mutation_pagination_guard.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_named_connections_integration.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_naming_single_source.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_one_to_one.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_operation_seam_sync.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_partial_selects.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_primary_key_facts.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_provisional_import.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_query_column_validation.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_query_immutability.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_query_typing.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_raw_sql.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_refresh.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_registry_entrypoints.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_registry_owner.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_relation_specs.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_relationship_engine.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_relationship_resolution_errors.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_route_single_site.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_routing_errors.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_save_pk_edges.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_save_semantics.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_schema.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_schema_constraints.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_schema_db_type_metadata.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_schema_enum_annotations.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_session.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_shadow_fk_types.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_sqlite_alembic_reconnect_hydration.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_static_contracts.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_string_search.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_structural_types.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_temporal_types.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_transactions.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_traversed_projection.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_typed_null_binds.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/tests/test_typed_save_bind.py +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/uv.lock +0 -0
- {ferro_orm-0.16.3 → ferro_orm-0.17.1}/zensical.toml +0 -0
|
@@ -1,6 +1,44 @@
|
|
|
1
1
|
# CHANGELOG
|
|
2
2
|
|
|
3
3
|
|
|
4
|
+
## v0.17.1 (2026-07-19)
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
- **migrate**: Auto-migrate pass ownership — column-before-index sequencing and FK on_delete
|
|
9
|
+
reconciliation ([#326](https://github.com/syn54x/ferro-orm/pull/326),
|
|
10
|
+
[`3451b1d`](https://github.com/syn54x/ferro-orm/commit/3451b1dad37d8ac39709d986aa20b1de4c12542a))
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
## v0.17.0 (2026-07-18)
|
|
14
|
+
|
|
15
|
+
### Documentation
|
|
16
|
+
|
|
17
|
+
- Design existence tests (.exists()) and uniform ~ negation
|
|
18
|
+
([`c68a477`](https://github.com/syn54x/ferro-orm/commit/c68a47780cd5fe6d8ecfcb4f7e0f9c8ec2b798fe))
|
|
19
|
+
|
|
20
|
+
- **query**: Document universal ~ negation and three-valued logic
|
|
21
|
+
([`6061d66`](https://github.com/syn54x/ferro-orm/commit/6061d66e96c99f089339f7a4a83b9424101da8be))
|
|
22
|
+
|
|
23
|
+
### Features
|
|
24
|
+
|
|
25
|
+
- **query**: Bare .exists() on reverse FK — existence-test tracer bullet
|
|
26
|
+
([#319](https://github.com/syn54x/ferro-orm/pull/319),
|
|
27
|
+
[`2538e06`](https://github.com/syn54x/ferro-orm/commit/2538e06b217e449d10dd564687f5ca3581d5d08d))
|
|
28
|
+
|
|
29
|
+
- **query**: Existence-test error surfaces and docs — the feature's edges
|
|
30
|
+
([`be88aed`](https://github.com/syn54x/ferro-orm/commit/be88aed35f0975f9333bf0dabacaffc8a82f8f34))
|
|
31
|
+
|
|
32
|
+
- **query**: M2M existence tests — the two-hop correlation path
|
|
33
|
+
([`336b529`](https://github.com/syn54x/ferro-orm/commit/336b5298d0e7beca8231452655544fcc7a15ad6a))
|
|
34
|
+
|
|
35
|
+
- **query**: Scoped existence tests — inner predicates, nesting, cross-scope guard
|
|
36
|
+
([`df11625`](https://github.com/syn54x/ferro-orm/commit/df11625b90e01d293f4863bec8afafb9110a1ac3))
|
|
37
|
+
|
|
38
|
+
- **query**: Uniform predicate negation — prefix ~ as a NOT wire node
|
|
39
|
+
([`bfa3126`](https://github.com/syn54x/ferro-orm/commit/bfa3126914b5a1b5d93a65ee3fe2f066bb314b1f))
|
|
40
|
+
|
|
41
|
+
|
|
4
42
|
## v0.16.3 (2026-07-16)
|
|
5
43
|
|
|
6
44
|
### Bug Fixes
|
|
@@ -56,6 +56,10 @@ _Avoid_: Join inference, nested filter, path lookup, string path
|
|
|
56
56
|
The ordered sequence of forward-FK hops a traversal walks (`account`, or `account → owner`). A path is the identity of a join: the same path referenced anywhere in a query is one join, and distinct paths to the same model are distinct joins. Left-join requests apply to a whole path.
|
|
57
57
|
_Avoid_: Join alias, lookup chain, dotted path string
|
|
58
58
|
|
|
59
|
+
**Existence test**:
|
|
60
|
+
The only predicate form on a reverse or many-to-many relation — `t.lines.exists(...)` — asking whether at least one related row exists, optionally scoped by a full inner predicate over the related model. Renders as a correlated EXISTS; the result stays root-shaped (shape-preserving query), so it composes with any other predicate, ordering, and paging. Reverse relations are *tested*, never *traversed*: traversal remains a forward-FK concept.
|
|
61
|
+
_Avoid_: membership filter, semi-join filter, reverse traversal, subquery filter, `.any()`
|
|
62
|
+
|
|
59
63
|
**Shape-preserving query**:
|
|
60
64
|
The invariant that filtering and ordering never change what a query returns — a query over Transaction yields Transaction instances regardless of which relations its predicates traverse. Only an explicit projection operation may change the result shape.
|
|
61
65
|
_Avoid_: Implicit projection, row narrowing
|
|
@@ -119,3 +123,19 @@ _Avoid_: Import-time registration, partial registry
|
|
|
119
123
|
**Resolved registration**:
|
|
120
124
|
The registry epoch after relationship resolution completes — join tables exist, shadow FK columns are wired, and the SchemaIR modelset is authoritative for DDL and auto-migrate.
|
|
121
125
|
_Avoid_: Final registration, committed registry
|
|
126
|
+
|
|
127
|
+
**Create pass**:
|
|
128
|
+
The auto-migrate step that brings missing tables into existence — the table, its columns, its indexes and constraints, together. A table that already exists is left completely untouched by this pass, whatever its shape.
|
|
129
|
+
_Avoid_: Bootstrap, ensure-tables, table sync
|
|
130
|
+
|
|
131
|
+
**Reconciliation pass**:
|
|
132
|
+
The `migrate_updates` step that alters existing tables to match the registered models — the only authority for DDL against a table that already exists. Within one table, column changes land before the indexes and constraints that reference them.
|
|
133
|
+
_Avoid_: Update pass, schema sync, drift repair
|
|
134
|
+
|
|
135
|
+
**Ferro-owned artifact**:
|
|
136
|
+
An index or constraint whose name follows ferro's canonical naming (`idx_`, `uq_`, `fk_`, `ck_`), marking it as reconcilable: auto-migrate may create, rebuild, or drop it to match the declared model. Artifacts named any other way belong to the user and are never altered or dropped.
|
|
137
|
+
_Avoid_: Managed index, system constraint, internal index
|
|
138
|
+
|
|
139
|
+
**Constraint rebuild**:
|
|
140
|
+
Drop-and-recreate of a ferro-owned constraint whose live definition no longer matches the declared model — a foreign key's `on_delete`, its target, its columns. Metadata-only: rows are never touched. On a backend that cannot alter constraints, ferro warns loudly and skips; it never diverges silently.
|
|
141
|
+
_Avoid_: Constraint alter, FK patch, in-place constraint update
|
|
@@ -95,9 +95,9 @@ checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04"
|
|
|
95
95
|
|
|
96
96
|
[[package]]
|
|
97
97
|
name = "cc"
|
|
98
|
-
version = "1.
|
|
98
|
+
version = "1.3.0"
|
|
99
99
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
100
|
-
checksum = "
|
|
100
|
+
checksum = "c89588d05638b5b4594a3348a2d6c20277e43a7f5c5202b05cc56888475a47b8"
|
|
101
101
|
dependencies = [
|
|
102
102
|
"find-msvc-tools",
|
|
103
103
|
"shlex",
|
|
@@ -210,7 +210,7 @@ dependencies = [
|
|
|
210
210
|
"ident_case",
|
|
211
211
|
"proc-macro2",
|
|
212
212
|
"quote",
|
|
213
|
-
"syn",
|
|
213
|
+
"syn 2.0.119",
|
|
214
214
|
]
|
|
215
215
|
|
|
216
216
|
[[package]]
|
|
@@ -221,7 +221,7 @@ checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead"
|
|
|
221
221
|
dependencies = [
|
|
222
222
|
"darling_core",
|
|
223
223
|
"quote",
|
|
224
|
-
"syn",
|
|
224
|
+
"syn 2.0.119",
|
|
225
225
|
]
|
|
226
226
|
|
|
227
227
|
[[package]]
|
|
@@ -269,7 +269,7 @@ checksum = "1ac70aa55017e108007fbaf5aa0f54b021c98f92ff8af59d42eda9da96e3dd4f"
|
|
|
269
269
|
dependencies = [
|
|
270
270
|
"proc-macro2",
|
|
271
271
|
"quote",
|
|
272
|
-
"syn",
|
|
272
|
+
"syn 2.0.119",
|
|
273
273
|
]
|
|
274
274
|
|
|
275
275
|
[[package]]
|
|
@@ -327,7 +327,7 @@ dependencies = [
|
|
|
327
327
|
|
|
328
328
|
[[package]]
|
|
329
329
|
name = "ferro"
|
|
330
|
-
version = "0.
|
|
330
|
+
version = "0.17.1"
|
|
331
331
|
dependencies = [
|
|
332
332
|
"chrono",
|
|
333
333
|
"dashmap",
|
|
@@ -412,9 +412,9 @@ dependencies = [
|
|
|
412
412
|
|
|
413
413
|
[[package]]
|
|
414
414
|
name = "futures"
|
|
415
|
-
version = "0.3.
|
|
415
|
+
version = "0.3.33"
|
|
416
416
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
417
|
-
checksum = "
|
|
417
|
+
checksum = "a88cf1f829d945f548cf8fec32c61b1f202b6d93b45848602fc02af4b12ad218"
|
|
418
418
|
dependencies = [
|
|
419
419
|
"futures-channel",
|
|
420
420
|
"futures-core",
|
|
@@ -427,9 +427,9 @@ dependencies = [
|
|
|
427
427
|
|
|
428
428
|
[[package]]
|
|
429
429
|
name = "futures-channel"
|
|
430
|
-
version = "0.3.
|
|
430
|
+
version = "0.3.33"
|
|
431
431
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
432
|
-
checksum = "
|
|
432
|
+
checksum = "262590f4fe6afeb0bc83be1daa64e52657fe185690a958af7f3ad0e92085c5ae"
|
|
433
433
|
dependencies = [
|
|
434
434
|
"futures-core",
|
|
435
435
|
"futures-sink",
|
|
@@ -437,15 +437,15 @@ dependencies = [
|
|
|
437
437
|
|
|
438
438
|
[[package]]
|
|
439
439
|
name = "futures-core"
|
|
440
|
-
version = "0.3.
|
|
440
|
+
version = "0.3.33"
|
|
441
441
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
442
|
-
checksum = "
|
|
442
|
+
checksum = "2cd50c473c80f6d7c3670a752354b8e569b1a7cbfdc0419ec88e5edad85e0dc7"
|
|
443
443
|
|
|
444
444
|
[[package]]
|
|
445
445
|
name = "futures-executor"
|
|
446
|
-
version = "0.3.
|
|
446
|
+
version = "0.3.33"
|
|
447
447
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
448
|
-
checksum = "
|
|
448
|
+
checksum = "6754879cc9f2c66f88c6e5c35344bb0bdb0708b0352b1201815667c7eabc7458"
|
|
449
449
|
dependencies = [
|
|
450
450
|
"futures-core",
|
|
451
451
|
"futures-task",
|
|
@@ -465,38 +465,38 @@ dependencies = [
|
|
|
465
465
|
|
|
466
466
|
[[package]]
|
|
467
467
|
name = "futures-io"
|
|
468
|
-
version = "0.3.
|
|
468
|
+
version = "0.3.33"
|
|
469
469
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
470
|
-
checksum = "
|
|
470
|
+
checksum = "4577ecaa3c4f96589d473f679a71b596316f6641bc350038b962a5daf0085d7a"
|
|
471
471
|
|
|
472
472
|
[[package]]
|
|
473
473
|
name = "futures-macro"
|
|
474
|
-
version = "0.3.
|
|
474
|
+
version = "0.3.33"
|
|
475
475
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
476
|
-
checksum = "
|
|
476
|
+
checksum = "2d6d3cde68c518367be28956066ddfef33813991b77a55005a69dae04bf3b10b"
|
|
477
477
|
dependencies = [
|
|
478
478
|
"proc-macro2",
|
|
479
479
|
"quote",
|
|
480
|
-
"syn",
|
|
480
|
+
"syn 2.0.119",
|
|
481
481
|
]
|
|
482
482
|
|
|
483
483
|
[[package]]
|
|
484
484
|
name = "futures-sink"
|
|
485
|
-
version = "0.3.
|
|
485
|
+
version = "0.3.33"
|
|
486
486
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
487
|
-
checksum = "
|
|
487
|
+
checksum = "e34418ac499d6305c2fb5ad0ed2f6ac998c5f8ca209b4510f7f94242c647e307"
|
|
488
488
|
|
|
489
489
|
[[package]]
|
|
490
490
|
name = "futures-task"
|
|
491
|
-
version = "0.3.
|
|
491
|
+
version = "0.3.33"
|
|
492
492
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
493
|
-
checksum = "
|
|
493
|
+
checksum = "b231ed28831efb4a61a08580c4bc233ec56bc009f4cd8f52da2c3cb97df0c109"
|
|
494
494
|
|
|
495
495
|
[[package]]
|
|
496
496
|
name = "futures-util"
|
|
497
|
-
version = "0.3.
|
|
497
|
+
version = "0.3.33"
|
|
498
498
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
499
|
-
checksum = "
|
|
499
|
+
checksum = "a77a90a256fce34da66415271e30f94ee91c57b04b8a2c042d9cf3220179deaa"
|
|
500
500
|
dependencies = [
|
|
501
501
|
"futures-channel",
|
|
502
502
|
"futures-core",
|
|
@@ -772,13 +772,13 @@ dependencies = [
|
|
|
772
772
|
|
|
773
773
|
[[package]]
|
|
774
774
|
name = "inherent"
|
|
775
|
-
version = "1.0.
|
|
775
|
+
version = "1.0.14"
|
|
776
776
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
777
|
-
checksum = "
|
|
777
|
+
checksum = "bee2c455ca60511a054699102d40ce7153621cb2429558f9eaa600e4499b5984"
|
|
778
778
|
dependencies = [
|
|
779
779
|
"proc-macro2",
|
|
780
780
|
"quote",
|
|
781
|
-
"syn",
|
|
781
|
+
"syn 3.0.0",
|
|
782
782
|
]
|
|
783
783
|
|
|
784
784
|
[[package]]
|
|
@@ -1045,9 +1045,9 @@ checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6"
|
|
|
1045
1045
|
|
|
1046
1046
|
[[package]]
|
|
1047
1047
|
name = "portable-atomic"
|
|
1048
|
-
version = "1.
|
|
1048
|
+
version = "1.14.0"
|
|
1049
1049
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1050
|
-
checksum = "
|
|
1050
|
+
checksum = "3d20d5497ef88037a52ff98267d066e7f11fcc5e99bbfbd58a42336193aacec3"
|
|
1051
1051
|
|
|
1052
1052
|
[[package]]
|
|
1053
1053
|
name = "potential_utf"
|
|
@@ -1069,9 +1069,9 @@ dependencies = [
|
|
|
1069
1069
|
|
|
1070
1070
|
[[package]]
|
|
1071
1071
|
name = "proc-macro2"
|
|
1072
|
-
version = "1.0.
|
|
1072
|
+
version = "1.0.107"
|
|
1073
1073
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1074
|
-
checksum = "
|
|
1074
|
+
checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9"
|
|
1075
1075
|
dependencies = [
|
|
1076
1076
|
"unicode-ident",
|
|
1077
1077
|
]
|
|
@@ -1134,7 +1134,7 @@ dependencies = [
|
|
|
1134
1134
|
"proc-macro2",
|
|
1135
1135
|
"pyo3-macros-backend",
|
|
1136
1136
|
"quote",
|
|
1137
|
-
"syn",
|
|
1137
|
+
"syn 2.0.119",
|
|
1138
1138
|
]
|
|
1139
1139
|
|
|
1140
1140
|
[[package]]
|
|
@@ -1147,14 +1147,14 @@ dependencies = [
|
|
|
1147
1147
|
"proc-macro2",
|
|
1148
1148
|
"pyo3-build-config",
|
|
1149
1149
|
"quote",
|
|
1150
|
-
"syn",
|
|
1150
|
+
"syn 2.0.119",
|
|
1151
1151
|
]
|
|
1152
1152
|
|
|
1153
1153
|
[[package]]
|
|
1154
1154
|
name = "quote"
|
|
1155
|
-
version = "1.0.
|
|
1155
|
+
version = "1.0.47"
|
|
1156
1156
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1157
|
-
checksum = "
|
|
1157
|
+
checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001"
|
|
1158
1158
|
dependencies = [
|
|
1159
1159
|
"proc-macro2",
|
|
1160
1160
|
]
|
|
@@ -1320,15 +1320,15 @@ dependencies = [
|
|
|
1320
1320
|
"heck 0.4.1",
|
|
1321
1321
|
"proc-macro2",
|
|
1322
1322
|
"quote",
|
|
1323
|
-
"syn",
|
|
1323
|
+
"syn 2.0.119",
|
|
1324
1324
|
"thiserror",
|
|
1325
1325
|
]
|
|
1326
1326
|
|
|
1327
1327
|
[[package]]
|
|
1328
1328
|
name = "serde"
|
|
1329
|
-
version = "1.0.
|
|
1329
|
+
version = "1.0.229"
|
|
1330
1330
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1331
|
-
checksum = "
|
|
1331
|
+
checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba"
|
|
1332
1332
|
dependencies = [
|
|
1333
1333
|
"serde_core",
|
|
1334
1334
|
"serde_derive",
|
|
@@ -1336,22 +1336,22 @@ dependencies = [
|
|
|
1336
1336
|
|
|
1337
1337
|
[[package]]
|
|
1338
1338
|
name = "serde_core"
|
|
1339
|
-
version = "1.0.
|
|
1339
|
+
version = "1.0.229"
|
|
1340
1340
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1341
|
-
checksum = "
|
|
1341
|
+
checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48"
|
|
1342
1342
|
dependencies = [
|
|
1343
1343
|
"serde_derive",
|
|
1344
1344
|
]
|
|
1345
1345
|
|
|
1346
1346
|
[[package]]
|
|
1347
1347
|
name = "serde_derive"
|
|
1348
|
-
version = "1.0.
|
|
1348
|
+
version = "1.0.229"
|
|
1349
1349
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1350
|
-
checksum = "
|
|
1350
|
+
checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348"
|
|
1351
1351
|
dependencies = [
|
|
1352
1352
|
"proc-macro2",
|
|
1353
1353
|
"quote",
|
|
1354
|
-
"syn",
|
|
1354
|
+
"syn 3.0.0",
|
|
1355
1355
|
]
|
|
1356
1356
|
|
|
1357
1357
|
[[package]]
|
|
@@ -1533,7 +1533,7 @@ dependencies = [
|
|
|
1533
1533
|
"quote",
|
|
1534
1534
|
"sqlx-core",
|
|
1535
1535
|
"sqlx-macros-core",
|
|
1536
|
-
"syn",
|
|
1536
|
+
"syn 2.0.119",
|
|
1537
1537
|
]
|
|
1538
1538
|
|
|
1539
1539
|
[[package]]
|
|
@@ -1556,7 +1556,7 @@ dependencies = [
|
|
|
1556
1556
|
"sqlx-mysql",
|
|
1557
1557
|
"sqlx-postgres",
|
|
1558
1558
|
"sqlx-sqlite",
|
|
1559
|
-
"syn",
|
|
1559
|
+
"syn 2.0.119",
|
|
1560
1560
|
"tokio",
|
|
1561
1561
|
"url",
|
|
1562
1562
|
]
|
|
@@ -1707,6 +1707,17 @@ dependencies = [
|
|
|
1707
1707
|
"unicode-ident",
|
|
1708
1708
|
]
|
|
1709
1709
|
|
|
1710
|
+
[[package]]
|
|
1711
|
+
name = "syn"
|
|
1712
|
+
version = "3.0.0"
|
|
1713
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1714
|
+
checksum = "f2fac314a64dc9a36e61a9eb4261a5e9bbfbc922b27e518af97bc32b926cf967"
|
|
1715
|
+
dependencies = [
|
|
1716
|
+
"proc-macro2",
|
|
1717
|
+
"quote",
|
|
1718
|
+
"unicode-ident",
|
|
1719
|
+
]
|
|
1720
|
+
|
|
1710
1721
|
[[package]]
|
|
1711
1722
|
name = "synstructure"
|
|
1712
1723
|
version = "0.13.2"
|
|
@@ -1715,7 +1726,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2"
|
|
|
1715
1726
|
dependencies = [
|
|
1716
1727
|
"proc-macro2",
|
|
1717
1728
|
"quote",
|
|
1718
|
-
"syn",
|
|
1729
|
+
"syn 2.0.119",
|
|
1719
1730
|
]
|
|
1720
1731
|
|
|
1721
1732
|
[[package]]
|
|
@@ -1726,22 +1737,22 @@ checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca"
|
|
|
1726
1737
|
|
|
1727
1738
|
[[package]]
|
|
1728
1739
|
name = "thiserror"
|
|
1729
|
-
version = "2.0.
|
|
1740
|
+
version = "2.0.19"
|
|
1730
1741
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1731
|
-
checksum = "
|
|
1742
|
+
checksum = "09a43598840e33d5b0331f38c5e30d13bb11c11210a4b58f0d9b18a5a5eefcd9"
|
|
1732
1743
|
dependencies = [
|
|
1733
1744
|
"thiserror-impl",
|
|
1734
1745
|
]
|
|
1735
1746
|
|
|
1736
1747
|
[[package]]
|
|
1737
1748
|
name = "thiserror-impl"
|
|
1738
|
-
version = "2.0.
|
|
1749
|
+
version = "2.0.19"
|
|
1739
1750
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1740
|
-
checksum = "
|
|
1751
|
+
checksum = "43cbfe0cf76104d42a574802844187e84a305e531ed54455f11fbde0f10541cd"
|
|
1741
1752
|
dependencies = [
|
|
1742
1753
|
"proc-macro2",
|
|
1743
1754
|
"quote",
|
|
1744
|
-
"syn",
|
|
1755
|
+
"syn 3.0.0",
|
|
1745
1756
|
]
|
|
1746
1757
|
|
|
1747
1758
|
[[package]]
|
|
@@ -1771,9 +1782,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
|
|
1771
1782
|
|
|
1772
1783
|
[[package]]
|
|
1773
1784
|
name = "tokio"
|
|
1774
|
-
version = "1.
|
|
1785
|
+
version = "1.53.0"
|
|
1775
1786
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1776
|
-
checksum = "
|
|
1787
|
+
checksum = "d988bcd52dbe076d3d46903332f58c912b87a2c49b1428419a5845154762ffee"
|
|
1777
1788
|
dependencies = [
|
|
1778
1789
|
"bytes",
|
|
1779
1790
|
"libc",
|
|
@@ -1788,13 +1799,13 @@ dependencies = [
|
|
|
1788
1799
|
|
|
1789
1800
|
[[package]]
|
|
1790
1801
|
name = "tokio-macros"
|
|
1791
|
-
version = "2.7.
|
|
1802
|
+
version = "2.7.1"
|
|
1792
1803
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1793
|
-
checksum = "
|
|
1804
|
+
checksum = "6328af13490e73a9b4694030fafd93f8c8c6a9dede33e821c3fc63eddf8042ba"
|
|
1794
1805
|
dependencies = [
|
|
1795
1806
|
"proc-macro2",
|
|
1796
1807
|
"quote",
|
|
1797
|
-
"syn",
|
|
1808
|
+
"syn 2.0.119",
|
|
1798
1809
|
]
|
|
1799
1810
|
|
|
1800
1811
|
[[package]]
|
|
@@ -1828,7 +1839,7 @@ checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da"
|
|
|
1828
1839
|
dependencies = [
|
|
1829
1840
|
"proc-macro2",
|
|
1830
1841
|
"quote",
|
|
1831
|
-
"syn",
|
|
1842
|
+
"syn 2.0.119",
|
|
1832
1843
|
]
|
|
1833
1844
|
|
|
1834
1845
|
[[package]]
|
|
@@ -1970,7 +1981,7 @@ dependencies = [
|
|
|
1970
1981
|
"bumpalo",
|
|
1971
1982
|
"proc-macro2",
|
|
1972
1983
|
"quote",
|
|
1973
|
-
"syn",
|
|
1984
|
+
"syn 2.0.119",
|
|
1974
1985
|
"wasm-bindgen-shared",
|
|
1975
1986
|
]
|
|
1976
1987
|
|
|
@@ -1989,14 +2000,14 @@ version = "0.26.11"
|
|
|
1989
2000
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1990
2001
|
checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9"
|
|
1991
2002
|
dependencies = [
|
|
1992
|
-
"webpki-roots 1.0.
|
|
2003
|
+
"webpki-roots 1.0.9",
|
|
1993
2004
|
]
|
|
1994
2005
|
|
|
1995
2006
|
[[package]]
|
|
1996
2007
|
name = "webpki-roots"
|
|
1997
|
-
version = "1.0.
|
|
2008
|
+
version = "1.0.9"
|
|
1998
2009
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1999
|
-
checksum = "
|
|
2010
|
+
checksum = "7dcd9d09a39985f5344844e66b0c530a33843579125f23e21e9f0f220850f22a"
|
|
2000
2011
|
dependencies = [
|
|
2001
2012
|
"rustls-pki-types",
|
|
2002
2013
|
]
|
|
@@ -2032,7 +2043,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf"
|
|
|
2032
2043
|
dependencies = [
|
|
2033
2044
|
"proc-macro2",
|
|
2034
2045
|
"quote",
|
|
2035
|
-
"syn",
|
|
2046
|
+
"syn 2.0.119",
|
|
2036
2047
|
]
|
|
2037
2048
|
|
|
2038
2049
|
[[package]]
|
|
@@ -2043,7 +2054,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358"
|
|
|
2043
2054
|
dependencies = [
|
|
2044
2055
|
"proc-macro2",
|
|
2045
2056
|
"quote",
|
|
2046
|
-
"syn",
|
|
2057
|
+
"syn 2.0.119",
|
|
2047
2058
|
]
|
|
2048
2059
|
|
|
2049
2060
|
[[package]]
|
|
@@ -2243,7 +2254,7 @@ checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e"
|
|
|
2243
2254
|
dependencies = [
|
|
2244
2255
|
"proc-macro2",
|
|
2245
2256
|
"quote",
|
|
2246
|
-
"syn",
|
|
2257
|
+
"syn 2.0.119",
|
|
2247
2258
|
"synstructure",
|
|
2248
2259
|
]
|
|
2249
2260
|
|
|
@@ -2264,7 +2275,7 @@ checksum = "e2e817b7b52d0c7358d3246da9d69935ebb18116b2b102b4230dac079b4862f5"
|
|
|
2264
2275
|
dependencies = [
|
|
2265
2276
|
"proc-macro2",
|
|
2266
2277
|
"quote",
|
|
2267
|
-
"syn",
|
|
2278
|
+
"syn 2.0.119",
|
|
2268
2279
|
]
|
|
2269
2280
|
|
|
2270
2281
|
[[package]]
|
|
@@ -2284,7 +2295,7 @@ checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1"
|
|
|
2284
2295
|
dependencies = [
|
|
2285
2296
|
"proc-macro2",
|
|
2286
2297
|
"quote",
|
|
2287
|
-
"syn",
|
|
2298
|
+
"syn 2.0.119",
|
|
2288
2299
|
"synstructure",
|
|
2289
2300
|
]
|
|
2290
2301
|
|
|
@@ -2324,7 +2335,7 @@ checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555"
|
|
|
2324
2335
|
dependencies = [
|
|
2325
2336
|
"proc-macro2",
|
|
2326
2337
|
"quote",
|
|
2327
|
-
"syn",
|
|
2338
|
+
"syn 2.0.119",
|
|
2328
2339
|
]
|
|
2329
2340
|
|
|
2330
2341
|
[[package]]
|
|
@@ -542,6 +542,13 @@ pub fn fk_name(table_lower: &str, col_name: &str, to_table: &str) -> String {
|
|
|
542
542
|
raw
|
|
543
543
|
}
|
|
544
544
|
|
|
545
|
+
/// Whether a live constraint name follows the ferro FK convention above — the
|
|
546
|
+
/// ownership test: reconciliation only ever rebuilds names ferro emits;
|
|
547
|
+
/// constraints named any other way belong to the user and are never altered.
|
|
548
|
+
pub fn is_ferro_fk_name(name: &str) -> bool {
|
|
549
|
+
name.starts_with("fk_")
|
|
550
|
+
}
|
|
551
|
+
|
|
545
552
|
/// Single-column unique name with 63-char guard.
|
|
546
553
|
pub fn single_unique_index_name(table_lower: &str, col_name: &str) -> String {
|
|
547
554
|
let raw = format!("uq_{table_lower}_{col_name}");
|
|
@@ -408,16 +408,7 @@ fn emit_add_column(
|
|
|
408
408
|
|
|
409
409
|
if let Some(fk) = model.foreign_keys.iter().find(|fk| fk.column == column) {
|
|
410
410
|
if dialect == Dialect::Postgres {
|
|
411
|
-
|
|
412
|
-
result.statements.push(format!(
|
|
413
|
-
"ALTER TABLE {} ADD CONSTRAINT {} FOREIGN KEY ({}) REFERENCES {} ({}) ON DELETE {}",
|
|
414
|
-
quote_ident(table),
|
|
415
|
-
quote_ident(&fk_constraint_name(table, fk)),
|
|
416
|
-
quote_ident(column),
|
|
417
|
-
quote_ident(&fk.to_table),
|
|
418
|
-
quote_ident(&fk.to_column),
|
|
419
|
-
fk_action_sql(on_delete),
|
|
420
|
-
));
|
|
411
|
+
result.statements.push(render_add_fk_sql(table, fk));
|
|
421
412
|
} else {
|
|
422
413
|
result.warnings.push(format!(
|
|
423
414
|
"Added foreign-key column '{}.{}' without its FOREIGN KEY constraint \
|
|
@@ -432,6 +423,39 @@ fn emit_add_column(
|
|
|
432
423
|
Ok(result)
|
|
433
424
|
}
|
|
434
425
|
|
|
426
|
+
/// `ALTER TABLE ... ADD CONSTRAINT ... FOREIGN KEY ... ON DELETE ...` for one
|
|
427
|
+
/// IR foreign key. Postgres-only — SQLite cannot add table constraints to an
|
|
428
|
+
/// existing table; its callers warn instead.
|
|
429
|
+
fn render_add_fk_sql(table: &str, fk: &ferro_schema_ir::SchemaForeignKey) -> String {
|
|
430
|
+
format!(
|
|
431
|
+
"ALTER TABLE {} ADD CONSTRAINT {} FOREIGN KEY ({}) REFERENCES {} ({}) ON DELETE {}",
|
|
432
|
+
quote_ident(table),
|
|
433
|
+
quote_ident(&fk_constraint_name(table, fk)),
|
|
434
|
+
quote_ident(&fk.column),
|
|
435
|
+
quote_ident(&fk.to_table),
|
|
436
|
+
quote_ident(&fk.to_column),
|
|
437
|
+
fk_action_sql(fk_action_from_str(fk.on_delete.as_deref())),
|
|
438
|
+
)
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
/// Find the declared FK for `column` on `table` in the new-IR model.
|
|
442
|
+
fn find_foreign_key<'a>(
|
|
443
|
+
model: &'a SchemaModel,
|
|
444
|
+
table: &str,
|
|
445
|
+
column: &str,
|
|
446
|
+
) -> Result<&'a ferro_schema_ir::SchemaForeignKey, EmissionError> {
|
|
447
|
+
model
|
|
448
|
+
.foreign_keys
|
|
449
|
+
.iter()
|
|
450
|
+
.find(|fk| fk.column == column)
|
|
451
|
+
.ok_or_else(|| EmissionError {
|
|
452
|
+
message: format!(
|
|
453
|
+
"Foreign-key operation for '{}.{}' has no matching FK in the declared IR",
|
|
454
|
+
table, column
|
|
455
|
+
),
|
|
456
|
+
})
|
|
457
|
+
}
|
|
458
|
+
|
|
435
459
|
fn emit_alter_column_type(
|
|
436
460
|
table: &str,
|
|
437
461
|
column: &str,
|
|
@@ -673,6 +697,61 @@ pub fn emit_sql_with_ir(
|
|
|
673
697
|
MigrationOp::DropIndex { table: _, name } => {
|
|
674
698
|
result.statements.push(format!("DROP INDEX IF EXISTS \"{}\"", name));
|
|
675
699
|
}
|
|
700
|
+
MigrationOp::AddForeignKey { table, column } => {
|
|
701
|
+
let model = find_model(&new_models, table)?;
|
|
702
|
+
let fk = find_foreign_key(model, table, column)?;
|
|
703
|
+
match dialect {
|
|
704
|
+
Dialect::Postgres => result.statements.push(render_add_fk_sql(table, fk)),
|
|
705
|
+
Dialect::Sqlite => result.warnings.push(format!(
|
|
706
|
+
"Declared FOREIGN KEY on '{}.{}' (on_delete {}) has no live \
|
|
707
|
+
constraint, and SQLite cannot add table constraints to an \
|
|
708
|
+
existing table. Referential integrity for this column is not \
|
|
709
|
+
database-enforced; use Alembic if you need the constraint.",
|
|
710
|
+
table,
|
|
711
|
+
column,
|
|
712
|
+
fk_action_sql(fk_action_from_str(fk.on_delete.as_deref())),
|
|
713
|
+
)),
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
MigrationOp::RebuildForeignKey {
|
|
717
|
+
table,
|
|
718
|
+
column,
|
|
719
|
+
old_name,
|
|
720
|
+
} => {
|
|
721
|
+
let model = find_model(&new_models, table)?;
|
|
722
|
+
let fk = find_foreign_key(model, table, column)?;
|
|
723
|
+
match dialect {
|
|
724
|
+
Dialect::Postgres => {
|
|
725
|
+
result.statements.push(format!(
|
|
726
|
+
"ALTER TABLE {} DROP CONSTRAINT {}",
|
|
727
|
+
quote_ident(table),
|
|
728
|
+
quote_ident(old_name),
|
|
729
|
+
));
|
|
730
|
+
result.statements.push(render_add_fk_sql(table, fk));
|
|
731
|
+
}
|
|
732
|
+
Dialect::Sqlite => {
|
|
733
|
+
let live_action = find_model(&old_models, table)
|
|
734
|
+
.ok()
|
|
735
|
+
.and_then(|old| {
|
|
736
|
+
old.foreign_keys.iter().find(|live| live.column == *column)
|
|
737
|
+
})
|
|
738
|
+
.map(|live| {
|
|
739
|
+
fk_action_sql(fk_action_from_str(live.on_delete.as_deref()))
|
|
740
|
+
})
|
|
741
|
+
.unwrap_or("<unknown>");
|
|
742
|
+
result.warnings.push(format!(
|
|
743
|
+
"Foreign key on '{}.{}' declares on_delete {} but the live \
|
|
744
|
+
constraint enforces {}; SQLite cannot alter constraints in \
|
|
745
|
+
place, so the live behavior remains. Migrate with Alembic to \
|
|
746
|
+
apply the declared action.",
|
|
747
|
+
table,
|
|
748
|
+
column,
|
|
749
|
+
fk_action_sql(fk_action_from_str(fk.on_delete.as_deref())),
|
|
750
|
+
live_action,
|
|
751
|
+
));
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
}
|
|
676
755
|
}
|
|
677
756
|
}
|
|
678
757
|
|