plain.postgres 0.98.0__tar.gz → 0.99.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.
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/PKG-INFO +101 -20
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/CHANGELOG.md +15 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/README.md +100 -19
- plain_postgres-0.99.0/plain/postgres/cli/diagnose.py +312 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/introspection/__init__.py +2 -0
- plain_postgres-0.99.0/plain/postgres/introspection/health/__init__.py +34 -0
- plain_postgres-0.99.0/plain/postgres/introspection/health/checks_cumulative.py +670 -0
- plain_postgres-0.99.0/plain/postgres/introspection/health/checks_snapshot.py +330 -0
- plain_postgres-0.99.0/plain/postgres/introspection/health/checks_structural.py +292 -0
- plain_postgres-0.99.0/plain/postgres/introspection/health/context.py +223 -0
- plain_postgres-0.99.0/plain/postgres/introspection/health/helpers.py +164 -0
- plain_postgres-0.99.0/plain/postgres/introspection/health/ownership.py +65 -0
- plain_postgres-0.99.0/plain/postgres/introspection/health/runner.py +158 -0
- plain_postgres-0.99.0/plain/postgres/introspection/health/types.py +54 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/pyproject.toml +1 -1
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/test_connection_lifecycle.py +2 -2
- plain_postgres-0.99.0/tests/test_diagnose.py +244 -0
- plain_postgres-0.99.0/tests/test_health.py +47 -0
- plain_postgres-0.98.0/plain/postgres/cli/diagnose.py +0 -206
- plain_postgres-0.98.0/plain/postgres/introspection/health.py +0 -737
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/.gitignore +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/CLAUDE.md +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/LICENSE +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/README.md +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/__init__.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/adapters.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/agents/.claude/rules/plain-postgres.md +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/agents/.claude/skills/plain-postgres-doctor/SKILL.md +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/aggregates.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/base.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/cli/__init__.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/cli/converge.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/cli/core.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/cli/decorators.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/cli/migrations.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/cli/schema.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/cli/sync.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/config.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/connection.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/constants.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/constraints.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/convergence/__init__.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/convergence/analysis.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/convergence/fixes.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/convergence/planning.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/database_url.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/db.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/ddl.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/default_settings.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/deletion.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/dialect.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/entrypoints.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/enums.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/exceptions.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/expressions.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/fields/__init__.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/fields/base.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/fields/binary.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/fields/boolean.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/fields/duration.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/fields/encrypted.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/fields/json.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/fields/mixins.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/fields/network.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/fields/numeric.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/fields/primary_key.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/fields/related.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/fields/related_descriptors.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/fields/related_lookups.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/fields/related_managers.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/fields/reverse_descriptors.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/fields/reverse_related.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/fields/temporal.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/fields/text.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/fields/timezones.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/fields/uuid.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/forms.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/functions/__init__.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/functions/comparison.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/functions/datetime.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/functions/math.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/functions/mixins.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/functions/random.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/functions/text.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/functions/uuid.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/functions/window.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/indexes.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/introspection/schema.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/lookups.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/meta.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/middleware.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/migrations/__init__.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/migrations/autodetector.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/migrations/exceptions.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/migrations/executor.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/migrations/graph.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/migrations/loader.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/migrations/migration.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/migrations/operations/__init__.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/migrations/operations/base.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/migrations/operations/fields.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/migrations/operations/models.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/migrations/operations/special.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/migrations/optimizer.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/migrations/questioner.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/migrations/recorder.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/migrations/serializer.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/migrations/state.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/migrations/utils.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/migrations/writer.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/options.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/otel.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/preflight.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/query.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/query_utils.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/registry.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/schema.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/sources.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/sql/__init__.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/sql/compiler.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/sql/constants.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/sql/datastructures.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/sql/query.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/sql/where.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/test/__init__.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/test/database.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/test/pytest.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/transaction.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/types.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/types.pyi +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/plain/postgres/utils.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/app/examples/forms.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/app/examples/migrations/0001_initial.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/app/examples/migrations/0002_test_field_removed.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/app/examples/migrations/0003_deleteparent_childsetnull_childsetdefault_and_more.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/app/examples/migrations/0004_defaultquerysetmodel_mixintestmodel_and_more.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/app/examples/migrations/0005_feature_carfeature_car_features.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/app/examples/migrations/0006_secretstore.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/app/examples/migrations/0007_treenode_unconstrainedchild.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/app/examples/migrations/0008_setsentinelparent_diamondparenta_midparent_and_more.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/app/examples/migrations/0009_circb_circa_circb_partner.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/app/examples/migrations/0010_hideableitem.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/app/examples/migrations/0011_defaultsexample.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/app/examples/migrations/0012_iterationexample.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/app/examples/migrations/0013_indexexample_constraintexample_nullabilityexample.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/app/examples/migrations/0014_widget_rename_feature_tag_remove_carfeature_car_and_more.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/app/examples/migrations/0015_dbdefaultsexample.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/app/examples/migrations/0016_formsexample.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/app/examples/migrations/0017_random_string_token.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/app/examples/migrations/__init__.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/app/examples/models/__init__.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/app/examples/models/constraints.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/app/examples/models/defaults.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/app/examples/models/delete.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/app/examples/models/encrypted.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/app/examples/models/forms.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/app/examples/models/indexes.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/app/examples/models/iteration.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/app/examples/models/mixins.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/app/examples/models/nullability.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/app/examples/models/querysets.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/app/examples/models/relationships.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/app/examples/models/trees.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/app/examples/models/unregistered.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/app/examples/urls.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/app/examples/views.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/app/settings.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/app/urls.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/conftest.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/conftest_convergence.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/test_autodetector_not_null_errors.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/test_autodetector_type_change.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/test_connection_isolation.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/test_connection_pool.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/test_convergence.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/test_convergence_constraints.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/test_convergence_defaults.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/test_convergence_fk.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/test_convergence_indexes.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/test_convergence_nullability.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/test_convergence_timeouts.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/test_database_url.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/test_db_expression_defaults.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/test_delete_behaviors.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/test_encrypted_fields.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/test_exceptions.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/test_executor_connection_hook.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/test_field_defaults.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/test_functions_uuid.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/test_introspection.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/test_iterator.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/test_literal_default_persistence.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/test_m2m.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/test_management_connection.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/test_manager_assignment.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/test_migration_executor.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/test_mixins.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/test_modelform_roundtrip.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/test_no_callable_defaults.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/test_otel_metrics.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/test_random_string_field.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/test_raw_query.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/test_read_only_transactions.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/test_related.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/test_schema_normalize_type.py +0 -0
- {plain_postgres-0.98.0 → plain_postgres-0.99.0}/tests/test_schema_timeouts.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: plain.postgres
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.99.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
|
|
@@ -1198,37 +1198,110 @@ graph TB
|
|
|
1198
1198
|
|
|
1199
1199
|
## Diagnostics
|
|
1200
1200
|
|
|
1201
|
-
|
|
1201
|
+
Run health checks against your database. `diagnose` is designed to produce
|
|
1202
|
+
only actionable findings — every warning has a copy-paste fix or specific
|
|
1203
|
+
resource to investigate, and noisy one-off signals (hit ratios, XID age) are
|
|
1204
|
+
surfaced as informational context rather than as warnings.
|
|
1202
1205
|
|
|
1203
1206
|
```bash
|
|
1204
1207
|
uv run plain postgres diagnose
|
|
1205
1208
|
```
|
|
1206
1209
|
|
|
1207
|
-
|
|
1210
|
+
Output modes:
|
|
1208
1211
|
|
|
1209
1212
|
```bash
|
|
1210
|
-
uv run plain postgres diagnose --json
|
|
1213
|
+
uv run plain postgres diagnose --json # structured output for scripts/agents
|
|
1214
|
+
uv run plain postgres diagnose --verbose # expand to show every check, including passing
|
|
1215
|
+
uv run plain postgres diagnose --all # include findings on installed-package tables
|
|
1211
1216
|
```
|
|
1212
1217
|
|
|
1213
|
-
|
|
1218
|
+
### Guiding principle
|
|
1214
1219
|
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1220
|
+
`diagnose` emits a **warning** only if the remedy fits in the user's codebase
|
|
1221
|
+
or is an app-level action they own. If the remedy is "run SQL against your
|
|
1222
|
+
DB" or "configure your Postgres server," the check emits **operational
|
|
1223
|
+
context** or an **informational number**, not a warning. This keeps the
|
|
1224
|
+
warning surface high-trust — every warning has an edit-to-make — and prevents
|
|
1225
|
+
`diagnose` from bleeding into DB-host concerns.
|
|
1226
|
+
|
|
1227
|
+
### Warning-tier checks
|
|
1228
|
+
|
|
1229
|
+
Things the user can fix by editing code + running `plain postgres sync`, or
|
|
1230
|
+
app-level incidents they must act on.
|
|
1231
|
+
|
|
1232
|
+
**Structural — always-real; a fix is possible immediately.**
|
|
1233
|
+
|
|
1234
|
+
| Check | What it finds | Severity |
|
|
1235
|
+
| ----------------------- | --------------------------------------------------------------------------------------------------- | ---------------- |
|
|
1236
|
+
| **Invalid indexes** | Broken indexes from failed `CREATE INDEX CONCURRENTLY` — maintained on writes, never used for reads | Warning |
|
|
1237
|
+
| **Duplicate indexes** | One index is a column-prefix of another on the same table | Warning |
|
|
1238
|
+
| **Missing FK indexes** | Foreign key columns without any index coverage | Warning |
|
|
1239
|
+
| **Sequence exhaustion** | Identity sequences approaching their type max | Warning/Critical |
|
|
1240
|
+
|
|
1241
|
+
**Cumulative — depends on stats since the last reset.**
|
|
1242
|
+
|
|
1243
|
+
| Check | What it finds | Severity |
|
|
1244
|
+
| ---------------------------- | -------------------------------------------------------------------------------------------------------------------- | -------- |
|
|
1245
|
+
| **Unused indexes** | Indexes with zero scans since stats reset (>1 MB). Excludes unique, constraint-backing, and sole-FK-coverage indexes | Warning |
|
|
1246
|
+
| **Missing index candidates** | Tables with seq-scan activity suggesting a missing index. Includes top contributing queries from pg_stat_statements | Warning |
|
|
1247
|
+
|
|
1248
|
+
**Snapshot — point-in-time incidents.**
|
|
1249
|
+
|
|
1250
|
+
| Check | What it finds | Severity |
|
|
1251
|
+
| ---------------------------- | ----------------------------------------------------------------------- | ---------------- |
|
|
1252
|
+
| **Long-running connections** | Client backends idle-in-transaction or running a query past a threshold | Warning/Critical |
|
|
1253
|
+
| **Blocking queries** | Queries currently blocking other queries via held locks | Warning/Critical |
|
|
1254
|
+
|
|
1255
|
+
### Operational-context findings
|
|
1256
|
+
|
|
1257
|
+
These are facts about the database whose remedies live outside Plain today
|
|
1258
|
+
(`ANALYZE`, `VACUUM`, `REINDEX`, autovacuum server tuning). They're surfaced
|
|
1259
|
+
so agents and humans can interpret findings correctly, but the CLI renders
|
|
1260
|
+
them as context rather than alarming warnings — the user can't express the
|
|
1261
|
+
fix in their model code. (In JSON output each finding still carries
|
|
1262
|
+
`status: "warning"`; the `tier: "operational"` field is what distinguishes
|
|
1263
|
+
it.) Each finding still carries the exact SQL in its suggestion for anyone
|
|
1264
|
+
who wants to act.
|
|
1265
|
+
|
|
1266
|
+
| Finding | What it reports |
|
|
1267
|
+
| ------------------- | -------------------------------------------------------------------------------- |
|
|
1268
|
+
| **Stats freshness** | Tables whose planner statistics are missing (never analyzed) or stale |
|
|
1269
|
+
| **Vacuum health** | Tables with >10% dead tuples |
|
|
1270
|
+
| **Index bloat** | btree indexes with significant estimated wasted space (≥10 MB, ioguix estimator) |
|
|
1271
|
+
|
|
1272
|
+
If a future release exposes per-table autovacuum / fillfactor parameters in
|
|
1273
|
+
`model_options` (see the `postgres-model-storage-parameters` arc), these
|
|
1274
|
+
findings can graduate back to the warning tier — because the remedy will be
|
|
1275
|
+
expressible in code.
|
|
1218
1276
|
|
|
1219
|
-
###
|
|
1277
|
+
### Informational context
|
|
1220
1278
|
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1279
|
+
Alongside checks, `diagnose` surfaces context an agent or human may want to read but that isn't actionable on its own:
|
|
1280
|
+
|
|
1281
|
+
- **Cache hit ratio**, **Index hit ratio** — buffer hit rates (volatile after restart; not a warning in themselves)
|
|
1282
|
+
- **XID wraparound** — transaction ID age as a percent of the 2B limit. Autovacuum usually keeps this low; long-running transactions can block the freeze process even on managed Postgres
|
|
1283
|
+
- **Connection saturation** — active/max connections at this moment
|
|
1284
|
+
- **Stats reset** — when cumulative stats were last reset (affects the confidence of operational checks)
|
|
1285
|
+
- **pg_stat_statements** — whether the extension is installed
|
|
1286
|
+
|
|
1287
|
+
### Cross-check caveats
|
|
1288
|
+
|
|
1289
|
+
Findings whose confidence depends on another check are tagged with a caveat. For example:
|
|
1290
|
+
|
|
1291
|
+
- `unused_indexes` on a table flagged by `stats_freshness` → caveat: "this table has never been analyzed — the planner may not yet use this index; re-check after running ANALYZE"
|
|
1292
|
+
- `missing_index_candidates` on a never-analyzed table → caveat: "planner statistics are absent — running ANALYZE may change query plans and make this finding moot"
|
|
1293
|
+
|
|
1294
|
+
This prevents false confidence: dropping an "unused" index on a never-analyzed table is often the wrong move.
|
|
1295
|
+
|
|
1296
|
+
### Model-aware suggestions
|
|
1297
|
+
|
|
1298
|
+
Findings on app-owned tables include the Plain model class and its source file. Suggestions reference the exact edit point:
|
|
1299
|
+
|
|
1300
|
+
```
|
|
1301
|
+
app/processing/models.py :: ProcessingResult — Add an Index on ["is_processing"] to the model, then run plain postgres sync
|
|
1302
|
+
```
|
|
1303
|
+
|
|
1304
|
+
This closes the loop from detection to fix — agents can draft the model edit without guessing.
|
|
1232
1305
|
|
|
1233
1306
|
### App vs package issues
|
|
1234
1307
|
|
|
@@ -1248,6 +1321,8 @@ heroku run -a your-app "plain postgres diagnose --json"
|
|
|
1248
1321
|
|
|
1249
1322
|
The `--json` flag must be quoted so Heroku passes it through to the command.
|
|
1250
1323
|
|
|
1324
|
+
Cumulative-stat checks (`stats_freshness`, `vacuum_health`, `unused_indexes`, `missing_index_candidates`, `index_bloat`) need cumulative stat history after the last reset to be reliable. Check the `stats_reset` informational to see how much history you have. (Note: this list spans both the warning and operational tiers — the common thread is that all five depend on counters that `pg_stat_reset()` wipes.)
|
|
1325
|
+
|
|
1251
1326
|
### Preflight checks
|
|
1252
1327
|
|
|
1253
1328
|
Two related checks run automatically during `uv run plain preflight` (and `uv run plain check`):
|
|
@@ -1257,6 +1332,12 @@ Two related checks run automatically during `uv run plain preflight` (and `uv ru
|
|
|
1257
1332
|
|
|
1258
1333
|
These are static, code-level checks that catch issues before you deploy. The `diagnose` command complements them with runtime stats from the actual database.
|
|
1259
1334
|
|
|
1335
|
+
### What diagnose deliberately doesn't do
|
|
1336
|
+
|
|
1337
|
+
- **LLM-powered column recommendations for missing indexes** — `missing_index_candidates` shows the culprit queries and lets you decide. For precise column-level suggestions, use a platform tool (PlanetScale Insights, Dexter, pg_qualstats + hypopg).
|
|
1338
|
+
- **Historical trending** — `diagnose` is stateless; it reports on the current state of cumulative stats. Continuous monitoring is out of scope.
|
|
1339
|
+
- **Niche server checks** (WAL bloat, replication slot age, etc.) — better covered by your Postgres provider's monitoring or a dedicated tool; users on self-hosted setups that need them typically have their own tooling.
|
|
1340
|
+
|
|
1260
1341
|
## Settings
|
|
1261
1342
|
|
|
1262
1343
|
The connection is configured with a single URL (`POSTGRES_URL`). `DATABASE_URL` is read as a platform-compat fallback. Set the URL to `none` to explicitly disable the database (e.g. during Docker image builds).
|
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# plain-postgres changelog
|
|
2
2
|
|
|
3
|
+
## [0.99.0](https://github.com/dropseed/plain/releases/plain-postgres@0.99.0) (2026-04-23)
|
|
4
|
+
|
|
5
|
+
### What's changed
|
|
6
|
+
|
|
7
|
+
- **Reworked `plain postgres diagnose` around tiered findings.** Warnings are now reserved for things the user can fix by editing model code or taking an app-level action — every warning carries a copy-paste fix or a model-file pointer (`app/path.py :: ModelName`). Noisy one-off signals (cache/index hit ratios, XID wraparound, connection saturation, pg_stat_statements availability, stats reset age) render as **informational context**; DB-state facts whose remedies live outside Plain (stats freshness, vacuum health, index bloat) render as **operational context** instead of warnings. Added `--verbose` to expand every check, and `--all` still includes installed-package tables. ([26abb6cbc075](https://github.com/dropseed/plain/commit/26abb6cbc075))
|
|
8
|
+
- **New diagnostic checks:** `stats_freshness` (uses `pg_class.reltuples` so it survives `pg_stat_reset`), `index_bloat` (ioguix btree estimator, public schema only), `missing_index_candidates` (seq-scan heuristics with per-query drill-down from `pg_stat_statements`), `blocking_queries` (wait age from `pg_locks.waitstart`, PG 14+), and `long_running_connections` (xact age for idle-in-transaction). Findings include **cross-check caveats** — e.g. an `unused_indexes` finding on a table that's also flagged by `stats_freshness` or `vacuum_health` now carries a warning that dropping the index may be premature. ([26abb6cbc075](https://github.com/dropseed/plain/commit/26abb6cbc075))
|
|
9
|
+
- **Permission-safe probes.** Checks that may hit permission errors (`pg_stat_statements`, `pg_stat_activity`, `pg_locks`) now wrap their queries in `cursor.connection.transaction()` so a failure rolls back cleanly in either autocommit or transaction mode without cascade-failing later checks. ([26abb6cbc075](https://github.com/dropseed/plain/commit/26abb6cbc075))
|
|
10
|
+
- **Refactored internals.** The 1800+ line `introspection/health.py` split into an `introspection/health/` package along natural seams (types, ownership, context, helpers, checks grouped by `structural`/`cumulative`/`snapshot`, and a runner). Public re-exports are unchanged. ([26abb6cbc075](https://github.com/dropseed/plain/commit/26abb6cbc075))
|
|
11
|
+
- Adapter annotations use `Response` after plain 0.135.0 merged `ResponseBase` into `Response`. ([f5007281d7fa](https://github.com/dropseed/plain/commit/f5007281d7fa))
|
|
12
|
+
|
|
13
|
+
### Upgrade instructions
|
|
14
|
+
|
|
15
|
+
- Requires `plain>=0.135.0`.
|
|
16
|
+
- No code changes required. If you parse `plain postgres diagnose --json`, note the new `tier` field on each finding (`"structural"`, `"cumulative"`, `"snapshot"`, or `"operational"`) — operational findings still carry `status: "warning"` but the CLI renders them as context rather than as alarming warnings.
|
|
17
|
+
|
|
3
18
|
## [0.98.0](https://github.com/dropseed/plain/releases/plain-postgres@0.98.0) (2026-04-22)
|
|
4
19
|
|
|
5
20
|
### What's changed
|
|
@@ -1184,37 +1184,110 @@ graph TB
|
|
|
1184
1184
|
|
|
1185
1185
|
## Diagnostics
|
|
1186
1186
|
|
|
1187
|
-
|
|
1187
|
+
Run health checks against your database. `diagnose` is designed to produce
|
|
1188
|
+
only actionable findings — every warning has a copy-paste fix or specific
|
|
1189
|
+
resource to investigate, and noisy one-off signals (hit ratios, XID age) are
|
|
1190
|
+
surfaced as informational context rather than as warnings.
|
|
1188
1191
|
|
|
1189
1192
|
```bash
|
|
1190
1193
|
uv run plain postgres diagnose
|
|
1191
1194
|
```
|
|
1192
1195
|
|
|
1193
|
-
|
|
1196
|
+
Output modes:
|
|
1194
1197
|
|
|
1195
1198
|
```bash
|
|
1196
|
-
uv run plain postgres diagnose --json
|
|
1199
|
+
uv run plain postgres diagnose --json # structured output for scripts/agents
|
|
1200
|
+
uv run plain postgres diagnose --verbose # expand to show every check, including passing
|
|
1201
|
+
uv run plain postgres diagnose --all # include findings on installed-package tables
|
|
1197
1202
|
```
|
|
1198
1203
|
|
|
1199
|
-
|
|
1204
|
+
### Guiding principle
|
|
1200
1205
|
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1206
|
+
`diagnose` emits a **warning** only if the remedy fits in the user's codebase
|
|
1207
|
+
or is an app-level action they own. If the remedy is "run SQL against your
|
|
1208
|
+
DB" or "configure your Postgres server," the check emits **operational
|
|
1209
|
+
context** or an **informational number**, not a warning. This keeps the
|
|
1210
|
+
warning surface high-trust — every warning has an edit-to-make — and prevents
|
|
1211
|
+
`diagnose` from bleeding into DB-host concerns.
|
|
1212
|
+
|
|
1213
|
+
### Warning-tier checks
|
|
1214
|
+
|
|
1215
|
+
Things the user can fix by editing code + running `plain postgres sync`, or
|
|
1216
|
+
app-level incidents they must act on.
|
|
1217
|
+
|
|
1218
|
+
**Structural — always-real; a fix is possible immediately.**
|
|
1219
|
+
|
|
1220
|
+
| Check | What it finds | Severity |
|
|
1221
|
+
| ----------------------- | --------------------------------------------------------------------------------------------------- | ---------------- |
|
|
1222
|
+
| **Invalid indexes** | Broken indexes from failed `CREATE INDEX CONCURRENTLY` — maintained on writes, never used for reads | Warning |
|
|
1223
|
+
| **Duplicate indexes** | One index is a column-prefix of another on the same table | Warning |
|
|
1224
|
+
| **Missing FK indexes** | Foreign key columns without any index coverage | Warning |
|
|
1225
|
+
| **Sequence exhaustion** | Identity sequences approaching their type max | Warning/Critical |
|
|
1226
|
+
|
|
1227
|
+
**Cumulative — depends on stats since the last reset.**
|
|
1228
|
+
|
|
1229
|
+
| Check | What it finds | Severity |
|
|
1230
|
+
| ---------------------------- | -------------------------------------------------------------------------------------------------------------------- | -------- |
|
|
1231
|
+
| **Unused indexes** | Indexes with zero scans since stats reset (>1 MB). Excludes unique, constraint-backing, and sole-FK-coverage indexes | Warning |
|
|
1232
|
+
| **Missing index candidates** | Tables with seq-scan activity suggesting a missing index. Includes top contributing queries from pg_stat_statements | Warning |
|
|
1233
|
+
|
|
1234
|
+
**Snapshot — point-in-time incidents.**
|
|
1235
|
+
|
|
1236
|
+
| Check | What it finds | Severity |
|
|
1237
|
+
| ---------------------------- | ----------------------------------------------------------------------- | ---------------- |
|
|
1238
|
+
| **Long-running connections** | Client backends idle-in-transaction or running a query past a threshold | Warning/Critical |
|
|
1239
|
+
| **Blocking queries** | Queries currently blocking other queries via held locks | Warning/Critical |
|
|
1240
|
+
|
|
1241
|
+
### Operational-context findings
|
|
1242
|
+
|
|
1243
|
+
These are facts about the database whose remedies live outside Plain today
|
|
1244
|
+
(`ANALYZE`, `VACUUM`, `REINDEX`, autovacuum server tuning). They're surfaced
|
|
1245
|
+
so agents and humans can interpret findings correctly, but the CLI renders
|
|
1246
|
+
them as context rather than alarming warnings — the user can't express the
|
|
1247
|
+
fix in their model code. (In JSON output each finding still carries
|
|
1248
|
+
`status: "warning"`; the `tier: "operational"` field is what distinguishes
|
|
1249
|
+
it.) Each finding still carries the exact SQL in its suggestion for anyone
|
|
1250
|
+
who wants to act.
|
|
1251
|
+
|
|
1252
|
+
| Finding | What it reports |
|
|
1253
|
+
| ------------------- | -------------------------------------------------------------------------------- |
|
|
1254
|
+
| **Stats freshness** | Tables whose planner statistics are missing (never analyzed) or stale |
|
|
1255
|
+
| **Vacuum health** | Tables with >10% dead tuples |
|
|
1256
|
+
| **Index bloat** | btree indexes with significant estimated wasted space (≥10 MB, ioguix estimator) |
|
|
1257
|
+
|
|
1258
|
+
If a future release exposes per-table autovacuum / fillfactor parameters in
|
|
1259
|
+
`model_options` (see the `postgres-model-storage-parameters` arc), these
|
|
1260
|
+
findings can graduate back to the warning tier — because the remedy will be
|
|
1261
|
+
expressible in code.
|
|
1204
1262
|
|
|
1205
|
-
###
|
|
1263
|
+
### Informational context
|
|
1206
1264
|
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1265
|
+
Alongside checks, `diagnose` surfaces context an agent or human may want to read but that isn't actionable on its own:
|
|
1266
|
+
|
|
1267
|
+
- **Cache hit ratio**, **Index hit ratio** — buffer hit rates (volatile after restart; not a warning in themselves)
|
|
1268
|
+
- **XID wraparound** — transaction ID age as a percent of the 2B limit. Autovacuum usually keeps this low; long-running transactions can block the freeze process even on managed Postgres
|
|
1269
|
+
- **Connection saturation** — active/max connections at this moment
|
|
1270
|
+
- **Stats reset** — when cumulative stats were last reset (affects the confidence of operational checks)
|
|
1271
|
+
- **pg_stat_statements** — whether the extension is installed
|
|
1272
|
+
|
|
1273
|
+
### Cross-check caveats
|
|
1274
|
+
|
|
1275
|
+
Findings whose confidence depends on another check are tagged with a caveat. For example:
|
|
1276
|
+
|
|
1277
|
+
- `unused_indexes` on a table flagged by `stats_freshness` → caveat: "this table has never been analyzed — the planner may not yet use this index; re-check after running ANALYZE"
|
|
1278
|
+
- `missing_index_candidates` on a never-analyzed table → caveat: "planner statistics are absent — running ANALYZE may change query plans and make this finding moot"
|
|
1279
|
+
|
|
1280
|
+
This prevents false confidence: dropping an "unused" index on a never-analyzed table is often the wrong move.
|
|
1281
|
+
|
|
1282
|
+
### Model-aware suggestions
|
|
1283
|
+
|
|
1284
|
+
Findings on app-owned tables include the Plain model class and its source file. Suggestions reference the exact edit point:
|
|
1285
|
+
|
|
1286
|
+
```
|
|
1287
|
+
app/processing/models.py :: ProcessingResult — Add an Index on ["is_processing"] to the model, then run plain postgres sync
|
|
1288
|
+
```
|
|
1289
|
+
|
|
1290
|
+
This closes the loop from detection to fix — agents can draft the model edit without guessing.
|
|
1218
1291
|
|
|
1219
1292
|
### App vs package issues
|
|
1220
1293
|
|
|
@@ -1234,6 +1307,8 @@ heroku run -a your-app "plain postgres diagnose --json"
|
|
|
1234
1307
|
|
|
1235
1308
|
The `--json` flag must be quoted so Heroku passes it through to the command.
|
|
1236
1309
|
|
|
1310
|
+
Cumulative-stat checks (`stats_freshness`, `vacuum_health`, `unused_indexes`, `missing_index_candidates`, `index_bloat`) need cumulative stat history after the last reset to be reliable. Check the `stats_reset` informational to see how much history you have. (Note: this list spans both the warning and operational tiers — the common thread is that all five depend on counters that `pg_stat_reset()` wipes.)
|
|
1311
|
+
|
|
1237
1312
|
### Preflight checks
|
|
1238
1313
|
|
|
1239
1314
|
Two related checks run automatically during `uv run plain preflight` (and `uv run plain check`):
|
|
@@ -1243,6 +1318,12 @@ Two related checks run automatically during `uv run plain preflight` (and `uv ru
|
|
|
1243
1318
|
|
|
1244
1319
|
These are static, code-level checks that catch issues before you deploy. The `diagnose` command complements them with runtime stats from the actual database.
|
|
1245
1320
|
|
|
1321
|
+
### What diagnose deliberately doesn't do
|
|
1322
|
+
|
|
1323
|
+
- **LLM-powered column recommendations for missing indexes** — `missing_index_candidates` shows the culprit queries and lets you decide. For precise column-level suggestions, use a platform tool (PlanetScale Insights, Dexter, pg_qualstats + hypopg).
|
|
1324
|
+
- **Historical trending** — `diagnose` is stateless; it reports on the current state of cumulative stats. Continuous monitoring is out of scope.
|
|
1325
|
+
- **Niche server checks** (WAL bloat, replication slot age, etc.) — better covered by your Postgres provider's monitoring or a dedicated tool; users on self-hosted setups that need them typically have their own tooling.
|
|
1326
|
+
|
|
1246
1327
|
## Settings
|
|
1247
1328
|
|
|
1248
1329
|
The connection is configured with a single URL (`POSTGRES_URL`). `DATABASE_URL` is read as a platform-compat fallback. Set the URL to `none` to explicitly disable the database (e.g. during Docker image builds).
|