ferro-orm 0.11.0__tar.gz → 0.12.0__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.11.0 → ferro_orm-0.12.0}/.github/PERMISSIONS.md +2 -2
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/.github/pull_request_template.md +9 -1
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/.github/workflows/ci.yml +101 -3
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/.github/workflows/publish-docs.yml +3 -3
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/.gitignore +1 -1
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/AGENTS.md +86 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/CHANGELOG.md +14 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/CONTRIBUTING.md +3 -3
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/Cargo.lock +52 -225
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/Cargo.toml +6 -1
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/PKG-INFO +2 -2
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/README.md +1 -1
- ferro_orm-0.12.0/crates/ferro-migrate/Cargo.toml +7 -0
- ferro_orm-0.12.0/crates/ferro-migrate/src/lib.rs +271 -0
- ferro_orm-0.12.0/crates/ferro-schema-ir/Cargo.toml +8 -0
- ferro_orm-0.12.0/crates/ferro-schema-ir/src/lib.rs +195 -0
- ferro_orm-0.12.0/docs/examples/multiple_databases.py +45 -0
- ferro_orm-0.12.0/docs/examples/mutations.py +49 -0
- ferro_orm-0.12.0/docs/examples/pagination.py +47 -0
- ferro_orm-0.12.0/docs/examples/predicates.py +92 -0
- ferro_orm-0.12.0/docs/examples/predicates_annotated.py +36 -0
- ferro_orm-0.12.0/docs/examples/quickstart.py +111 -0
- ferro_orm-0.12.0/docs/examples/quickstart_annotated.py +48 -0
- ferro_orm-0.12.0/docs/examples/raw_sql.py +43 -0
- ferro_orm-0.12.0/docs/examples/relationships.py +128 -0
- ferro_orm-0.12.0/docs/examples/relationships_annotated.py +108 -0
- ferro_orm-0.12.0/docs/examples/soft_deletes.py +61 -0
- ferro_orm-0.12.0/docs/examples/soft_deletes_annotated.py +58 -0
- ferro_orm-0.12.0/docs/examples/testing_conftest.py +33 -0
- ferro_orm-0.12.0/docs/examples/timestamps.py +53 -0
- ferro_orm-0.12.0/docs/examples/timestamps_annotated.py +50 -0
- ferro_orm-0.12.0/docs/examples/transactions.py +58 -0
- ferro_orm-0.12.0/docs/pages/api/connection.md +21 -0
- ferro_orm-0.12.0/docs/pages/api/exceptions.md +5 -0
- ferro_orm-0.12.0/docs/pages/api/fields.md +15 -0
- ferro_orm-0.12.0/docs/pages/api/migrations.md +7 -0
- ferro_orm-0.12.0/docs/pages/api/model.md +5 -0
- ferro_orm-0.12.0/docs/pages/api/queries.md +11 -0
- ferro_orm-0.12.0/docs/pages/api/raw-sql.md +9 -0
- ferro_orm-0.12.0/docs/pages/api/relationships.md +11 -0
- ferro_orm-0.12.0/docs/pages/api/transactions.md +7 -0
- ferro_orm-0.12.0/docs/pages/changelog.md +1 -0
- ferro_orm-0.12.0/docs/pages/concepts/architecture.md +234 -0
- ferro_orm-0.12.0/docs/pages/concepts/backends.md +107 -0
- ferro_orm-0.12.0/docs/pages/concepts/identity-map.md +151 -0
- ferro_orm-0.12.0/docs/pages/concepts/performance.md +108 -0
- {ferro_orm-0.11.0/docs → ferro_orm-0.12.0/docs/pages}/concepts/query-typing.md +34 -33
- ferro_orm-0.12.0/docs/pages/concepts/type-safety.md +110 -0
- ferro_orm-0.12.0/docs/pages/contributing.md +5 -0
- ferro_orm-0.12.0/docs/pages/faq.md +103 -0
- ferro_orm-0.12.0/docs/pages/getting-started/installation.md +76 -0
- ferro_orm-0.12.0/docs/pages/getting-started/next-steps.md +56 -0
- ferro_orm-0.12.0/docs/pages/getting-started/quickstart.md +103 -0
- ferro_orm-0.12.0/docs/pages/guide/connections.md +192 -0
- ferro_orm-0.12.0/docs/pages/guide/migrations.md +164 -0
- ferro_orm-0.12.0/docs/pages/guide/models-and-fields.md +477 -0
- ferro_orm-0.12.0/docs/pages/guide/mutations.md +145 -0
- ferro_orm-0.12.0/docs/pages/guide/queries.md +177 -0
- ferro_orm-0.12.0/docs/pages/guide/raw-sql.md +109 -0
- ferro_orm-0.12.0/docs/pages/guide/relationships.md +240 -0
- ferro_orm-0.12.0/docs/pages/guide/transactions.md +121 -0
- ferro_orm-0.12.0/docs/pages/howto/migrate-from-sqlalchemy.md +270 -0
- ferro_orm-0.12.0/docs/pages/howto/migrating-to-v0-12-0.md +147 -0
- ferro_orm-0.12.0/docs/pages/howto/multiple-databases.md +71 -0
- ferro_orm-0.12.0/docs/pages/howto/pagination.md +122 -0
- ferro_orm-0.12.0/docs/pages/howto/soft-deletes.md +63 -0
- ferro_orm-0.12.0/docs/pages/howto/testing.md +169 -0
- ferro_orm-0.12.0/docs/pages/howto/timestamps.md +56 -0
- ferro_orm-0.12.0/docs/pages/index.md +12 -0
- ferro_orm-0.12.0/docs/pages/roadmap.md +22 -0
- ferro_orm-0.12.0/docs/pages/why-ferro.md +89 -0
- ferro_orm-0.12.0/docs/plans/2026-06-19-001-ir-first-roadmap.md +626 -0
- ferro_orm-0.12.0/docs/plans/ir-first-migration-guide.md +165 -0
- ferro_orm-0.12.0/docs/plans/ir-first-release-checklist.md +46 -0
- ferro_orm-0.12.0/docs/rfc/ir-contracts-v1.md +228 -0
- ferro_orm-0.12.0/docs/solutions/architecture-patterns/ir-first-merge-readiness-review.md +235 -0
- ferro_orm-0.12.0/docs/solutions/patterns/ir-invariants.md +182 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/docs/solutions/patterns/typed-null-binds.md +21 -28
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/pyproject.toml +8 -7
- ferro_orm-0.12.0/scripts/demo_queries.py +271 -0
- ferro_orm-0.11.0/scripts/demo_queries.py → ferro_orm-0.12.0/scripts/demo_queries_pre_v012.py +20 -22
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/src/backend.rs +16 -0
- ferro_orm-0.12.0/src/codec.rs +517 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/src/connection.rs +17 -2
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/src/ferro/__init__.py +5 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/src/ferro/_core.pyi +44 -11
- ferro_orm-0.12.0/src/ferro/_deprecations.py +100 -0
- ferro_orm-0.12.0/src/ferro/ir/__init__.py +13 -0
- ferro_orm-0.12.0/src/ferro/ir/compiler.py +439 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/src/ferro/metaclass.py +3 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/src/ferro/migrations/alembic.py +184 -14
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/src/ferro/models.py +119 -73
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/src/ferro/query/builder.py +100 -44
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/src/ferro/query/nodes.py +86 -13
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/src/ferro/raw.py +28 -22
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/src/ferro/relations/__init__.py +2 -0
- ferro_orm-0.12.0/src/ferro/session.py +43 -0
- ferro_orm-0.12.0/src/ferro/state.py +146 -0
- ferro_orm-0.12.0/src/hydration.rs +57 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/src/lib.rs +8 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/src/migrate.rs +214 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/src/operations.rs +600 -551
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/src/query.rs +308 -223
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/src/schema.rs +32 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/src/state.rs +45 -0
- ferro_orm-0.12.0/tests/fixtures/ir_vectors/README.md +45 -0
- ferro_orm-0.12.0/tests/fixtures/ir_vectors/codec_registry_core_v1.json +100 -0
- ferro_orm-0.12.0/tests/fixtures/ir_vectors/query_user_compound_v1.json +58 -0
- ferro_orm-0.12.0/tests/fixtures/ir_vectors/schema_invoice_baseline_v1.json +101 -0
- ferro_orm-0.12.0/tests/fixtures/ir_vectors/schema_phase1_fixture_models_v1.json +215 -0
- ferro_orm-0.12.0/tests/fixtures/shadow_reports/postgres.json +47 -0
- ferro_orm-0.12.0/tests/fixtures/shadow_reports/sqlite.json +47 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/tests/test_alembic_bridge.py +26 -0
- ferro_orm-0.12.0/tests/test_deprecated_operator_inventory.py +51 -0
- ferro_orm-0.12.0/tests/test_deprecations.py +74 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/tests/test_docs_examples.py +39 -5
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/tests/test_documentation_features.py +27 -22
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/tests/test_hydration.py +71 -4
- ferro_orm-0.12.0/tests/test_ir_vectors_contract.py +334 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/tests/test_query_builder.py +51 -24
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/tests/test_query_typing.py +20 -10
- ferro_orm-0.12.0/tests/test_session.py +104 -0
- ferro_orm-0.12.0/tests/test_shadow_reports.py +112 -0
- ferro_orm-0.12.0/tests/test_static_contracts.py +8 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/tests/test_typed_null_binds.py +42 -6
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/uv.lock +90 -131
- ferro_orm-0.12.0/zensical.toml +145 -0
- ferro_orm-0.11.0/docs/TEST_RESULTS.md +0 -210
- ferro_orm-0.11.0/docs/api/exceptions.md +0 -15
- ferro_orm-0.11.0/docs/api/fields.md +0 -21
- ferro_orm-0.11.0/docs/api/model.md +0 -31
- ferro_orm-0.11.0/docs/api/query.md +0 -97
- ferro_orm-0.11.0/docs/api/raw-sql.md +0 -124
- ferro_orm-0.11.0/docs/api/relationships.md +0 -35
- ferro_orm-0.11.0/docs/api/transactions.md +0 -36
- ferro_orm-0.11.0/docs/api/utilities.md +0 -73
- ferro_orm-0.11.0/docs/changelog.md +0 -46
- ferro_orm-0.11.0/docs/coming-soon.md +0 -484
- ferro_orm-0.11.0/docs/concepts/architecture.md +0 -332
- ferro_orm-0.11.0/docs/concepts/identity-map.md +0 -285
- ferro_orm-0.11.0/docs/concepts/performance.md +0 -222
- ferro_orm-0.11.0/docs/concepts/type-safety.md +0 -183
- ferro_orm-0.11.0/docs/contributing.md +0 -3
- ferro_orm-0.11.0/docs/faq.md +0 -262
- ferro_orm-0.11.0/docs/getting-started/installation.md +0 -86
- ferro_orm-0.11.0/docs/getting-started/next-steps.md +0 -159
- ferro_orm-0.11.0/docs/getting-started/tutorial.md +0 -388
- ferro_orm-0.11.0/docs/guide/backend.md +0 -404
- ferro_orm-0.11.0/docs/guide/database.md +0 -385
- ferro_orm-0.11.0/docs/guide/migrations.md +0 -445
- ferro_orm-0.11.0/docs/guide/models-and-fields.md +0 -272
- ferro_orm-0.11.0/docs/guide/mutations.md +0 -478
- ferro_orm-0.11.0/docs/guide/queries.md +0 -395
- ferro_orm-0.11.0/docs/guide/relationships.md +0 -393
- ferro_orm-0.11.0/docs/guide/transactions.md +0 -380
- ferro_orm-0.11.0/docs/howto/multiple-databases.md +0 -74
- ferro_orm-0.11.0/docs/howto/pagination.md +0 -355
- ferro_orm-0.11.0/docs/howto/soft-deletes.md +0 -86
- ferro_orm-0.11.0/docs/howto/testing.md +0 -205
- ferro_orm-0.11.0/docs/howto/timestamps.md +0 -57
- ferro_orm-0.11.0/docs/index.md +0 -142
- ferro_orm-0.11.0/docs/migration-sqlalchemy.md +0 -173
- ferro_orm-0.11.0/docs/why-ferro.md +0 -206
- ferro_orm-0.11.0/mkdocs.yml +0 -170
- ferro_orm-0.11.0/src/ferro/state.py +0 -19
- ferro_orm-0.11.0/tests/test_static_contracts.py +0 -8
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/.github/PYPI_CHECKLIST.md +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/.github/PYPI_SETUP.md +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/.github/generated/wheels.generated.yml +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/.github/workflows/packaging-smoke.yml +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/.github/workflows/publish.yml +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/.github/workflows/release.yml +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/.pre-commit-config.yaml +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/.python-version +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/LICENSE +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/docs/brainstorms/2026-04-29-named-connections-role-routing-requirements.md +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/docs/brainstorms/2026-05-08-typed-query-predicates-requirements.md +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/docs/brainstorms/2026-05-13-configurable-column-storage-types-requirements.md +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/docs/brainstorms/2026-05-14-autogenerate-support-for-db-type-requirements.md +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/docs/brainstorms/2026-05-25-annotated-strenum-cold-hydration-requirements.md +0 -0
- {ferro_orm-0.11.0/docs → ferro_orm-0.12.0/docs/pages}/stylesheets/extra.css +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/docs/plans/2026-04-24-001-refactor-multi-db-backend-architecture-plan.md +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/docs/plans/2026-04-29-001-typed-null-binds-plan.md +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/docs/plans/2026-04-29-002-feat-named-connections-plan.md +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/docs/plans/2026-05-07-001-refactor-generic-model-connection-plan.md +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/docs/plans/2026-05-08-001-feat-typed-query-predicates-plan.md +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/docs/plans/2026-05-13-001-feat-configurable-column-storage-types-plan.md +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/docs/plans/2026-05-25-001-fix-annotated-strenum-cold-hydration-plan.md +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/docs/solutions/README.md +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/docs/solutions/issues/pydantic-slots-missing-after-ferro-hydration.md +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/docs/solutions/issues/python-3.14-deferred-annotation-typeerror-swallow.md +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/docs/solutions/issues/sa-pk-column-nullable-divergence.md +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/docs/solutions/issues/sa-vs-rust-unique-constraint-shape.md +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/docs/solutions/issues/sqlite-integer-decimal-hydrates-as-none.md +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/docs/solutions/issues/sqlite-null-hydrates-as-int-zero.md +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/docs/solutions/issues/typed-where-null-panics-is-null.md +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/docs/solutions/patterns/configurable-column-storage-types.md +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/docs/solutions/patterns/cross-emitter-ddl-parity.md +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/docs/solutions/patterns/ddl-on-live-engine.md +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/docs/solutions/patterns/foreign-key-index.md +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/docs/solutions/patterns/index-unique-redundancy.md +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/docs/solutions/patterns/shadow-fk-columns.md +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/docs/solutions/patterns/sqlite-alembic-reconnect-hydration-tests.md +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/justfile +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/src/ferro/_annotation_utils.py +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/src/ferro/_shadow_fk_types.py +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/src/ferro/base.py +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/src/ferro/composite_indexes.py +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/src/ferro/composite_uniques.py +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/src/ferro/exceptions.py +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/src/ferro/fields.py +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/src/ferro/migrations/__init__.py +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/src/ferro/py.typed +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/src/ferro/query/__init__.py +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/src/ferro/relations/descriptors.py +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/src/ferro/schema_metadata.py +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/src/introspect.rs +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/src/schema_bind.rs +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/tests/__init__.py +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/tests/conftest.py +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/tests/db_backends.py +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/tests/test_aggregation.py +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/tests/test_alembic_autogenerate.py +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/tests/test_alembic_db_type.py +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/tests/test_alembic_nullability.py +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/tests/test_alembic_type_mapping.py +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/tests/test_auto_migrate.py +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/tests/test_bulk_update.py +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/tests/test_composite_index.py +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/tests/test_composite_unique.py +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/tests/test_connection.py +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/tests/test_connection_redaction.py +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/tests/test_constraints.py +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/tests/test_cross_emitter_parity.py +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/tests/test_crud.py +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/tests/test_db_backends.py +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/tests/test_db_type_cross_emitter_parity.py +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/tests/test_db_type_integration.py +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/tests/test_db_type_typing.py +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/tests/test_db_type_validation.py +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/tests/test_deletion.py +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/tests/test_enum_cold_hydration.py +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/tests/test_field_wrapper.py +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/tests/test_helpers.py +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/tests/test_metaclass_internals.py +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/tests/test_metadata.py +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/tests/test_migrate_plan.py +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/tests/test_models.py +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/tests/test_named_connections_integration.py +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/tests/test_one_to_one.py +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/tests/test_raw_sql.py +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/tests/test_refresh.py +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/tests/test_relationship_engine.py +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/tests/test_schema.py +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/tests/test_schema_constraints.py +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/tests/test_schema_db_type_metadata.py +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/tests/test_schema_enum_annotations.py +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/tests/test_shadow_fk_types.py +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/tests/test_sqlite_alembic_reconnect_hydration.py +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/tests/test_string_search.py +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/tests/test_structural_types.py +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/tests/test_temporal_types.py +0 -0
- {ferro_orm-0.11.0 → ferro_orm-0.12.0}/tests/test_transactions.py +0 -0
|
@@ -133,12 +133,12 @@ permissions:
|
|
|
133
133
|
|
|
134
134
|
**Why These Permissions:**
|
|
135
135
|
- `pages: write` - Allows the workflow to:
|
|
136
|
-
- Deploy the generated
|
|
136
|
+
- Deploy the generated Zensical static site to GitHub Pages
|
|
137
137
|
- Update the Pages deployment for the repository
|
|
138
138
|
- `id-token: write` - Allows secure OIDC auth for Pages deployment
|
|
139
139
|
|
|
140
140
|
**What It Does:**
|
|
141
|
-
- Builds
|
|
141
|
+
- Builds Zensical docs
|
|
142
142
|
- Deploys docs to GitHub Pages
|
|
143
143
|
|
|
144
144
|
---
|
|
@@ -33,4 +33,12 @@
|
|
|
33
33
|
|
|
34
34
|
## Related Issues
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
- Closes #
|
|
37
|
+
- Closes #
|
|
38
|
+
|
|
39
|
+
<!-- Use one line per completed issue: Closes #123 / Fixes #123 / Resolves #123 -->
|
|
40
|
+
|
|
41
|
+
## Exit Steps
|
|
42
|
+
|
|
43
|
+
- [ ] Related completed issues are linked above with Closes/Fixes/Resolves
|
|
44
|
+
- [ ] Issue statuses are updated/auto-close on merge
|
|
@@ -3,9 +3,9 @@ name: CI
|
|
|
3
3
|
on:
|
|
4
4
|
workflow_call:
|
|
5
5
|
pull_request:
|
|
6
|
-
branches: [main]
|
|
6
|
+
branches: [main, feat/ir-first]
|
|
7
7
|
push:
|
|
8
|
-
branches: [main]
|
|
8
|
+
branches: [main, feat/ir-first]
|
|
9
9
|
workflow_dispatch:
|
|
10
10
|
|
|
11
11
|
concurrency:
|
|
@@ -16,6 +16,33 @@ permissions:
|
|
|
16
16
|
contents: read
|
|
17
17
|
|
|
18
18
|
jobs:
|
|
19
|
+
changed-shadow-paths:
|
|
20
|
+
name: Detect Shadow-Report Paths
|
|
21
|
+
runs-on: ubuntu-latest
|
|
22
|
+
if: github.event_name == 'pull_request'
|
|
23
|
+
outputs:
|
|
24
|
+
requires_shadow_reports: ${{ steps.filter.outputs.shadow }}
|
|
25
|
+
steps:
|
|
26
|
+
- name: Checkout repository
|
|
27
|
+
uses: actions/checkout@v4
|
|
28
|
+
|
|
29
|
+
- name: Detect planner/IR path changes
|
|
30
|
+
id: filter
|
|
31
|
+
uses: dorny/paths-filter@v3
|
|
32
|
+
with:
|
|
33
|
+
filters: |
|
|
34
|
+
shadow:
|
|
35
|
+
- 'src/operations.rs'
|
|
36
|
+
- 'src/query.rs'
|
|
37
|
+
- 'src/schema.rs'
|
|
38
|
+
- 'src/migrate.rs'
|
|
39
|
+
- 'src/backend.rs'
|
|
40
|
+
- 'src/connection.rs'
|
|
41
|
+
- 'src/ferro/ir/**'
|
|
42
|
+
- 'crates/ferro-schema-ir/**'
|
|
43
|
+
- 'tests/test_shadow_reports.py'
|
|
44
|
+
- 'tests/fixtures/shadow_reports/**'
|
|
45
|
+
|
|
19
46
|
lint-and-format:
|
|
20
47
|
name: Lint & Format (Pre-commit / Prek)
|
|
21
48
|
runs-on: ubuntu-latest
|
|
@@ -126,6 +153,10 @@ jobs:
|
|
|
126
153
|
run: |
|
|
127
154
|
uv run maturin develop
|
|
128
155
|
|
|
156
|
+
- name: Run IR vector contract harness
|
|
157
|
+
run: |
|
|
158
|
+
uv run pytest -v tests/test_ir_vectors_contract.py
|
|
159
|
+
|
|
129
160
|
- name: Run pytest
|
|
130
161
|
run: |
|
|
131
162
|
uv run pytest -v --cov=src --cov-report=xml --cov-report=term
|
|
@@ -169,6 +200,10 @@ jobs:
|
|
|
169
200
|
run: |
|
|
170
201
|
uv run maturin develop
|
|
171
202
|
|
|
203
|
+
- name: Run IR vector contract harness
|
|
204
|
+
run: |
|
|
205
|
+
uv run pytest -v tests/test_ir_vectors_contract.py
|
|
206
|
+
|
|
172
207
|
- name: Run pytest
|
|
173
208
|
run: |
|
|
174
209
|
uv run pytest -v --cov=src --cov-report=xml --cov-report=term
|
|
@@ -236,6 +271,64 @@ jobs:
|
|
|
236
271
|
run: |
|
|
237
272
|
uv run pytest -v -m "backend_matrix or postgres_only" --db-backends=sqlite,postgres
|
|
238
273
|
|
|
274
|
+
test-shadow-reports-pr:
|
|
275
|
+
name: Shadow reports (touched paths)
|
|
276
|
+
runs-on: ubuntu-latest
|
|
277
|
+
needs: [changed-shadow-paths]
|
|
278
|
+
if: github.event_name == 'pull_request' && needs.changed-shadow-paths.outputs.requires_shadow_reports == 'true'
|
|
279
|
+
services:
|
|
280
|
+
postgres:
|
|
281
|
+
image: postgres:17
|
|
282
|
+
env:
|
|
283
|
+
POSTGRES_USER: ferro
|
|
284
|
+
POSTGRES_PASSWORD: ferro
|
|
285
|
+
POSTGRES_DB: ferro
|
|
286
|
+
ports:
|
|
287
|
+
- 5432:5432
|
|
288
|
+
options: >-
|
|
289
|
+
--health-cmd "pg_isready -U ferro -d ferro"
|
|
290
|
+
--health-interval 10s
|
|
291
|
+
--health-timeout 5s
|
|
292
|
+
--health-retries 5
|
|
293
|
+
env:
|
|
294
|
+
FERRO_SUPABASE_URL: postgresql://ferro:ferro@127.0.0.1:5432/ferro?sslmode=disable
|
|
295
|
+
FERRO_SHADOW_RUNTIME: "1"
|
|
296
|
+
FERRO_SHADOW_RUNTIME_STRICT: "1"
|
|
297
|
+
steps:
|
|
298
|
+
- name: Checkout repository
|
|
299
|
+
uses: actions/checkout@v4
|
|
300
|
+
|
|
301
|
+
- name: Set up Python
|
|
302
|
+
uses: actions/setup-python@v5
|
|
303
|
+
with:
|
|
304
|
+
python-version: '3.13'
|
|
305
|
+
|
|
306
|
+
- name: Install UV
|
|
307
|
+
uses: astral-sh/setup-uv@v5
|
|
308
|
+
with:
|
|
309
|
+
enable-cache: true
|
|
310
|
+
|
|
311
|
+
- name: Set up Rust
|
|
312
|
+
uses: dtolnay/rust-toolchain@stable
|
|
313
|
+
|
|
314
|
+
- name: Cache Rust build
|
|
315
|
+
uses: Swatinem/rust-cache@v2
|
|
316
|
+
with:
|
|
317
|
+
prefix-key: v1
|
|
318
|
+
cache-on-failure: true
|
|
319
|
+
|
|
320
|
+
- name: Install dependencies
|
|
321
|
+
run: |
|
|
322
|
+
uv sync --only-group ci-test --no-install-project --python 3.13
|
|
323
|
+
|
|
324
|
+
- name: Build Rust extension
|
|
325
|
+
run: |
|
|
326
|
+
uv run maturin develop
|
|
327
|
+
|
|
328
|
+
- name: Verify stable shadow reports
|
|
329
|
+
run: |
|
|
330
|
+
uv run pytest -v tests/test_shadow_reports.py::test_shadow_report_fixture_stable --db-backends=sqlite,postgres
|
|
331
|
+
|
|
239
332
|
check-conventional-commits:
|
|
240
333
|
name: Check Conventional Commits
|
|
241
334
|
runs-on: ubuntu-latest
|
|
@@ -285,7 +378,7 @@ jobs:
|
|
|
285
378
|
|
|
286
379
|
all-checks:
|
|
287
380
|
name: All Checks Passed
|
|
288
|
-
needs: [lint-and-format, test-python-pr, test-python-main, test-python-backend-matrix, test-rust]
|
|
381
|
+
needs: [changed-shadow-paths, lint-and-format, test-python-pr, test-python-main, test-python-backend-matrix, test-shadow-reports-pr, test-rust]
|
|
289
382
|
runs-on: ubuntu-latest
|
|
290
383
|
if: always()
|
|
291
384
|
steps:
|
|
@@ -294,10 +387,15 @@ jobs:
|
|
|
294
387
|
run: |
|
|
295
388
|
ok() { [[ "$1" == "success" || "$1" == "skipped" ]]; }
|
|
296
389
|
|
|
390
|
+
if [[ "${{ needs.changed-shadow-paths.result }}" == "failure" ]]; then
|
|
391
|
+
echo "Shadow path detection failed; refusing to treat shadow gate as passed."
|
|
392
|
+
exit 1
|
|
393
|
+
fi
|
|
297
394
|
if ! ok "${{ needs.lint-and-format.result }}"; then exit 1; fi
|
|
298
395
|
if ! ok "${{ needs.test-python-pr.result }}"; then exit 1; fi
|
|
299
396
|
if ! ok "${{ needs.test-python-main.result }}"; then exit 1; fi
|
|
300
397
|
if ! ok "${{ needs.test-python-backend-matrix.result }}"; then exit 1; fi
|
|
398
|
+
if ! ok "${{ needs.test-shadow-reports-pr.result }}"; then exit 1; fi
|
|
301
399
|
if ! ok "${{ needs.test-rust.result }}"; then exit 1; fi
|
|
302
400
|
|
|
303
401
|
echo "All checks passed!"
|
|
@@ -18,7 +18,7 @@ permissions:
|
|
|
18
18
|
|
|
19
19
|
jobs:
|
|
20
20
|
build-docs:
|
|
21
|
-
name: Build docs (
|
|
21
|
+
name: Build docs (Zensical)
|
|
22
22
|
runs-on: ubuntu-latest
|
|
23
23
|
steps:
|
|
24
24
|
- name: Checkout repository
|
|
@@ -40,9 +40,9 @@ jobs:
|
|
|
40
40
|
run: |
|
|
41
41
|
uv sync --only-group docs --no-install-project --python 3.13
|
|
42
42
|
|
|
43
|
-
- name: Build
|
|
43
|
+
- name: Build Zensical site
|
|
44
44
|
run: |
|
|
45
|
-
uv run --no-sync
|
|
45
|
+
uv run --no-sync zensical build --clean
|
|
46
46
|
|
|
47
47
|
- name: Upload Pages artifact
|
|
48
48
|
uses: actions/upload-pages-artifact@v3
|
|
@@ -190,3 +190,89 @@ What this means in practice:
|
|
|
190
190
|
|
|
191
191
|
This rule binds human contributors and AI agents equally, and overrides any
|
|
192
192
|
agent default that biases toward minimal or expedient changes.
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
## I-8: Docs examples show both field-declaration styles
|
|
197
|
+
|
|
198
|
+
Ferro supports two equivalent ways to declare model fields: assignment
|
|
199
|
+
(`name: str = Field(unique=True)`) and `Annotated` metadata
|
|
200
|
+
(`name: Annotated[str, Field(unique=True)]`). Every documentation example
|
|
201
|
+
that declares model fields with `Field()`/`FerroField()` options must show
|
|
202
|
+
**both** styles, side by side, as content tabs:
|
|
203
|
+
|
|
204
|
+
=== "Assignment"
|
|
205
|
+
|
|
206
|
+
```python
|
|
207
|
+
--8<-- "docs/examples/<example>.py:models"
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
=== "Annotated"
|
|
211
|
+
|
|
212
|
+
```python
|
|
213
|
+
--8<-- "docs/examples/<example>_annotated.py:models"
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
Rules:
|
|
217
|
+
|
|
218
|
+
- Both tabs must be backed by real, runnable code. Snippet-embedded model
|
|
219
|
+
definitions get a runnable `<name>_annotated.py` companion in
|
|
220
|
+
`docs/examples/` (exercised by `tests/test_docs_examples.py`); inline
|
|
221
|
+
blocks are written in both styles and compile-checked by the same test.
|
|
222
|
+
- Constructs with only one valid form appear identically in both tabs and
|
|
223
|
+
are not tabbed on their own: forward FKs are always
|
|
224
|
+
`Annotated[Target, ForeignKey(...)]`, and `BackRef()` / `ManyToMany()`
|
|
225
|
+
are always assignments.
|
|
226
|
+
- Code blocks that do not declare fields (queries, mutations, transactions,
|
|
227
|
+
usage snippets) are not affected by this rule.
|
|
228
|
+
|
|
229
|
+
This keeps users from ever wondering whether something is possible in their
|
|
230
|
+
preferred declaration style.
|
|
231
|
+
|
|
232
|
+
---
|
|
233
|
+
|
|
234
|
+
## I-9: Lambda predicates are the official query style
|
|
235
|
+
|
|
236
|
+
Documentation and examples use the lambda predicate style for all queries:
|
|
237
|
+
|
|
238
|
+
```python
|
|
239
|
+
adults = await User.where(lambda t: t.age >= 18).all()
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
Rules:
|
|
243
|
+
|
|
244
|
+
- **Every query example** in docs, docstring `Examples:` sections, and
|
|
245
|
+
`docs/examples/` scripts uses lambda predicates.
|
|
246
|
+
- When the predicate styles themselves are documented, present them in
|
|
247
|
+
order **lambda > `col()` > operator**, with lambda labeled the officially
|
|
248
|
+
recommended style.
|
|
249
|
+
- **Operator style** (`User.where(User.age >= 18)`) is compatible today but
|
|
250
|
+
is slated for deprecation in a future release and fails static type
|
|
251
|
+
checking (`User.age >= 18` types as `bool`; `where()` expects
|
|
252
|
+
`QueryNode | Predicate`). Docs say so explicitly wherever the style is
|
|
253
|
+
shown.
|
|
254
|
+
- **`order_by` is not a predicate** and keeps attribute style
|
|
255
|
+
(`order_by(User.age, "desc")`). Passing a lambda to `order_by` silently
|
|
256
|
+
produces a junk column name — never show it.
|
|
257
|
+
|
|
258
|
+
The canonical comparisons live in `docs/pages/guide/queries.md`
|
|
259
|
+
("Predicate Styles") and `docs/pages/concepts/query-typing.md`; everywhere
|
|
260
|
+
else uses lambda without restating the trade-offs.
|
|
261
|
+
|
|
262
|
+
---
|
|
263
|
+
|
|
264
|
+
## I-10: PRs must close scoped issues explicitly
|
|
265
|
+
|
|
266
|
+
Issue closure is part of feature completion, not optional cleanup.
|
|
267
|
+
|
|
268
|
+
Rules:
|
|
269
|
+
|
|
270
|
+
- Every PR that completes scoped work **must** include GitHub auto-close
|
|
271
|
+
keywords in the PR body for each completed issue, e.g.
|
|
272
|
+
`Closes #89`, `Fixes #90`, `Resolves #91`.
|
|
273
|
+
- Do not rely on manual post-merge issue triage when the work is already done
|
|
274
|
+
in the PR; encode closure directly in the PR body.
|
|
275
|
+
- PRs must include an explicit exit-steps checklist item confirming issue status
|
|
276
|
+
updates are complete before merge.
|
|
277
|
+
- AI agents and human contributors follow the same requirement. If issue status
|
|
278
|
+
closure is missing, the PR is not done.
|
|
@@ -1,6 +1,20 @@
|
|
|
1
1
|
# CHANGELOG
|
|
2
2
|
|
|
3
3
|
|
|
4
|
+
## v0.12.0 (2026-06-23)
|
|
5
|
+
|
|
6
|
+
### Documentation
|
|
7
|
+
|
|
8
|
+
- Rewrite site on Zensical with runnable examples
|
|
9
|
+
([#70](https://github.com/syn54x/ferro-orm/pull/70),
|
|
10
|
+
[`da86911`](https://github.com/syn54x/ferro-orm/commit/da869118c55314363139a021c139a52a2bc8d1fb))
|
|
11
|
+
|
|
12
|
+
### Features
|
|
13
|
+
|
|
14
|
+
- IR-first architecture program (Phases 0–7) ([#116](https://github.com/syn54x/ferro-orm/pull/116),
|
|
15
|
+
[`1c22857`](https://github.com/syn54x/ferro-orm/commit/1c228577aa663c4630a5c8a33f0bb000ebe288b2))
|
|
16
|
+
|
|
17
|
+
|
|
4
18
|
## v0.11.0 (2026-06-11)
|
|
5
19
|
|
|
6
20
|
### Chores
|
|
@@ -37,7 +37,7 @@ This will install all development dependencies including:
|
|
|
37
37
|
- Testing tools (pytest, pytest-asyncio, pytest-cov)
|
|
38
38
|
- Linting and formatting tools (ruff, prek)
|
|
39
39
|
- Build tools (maturin)
|
|
40
|
-
- Documentation tools (
|
|
40
|
+
- Documentation tools (zensical)
|
|
41
41
|
- Release tools (commitizen, python-semantic-release)
|
|
42
42
|
|
|
43
43
|
### 3. Install Pre-commit Hooks
|
|
@@ -102,10 +102,10 @@ cargo clippy # Rust linting
|
|
|
102
102
|
|
|
103
103
|
```bash
|
|
104
104
|
# Serve documentation locally (with live reload)
|
|
105
|
-
uv run
|
|
105
|
+
uv run zensical serve
|
|
106
106
|
|
|
107
107
|
# Build documentation
|
|
108
|
-
uv run
|
|
108
|
+
uv run zensical build
|
|
109
109
|
|
|
110
110
|
# Documentation will be available at http://127.0.0.1:8000/
|
|
111
111
|
```
|