plain.postgres 0.108.1__tar.gz → 0.110.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.
Files changed (222) hide show
  1. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/PKG-INFO +2 -2
  2. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/CHANGELOG.md +29 -2
  3. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/README.md +1 -1
  4. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/base.py +5 -8
  5. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/connection.py +1 -1
  6. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/convergence/analysis.py +163 -86
  7. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/fields/__init__.py +1 -3
  8. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/fields/related.py +34 -174
  9. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/fields/related_descriptors.py +8 -54
  10. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/fields/related_lookups.py +24 -18
  11. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/fields/related_managers.py +32 -43
  12. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/fields/reverse_related.py +7 -88
  13. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/forms.py +1 -1
  14. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/lookups.py +14 -9
  15. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/meta.py +1 -2
  16. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/migrations/autodetector.py +4 -11
  17. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/query.py +0 -17
  18. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/query_utils.py +1 -1
  19. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/sql/compiler.py +1 -1
  20. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/sql/datastructures.py +8 -8
  21. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/sql/query.py +10 -13
  22. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/types.pyi +0 -9
  23. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/pyproject.toml +1 -1
  24. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/app/examples/migrations/0007_treenode_unconstrainedchild.py +0 -18
  25. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/app/examples/models/delete.py +0 -11
  26. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/internal/test_convergence_constraints.py +112 -47
  27. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/internal/test_convergence_fk.py +1 -15
  28. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/internal/test_convergence_indexes.py +20 -20
  29. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/internal/test_literal_default_persistence.py +5 -5
  30. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/public/test_delete_behaviors.py +0 -24
  31. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/public/test_related.py +0 -27
  32. plain_postgres-0.110.0/tests/public/test_related_instance_filter.py +89 -0
  33. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/.gitignore +0 -0
  34. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/CLAUDE.md +0 -0
  35. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/LICENSE +0 -0
  36. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/README.md +0 -0
  37. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/__init__.py +0 -0
  38. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/adapters.py +0 -0
  39. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/agents/.claude/rules/plain-postgres.md +0 -0
  40. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/agents/.claude/skills/plain-postgres-doctor/SKILL.md +0 -0
  41. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/aggregates.py +0 -0
  42. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/cli/__init__.py +0 -0
  43. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/cli/converge.py +0 -0
  44. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/cli/core.py +0 -0
  45. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/cli/decorators.py +0 -0
  46. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/cli/diagnose.py +0 -0
  47. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/cli/migrations.py +0 -0
  48. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/cli/schema.py +0 -0
  49. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/cli/sync.py +0 -0
  50. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/config.py +0 -0
  51. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/constants.py +0 -0
  52. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/constraints.py +0 -0
  53. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/convergence/__init__.py +0 -0
  54. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/convergence/fixes.py +0 -0
  55. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/convergence/planning.py +0 -0
  56. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/database_url.py +0 -0
  57. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/db.py +0 -0
  58. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/ddl.py +0 -0
  59. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/default_settings.py +0 -0
  60. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/deletion.py +0 -0
  61. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/dialect.py +0 -0
  62. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/entrypoints.py +0 -0
  63. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/enums.py +0 -0
  64. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/exceptions.py +0 -0
  65. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/expressions.py +0 -0
  66. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/fields/base.py +0 -0
  67. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/fields/binary.py +0 -0
  68. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/fields/boolean.py +0 -0
  69. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/fields/duration.py +0 -0
  70. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/fields/encrypted.py +0 -0
  71. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/fields/json.py +0 -0
  72. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/fields/mixins.py +0 -0
  73. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/fields/network.py +0 -0
  74. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/fields/numeric.py +0 -0
  75. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/fields/primary_key.py +0 -0
  76. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/fields/reverse_descriptors.py +0 -0
  77. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/fields/temporal.py +0 -0
  78. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/fields/text.py +0 -0
  79. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/fields/timezones.py +0 -0
  80. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/fields/uuid.py +0 -0
  81. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/functions/__init__.py +0 -0
  82. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/functions/comparison.py +0 -0
  83. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/functions/datetime.py +0 -0
  84. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/functions/math.py +0 -0
  85. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/functions/mixins.py +0 -0
  86. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/functions/random.py +0 -0
  87. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/functions/text.py +0 -0
  88. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/functions/uuid.py +0 -0
  89. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/functions/window.py +0 -0
  90. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/indexes.py +0 -0
  91. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/introspection/__init__.py +0 -0
  92. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/introspection/health/__init__.py +0 -0
  93. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/introspection/health/checks_cumulative.py +0 -0
  94. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/introspection/health/checks_snapshot.py +0 -0
  95. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/introspection/health/checks_structural.py +0 -0
  96. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/introspection/health/context.py +0 -0
  97. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/introspection/health/helpers.py +0 -0
  98. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/introspection/health/ownership.py +0 -0
  99. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/introspection/health/runner.py +0 -0
  100. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/introspection/health/types.py +0 -0
  101. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/introspection/schema.py +0 -0
  102. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/middleware.py +0 -0
  103. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/migrations/__init__.py +0 -0
  104. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/migrations/exceptions.py +0 -0
  105. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/migrations/executor.py +0 -0
  106. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/migrations/graph.py +0 -0
  107. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/migrations/loader.py +0 -0
  108. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/migrations/migration.py +0 -0
  109. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/migrations/operations/__init__.py +0 -0
  110. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/migrations/operations/base.py +0 -0
  111. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/migrations/operations/fields.py +0 -0
  112. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/migrations/operations/models.py +0 -0
  113. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/migrations/operations/special.py +0 -0
  114. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/migrations/optimizer.py +0 -0
  115. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/migrations/questioner.py +0 -0
  116. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/migrations/recorder.py +0 -0
  117. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/migrations/serializer.py +0 -0
  118. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/migrations/state.py +0 -0
  119. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/migrations/utils.py +0 -0
  120. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/migrations/writer.py +0 -0
  121. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/options.py +0 -0
  122. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/otel.py +0 -0
  123. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/preflight/__init__.py +0 -0
  124. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/preflight/database.py +0 -0
  125. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/preflight/indexes.py +0 -0
  126. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/preflight/models.py +0 -0
  127. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/registry.py +0 -0
  128. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/schema.py +0 -0
  129. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/sources.py +0 -0
  130. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/sql/__init__.py +0 -0
  131. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/sql/constants.py +0 -0
  132. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/sql/where.py +0 -0
  133. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/test/__init__.py +0 -0
  134. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/test/database.py +0 -0
  135. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/test/pytest.py +0 -0
  136. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/transaction.py +0 -0
  137. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/types.py +0 -0
  138. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/plain/postgres/utils.py +0 -0
  139. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/app/examples/forms.py +0 -0
  140. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/app/examples/migrations/0001_initial.py +0 -0
  141. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/app/examples/migrations/0002_test_field_removed.py +0 -0
  142. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/app/examples/migrations/0003_deleteparent_childsetnull_childsetdefault_and_more.py +0 -0
  143. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/app/examples/migrations/0004_defaultquerysetmodel_mixintestmodel_and_more.py +0 -0
  144. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/app/examples/migrations/0005_feature_carfeature_car_features.py +0 -0
  145. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/app/examples/migrations/0006_secretstore.py +0 -0
  146. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/app/examples/migrations/0008_setsentinelparent_diamondparenta_midparent_and_more.py +0 -0
  147. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/app/examples/migrations/0009_circb_circa_circb_partner.py +0 -0
  148. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/app/examples/migrations/0010_hideableitem.py +0 -0
  149. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/app/examples/migrations/0011_defaultsexample.py +0 -0
  150. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/app/examples/migrations/0012_iterationexample.py +0 -0
  151. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/app/examples/migrations/0013_indexexample_constraintexample_nullabilityexample.py +0 -0
  152. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/app/examples/migrations/0014_widget_rename_feature_tag_remove_carfeature_car_and_more.py +0 -0
  153. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/app/examples/migrations/0015_dbdefaultsexample.py +0 -0
  154. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/app/examples/migrations/0016_formsexample.py +0 -0
  155. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/app/examples/migrations/0017_random_string_token.py +0 -0
  156. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/app/examples/migrations/0018_storageparametersexample.py +0 -0
  157. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/app/examples/migrations/__init__.py +0 -0
  158. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/app/examples/models/__init__.py +0 -0
  159. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/app/examples/models/constraints.py +0 -0
  160. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/app/examples/models/defaults.py +0 -0
  161. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/app/examples/models/encrypted.py +0 -0
  162. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/app/examples/models/forms.py +0 -0
  163. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/app/examples/models/indexes.py +0 -0
  164. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/app/examples/models/iteration.py +0 -0
  165. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/app/examples/models/mixins.py +0 -0
  166. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/app/examples/models/nullability.py +0 -0
  167. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/app/examples/models/querysets.py +0 -0
  168. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/app/examples/models/relationships.py +0 -0
  169. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/app/examples/models/storage_parameters.py +0 -0
  170. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/app/examples/models/trees.py +0 -0
  171. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/app/examples/models/unregistered.py +0 -0
  172. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/app/examples/urls.py +0 -0
  173. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/app/examples/views.py +0 -0
  174. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/app/settings.py +0 -0
  175. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/app/urls.py +0 -0
  176. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/conftest.py +0 -0
  177. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/conftest_convergence.py +0 -0
  178. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/internal/test_autodetector_not_null_errors.py +0 -0
  179. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/internal/test_autodetector_type_change.py +0 -0
  180. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/internal/test_connection_isolation.py +0 -0
  181. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/internal/test_connection_lifecycle.py +0 -0
  182. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/internal/test_connection_pool.py +0 -0
  183. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/internal/test_connection_self_heal.py +0 -0
  184. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/internal/test_constraint_violation_error.py +0 -0
  185. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/internal/test_convergence.py +0 -0
  186. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/internal/test_convergence_defaults.py +0 -0
  187. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/internal/test_convergence_nullability.py +0 -0
  188. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/internal/test_convergence_storage_parameters.py +0 -0
  189. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/internal/test_convergence_timeouts.py +0 -0
  190. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/internal/test_db_expression_defaults.py +0 -0
  191. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/internal/test_diagnose.py +0 -0
  192. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/internal/test_executor_connection_hook.py +0 -0
  193. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/internal/test_fk_characterization.py +0 -0
  194. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/internal/test_health.py +0 -0
  195. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/internal/test_introspection.py +0 -0
  196. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/internal/test_management_connection.py +0 -0
  197. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/internal/test_migration_executor.py +0 -0
  198. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/internal/test_no_callable_defaults.py +0 -0
  199. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/internal/test_otel_metrics.py +0 -0
  200. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/internal/test_preflight_duplicate_indexes.py +0 -0
  201. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/internal/test_preflight_fk_composite_hint.py +0 -0
  202. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/internal/test_preflight_fk_coverage.py +0 -0
  203. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/internal/test_schema_normalize_type.py +0 -0
  204. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/internal/test_schema_timeouts.py +0 -0
  205. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/public/test_create_update.py +0 -0
  206. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/public/test_database_url.py +0 -0
  207. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/public/test_deferred_loading.py +0 -0
  208. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/public/test_encrypted_fields.py +0 -0
  209. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/public/test_exceptions.py +0 -0
  210. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/public/test_field_defaults.py +0 -0
  211. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/public/test_functions_uuid.py +0 -0
  212. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/public/test_integrity_error_mapping.py +0 -0
  213. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/public/test_iterator.py +0 -0
  214. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/public/test_m2m.py +0 -0
  215. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/public/test_manager_assignment.py +0 -0
  216. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/public/test_manual_pk.py +0 -0
  217. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/public/test_mixins.py +0 -0
  218. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/public/test_modelform_roundtrip.py +0 -0
  219. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/public/test_queryset_repr.py +0 -0
  220. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/public/test_random_string_field.py +0 -0
  221. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/public/test_raw_query.py +0 -0
  222. {plain_postgres-0.108.1 → plain_postgres-0.110.0}/tests/public/test_read_only_transactions.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: plain.postgres
3
- Version: 0.108.1
3
+ Version: 0.110.0
4
4
  Summary: Model your data and store it in a database.
5
5
  Author-email: Dave Gaeddert <dave.gaeddert@dropseed.dev>
6
6
  License-Expression: BSD-3-Clause
@@ -957,7 +957,7 @@ book.author.name # one query — loads the rest of the row
957
957
 
958
958
  The first access to any non-key field loads the whole row in a single query. There is no separate `author_id` attribute — `book.author.id` is the foreign key value, and it is type-checked because `book.author` is an `Author`. In loops, use `select_related()` to load related rows up front and avoid a query per row.
959
959
 
960
- The partial-instance shortcut relies on the database guaranteeing the row exists. A foreign key declared with `db_constraint=False` has no such guarantee, so it is queried on access instead — a stale key raises `DoesNotExist` right away rather than yielding a placeholder.
960
+ The partial-instance shortcut is safe because Plain always creates a database foreign-key constraint, so the referenced row is guaranteed to exist.
961
961
 
962
962
  ### Reverse relationships
963
963
 
@@ -1,5 +1,32 @@
1
1
  # plain-postgres changelog
2
2
 
3
+ ## [0.110.0](https://github.com/dropseed/plain/releases/plain-postgres@0.110.0) (2026-06-17)
4
+
5
+ ### What's changed
6
+
7
+ - Internal: the foreign-key/related-field internals are collapsed to the single-column-to-`id` model Plain actually uses, removing the inherited Django composite-key and `to_field` scaffolding. `PathInfo.target_fields` (a tuple) becomes a scalar `target_field`, and a `Join` now holds one `join_col` pair instead of a `join_cols` list. The unused multi-column helpers go with it: `RelatedField.resolve_related_fields()`, the `related_fields`/`local_related_fields`/`foreign_related_fields` properties, `ForeignKeyField.get_reverse_joining_columns()`, and `ForeignObjectRel.get_related_field()` / `field_name` / `set_field_name()` / `db_type` / the `multiple` flag (along with its now-dead reverse-cache priming, left over from the long-removed one-to-one relation). `get_local_related_value()`, `get_foreign_related_value()`, and the join-column accessors now return scalars instead of 1-tuples. ([cbd15fb707](https://github.com/dropseed/plain/commit/cbd15fb707))
8
+ - Internal: the related-lookup prep path (`related_lookups.py`, `lookups.py`) now narrows on `RelatedField | ForeignObjectRel` to find a relation's target field instead of duck-typing with `getattr(output_field, "target_field")` / `hasattr(..., "path_infos")`, so the dependency is greppable, type-checked, and fails loudly if it's ever removed rather than silently falling back. ([cbd15fb707](https://github.com/dropseed/plain/commit/cbd15fb707))
9
+
10
+ ### Upgrade instructions
11
+
12
+ - No changes required. These are internal ORM query-construction details — how foreign keys, reverse relations, and many-to-many relations behave (filtering, prefetching, related-manager access) is unchanged.
13
+
14
+ ## [0.109.0](https://github.com/dropseed/plain/releases/plain-postgres@0.109.0) (2026-06-17)
15
+
16
+ ### What's changed
17
+
18
+ - **The `db_constraint` argument is removed from `ForeignKeyField` — every foreign key is now backed by a database `FOREIGN KEY` constraint, always.** Because the database guarantees the referenced row exists, accessing a foreign key always builds a partial related instance from just the stored id (no query); the old "query on access when unconstrained" path is gone. The `fields.foreign_key_unconstrained_requires_no_action` preflight check is also removed. ([9ec559db38](https://github.com/dropseed/plain/commit/9ec559db38))
19
+ - **`limit_choices_to` is removed from `ForeignKeyField` and `ManyToManyField`.** The supporting machinery goes with it: `RelatedField.get_choices()` / `get_limit_choices_to()`, `ForeignObjectRel.get_choices()`, and `QuerySet.complex_filter()` are removed, and `BLANK_CHOICE_DASH` is no longer exported from `plain.postgres.fields`. To restrict the rows offered for a relation, filter the queryset explicitly in your form or view. ([68b6ced4f0](https://github.com/dropseed/plain/commit/68b6ced4f0))
20
+ - **The redundant foreign-key existence pre-check is removed.** `ForeignKeyField.validate()` no longer runs a `SELECT ... EXISTS` query to confirm the target row exists — one fewer query per FK validation. The database `FOREIGN KEY` constraint already enforces this, rejecting an invalid reference at write time (as a `psycopg.IntegrityError`). ([68b6ced4f0](https://github.com/dropseed/plain/commit/68b6ced4f0))
21
+ - Internal: convergence (schema-drift) analysis now reuses a single session-private temp "probe" table per model across all of that model's round-trip comparisons, instead of creating and dropping one per index/constraint/default comparison — fewer DDL statements during schema checks. The internal `canon*` helpers were renamed to `probe`/`normalize`. ([67167a11ee](https://github.com/dropseed/plain/commit/67167a11ee), [06650bea63](https://github.com/dropseed/plain/commit/06650bea63))
22
+
23
+ ### Upgrade instructions
24
+
25
+ - Remove any `db_constraint=False` arguments from `ForeignKeyField`. Foreign keys are always DB-constrained now; an unconstrained FK (e.g. for soft/cross-system references) is no longer supported.
26
+ - Remove `limit_choices_to=` from `ForeignKeyField` / `ManyToManyField` definitions. To constrain the rows offered for a relation, filter the related queryset explicitly in your form or view.
27
+ - Replace any `QuerySet.complex_filter(...)` calls with `.filter(...)` — pass a dict of lookups or a `Q` object directly.
28
+ - Most projects use none of these and need no changes.
29
+
3
30
  ## [0.108.1](https://github.com/dropseed/plain/releases/plain-postgres@0.108.1) (2026-06-09)
4
31
 
5
32
  ### What's changed
@@ -41,7 +68,7 @@
41
68
 
42
69
  ### Upgrade instructions
43
70
 
44
- - Replace `form.save()` with `form.create()` in create flows and `form.update()` in update flows. The `/plain-upgrade` skill rewrites these for you — the create-vs-update choice is context-dependent, so it reasons per call site.
71
+ - Replace `form.save()` with `form.create()` in create flows and `form.update()` in update flows.
45
72
  - `form.update(fields=[...])` is available to limit the columns written (a pass-through to `Model.update(fields=...)`).
46
73
  - For the old `form.save(commit=False)` pattern (set extra non-form attributes, then save), assign those attributes on `form.instance` after `is_valid()`, then call `form.create()` / `form.update()` — m2m data is still saved for you, so the separate `save_m2m()` step is no longer needed:
47
74
 
@@ -63,7 +90,7 @@
63
90
 
64
91
  ### Upgrade instructions
65
92
 
66
- - Replace `obj.save()` with `obj.create()` for a new row or `obj.update()` for an existing one; `obj.save(update_fields=[...])` becomes `obj.update(fields=[...])`. The `/plain-upgrade` skill rewrites these for you — the create-vs-update choice is context-dependent, so it reasons per call site.
93
+ - Replace `obj.save()` with `obj.create()` for a new row or `obj.update()` for an existing one; `obj.save(update_fields=[...])` becomes `obj.update(fields=[...])`.
67
94
  - Remove `force_insert=`/`force_update=` — `create()` and `update()` are the explicit forms.
68
95
  - Don't pass `id=` to a model constructor; load existing rows with `Model.query.get(id=...)`.
69
96
  - Catch `ValidationError` (or `(psycopg.IntegrityError, ValidationError)` when retrying) for unique/check conflicts on instance writes. Inside an open `transaction.atomic()` a violation aborts the transaction — wrap the write in its own `atomic()` to catch and continue.
@@ -944,7 +944,7 @@ book.author.name # one query — loads the rest of the row
944
944
 
945
945
  The first access to any non-key field loads the whole row in a single query. There is no separate `author_id` attribute — `book.author.id` is the foreign key value, and it is type-checked because `book.author` is an `Author`. In loops, use `select_related()` to load related rows up front and avoid a query per row.
946
946
 
947
- The partial-instance shortcut relies on the database guaranteeing the row exists. A foreign key declared with `db_constraint=False` has no such guarantee, so it is queried on access instead — a stale key raises `DoesNotExist` right away rather than yielding a placeholder.
947
+ The partial-instance shortcut is safe because Plain always creates a database foreign-key constraint, so the referenced row is guaranteed to exist.
948
948
 
949
949
  ### Reverse relationships
950
950
 
@@ -538,9 +538,6 @@ class Model(metaclass=ModelBase):
538
538
  # constraints aren't supported by the database, there's the
539
539
  # unavoidable risk of data corruption.
540
540
  if obj.id is None:
541
- # Remove the object from a related instance cache.
542
- if not field.remote_field.multiple:
543
- field.remote_field.delete_cached_value(obj)
544
541
  raise ValueError(
545
542
  f"{operation_name}() prohibited to prevent data loss due to unsaved "
546
543
  f"related object '{field.name}'."
@@ -549,10 +546,10 @@ class Model(metaclass=ModelBase):
549
546
  # Set related object if it has been saved after an
550
547
  # assignment.
551
548
  setattr(self, field.name, obj)
552
- # If the relationship's pk/to_field was changed, clear the
553
- # cached relationship. Compare the cached object's key against
554
- # the raw key value -- not getattr(self, field.name), which
555
- # for a foreign key returns the related object, not the key.
549
+ # If the relationship's key was changed, clear the cached
550
+ # relationship. Compare the cached object's key against the raw
551
+ # key value -- not getattr(self, field.name), which for a
552
+ # foreign key returns the related object, not the key.
556
553
  if getattr(obj, field.target_field.name) != field.value_from_object(
557
554
  self
558
555
  ):
@@ -622,7 +619,7 @@ class Model(metaclass=ModelBase):
622
619
  raise ValueError(
623
620
  f"Unsaved model instance {self!r} cannot be used in an ORM query."
624
621
  )
625
- return getattr(self, field.remote_field.get_related_field().name)
622
+ return getattr(self, field.target_field.name)
626
623
 
627
624
  def clean(self) -> None:
628
625
  """
@@ -646,7 +646,7 @@ class DatabaseConnection:
646
646
  }
647
647
  # Now get indexes. Sort order, opclasses, INCLUDE, and predicates all
648
648
  # ride along inside `pg_get_indexdef` and are compared via the
649
- # canonical-tail round-trip in convergence — no need to introspect
649
+ # normalized-tail round-trip in convergence — no need to introspect
650
650
  # them here as separate columns.
651
651
  cursor.execute(
652
652
  """