ferro-orm 0.11.0__tar.gz → 0.12.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.
Files changed (266) hide show
  1. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/.github/PERMISSIONS.md +2 -2
  2. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/.github/pull_request_template.md +9 -1
  3. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/.github/workflows/ci.yml +101 -3
  4. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/.github/workflows/publish-docs.yml +3 -3
  5. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/.gitignore +1 -1
  6. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/AGENTS.md +106 -1
  7. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/CHANGELOG.md +23 -0
  8. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/CONTRIBUTING.md +3 -3
  9. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/Cargo.lock +52 -225
  10. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/Cargo.toml +6 -1
  11. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/PKG-INFO +2 -2
  12. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/README.md +1 -1
  13. ferro_orm-0.12.1/crates/ferro-migrate/Cargo.toml +7 -0
  14. ferro_orm-0.12.1/crates/ferro-migrate/src/lib.rs +271 -0
  15. ferro_orm-0.12.1/crates/ferro-schema-ir/Cargo.toml +8 -0
  16. ferro_orm-0.12.1/crates/ferro-schema-ir/src/lib.rs +195 -0
  17. ferro_orm-0.12.1/docs/examples/multiple_databases.py +45 -0
  18. ferro_orm-0.12.1/docs/examples/mutations.py +49 -0
  19. ferro_orm-0.12.1/docs/examples/pagination.py +47 -0
  20. ferro_orm-0.12.1/docs/examples/predicates.py +92 -0
  21. ferro_orm-0.12.1/docs/examples/predicates_annotated.py +36 -0
  22. ferro_orm-0.12.1/docs/examples/quickstart.py +111 -0
  23. ferro_orm-0.12.1/docs/examples/quickstart_annotated.py +48 -0
  24. ferro_orm-0.12.1/docs/examples/raw_sql.py +43 -0
  25. ferro_orm-0.12.1/docs/examples/relationships.py +128 -0
  26. ferro_orm-0.12.1/docs/examples/relationships_annotated.py +108 -0
  27. ferro_orm-0.12.1/docs/examples/soft_deletes.py +61 -0
  28. ferro_orm-0.12.1/docs/examples/soft_deletes_annotated.py +58 -0
  29. ferro_orm-0.12.1/docs/examples/testing_conftest.py +33 -0
  30. ferro_orm-0.12.1/docs/examples/timestamps.py +53 -0
  31. ferro_orm-0.12.1/docs/examples/timestamps_annotated.py +50 -0
  32. ferro_orm-0.12.1/docs/examples/transactions.py +58 -0
  33. ferro_orm-0.12.1/docs/pages/api/connection.md +21 -0
  34. ferro_orm-0.12.1/docs/pages/api/exceptions.md +5 -0
  35. ferro_orm-0.12.1/docs/pages/api/fields.md +15 -0
  36. ferro_orm-0.12.1/docs/pages/api/migrations.md +7 -0
  37. ferro_orm-0.12.1/docs/pages/api/model.md +5 -0
  38. ferro_orm-0.12.1/docs/pages/api/queries.md +11 -0
  39. ferro_orm-0.12.1/docs/pages/api/raw-sql.md +9 -0
  40. ferro_orm-0.12.1/docs/pages/api/relationships.md +11 -0
  41. ferro_orm-0.12.1/docs/pages/api/transactions.md +7 -0
  42. ferro_orm-0.12.1/docs/pages/changelog.md +1 -0
  43. ferro_orm-0.12.1/docs/pages/concepts/architecture.md +234 -0
  44. ferro_orm-0.12.1/docs/pages/concepts/backends.md +107 -0
  45. ferro_orm-0.12.1/docs/pages/concepts/identity-map.md +151 -0
  46. ferro_orm-0.12.1/docs/pages/concepts/performance.md +108 -0
  47. {ferro_orm-0.11.0/docs → ferro_orm-0.12.1/docs/pages}/concepts/query-typing.md +34 -33
  48. ferro_orm-0.12.1/docs/pages/concepts/type-safety.md +110 -0
  49. ferro_orm-0.12.1/docs/pages/contributing.md +5 -0
  50. ferro_orm-0.12.1/docs/pages/faq.md +103 -0
  51. ferro_orm-0.12.1/docs/pages/getting-started/installation.md +76 -0
  52. ferro_orm-0.12.1/docs/pages/getting-started/next-steps.md +56 -0
  53. ferro_orm-0.12.1/docs/pages/getting-started/quickstart.md +103 -0
  54. ferro_orm-0.12.1/docs/pages/guide/connections.md +192 -0
  55. ferro_orm-0.12.1/docs/pages/guide/migrations.md +164 -0
  56. ferro_orm-0.12.1/docs/pages/guide/models-and-fields.md +477 -0
  57. ferro_orm-0.12.1/docs/pages/guide/mutations.md +145 -0
  58. ferro_orm-0.12.1/docs/pages/guide/queries.md +177 -0
  59. ferro_orm-0.12.1/docs/pages/guide/raw-sql.md +109 -0
  60. ferro_orm-0.12.1/docs/pages/guide/relationships.md +240 -0
  61. ferro_orm-0.12.1/docs/pages/guide/transactions.md +121 -0
  62. ferro_orm-0.12.1/docs/pages/howto/migrate-from-sqlalchemy.md +270 -0
  63. ferro_orm-0.12.1/docs/pages/howto/migrating-to-v0-12-0.md +151 -0
  64. ferro_orm-0.12.1/docs/pages/howto/multiple-databases.md +71 -0
  65. ferro_orm-0.12.1/docs/pages/howto/pagination.md +122 -0
  66. ferro_orm-0.12.1/docs/pages/howto/soft-deletes.md +63 -0
  67. ferro_orm-0.12.1/docs/pages/howto/testing.md +169 -0
  68. ferro_orm-0.12.1/docs/pages/howto/timestamps.md +56 -0
  69. ferro_orm-0.12.1/docs/pages/index.md +12 -0
  70. ferro_orm-0.12.1/docs/pages/roadmap.md +22 -0
  71. ferro_orm-0.12.1/docs/pages/why-ferro.md +89 -0
  72. ferro_orm-0.12.1/docs/plans/2026-06-19-001-ir-first-roadmap.md +626 -0
  73. ferro_orm-0.12.1/docs/plans/ir-first-migration-guide.md +165 -0
  74. ferro_orm-0.12.1/docs/plans/ir-first-release-checklist.md +46 -0
  75. ferro_orm-0.12.1/docs/rfc/ir-contracts-v1.md +228 -0
  76. ferro_orm-0.12.1/docs/solutions/architecture-patterns/ir-first-merge-readiness-review.md +235 -0
  77. ferro_orm-0.12.1/docs/solutions/patterns/ir-invariants.md +182 -0
  78. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/docs/solutions/patterns/typed-null-binds.md +21 -28
  79. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/pyproject.toml +8 -7
  80. ferro_orm-0.12.1/scripts/demo_queries.py +271 -0
  81. ferro_orm-0.11.0/scripts/demo_queries.py → ferro_orm-0.12.1/scripts/demo_queries_pre_v012.py +20 -22
  82. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/src/backend.rs +16 -0
  83. ferro_orm-0.12.1/src/codec.rs +517 -0
  84. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/src/connection.rs +17 -2
  85. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/src/ferro/__init__.py +5 -0
  86. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/src/ferro/_core.pyi +44 -11
  87. ferro_orm-0.12.1/src/ferro/_deprecations.py +100 -0
  88. ferro_orm-0.12.1/src/ferro/ir/__init__.py +13 -0
  89. ferro_orm-0.12.1/src/ferro/ir/compiler.py +439 -0
  90. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/src/ferro/metaclass.py +3 -0
  91. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/src/ferro/migrations/alembic.py +184 -14
  92. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/src/ferro/models.py +136 -87
  93. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/src/ferro/query/builder.py +100 -44
  94. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/src/ferro/query/nodes.py +86 -13
  95. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/src/ferro/raw.py +28 -22
  96. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/src/ferro/relations/__init__.py +2 -0
  97. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/src/ferro/relations/descriptors.py +3 -4
  98. ferro_orm-0.12.1/src/ferro/session.py +45 -0
  99. ferro_orm-0.12.1/src/ferro/state.py +146 -0
  100. ferro_orm-0.12.1/src/hydration.rs +57 -0
  101. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/src/lib.rs +8 -0
  102. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/src/migrate.rs +214 -0
  103. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/src/operations.rs +601 -551
  104. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/src/query.rs +308 -223
  105. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/src/schema.rs +32 -0
  106. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/src/state.rs +45 -0
  107. ferro_orm-0.12.1/tests/fixtures/ir_vectors/README.md +45 -0
  108. ferro_orm-0.12.1/tests/fixtures/ir_vectors/codec_registry_core_v1.json +100 -0
  109. ferro_orm-0.12.1/tests/fixtures/ir_vectors/query_user_compound_v1.json +58 -0
  110. ferro_orm-0.12.1/tests/fixtures/ir_vectors/schema_invoice_baseline_v1.json +101 -0
  111. ferro_orm-0.12.1/tests/fixtures/ir_vectors/schema_phase1_fixture_models_v1.json +215 -0
  112. ferro_orm-0.12.1/tests/fixtures/shadow_reports/postgres.json +47 -0
  113. ferro_orm-0.12.1/tests/fixtures/shadow_reports/sqlite.json +47 -0
  114. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/tests/test_alembic_bridge.py +26 -0
  115. ferro_orm-0.12.1/tests/test_deprecated_operator_inventory.py +51 -0
  116. ferro_orm-0.12.1/tests/test_deprecations.py +74 -0
  117. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/tests/test_docs_examples.py +39 -5
  118. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/tests/test_documentation_features.py +27 -22
  119. ferro_orm-0.12.1/tests/test_framework_predicates.py +72 -0
  120. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/tests/test_hydration.py +71 -4
  121. ferro_orm-0.12.1/tests/test_ir_vectors_contract.py +334 -0
  122. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/tests/test_query_builder.py +51 -24
  123. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/tests/test_query_typing.py +20 -10
  124. ferro_orm-0.12.1/tests/test_session.py +130 -0
  125. ferro_orm-0.12.1/tests/test_shadow_reports.py +112 -0
  126. ferro_orm-0.12.1/tests/test_static_contracts.py +8 -0
  127. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/tests/test_typed_null_binds.py +42 -6
  128. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/uv.lock +90 -131
  129. ferro_orm-0.12.1/zensical.toml +145 -0
  130. ferro_orm-0.11.0/docs/TEST_RESULTS.md +0 -210
  131. ferro_orm-0.11.0/docs/api/exceptions.md +0 -15
  132. ferro_orm-0.11.0/docs/api/fields.md +0 -21
  133. ferro_orm-0.11.0/docs/api/model.md +0 -31
  134. ferro_orm-0.11.0/docs/api/query.md +0 -97
  135. ferro_orm-0.11.0/docs/api/raw-sql.md +0 -124
  136. ferro_orm-0.11.0/docs/api/relationships.md +0 -35
  137. ferro_orm-0.11.0/docs/api/transactions.md +0 -36
  138. ferro_orm-0.11.0/docs/api/utilities.md +0 -73
  139. ferro_orm-0.11.0/docs/changelog.md +0 -46
  140. ferro_orm-0.11.0/docs/coming-soon.md +0 -484
  141. ferro_orm-0.11.0/docs/concepts/architecture.md +0 -332
  142. ferro_orm-0.11.0/docs/concepts/identity-map.md +0 -285
  143. ferro_orm-0.11.0/docs/concepts/performance.md +0 -222
  144. ferro_orm-0.11.0/docs/concepts/type-safety.md +0 -183
  145. ferro_orm-0.11.0/docs/contributing.md +0 -3
  146. ferro_orm-0.11.0/docs/faq.md +0 -262
  147. ferro_orm-0.11.0/docs/getting-started/installation.md +0 -86
  148. ferro_orm-0.11.0/docs/getting-started/next-steps.md +0 -159
  149. ferro_orm-0.11.0/docs/getting-started/tutorial.md +0 -388
  150. ferro_orm-0.11.0/docs/guide/backend.md +0 -404
  151. ferro_orm-0.11.0/docs/guide/database.md +0 -385
  152. ferro_orm-0.11.0/docs/guide/migrations.md +0 -445
  153. ferro_orm-0.11.0/docs/guide/models-and-fields.md +0 -272
  154. ferro_orm-0.11.0/docs/guide/mutations.md +0 -478
  155. ferro_orm-0.11.0/docs/guide/queries.md +0 -395
  156. ferro_orm-0.11.0/docs/guide/relationships.md +0 -393
  157. ferro_orm-0.11.0/docs/guide/transactions.md +0 -380
  158. ferro_orm-0.11.0/docs/howto/multiple-databases.md +0 -74
  159. ferro_orm-0.11.0/docs/howto/pagination.md +0 -355
  160. ferro_orm-0.11.0/docs/howto/soft-deletes.md +0 -86
  161. ferro_orm-0.11.0/docs/howto/testing.md +0 -205
  162. ferro_orm-0.11.0/docs/howto/timestamps.md +0 -57
  163. ferro_orm-0.11.0/docs/index.md +0 -142
  164. ferro_orm-0.11.0/docs/migration-sqlalchemy.md +0 -173
  165. ferro_orm-0.11.0/docs/why-ferro.md +0 -206
  166. ferro_orm-0.11.0/mkdocs.yml +0 -170
  167. ferro_orm-0.11.0/src/ferro/state.py +0 -19
  168. ferro_orm-0.11.0/tests/test_static_contracts.py +0 -8
  169. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  170. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  171. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/.github/PYPI_CHECKLIST.md +0 -0
  172. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/.github/PYPI_SETUP.md +0 -0
  173. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/.github/generated/wheels.generated.yml +0 -0
  174. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/.github/workflows/packaging-smoke.yml +0 -0
  175. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/.github/workflows/publish.yml +0 -0
  176. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/.github/workflows/release.yml +0 -0
  177. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/.pre-commit-config.yaml +0 -0
  178. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/.python-version +0 -0
  179. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/LICENSE +0 -0
  180. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/docs/brainstorms/2026-04-29-named-connections-role-routing-requirements.md +0 -0
  181. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/docs/brainstorms/2026-05-08-typed-query-predicates-requirements.md +0 -0
  182. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/docs/brainstorms/2026-05-13-configurable-column-storage-types-requirements.md +0 -0
  183. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/docs/brainstorms/2026-05-14-autogenerate-support-for-db-type-requirements.md +0 -0
  184. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/docs/brainstorms/2026-05-25-annotated-strenum-cold-hydration-requirements.md +0 -0
  185. {ferro_orm-0.11.0/docs → ferro_orm-0.12.1/docs/pages}/stylesheets/extra.css +0 -0
  186. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/docs/plans/2026-04-24-001-refactor-multi-db-backend-architecture-plan.md +0 -0
  187. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/docs/plans/2026-04-29-001-typed-null-binds-plan.md +0 -0
  188. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/docs/plans/2026-04-29-002-feat-named-connections-plan.md +0 -0
  189. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/docs/plans/2026-05-07-001-refactor-generic-model-connection-plan.md +0 -0
  190. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/docs/plans/2026-05-08-001-feat-typed-query-predicates-plan.md +0 -0
  191. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/docs/plans/2026-05-13-001-feat-configurable-column-storage-types-plan.md +0 -0
  192. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/docs/plans/2026-05-25-001-fix-annotated-strenum-cold-hydration-plan.md +0 -0
  193. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/docs/solutions/README.md +0 -0
  194. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/docs/solutions/issues/pydantic-slots-missing-after-ferro-hydration.md +0 -0
  195. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/docs/solutions/issues/python-3.14-deferred-annotation-typeerror-swallow.md +0 -0
  196. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/docs/solutions/issues/sa-pk-column-nullable-divergence.md +0 -0
  197. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/docs/solutions/issues/sa-vs-rust-unique-constraint-shape.md +0 -0
  198. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/docs/solutions/issues/sqlite-integer-decimal-hydrates-as-none.md +0 -0
  199. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/docs/solutions/issues/sqlite-null-hydrates-as-int-zero.md +0 -0
  200. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/docs/solutions/issues/typed-where-null-panics-is-null.md +0 -0
  201. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/docs/solutions/patterns/configurable-column-storage-types.md +0 -0
  202. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/docs/solutions/patterns/cross-emitter-ddl-parity.md +0 -0
  203. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/docs/solutions/patterns/ddl-on-live-engine.md +0 -0
  204. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/docs/solutions/patterns/foreign-key-index.md +0 -0
  205. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/docs/solutions/patterns/index-unique-redundancy.md +0 -0
  206. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/docs/solutions/patterns/shadow-fk-columns.md +0 -0
  207. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/docs/solutions/patterns/sqlite-alembic-reconnect-hydration-tests.md +0 -0
  208. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/justfile +0 -0
  209. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/src/ferro/_annotation_utils.py +0 -0
  210. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/src/ferro/_shadow_fk_types.py +0 -0
  211. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/src/ferro/base.py +0 -0
  212. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/src/ferro/composite_indexes.py +0 -0
  213. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/src/ferro/composite_uniques.py +0 -0
  214. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/src/ferro/exceptions.py +0 -0
  215. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/src/ferro/fields.py +0 -0
  216. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/src/ferro/migrations/__init__.py +0 -0
  217. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/src/ferro/py.typed +0 -0
  218. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/src/ferro/query/__init__.py +0 -0
  219. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/src/ferro/schema_metadata.py +0 -0
  220. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/src/introspect.rs +0 -0
  221. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/src/schema_bind.rs +0 -0
  222. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/tests/__init__.py +0 -0
  223. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/tests/conftest.py +0 -0
  224. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/tests/db_backends.py +0 -0
  225. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/tests/test_aggregation.py +0 -0
  226. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/tests/test_alembic_autogenerate.py +0 -0
  227. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/tests/test_alembic_db_type.py +0 -0
  228. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/tests/test_alembic_nullability.py +0 -0
  229. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/tests/test_alembic_type_mapping.py +0 -0
  230. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/tests/test_auto_migrate.py +0 -0
  231. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/tests/test_bulk_update.py +0 -0
  232. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/tests/test_composite_index.py +0 -0
  233. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/tests/test_composite_unique.py +0 -0
  234. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/tests/test_connection.py +0 -0
  235. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/tests/test_connection_redaction.py +0 -0
  236. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/tests/test_constraints.py +0 -0
  237. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/tests/test_cross_emitter_parity.py +0 -0
  238. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/tests/test_crud.py +0 -0
  239. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/tests/test_db_backends.py +0 -0
  240. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/tests/test_db_type_cross_emitter_parity.py +0 -0
  241. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/tests/test_db_type_integration.py +0 -0
  242. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/tests/test_db_type_typing.py +0 -0
  243. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/tests/test_db_type_validation.py +0 -0
  244. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/tests/test_deletion.py +0 -0
  245. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/tests/test_enum_cold_hydration.py +0 -0
  246. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/tests/test_field_wrapper.py +0 -0
  247. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/tests/test_helpers.py +0 -0
  248. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/tests/test_metaclass_internals.py +0 -0
  249. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/tests/test_metadata.py +0 -0
  250. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/tests/test_migrate_plan.py +0 -0
  251. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/tests/test_models.py +0 -0
  252. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/tests/test_named_connections_integration.py +0 -0
  253. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/tests/test_one_to_one.py +0 -0
  254. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/tests/test_raw_sql.py +0 -0
  255. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/tests/test_refresh.py +0 -0
  256. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/tests/test_relationship_engine.py +0 -0
  257. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/tests/test_schema.py +0 -0
  258. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/tests/test_schema_constraints.py +0 -0
  259. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/tests/test_schema_db_type_metadata.py +0 -0
  260. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/tests/test_schema_enum_annotations.py +0 -0
  261. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/tests/test_shadow_fk_types.py +0 -0
  262. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/tests/test_sqlite_alembic_reconnect_hydration.py +0 -0
  263. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/tests/test_string_search.py +0 -0
  264. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/tests/test_structural_types.py +0 -0
  265. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/tests/test_temporal_types.py +0 -0
  266. {ferro_orm-0.11.0 → ferro_orm-0.12.1}/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 MkDocs static site to GitHub Pages
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 MkDocs docs
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
- <!-- Example: Closes #123 -->
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 (MkDocs)
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 MkDocs site
43
+ - name: Build Zensical site
44
44
  run: |
45
- uv run --no-sync mkdocs build
45
+ uv run --no-sync zensical build --clean
46
46
 
47
47
  - name: Upload Pages artifact
48
48
  uses: actions/upload-pages-artifact@v3
@@ -189,7 +189,7 @@ venv.bak/
189
189
  # Rope project settings
190
190
  .ropeproject
191
191
 
192
- # mkdocs documentation
192
+ # zensical documentation
193
193
  /site
194
194
 
195
195
  # mypy
@@ -90,7 +90,8 @@ If you add a new schema feature (e.g. partial indexes, exclusion constraints):
90
90
  numbered list above.
91
91
  2. Implement it in **both** the Alembic and Rust paths in the same PR.
92
92
  3. Add a parity test that asserts the names match.
93
- 4. Add a regression entry to `CHANGELOG.md`.
93
+ 4. Do not edit `CHANGELOG.md` manually — release tooling records entries at
94
+ release time (see I-11).
94
95
 
95
96
  ---
96
97
 
@@ -190,3 +191,107 @@ What this means in practice:
190
191
 
191
192
  This rule binds human contributors and AI agents equally, and overrides any
192
193
  agent default that biases toward minimal or expedient changes.
194
+
195
+ ---
196
+
197
+ ## I-8: Docs examples show both field-declaration styles
198
+
199
+ Ferro supports two equivalent ways to declare model fields: assignment
200
+ (`name: str = Field(unique=True)`) and `Annotated` metadata
201
+ (`name: Annotated[str, Field(unique=True)]`). Every documentation example
202
+ that declares model fields with `Field()`/`FerroField()` options must show
203
+ **both** styles, side by side, as content tabs:
204
+
205
+ === "Assignment"
206
+
207
+ ```python
208
+ --8<-- "docs/examples/<example>.py:models"
209
+ ```
210
+
211
+ === "Annotated"
212
+
213
+ ```python
214
+ --8<-- "docs/examples/<example>_annotated.py:models"
215
+ ```
216
+
217
+ Rules:
218
+
219
+ - Both tabs must be backed by real, runnable code. Snippet-embedded model
220
+ definitions get a runnable `<name>_annotated.py` companion in
221
+ `docs/examples/` (exercised by `tests/test_docs_examples.py`); inline
222
+ blocks are written in both styles and compile-checked by the same test.
223
+ - Constructs with only one valid form appear identically in both tabs and
224
+ are not tabbed on their own: forward FKs are always
225
+ `Annotated[Target, ForeignKey(...)]`, and `BackRef()` / `ManyToMany()`
226
+ are always assignments.
227
+ - Code blocks that do not declare fields (queries, mutations, transactions,
228
+ usage snippets) are not affected by this rule.
229
+
230
+ This keeps users from ever wondering whether something is possible in their
231
+ preferred declaration style.
232
+
233
+ ---
234
+
235
+ ## I-9: Lambda predicates are the official query style
236
+
237
+ Documentation and examples use the lambda predicate style for all queries:
238
+
239
+ ```python
240
+ adults = await User.where(lambda t: t.age >= 18).all()
241
+ ```
242
+
243
+ Rules:
244
+
245
+ - **Every query example** in docs, docstring `Examples:` sections, and
246
+ `docs/examples/` scripts uses lambda predicates.
247
+ - When the predicate styles themselves are documented, present them in
248
+ order **lambda > `col()` > operator**, with lambda labeled the officially
249
+ recommended style.
250
+ - **Operator style** (`User.where(User.age >= 18)`) is compatible today but
251
+ is slated for deprecation in a future release and fails static type
252
+ checking (`User.age >= 18` types as `bool`; `where()` expects
253
+ `QueryNode | Predicate`). Docs say so explicitly wherever the style is
254
+ shown.
255
+ - **`order_by` is not a predicate** and keeps attribute style
256
+ (`order_by(User.age, "desc")`). Passing a lambda to `order_by` silently
257
+ produces a junk column name — never show it.
258
+
259
+ The canonical comparisons live in `docs/pages/guide/queries.md`
260
+ ("Predicate Styles") and `docs/pages/concepts/query-typing.md`; everywhere
261
+ else uses lambda without restating the trade-offs.
262
+
263
+ ---
264
+
265
+ ## I-10: PRs must close scoped issues explicitly
266
+
267
+ Issue closure is part of feature completion, not optional cleanup.
268
+
269
+ Rules:
270
+
271
+ - Every PR that completes scoped work **must** include GitHub auto-close
272
+ keywords in the PR body for each completed issue, e.g.
273
+ `Closes #89`, `Fixes #90`, `Resolves #91`.
274
+ - Do not rely on manual post-merge issue triage when the work is already done
275
+ in the PR; encode closure directly in the PR body.
276
+ - PRs must include an explicit exit-steps checklist item confirming issue status
277
+ updates are complete before merge.
278
+ - AI agents and human contributors follow the same requirement. If issue status
279
+ closure is missing, the PR is not done.
280
+
281
+ ---
282
+
283
+ ## I-11: Do not edit CHANGELOG.md manually
284
+
285
+ `CHANGELOG.md` is updated automatically by the release workflow (semantic
286
+ release / release tooling). Agents and contributors must **not** add,
287
+ reorder, or edit changelog entries in feature, bugfix, or docs PRs.
288
+
289
+ What to do instead:
290
+
291
+ - Describe user-visible changes in the PR title and body.
292
+ - Rely on conventional commit messages and the release process to populate
293
+ `CHANGELOG.md` after merge.
294
+
295
+ If release tooling fails to capture a change, fix the release configuration or
296
+ commit message conventions — do not patch `CHANGELOG.md` by hand in ordinary
297
+ PRs.
@@ -1,6 +1,29 @@
1
1
  # CHANGELOG
2
2
 
3
3
 
4
+ ## v0.12.1 (2026-06-23)
5
+
6
+ ### Bug Fixes
7
+
8
+ - Stop framework predicate warnings and bind unnamed sessions to default
9
+ ([#124](https://github.com/syn54x/ferro-orm/pull/124),
10
+ [`66b92d8`](https://github.com/syn54x/ferro-orm/commit/66b92d8b691a1ad806691b9841bcbaf93c78f691))
11
+
12
+
13
+ ## v0.12.0 (2026-06-23)
14
+
15
+ ### Documentation
16
+
17
+ - Rewrite site on Zensical with runnable examples
18
+ ([#70](https://github.com/syn54x/ferro-orm/pull/70),
19
+ [`da86911`](https://github.com/syn54x/ferro-orm/commit/da869118c55314363139a021c139a52a2bc8d1fb))
20
+
21
+ ### Features
22
+
23
+ - IR-first architecture program (Phases 0–7) ([#116](https://github.com/syn54x/ferro-orm/pull/116),
24
+ [`1c22857`](https://github.com/syn54x/ferro-orm/commit/1c228577aa663c4630a5c8a33f0bb000ebe288b2))
25
+
26
+
4
27
  ## v0.11.0 (2026-06-11)
5
28
 
6
29
  ### 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 (mkdocs-material)
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 mkdocs serve
105
+ uv run zensical serve
106
106
 
107
107
  # Build documentation
108
- uv run mkdocs build
108
+ uv run zensical build
109
109
 
110
110
  # Documentation will be available at http://127.0.0.1:8000/
111
111
  ```