hare-orm 0.9.0__py3-none-any.whl
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.
- hare/__init__.py +47 -0
- hare/__main__.py +8 -0
- hare/classes/__init__.py +1 -0
- hare/classes/class_path.py +50 -0
- hare/classes/class_property.py +18 -0
- hare/classes/comparable_values.py +113 -0
- hare/classes/constants.py +11 -0
- hare/classes/declared_subclass.py +26 -0
- hare/classes/lazy_exports.py +56 -0
- hare/classes/shown_value_repr.py +21 -0
- hare/classes/value_descriptions.py +81 -0
- hare/cli/__init__.py +3 -0
- hare/cli/__main__.py +7 -0
- hare/cli/arg_parser_builder.py +344 -0
- hare/cli/commands/__init__.py +0 -0
- hare/cli/commands/database_shell_commands.py +56 -0
- hare/cli/commands/distributed_recovery_commands.py +86 -0
- hare/cli/commands/interactive_rename_questions.py +30 -0
- hare/cli/commands/migration_commands.py +579 -0
- hare/cli/commands/schema_commands.py +123 -0
- hare/cli/commands/stub_commands.py +52 -0
- hare/cli/config_locator.py +37 -0
- hare/cli/constants.py +24 -0
- hare/cli/context/__init__.py +9 -0
- hare/cli/context/cli_context.py +17 -0
- hare/cli/context/command_context.py +108 -0
- hare/cli/exceptions.py +9 -0
- hare/cli/hare_cli.py +111 -0
- hare/cli/output/__init__.py +1 -0
- hare/cli/output/output_formatter.py +145 -0
- hare/cli/output/terminal_colors.py +89 -0
- hare/cli/plugins/__init__.py +16 -0
- hare/cli/plugins/cli_command.py +43 -0
- hare/cli/plugins/cli_command_registry.py +144 -0
- hare/cli/plugins/loaded_cli_command.py +13 -0
- hare/cli/shell_launcher.py +95 -0
- hare/contrib/__init__.py +0 -0
- hare/contrib/application_lifecycle.py +157 -0
- hare/contrib/factories/__init__.py +39 -0
- hare/contrib/factories/constants.py +21 -0
- hare/contrib/factories/factory_reference.py +27 -0
- hare/contrib/factories/field_declarations/__init__.py +1 -0
- hare/contrib/factories/field_declarations/declaration.py +19 -0
- hare/contrib/factories/field_declarations/faker.py +49 -0
- hare/contrib/factories/field_declarations/iterator.py +36 -0
- hare/contrib/factories/field_declarations/lazy_attribute.py +35 -0
- hare/contrib/factories/field_declarations/lazy_function.py +22 -0
- hare/contrib/factories/field_declarations/many_to_many.py +40 -0
- hare/contrib/factories/field_declarations/post_declaration.py +22 -0
- hare/contrib/factories/field_declarations/related_factory.py +37 -0
- hare/contrib/factories/field_declarations/sequence.py +22 -0
- hare/contrib/factories/field_declarations/sub_factory.py +30 -0
- hare/contrib/factories/model_factory.py +284 -0
- hare/contrib/factories/trait.py +23 -0
- hare/contrib/frameworks/__init__.py +14 -0
- hare/contrib/frameworks/constants.py +45 -0
- hare/contrib/frameworks/error_answers.py +93 -0
- hare/contrib/frameworks/exceptions.py +19 -0
- hare/contrib/frameworks/fastapi/__init__.py +12 -0
- hare/contrib/frameworks/fastapi/constants.py +4 -0
- hare/contrib/frameworks/fastapi/hare_exception_handlers.py +103 -0
- hare/contrib/frameworks/fastapi/hare_fast_api.py +139 -0
- hare/contrib/frameworks/fastapi/middleware/__init__.py +7 -0
- hare/contrib/frameworks/fastapi/middleware/request_state_reset_middleware.py +27 -0
- hare/contrib/frameworks/fastapi/middleware/transaction_failing_handler.py +31 -0
- hare/contrib/frameworks/fastapi/middleware/transaction_middleware.py +72 -0
- hare/contrib/frameworks/fastapi/request_query_dependency.py +88 -0
- hare/contrib/frameworks/hare_lifecycle.py +50 -0
- hare/contrib/frameworks/health_routes.py +101 -0
- hare/contrib/frameworks/litestar/__init__.py +14 -0
- hare/contrib/frameworks/litestar/constants.py +18 -0
- hare/contrib/frameworks/litestar/hare_dto.py +194 -0
- hare/contrib/frameworks/litestar/hare_exception_handlers.py +77 -0
- hare/contrib/frameworks/litestar/hare_plugin.py +181 -0
- hare/contrib/frameworks/litestar/hare_transfer_function_factory.py +38 -0
- hare/contrib/frameworks/litestar/middleware/__init__.py +7 -0
- hare/contrib/frameworks/litestar/middleware/request_state_reset_middleware.py +23 -0
- hare/contrib/frameworks/litestar/middleware/transaction_middleware.py +35 -0
- hare/contrib/frameworks/litestar/request_query_di_plugin.py +96 -0
- hare/contrib/frameworks/pages/__init__.py +22 -0
- hare/contrib/frameworks/pages/cursor_page_schema.py +25 -0
- hare/contrib/frameworks/pages/page_schema.py +25 -0
- hare/contrib/frameworks/pages/scroll_page_schema.py +23 -0
- hare/contrib/frameworks/parameter_annotation.py +110 -0
- hare/contrib/frameworks/request_state.py +16 -0
- hare/contrib/frameworks/request_transaction.py +186 -0
- hare/contrib/frameworks/robyn/__init__.py +13 -0
- hare/contrib/frameworks/robyn/application/__init__.py +11 -0
- hare/contrib/frameworks/robyn/application/hare_robyn.py +199 -0
- hare/contrib/frameworks/robyn/application/hare_sub_router.py +50 -0
- hare/contrib/frameworks/robyn/constants.py +32 -0
- hare/contrib/frameworks/robyn/hare_exception_handlers.py +128 -0
- hare/contrib/frameworks/robyn/hare_open_api.py +91 -0
- hare/contrib/frameworks/robyn/route_handler.py +198 -0
- hare/contrib/mypy/__init__.py +11 -0
- hare/contrib/mypy/annotation_types.py +170 -0
- hare/contrib/mypy/constants.py +83 -0
- hare/contrib/mypy/enums.py +18 -0
- hare/contrib/mypy/field_names_check.py +222 -0
- hare/contrib/mypy/filter_arguments_check.py +129 -0
- hare/contrib/mypy/hare_mypy_plugin.py +166 -0
- hare/contrib/mypy/instance_attribute_types.py +137 -0
- hare/contrib/mypy/model_registry.py +127 -0
- hare/contrib/mypy/mypy_types.py +383 -0
- hare/contrib/mypy/queryset_extension_methods.py +109 -0
- hare/contrib/mypy/values_row_types.py +146 -0
- hare/contrib/mypy/write_arguments_check.py +159 -0
- hare/contrib/notify/__init__.py +5 -0
- hare/contrib/notify/constants.py +14 -0
- hare/contrib/notify/notification_listener.py +317 -0
- hare/contrib/opentelemetry/__init__.py +16 -0
- hare/contrib/opentelemetry/constants.py +31 -0
- hare/contrib/opentelemetry/open_telemetry_instrumentor.py +60 -0
- hare/contrib/opentelemetry/pool_metric_instruments.py +210 -0
- hare/contrib/opentelemetry/query_spans.py +69 -0
- hare/contrib/outbox/__init__.py +65 -0
- hare/contrib/outbox/broker_arguments.py +40 -0
- hare/contrib/outbox/brokers/__init__.py +1 -0
- hare/contrib/outbox/brokers/rabbitmq_connection.py +55 -0
- hare/contrib/outbox/brokers/redis_connection.py +42 -0
- hare/contrib/outbox/capture/__init__.py +6 -0
- hare/contrib/outbox/capture/change_capture.py +366 -0
- hare/contrib/outbox/capture/change_extension.py +22 -0
- hare/contrib/outbox/capture/constants.py +19 -0
- hare/contrib/outbox/constants.py +31 -0
- hare/contrib/outbox/deliveries/__init__.py +22 -0
- hare/contrib/outbox/deliveries/callable_delivery.py +44 -0
- hare/contrib/outbox/deliveries/constants.py +19 -0
- hare/contrib/outbox/deliveries/kafka_delivery.py +124 -0
- hare/contrib/outbox/deliveries/outbox_delivery.py +106 -0
- hare/contrib/outbox/deliveries/rabbitmq_delivery.py +63 -0
- hare/contrib/outbox/deliveries/redis_streams_delivery.py +110 -0
- hare/contrib/outbox/deliveries/topic_router.py +103 -0
- hare/contrib/outbox/deliveries/webhook_delivery.py +106 -0
- hare/contrib/outbox/exceptions.py +7 -0
- hare/contrib/outbox/outbox_event.py +362 -0
- hare/contrib/outbox/outbox_json_encoding.py +87 -0
- hare/contrib/outbox/relay/__init__.py +7 -0
- hare/contrib/outbox/relay/constants.py +41 -0
- hare/contrib/outbox/relay/declarations.py +76 -0
- hare/contrib/outbox/relay/outbox_backlog.py +18 -0
- hare/contrib/outbox/relay/outbox_relay.py +646 -0
- hare/contrib/outbox/wakeups/__init__.py +20 -0
- hare/contrib/outbox/wakeups/constants.py +20 -0
- hare/contrib/outbox/wakeups/in_process_wakeup.py +17 -0
- hare/contrib/outbox/wakeups/kafka_wakeup.py +123 -0
- hare/contrib/outbox/wakeups/listen_notify_wakeup.py +75 -0
- hare/contrib/outbox/wakeups/outbox_wakeup.py +202 -0
- hare/contrib/outbox/wakeups/rabbitmq_wakeup.py +64 -0
- hare/contrib/outbox/wakeups/redis_wakeup.py +53 -0
- hare/contrib/pydantic/__init__.py +12 -0
- hare/contrib/pydantic/constants.py +41 -0
- hare/contrib/pydantic/creation/__init__.py +1 -0
- hare/contrib/pydantic/creation/computed_field_schemas.py +77 -0
- hare/contrib/pydantic/creation/data_field_schemas.py +230 -0
- hare/contrib/pydantic/creation/field_descriptions.py +17 -0
- hare/contrib/pydantic/creation/field_map.py +138 -0
- hare/contrib/pydantic/creation/generic_foreign_key_schemas.py +136 -0
- hare/contrib/pydantic/creation/generic_foreign_key_tag_reader.py +35 -0
- hare/contrib/pydantic/creation/model_annotations.py +44 -0
- hare/contrib/pydantic/creation/pydantic_creators.py +163 -0
- hare/contrib/pydantic/creation/pydantic_meta_reading.py +134 -0
- hare/contrib/pydantic/creation/pydantic_model_creator.py +434 -0
- hare/contrib/pydantic/creation/relation_field_schemas.py +269 -0
- hare/contrib/pydantic/descriptions/__init__.py +5 -0
- hare/contrib/pydantic/descriptions/computed_field_description.py +12 -0
- hare/contrib/pydantic/descriptions/model_description.py +69 -0
- hare/contrib/pydantic/descriptions/pydantic_meta_data.py +144 -0
- hare/contrib/pydantic/enums.py +12 -0
- hare/contrib/pydantic/models/__init__.py +9 -0
- hare/contrib/pydantic/models/pydantic_list_model.py +34 -0
- hare/contrib/pydantic/models/pydantic_model.py +292 -0
- hare/contrib/pytest/__init__.py +17 -0
- hare/contrib/pytest/constants.py +26 -0
- hare/contrib/pytest/hare_fixtures.py +112 -0
- hare/contrib/pytest/missing_pytest_asyncio_fixtures.py +34 -0
- hare/contrib/pytest/plugin.py +49 -0
- hare/contrib/repeated_queries/__init__.py +19 -0
- hare/contrib/repeated_queries/constants.py +10 -0
- hare/contrib/repeated_queries/repeated_query_collection.py +116 -0
- hare/contrib/repeated_queries/repeated_query_detector.py +227 -0
- hare/contrib/repeated_queries/repeated_query_entry.py +20 -0
- hare/contrib/repeated_queries/repeated_query_report.py +31 -0
- hare/contrib/repeated_queries/shape_stats.py +18 -0
- hare/contrib/request_query/__init__.py +71 -0
- hare/contrib/request_query/bounds/__init__.py +6 -0
- hare/contrib/request_query/bounds/constants.py +4 -0
- hare/contrib/request_query/bounds/lookup_pair_bounds.py +40 -0
- hare/contrib/request_query/bounds/parameter_bounds.py +41 -0
- hare/contrib/request_query/bounds/range_bounds.py +30 -0
- hare/contrib/request_query/constants.py +45 -0
- hare/contrib/request_query/declaration/__init__.py +6 -0
- hare/contrib/request_query/declaration/constants.py +19 -0
- hare/contrib/request_query/declaration/declaration_builder.py +515 -0
- hare/contrib/request_query/declaration/filter_declaration.py +25 -0
- hare/contrib/request_query/declaration/filter_parameter_builder.py +201 -0
- hare/contrib/request_query/declaration/parameter_filter.py +17 -0
- hare/contrib/request_query/declaration/request_query_declaration.py +138 -0
- hare/contrib/request_query/declaration/request_query_parameters.py +54 -0
- hare/contrib/request_query/declaration/request_query_registry.py +90 -0
- hare/contrib/request_query/descriptions/__init__.py +11 -0
- hare/contrib/request_query/descriptions/constants.py +11 -0
- hare/contrib/request_query/descriptions/parameter_choice.py +17 -0
- hare/contrib/request_query/descriptions/parameter_describer.py +240 -0
- hare/contrib/request_query/descriptions/parameter_description.py +66 -0
- hare/contrib/request_query/descriptions/relation_description.py +30 -0
- hare/contrib/request_query/enums.py +69 -0
- hare/contrib/request_query/exceptions.py +52 -0
- hare/contrib/request_query/options/__init__.py +33 -0
- hare/contrib/request_query/options/constants.py +25 -0
- hare/contrib/request_query/options/deleted_config.py +90 -0
- hare/contrib/request_query/options/fields_config.py +55 -0
- hare/contrib/request_query/options/filter.py +34 -0
- hare/contrib/request_query/options/filter_field.py +81 -0
- hare/contrib/request_query/options/in_path.py +12 -0
- hare/contrib/request_query/options/include_config.py +56 -0
- hare/contrib/request_query/options/latest_versions.py +71 -0
- hare/contrib/request_query/options/no_filter.py +11 -0
- hare/contrib/request_query/options/ordering_config.py +81 -0
- hare/contrib/request_query/options/parameter_field.py +27 -0
- hare/contrib/request_query/options/request_option.py +152 -0
- hare/contrib/request_query/options/search_config.py +83 -0
- hare/contrib/request_query/paginations/__init__.py +1 -0
- hare/contrib/request_query/paginations/base_offset_pagination.py +78 -0
- hare/contrib/request_query/paginations/constants.py +17 -0
- hare/contrib/request_query/paginations/cursor.py +83 -0
- hare/contrib/request_query/paginations/cursor_pagination.py +184 -0
- hare/contrib/request_query/paginations/offset_pagination.py +31 -0
- hare/contrib/request_query/paginations/pagination.py +120 -0
- hare/contrib/request_query/paginations/scroll_pagination.py +31 -0
- hare/contrib/request_query/request_query.py +1259 -0
- hare/contrib/request_query/results/__init__.py +11 -0
- hare/contrib/request_query/results/cursor_page.py +25 -0
- hare/contrib/request_query/results/page.py +25 -0
- hare/contrib/request_query/results/scroll_page.py +23 -0
- hare/contrib/request_query/row_changes.py +80 -0
- hare/contrib/request_query/types/__init__.py +15 -0
- hare/contrib/request_query/types/comma_separated.py +46 -0
- hare/contrib/request_query/types/constants.py +16 -0
- hare/contrib/request_query/types/generic_target.py +87 -0
- hare/contrib/request_query/types/key_columns.py +60 -0
- hare/contrib/request_query/types/text_parameter.py +18 -0
- hare/contrib/request_query/value_annotation.py +216 -0
- hare/contrib/request_query/value_counter.py +115 -0
- hare/contrib/request_query/value_target.py +50 -0
- hare/contrib/taskiq/__init__.py +15 -0
- hare/contrib/taskiq/constants.py +23 -0
- hare/contrib/taskiq/hare_taskiq.py +76 -0
- hare/contrib/taskiq/hare_taskiq_middleware.py +195 -0
- hare/contrib/taskiq/running_task.py +29 -0
- hare/contrib/taskiq/task_tenant_labels.py +102 -0
- hare/contrib/taskiq/taskiq_delivery.py +117 -0
- hare/contrib/test/__init__.py +39 -0
- hare/contrib/test/conditions/__init__.py +10 -0
- hare/contrib/test/conditions/condition.py +11 -0
- hare/contrib/test/conditions/in_condition.py +21 -0
- hare/contrib/test/conditions/not_eq.py +18 -0
- hare/contrib/test/conditions/not_in.py +21 -0
- hare/contrib/test/constants.py +18 -0
- hare/contrib/test/databases/__init__.py +1 -0
- hare/contrib/test/databases/kept_test_schema.py +51 -0
- hare/contrib/test/databases/model_truncation.py +128 -0
- hare/contrib/test/databases/reusable_test_databases.py +244 -0
- hare/contrib/test/databases/rollback_isolation.py +149 -0
- hare/contrib/test/databases/temporary_databases.py +118 -0
- hare/contrib/test/exceptions.py +5 -0
- hare/contrib/test/features/__init__.py +1 -0
- hare/contrib/test/features/feature_conditions.py +65 -0
- hare/contrib/test/features/feature_requirements.py +84 -0
- hare/contrib/test/isolated_contexts.py +144 -0
- hare/contrib/test/queries/__init__.py +1 -0
- hare/contrib/test/queries/query_counter.py +35 -0
- hare/contrib/test/queries/query_counting.py +59 -0
- hare/contrib/versioning/__init__.py +7 -0
- hare/contrib/versioning/constants.py +5 -0
- hare/contrib/versioning/versioned_model.py +139 -0
- hare/core/__init__.py +4 -0
- hare/core/apps/__init__.py +8 -0
- hare/core/apps/apps.py +693 -0
- hare/core/apps/cross_connection_checks.py +76 -0
- hare/core/apps/model_connection_checks.py +199 -0
- hare/core/apps/model_discovery.py +142 -0
- hare/core/apps/relation_linking.py +773 -0
- hare/core/apps/swappable_models.py +118 -0
- hare/core/apps/table_names.py +39 -0
- hare/core/caching/__init__.py +1 -0
- hare/core/caching/cache.py +426 -0
- hare/core/caching/caches.py +58 -0
- hare/core/caching/constants.py +13 -0
- hare/core/caching/declarations.py +8 -0
- hare/core/caching/forgettable_cache.py +16 -0
- hare/core/caching/model_cache.py +138 -0
- hare/core/config/__init__.py +25 -0
- hare/core/config/app_config.py +64 -0
- hare/core/config/cli_config.py +38 -0
- hare/core/config/config_secrets.py +101 -0
- hare/core/config/config_section.py +37 -0
- hare/core/config/connection_config.py +69 -0
- hare/core/config/constants.py +17 -0
- hare/core/config/db_url_config.py +24 -0
- hare/core/config/hare_config.py +407 -0
- hare/core/config/migration_safety_config.py +54 -0
- hare/core/config/migrations_config.py +72 -0
- hare/core/connections/__init__.py +1 -0
- hare/core/connections/connection_handler.py +457 -0
- hare/core/connections/connection_token.py +36 -0
- hare/core/connections/connections.py +133 -0
- hare/core/constants.py +40 -0
- hare/core/hare.py +205 -0
- hare/core/hare_context.py +854 -0
- hare/core/hare_meta.py +18 -0
- hare/core/log.py +6 -0
- hare/core/registries.py +22 -0
- hare/core/routing/__init__.py +5 -0
- hare/core/routing/connection_router.py +109 -0
- hare/core/routing/primary_reads.py +42 -0
- hare/core/routing/routing.py +28 -0
- hare/core/routing/written_connections.py +63 -0
- hare/ddl/__init__.py +57 -0
- hare/ddl/conditions/__init__.py +1 -0
- hare/ddl/conditions/constraint_condition.py +154 -0
- hare/ddl/conditions/exclusive_arc_condition.py +80 -0
- hare/ddl/conditions/tenant_condition.py +48 -0
- hare/ddl/conditions/trigger_condition.py +44 -0
- hare/ddl/constants.py +68 -0
- hare/ddl/constraints/__init__.py +7 -0
- hare/ddl/constraints/check_constraint.py +38 -0
- hare/ddl/constraints/exclusion_constraint.py +116 -0
- hare/ddl/constraints/foreign_key_constraint.py +39 -0
- hare/ddl/constraints/unique_constraint.py +150 -0
- hare/ddl/ddl_term_sql.py +45 -0
- hare/ddl/declared_names.py +47 -0
- hare/ddl/enums.py +117 -0
- hare/ddl/expressions/__init__.py +0 -0
- hare/ddl/expressions/declared_expressions.py +102 -0
- hare/ddl/expressions/expression_field_renaming.py +150 -0
- hare/ddl/generated_names.py +87 -0
- hare/ddl/indexes/__init__.py +11 -0
- hare/ddl/indexes/index.py +531 -0
- hare/ddl/indexes/ordered_index_key.py +27 -0
- hare/ddl/indexes/partial_index.py +75 -0
- hare/ddl/raw_sql_term.py +44 -0
- hare/ddl/schema_objects/__init__.py +12 -0
- hare/ddl/schema_objects/database_function.py +91 -0
- hare/ddl/schema_objects/database_sequence.py +87 -0
- hare/ddl/schema_objects/dictionary.py +69 -0
- hare/ddl/schema_objects/enum_type.py +24 -0
- hare/ddl/schema_objects/materialized_view.py +52 -0
- hare/ddl/schema_objects/named_schema_object.py +24 -0
- hare/ddl/schema_objects/trigger.py +151 -0
- hare/ddl/schema_objects/view.py +132 -0
- hare/ddl/security/__init__.py +8 -0
- hare/ddl/security/grant.py +106 -0
- hare/ddl/security/policy.py +92 -0
- hare/ddl/table_options.py +364 -0
- hare/dialects/__init__.py +0 -0
- hare/dialects/base/__init__.py +0 -0
- hare/dialects/base/clauses/__init__.py +1 -0
- hare/dialects/base/clauses/enums.py +37 -0
- hare/dialects/base/clauses/limit_returning_conflict_query_clauses.py +194 -0
- hare/dialects/base/clauses/merge_when_sql.py +24 -0
- hare/dialects/base/clauses/query_clauses.py +636 -0
- hare/dialects/base/client/__init__.py +16 -0
- hare/dialects/base/client/connect_failure_reports.py +49 -0
- hare/dialects/base/client/connection_ping.py +48 -0
- hare/dialects/base/client/connection_wrapper.py +126 -0
- hare/dialects/base/client/constants.py +41 -0
- hare/dialects/base/client/database_client.py +1187 -0
- hare/dialects/base/client/declarations.py +37 -0
- hare/dialects/base/client/driver_statement_log_filter.py +33 -0
- hare/dialects/base/client/password_provider.py +144 -0
- hare/dialects/base/client/pool/__init__.py +1 -0
- hare/dialects/base/client/pool/pool_connection_wrapper.py +37 -0
- hare/dialects/base/client/pool/pool_statistics.py +84 -0
- hare/dialects/base/client/pool/pool_timeouts.py +48 -0
- hare/dialects/base/client/transaction_client.py +621 -0
- hare/dialects/base/client/transaction_lifecycle/__init__.py +1 -0
- hare/dialects/base/client/transaction_lifecycle/pending_statements.py +74 -0
- hare/dialects/base/client/transaction_lifecycle/transaction_callbacks.py +128 -0
- hare/dialects/base/client/transaction_lifecycle/transaction_ending.py +360 -0
- hare/dialects/base/connection/__init__.py +1 -0
- hare/dialects/base/connection/connection_option.py +142 -0
- hare/dialects/base/connection/connection_options.py +69 -0
- hare/dialects/base/connection/constants.py +27 -0
- hare/dialects/base/connection/db_url_config_generator.py +194 -0
- hare/dialects/base/connection/driver.py +136 -0
- hare/dialects/base/constants.py +72 -0
- hare/dialects/base/dialect.py +360 -0
- hare/dialects/base/features.py +369 -0
- hare/dialects/base/literals/__init__.py +1 -0
- hare/dialects/base/literals/constants.py +12 -0
- hare/dialects/base/literals/sql_literals.py +254 -0
- hare/dialects/base/lookups/__init__.py +1 -0
- hare/dialects/base/lookups/filter_operators.py +171 -0
- hare/dialects/base/migration_safety/__init__.py +12 -0
- hare/dialects/base/migration_safety/add_field_backfill_rule.py +37 -0
- hare/dialects/base/migration_safety/alter_field_rewrite_rule.py +39 -0
- hare/dialects/base/migration_safety/constants.py +4 -0
- hare/dialects/base/migration_safety/delete_model_rule.py +33 -0
- hare/dialects/base/migration_safety/migration_safety_rule.py +45 -0
- hare/dialects/base/migration_safety/migration_safety_rules.py +72 -0
- hare/dialects/base/migration_safety/remove_field_rule.py +31 -0
- hare/dialects/base/migration_safety/rename_field_rule.py +41 -0
- hare/dialects/base/migration_safety/rename_model_rule.py +42 -0
- hare/dialects/base/migration_safety/run_sql_rule.py +27 -0
- hare/dialects/base/migration_safety/schema_change_with_run_python_rule.py +49 -0
- hare/dialects/base/parameters/__init__.py +1 -0
- hare/dialects/base/parameters/large_in_list.py +147 -0
- hare/dialects/base/parameters/sql_parameters.py +185 -0
- hare/dialects/base/renderers/__init__.py +7 -0
- hare/dialects/base/renderers/checked_term_renderers.py +61 -0
- hare/dialects/base/renderers/json_renderers.py +60 -0
- hare/dialects/base/renderers/term_renderers.py +508 -0
- hare/dialects/base/results/__init__.py +9 -0
- hare/dialects/base/results/described_result.py +22 -0
- hare/dialects/base/results/statement_result.py +53 -0
- hare/dialects/base/schema/__init__.py +0 -0
- hare/dialects/base/schema/base_schema_editor.py +1139 -0
- hare/dialects/base/schema/columns/__init__.py +1 -0
- hare/dialects/base/schema/columns/column_backfill.py +347 -0
- hare/dialects/base/schema/columns/column_conversion_check.py +51 -0
- hare/dialects/base/schema/columns/column_definitions.py +473 -0
- hare/dialects/base/schema/columns/column_narrowing_check.py +178 -0
- hare/dialects/base/schema/columns/column_renames.py +77 -0
- hare/dialects/base/schema/columns/column_type_changes.py +140 -0
- hare/dialects/base/schema/constants.py +30 -0
- hare/dialects/base/schema/constraints/__init__.py +1 -0
- hare/dialects/base/schema/constraints/constraint_names.py +45 -0
- hare/dialects/base/schema/constraints/constraint_statements.py +262 -0
- hare/dialects/base/schema/data/__init__.py +9 -0
- hare/dialects/base/schema/data/model_sql_data.py +41 -0
- hare/dialects/base/schema/data/referencing_key_columns.py +24 -0
- hare/dialects/base/schema/indexes/__init__.py +1 -0
- hare/dialects/base/schema/indexes/generated_index_names.py +180 -0
- hare/dialects/base/schema/indexes/index_statements.py +397 -0
- hare/dialects/base/schema/relations/__init__.py +1 -0
- hare/dialects/base/schema/relations/foreign_key_rebuild.py +480 -0
- hare/dialects/base/schema/relations/many_to_many_through_tables.py +285 -0
- hare/dialects/base/schema/runtime_statements/__init__.py +1 -0
- hare/dialects/base/schema/runtime_statements/table_clearing.py +54 -0
- hare/dialects/base/schema/runtime_statements/table_locks.py +34 -0
- hare/dialects/base/schema/runtime_statements/tenant_conditions.py +71 -0
- hare/dialects/base/schema/schema_editor_part.py +34 -0
- hare/dialects/base/schema/schema_objects/__init__.py +1 -0
- hare/dialects/base/schema/schema_objects/database_functions.py +74 -0
- hare/dialects/base/schema/schema_objects/dictionaries.py +75 -0
- hare/dialects/base/schema/schema_objects/enum_types.py +88 -0
- hare/dialects/base/schema/schema_objects/extensions.py +69 -0
- hare/dialects/base/schema/schema_objects/grants.py +49 -0
- hare/dialects/base/schema/schema_objects/materialized_views.py +111 -0
- hare/dialects/base/schema/schema_objects/row_level_security_policies.py +82 -0
- hare/dialects/base/schema/schema_objects/schemas.py +65 -0
- hare/dialects/base/schema/schema_objects/sequences.py +95 -0
- hare/dialects/base/schema/schema_objects/views.py +81 -0
- hare/dialects/base/schema/shadow/__init__.py +0 -0
- hare/dialects/base/schema/shadow/shadow_database.py +77 -0
- hare/dialects/base/schema/tables/__init__.py +1 -0
- hare/dialects/base/schema/tables/table_comments.py +92 -0
- hare/dialects/base/schema/tables/table_creation.py +742 -0
- hare/dialects/base/schema/tables/table_partitions.py +78 -0
- hare/dialects/base/schema/tables/table_rebuild.py +268 -0
- hare/dialects/base/schema/triggers/__init__.py +1 -0
- hare/dialects/base/schema/triggers/trigger_statements.py +85 -0
- hare/dialects/base/search/__init__.py +1 -0
- hare/dialects/base/search/text_search.py +135 -0
- hare/dialects/base/sql_dialect.py +23 -0
- hare/dialects/base/transactions/__init__.py +1 -0
- hare/dialects/base/transactions/constants.py +5 -0
- hare/dialects/base/transactions/contexts/__init__.py +1 -0
- hare/dialects/base/transactions/contexts/joined_transaction_context.py +36 -0
- hare/dialects/base/transactions/contexts/nested_transaction_context.py +149 -0
- hare/dialects/base/transactions/contexts/non_transactional_context.py +32 -0
- hare/dialects/base/transactions/contexts/top_level_transaction_context.py +79 -0
- hare/dialects/base/transactions/contexts/transaction_context.py +148 -0
- hare/dialects/base/transactions/savepoints/__init__.py +1 -0
- hare/dialects/base/transactions/savepoints/nested_savepoint_lock.py +152 -0
- hare/dialects/base/transactions/savepoints/savepoint_span.py +51 -0
- hare/dialects/base/transactions/transaction_callback.py +32 -0
- hare/dialects/base/transactions/transaction_statements.py +128 -0
- hare/dialects/base/transactions/two_phase_commit.py +134 -0
- hare/dialects/base/types/__init__.py +9 -0
- hare/dialects/base/types/type_mapping.py +63 -0
- hare/dialects/base/types/type_registry.py +395 -0
- hare/dialects/clickhouse/__init__.py +1 -0
- hare/dialects/clickhouse/clauses/__init__.py +1 -0
- hare/dialects/clickhouse/clauses/clickhouse_query_clauses.py +475 -0
- hare/dialects/clickhouse/clauses/constants.py +42 -0
- hare/dialects/clickhouse/clickhouse_dialect.py +260 -0
- hare/dialects/clickhouse/clickhouse_introspector.py +414 -0
- hare/dialects/clickhouse/clickhouse_table_options.py +727 -0
- hare/dialects/clickhouse/client/__init__.py +1 -0
- hare/dialects/clickhouse/client/clickhouse_client.py +913 -0
- hare/dialects/clickhouse/client/clickhouse_connection.py +30 -0
- hare/dialects/clickhouse/client/clickhouse_error_codes.py +26 -0
- hare/dialects/clickhouse/client/clickhouse_external_sets.py +109 -0
- hare/dialects/clickhouse/client/clickhouse_query_templates.py +79 -0
- hare/dialects/clickhouse/client/clickhouse_statement_result.py +15 -0
- hare/dialects/clickhouse/client/clickhouse_streamed_row.py +52 -0
- hare/dialects/clickhouse/client/clickhouse_transaction_client.py +188 -0
- hare/dialects/clickhouse/client/constants.py +211 -0
- hare/dialects/clickhouse/client/declarations.py +47 -0
- hare/dialects/clickhouse/cluster/__init__.py +0 -0
- hare/dialects/clickhouse/cluster/clickhouse_cluster.py +162 -0
- hare/dialects/clickhouse/cluster/clickhouse_cluster_statements.py +154 -0
- hare/dialects/clickhouse/cluster/constants.py +82 -0
- hare/dialects/clickhouse/connection/__init__.py +1 -0
- hare/dialects/clickhouse/connection/clickhouse_driver.py +40 -0
- hare/dialects/clickhouse/constants.py +226 -0
- hare/dialects/clickhouse/drivers/__init__.py +1 -0
- hare/dialects/clickhouse/drivers/clickhouse_connect/__init__.py +1 -0
- hare/dialects/clickhouse/drivers/clickhouse_connect/clickhouse_connect_driver.py +43 -0
- hare/dialects/clickhouse/drivers/clickhouse_connect/client/__init__.py +1 -0
- hare/dialects/clickhouse/drivers/clickhouse_connect/client/clickhouse_connect_client.py +390 -0
- hare/dialects/clickhouse/drivers/clickhouse_connect/client/clickhouse_connect_dynamic_type.py +76 -0
- hare/dialects/clickhouse/drivers/clickhouse_connect/client/clickhouse_connect_totals_query.py +70 -0
- hare/dialects/clickhouse/drivers/clickhouse_connect/client/clickhouse_connect_transaction_client.py +56 -0
- hare/dialects/clickhouse/drivers/clickhouse_connect/client/clickhouse_connect_whole_response_query.py +127 -0
- hare/dialects/clickhouse/drivers/clickhouse_connect/client/clickhouse_json_compact_values.py +96 -0
- hare/dialects/clickhouse/drivers/clickhouse_connect/constants.py +60 -0
- hare/dialects/clickhouse/drivers/clickhouse_driver/__init__.py +1 -0
- hare/dialects/clickhouse/drivers/clickhouse_driver/clickhouse_driver_driver.py +48 -0
- hare/dialects/clickhouse/drivers/clickhouse_driver/client/__init__.py +1 -0
- hare/dialects/clickhouse/drivers/clickhouse_driver/client/clickhouse_driver_client.py +361 -0
- hare/dialects/clickhouse/drivers/clickhouse_driver/client/clickhouse_driver_client_info.py +70 -0
- hare/dialects/clickhouse/drivers/clickhouse_driver/client/clickhouse_driver_column_types.py +104 -0
- hare/dialects/clickhouse/drivers/clickhouse_driver/client/clickhouse_driver_connections.py +189 -0
- hare/dialects/clickhouse/drivers/clickhouse_driver/client/clickhouse_driver_decompressors.py +48 -0
- hare/dialects/clickhouse/drivers/clickhouse_driver/client/clickhouse_driver_dynamic_column.py +51 -0
- hare/dialects/clickhouse/drivers/clickhouse_driver/client/clickhouse_driver_library_client.py +239 -0
- hare/dialects/clickhouse/drivers/clickhouse_driver/client/clickhouse_driver_library_connection.py +16 -0
- hare/dialects/clickhouse/drivers/clickhouse_driver/client/clickhouse_driver_map_columns.py +49 -0
- hare/dialects/clickhouse/drivers/clickhouse_driver/client/clickhouse_driver_moment_columns.py +85 -0
- hare/dialects/clickhouse/drivers/clickhouse_driver/client/clickhouse_driver_query_result.py +24 -0
- hare/dialects/clickhouse/drivers/clickhouse_driver/client/clickhouse_driver_row_stream.py +127 -0
- hare/dialects/clickhouse/drivers/clickhouse_driver/client/clickhouse_driver_service_block_stream.py +95 -0
- hare/dialects/clickhouse/drivers/clickhouse_driver/client/clickhouse_driver_settings.py +62 -0
- hare/dialects/clickhouse/drivers/clickhouse_driver/client/clickhouse_driver_transaction_client.py +23 -0
- hare/dialects/clickhouse/drivers/clickhouse_driver/client/clickhouse_driver_tuple_columns.py +38 -0
- hare/dialects/clickhouse/drivers/clickhouse_driver/client/clickhouse_driver_variant_column.py +76 -0
- hare/dialects/clickhouse/drivers/clickhouse_driver/constants.py +133 -0
- hare/dialects/clickhouse/drivers/clickhouse_shared_variant_values.py +878 -0
- hare/dialects/clickhouse/drivers/constants.py +143 -0
- hare/dialects/clickhouse/enums.py +38 -0
- hare/dialects/clickhouse/fields/__init__.py +43 -0
- hare/dialects/clickhouse/fields/clickhouse_date_field.py +32 -0
- hare/dialects/clickhouse/fields/clickhouse_datetime_field.py +162 -0
- hare/dialects/clickhouse/fields/clickhouse_integer_field.py +20 -0
- hare/dialects/clickhouse/fields/constants.py +31 -0
- hare/dialects/clickhouse/fields/declarations.py +81 -0
- hare/dialects/clickhouse/fields/dynamic_field.py +122 -0
- hare/dialects/clickhouse/fields/fixed_string_field.py +81 -0
- hare/dialects/clickhouse/fields/float32_field.py +39 -0
- hare/dialects/clickhouse/fields/low_cardinality_field.py +72 -0
- hare/dialects/clickhouse/fields/variant_field.py +174 -0
- hare/dialects/clickhouse/functions/__init__.py +39 -0
- hare/dialects/clickhouse/functions/aggregates/__init__.py +37 -0
- hare/dialects/clickhouse/functions/aggregates/arg_extremum.py +23 -0
- hare/dialects/clickhouse/functions/aggregates/declarations.py +120 -0
- hare/dialects/clickhouse/functions/aggregates/group_array.py +48 -0
- hare/dialects/clickhouse/functions/aggregates/median.py +18 -0
- hare/dialects/clickhouse/functions/aggregates/parametric_aggregate.py +48 -0
- hare/dialects/clickhouse/functions/aggregates/parametric_aggregate_function.py +45 -0
- hare/dialects/clickhouse/functions/aggregates/parametric_analytic_function.py +27 -0
- hare/dialects/clickhouse/functions/aggregates/quantile.py +74 -0
- hare/dialects/clickhouse/functions/aggregates/quantiles.py +58 -0
- hare/dialects/clickhouse/functions/aggregates/top_k.py +44 -0
- hare/dialects/clickhouse/functions/dict_get.py +199 -0
- hare/dialects/clickhouse/indexes/__init__.py +19 -0
- hare/dialects/clickhouse/indexes/bloom_filter_index.py +49 -0
- hare/dialects/clickhouse/indexes/clickhouse_index.py +145 -0
- hare/dialects/clickhouse/indexes/constants.py +14 -0
- hare/dialects/clickhouse/indexes/min_max_index.py +22 -0
- hare/dialects/clickhouse/indexes/ngram_bloom_filter_index.py +43 -0
- hare/dialects/clickhouse/indexes/set_index.py +35 -0
- hare/dialects/clickhouse/indexes/token_bloom_filter_index.py +60 -0
- hare/dialects/clickhouse/introspection/__init__.py +0 -0
- hare/dialects/clickhouse/introspection/clickhouse_check_constraints.py +40 -0
- hare/dialects/clickhouse/introspection/clickhouse_observed_table_options.py +280 -0
- hare/dialects/clickhouse/introspection/clickhouse_sql_parts.py +302 -0
- hare/dialects/clickhouse/introspection/clickhouse_type_parser.py +276 -0
- hare/dialects/clickhouse/introspection/constants.py +69 -0
- hare/dialects/clickhouse/keeper/__init__.py +0 -0
- hare/dialects/clickhouse/keeper/clickhouse_migration_lock.py +114 -0
- hare/dialects/clickhouse/keeper/constants.py +38 -0
- hare/dialects/clickhouse/keeper/keeper_codec.py +152 -0
- hare/dialects/clickhouse/keeper/keeper_session.py +213 -0
- hare/dialects/clickhouse/literals/__init__.py +1 -0
- hare/dialects/clickhouse/literals/clickhouse_literals.py +362 -0
- hare/dialects/clickhouse/lookups/__init__.py +0 -0
- hare/dialects/clickhouse/lookups/clickhouse_array_elements_key.py +32 -0
- hare/dialects/clickhouse/lookups/clickhouse_filter_operators.py +49 -0
- hare/dialects/clickhouse/lookups/clickhouse_global_lookups.py +129 -0
- hare/dialects/clickhouse/lookups/clickhouse_json_equality.py +78 -0
- hare/dialects/clickhouse/lookups/clickhouse_json_key_existence.py +38 -0
- hare/dialects/clickhouse/lookups/clickhouse_json_lookups.py +57 -0
- hare/dialects/clickhouse/lookups/clickhouse_json_path_lookups.py +102 -0
- hare/dialects/clickhouse/lookups/clickhouse_json_value_text.py +24 -0
- hare/dialects/clickhouse/lookups/clickhouse_typed_value_lookups.py +213 -0
- hare/dialects/clickhouse/lookups/constants.py +67 -0
- hare/dialects/clickhouse/lookups/declarations.py +14 -0
- hare/dialects/clickhouse/lookups/global_contains_criterion.py +15 -0
- hare/dialects/clickhouse/lookups/in_list/__init__.py +0 -0
- hare/dialects/clickhouse/lookups/in_list/clickhouse_large_in_list.py +95 -0
- hare/dialects/clickhouse/lookups/in_list/clickhouse_value_set_values.py +45 -0
- hare/dialects/clickhouse/migration_safety/__init__.py +9 -0
- hare/dialects/clickhouse/migration_safety/clickhouse_migration_safety_rules.py +34 -0
- hare/dialects/clickhouse/migration_safety/constants.py +10 -0
- hare/dialects/clickhouse/parameters/__init__.py +1 -0
- hare/dialects/clickhouse/parameters/clickhouse_parameters.py +42 -0
- hare/dialects/clickhouse/query/__init__.py +1 -0
- hare/dialects/clickhouse/query/clickhouse_dialect_variants.py +31 -0
- hare/dialects/clickhouse/query/clickhouse_queryset_methods.py +356 -0
- hare/dialects/clickhouse/query/clickhouse_sql_context.py +47 -0
- hare/dialects/clickhouse/query/clickhouse_totals.py +34 -0
- hare/dialects/clickhouse/query/constants.py +24 -0
- hare/dialects/clickhouse/query/declarations.py +21 -0
- hare/dialects/clickhouse/query/totals_result.py +21 -0
- hare/dialects/clickhouse/renderers/__init__.py +1 -0
- hare/dialects/clickhouse/renderers/clickhouse_aggregate_renderers.py +124 -0
- hare/dialects/clickhouse/renderers/clickhouse_assigned_enum_number.py +30 -0
- hare/dialects/clickhouse/renderers/clickhouse_cast_renderers.py +49 -0
- hare/dialects/clickhouse/renderers/clickhouse_checked_integer_result.py +34 -0
- hare/dialects/clickhouse/renderers/clickhouse_condition_renderers.py +27 -0
- hare/dialects/clickhouse/renderers/clickhouse_container_renderers.py +129 -0
- hare/dialects/clickhouse/renderers/clickhouse_json_renderers.py +105 -0
- hare/dialects/clickhouse/renderers/clickhouse_json_texts.py +34 -0
- hare/dialects/clickhouse/renderers/clickhouse_number_renderers.py +76 -0
- hare/dialects/clickhouse/renderers/clickhouse_renderers.py +339 -0
- hare/dialects/clickhouse/renderers/clickhouse_temporal_renderers.py +262 -0
- hare/dialects/clickhouse/renderers/clickhouse_text_renderers.py +117 -0
- hare/dialects/clickhouse/renderers/clickhouse_value_casts.py +115 -0
- hare/dialects/clickhouse/renderers/clickhouse_window_renderers.py +72 -0
- hare/dialects/clickhouse/renderers/constants.py +341 -0
- hare/dialects/clickhouse/schema/__init__.py +1 -0
- hare/dialects/clickhouse/schema/columns/__init__.py +1 -0
- hare/dialects/clickhouse/schema/columns/clickhouse_column_backfill.py +106 -0
- hare/dialects/clickhouse/schema/columns/clickhouse_column_conversion_check.py +173 -0
- hare/dialects/clickhouse/schema/columns/clickhouse_column_definitions.py +62 -0
- hare/dialects/clickhouse/schema/columns/clickhouse_column_narrowing_check.py +109 -0
- hare/dialects/clickhouse/schema/columns/clickhouse_column_renames.py +45 -0
- hare/dialects/clickhouse/schema/constants.py +201 -0
- hare/dialects/clickhouse/schema/declarations.py +95 -0
- hare/dialects/clickhouse/schema/indexes/__init__.py +0 -0
- hare/dialects/clickhouse/schema/indexes/clickhouse_index_statements.py +60 -0
- hare/dialects/clickhouse/schema/runtime_statements/__init__.py +1 -0
- hare/dialects/clickhouse/schema/runtime_statements/clickhouse_table_clearing.py +19 -0
- hare/dialects/clickhouse/schema/schema_objects/__init__.py +0 -0
- hare/dialects/clickhouse/schema/schema_objects/clickhouse_dictionaries.py +169 -0
- hare/dialects/clickhouse/schema/schema_objects/clickhouse_materialized_views.py +221 -0
- hare/dialects/clickhouse/schema/schema_objects/clickhouse_schemas.py +69 -0
- hare/dialects/clickhouse/schema/schema_objects/clickhouse_views.py +59 -0
- hare/dialects/clickhouse/schema/shadow/__init__.py +0 -0
- hare/dialects/clickhouse/schema/shadow/clickhouse_shadow_database.py +155 -0
- hare/dialects/clickhouse/schema/tables/__init__.py +1 -0
- hare/dialects/clickhouse/schema/tables/clickhouse_table_comments.py +43 -0
- hare/dialects/clickhouse/schema/tables/clickhouse_table_creation.py +50 -0
- hare/dialects/clickhouse/schema/tables/clickhouse_table_partitions.py +160 -0
- hare/dialects/clickhouse/schema/tables/clickhouse_table_rebuild.py +227 -0
- hare/dialects/clickhouse/schema_objects/__init__.py +5 -0
- hare/dialects/clickhouse/schema_objects/clickhouse_dictionary.py +118 -0
- hare/dialects/clickhouse/schema_objects/clickhouse_materialized_view.py +159 -0
- hare/dialects/clickhouse/schema_objects/clickhouse_projection.py +204 -0
- hare/dialects/clickhouse/server_versions.py +5 -0
- hare/dialects/clickhouse/spatial/__init__.py +0 -0
- hare/dialects/clickhouse/spatial/clickhouse_geometry_values.py +208 -0
- hare/dialects/clickhouse/spatial/clickhouse_spatial_renderers.py +265 -0
- hare/dialects/clickhouse/spatial/constants.py +66 -0
- hare/dialects/clickhouse/transactions/__init__.py +0 -0
- hare/dialects/clickhouse/transactions/clickhouse_transaction_statements.py +19 -0
- hare/dialects/clickhouse/types/__init__.py +1 -0
- hare/dialects/clickhouse/types/clickhouse_address_values.py +35 -0
- hare/dialects/clickhouse/types/clickhouse_binary_values.py +58 -0
- hare/dialects/clickhouse/types/clickhouse_container_values.py +267 -0
- hare/dialects/clickhouse/types/clickhouse_dynamic_values.py +307 -0
- hare/dialects/clickhouse/types/clickhouse_enum_types.py +232 -0
- hare/dialects/clickhouse/types/clickhouse_json_values.py +202 -0
- hare/dialects/clickhouse/types/clickhouse_low_cardinality_values.py +95 -0
- hare/dialects/clickhouse/types/clickhouse_nullable_types.py +27 -0
- hare/dialects/clickhouse/types/clickhouse_type_names.py +128 -0
- hare/dialects/clickhouse/types/clickhouse_types.py +258 -0
- hare/dialects/clickhouse/types/clickhouse_variant_values.py +128 -0
- hare/dialects/clickhouse/types/constants.py +139 -0
- hare/dialects/clickhouse/types/declarations.py +23 -0
- hare/dialects/constants.py +32 -0
- hare/dialects/dialect_registry.py +340 -0
- hare/dialects/enums.py +34 -0
- hare/dialects/postgresql/__init__.py +0 -0
- hare/dialects/postgresql/clauses/__init__.py +1 -0
- hare/dialects/postgresql/clauses/constants.py +44 -0
- hare/dialects/postgresql/clauses/postgresql_query_clauses.py +114 -0
- hare/dialects/postgresql/client/__init__.py +10 -0
- hare/dialects/postgresql/client/constants.py +328 -0
- hare/dialects/postgresql/client/postgresql_client.py +1224 -0
- hare/dialects/postgresql/client/postgresql_connect_errors.py +66 -0
- hare/dialects/postgresql/client/postgresql_transaction_client.py +80 -0
- hare/dialects/postgresql/client/reusable_test_schemas.py +197 -0
- hare/dialects/postgresql/client/transaction_pooler.py +137 -0
- hare/dialects/postgresql/connection/__init__.py +1 -0
- hare/dialects/postgresql/connection/constants.py +11 -0
- hare/dialects/postgresql/connection/postgresql_driver.py +99 -0
- hare/dialects/postgresql/constants.py +862 -0
- hare/dialects/postgresql/drivers/__init__.py +0 -0
- hare/dialects/postgresql/drivers/asyncpg/__init__.py +0 -0
- hare/dialects/postgresql/drivers/asyncpg/asyncpg_date_codec.py +81 -0
- hare/dialects/postgresql/drivers/asyncpg/asyncpg_driver.py +37 -0
- hare/dialects/postgresql/drivers/asyncpg/asyncpg_extension_type_codecs.py +78 -0
- hare/dialects/postgresql/drivers/asyncpg/asyncpg_hstore_codec.py +84 -0
- hare/dialects/postgresql/drivers/asyncpg/asyncpg_interval_codec.py +72 -0
- hare/dialects/postgresql/drivers/asyncpg/asyncpg_timestamp_codec.py +74 -0
- hare/dialects/postgresql/drivers/asyncpg/asyncpg_timestamptz_codec.py +88 -0
- hare/dialects/postgresql/drivers/asyncpg/asyncpg_tsvector_codec.py +264 -0
- hare/dialects/postgresql/drivers/asyncpg/client/__init__.py +9 -0
- hare/dialects/postgresql/drivers/asyncpg/client/asyncpg_client.py +738 -0
- hare/dialects/postgresql/drivers/asyncpg/client/asyncpg_transaction_client.py +197 -0
- hare/dialects/postgresql/drivers/asyncpg/constants.py +150 -0
- hare/dialects/postgresql/drivers/asyncpg/pre_epoch_local_zone.py +27 -0
- hare/dialects/postgresql/drivers/constants.py +22 -0
- hare/dialects/postgresql/drivers/rust_pg/__init__.py +0 -0
- hare/dialects/postgresql/drivers/rust_pg/client/__init__.py +9 -0
- hare/dialects/postgresql/drivers/rust_pg/client/rust_pg_client.py +461 -0
- hare/dialects/postgresql/drivers/rust_pg/client/rust_pg_transaction_client.py +306 -0
- hare/dialects/postgresql/drivers/rust_pg/client/rust_pg_transaction_connection_wrapper.py +53 -0
- hare/dialects/postgresql/drivers/rust_pg/constants.py +43 -0
- hare/dialects/postgresql/drivers/rust_pg/rust_pg_driver.py +66 -0
- hare/dialects/postgresql/enums.py +99 -0
- hare/dialects/postgresql/fields/__init__.py +68 -0
- hare/dialects/postgresql/fields/citext_field.py +42 -0
- hare/dialects/postgresql/fields/constants.py +115 -0
- hare/dialects/postgresql/fields/fixed_char_field.py +23 -0
- hare/dialects/postgresql/fields/hstore/__init__.py +5 -0
- hare/dialects/postgresql/fields/hstore/h_store_field.py +105 -0
- hare/dialects/postgresql/fields/hstore/h_store_text.py +86 -0
- hare/dialects/postgresql/fields/interval_field.py +31 -0
- hare/dialects/postgresql/fields/ltree_field.py +98 -0
- hare/dialects/postgresql/fields/multiranges/__init__.py +19 -0
- hare/dialects/postgresql/fields/multiranges/declarations.py +55 -0
- hare/dialects/postgresql/fields/multiranges/multi_range_field.py +326 -0
- hare/dialects/postgresql/fields/naive_datetime_field.py +74 -0
- hare/dialects/postgresql/fields/naive_time_field.py +64 -0
- hare/dialects/postgresql/fields/native_enum/__init__.py +5 -0
- hare/dialects/postgresql/fields/native_enum/native_enum_field.py +23 -0
- hare/dialects/postgresql/fields/native_enum/native_enum_field_instance.py +87 -0
- hare/dialects/postgresql/fields/network/__init__.py +7 -0
- hare/dialects/postgresql/fields/network/cidr_field.py +24 -0
- hare/dialects/postgresql/fields/network/inet_field.py +25 -0
- hare/dialects/postgresql/fields/network/mac_address_field.py +59 -0
- hare/dialects/postgresql/fields/network/network_field.py +80 -0
- hare/dialects/postgresql/fields/postgis_field.py +206 -0
- hare/dialects/postgresql/fields/ranges/__init__.py +19 -0
- hare/dialects/postgresql/fields/ranges/date_range_field.py +48 -0
- hare/dialects/postgresql/fields/ranges/date_time_range_field.py +153 -0
- hare/dialects/postgresql/fields/ranges/decimal_range_field.py +42 -0
- hare/dialects/postgresql/fields/ranges/declarations.py +15 -0
- hare/dialects/postgresql/fields/ranges/int_range_field.py +60 -0
- hare/dialects/postgresql/fields/ranges/range.py +26 -0
- hare/dialects/postgresql/fields/ranges/range_field.py +349 -0
- hare/dialects/postgresql/fields/ts_vector_field.py +143 -0
- hare/dialects/postgresql/functions/__init__.py +72 -0
- hare/dialects/postgresql/functions/aggregates/__init__.py +21 -0
- hare/dialects/postgresql/functions/aggregates/declarations.py +67 -0
- hare/dialects/postgresql/functions/aggregates/jsonb_agg.py +35 -0
- hare/dialects/postgresql/functions/aggregates/jsonb_agg_field.py +29 -0
- hare/dialects/postgresql/functions/aggregates/range_agg.py +22 -0
- hare/dialects/postgresql/functions/aggregates/string_agg.py +101 -0
- hare/dialects/postgresql/functions/aggregates/string_agg_function.py +13 -0
- hare/dialects/postgresql/functions/array/__init__.py +13 -0
- hare/dialects/postgresql/functions/array/any_value.py +13 -0
- hare/dialects/postgresql/functions/array/array_slice.py +28 -0
- hare/dialects/postgresql/functions/array/array_subquery.py +62 -0
- hare/dialects/postgresql/functions/array/array_subscript.py +66 -0
- hare/dialects/postgresql/functions/constants.py +8 -0
- hare/dialects/postgresql/functions/ltree/__init__.py +7 -0
- hare/dialects/postgresql/functions/ltree/subpath.py +54 -0
- hare/dialects/postgresql/functions/random_uuid.py +26 -0
- hare/dialects/postgresql/functions/spatial/__init__.py +9 -0
- hare/dialects/postgresql/functions/spatial/st_distance.py +63 -0
- hare/dialects/postgresql/functions/spatial/std_within.py +46 -0
- hare/dialects/postgresql/functions/statistics/__init__.py +31 -0
- hare/dialects/postgresql/functions/statistics/covar_pop.py +49 -0
- hare/dialects/postgresql/functions/statistics/declarations.py +84 -0
- hare/dialects/postgresql/functions/statistics/regr_count.py +21 -0
- hare/dialects/postgresql/functions/statistics/statistic_pair_aggregate.py +55 -0
- hare/dialects/postgresql/functions/transaction_now.py +27 -0
- hare/dialects/postgresql/functions/trigram/__init__.py +21 -0
- hare/dialects/postgresql/functions/trigram/declarations.py +53 -0
- hare/dialects/postgresql/functions/trigram/trigram_function.py +61 -0
- hare/dialects/postgresql/functions/trigram/trigram_word_similarity.py +19 -0
- hare/dialects/postgresql/indexes/__init__.py +25 -0
- hare/dialects/postgresql/indexes/constants.py +16 -0
- hare/dialects/postgresql/indexes/declarations.py +36 -0
- hare/dialects/postgresql/indexes/hnsw_index.py +63 -0
- hare/dialects/postgresql/indexes/ivfflat_index.py +37 -0
- hare/dialects/postgresql/indexes/postgresql_index.py +112 -0
- hare/dialects/postgresql/introspection/__init__.py +0 -0
- hare/dialects/postgresql/introspection/postgresql_array_literals.py +101 -0
- hare/dialects/postgresql/introspection/postgresql_definitions.py +193 -0
- hare/dialects/postgresql/introspection/postgresql_inspected_schema_objects.py +196 -0
- hare/dialects/postgresql/introspection/postgresql_object_parts.py +102 -0
- hare/dialects/postgresql/literals/__init__.py +1 -0
- hare/dialects/postgresql/literals/postgresql_literals.py +99 -0
- hare/dialects/postgresql/lookups/__init__.py +0 -0
- hare/dialects/postgresql/lookups/array/__init__.py +5 -0
- hare/dialects/postgresql/lookups/array/array_length.py +26 -0
- hare/dialects/postgresql/lookups/constants.py +44 -0
- hare/dialects/postgresql/lookups/hstore/__init__.py +11 -0
- hare/dialects/postgresql/lookups/hstore/h_store_value_term.py +18 -0
- hare/dialects/postgresql/lookups/hstore/postgresql_h_store_field_lookups.py +75 -0
- hare/dialects/postgresql/lookups/hstore/postgresql_h_store_lookups.py +38 -0
- hare/dialects/postgresql/lookups/in_list/__init__.py +11 -0
- hare/dialects/postgresql/lookups/in_list/array_parameter.py +104 -0
- hare/dialects/postgresql/lookups/in_list/postgresql_large_in_list.py +78 -0
- hare/dialects/postgresql/lookups/in_list/unnest_row_values.py +32 -0
- hare/dialects/postgresql/lookups/json/__init__.py +9 -0
- hare/dialects/postgresql/lookups/json/postgresql_json_filter_guards.py +111 -0
- hare/dialects/postgresql/lookups/json/postgresql_json_lookups.py +59 -0
- hare/dialects/postgresql/lookups/ltree/__init__.py +9 -0
- hare/dialects/postgresql/lookups/ltree/postgresql_ltree_field_lookups.py +54 -0
- hare/dialects/postgresql/lookups/ltree/postgresql_ltree_lookups.py +35 -0
- hare/dialects/postgresql/lookups/multiranges/__init__.py +9 -0
- hare/dialects/postgresql/lookups/multiranges/postgresql_multi_range_field_lookups.py +50 -0
- hare/dialects/postgresql/lookups/network/__init__.py +1 -0
- hare/dialects/postgresql/lookups/network/postgresql_network_field_lookups.py +46 -0
- hare/dialects/postgresql/lookups/network/postgresql_network_lookups.py +35 -0
- hare/dialects/postgresql/lookups/postgresql_filter_operators.py +96 -0
- hare/dialects/postgresql/lookups/postgresql_regex_lookups.py +22 -0
- hare/dialects/postgresql/lookups/postgresql_value_encoders.py +163 -0
- hare/dialects/postgresql/lookups/ranges/__init__.py +9 -0
- hare/dialects/postgresql/lookups/ranges/postgresql_range_field_lookups.py +49 -0
- hare/dialects/postgresql/lookups/ranges/postgresql_range_lookups.py +49 -0
- hare/dialects/postgresql/lookups/trigram/__init__.py +1 -0
- hare/dialects/postgresql/lookups/trigram/postgresql_trigram_lookups.py +69 -0
- hare/dialects/postgresql/lookups/trigram/trigram_operator_term.py +16 -0
- hare/dialects/postgresql/lookups/unaccent_transform.py +39 -0
- hare/dialects/postgresql/migration_safety/__init__.py +9 -0
- hare/dialects/postgresql/migration_safety/check_constraint_validation_rule.py +36 -0
- hare/dialects/postgresql/migration_safety/constants.py +18 -0
- hare/dialects/postgresql/migration_safety/foreign_key_validation_rule.py +74 -0
- hare/dialects/postgresql/migration_safety/index_without_concurrently_rule.py +45 -0
- hare/dialects/postgresql/migration_safety/postgresql_migration_safety_rules.py +59 -0
- hare/dialects/postgresql/migration_safety/set_not_null_rule.py +47 -0
- hare/dialects/postgresql/migration_safety/unique_constraint_index_rule.py +65 -0
- hare/dialects/postgresql/migration_safety/volatile_default_rule.py +40 -0
- hare/dialects/postgresql/parameters/__init__.py +1 -0
- hare/dialects/postgresql/parameters/constants.py +83 -0
- hare/dialects/postgresql/parameters/postgresql_parameters.py +86 -0
- hare/dialects/postgresql/partitioning/__init__.py +23 -0
- hare/dialects/postgresql/partitioning/constants.py +56 -0
- hare/dialects/postgresql/partitioning/explicit_partitioning.py +97 -0
- hare/dialects/postgresql/partitioning/hash_partitioning.py +50 -0
- hare/dialects/postgresql/partitioning/list_partitioning.py +55 -0
- hare/dialects/postgresql/partitioning/observed_partitioning.py +205 -0
- hare/dialects/postgresql/partitioning/partitioning.py +280 -0
- hare/dialects/postgresql/partitioning/partitions/__init__.py +1 -0
- hare/dialects/postgresql/partitioning/partitions/default_partition.py +30 -0
- hare/dialects/postgresql/partitioning/partitions/list_partition.py +36 -0
- hare/dialects/postgresql/partitioning/partitions/partition.py +46 -0
- hare/dialects/postgresql/partitioning/partitions/range_partition.py +94 -0
- hare/dialects/postgresql/partitioning/range_partitioning.py +60 -0
- hare/dialects/postgresql/postgresql_dialect.py +207 -0
- hare/dialects/postgresql/postgresql_introspector.py +1055 -0
- hare/dialects/postgresql/postgresql_table_options.py +165 -0
- hare/dialects/postgresql/query/__init__.py +7 -0
- hare/dialects/postgresql/query/declarations.py +13 -0
- hare/dialects/postgresql/renderers/__init__.py +7 -0
- hare/dialects/postgresql/renderers/constants.py +43 -0
- hare/dialects/postgresql/renderers/postgresql_container_renderers.py +90 -0
- hare/dialects/postgresql/renderers/postgresql_defaults.py +88 -0
- hare/dialects/postgresql/renderers/postgresql_json_renderers.py +57 -0
- hare/dialects/postgresql/renderers/postgresql_number_renderers.py +58 -0
- hare/dialects/postgresql/renderers/postgresql_renderers.py +82 -0
- hare/dialects/postgresql/renderers/postgresql_temporal_renderers.py +179 -0
- hare/dialects/postgresql/renderers/postgresql_text_renderers.py +67 -0
- hare/dialects/postgresql/request_query/__init__.py +8 -0
- hare/dialects/postgresql/request_query/declarations.py +17 -0
- hare/dialects/postgresql/schema/__init__.py +0 -0
- hare/dialects/postgresql/schema/columns/__init__.py +1 -0
- hare/dialects/postgresql/schema/columns/postgresql_column_backfill.py +13 -0
- hare/dialects/postgresql/schema/columns/postgresql_column_narrowing_check.py +42 -0
- hare/dialects/postgresql/schema/columns/postgresql_column_type_changes.py +129 -0
- hare/dialects/postgresql/schema/constants.py +384 -0
- hare/dialects/postgresql/schema/constraints/__init__.py +1 -0
- hare/dialects/postgresql/schema/constraints/postgresql_constraint_statements.py +119 -0
- hare/dialects/postgresql/schema/indexes/__init__.py +1 -0
- hare/dialects/postgresql/schema/indexes/postgresql_index_statements.py +24 -0
- hare/dialects/postgresql/schema/postgresql_schema_editor.py +280 -0
- hare/dialects/postgresql/schema/relations/__init__.py +1 -0
- hare/dialects/postgresql/schema/relations/postgresql_foreign_key_rebuild.py +230 -0
- hare/dialects/postgresql/schema/runtime_statements/__init__.py +1 -0
- hare/dialects/postgresql/schema/runtime_statements/postgresql_foreign_key_deferral.py +109 -0
- hare/dialects/postgresql/schema/runtime_statements/postgresql_table_clearing.py +80 -0
- hare/dialects/postgresql/schema/runtime_statements/postgresql_table_locks.py +27 -0
- hare/dialects/postgresql/schema/runtime_statements/postgresql_tenant_conditions.py +34 -0
- hare/dialects/postgresql/schema/schema_objects/__init__.py +1 -0
- hare/dialects/postgresql/schema/schema_objects/postgresql_database_functions.py +95 -0
- hare/dialects/postgresql/schema/schema_objects/postgresql_enum_types.py +130 -0
- hare/dialects/postgresql/schema/schema_objects/postgresql_extensions.py +35 -0
- hare/dialects/postgresql/schema/schema_objects/postgresql_grants.py +89 -0
- hare/dialects/postgresql/schema/schema_objects/postgresql_materialized_views.py +107 -0
- hare/dialects/postgresql/schema/schema_objects/postgresql_row_level_security_policies.py +125 -0
- hare/dialects/postgresql/schema/schema_objects/postgresql_schemas.py +51 -0
- hare/dialects/postgresql/schema/schema_objects/postgresql_sequences.py +132 -0
- hare/dialects/postgresql/schema/schema_objects/postgresql_views.py +53 -0
- hare/dialects/postgresql/schema/shadow/__init__.py +0 -0
- hare/dialects/postgresql/schema/shadow/postgresql_shadow_database.py +78 -0
- hare/dialects/postgresql/schema/tables/__init__.py +1 -0
- hare/dialects/postgresql/schema/tables/postgresql_table_comments.py +74 -0
- hare/dialects/postgresql/schema/tables/postgresql_table_partitions.py +229 -0
- hare/dialects/postgresql/schema/tables/postgresql_table_rebuild.py +118 -0
- hare/dialects/postgresql/schema/triggers/__init__.py +1 -0
- hare/dialects/postgresql/schema/triggers/postgresql_trigger_statements.py +141 -0
- hare/dialects/postgresql/search/__init__.py +8 -0
- hare/dialects/postgresql/search/constants.py +43 -0
- hare/dialects/postgresql/search/criterion/__init__.py +14 -0
- hare/dialects/postgresql/search/criterion/declarations.py +14 -0
- hare/dialects/postgresql/search/criterion/search_criterion.py +62 -0
- hare/dialects/postgresql/search/criterion/ts_query_function.py +20 -0
- hare/dialects/postgresql/search/criterion/ts_query_invert.py +32 -0
- hare/dialects/postgresql/search/enums.py +12 -0
- hare/dialects/postgresql/search/functions/__init__.py +9 -0
- hare/dialects/postgresql/search/functions/plain_to_ts_query.py +18 -0
- hare/dialects/postgresql/search/functions/to_ts_vector.py +20 -0
- hare/dialects/postgresql/search/lexemes/__init__.py +1 -0
- hare/dialects/postgresql/search/lexemes/combined_lexeme.py +35 -0
- hare/dialects/postgresql/search/lexemes/lexeme.py +77 -0
- hare/dialects/postgresql/search/lexemes/lexeme_combinable.py +59 -0
- hare/dialects/postgresql/search/postgresql_text_search.py +237 -0
- hare/dialects/postgresql/search/ts_vector_expression_reader.py +106 -0
- hare/dialects/postgresql/server_versions.py +26 -0
- hare/dialects/postgresql/spatial/__init__.py +7 -0
- hare/dialects/postgresql/spatial/constants.py +118 -0
- hare/dialects/postgresql/spatial/postgresql_spatial_renderers.py +102 -0
- hare/dialects/postgresql/transactions/__init__.py +1 -0
- hare/dialects/postgresql/transactions/constants.py +21 -0
- hare/dialects/postgresql/transactions/postgresql_transaction_statements.py +40 -0
- hare/dialects/postgresql/transactions/postgresql_two_phase_commit.py +87 -0
- hare/dialects/postgresql/types/__init__.py +1 -0
- hare/dialects/postgresql/types/postgresql_container_values.py +104 -0
- hare/dialects/postgresql/types/postgresql_types.py +213 -0
- hare/dialects/postgresql/validators/__init__.py +15 -0
- hare/dialects/postgresql/validators/keys_validator.py +32 -0
- hare/dialects/postgresql/validators/range_bound_validator.py +33 -0
- hare/dialects/postgresql/validators/range_max_value_validator.py +17 -0
- hare/dialects/postgresql/validators/range_min_value_validator.py +17 -0
- hare/dialects/postgresql/vectors/__init__.py +1 -0
- hare/dialects/postgresql/vectors/constants.py +13 -0
- hare/dialects/postgresql/vectors/postgresql_vector_renderers.py +40 -0
- hare/dialects/postgresql/vectors/postgresql_vector_values.py +94 -0
- hare/dialects/sqlite/__init__.py +0 -0
- hare/dialects/sqlite/clauses/__init__.py +1 -0
- hare/dialects/sqlite/clauses/constants.py +7 -0
- hare/dialects/sqlite/clauses/sqlite_query_clauses.py +100 -0
- hare/dialects/sqlite/client/__init__.py +12 -0
- hare/dialects/sqlite/client/constants.py +103 -0
- hare/dialects/sqlite/client/declarations.py +27 -0
- hare/dialects/sqlite/client/sqlite_client.py +507 -0
- hare/dialects/sqlite/client/sqlite_migration_lock.py +76 -0
- hare/dialects/sqlite/client/sqlite_transaction_client.py +160 -0
- hare/dialects/sqlite/connection/__init__.py +1 -0
- hare/dialects/sqlite/connection/constants.py +7 -0
- hare/dialects/sqlite/connection/sqlite_driver.py +59 -0
- hare/dialects/sqlite/constants.py +451 -0
- hare/dialects/sqlite/drivers/__init__.py +1 -0
- hare/dialects/sqlite/drivers/aiosqlite/__init__.py +1 -0
- hare/dialects/sqlite/drivers/aiosqlite/aiosqlite_driver.py +41 -0
- hare/dialects/sqlite/drivers/aiosqlite/client/__init__.py +23 -0
- hare/dialects/sqlite/drivers/aiosqlite/client/aiosqlite_client.py +428 -0
- hare/dialects/sqlite/drivers/aiosqlite/client/aiosqlite_client_with_regexp_support.py +16 -0
- hare/dialects/sqlite/drivers/aiosqlite/client/aiosqlite_connection_wrapper.py +62 -0
- hare/dialects/sqlite/drivers/aiosqlite/client/aiosqlite_statement_timeout_connection_wrapper.py +53 -0
- hare/dialects/sqlite/drivers/aiosqlite/client/aiosqlite_transaction_client.py +176 -0
- hare/dialects/sqlite/drivers/aiosqlite/client/aiosqlite_transaction_connection_wrapper.py +23 -0
- hare/dialects/sqlite/drivers/aiosqlite/constants.py +11 -0
- hare/dialects/sqlite/drivers/constants.py +19 -0
- hare/dialects/sqlite/enums.py +37 -0
- hare/dialects/sqlite/exceptions.py +10 -0
- hare/dialects/sqlite/functions/__init__.py +0 -0
- hare/dialects/sqlite/functions/comparison/__init__.py +11 -0
- hare/dialects/sqlite/functions/comparison/sqlite_cast.py +204 -0
- hare/dialects/sqlite/functions/comparison/sqlite_greatest_least.py +63 -0
- hare/dialects/sqlite/functions/constants.py +102 -0
- hare/dialects/sqlite/functions/datetime/__init__.py +13 -0
- hare/dialects/sqlite/functions/datetime/date_truncation.py +115 -0
- hare/dialects/sqlite/functions/datetime/sqlite_date_part_extraction.py +77 -0
- hare/dialects/sqlite/functions/datetime/sqlite_date_timestamp.py +48 -0
- hare/dialects/sqlite/functions/datetime/sqlite_local_now.py +54 -0
- hare/dialects/sqlite/functions/datetime/temporal_arithmetic_functions.py +147 -0
- hare/dialects/sqlite/functions/decimal/__init__.py +1 -0
- hare/dialects/sqlite/functions/decimal/sqlite_decimal_arithmetic.py +152 -0
- hare/dialects/sqlite/functions/decimal/sqlite_decimal_average.py +23 -0
- hare/dialects/sqlite/functions/decimal/sqlite_decimal_collation.py +125 -0
- hare/dialects/sqlite/functions/decimal/sqlite_decimal_comparand.py +23 -0
- hare/dialects/sqlite/functions/decimal/sqlite_decimal_operation.py +33 -0
- hare/dialects/sqlite/functions/decimal/sqlite_decimal_round.py +50 -0
- hare/dialects/sqlite/functions/decimal/sqlite_decimal_storage.py +77 -0
- hare/dialects/sqlite/functions/decimal/sqlite_decimal_sum.py +62 -0
- hare/dialects/sqlite/functions/decimal/sqlite_decimal_text.py +22 -0
- hare/dialects/sqlite/functions/decimal/sqlite_stored_decimal.py +29 -0
- hare/dialects/sqlite/functions/json/__init__.py +9 -0
- hare/dialects/sqlite/functions/json/sqlite_json_datetime.py +124 -0
- hare/dialects/sqlite/functions/json/sqlite_json_path.py +116 -0
- hare/dialects/sqlite/functions/regex/__init__.py +5 -0
- hare/dialects/sqlite/functions/regex/sqlite_posix_regex.py +102 -0
- hare/dialects/sqlite/functions/regex/sqlite_regex_criterion.py +18 -0
- hare/dialects/sqlite/functions/sqlite_checked_integer.py +15 -0
- hare/dialects/sqlite/functions/sqlite_collation.py +51 -0
- hare/dialects/sqlite/functions/sqlite_connection_function.py +17 -0
- hare/dialects/sqlite/functions/sqlite_function_errors.py +45 -0
- hare/dialects/sqlite/functions/sqlite_integer_range.py +48 -0
- hare/dialects/sqlite/functions/sqlite_math_functions.py +233 -0
- hare/dialects/sqlite/functions/sqlite_native_functions.py +12 -0
- hare/dialects/sqlite/functions/sqlite_sort_keys.py +58 -0
- hare/dialects/sqlite/functions/statistics/__init__.py +19 -0
- hare/dialects/sqlite/functions/statistics/declarations.py +31 -0
- hare/dialects/sqlite/functions/statistics/sqlite_statistic.py +118 -0
- hare/dialects/sqlite/functions/statistics/sqlite_statistics.py +51 -0
- hare/dialects/sqlite/functions/text/__init__.py +1 -0
- hare/dialects/sqlite/functions/text/sqlite_text_functions.py +140 -0
- hare/dialects/sqlite/indexes/__init__.py +7 -0
- hare/dialects/sqlite/indexes/constants.py +45 -0
- hare/dialects/sqlite/indexes/full_text_index.py +228 -0
- hare/dialects/sqlite/indexes/separate_table_index.py +105 -0
- hare/dialects/sqlite/indexes/spatialite_index.py +228 -0
- hare/dialects/sqlite/literals/__init__.py +1 -0
- hare/dialects/sqlite/literals/sqlite_literals.py +51 -0
- hare/dialects/sqlite/lookups/__init__.py +0 -0
- hare/dialects/sqlite/lookups/constants.py +18 -0
- hare/dialects/sqlite/lookups/in_list/__init__.py +11 -0
- hare/dialects/sqlite/lookups/in_list/json_array_row_values.py +39 -0
- hare/dialects/sqlite/lookups/in_list/json_array_values.py +116 -0
- hare/dialects/sqlite/lookups/in_list/sqlite_large_in_list.py +96 -0
- hare/dialects/sqlite/lookups/json/__init__.py +1 -0
- hare/dialects/sqlite/lookups/json/sqlite_json_filter_guards.py +128 -0
- hare/dialects/sqlite/lookups/json/sqlite_json_lookups.py +51 -0
- hare/dialects/sqlite/lookups/json/sqlite_json_path_lookups.py +56 -0
- hare/dialects/sqlite/lookups/json/sqlite_json_type_criterion.py +13 -0
- hare/dialects/sqlite/lookups/sqlite_filter_operators.py +89 -0
- hare/dialects/sqlite/migration_safety/__init__.py +9 -0
- hare/dialects/sqlite/migration_safety/sqlite_migration_safety_rules.py +32 -0
- hare/dialects/sqlite/parameters/__init__.py +1 -0
- hare/dialects/sqlite/parameters/constants.py +11 -0
- hare/dialects/sqlite/parameters/sqlite_parameter_adapters.py +61 -0
- hare/dialects/sqlite/parameters/sqlite_parameters.py +27 -0
- hare/dialects/sqlite/query/__init__.py +7 -0
- hare/dialects/sqlite/query/declarations.py +13 -0
- hare/dialects/sqlite/renderers/__init__.py +7 -0
- hare/dialects/sqlite/renderers/constants.py +43 -0
- hare/dialects/sqlite/renderers/sqlite_defaults.py +84 -0
- hare/dialects/sqlite/renderers/sqlite_json_renderers.py +142 -0
- hare/dialects/sqlite/renderers/sqlite_number_renderers.py +137 -0
- hare/dialects/sqlite/renderers/sqlite_renderers.py +235 -0
- hare/dialects/sqlite/renderers/sqlite_temporal_renderers.py +138 -0
- hare/dialects/sqlite/renderers/sqlite_text_renderers.py +60 -0
- hare/dialects/sqlite/request_query/__init__.py +8 -0
- hare/dialects/sqlite/request_query/declarations.py +16 -0
- hare/dialects/sqlite/schema/__init__.py +0 -0
- hare/dialects/sqlite/schema/columns/__init__.py +1 -0
- hare/dialects/sqlite/schema/columns/sqlite_column_backfill.py +29 -0
- hare/dialects/sqlite/schema/columns/sqlite_column_conversion_check.py +181 -0
- hare/dialects/sqlite/schema/columns/sqlite_column_narrowing_check.py +24 -0
- hare/dialects/sqlite/schema/columns/sqlite_column_type_changes.py +148 -0
- hare/dialects/sqlite/schema/constants.py +108 -0
- hare/dialects/sqlite/schema/constraints/__init__.py +1 -0
- hare/dialects/sqlite/schema/constraints/sqlite_constraint_statements.py +32 -0
- hare/dialects/sqlite/schema/indexes/__init__.py +1 -0
- hare/dialects/sqlite/schema/indexes/sqlite_generated_index_names.py +61 -0
- hare/dialects/sqlite/schema/indexes/sqlite_index_statements.py +78 -0
- hare/dialects/sqlite/schema/relations/__init__.py +1 -0
- hare/dialects/sqlite/schema/relations/sqlite_foreign_key_rebuild.py +100 -0
- hare/dialects/sqlite/schema/runtime_statements/__init__.py +1 -0
- hare/dialects/sqlite/schema/runtime_statements/sqlite_foreign_key_deferral.py +87 -0
- hare/dialects/sqlite/schema/runtime_statements/sqlite_table_clearing.py +39 -0
- hare/dialects/sqlite/schema/runtime_statements/sqlite_tenant_conditions.py +21 -0
- hare/dialects/sqlite/schema/shadow/__init__.py +0 -0
- hare/dialects/sqlite/schema/shadow/sqlite_shadow_database.py +36 -0
- hare/dialects/sqlite/schema/sqlite_schema_editor.py +492 -0
- hare/dialects/sqlite/schema/tables/__init__.py +1 -0
- hare/dialects/sqlite/schema/tables/sqlite_table_comments.py +32 -0
- hare/dialects/sqlite/schema/tables/sqlite_table_rebuild.py +164 -0
- hare/dialects/sqlite/schema/triggers/__init__.py +1 -0
- hare/dialects/sqlite/schema/triggers/sqlite_trigger_statements.py +70 -0
- hare/dialects/sqlite/search/__init__.py +8 -0
- hare/dialects/sqlite/search/constants.py +33 -0
- hare/dialects/sqlite/search/sqlite_full_text_query.py +137 -0
- hare/dialects/sqlite/search/sqlite_search_renderers.py +33 -0
- hare/dialects/sqlite/search/sqlite_text_search.py +308 -0
- hare/dialects/sqlite/search/terms/__init__.py +1 -0
- hare/dialects/sqlite/search/terms/full_text_headline.py +56 -0
- hare/dialects/sqlite/search/terms/full_text_match.py +73 -0
- hare/dialects/sqlite/search/terms/full_text_query.py +42 -0
- hare/dialects/sqlite/search/terms/full_text_query_combination.py +82 -0
- hare/dialects/sqlite/search/terms/full_text_rank.py +34 -0
- hare/dialects/sqlite/search/terms/full_text_row_value.py +104 -0
- hare/dialects/sqlite/server_versions.py +17 -0
- hare/dialects/sqlite/spatial/__init__.py +0 -0
- hare/dialects/sqlite/spatial/constants.py +173 -0
- hare/dialects/sqlite/spatial/spatialite_blob_reader.py +166 -0
- hare/dialects/sqlite/spatial/spatialite_blob_writer.py +105 -0
- hare/dialects/sqlite/spatial/sqlite_geometry_values.py +75 -0
- hare/dialects/sqlite/spatial/sqlite_spatial_extension.py +116 -0
- hare/dialects/sqlite/spatial/sqlite_spatial_renderers.py +202 -0
- hare/dialects/sqlite/sqlite_dialect.py +138 -0
- hare/dialects/sqlite/sqlite_introspector.py +1025 -0
- hare/dialects/sqlite/sqlite_table_options.py +92 -0
- hare/dialects/sqlite/table_option_constants.py +15 -0
- hare/dialects/sqlite/transactions/__init__.py +1 -0
- hare/dialects/sqlite/transactions/constants.py +10 -0
- hare/dialects/sqlite/transactions/sqlite_transaction_statements.py +19 -0
- hare/dialects/sqlite/types/__init__.py +1 -0
- hare/dialects/sqlite/types/sqlite_types.py +87 -0
- hare/dialects/sqlite/vectors/__init__.py +1 -0
- hare/dialects/sqlite/vectors/constants.py +16 -0
- hare/dialects/sqlite/vectors/sqlite_vector_extension.py +112 -0
- hare/dialects/sqlite/vectors/sqlite_vector_renderers.py +55 -0
- hare/dialects/sqlite/vectors/sqlite_vector_values.py +113 -0
- hare/exceptions.py +397 -0
- hare/fields/__init__.py +133 -0
- hare/fields/composite_primary_key.py +40 -0
- hare/fields/constants.py +120 -0
- hare/fields/data/__init__.py +3 -0
- hare/fields/data/binary_field.py +62 -0
- hare/fields/data/boolean_field.py +57 -0
- hare/fields/data/choices/__init__.py +16 -0
- hare/fields/data/choices/char_enum_field.py +27 -0
- hare/fields/data/choices/char_enum_field_instance.py +117 -0
- hare/fields/data/choices/int_enum_field.py +23 -0
- hare/fields/data/choices/int_enum_field_instance.py +102 -0
- hare/fields/data/constants.py +122 -0
- hare/fields/data/containers/__init__.py +10 -0
- hare/fields/data/containers/array_field.py +152 -0
- hare/fields/data/containers/constants.py +25 -0
- hare/fields/data/containers/container_field.py +342 -0
- hare/fields/data/containers/declarations.py +13 -0
- hare/fields/data/containers/map_field.py +165 -0
- hare/fields/data/containers/nested_field.py +47 -0
- hare/fields/data/containers/tuple_field.py +177 -0
- hare/fields/data/json/__init__.py +7 -0
- hare/fields/data/json/json_codec.py +152 -0
- hare/fields/data/json/json_field.py +387 -0
- hare/fields/data/json/json_path_field.py +77 -0
- hare/fields/data/json/json_text_field.py +13 -0
- hare/fields/data/network/__init__.py +8 -0
- hare/fields/data/network/constants.py +6 -0
- hare/fields/data/network/ip_address_field.py +109 -0
- hare/fields/data/network/ipv4_address_field.py +26 -0
- hare/fields/data/numeric/__init__.py +23 -0
- hare/fields/data/numeric/big_int_field.py +22 -0
- hare/fields/data/numeric/decimal_field.py +187 -0
- hare/fields/data/numeric/float_field.py +83 -0
- hare/fields/data/numeric/int_field.py +239 -0
- hare/fields/data/numeric/positive_big_int_field.py +19 -0
- hare/fields/data/numeric/positive_int_field.py +19 -0
- hare/fields/data/numeric/positive_small_int_field.py +19 -0
- hare/fields/data/numeric/small_int_field.py +22 -0
- hare/fields/data/temporal/__init__.py +11 -0
- hare/fields/data/temporal/date_field.py +87 -0
- hare/fields/data/temporal/datetime_field.py +384 -0
- hare/fields/data/temporal/parse_datetime.py +17 -0
- hare/fields/data/temporal/temporal_values.py +119 -0
- hare/fields/data/temporal/time_delta_field.py +111 -0
- hare/fields/data/temporal/time_field.py +193 -0
- hare/fields/data/text/__init__.py +20 -0
- hare/fields/data/text/char_field.py +78 -0
- hare/fields/data/text/email_field.py +76 -0
- hare/fields/data/text/phone_field.py +114 -0
- hare/fields/data/text/slug_field.py +52 -0
- hare/fields/data/text/text_field.py +33 -0
- hare/fields/data/text/text_values.py +39 -0
- hare/fields/data/text/url_field.py +62 -0
- hare/fields/data/uuid_field.py +82 -0
- hare/fields/database_default.py +28 -0
- hare/fields/db_default_not_set.py +36 -0
- hare/fields/db_defaults/__init__.py +13 -0
- hare/fields/db_defaults/now.py +108 -0
- hare/fields/db_defaults/random_hex.py +30 -0
- hare/fields/db_defaults/sql_default.py +95 -0
- hare/fields/db_defaults/uuid_v7.py +36 -0
- hare/fields/encrypted/__init__.py +7 -0
- hare/fields/encrypted/blind_index_field.py +49 -0
- hare/fields/encrypted/constants.py +41 -0
- hare/fields/encrypted/encrypted_field_base.py +143 -0
- hare/fields/encrypted/encrypted_json_field.py +238 -0
- hare/fields/encrypted/encrypted_text_field.py +130 -0
- hare/fields/encrypted/field_encryption.py +267 -0
- hare/fields/enums.py +91 -0
- hare/fields/field.py +1231 -0
- hare/fields/field_meta.py +16 -0
- hare/fields/generated_field.py +211 -0
- hare/fields/narrowing/__init__.py +7 -0
- hare/fields/narrowing/decimal_digits_limit.py +11 -0
- hare/fields/narrowing/enum_values_limit.py +32 -0
- hare/fields/narrowing/integer_range_limit.py +13 -0
- hare/fields/narrowing/narrowing_limit.py +8 -0
- hare/fields/narrowing/text_length_limit.py +13 -0
- hare/fields/registrations/__init__.py +1 -0
- hare/fields/registrations/registered_lookup.py +29 -0
- hare/fields/registrations/registered_transform.py +22 -0
- hare/fields/relations/__init__.py +3 -0
- hare/fields/relations/constants.py +10 -0
- hare/fields/relations/declarations.py +5 -0
- hare/fields/relations/fields/__init__.py +35 -0
- hare/fields/relations/fields/backward_foreign_key_relation.py +46 -0
- hare/fields/relations/fields/declarations.py +21 -0
- hare/fields/relations/fields/foreign_key_field.py +89 -0
- hare/fields/relations/fields/foreign_key_field_instance.py +124 -0
- hare/fields/relations/fields/generic_foreign_key_field.py +56 -0
- hare/fields/relations/fields/generic_foreign_key_field_instance.py +455 -0
- hare/fields/relations/fields/many_to_many_field.py +60 -0
- hare/fields/relations/fields/many_to_many_field_instance.py +126 -0
- hare/fields/relations/fields/one_to_one_field.py +89 -0
- hare/fields/relations/fields/one_to_one_field_instance.py +45 -0
- hare/fields/relations/fields/relational_field.py +153 -0
- hare/fields/relations/inherited_relation.py +30 -0
- hare/fields/relations/relation_accessors.py +271 -0
- hare/fields/relations/relation_values.py +106 -0
- hare/fields/relations/swappable_model_reference.py +60 -0
- hare/fields/validators/__init__.py +63 -0
- hare/fields/validators/exceptions.py +52 -0
- hare/fields/validators/formats/__init__.py +1 -0
- hare/fields/validators/formats/comma_separated_integer_list_validator.py +22 -0
- hare/fields/validators/formats/domain_name_validator.py +74 -0
- hare/fields/validators/formats/e164_phone_validator.py +32 -0
- hare/fields/validators/formats/email_validator.py +87 -0
- hare/fields/validators/formats/ipv46_validator.py +28 -0
- hare/fields/validators/formats/ipv4_validator.py +23 -0
- hare/fields/validators/formats/ipv6_validator.py +23 -0
- hare/fields/validators/formats/regex_validator.py +38 -0
- hare/fields/validators/formats/slug_validator.py +36 -0
- hare/fields/validators/formats/url_validator.py +95 -0
- hare/fields/validators/limits/__init__.py +1 -0
- hare/fields/validators/limits/length_validator.py +17 -0
- hare/fields/validators/limits/max_digits_validator.py +58 -0
- hare/fields/validators/limits/max_length_validator.py +20 -0
- hare/fields/validators/limits/max_value_validator.py +19 -0
- hare/fields/validators/limits/min_length_validator.py +20 -0
- hare/fields/validators/limits/min_value_validator.py +19 -0
- hare/fields/validators/limits/numeric_validator.py +19 -0
- hare/fields/validators/validator.py +34 -0
- hare/gis/__init__.py +52 -0
- hare/gis/aggregates/__init__.py +5 -0
- hare/gis/aggregates/declarations.py +42 -0
- hare/gis/aggregates/spatial_aggregate.py +57 -0
- hare/gis/constants.py +126 -0
- hare/gis/enums.py +74 -0
- hare/gis/fields/__init__.py +23 -0
- hare/gis/fields/declarations.py +61 -0
- hare/gis/fields/extent_field.py +60 -0
- hare/gis/fields/geometry_field.py +239 -0
- hare/gis/fields/made_line_field.py +86 -0
- hare/gis/functions/__init__.py +53 -0
- hare/gis/functions/buffer.py +29 -0
- hare/gis/functions/constants.py +17 -0
- hare/gis/functions/declarations.py +188 -0
- hare/gis/functions/simplify.py +29 -0
- hare/gis/functions/spatial_function.py +115 -0
- hare/gis/functions/transform.py +41 -0
- hare/gis/geometries/__init__.py +19 -0
- hare/gis/geometries/declarations.py +38 -0
- hare/gis/geometries/geometry.py +297 -0
- hare/gis/geometries/geometry_collection.py +62 -0
- hare/gis/geometries/line_string.py +46 -0
- hare/gis/geometries/multi_geometry.py +75 -0
- hare/gis/geometries/point.py +65 -0
- hare/gis/geometries/polygon.py +89 -0
- hare/gis/lookups/__init__.py +3 -0
- hare/gis/lookups/spatial_field_lookups.py +219 -0
- hare/gis/readers/__init__.py +11 -0
- hare/gis/readers/constants.py +15 -0
- hare/gis/readers/ewkb_reader.py +148 -0
- hare/gis/readers/geo_json_reader.py +54 -0
- hare/gis/readers/wkt_reader.py +226 -0
- hare/gis/spatial_features.py +57 -0
- hare/gis/terms/__init__.py +11 -0
- hare/gis/terms/geometry_value.py +33 -0
- hare/gis/terms/spatial_aggregate_function.py +30 -0
- hare/gis/terms/spatial_function_term.py +39 -0
- hare/gis/terms/spatial_relation_term.py +39 -0
- hare/health/__init__.py +19 -0
- hare/health/constants.py +32 -0
- hare/health/criteria/__init__.py +27 -0
- hare/health/criteria/acquire_wait_time.py +35 -0
- hare/health/criteria/all_of.py +38 -0
- hare/health/criteria/declarations.py +33 -0
- hare/health/criteria/health_criterion.py +87 -0
- hare/health/criteria/ping_failed.py +27 -0
- hare/health/criteria/ping_latency.py +29 -0
- hare/health/criteria/pool_count_criterion.py +37 -0
- hare/health/criteria/pool_saturation.py +35 -0
- hare/health/criteria/waiting_requests.py +33 -0
- hare/health/declarations.py +83 -0
- hare/health/enums.py +14 -0
- hare/health/health_check.py +240 -0
- hare/health/health_report.py +65 -0
- hare/inspectdb/__init__.py +38 -0
- hare/inspectdb/constants.py +60 -0
- hare/inspectdb/exceptions.py +72 -0
- hare/inspectdb/generation/__init__.py +1 -0
- hare/inspectdb/generation/column_type_mapper.py +113 -0
- hare/inspectdb/generation/declarations.py +34 -0
- hare/inspectdb/generation/inspected_model.py +35 -0
- hare/inspectdb/generation/inspected_model_builder.py +1174 -0
- hare/inspectdb/generation/many_to_many_tables.py +91 -0
- hare/inspectdb/generation/model_factory.py +88 -0
- hare/inspectdb/generation/model_naming.py +75 -0
- hare/inspectdb/generation/model_source_builder.py +148 -0
- hare/inspectdb/introspection/__init__.py +28 -0
- hare/inspectdb/introspection/column_info.py +67 -0
- hare/inspectdb/introspection/composite_foreign_key_info.py +27 -0
- hare/inspectdb/introspection/database_catalog.py +252 -0
- hare/inspectdb/introspection/enums.py +26 -0
- hare/inspectdb/introspection/foreign_key_info.py +25 -0
- hare/inspectdb/introspection/index_info.py +265 -0
- hare/inspectdb/introspection/inspected_field_specification.py +47 -0
- hare/inspectdb/introspection/schema_introspector.py +564 -0
- hare/inspectdb/introspection/schema_part.py +103 -0
- hare/inspectdb/introspection/table_info.py +112 -0
- hare/inspectdb/introspection/table_parts.py +101 -0
- hare/inspectdb/schema_inspector.py +224 -0
- hare/instrumentation/__init__.py +31 -0
- hare/instrumentation/capture/__init__.py +9 -0
- hare/instrumentation/capture/capture_needs.py +54 -0
- hare/instrumentation/capture/captured_change.py +38 -0
- hare/instrumentation/capture/captured_write.py +223 -0
- hare/instrumentation/capture/change_capturing.py +496 -0
- hare/instrumentation/capture/change_sink.py +57 -0
- hare/instrumentation/change_events.py +246 -0
- hare/instrumentation/constants.py +41 -0
- hare/instrumentation/declarations.py +196 -0
- hare/instrumentation/enums.py +35 -0
- hare/instrumentation/observers/__init__.py +1 -0
- hare/instrumentation/observers/observer.py +56 -0
- hare/instrumentation/observers/observer_dispatch.py +197 -0
- hare/instrumentation/observers/observer_set.py +138 -0
- hare/instrumentation/observers/observers.py +368 -0
- hare/instrumentation/pools/__init__.py +1 -0
- hare/instrumentation/pools/duration_records.py +50 -0
- hare/instrumentation/pools/pool_metrics.py +50 -0
- hare/instrumentation/pools/pool_registry.py +49 -0
- hare/instrumentation/queries/__init__.py +1 -0
- hare/instrumentation/queries/query_tags.py +133 -0
- hare/instrumentation/queries/query_wrapper.py +37 -0
- hare/lazy_loading/__init__.py +1 -0
- hare/lazy_loading/lazy_pattern.py +45 -0
- hare/lazy_loading/pydantic_classes.py +96 -0
- hare/migrations/__init__.py +90 -0
- hare/migrations/api/__init__.py +24 -0
- hare/migrations/api/checkmigrations.py +55 -0
- hare/migrations/api/makemigrations.py +78 -0
- hare/migrations/api/migrate.py +47 -0
- hare/migrations/api/migration_request_parser.py +86 -0
- hare/migrations/api/plan.py +39 -0
- hare/migrations/api/sqlmigrate.py +51 -0
- hare/migrations/api/squashmigrations.py +51 -0
- hare/migrations/autodetection/__init__.py +4 -0
- hare/migrations/autodetection/constants.py +49 -0
- hare/migrations/autodetection/diffs/__init__.py +1 -0
- hare/migrations/autodetection/diffs/constraint_diff.py +48 -0
- hare/migrations/autodetection/diffs/declarations.py +73 -0
- hare/migrations/autodetection/diffs/declared_schema_object_diff.py +47 -0
- hare/migrations/autodetection/diffs/grant_diff.py +24 -0
- hare/migrations/autodetection/diffs/index_diff.py +73 -0
- hare/migrations/autodetection/diffs/materialized_view_diff.py +44 -0
- hare/migrations/autodetection/diffs/partition_diff.py +99 -0
- hare/migrations/autodetection/diffs/schema_object_diff.py +153 -0
- hare/migrations/autodetection/diffs/state_field_diff.py +566 -0
- hare/migrations/autodetection/diffs/state_model_diff.py +355 -0
- hare/migrations/autodetection/diffs/trigger_diff.py +31 -0
- hare/migrations/autodetection/diffs/view_diff.py +24 -0
- hare/migrations/autodetection/field_comparable_values.py +20 -0
- hare/migrations/autodetection/migration_autodetector.py +337 -0
- hare/migrations/autodetection/migration_splitter.py +151 -0
- hare/migrations/autodetection/operation_generator.py +1115 -0
- hare/migrations/autodetection/operation_sorter.py +213 -0
- hare/migrations/autodetection/rename_questions.py +98 -0
- hare/migrations/autodetection/required_extensions.py +118 -0
- hare/migrations/autodetection/schema_object_operations.py +150 -0
- hare/migrations/autodetection/split_migration.py +24 -0
- hare/migrations/autodetection/state_signatures.py +192 -0
- hare/migrations/constants.py +109 -0
- hare/migrations/drift/__init__.py +13 -0
- hare/migrations/drift/column_mismatch.py +14 -0
- hare/migrations/drift/constants.py +43 -0
- hare/migrations/drift/detect_drift.py +40 -0
- hare/migrations/drift/detect_drift_for_alias.py +87 -0
- hare/migrations/drift/drift_result.py +22 -0
- hare/migrations/drift/shadow/__init__.py +0 -0
- hare/migrations/drift/shadow/column_field_names.py +26 -0
- hare/migrations/drift/shadow/schema_comparison.py +557 -0
- hare/migrations/drift/shadow/shadow_drift.py +318 -0
- hare/migrations/drift/shadow/shadow_state.py +83 -0
- hare/migrations/exceptions.py +69 -0
- hare/migrations/execution/__init__.py +3 -0
- hare/migrations/execution/connections_plan.py +192 -0
- hare/migrations/execution/constants.py +4 -0
- hare/migrations/execution/executor/__init__.py +11 -0
- hare/migrations/execution/executor/migration_executor.py +640 -0
- hare/migrations/execution/executor/migration_target.py +9 -0
- hare/migrations/execution/executor/plan_step.py +30 -0
- hare/migrations/execution/migration_runner.py +304 -0
- hare/migrations/execution/swappable_setting_check.py +161 -0
- hare/migrations/loading/__init__.py +4 -0
- hare/migrations/loading/graph/__init__.py +13 -0
- hare/migrations/loading/graph/dummy_node.py +22 -0
- hare/migrations/loading/graph/migration_graph.py +235 -0
- hare/migrations/loading/graph/migration_key.py +14 -0
- hare/migrations/loading/graph/node.py +40 -0
- hare/migrations/loading/migration_loader.py +256 -0
- hare/migrations/loading/migrations_modules.py +207 -0
- hare/migrations/loading/recorder/__init__.py +9 -0
- hare/migrations/loading/recorder/migration_recorder.py +130 -0
- hare/migrations/loading/recorder/noop_recorder.py +26 -0
- hare/migrations/making/__init__.py +1 -0
- hare/migrations/making/declared_attribute_values.py +27 -0
- hare/migrations/making/migration_changes.py +27 -0
- hare/migrations/making/migration_checks.py +115 -0
- hare/migrations/making/migration_maker.py +291 -0
- hare/migrations/making/migration_optimizer.py +70 -0
- hare/migrations/making/migration_squasher.py +193 -0
- hare/migrations/making/squashed_migration.py +24 -0
- hare/migrations/migration.py +341 -0
- hare/migrations/operations/__init__.py +132 -0
- hare/migrations/operations/columns/__init__.py +11 -0
- hare/migrations/operations/columns/alter_column_not_null_safe.py +140 -0
- hare/migrations/operations/columns/backfill_column.py +118 -0
- hare/migrations/operations/constants.py +20 -0
- hare/migrations/operations/constraints/__init__.py +15 -0
- hare/migrations/operations/constraints/add_constraint.py +129 -0
- hare/migrations/operations/constraints/declarations.py +13 -0
- hare/migrations/operations/constraints/rename_constraint.py +21 -0
- hare/migrations/operations/constraints/validate_constraint.py +66 -0
- hare/migrations/operations/database_functions/__init__.py +10 -0
- hare/migrations/operations/database_functions/add_function.py +28 -0
- hare/migrations/operations/database_functions/alter_function.py +30 -0
- hare/migrations/operations/database_functions/remove_function.py +20 -0
- hare/migrations/operations/database_functions/rename_function.py +21 -0
- hare/migrations/operations/declared_uniqueness_checks.py +76 -0
- hare/migrations/operations/dependencies/__init__.py +1 -0
- hare/migrations/operations/dependencies/operation_dependency.py +89 -0
- hare/migrations/operations/dependencies/relation_dependencies.py +157 -0
- hare/migrations/operations/dictionaries/__init__.py +10 -0
- hare/migrations/operations/dictionaries/add_dictionary.py +28 -0
- hare/migrations/operations/dictionaries/alter_dictionary.py +29 -0
- hare/migrations/operations/dictionaries/remove_dictionary.py +20 -0
- hare/migrations/operations/dictionaries/rename_dictionary.py +21 -0
- hare/migrations/operations/enum_types/__init__.py +7 -0
- hare/migrations/operations/enum_types/alter_enum_type.py +64 -0
- hare/migrations/operations/enum_types/create_enum_type.py +57 -0
- hare/migrations/operations/enum_types/drop_enum_type.py +66 -0
- hare/migrations/operations/enum_types/enum_type_operation.py +35 -0
- hare/migrations/operations/enums.py +24 -0
- hare/migrations/operations/extensions/__init__.py +15 -0
- hare/migrations/operations/extensions/create_collation.py +82 -0
- hare/migrations/operations/extensions/create_extension.py +47 -0
- hare/migrations/operations/extensions/remove_collation.py +35 -0
- hare/migrations/operations/extensions/remove_extension.py +40 -0
- hare/migrations/operations/fields/__init__.py +11 -0
- hare/migrations/operations/fields/add_field.py +135 -0
- hare/migrations/operations/fields/alter_field.py +128 -0
- hare/migrations/operations/fields/field_add_remove_operation.py +41 -0
- hare/migrations/operations/fields/field_like.py +14 -0
- hare/migrations/operations/fields/remove_field.py +326 -0
- hare/migrations/operations/fields/rename_field.py +725 -0
- hare/migrations/operations/grants/__init__.py +8 -0
- hare/migrations/operations/grants/add_grant.py +31 -0
- hare/migrations/operations/grants/remove_grant.py +35 -0
- hare/migrations/operations/hare_operation.py +174 -0
- hare/migrations/operations/indexes/__init__.py +13 -0
- hare/migrations/operations/indexes/add_index.py +42 -0
- hare/migrations/operations/indexes/declarations.py +12 -0
- hare/migrations/operations/indexes/remove_index.py +36 -0
- hare/migrations/operations/materialized_views/__init__.py +17 -0
- hare/migrations/operations/materialized_views/add_materialized_view.py +37 -0
- hare/migrations/operations/materialized_views/alter_materialized_view.py +32 -0
- hare/migrations/operations/materialized_views/refresh_materialized_view.py +57 -0
- hare/migrations/operations/materialized_views/remove_materialized_view.py +28 -0
- hare/migrations/operations/materialized_views/rename_materialized_view.py +23 -0
- hare/migrations/operations/model_bound_operation.py +95 -0
- hare/migrations/operations/models/__init__.py +12 -0
- hare/migrations/operations/models/alter_model_options.py +158 -0
- hare/migrations/operations/models/alter_model_schema.py +114 -0
- hare/migrations/operations/models/alter_model_table.py +65 -0
- hare/migrations/operations/models/create_model.py +407 -0
- hare/migrations/operations/models/delete_model.py +122 -0
- hare/migrations/operations/models/model_table_operation.py +45 -0
- hare/migrations/operations/models/rename_model.py +165 -0
- hare/migrations/operations/models/table_renaming_operation.py +101 -0
- hare/migrations/operations/operation.py +252 -0
- hare/migrations/operations/partitions/__init__.py +11 -0
- hare/migrations/operations/partitions/add_partition.py +36 -0
- hare/migrations/operations/partitions/partition_operation.py +93 -0
- hare/migrations/operations/partitions/remove_partition.py +36 -0
- hare/migrations/operations/policies/__init__.py +11 -0
- hare/migrations/operations/policies/add_policy.py +28 -0
- hare/migrations/operations/policies/alter_policy.py +30 -0
- hare/migrations/operations/policies/alter_row_level_security.py +90 -0
- hare/migrations/operations/policies/remove_policy.py +21 -0
- hare/migrations/operations/policies/rename_policy.py +21 -0
- hare/migrations/operations/schema_objects/__init__.py +11 -0
- hare/migrations/operations/schema_objects/add_schema_object.py +103 -0
- hare/migrations/operations/schema_objects/alter_schema_object.py +89 -0
- hare/migrations/operations/schema_objects/object_types/__init__.py +1 -0
- hare/migrations/operations/schema_objects/object_types/constraint_object_type.py +98 -0
- hare/migrations/operations/schema_objects/object_types/dictionary_object_type.py +51 -0
- hare/migrations/operations/schema_objects/object_types/function_object_type.py +55 -0
- hare/migrations/operations/schema_objects/object_types/grant_object_type.py +71 -0
- hare/migrations/operations/schema_objects/object_types/index_object_type.py +140 -0
- hare/migrations/operations/schema_objects/object_types/materialized_view_object_type.py +63 -0
- hare/migrations/operations/schema_objects/object_types/policy_object_type.py +53 -0
- hare/migrations/operations/schema_objects/object_types/schema_object_type.py +234 -0
- hare/migrations/operations/schema_objects/object_types/sequence_object_type.py +54 -0
- hare/migrations/operations/schema_objects/object_types/trigger_object_type.py +46 -0
- hare/migrations/operations/schema_objects/object_types/view_object_type.py +60 -0
- hare/migrations/operations/schema_objects/remove_schema_object.py +105 -0
- hare/migrations/operations/schema_objects/rename_schema_object.py +116 -0
- hare/migrations/operations/schemas/__init__.py +11 -0
- hare/migrations/operations/schemas/create_schema.py +45 -0
- hare/migrations/operations/schemas/drop_schema.py +40 -0
- hare/migrations/operations/sequences/__init__.py +10 -0
- hare/migrations/operations/sequences/add_sequence.py +28 -0
- hare/migrations/operations/sequences/alter_sequence.py +29 -0
- hare/migrations/operations/sequences/remove_sequence.py +20 -0
- hare/migrations/operations/sequences/rename_sequence.py +21 -0
- hare/migrations/operations/special/__init__.py +16 -0
- hare/migrations/operations/special/run_python.py +82 -0
- hare/migrations/operations/special/run_sql.py +107 -0
- hare/migrations/operations/special/separate_database_and_state.py +95 -0
- hare/migrations/operations/special/synchronize_key_series.py +51 -0
- hare/migrations/operations/triggers/__init__.py +15 -0
- hare/migrations/operations/triggers/add_trigger.py +28 -0
- hare/migrations/operations/triggers/alter_trigger.py +28 -0
- hare/migrations/operations/triggers/remove_trigger.py +20 -0
- hare/migrations/operations/triggers/rename_trigger.py +21 -0
- hare/migrations/operations/views/__init__.py +10 -0
- hare/migrations/operations/views/add_view.py +29 -0
- hare/migrations/operations/views/alter_view.py +29 -0
- hare/migrations/operations/views/remove_view.py +20 -0
- hare/migrations/operations/views/rename_view.py +21 -0
- hare/migrations/reports/__init__.py +12 -0
- hare/migrations/reports/operation_effect.py +28 -0
- hare/migrations/reports/operation_plan.py +23 -0
- hare/migrations/runtime_enums.py +88 -0
- hare/migrations/safety/__init__.py +16 -0
- hare/migrations/safety/enums.py +37 -0
- hare/migrations/safety/migration_risk.py +33 -0
- hare/migrations/safety/migration_safety_checker.py +250 -0
- hare/migrations/safety/migration_safety_context.py +142 -0
- hare/migrations/state/__init__.py +11 -0
- hare/migrations/state/model_state.py +359 -0
- hare/migrations/state/state.py +297 -0
- hare/migrations/state/state_apps.py +315 -0
- hare/migrations/state/state_rendering.py +222 -0
- hare/migrations/swappable_dependency.py +36 -0
- hare/migrations/writer/__init__.py +9 -0
- hare/migrations/writer/constants.py +28 -0
- hare/migrations/writer/import_manager.py +106 -0
- hare/migrations/writer/migration_writer.py +986 -0
- hare/models/__init__.py +20 -0
- hare/models/class_building/__init__.py +1 -0
- hare/models/class_building/abstract_meta_inheritance.py +116 -0
- hare/models/class_building/blind_indexes.py +54 -0
- hare/models/class_building/constants.py +61 -0
- hare/models/class_building/extension_model_options.py +20 -0
- hare/models/class_building/field_comments.py +131 -0
- hare/models/class_building/generic_foreign_keys.py +287 -0
- hare/models/class_building/instance_constructors.py +110 -0
- hare/models/class_building/lazy_relation_fields.py +140 -0
- hare/models/class_building/model_definition_checks.py +710 -0
- hare/models/class_building/model_field_collection.py +185 -0
- hare/models/class_building/model_managers.py +62 -0
- hare/models/class_building/primary_key_declaration.py +204 -0
- hare/models/class_building/schema_object_declarations.py +106 -0
- hare/models/constants.py +75 -0
- hare/models/deletion/__init__.py +0 -0
- hare/models/deletion/cascade/__init__.py +1 -0
- hare/models/deletion/cascade/cascade_deletion.py +818 -0
- hare/models/deletion/cascade/cascade_restore.py +150 -0
- hare/models/deletion/cascade/deletion_collector.py +646 -0
- hare/models/deletion/cascade/deletion_graph.py +418 -0
- hare/models/deletion/cascade/deletion_plan.py +94 -0
- hare/models/deletion/cascade/protect_constraint_deferral.py +91 -0
- hare/models/deletion/cascade/related_rows.py +417 -0
- hare/models/deletion/cascade/tenant_schema_visits.py +96 -0
- hare/models/deletion/constants.py +29 -0
- hare/models/deletion/instance_deletion.py +288 -0
- hare/models/deletion/preview/__init__.py +1 -0
- hare/models/deletion/preview/delete_preview.py +93 -0
- hare/models/deletion/preview/delete_preview_builder.py +431 -0
- hare/models/deletion/soft_deletion.py +207 -0
- hare/models/enums.py +76 -0
- hare/models/instances/__init__.py +1 -0
- hare/models/instances/dirty_fields.py +99 -0
- hare/models/instances/field_snapshot.py +116 -0
- hare/models/instances/instance_connections.py +61 -0
- hare/models/instances/instance_copies.py +46 -0
- hare/models/instances/instance_initialization.py +323 -0
- hare/models/instances/instance_refresh.py +158 -0
- hare/models/instances/instance_saving.py +512 -0
- hare/models/meta_info.py +1143 -0
- hare/models/model.py +935 -0
- hare/models/model_meta.py +255 -0
- hare/models/tenancy/__init__.py +1 -0
- hare/models/tenancy/constants.py +16 -0
- hare/models/tenancy/tenancy.py +363 -0
- hare/models/tenancy/tenant_row_level_security.py +76 -0
- hare/models/tenancy/tenant_schemas.py +232 -0
- hare/models/uniqueness/__init__.py +0 -0
- hare/models/uniqueness/declared_uniqueness.py +99 -0
- hare/models/write/__init__.py +3 -0
- hare/models/write/generated_keys.py +97 -0
- hare/models/write/insert/__init__.py +1 -0
- hare/models/write/insert/insert_conflict.py +88 -0
- hare/models/write/insert/insert_statement.py +155 -0
- hare/models/write/instance_capture.py +173 -0
- hare/models/write/instance_values.py +126 -0
- hare/models/write/instance_writer.py +949 -0
- hare/models/write/returned_values.py +98 -0
- hare/models/write/rollback_restores.py +213 -0
- hare/models/write/rules/__init__.py +2 -0
- hare/models/write/rules/constants.py +65 -0
- hare/models/write/rules/enums.py +18 -0
- hare/models/write/rules/relation_key_values.py +50 -0
- hare/models/write/rules/row_write_rules.py +635 -0
- hare/models/write/rules/tenant_write_rules.py +300 -0
- hare/models/write/rules/written_instances.py +37 -0
- hare/models/write/rules/written_target_checks.py +63 -0
- hare/models/write/update/__init__.py +1 -0
- hare/models/write/update/expression_assignment.py +162 -0
- hare/models/write/update/update_parameter_slot.py +43 -0
- hare/models/write/write_steps.py +98 -0
- hare/native/__init__.py +1 -0
- hare/native/native_modules.py +19 -0
- hare/numbers/__init__.py +1 -0
- hare/numbers/finite_numbers.py +27 -0
- hare/py.typed +0 -0
- hare/query/__init__.py +0 -0
- hare/query/constants.py +41 -0
- hare/query/enums.py +129 -0
- hare/query/expressions/__init__.py +63 -0
- hare/query/expressions/aggregate.py +442 -0
- hare/query/expressions/aggregate_paths/__init__.py +9 -0
- hare/query/expressions/aggregate_paths/aggregate_crossing.py +20 -0
- hare/query/expressions/aggregate_paths/aggregated_multi_valued_paths.py +581 -0
- hare/query/expressions/aggregate_paths/constants.py +10 -0
- hare/query/expressions/arithmetic/__init__.py +1 -0
- hare/query/expressions/arithmetic/arithmetic_operators.py +57 -0
- hare/query/expressions/arithmetic/combinable_expression.py +47 -0
- hare/query/expressions/arithmetic/combined_expression.py +614 -0
- hare/query/expressions/arithmetic/constants.py +37 -0
- hare/query/expressions/case/__init__.py +1 -0
- hare/query/expressions/case/case.py +230 -0
- hare/query/expressions/case/case_branch_value.py +14 -0
- hare/query/expressions/case/when.py +167 -0
- hare/query/expressions/compatibility/__init__.py +9 -0
- hare/query/expressions/compatibility/constants.py +107 -0
- hare/query/expressions/compatibility/output_field_compatibility.py +248 -0
- hare/query/expressions/compatibility/result_branch.py +46 -0
- hare/query/expressions/conditions/__init__.py +1 -0
- hare/query/expressions/conditions/q.py +525 -0
- hare/query/expressions/conditions/query_modifier.py +90 -0
- hare/query/expressions/constants.py +120 -0
- hare/query/expressions/declarations.py +12 -0
- hare/query/expressions/enums.py +39 -0
- hare/query/expressions/expression.py +129 -0
- hare/query/expressions/expression_context.py +63 -0
- hare/query/expressions/expression_result.py +41 -0
- hare/query/expressions/f.py +212 -0
- hare/query/expressions/frames/__init__.py +12 -0
- hare/query/expressions/frames/constants.py +14 -0
- hare/query/expressions/frames/declarations.py +22 -0
- hare/query/expressions/frames/window_frame.py +126 -0
- hare/query/expressions/function.py +490 -0
- hare/query/expressions/joins/__init__.py +1 -0
- hare/query/expressions/joins/array_join.py +147 -0
- hare/query/expressions/joins/array_join_element.py +27 -0
- hare/query/expressions/joins/asof_join.py +263 -0
- hare/query/expressions/joins/filtered_relation.py +338 -0
- hare/query/expressions/joins/json_table.py +147 -0
- hare/query/expressions/joins/json_table_column.py +21 -0
- hare/query/expressions/joins/lateral.py +88 -0
- hare/query/expressions/joins/merge_source_row.py +44 -0
- hare/query/expressions/joins/named_columns.py +43 -0
- hare/query/expressions/joins/named_join.py +204 -0
- hare/query/expressions/numeric/__init__.py +11 -0
- hare/query/expressions/numeric/numeric_type.py +18 -0
- hare/query/expressions/numeric/numeric_typing.py +216 -0
- hare/query/expressions/numeric/unrounded_decimal_field.py +16 -0
- hare/query/expressions/ordering.py +55 -0
- hare/query/expressions/raw_sql.py +168 -0
- hare/query/expressions/subqueries/__init__.py +1 -0
- hare/query/expressions/subqueries/cte_rows.py +46 -0
- hare/query/expressions/subqueries/declarations.py +8 -0
- hare/query/expressions/subqueries/exists.py +181 -0
- hare/query/expressions/subqueries/outer_reference.py +157 -0
- hare/query/expressions/subqueries/outer_scope.py +74 -0
- hare/query/expressions/subqueries/recursive_rows.py +177 -0
- hare/query/expressions/subqueries/subquery.py +236 -0
- hare/query/expressions/temporal/__init__.py +9 -0
- hare/query/expressions/temporal/constants.py +43 -0
- hare/query/expressions/temporal/temporal_arithmetic.py +254 -0
- hare/query/expressions/temporal/temporal_operand.py +25 -0
- hare/query/expressions/term_expression.py +28 -0
- hare/query/expressions/value.py +259 -0
- hare/query/expressions/value_references/__init__.py +49 -0
- hare/query/expressions/value_references/array_value_reference.py +41 -0
- hare/query/expressions/value_references/composite_key_value_reference.py +61 -0
- hare/query/expressions/value_references/cursor_value_reference.py +41 -0
- hare/query/expressions/value_references/encoded_value_reference.py +43 -0
- hare/query/expressions/value_references/expression_arguments.py +181 -0
- hare/query/expressions/value_references/like_value_reference.py +46 -0
- hare/query/expressions/value_references/list_parameter_value_reference.py +65 -0
- hare/query/expressions/value_references/list_value_reference.py +55 -0
- hare/query/expressions/value_references/literal_value_reference.py +38 -0
- hare/query/expressions/value_references/open_range_value_reference.py +53 -0
- hare/query/expressions/value_references/range_value_reference.py +49 -0
- hare/query/expressions/value_references/rebuilt_criterion_value_reference.py +93 -0
- hare/query/expressions/value_references/related_key_value_reference.py +67 -0
- hare/query/expressions/value_references/related_value_reference.py +33 -0
- hare/query/expressions/value_references/row_list_value_reference.py +67 -0
- hare/query/expressions/value_references/scalar_value_reference.py +41 -0
- hare/query/expressions/value_references/value_reference_types.py +65 -0
- hare/query/expressions/value_references/write_value_reference.py +41 -0
- hare/query/expressions/window.py +220 -0
- hare/query/filters/__init__.py +21 -0
- hare/query/filters/constants.py +89 -0
- hare/query/filters/lookups/__init__.py +1 -0
- hare/query/filters/lookups/annotation_container_lookups.py +40 -0
- hare/query/filters/lookups/constants.py +60 -0
- hare/query/filters/lookups/containers/__init__.py +3 -0
- hare/query/filters/lookups/containers/container_field_lookups.py +78 -0
- hare/query/filters/lookups/containers/container_lookups.py +80 -0
- hare/query/filters/lookups/containers/container_value_encoders.py +94 -0
- hare/query/filters/lookups/date_part_lookups.py +292 -0
- hare/query/filters/lookups/dialect_implemented_operators.py +39 -0
- hare/query/filters/lookups/field_lookup.py +59 -0
- hare/query/filters/lookups/field_lookups.py +289 -0
- hare/query/filters/lookups/field_transforms.py +98 -0
- hare/query/filters/lookups/json/__init__.py +1 -0
- hare/query/filters/lookups/json/json_filter_guards.py +412 -0
- hare/query/filters/lookups/json/json_filter_parser.py +82 -0
- hare/query/filters/lookups/json/json_lookups.py +67 -0
- hare/query/filters/lookups/json/json_path_lookups.py +184 -0
- hare/query/filters/lookups/lookups.py +371 -0
- hare/query/filters/lookups/value_encoders.py +246 -0
- hare/query/filters/resolution/__init__.py +1 -0
- hare/query/filters/resolution/annotation_filters.py +280 -0
- hare/query/filters/resolution/composite_key_filters.py +439 -0
- hare/query/filters/resolution/filter_kwargs.py +704 -0
- hare/query/filters/resolution/filter_values.py +565 -0
- hare/query/filters/resolution/json_path_filters.py +157 -0
- hare/query/filters/resolution/lookup_support.py +84 -0
- hare/query/filters/resolution/relation_filters.py +510 -0
- hare/query/filters/resolution/sensitive_filter_keys.py +91 -0
- hare/query/filters/resolution/to_many_filters.py +436 -0
- hare/query/functions/__init__.py +185 -0
- hare/query/functions/aggregates/__init__.py +9 -0
- hare/query/functions/aggregates/array_agg.py +48 -0
- hare/query/functions/aggregates/avg.py +59 -0
- hare/query/functions/aggregates/constants.py +5 -0
- hare/query/functions/aggregates/count.py +81 -0
- hare/query/functions/aggregates/declarations.py +51 -0
- hare/query/functions/aggregates/statistic_aggregate.py +67 -0
- hare/query/functions/aggregates/sum.py +55 -0
- hare/query/functions/comparison/__init__.py +9 -0
- hare/query/functions/comparison/cast.py +121 -0
- hare/query/functions/comparison/coalesce.py +140 -0
- hare/query/functions/comparison/collate.py +45 -0
- hare/query/functions/comparison/declarations.py +21 -0
- hare/query/functions/comparison/function_arguments.py +70 -0
- hare/query/functions/comparison/greatest_least_function.py +108 -0
- hare/query/functions/comparison/null_if.py +78 -0
- hare/query/functions/containers/__init__.py +7 -0
- hare/query/functions/containers/array_item.py +69 -0
- hare/query/functions/datetime/__init__.py +55 -0
- hare/query/functions/datetime/date_function_source.py +31 -0
- hare/query/functions/datetime/declarations.py +193 -0
- hare/query/functions/datetime/extract.py +97 -0
- hare/query/functions/datetime/now.py +26 -0
- hare/query/functions/datetime/trunc.py +124 -0
- hare/query/functions/json/__init__.py +6 -0
- hare/query/functions/json/json_array.py +34 -0
- hare/query/functions/json/json_object.py +161 -0
- hare/query/functions/math/__init__.py +53 -0
- hare/query/functions/math/declarations.py +192 -0
- hare/query/functions/math/enums.py +16 -0
- hare/query/functions/math/math_function.py +110 -0
- hare/query/functions/math/mod.py +52 -0
- hare/query/functions/math/pi.py +21 -0
- hare/query/functions/math/random.py +22 -0
- hare/query/functions/math/round.py +85 -0
- hare/query/functions/text/__init__.py +55 -0
- hare/query/functions/text/concat.py +99 -0
- hare/query/functions/text/declarations.py +197 -0
- hare/query/functions/text/l_pad.py +17 -0
- hare/query/functions/text/length.py +38 -0
- hare/query/functions/text/r_pad.py +17 -0
- hare/query/functions/text/replace.py +17 -0
- hare/query/functions/text/text_function.py +114 -0
- hare/query/functions/window/__init__.py +45 -0
- hare/query/functions/window/aggregate_window_function.py +43 -0
- hare/query/functions/window/avg.py +23 -0
- hare/query/functions/window/constants.py +3 -0
- hare/query/functions/window/count.py +54 -0
- hare/query/functions/window/declarations.py +153 -0
- hare/query/functions/window/distribution_window_function.py +21 -0
- hare/query/functions/window/field_window_function.py +149 -0
- hare/query/functions/window/n_tile.py +41 -0
- hare/query/functions/window/nth_value.py +54 -0
- hare/query/functions/window/offset_window_function.py +85 -0
- hare/query/functions/window/rank_like_window_function.py +21 -0
- hare/query/functions/window/statistic_window_function.py +44 -0
- hare/query/functions/window/sum.py +23 -0
- hare/query/functions/window/window_function.py +134 -0
- hare/query/generic_foreign_keys/__init__.py +3 -0
- hare/query/generic_foreign_keys/constants.py +21 -0
- hare/query/generic_foreign_keys/generic_foreign_key_filters.py +251 -0
- hare/query/generic_foreign_keys/generic_foreign_key_paths.py +183 -0
- hare/query/generic_foreign_keys/generic_foreign_key_types.py +94 -0
- hare/query/grouping/__init__.py +14 -0
- hare/query/grouping/declarations.py +21 -0
- hare/query/grouping/grouping.py +60 -0
- hare/query/grouping/grouping_set.py +67 -0
- hare/query/grouping/grouping_sets.py +55 -0
- hare/query/key_columns.py +297 -0
- hare/query/lookup_info/__init__.py +12 -0
- hare/query/lookup_info/declarations.py +27 -0
- hare/query/lookup_info/lookup_info.py +89 -0
- hare/query/lookup_info/lookup_info_builder.py +807 -0
- hare/query/lookup_info/lookup_path.py +94 -0
- hare/query/lookup_info/lookup_paths.py +415 -0
- hare/query/lookup_info/ordering_info.py +43 -0
- hare/query/lookup_info/value_paths.py +135 -0
- hare/query/managers/__init__.py +1 -0
- hare/query/managers/base_manager.py +20 -0
- hare/query/managers/manager.py +130 -0
- hare/query/plans/__init__.py +4 -0
- hare/query/plans/call_signatures/__init__.py +1 -0
- hare/query/plans/call_signatures/call_signature_plans.py +318 -0
- hare/query/plans/call_signatures/call_signature_runs.py +466 -0
- hare/query/plans/constants.py +37 -0
- hare/query/plans/description/__init__.py +11 -0
- hare/query/plans/description/declared_plan_parts.py +7 -0
- hare/query/plans/description/filter_plan_descriptions.py +229 -0
- hare/query/plans/description/hashable_values.py +22 -0
- hare/query/plans/description/plan_context.py +33 -0
- hare/query/plans/description/plan_describer_compiler.py +355 -0
- hare/query/plans/description/plan_description.py +66 -0
- hare/query/plans/description/plan_parts.py +150 -0
- hare/query/plans/description/plannable.py +69 -0
- hare/query/plans/description/term_plan_descriptions.py +92 -0
- hare/query/plans/enums.py +97 -0
- hare/query/plans/plan_origins.py +99 -0
- hare/query/plans/recording/__init__.py +1 -0
- hare/query/plans/recording/plan_recording.py +100 -0
- hare/query/plans/recording/scope_value_source.py +67 -0
- hare/query/plans/statement/__init__.py +1 -0
- hare/query/plans/statement/declared_plan_slots.py +11 -0
- hare/query/plans/statement/query_key_compiler.py +171 -0
- hare/query/plans/statement/raw_sql_plan.py +47 -0
- hare/query/plans/statement/statement_plan.py +522 -0
- hare/query/plans/statement/statement_plan_descriptions.py +451 -0
- hare/query/plans/statement/statement_plan_runs.py +306 -0
- hare/query/plans/statement/statement_plans.py +128 -0
- hare/query/query_connection.py +110 -0
- hare/query/queryset/__init__.py +19 -0
- hare/query/queryset/annotation_access_tracker.py +20 -0
- hare/query/queryset/arguments/__init__.py +1 -0
- hare/query/queryset/arguments/annotation_arguments.py +215 -0
- hare/query/queryset/arguments/collection_arguments.py +29 -0
- hare/query/queryset/arguments/filter_arguments.py +260 -0
- hare/query/queryset/arguments/ordering_arguments.py +242 -0
- hare/query/queryset/arguments/values_arguments.py +145 -0
- hare/query/queryset/combination/__init__.py +1 -0
- hare/query/queryset/combination/combination.py +58 -0
- hare/query/queryset/combination/queryset_combination.py +109 -0
- hare/query/queryset/concrete_field_paths.py +109 -0
- hare/query/queryset/constants.py +83 -0
- hare/query/queryset/date_lists.py +74 -0
- hare/query/queryset/declarations.py +7 -0
- hare/query/queryset/extensions/__init__.py +9 -0
- hare/query/queryset/extensions/query_set_extension.py +78 -0
- hare/query/queryset/extensions/query_set_extension_call.py +19 -0
- hare/query/queryset/extensions/query_set_extension_query.py +146 -0
- hare/query/queryset/extensions/query_set_extensions.py +247 -0
- hare/query/queryset/lazy_relation_names.py +33 -0
- hare/query/queryset/model_query.py +79 -0
- hare/query/queryset/objects_by_key.py +79 -0
- hare/query/queryset/options/__init__.py +1 -0
- hare/query/queryset/options/query_option.py +42 -0
- hare/query/queryset/options/query_options.py +313 -0
- hare/query/queryset/pending_calls/__init__.py +1 -0
- hare/query/queryset/pending_calls/calls_before_setup.py +185 -0
- hare/query/queryset/pending_calls/pending_filter_calls.py +144 -0
- hare/query/queryset/query_specification.py +1088 -0
- hare/query/queryset/queryset.py +2527 -0
- hare/query/queryset/relations/__init__.py +3 -0
- hare/query/queryset/relations/linked_many_to_many_relation.py +41 -0
- hare/query/queryset/relations/many_to_many/__init__.py +1 -0
- hare/query/queryset/relations/many_to_many/linked_keys.py +147 -0
- hare/query/queryset/relations/many_to_many/linked_rows_queries.py +175 -0
- hare/query/queryset/relations/many_to_many/many_to_many_members.py +173 -0
- hare/query/queryset/relations/many_to_many/many_to_many_scope_checks.py +332 -0
- hare/query/queryset/relations/many_to_many/through_defaults.py +244 -0
- hare/query/queryset/relations/many_to_many/through_row_inserting.py +516 -0
- hare/query/queryset/relations/many_to_many/through_row_unlinking.py +333 -0
- hare/query/queryset/relations/many_to_many/through_rows.py +185 -0
- hare/query/queryset/relations/many_to_many_relation.py +382 -0
- hare/query/queryset/relations/related_queryset/__init__.py +9 -0
- hare/query/queryset/relations/related_queryset/related_query_set.py +366 -0
- hare/query/queryset/relations/related_queryset/related_rows_iterator.py +42 -0
- hare/query/queryset/relations/related_queryset/relation_rows.py +73 -0
- hare/query/queryset/relations/related_queryset/unsaved_owner_condition.py +37 -0
- hare/query/queryset/relations/reverse_relation.py +474 -0
- hare/query/queryset/row_multiplication.py +151 -0
- hare/query/queryset/schema_object_calls.py +45 -0
- hare/query/queryset/selection/__init__.py +1 -0
- hare/query/queryset/selection/statement_selection.py +217 -0
- hare/query/queryset/selection/values_selection.py +65 -0
- hare/query/queryset/single_rows/__init__.py +1 -0
- hare/query/queryset/single_rows/get_exception_argument.py +7 -0
- hare/query/queryset/single_rows/get_exceptions.py +91 -0
- hare/query/queryset/single_rows/none_awaitable_type.py +21 -0
- hare/query/queryset/single_rows/query_set_single.py +49 -0
- hare/query/queryset/single_rows/single_row.py +103 -0
- hare/query/queryset/specification_copying.py +123 -0
- hare/query/queryset/table_sample.py +60 -0
- hare/query/raw_sql/__init__.py +6 -0
- hare/query/raw_sql/execute_sql.py +71 -0
- hare/query/raw_sql/sql_query_result.py +38 -0
- hare/query/relation_loading/__init__.py +14 -0
- hare/query/relation_loading/constants.py +8 -0
- hare/query/relation_loading/prefetching/__init__.py +1 -0
- hare/query/relation_loading/prefetching/declarations.py +32 -0
- hare/query/relation_loading/prefetching/direct_relation_prefetch.py +234 -0
- hare/query/relation_loading/prefetching/many_to_many_prefetch.py +496 -0
- hare/query/relation_loading/prefetching/prefetch.py +198 -0
- hare/query/relation_loading/prefetching/prefetch_checks.py +80 -0
- hare/query/relation_loading/prefetching/prefetch_related_objects.py +48 -0
- hare/query/relation_loading/prefetching/prefetch_request.py +30 -0
- hare/query/relation_loading/prefetching/prefetcher.py +200 -0
- hare/query/relation_loading/prefetching/related_rows_fetch.py +116 -0
- hare/query/relation_loading/prefetching/reverse_relation_prefetch.py +201 -0
- hare/query/relation_loading/prefetching/sliced_prefetch.py +165 -0
- hare/query/relation_loading/select.py +26 -0
- hare/query/rows/__init__.py +3 -0
- hare/query/rows/constants.py +33 -0
- hare/query/rows/enums.py +81 -0
- hare/query/rows/model_rows/__init__.py +1 -0
- hare/query/rows/model_rows/combined_model_rows.py +254 -0
- hare/query/rows/model_rows/model_columns.py +210 -0
- hare/query/rows/model_rows/model_rows.py +462 -0
- hare/query/rows/native/__init__.py +1 -0
- hare/query/rows/native/enums.py +12 -0
- hare/query/rows/native/field_codecs.py +450 -0
- hare/query/rows/native/hydrate_accelerator.py +264 -0
- hare/query/rows/native/hydration_layout.py +114 -0
- hare/query/rows/values_rows/__init__.py +1 -0
- hare/query/rows/values_rows/combined_values_rows.py +133 -0
- hare/query/rows/values_rows/dict_rows.py +92 -0
- hare/query/rows/values_rows/flat_rows.py +33 -0
- hare/query/rows/values_rows/named_rows.py +52 -0
- hare/query/rows/values_rows/tuple_rows.py +128 -0
- hare/query/rows/values_rows/value_field.py +26 -0
- hare/query/rows/values_rows/values_rows.py +175 -0
- hare/query/scopes/__init__.py +21 -0
- hare/query/scopes/constants.py +14 -0
- hare/query/scopes/manager_scope.py +51 -0
- hare/query/scopes/row_scope.py +46 -0
- hare/query/scopes/row_scopes.py +281 -0
- hare/query/scopes/row_visibility.py +89 -0
- hare/query/scopes/scope_join_conditions.py +273 -0
- hare/query/scopes/soft_delete_scope.py +17 -0
- hare/query/scopes/tenants/__init__.py +1 -0
- hare/query/scopes/tenants/all_tenants.py +11 -0
- hare/query/scopes/tenants/model_tenants.py +79 -0
- hare/query/scopes/tenants/tenant_scope.py +70 -0
- hare/query/scopes/tenants/tenant_values.py +52 -0
- hare/query/statements/__init__.py +30 -0
- hare/query/statements/awaitable_query.py +709 -0
- hare/query/statements/building/__init__.py +1 -0
- hare/query/statements/building/keyset_bounds.py +179 -0
- hare/query/statements/building/query_annotations.py +350 -0
- hare/query/statements/building/query_conditions.py +244 -0
- hare/query/statements/building/query_ctes.py +70 -0
- hare/query/statements/building/query_grouping.py +347 -0
- hare/query/statements/building/query_joins.py +282 -0
- hare/query/statements/building/query_ordering.py +275 -0
- hare/query/statements/building/row_locks.py +216 -0
- hare/query/statements/constants.py +111 -0
- hare/query/statements/select/__init__.py +4 -0
- hare/query/statements/select/combined/__init__.py +1 -0
- hare/query/statements/select/combined/combined_branches.py +380 -0
- hare/query/statements/select/combined/combined_derived_queries.py +220 -0
- hare/query/statements/select/combined/combined_plan_descriptions.py +43 -0
- hare/query/statements/select/combined_query.py +354 -0
- hare/query/statements/select/model_rows/__init__.py +1 -0
- hare/query/statements/select/model_rows/instance_hydration.py +162 -0
- hare/query/statements/select/model_rows/model_rows_plan_descriptions.py +108 -0
- hare/query/statements/select/model_rows/only_defer_fields.py +243 -0
- hare/query/statements/select/model_rows/select_related_joins.py +112 -0
- hare/query/statements/select/model_rows_query.py +416 -0
- hare/query/statements/select/raw_sql_query.py +151 -0
- hare/query/statements/select/rows_query.py +210 -0
- hare/query/statements/select/select_query.py +110 -0
- hare/query/statements/select/values/__init__.py +1 -0
- hare/query/statements/select/values/constants.py +9 -0
- hare/query/statements/select/values/values_distinct.py +41 -0
- hare/query/statements/select/values/values_grouping.py +118 -0
- hare/query/statements/select/values/values_output.py +298 -0
- hare/query/statements/select/values/values_reading.py +26 -0
- hare/query/statements/select/values/window_filter_wrapping.py +91 -0
- hare/query/statements/select/values_query.py +754 -0
- hare/query/statements/summary/__init__.py +3 -0
- hare/query/statements/summary/aggregate_query.py +732 -0
- hare/query/statements/summary/contains_query.py +66 -0
- hare/query/statements/summary/count_query.py +117 -0
- hare/query/statements/summary/exists_query.py +151 -0
- hare/query/statements/summary/rows_summary_query.py +187 -0
- hare/query/statements/write/__init__.py +3 -0
- hare/query/statements/write/bulk/__init__.py +1 -0
- hare/query/statements/write/bulk/bulk_objects.py +61 -0
- hare/query/statements/write/bulk/bulk_update_checks.py +92 -0
- hare/query/statements/write/bulk/bulk_update_query.py +1012 -0
- hare/query/statements/write/bulk/bulk_write_batches.py +368 -0
- hare/query/statements/write/bulk/create/__init__.py +1 -0
- hare/query/statements/write/bulk/create/bulk_create_query.py +936 -0
- hare/query/statements/write/bulk/create/bulk_create_reports.py +316 -0
- hare/query/statements/write/bulk/create/conflict_clause.py +137 -0
- hare/query/statements/write/bulk/create/copy_insert.py +143 -0
- hare/query/statements/write/bulk/create/default_rows_insert.py +85 -0
- hare/query/statements/write/bulk/create/inline_insert.py +93 -0
- hare/query/statements/write/bulk/create/multi_row_insert.py +277 -0
- hare/query/statements/write/bulk/create/returned_rows_matching.py +136 -0
- hare/query/statements/write/bulk/create/template_insert.py +185 -0
- hare/query/statements/write/bulk/declarations.py +61 -0
- hare/query/statements/write/create_or_update.py +193 -0
- hare/query/statements/write/declarations.py +26 -0
- hare/query/statements/write/delete_query.py +402 -0
- hare/query/statements/write/insert_from_query.py +373 -0
- hare/query/statements/write/matching_rows_query.py +268 -0
- hare/query/statements/write/merge/__init__.py +1 -0
- hare/query/statements/write/merge/merge_query.py +818 -0
- hare/query/statements/write/merge/merge_when.py +87 -0
- hare/query/statements/write/restore_query.py +105 -0
- hare/query/statements/write/returning/__init__.py +1 -0
- hare/query/statements/write/returning/delete_returning_query.py +154 -0
- hare/query/statements/write/returning/returned_rows.py +246 -0
- hare/query/statements/write/returning/update_returning_query.py +120 -0
- hare/query/statements/write/update_query.py +851 -0
- hare/search/__init__.py +29 -0
- hare/search/constants.py +22 -0
- hare/search/enums.py +26 -0
- hare/search/query/__init__.py +8 -0
- hare/search/query/combined_search_query.py +46 -0
- hare/search/query/declarations.py +9 -0
- hare/search/query/search_query.py +75 -0
- hare/search/query/search_query_combinable.py +40 -0
- hare/search/search_arguments.py +79 -0
- hare/search/search_features.py +35 -0
- hare/search/search_headline.py +186 -0
- hare/search/search_rank.py +144 -0
- hare/search/types.py +16 -0
- hare/search/vector/__init__.py +7 -0
- hare/search/vector/combined_search_vector.py +32 -0
- hare/search/vector/search_vector.py +77 -0
- hare/search/vector/search_vector_combinable.py +30 -0
- hare/sql/__init__.py +71 -0
- hare/sql/analytics/__init__.py +17 -0
- hare/sql/analytics/count.py +13 -0
- hare/sql/analytics/current_row.py +10 -0
- hare/sql/analytics/declarations.py +15 -0
- hare/sql/analytics/row_number.py +13 -0
- hare/sql/builder/__init__.py +29 -0
- hare/sql/builder/joins/__init__.py +16 -0
- hare/sql/builder/joins/join.py +71 -0
- hare/sql/builder/joins/join_on.py +73 -0
- hare/sql/builder/joins/joiner.py +38 -0
- hare/sql/builder/queries/__init__.py +17 -0
- hare/sql/builder/queries/constants.py +5 -0
- hare/sql/builder/queries/correlated_subqueries.py +583 -0
- hare/sql/builder/queries/pagination_sql.py +19 -0
- hare/sql/builder/queries/query.py +109 -0
- hare/sql/builder/queries/query_builder.py +1090 -0
- hare/sql/builder/queries/query_sql_rendering.py +407 -0
- hare/sql/builder/queries/set_operation_query.py +203 -0
- hare/sql/builder/returned_value.py +19 -0
- hare/sql/builder/tables/__init__.py +22 -0
- hare/sql/builder/tables/aliased_query.py +33 -0
- hare/sql/builder/tables/array_join_source.py +39 -0
- hare/sql/builder/tables/asof_join_source.py +29 -0
- hare/sql/builder/tables/cte.py +18 -0
- hare/sql/builder/tables/database.py +12 -0
- hare/sql/builder/tables/json_table_query.py +76 -0
- hare/sql/builder/tables/lateral_query.py +26 -0
- hare/sql/builder/tables/schema.py +42 -0
- hare/sql/builder/tables/selectable.py +83 -0
- hare/sql/builder/tables/table.py +170 -0
- hare/sql/builder_methods.py +56 -0
- hare/sql/constants.py +87 -0
- hare/sql/enums.py +211 -0
- hare/sql/exceptions.py +31 -0
- hare/sql/functions/__init__.py +81 -0
- hare/sql/functions/address_text.py +18 -0
- hare/sql/functions/cast.py +19 -0
- hare/sql/functions/cast_to.py +38 -0
- hare/sql/functions/coalesce.py +13 -0
- hare/sql/functions/count.py +14 -0
- hare/sql/functions/datetime/__init__.py +1 -0
- hare/sql/functions/datetime/date.py +16 -0
- hare/sql/functions/datetime/date_as_timestamp.py +23 -0
- hare/sql/functions/datetime/date_trunc.py +65 -0
- hare/sql/functions/datetime/datetime_as_text.py +16 -0
- hare/sql/functions/datetime/datetime_cast.py +68 -0
- hare/sql/functions/datetime/extract.py +92 -0
- hare/sql/functions/datetime/now.py +14 -0
- hare/sql/functions/datetime/temporal_difference.py +26 -0
- hare/sql/functions/datetime/temporal_shift.py +38 -0
- hare/sql/functions/datetime/timestamp_comparand.py +18 -0
- hare/sql/functions/declarations.py +19 -0
- hare/sql/functions/distinct_option_function.py +33 -0
- hare/sql/functions/greatest_least.py +25 -0
- hare/sql/functions/grouping_function.py +13 -0
- hare/sql/functions/json/__init__.py +1 -0
- hare/sql/functions/json/json_array.py +14 -0
- hare/sql/functions/json/json_object.py +14 -0
- hare/sql/functions/json/json_sort_key.py +15 -0
- hare/sql/functions/json/json_value.py +19 -0
- hare/sql/functions/numeric_cast.py +16 -0
- hare/sql/functions/random_number.py +13 -0
- hare/sql/functions/round.py +20 -0
- hare/sql/functions/statistic.py +20 -0
- hare/sql/functions/std_dev.py +13 -0
- hare/sql/functions/text/__init__.py +1 -0
- hare/sql/functions/text/collate.py +61 -0
- hare/sql/functions/text/concat.py +18 -0
- hare/sql/functions/text/concat_function.py +53 -0
- hare/sql/functions/text/decimal_text_collate.py +16 -0
- hare/sql/functions/text/lower.py +12 -0
- hare/sql/functions/text/replace.py +12 -0
- hare/sql/functions/text/upper.py +12 -0
- hare/sql/identifiers.py +61 -0
- hare/sql/sql_context.py +155 -0
- hare/sql/terms/__init__.py +90 -0
- hare/sql/terms/arithmetic_expression.py +120 -0
- hare/sql/terms/array.py +109 -0
- hare/sql/terms/bracket.py +12 -0
- hare/sql/terms/case/__init__.py +1 -0
- hare/sql/terms/case/case.py +123 -0
- hare/sql/terms/case/when_then.py +11 -0
- hare/sql/terms/constants.py +5 -0
- hare/sql/terms/containers/__init__.py +35 -0
- hare/sql/terms/containers/array_element_term.py +58 -0
- hare/sql/terms/containers/array_slice_term.py +28 -0
- hare/sql/terms/containers/constants.py +6 -0
- hare/sql/terms/containers/container_function.py +22 -0
- hare/sql/terms/containers/container_literal.py +37 -0
- hare/sql/terms/containers/declarations.py +47 -0
- hare/sql/terms/containers/map_value_term.py +30 -0
- hare/sql/terms/containers/tuple_element_term.py +21 -0
- hare/sql/terms/criteria/__init__.py +37 -0
- hare/sql/terms/criteria/basic_criterion.py +92 -0
- hare/sql/terms/criteria/between_criterion.py +39 -0
- hare/sql/terms/criteria/complex_criterion.py +47 -0
- hare/sql/terms/criteria/contains_criterion.py +81 -0
- hare/sql/terms/criteria/criterion.py +87 -0
- hare/sql/terms/criteria/empty_criterion.py +38 -0
- hare/sql/terms/criteria/is_distinct_from_criterion.py +52 -0
- hare/sql/terms/criteria/is_not_true_criterion.py +49 -0
- hare/sql/terms/criteria/json_attribute_criterion.py +62 -0
- hare/sql/terms/criteria/like.py +56 -0
- hare/sql/terms/criteria/nested_criterion.py +78 -0
- hare/sql/terms/criteria/not_criterion.py +78 -0
- hare/sql/terms/criteria/null_criterion.py +47 -0
- hare/sql/terms/criteria/range_criterion.py +28 -0
- hare/sql/terms/criteria/true_criterion.py +13 -0
- hare/sql/terms/field.py +65 -0
- hare/sql/terms/functions/__init__.py +30 -0
- hare/sql/terms/functions/aggregate_function.py +119 -0
- hare/sql/terms/functions/analytic_function.py +107 -0
- hare/sql/terms/functions/custom_function.py +39 -0
- hare/sql/terms/functions/decimal_mod.py +27 -0
- hare/sql/terms/functions/float_mod.py +24 -0
- hare/sql/terms/functions/function.py +131 -0
- hare/sql/terms/functions/interval.py +110 -0
- hare/sql/terms/functions/mod.py +22 -0
- hare/sql/terms/functions/pow.py +11 -0
- hare/sql/terms/functions/window_frame_analytic_function.py +78 -0
- hare/sql/terms/grouping/__init__.py +14 -0
- hare/sql/terms/grouping/declarations.py +17 -0
- hare/sql/terms/grouping/grouping_element.py +42 -0
- hare/sql/terms/grouping/grouping_sets_element.py +46 -0
- hare/sql/terms/index.py +15 -0
- hare/sql/terms/infix_operator.py +34 -0
- hare/sql/terms/json.py +100 -0
- hare/sql/terms/negative.py +49 -0
- hare/sql/terms/node.py +135 -0
- hare/sql/terms/parameters/__init__.py +1 -0
- hare/sql/terms/parameters/list_parameter.py +33 -0
- hare/sql/terms/parameters/parameter.py +35 -0
- hare/sql/terms/parameters/parameterized_value_wrapper.py +19 -0
- hare/sql/terms/parameters/parameterizer.py +99 -0
- hare/sql/terms/parameters/query_parameters.py +74 -0
- hare/sql/terms/parameters/recording_parameterizer.py +27 -0
- hare/sql/terms/qualified_outer_field.py +58 -0
- hare/sql/terms/select_reference.py +80 -0
- hare/sql/terms/star.py +30 -0
- hare/sql/terms/subqueries/__init__.py +1 -0
- hare/sql/terms/subqueries/exists_term.py +111 -0
- hare/sql/terms/subqueries/outer_aggregate_term.py +51 -0
- hare/sql/terms/term.py +334 -0
- hare/sql/terms/term_identity_text.py +60 -0
- hare/sql/terms/tuple.py +52 -0
- hare/sql/terms/values/__init__.py +1 -0
- hare/sql/terms/values/literal_value.py +21 -0
- hare/sql/terms/values/null_value.py +10 -0
- hare/sql/terms/values/old_row_value.py +28 -0
- hare/sql/terms/values/row_value_list.py +15 -0
- hare/sql/terms/values/value_wrapper.py +129 -0
- hare/sql/types/__init__.py +1 -0
- hare/sql/types/sql_type.py +13 -0
- hare/sql/types/sql_types.py +17 -0
- hare/stubs/__init__.py +2 -0
- hare/stubs/constants.py +18 -0
- hare/stubs/model_stub.py +415 -0
- hare/stubs/module_stub.py +150 -0
- hare/stubs/stub_imports.py +91 -0
- hare/stubs/stub_writer.py +60 -0
- hare/stubs/value_type_text.py +98 -0
- hare/time/__init__.py +12 -0
- hare/time/constants.py +27 -0
- hare/time/system_clock.py +84 -0
- hare/time/timezone.py +534 -0
- hare/time/zone_info.py +13 -0
- hare/transactions/__init__.py +25 -0
- hare/transactions/atomic/__init__.py +1 -0
- hare/transactions/atomic/atomic.py +138 -0
- hare/transactions/atomic/atomic_attempt.py +62 -0
- hare/transactions/atomic/atomic_attempts.py +73 -0
- hare/transactions/constants.py +41 -0
- hare/transactions/distributed/__init__.py +9 -0
- hare/transactions/distributed/declarations.py +32 -0
- hare/transactions/distributed/distributed_coordinator.py +784 -0
- hare/transactions/distributed/distributed_transactions.py +26 -0
- hare/transactions/distributed/stale_prepared_transaction.py +23 -0
- hare/transactions/enums.py +31 -0
- hare/transactions/transaction_options.py +86 -0
- hare/transactions/transactions.py +228 -0
- hare/typing_info/__init__.py +3 -0
- hare/typing_info/bound_models.py +73 -0
- hare/typing_info/constants.py +13 -0
- hare/typing_info/declarations.py +44 -0
- hare/typing_info/filter_value_types.py +144 -0
- hare/vectors/__init__.py +18 -0
- hare/vectors/constants.py +10 -0
- hare/vectors/declarations.py +41 -0
- hare/vectors/enums.py +14 -0
- hare/vectors/terms/__init__.py +6 -0
- hare/vectors/terms/vector_distance_term.py +22 -0
- hare/vectors/terms/vector_literal.py +18 -0
- hare/vectors/vector_distance_expression.py +107 -0
- hare/vectors/vector_field.py +147 -0
- hare/warnings.py +13 -0
- hare_orm-0.9.0.dist-info/LICENSE +27 -0
- hare_orm-0.9.0.dist-info/METADATA +321 -0
- hare_orm-0.9.0.dist-info/NOTICE.md +96 -0
- hare_orm-0.9.0.dist-info/NOTICE.ru.md +98 -0
- hare_orm-0.9.0.dist-info/RECORD +2267 -0
- hare_orm-0.9.0.dist-info/WHEEL +4 -0
- hare_orm-0.9.0.dist-info/entry_points.txt +6 -0
|
@@ -0,0 +1,1224 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import abc
|
|
4
|
+
import asyncio
|
|
5
|
+
import ssl
|
|
6
|
+
import time
|
|
7
|
+
import uuid
|
|
8
|
+
from asyncio.events import AbstractEventLoop
|
|
9
|
+
from collections.abc import AsyncGenerator, Callable, Coroutine
|
|
10
|
+
from contextlib import asynccontextmanager
|
|
11
|
+
from typing import TYPE_CHECKING, Any, ClassVar, Self, SupportsInt, TypeVar, cast
|
|
12
|
+
|
|
13
|
+
from hare.core.caching.cache import Cache
|
|
14
|
+
from hare.dialects.base.client.connect_failure_reports import ConnectFailureReports
|
|
15
|
+
from hare.dialects.base.client.connection_wrapper import ConnectionWrapper
|
|
16
|
+
from hare.dialects.base.client.database_client import DatabaseClient
|
|
17
|
+
from hare.dialects.base.client.declarations import ShellCommand
|
|
18
|
+
from hare.dialects.base.client.password_provider import PasswordProvider
|
|
19
|
+
from hare.dialects.base.client.pool.pool_connection_wrapper import PoolConnectionWrapper
|
|
20
|
+
from hare.dialects.base.literals.constants import PYTHON_LONG_INT_ERROR_START, SQL_LONG_INT_MESSAGE, SQL_NULL_BYTE
|
|
21
|
+
from hare.dialects.base.results.statement_result import StatementResult
|
|
22
|
+
from hare.dialects.postgresql.client.constants import (
|
|
23
|
+
CTE_DEFINITION_RE,
|
|
24
|
+
CTE_INTRODUCER_RE,
|
|
25
|
+
LEADING_WORD_RE,
|
|
26
|
+
PARENTHESIZED_GROUP_RE,
|
|
27
|
+
POSTGRES_AUTHORIZATION_SQLSTATE_CLASS,
|
|
28
|
+
POSTGRES_CREATE_LEGACY_PUBLIC_SCHEMA_STATEMENTS,
|
|
29
|
+
POSTGRES_CREATE_PUBLIC_SCHEMA_STATEMENTS,
|
|
30
|
+
POSTGRES_DATABASE_EXISTS_SQL,
|
|
31
|
+
POSTGRES_DATABASE_OWNER_PUBLIC_SCHEMA_VERSION_NUMBER,
|
|
32
|
+
POSTGRES_DATABASE_PREPARED_TRANSACTIONS_SQL,
|
|
33
|
+
POSTGRES_DATABASE_ROLE_SETTINGS_SQL,
|
|
34
|
+
POSTGRES_DROP_DATABASE_SQL,
|
|
35
|
+
POSTGRES_DROP_SCHEMA_CASCADE_SQL,
|
|
36
|
+
POSTGRES_FAILING_ROW_RE,
|
|
37
|
+
POSTGRES_FORCED_DROP_DATABASE_SQL,
|
|
38
|
+
POSTGRES_HIDDEN_FAILING_ROW_TEXT,
|
|
39
|
+
POSTGRES_INSUFFICIENT_RESOURCES_SQLSTATE_CLASS,
|
|
40
|
+
POSTGRES_MISSING_CONFLICT_TARGET_SQLSTATE,
|
|
41
|
+
POSTGRES_MISSING_CONFLICT_TARGET_TEXT,
|
|
42
|
+
POSTGRES_NULL_CHARACTER_SQLSTATES,
|
|
43
|
+
POSTGRES_PASSWORD_ENVIRONMENT_VARIABLE,
|
|
44
|
+
POSTGRES_POOL_CLOSED_WHILE_OPENING_MESSAGE,
|
|
45
|
+
POSTGRES_RESET_DATABASE_ROLE_SETTINGS_SQL,
|
|
46
|
+
POSTGRES_RESET_DATABASE_SETTINGS_SQL,
|
|
47
|
+
POSTGRES_ROLLBACK_PREPARED_SQL,
|
|
48
|
+
POSTGRES_SERVER_VERSION_NUMBER_MAJOR_FACTOR,
|
|
49
|
+
POSTGRES_SESSION_TIME_ZONE,
|
|
50
|
+
POSTGRES_SESSION_TIME_ZONE_SETTING,
|
|
51
|
+
POSTGRES_SHELL_APPLICATION_NAME_VARIABLE,
|
|
52
|
+
POSTGRES_SHELL_OPTIONS_VARIABLE,
|
|
53
|
+
POSTGRES_SHELL_PROGRAM,
|
|
54
|
+
POSTGRES_STATEMENT_NULL_BYTE_MESSAGE,
|
|
55
|
+
POSTGRES_TERMINATE_OTHER_DATABASE_SESSIONS_SQL,
|
|
56
|
+
POSTGRES_UNUSABLE_CHANNEL_MESSAGE,
|
|
57
|
+
POSTGRES_UNUSABLE_ROOT_CERTIFICATE_MESSAGE,
|
|
58
|
+
POSTGRES_USER_SCHEMAS_SQL,
|
|
59
|
+
POSTGRES_UTC_TIME_ZONE_NAMES,
|
|
60
|
+
POSTGRES_VALUE_NULL_BYTE_MESSAGE,
|
|
61
|
+
POSTGRESQL_CURRENT_SEARCH_PATH_SQL,
|
|
62
|
+
POSTGRESQL_MISSING_TENANT_SCHEMA_MESSAGE,
|
|
63
|
+
POSTGRESQL_POOLER_LOGIN_REFUSAL_SQLSTATE,
|
|
64
|
+
POSTGRESQL_POOLER_LOGIN_REFUSAL_TEXT,
|
|
65
|
+
POSTGRESQL_SCHEMA_EXISTS_SQL,
|
|
66
|
+
POSTGRESQL_SET_TRANSACTION_SEARCH_PATH_SQL,
|
|
67
|
+
POSTGRESQL_SINGLE_CONNECTION_POOL_SETTINGS,
|
|
68
|
+
RETURNING_CLAUSE_RE,
|
|
69
|
+
SQL_BLOCK_COMMENT_DELIMITER_RE,
|
|
70
|
+
SQL_COMMENT_OR_QUOTED_TEXT_RE,
|
|
71
|
+
SQL_QUOTED_TEXT_PLACEHOLDER,
|
|
72
|
+
WRITE_STATEMENT_KEYWORDS,
|
|
73
|
+
WRITE_STATEMENT_TYPE_CACHED_TEXT_MAX_LENGTH,
|
|
74
|
+
)
|
|
75
|
+
from hare.dialects.postgresql.client.reusable_test_schemas import ReusableTestSchemas
|
|
76
|
+
from hare.dialects.postgresql.client.transaction_pooler import TransactionPooler
|
|
77
|
+
from hare.dialects.postgresql.constants import (
|
|
78
|
+
POSTGRES_CONNECTION_OPTION_DEFAULTS,
|
|
79
|
+
POSTGRES_CONNECTION_OPTIONS,
|
|
80
|
+
POSTGRES_DEFAULT_PORT,
|
|
81
|
+
POSTGRES_PORT_OPTION,
|
|
82
|
+
POSTGRES_SERVER_VERSION_NUMBER_SQL,
|
|
83
|
+
POSTGRESQL_DEFAULT_SCHEMA,
|
|
84
|
+
POSTGRESQL_DIALECT,
|
|
85
|
+
REUSABLE_TEST_DATABASE_LEASE_CREDENTIAL,
|
|
86
|
+
)
|
|
87
|
+
from hare.dialects.postgresql.query.declarations import PostgresqlQuery
|
|
88
|
+
from hare.exceptions import (
|
|
89
|
+
ConfigurationError,
|
|
90
|
+
DatabaseError,
|
|
91
|
+
DBConnectionError,
|
|
92
|
+
OperationalError,
|
|
93
|
+
ValidationError,
|
|
94
|
+
)
|
|
95
|
+
from hare.instrumentation.observers.observers import Observers
|
|
96
|
+
from hare.instrumentation.pools.pool_registry import PoolRegistry
|
|
97
|
+
from hare.sql.builder.queries.query import Query
|
|
98
|
+
|
|
99
|
+
if TYPE_CHECKING:
|
|
100
|
+
from asyncpg.connection import Connection
|
|
101
|
+
|
|
102
|
+
from hare.contrib.test.databases.kept_test_schema import KeptTestSchema
|
|
103
|
+
|
|
104
|
+
T = TypeVar("T")
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
CoroutineFunction = Callable[..., Coroutine[None, None, T]]
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
class PostgresqlClient(DatabaseClient, abc.ABC):
|
|
111
|
+
"""What the PostgreSQL drivers share: the pool and its health, the statement options, the errors told apart
|
|
112
|
+
by SQLSTATE, and the test databases."""
|
|
113
|
+
|
|
114
|
+
rejected_sql_character: ClassVar[str | None] = SQL_NULL_BYTE
|
|
115
|
+
runs_statement_options: ClassVar[bool] = True
|
|
116
|
+
|
|
117
|
+
def raise_rejected_sql_character(self, sql: str) -> None:
|
|
118
|
+
PostgresqlClient.raise_if_statement_has_null_byte(sql)
|
|
119
|
+
|
|
120
|
+
@staticmethod
|
|
121
|
+
def translate_driver_error(
|
|
122
|
+
client: Any,
|
|
123
|
+
error: BaseException,
|
|
124
|
+
sql: str | None,
|
|
125
|
+
parameters: Any,
|
|
126
|
+
args: tuple[Any, ...],
|
|
127
|
+
is_query_executing: bool,
|
|
128
|
+
) -> BaseException:
|
|
129
|
+
translated = error
|
|
130
|
+
if isinstance(error, Exception):
|
|
131
|
+
translated = client.get_driver_error(error, args) or error
|
|
132
|
+
if (
|
|
133
|
+
isinstance(translated, DatabaseError)
|
|
134
|
+
and getattr(error, "sqlstate", None) in POSTGRES_NULL_CHARACTER_SQLSTATES
|
|
135
|
+
):
|
|
136
|
+
translated = ValidationError(POSTGRES_VALUE_NULL_BYTE_MESSAGE)
|
|
137
|
+
elif isinstance(error, ValueError) and str(error).startswith(PYTHON_LONG_INT_ERROR_START):
|
|
138
|
+
# The driver writes a bound int as text, which Python refuses past its digit limit.
|
|
139
|
+
translated = ValidationError(SQL_LONG_INT_MESSAGE)
|
|
140
|
+
if isinstance(translated, DatabaseError):
|
|
141
|
+
if translated.sql is None:
|
|
142
|
+
translated.sql = sql
|
|
143
|
+
translated.parameters = parameters
|
|
144
|
+
PostgresqlClient.hide_failing_row(translated)
|
|
145
|
+
if client.is_transaction_client:
|
|
146
|
+
if is_query_executing and isinstance(translated, asyncio.CancelledError):
|
|
147
|
+
client._mark_statement_interrupted()
|
|
148
|
+
else:
|
|
149
|
+
client._mark_statement_failed()
|
|
150
|
+
return translated
|
|
151
|
+
|
|
152
|
+
query_class: type[Query] = PostgresqlQuery
|
|
153
|
+
#: Statement text -> whether it is a write reporting a row count (_is_write_without_returning()).
|
|
154
|
+
write_statement_types: ClassVar[Cache[bool]] = Cache(
|
|
155
|
+
Cache.max_size_from_env(), holds_sql=False, keyed_by_model=False
|
|
156
|
+
)
|
|
157
|
+
native_python_types = DatabaseClient.native_python_types | {bool, uuid.UUID}
|
|
158
|
+
|
|
159
|
+
@staticmethod
|
|
160
|
+
async def run_renewing_refused_password(
|
|
161
|
+
method: CoroutineFunction[Any], client: PostgresqlClient, *args: Any, **kwargs: Any
|
|
162
|
+
) -> Any:
|
|
163
|
+
"""Runs ``method``, once more with a new password when the server refused the one a new pool
|
|
164
|
+
connection was opened with - a rotated credential; the statement never reached the server.
|
|
165
|
+
|
|
166
|
+
Args:
|
|
167
|
+
method: The client method.
|
|
168
|
+
client: The client.
|
|
169
|
+
args: The method's positional arguments.
|
|
170
|
+
kwargs: The method's keyword arguments.
|
|
171
|
+
|
|
172
|
+
Returns:
|
|
173
|
+
What the method returned.
|
|
174
|
+
"""
|
|
175
|
+
try:
|
|
176
|
+
return await method(client, *args, **kwargs)
|
|
177
|
+
except Exception as error:
|
|
178
|
+
if not client.is_authentication_failure(error):
|
|
179
|
+
raise
|
|
180
|
+
await client.renew_password()
|
|
181
|
+
return await method(client, *args, **kwargs)
|
|
182
|
+
|
|
183
|
+
@staticmethod
|
|
184
|
+
def get_statement_error(error: Exception) -> Exception:
|
|
185
|
+
"""The error of a statement the server refused - a bound text holding a null byte refused as
|
|
186
|
+
every statement refuses it, any other refusal an ``OperationalError``.
|
|
187
|
+
|
|
188
|
+
Args:
|
|
189
|
+
error: The driver's error.
|
|
190
|
+
|
|
191
|
+
Returns:
|
|
192
|
+
The error to raise.
|
|
193
|
+
"""
|
|
194
|
+
if getattr(error, "sqlstate", None) in POSTGRES_NULL_CHARACTER_SQLSTATES:
|
|
195
|
+
return ValidationError(POSTGRES_VALUE_NULL_BYTE_MESSAGE)
|
|
196
|
+
return OperationalError(error)
|
|
197
|
+
|
|
198
|
+
@staticmethod
|
|
199
|
+
def hide_failing_row(error: DatabaseError) -> None:
|
|
200
|
+
"""Writes ``<hidden>`` for the row a NOT NULL or CHECK violation names - a sensitive field's
|
|
201
|
+
value among its columns; the driver's error, holding it too, isn't chained to the error.
|
|
202
|
+
|
|
203
|
+
Args:
|
|
204
|
+
error: The error.
|
|
205
|
+
"""
|
|
206
|
+
# An argument is the driver's error itself on some drivers - its text is what is shown.
|
|
207
|
+
texts = [argument if isinstance(argument, str) else str(argument) for argument in error.args]
|
|
208
|
+
if not any(POSTGRES_FAILING_ROW_RE.search(text) for text in texts):
|
|
209
|
+
return
|
|
210
|
+
error.args = tuple(POSTGRES_FAILING_ROW_RE.sub(POSTGRES_HIDDEN_FAILING_ROW_TEXT, text) for text in texts)
|
|
211
|
+
error.hides_driver_error = True
|
|
212
|
+
|
|
213
|
+
@staticmethod
|
|
214
|
+
def raise_if_statement_has_null_byte(sql: str) -> None:
|
|
215
|
+
"""Rejects a statement text holding a null byte, which the Postgres protocol can't carry.
|
|
216
|
+
|
|
217
|
+
Args:
|
|
218
|
+
sql: The statement text.
|
|
219
|
+
|
|
220
|
+
Raises:
|
|
221
|
+
ValidationError: The text holds a null byte.
|
|
222
|
+
"""
|
|
223
|
+
if SQL_NULL_BYTE in sql:
|
|
224
|
+
raise ValidationError(POSTGRES_STATEMENT_NULL_BYTE_MESSAGE)
|
|
225
|
+
|
|
226
|
+
@staticmethod
|
|
227
|
+
def raise_if_root_certificate_unusable(path: str | None) -> None:
|
|
228
|
+
"""Rejects a root certificate file that can't be read or holds no certificate, before a
|
|
229
|
+
connection is opened.
|
|
230
|
+
|
|
231
|
+
Args:
|
|
232
|
+
path: The file, None for none given.
|
|
233
|
+
|
|
234
|
+
Raises:
|
|
235
|
+
ConfigurationError: The file can't be read or holds no certificate.
|
|
236
|
+
"""
|
|
237
|
+
if path is None:
|
|
238
|
+
return
|
|
239
|
+
try:
|
|
240
|
+
ssl.create_default_context().load_verify_locations(cafile=path)
|
|
241
|
+
except (OSError, ValueError) as error:
|
|
242
|
+
# ssl.SSLError is an OSError too - a file holding no certificate; a ValueError a path with a null byte.
|
|
243
|
+
reason = error.strerror if isinstance(error, OSError) and error.strerror else error
|
|
244
|
+
raise ConfigurationError(
|
|
245
|
+
POSTGRES_UNUSABLE_ROOT_CERTIFICATE_MESSAGE.format(path=path, reason=reason)
|
|
246
|
+
) from None
|
|
247
|
+
|
|
248
|
+
@staticmethod
|
|
249
|
+
def raise_if_channel_unusable(channel: str) -> None:
|
|
250
|
+
"""Rejects a LISTEN channel the server can't take, before a connection is opened for it.
|
|
251
|
+
|
|
252
|
+
Args:
|
|
253
|
+
channel: The channel name.
|
|
254
|
+
|
|
255
|
+
Raises:
|
|
256
|
+
ValidationError: The name is empty or holds a null byte.
|
|
257
|
+
"""
|
|
258
|
+
if not channel or SQL_NULL_BYTE in channel:
|
|
259
|
+
raise ValidationError(POSTGRES_UNUSABLE_CHANNEL_MESSAGE.format(channel=channel))
|
|
260
|
+
|
|
261
|
+
dialect = POSTGRESQL_DIALECT
|
|
262
|
+
features = POSTGRESQL_DIALECT.features.replace(supports_positional_rows=True, supports_pool_status=True)
|
|
263
|
+
connection_class: Connection | None = None
|
|
264
|
+
loop: AbstractEventLoop | None = None
|
|
265
|
+
# A transaction's client works on the connection its transaction holds - none of these apply.
|
|
266
|
+
direct_host: str | None = None
|
|
267
|
+
direct_port: int | None = None
|
|
268
|
+
_pool: Any = None
|
|
269
|
+
_connection: Any = None
|
|
270
|
+
#: The exceptions a failed connect is retried on - set per driver; none by default.
|
|
271
|
+
RETRYABLE_CONNECT_EXCEPTIONS: tuple[type[BaseException], ...] = ()
|
|
272
|
+
|
|
273
|
+
def __init__(
|
|
274
|
+
self,
|
|
275
|
+
user: str | None = None,
|
|
276
|
+
password: str | None = None,
|
|
277
|
+
database: str | None = None,
|
|
278
|
+
host: str | None = None,
|
|
279
|
+
port: SupportsInt = POSTGRES_DEFAULT_PORT,
|
|
280
|
+
**kwargs: Any,
|
|
281
|
+
) -> None:
|
|
282
|
+
super().__init__(**kwargs)
|
|
283
|
+
|
|
284
|
+
self.user = user
|
|
285
|
+
self.password = password
|
|
286
|
+
self.database = database
|
|
287
|
+
self.host = host
|
|
288
|
+
self.port = POSTGRES_PORT_OPTION.parse(port)
|
|
289
|
+
self.extra = kwargs.copy()
|
|
290
|
+
self.server_settings = self._get_server_settings_with_utc_session(self.extra.pop("server_settings", None))
|
|
291
|
+
self.extra.pop("connection_alias", None)
|
|
292
|
+
self.reusable_test_database_lease: int | None = self.extra.pop(REUSABLE_TEST_DATABASE_LEASE_CREDENTIAL, None)
|
|
293
|
+
#: The schema a leased test database kept from its previous lease - generate_schema() keeps it
|
|
294
|
+
#: when the context asks for the same one, and resets the database otherwise.
|
|
295
|
+
self.kept_test_schema: KeptTestSchema | None = None
|
|
296
|
+
#: The schema a leased test database holds as its context created it - kept, rows cleared, when
|
|
297
|
+
#: the lease ends with the schema unchanged.
|
|
298
|
+
self.leased_test_schema: KeptTestSchema | None = None
|
|
299
|
+
self.loop = self.extra.pop("loop", None)
|
|
300
|
+
self.connection_class = self.extra.pop("connection_class", self.connection_class)
|
|
301
|
+
settings = POSTGRES_CONNECTION_OPTIONS.read(self.extra, POSTGRES_CONNECTION_OPTION_DEFAULTS)
|
|
302
|
+
self.schema = settings["schema"]
|
|
303
|
+
self.application_name = settings["application_name"]
|
|
304
|
+
self.password_provider = PasswordProvider.from_settings(settings, self.password)
|
|
305
|
+
if settings["tenant_schema_template"] is not None:
|
|
306
|
+
# Local import: the tenant schemas import the models, which import the dialects.
|
|
307
|
+
from hare.models.tenancy.tenant_schemas import TenantSchemas
|
|
308
|
+
|
|
309
|
+
self.tenant_schema_template = TenantSchemas.get_checked_template(settings["tenant_schema_template"])
|
|
310
|
+
self.tenant_row_level_security: bool = settings["tenant_row_level_security"]
|
|
311
|
+
#: Whether the connection goes through a pooler in transaction pooling (PgBouncer, RDS Proxy) -
|
|
312
|
+
#: a server connection serves one transaction at a time, so what needs a session of its own
|
|
313
|
+
#: (LISTEN, a session setting) opens one on the server itself; a database it drops loses
|
|
314
|
+
#: the sessions the pooler keeps on it too.
|
|
315
|
+
self.transaction_pooling: bool = settings["transaction_pooling"]
|
|
316
|
+
#: The address of the server behind the pooler - None for no direct way to it.
|
|
317
|
+
self.direct_host: str | None = settings["direct_host"]
|
|
318
|
+
self.direct_port: int | None = settings["direct_port"]
|
|
319
|
+
if (self.direct_host is not None or self.direct_port is not None) and not self.transaction_pooling:
|
|
320
|
+
raise ConfigurationError(
|
|
321
|
+
"direct_host/direct_port name the server behind a transaction pooler - set "
|
|
322
|
+
"transaction_pooling=true for a connection going through one"
|
|
323
|
+
)
|
|
324
|
+
if self.direct_port is not None and self.direct_host is None:
|
|
325
|
+
raise ConfigurationError("direct_port needs direct_host - the server behind the pooler")
|
|
326
|
+
self.pool_minsize: int = settings["min_size"]
|
|
327
|
+
self.pool_maxsize: int = settings["max_size"]
|
|
328
|
+
if self.pool_minsize > self.pool_maxsize:
|
|
329
|
+
raise ConfigurationError(
|
|
330
|
+
f"min_size ({self.pool_minsize}) must not be greater than max_size ({self.pool_maxsize})"
|
|
331
|
+
)
|
|
332
|
+
self.connect_max_retries: int = settings["connect_max_retries"]
|
|
333
|
+
self.connect_retry_backoff_base_seconds: float = settings["connect_retry_backoff_base_seconds"]
|
|
334
|
+
self.read_retry_max_retries: int = settings["read_retry_max_retries"]
|
|
335
|
+
self.read_retry_backoff_base_seconds: float = settings["read_retry_backoff_base_seconds"]
|
|
336
|
+
if "statement_cache_size" in settings:
|
|
337
|
+
self.extra["statement_cache_size"] = settings["statement_cache_size"]
|
|
338
|
+
self.pool_acquire_timeout: float | None = settings["pool_acquire_timeout"]
|
|
339
|
+
self.command_timeout: float | None = settings["command_timeout"]
|
|
340
|
+
|
|
341
|
+
self._template: dict[str, Any] = {}
|
|
342
|
+
self._pool = None
|
|
343
|
+
self.closes_started = 0
|
|
344
|
+
self.opening_task = None
|
|
345
|
+
self._connection = None
|
|
346
|
+
self._pool_init_lock = asyncio.Lock()
|
|
347
|
+
#: The client of the server itself behind the transaction pooler
|
|
348
|
+
#: (``TransactionPooler.get_direct_client()``).
|
|
349
|
+
self._direct_client: Self | None = None
|
|
350
|
+
|
|
351
|
+
@staticmethod
|
|
352
|
+
def _get_server_settings_with_utc_session(server_settings: dict[str, Any] | None) -> dict[str, Any]:
|
|
353
|
+
"""A copy of the configured ``server_settings`` with the session ``TimeZone`` set to UTC.
|
|
354
|
+
|
|
355
|
+
Args:
|
|
356
|
+
server_settings: The configured settings, or None.
|
|
357
|
+
|
|
358
|
+
Returns:
|
|
359
|
+
The settings every connection is opened with.
|
|
360
|
+
|
|
361
|
+
Raises:
|
|
362
|
+
ConfigurationError: The settings name a ``TimeZone`` other than UTC.
|
|
363
|
+
"""
|
|
364
|
+
settings = dict(server_settings or {})
|
|
365
|
+
for key in [key for key in settings if str(key).lower() == POSTGRES_SESSION_TIME_ZONE_SETTING.lower()]:
|
|
366
|
+
configured_zone = settings.pop(key)
|
|
367
|
+
if str(configured_zone).strip().lower() not in POSTGRES_UTC_TIME_ZONE_NAMES:
|
|
368
|
+
raise ConfigurationError(
|
|
369
|
+
f"server_settings {key}={configured_zone!r} is not supported - hare runs every "
|
|
370
|
+
f"Postgres session with TimeZone={POSTGRES_SESSION_TIME_ZONE} (date/time casts, "
|
|
371
|
+
"CURRENT_DATE and db_default=Now() read the session zone). Set the zone values "
|
|
372
|
+
"are shown in with Hare.init(timezone=...) instead."
|
|
373
|
+
)
|
|
374
|
+
settings[POSTGRES_SESSION_TIME_ZONE_SETTING] = POSTGRES_SESSION_TIME_ZONE
|
|
375
|
+
return settings
|
|
376
|
+
|
|
377
|
+
async def _run_with_command_timeout(self, function: CoroutineFunction[Any], *args: Any, **kwargs: Any) -> Any:
|
|
378
|
+
"""Runs ``func(self, ...)``, cancelling it once ``command_timeout`` elapses. Enforced here:
|
|
379
|
+
asyncpg's own option waits for its cancel request to be answered, and rust_pg has none.
|
|
380
|
+
|
|
381
|
+
Raises:
|
|
382
|
+
TimeoutError: The call outlived ``command_timeout``.
|
|
383
|
+
"""
|
|
384
|
+
try:
|
|
385
|
+
async with asyncio.timeout(self.command_timeout) as timeout_scope:
|
|
386
|
+
return await function(self, *args, **kwargs)
|
|
387
|
+
except TimeoutError:
|
|
388
|
+
if not timeout_scope.expired():
|
|
389
|
+
raise
|
|
390
|
+
raise TimeoutError(f"Command timed out after {self.command_timeout}s") from None
|
|
391
|
+
|
|
392
|
+
@abc.abstractmethod
|
|
393
|
+
async def create_connection(self, with_db: bool) -> None:
|
|
394
|
+
raise NotImplementedError("create_connection is not implemented")
|
|
395
|
+
|
|
396
|
+
@abc.abstractmethod
|
|
397
|
+
async def create_pool(self, **kwargs: Any) -> Any:
|
|
398
|
+
"""Creates the driver's pool of connections.
|
|
399
|
+
|
|
400
|
+
Args:
|
|
401
|
+
kwargs: The pool's settings.
|
|
402
|
+
|
|
403
|
+
Returns:
|
|
404
|
+
The pool.
|
|
405
|
+
"""
|
|
406
|
+
raise NotImplementedError("create_pool is not implemented")
|
|
407
|
+
|
|
408
|
+
async def _create_pool_with_retry(self, **kwargs: Any) -> Any:
|
|
409
|
+
"""Creates the pool, retrying on the driver's ``RETRYABLE_CONNECT_EXCEPTIONS`` with exponential
|
|
410
|
+
backoff. Off by default (``connect_max_retries=0``).
|
|
411
|
+
"""
|
|
412
|
+
attempt = 0
|
|
413
|
+
renewed_password = False
|
|
414
|
+
while True:
|
|
415
|
+
try:
|
|
416
|
+
return await self.create_pool(**kwargs)
|
|
417
|
+
except Exception as error:
|
|
418
|
+
if (
|
|
419
|
+
self.password_provider is not None
|
|
420
|
+
and not renewed_password
|
|
421
|
+
and self.is_authentication_failure(error)
|
|
422
|
+
):
|
|
423
|
+
# A rotated credential - the provider is asked for the new one, once.
|
|
424
|
+
renewed_password = True
|
|
425
|
+
await self.renew_password()
|
|
426
|
+
if not callable(kwargs.get("password")):
|
|
427
|
+
kwargs["password"] = await self.password_provider.get()
|
|
428
|
+
continue
|
|
429
|
+
# A refused credential is the same on every attempt.
|
|
430
|
+
will_retry = (
|
|
431
|
+
(isinstance(error, self.RETRYABLE_CONNECT_EXCEPTIONS) or self.is_server_out_of_resources(error))
|
|
432
|
+
and attempt < self.connect_max_retries
|
|
433
|
+
and not self.is_authentication_failure(error)
|
|
434
|
+
)
|
|
435
|
+
ConnectFailureReports.record(self, error, attempt=attempt + 1, will_retry=will_retry)
|
|
436
|
+
if not will_retry:
|
|
437
|
+
raise
|
|
438
|
+
delay = self.connect_retry_backoff_base_seconds * (2**attempt)
|
|
439
|
+
self.log.debug(
|
|
440
|
+
"Connection attempt %d/%d failed (%s), retrying in %.2fs",
|
|
441
|
+
attempt + 1,
|
|
442
|
+
self.connect_max_retries,
|
|
443
|
+
error,
|
|
444
|
+
delay,
|
|
445
|
+
)
|
|
446
|
+
await asyncio.sleep(delay)
|
|
447
|
+
attempt += 1
|
|
448
|
+
|
|
449
|
+
async def _execute_read_query_with_retry(
|
|
450
|
+
self,
|
|
451
|
+
function: CoroutineFunction[Any],
|
|
452
|
+
*args: Any,
|
|
453
|
+
sql: str | None = None,
|
|
454
|
+
parameters: list[Any] | None = None,
|
|
455
|
+
**kwargs: Any,
|
|
456
|
+
) -> Any:
|
|
457
|
+
"""Runs a read-only query, retrying on ``DBConnectionError`` with exponential backoff - each
|
|
458
|
+
retry takes a fresh pool connection. Never retried: a write, and an ``OperationalError`` (a
|
|
459
|
+
cancelled query leaves the connection usable). Off by default
|
|
460
|
+
(``read_retry_max_retries=0``). Each attempt is reported to the observers separately,
|
|
461
|
+
without the backoff sleep.
|
|
462
|
+
"""
|
|
463
|
+
attempt = 0
|
|
464
|
+
while True:
|
|
465
|
+
attempt_start = time.perf_counter()
|
|
466
|
+
try:
|
|
467
|
+
result = await self._translate_exceptions(function, *args, **kwargs)
|
|
468
|
+
except DBConnectionError as error:
|
|
469
|
+
Observers.record_query(sql, parameters, attempt_start, error, self.connection_alias)
|
|
470
|
+
if attempt >= self.read_retry_max_retries:
|
|
471
|
+
raise
|
|
472
|
+
delay = self.read_retry_backoff_base_seconds * (2**attempt)
|
|
473
|
+
self.log.debug(
|
|
474
|
+
"Read query attempt %d/%d failed (%s), retrying in %.2fs",
|
|
475
|
+
attempt + 1,
|
|
476
|
+
self.read_retry_max_retries,
|
|
477
|
+
error,
|
|
478
|
+
delay,
|
|
479
|
+
)
|
|
480
|
+
await asyncio.sleep(delay)
|
|
481
|
+
attempt += 1
|
|
482
|
+
except Exception as error:
|
|
483
|
+
Observers.record_query(sql, parameters, attempt_start, error, self.connection_alias)
|
|
484
|
+
raise
|
|
485
|
+
else:
|
|
486
|
+
Observers.record_query(sql, parameters, attempt_start, None, self.connection_alias)
|
|
487
|
+
return result
|
|
488
|
+
|
|
489
|
+
async def _pool_acquire(self) -> Any:
|
|
490
|
+
"""Takes one raw connection from the pool - each driver overrides it with its own timeout and
|
|
491
|
+
exception translation.
|
|
492
|
+
"""
|
|
493
|
+
return await self._pool.acquire()
|
|
494
|
+
|
|
495
|
+
async def _pool_release(self, pool: Any, connection: Any) -> None:
|
|
496
|
+
"""Hands a connection back to the pool it was taken from.
|
|
497
|
+
|
|
498
|
+
Args:
|
|
499
|
+
pool: The pool.
|
|
500
|
+
connection: The connection.
|
|
501
|
+
"""
|
|
502
|
+
await pool.release(connection)
|
|
503
|
+
|
|
504
|
+
async def _post_connect(self) -> None:
|
|
505
|
+
await super()._post_connect()
|
|
506
|
+
if self.transaction_pooling and "search_path" in self.server_settings:
|
|
507
|
+
await TransactionPooler.raise_if_search_path_unreported(self)
|
|
508
|
+
await TransactionPooler.check_search_path(self, self.server_settings["search_path"])
|
|
509
|
+
if self.tenant_schema is not None:
|
|
510
|
+
await self._raise_if_tenant_schema_missing()
|
|
511
|
+
|
|
512
|
+
async def _raise_if_tenant_schema_missing(self) -> None:
|
|
513
|
+
"""Refuses the client of a tenant's schema the database doesn't hold - its pool closed, so the
|
|
514
|
+
next use, once the schema is created, checks again.
|
|
515
|
+
|
|
516
|
+
Raises:
|
|
517
|
+
ConfigurationError: The schema doesn't exist.
|
|
518
|
+
"""
|
|
519
|
+
if await self.execute_dicts(POSTGRESQL_SCHEMA_EXISTS_SQL, [self.tenant_schema]):
|
|
520
|
+
return
|
|
521
|
+
await self.close_refused_pool()
|
|
522
|
+
raise ConfigurationError(POSTGRESQL_MISSING_TENANT_SCHEMA_MESSAGE.format(schema=self.tenant_schema))
|
|
523
|
+
|
|
524
|
+
async def close_refused_pool(self) -> None:
|
|
525
|
+
"""Closes the pool just opened for a connection its setup refused - not the client: the next
|
|
526
|
+
use opens the pool and checks it again."""
|
|
527
|
+
pool, self._pool = self._pool, None
|
|
528
|
+
await self._close_pool(pool)
|
|
529
|
+
|
|
530
|
+
def get_server_client(self) -> PostgresqlClient:
|
|
531
|
+
"""The client of the server past the transaction pooler (``direct_host``) - this client for a
|
|
532
|
+
connection going straight to the server.
|
|
533
|
+
|
|
534
|
+
Raises:
|
|
535
|
+
ConfigurationError: The connection goes through a pooler and names no direct way to the
|
|
536
|
+
server.
|
|
537
|
+
"""
|
|
538
|
+
return TransactionPooler.get_direct_client(self)
|
|
539
|
+
|
|
540
|
+
def get_pool_bounds(self) -> tuple[int, int]:
|
|
541
|
+
return self.pool_minsize, self.pool_maxsize
|
|
542
|
+
|
|
543
|
+
def get_address(self) -> str:
|
|
544
|
+
return f"{self.host}:{self.port}"
|
|
545
|
+
|
|
546
|
+
async def get_shell_command(self) -> ShellCommand:
|
|
547
|
+
arguments = [POSTGRES_SHELL_PROGRAM, "--port", str(self.port)]
|
|
548
|
+
if self.host:
|
|
549
|
+
arguments += ["--host", self.host]
|
|
550
|
+
if self.user:
|
|
551
|
+
arguments += ["--username", self.user]
|
|
552
|
+
if self.database:
|
|
553
|
+
arguments += ["--dbname", self.database]
|
|
554
|
+
environment = self.get_shell_ssl_environment()
|
|
555
|
+
password = await self.password_provider.get() if self.password_provider is not None else self.password
|
|
556
|
+
if password:
|
|
557
|
+
environment[POSTGRES_PASSWORD_ENVIRONMENT_VARIABLE] = password
|
|
558
|
+
if self.application_name:
|
|
559
|
+
environment[POSTGRES_SHELL_APPLICATION_NAME_VARIABLE] = self.application_name
|
|
560
|
+
if self.schema:
|
|
561
|
+
environment[POSTGRES_SHELL_OPTIONS_VARIABLE] = f"-c search_path={self.schema}"
|
|
562
|
+
return ShellCommand(tuple(arguments), environment)
|
|
563
|
+
|
|
564
|
+
def get_shell_ssl_environment(self) -> dict[str, str]:
|
|
565
|
+
"""The libpq environment variables of the connection's TLS settings - for ``psql``.
|
|
566
|
+
|
|
567
|
+
Returns:
|
|
568
|
+
The variables, none for the driver's defaults.
|
|
569
|
+
"""
|
|
570
|
+
return {}
|
|
571
|
+
|
|
572
|
+
async def get_server_version(self) -> tuple[int, ...]:
|
|
573
|
+
server_version_number = await self._fetch_server_version_number()
|
|
574
|
+
return (
|
|
575
|
+
server_version_number // POSTGRES_SERVER_VERSION_NUMBER_MAJOR_FACTOR,
|
|
576
|
+
server_version_number % POSTGRES_SERVER_VERSION_NUMBER_MAJOR_FACTOR,
|
|
577
|
+
)
|
|
578
|
+
|
|
579
|
+
@abc.abstractmethod
|
|
580
|
+
async def _fetch_server_version_number(self) -> int:
|
|
581
|
+
"""Reads ``server_version_num`` straight off the pool, bypassing query instrumentation.
|
|
582
|
+
|
|
583
|
+
Returns:
|
|
584
|
+
The number - ``150004`` for 15.4.
|
|
585
|
+
"""
|
|
586
|
+
raise NotImplementedError("_fetch_server_version_number is not implemented")
|
|
587
|
+
|
|
588
|
+
@abc.abstractmethod
|
|
589
|
+
async def _close(self) -> None:
|
|
590
|
+
raise NotImplementedError("_close is not implemented")
|
|
591
|
+
|
|
592
|
+
@abc.abstractmethod
|
|
593
|
+
async def _close_pool(self, pool: Any) -> None:
|
|
594
|
+
"""Closes a pool the client no longer holds.
|
|
595
|
+
|
|
596
|
+
Args:
|
|
597
|
+
pool: The driver's pool.
|
|
598
|
+
"""
|
|
599
|
+
raise NotImplementedError("_close_pool is not implemented")
|
|
600
|
+
|
|
601
|
+
@abc.abstractmethod
|
|
602
|
+
def get_driver_error(self, error: Exception, call_arguments: tuple[Any, ...]) -> Exception | None:
|
|
603
|
+
"""The hare exception a driver's exception is raised as.
|
|
604
|
+
|
|
605
|
+
Args:
|
|
606
|
+
error: The exception a client method raised.
|
|
607
|
+
call_arguments: The method's positional arguments (query text, bind values).
|
|
608
|
+
|
|
609
|
+
Returns:
|
|
610
|
+
The hare exception, None for an exception raised as it is.
|
|
611
|
+
"""
|
|
612
|
+
raise NotImplementedError("get_driver_error is not implemented")
|
|
613
|
+
|
|
614
|
+
async def _translate_exceptions(self, function: CoroutineFunction[Any], *args: Any, **kwargs: Any) -> Any:
|
|
615
|
+
"""Runs ``func(self, ...)``, raising the driver's exceptions as hare's.
|
|
616
|
+
|
|
617
|
+
Args:
|
|
618
|
+
function: The method.
|
|
619
|
+
args: Its positional arguments.
|
|
620
|
+
kwargs: Its keyword arguments.
|
|
621
|
+
|
|
622
|
+
Returns:
|
|
623
|
+
What it returned.
|
|
624
|
+
"""
|
|
625
|
+
try:
|
|
626
|
+
return await function(self, *args, **kwargs)
|
|
627
|
+
except Exception as driver_error:
|
|
628
|
+
error = self.get_driver_error(driver_error, args)
|
|
629
|
+
if error is None:
|
|
630
|
+
raise
|
|
631
|
+
raise error from driver_error
|
|
632
|
+
|
|
633
|
+
async def close(self) -> None:
|
|
634
|
+
self.closes_started += 1
|
|
635
|
+
# Taken before anything is awaited: a pool opening after the close started (a query after
|
|
636
|
+
# Connections.reconnect()) has a template of its own, which it reads once open.
|
|
637
|
+
template = self._template
|
|
638
|
+
PoolRegistry.remove(self)
|
|
639
|
+
direct_client = self._direct_client
|
|
640
|
+
if direct_client is not None:
|
|
641
|
+
self._direct_client = None
|
|
642
|
+
await direct_client.close()
|
|
643
|
+
await self.close_tenant_clients()
|
|
644
|
+
await self._close()
|
|
645
|
+
# Unless a pool opened meanwhile (a query after Connections.reconnect()) took its own.
|
|
646
|
+
if self._template is template:
|
|
647
|
+
self._template.clear()
|
|
648
|
+
|
|
649
|
+
async def enter_tenant_schema(self, schema_name: str) -> str:
|
|
650
|
+
"""Runs the rest of the transaction in another tenant's schema: its search path starts with
|
|
651
|
+
that schema in place of the transaction's own tenant schema.
|
|
652
|
+
|
|
653
|
+
Args:
|
|
654
|
+
schema_name: The tenant's schema.
|
|
655
|
+
|
|
656
|
+
Returns:
|
|
657
|
+
The search path it replaced.
|
|
658
|
+
"""
|
|
659
|
+
(row,) = await self.execute_dicts(POSTGRESQL_CURRENT_SEARCH_PATH_SQL)
|
|
660
|
+
search_path = row["search_path"]
|
|
661
|
+
schemas = TransactionPooler.get_search_path_schemas(search_path)
|
|
662
|
+
if self.tenant_schema is not None and schemas[:1] == (self.tenant_schema,):
|
|
663
|
+
schemas = schemas[1:]
|
|
664
|
+
quote_identifier = self.dialect.literals.quote_identifier
|
|
665
|
+
await self.execute_dicts(
|
|
666
|
+
POSTGRESQL_SET_TRANSACTION_SEARCH_PATH_SQL,
|
|
667
|
+
[",".join(quote_identifier(schema) for schema in (schema_name, *schemas))],
|
|
668
|
+
)
|
|
669
|
+
return search_path
|
|
670
|
+
|
|
671
|
+
async def leave_tenant_schema(self, previous_schemas: str) -> None:
|
|
672
|
+
"""Brings the transaction back to the search path ``enter_tenant_schema()`` replaced.
|
|
673
|
+
|
|
674
|
+
Args:
|
|
675
|
+
previous_schemas: The search path.
|
|
676
|
+
"""
|
|
677
|
+
await self.execute_dicts(POSTGRESQL_SET_TRANSACTION_SEARCH_PATH_SQL, [previous_schemas])
|
|
678
|
+
|
|
679
|
+
def get_tenant_client_settings(self, schema_name: str) -> dict[str, Any]:
|
|
680
|
+
"""A search path of the tenant's schema, then the connection's own schema (``public``)."""
|
|
681
|
+
return {
|
|
682
|
+
"schema": f"{schema_name},{self.schema or POSTGRESQL_DEFAULT_SCHEMA}",
|
|
683
|
+
"tenant_schema_template": None,
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
def is_authentication_failure(self, error: BaseException) -> bool:
|
|
687
|
+
"""Whether a refused connection is a bad credential - the server's SQLSTATE class 28, or, past
|
|
688
|
+
a transaction pooler, the pooler's own refusal of the login.
|
|
689
|
+
|
|
690
|
+
Args:
|
|
691
|
+
error: The driver's error.
|
|
692
|
+
|
|
693
|
+
Returns:
|
|
694
|
+
True for a refused credential - retrying can't fix it.
|
|
695
|
+
"""
|
|
696
|
+
sqlstate = str(getattr(error, "sqlstate", None) or "")
|
|
697
|
+
if sqlstate.startswith(POSTGRES_AUTHORIZATION_SQLSTATE_CLASS):
|
|
698
|
+
return True
|
|
699
|
+
return (
|
|
700
|
+
self.transaction_pooling
|
|
701
|
+
and sqlstate == POSTGRESQL_POOLER_LOGIN_REFUSAL_SQLSTATE
|
|
702
|
+
and POSTGRESQL_POOLER_LOGIN_REFUSAL_TEXT in str(error)
|
|
703
|
+
)
|
|
704
|
+
|
|
705
|
+
@staticmethod
|
|
706
|
+
def is_missing_conflict_target_error(error: BaseException) -> bool:
|
|
707
|
+
"""Whether an INSERT failed because its ``ON CONFLICT`` names columns no unique index or
|
|
708
|
+
constraint of the table has (SQLSTATE 42P10).
|
|
709
|
+
|
|
710
|
+
Args:
|
|
711
|
+
error: The exception, hare's or the driver's.
|
|
712
|
+
|
|
713
|
+
Returns:
|
|
714
|
+
True for that refusal.
|
|
715
|
+
"""
|
|
716
|
+
sqlstate = getattr(error, "sqlstate", None) or getattr(error.__cause__, "sqlstate", None)
|
|
717
|
+
return sqlstate == POSTGRES_MISSING_CONFLICT_TARGET_SQLSTATE and POSTGRES_MISSING_CONFLICT_TARGET_TEXT in str(
|
|
718
|
+
error
|
|
719
|
+
)
|
|
720
|
+
|
|
721
|
+
@staticmethod
|
|
722
|
+
def is_server_out_of_resources(error: BaseException) -> bool:
|
|
723
|
+
"""Whether a refused connection is the server out of a resource - SQLSTATE class 53: too
|
|
724
|
+
many clients, no memory or disk left.
|
|
725
|
+
|
|
726
|
+
Args:
|
|
727
|
+
error: The driver's error.
|
|
728
|
+
|
|
729
|
+
Returns:
|
|
730
|
+
True for such a refusal - it passes once the server has the resource again.
|
|
731
|
+
"""
|
|
732
|
+
return str(getattr(error, "sqlstate", None) or "").startswith(POSTGRES_INSUFFICIENT_RESOURCES_SQLSTATE_CLASS)
|
|
733
|
+
|
|
734
|
+
@staticmethod
|
|
735
|
+
@abc.abstractmethod
|
|
736
|
+
def is_missing_database_error(error: BaseException) -> bool:
|
|
737
|
+
"""Whether the driver's failure to connect is the configured database missing (SQLSTATE 3D).
|
|
738
|
+
|
|
739
|
+
Args:
|
|
740
|
+
error: The driver's error.
|
|
741
|
+
|
|
742
|
+
Returns:
|
|
743
|
+
True for a missing database - retrying can't fix it.
|
|
744
|
+
"""
|
|
745
|
+
|
|
746
|
+
@staticmethod
|
|
747
|
+
def is_invalid_parameter_error(error: BaseException) -> bool:
|
|
748
|
+
"""Whether the driver refused a configured connection parameter it doesn't take.
|
|
749
|
+
|
|
750
|
+
Args:
|
|
751
|
+
error: The driver's error.
|
|
752
|
+
|
|
753
|
+
Returns:
|
|
754
|
+
True for a refused parameter; False for a driver taking every parameter it gets.
|
|
755
|
+
"""
|
|
756
|
+
return False
|
|
757
|
+
|
|
758
|
+
@asynccontextmanager
|
|
759
|
+
async def lock_timeout_session(self, seconds: float) -> AsyncGenerator[DatabaseClient]:
|
|
760
|
+
"""A client of its own on one connection with ``SET lock_timeout`` - a pooled connection
|
|
761
|
+
would lose the setting to the statement after it; past a transaction pooler, the server's
|
|
762
|
+
own. Closed when the block exits."""
|
|
763
|
+
session_client = self.create_independent_client(
|
|
764
|
+
{**POSTGRESQL_SINGLE_CONNECTION_POOL_SETTINGS, **TransactionPooler.get_direct_settings(self)}
|
|
765
|
+
)
|
|
766
|
+
try:
|
|
767
|
+
session_lock_timeout_sql = self.dialect.transactions.get_session_lock_timeout_sql(
|
|
768
|
+
max(1, round(seconds * 1000))
|
|
769
|
+
)
|
|
770
|
+
await session_client.execute(cast("str", session_lock_timeout_sql))
|
|
771
|
+
yield session_client
|
|
772
|
+
finally:
|
|
773
|
+
await session_client.close()
|
|
774
|
+
|
|
775
|
+
async def _reconnect(self, with_db: bool) -> None:
|
|
776
|
+
"""Opens a fresh pool for a database-level statement (CREATE/DROP DATABASE), closing the
|
|
777
|
+
current pool first - its sessions would keep the database from being dropped.
|
|
778
|
+
|
|
779
|
+
Args:
|
|
780
|
+
with_db: Whether to connect to the configured database - False connects to the server's
|
|
781
|
+
default one.
|
|
782
|
+
"""
|
|
783
|
+
await self.close()
|
|
784
|
+
await self.create_connection(with_db)
|
|
785
|
+
|
|
786
|
+
async def db_create(self) -> None:
|
|
787
|
+
if not self.database:
|
|
788
|
+
raise ConfigurationError("Can't create a database without a configured database name")
|
|
789
|
+
if self.reusable_test_database_lease is not None:
|
|
790
|
+
await self._prepare_reusable_test_database()
|
|
791
|
+
return
|
|
792
|
+
await self._create_database()
|
|
793
|
+
|
|
794
|
+
async def _create_database(self) -> None:
|
|
795
|
+
"""Runs CREATE DATABASE for the configured database, owned by the configured user."""
|
|
796
|
+
assert self.database is not None # nosec B101 - checked by db_create()
|
|
797
|
+
statement = f"CREATE DATABASE {self.dialect.literals.quote_identifier(self.database)}"
|
|
798
|
+
# No configured user means the driver connects as the default (PGUSER/OS) role, which then
|
|
799
|
+
# owns the new database - there is no role name to name here.
|
|
800
|
+
if self.user:
|
|
801
|
+
statement += f" OWNER {self.dialect.literals.quote_identifier(self.user)}"
|
|
802
|
+
await self._reconnect(with_db=False)
|
|
803
|
+
try:
|
|
804
|
+
await self.execute_script(statement)
|
|
805
|
+
finally:
|
|
806
|
+
await self.close()
|
|
807
|
+
|
|
808
|
+
async def db_delete(self) -> None:
|
|
809
|
+
if not self.database:
|
|
810
|
+
raise ConfigurationError("Can't drop a database without a configured database name")
|
|
811
|
+
if self.reusable_test_database_lease is not None:
|
|
812
|
+
await self._release_reusable_test_database()
|
|
813
|
+
return
|
|
814
|
+
await self._reconnect(with_db=False)
|
|
815
|
+
drop_sql = POSTGRES_FORCED_DROP_DATABASE_SQL if self.transaction_pooling else POSTGRES_DROP_DATABASE_SQL
|
|
816
|
+
try:
|
|
817
|
+
await self.execute_script(drop_sql.format(database=self.dialect.literals.quote_identifier(self.database)))
|
|
818
|
+
finally:
|
|
819
|
+
await self.close()
|
|
820
|
+
|
|
821
|
+
async def _prepare_reusable_test_database(self) -> None:
|
|
822
|
+
"""Makes a leased test database exist and be empty: reuses it as is when this process
|
|
823
|
+
already reset it, takes the schema it kept for a context creating its models' schema
|
|
824
|
+
(``generate_schema()`` decides on it), resets it when it exists from before, creates it
|
|
825
|
+
otherwise."""
|
|
826
|
+
from hare.contrib.test.databases.reusable_test_databases import ReusableTestDatabases
|
|
827
|
+
|
|
828
|
+
assert self.database is not None and self.reusable_test_database_lease is not None # nosec B101
|
|
829
|
+
self.leased_test_schema = None
|
|
830
|
+
self.kept_test_schema = ReusableTestDatabases.take_kept_schema(
|
|
831
|
+
self.database, self.reusable_test_database_lease
|
|
832
|
+
)
|
|
833
|
+
if self.kept_test_schema is None and not ReusableTestDatabases.is_clean(self.database):
|
|
834
|
+
if await self._database_exists():
|
|
835
|
+
await self._reset_database()
|
|
836
|
+
else:
|
|
837
|
+
await self._create_database()
|
|
838
|
+
ReusableTestDatabases.mark_used(self.database)
|
|
839
|
+
|
|
840
|
+
async def _release_reusable_test_database(self) -> None:
|
|
841
|
+
"""Returns a leased test database to the pool: keeps the schema its context created, the rows
|
|
842
|
+
cleared, when the schema is unchanged, and resets the database otherwise - also when that
|
|
843
|
+
fails, leaving it marked as needing a reset before its next use."""
|
|
844
|
+
from hare.contrib.test.databases.reusable_test_databases import ReusableTestDatabases
|
|
845
|
+
|
|
846
|
+
assert self.database is not None and self.reusable_test_database_lease is not None # nosec B101
|
|
847
|
+
if not ReusableTestDatabases.is_leased(self.database, self.reusable_test_database_lease):
|
|
848
|
+
return # already released - the slot may belong to another context by now
|
|
849
|
+
leased_test_schema, self.leased_test_schema = self.leased_test_schema, None
|
|
850
|
+
self.kept_test_schema = None
|
|
851
|
+
is_clean = False
|
|
852
|
+
kept_schema = None
|
|
853
|
+
try:
|
|
854
|
+
if leased_test_schema is not None:
|
|
855
|
+
kept_schema = await self._run_on_server_session(
|
|
856
|
+
lambda: self._clear_rows_on_its_session(leased_test_schema)
|
|
857
|
+
)
|
|
858
|
+
if kept_schema is None:
|
|
859
|
+
is_clean = await self._reset_database()
|
|
860
|
+
finally:
|
|
861
|
+
ReusableTestDatabases.release(
|
|
862
|
+
self.database, self.reusable_test_database_lease, is_clean=is_clean, kept_schema=kept_schema
|
|
863
|
+
)
|
|
864
|
+
|
|
865
|
+
async def generate_schema(self, safe: bool) -> None:
|
|
866
|
+
"""Creates every model of this connection in the database - on a leased test database holding
|
|
867
|
+
the same schema from its previous lease, nothing: the schema stands, its rows cleared.
|
|
868
|
+
|
|
869
|
+
Args:
|
|
870
|
+
safe: Whether each object is created only when it doesn't exist yet.
|
|
871
|
+
"""
|
|
872
|
+
from hare.contrib.test.databases.reusable_test_databases import ReusableTestDatabases
|
|
873
|
+
|
|
874
|
+
if self.reusable_test_database_lease is None:
|
|
875
|
+
await super().generate_schema(safe)
|
|
876
|
+
return
|
|
877
|
+
# Connected first, so the DDL is written for the features of the server's own version.
|
|
878
|
+
async with self.acquire_connection():
|
|
879
|
+
pass
|
|
880
|
+
schema = self.get_schema_sql(safe)
|
|
881
|
+
schema_key = ReusableTestSchemas.get_schema_key(schema)
|
|
882
|
+
kept_test_schema, self.kept_test_schema = self.kept_test_schema, None
|
|
883
|
+
if kept_test_schema is not None:
|
|
884
|
+
if kept_test_schema.schema_key == schema_key:
|
|
885
|
+
self.leased_test_schema = kept_test_schema
|
|
886
|
+
return
|
|
887
|
+
await self._reset_database()
|
|
888
|
+
self.log.debug("Creating schema: %s", schema)
|
|
889
|
+
if schema:
|
|
890
|
+
await self.execute_script(schema)
|
|
891
|
+
# Only the schema a context creates first thing is kept - a later call may follow DDL of the test.
|
|
892
|
+
if self.leased_test_schema is None and ReusableTestDatabases.may_keep_schema(
|
|
893
|
+
self.reusable_test_database_lease
|
|
894
|
+
):
|
|
895
|
+
self.leased_test_schema = await ReusableTestSchemas.get_kept_schema(self, schema_key)
|
|
896
|
+
|
|
897
|
+
async def _database_exists(self) -> bool:
|
|
898
|
+
"""Whether the configured database exists on the server.
|
|
899
|
+
|
|
900
|
+
Returns:
|
|
901
|
+
True if pg_database has it.
|
|
902
|
+
"""
|
|
903
|
+
await self._reconnect(with_db=False)
|
|
904
|
+
try:
|
|
905
|
+
rows = await self.execute_dicts(POSTGRES_DATABASE_EXISTS_SQL, [self.database])
|
|
906
|
+
finally:
|
|
907
|
+
await self.close()
|
|
908
|
+
return bool(rows)
|
|
909
|
+
|
|
910
|
+
async def _reset_database(self) -> bool:
|
|
911
|
+
"""Brings the configured database back to the state of a freshly created one without
|
|
912
|
+
dropping it: ends its other sessions, rolls back its prepared transactions, drops every
|
|
913
|
+
non-system schema (with the extensions installed in them), recreates the public schema
|
|
914
|
+
and clears database-level settings.
|
|
915
|
+
|
|
916
|
+
Returns:
|
|
917
|
+
False when the database does not exist, True once it was reset.
|
|
918
|
+
"""
|
|
919
|
+
return await self._run_on_server_session(self._reset_database_on_its_session)
|
|
920
|
+
|
|
921
|
+
async def _run_on_server_session(self, operation: Callable[[], Coroutine[Any, Any, T]]) -> T:
|
|
922
|
+
"""Runs a reset of the database on a session of the server's own past a transaction pooler: a
|
|
923
|
+
pooled session it ran on would stay in the pooler, the dropped extensions' objects cached -
|
|
924
|
+
PostGIS keeps their ids per session, and a query of a later test failed on the extension
|
|
925
|
+
created again.
|
|
926
|
+
|
|
927
|
+
Args:
|
|
928
|
+
operation: The reset, connecting and closing the client itself.
|
|
929
|
+
|
|
930
|
+
Returns:
|
|
931
|
+
What the operation returns.
|
|
932
|
+
"""
|
|
933
|
+
pooled_address = self.host, self.port
|
|
934
|
+
if self.transaction_pooling and self.direct_host is not None:
|
|
935
|
+
self.host, self.port = self.direct_host, self.direct_port or self.port
|
|
936
|
+
try:
|
|
937
|
+
return await operation()
|
|
938
|
+
finally:
|
|
939
|
+
self.host, self.port = pooled_address
|
|
940
|
+
|
|
941
|
+
async def _end_other_sessions(self) -> None:
|
|
942
|
+
"""Ends the database's other sessions and rolls back its prepared transactions."""
|
|
943
|
+
await self.execute(POSTGRES_TERMINATE_OTHER_DATABASE_SESSIONS_SQL)
|
|
944
|
+
for prepared_transaction_row in await self.execute_dicts(POSTGRES_DATABASE_PREPARED_TRANSACTIONS_SQL):
|
|
945
|
+
gid_literal = self.dialect.literals.get_string_literal_sql(prepared_transaction_row["gid"])
|
|
946
|
+
await self.execute_script(POSTGRES_ROLLBACK_PREPARED_SQL.format(gid_literal=gid_literal))
|
|
947
|
+
|
|
948
|
+
async def _get_settings_reset_statements(self) -> list[str]:
|
|
949
|
+
"""The statements clearing the database's settings and its roles' settings in it.
|
|
950
|
+
|
|
951
|
+
Returns:
|
|
952
|
+
The statements.
|
|
953
|
+
"""
|
|
954
|
+
role_setting_rows = await self.execute_dicts(POSTGRES_DATABASE_ROLE_SETTINGS_SQL)
|
|
955
|
+
quoted_database = self.dialect.literals.quote_identifier(self.database or "")
|
|
956
|
+
statements = [POSTGRES_RESET_DATABASE_SETTINGS_SQL.format(database=quoted_database)]
|
|
957
|
+
statements.extend(
|
|
958
|
+
POSTGRES_RESET_DATABASE_ROLE_SETTINGS_SQL.format(
|
|
959
|
+
role=role_setting_row["role_name"], database=quoted_database
|
|
960
|
+
)
|
|
961
|
+
for role_setting_row in role_setting_rows
|
|
962
|
+
)
|
|
963
|
+
return statements
|
|
964
|
+
|
|
965
|
+
async def _clear_rows_on_its_session(self, leased_test_schema: KeptTestSchema) -> KeptTestSchema | None:
|
|
966
|
+
"""Empties a leased test database whose schema is unchanged, keeping the schema - on the
|
|
967
|
+
session the client's address opens.
|
|
968
|
+
|
|
969
|
+
Args:
|
|
970
|
+
leased_test_schema: The schema the lease's context created.
|
|
971
|
+
|
|
972
|
+
Returns:
|
|
973
|
+
The schema kept, or None when the database has to be reset instead.
|
|
974
|
+
"""
|
|
975
|
+
try:
|
|
976
|
+
await self._reconnect(with_db=True)
|
|
977
|
+
except ConfigurationError:
|
|
978
|
+
await self.close()
|
|
979
|
+
return None
|
|
980
|
+
try:
|
|
981
|
+
await self._end_other_sessions()
|
|
982
|
+
kept_schema = await ReusableTestSchemas.clear_rows(self, leased_test_schema)
|
|
983
|
+
if kept_schema is not None:
|
|
984
|
+
await self.execute_script(";\n".join(await self._get_settings_reset_statements()))
|
|
985
|
+
return kept_schema
|
|
986
|
+
finally:
|
|
987
|
+
await self.close()
|
|
988
|
+
|
|
989
|
+
async def _reset_database_on_its_session(self) -> bool:
|
|
990
|
+
"""``_reset_database()`` on the session the client's address opens.
|
|
991
|
+
|
|
992
|
+
Returns:
|
|
993
|
+
False when the database does not exist, True once it was reset.
|
|
994
|
+
"""
|
|
995
|
+
try:
|
|
996
|
+
await self._reconnect(with_db=True)
|
|
997
|
+
except ConfigurationError:
|
|
998
|
+
await self.close()
|
|
999
|
+
if not await self._database_exists():
|
|
1000
|
+
return False
|
|
1001
|
+
raise
|
|
1002
|
+
|
|
1003
|
+
try:
|
|
1004
|
+
await self._end_other_sessions()
|
|
1005
|
+
schema_rows = await self.execute_dicts(POSTGRES_USER_SCHEMAS_SQL)
|
|
1006
|
+
version_rows = await self.execute_dicts(POSTGRES_SERVER_VERSION_NUMBER_SQL)
|
|
1007
|
+
statements = [
|
|
1008
|
+
POSTGRES_DROP_SCHEMA_CASCADE_SQL.format(
|
|
1009
|
+
schema=self.dialect.literals.quote_identifier(schema_row["nspname"])
|
|
1010
|
+
)
|
|
1011
|
+
for schema_row in schema_rows
|
|
1012
|
+
]
|
|
1013
|
+
if version_rows[0]["server_version_number"] >= POSTGRES_DATABASE_OWNER_PUBLIC_SCHEMA_VERSION_NUMBER:
|
|
1014
|
+
statements.extend(POSTGRES_CREATE_PUBLIC_SCHEMA_STATEMENTS)
|
|
1015
|
+
else:
|
|
1016
|
+
statements.extend(POSTGRES_CREATE_LEGACY_PUBLIC_SCHEMA_STATEMENTS)
|
|
1017
|
+
statements.extend(await self._get_settings_reset_statements())
|
|
1018
|
+
await self.execute_script(";\n".join(statements))
|
|
1019
|
+
finally:
|
|
1020
|
+
await self.close()
|
|
1021
|
+
return True
|
|
1022
|
+
|
|
1023
|
+
def acquire_connection(self) -> ConnectionWrapper[Any] | PoolConnectionWrapper[Any]:
|
|
1024
|
+
return PoolConnectionWrapper(self)
|
|
1025
|
+
|
|
1026
|
+
@staticmethod
|
|
1027
|
+
def _strip_comments_and_quoted_text(query: str) -> str:
|
|
1028
|
+
"""Blanks out comments (nested block comments included) and replaces every string
|
|
1029
|
+
literal, quoted identifier and dollar-quoted string with a placeholder word.
|
|
1030
|
+
|
|
1031
|
+
Args:
|
|
1032
|
+
query: The SQL text to inspect.
|
|
1033
|
+
|
|
1034
|
+
Returns:
|
|
1035
|
+
The query text with only unquoted SQL left readable.
|
|
1036
|
+
"""
|
|
1037
|
+
parts: list[str] = []
|
|
1038
|
+
position = 0
|
|
1039
|
+
while (token_match := SQL_COMMENT_OR_QUOTED_TEXT_RE.search(query, position)) is not None:
|
|
1040
|
+
parts.append(query[position : token_match.start()])
|
|
1041
|
+
token = token_match.group()
|
|
1042
|
+
if token == "/*": # nosec B105 - a comment marker, not a password
|
|
1043
|
+
depth = 1
|
|
1044
|
+
position = len(query)
|
|
1045
|
+
for delimiter_match in SQL_BLOCK_COMMENT_DELIMITER_RE.finditer(query, token_match.end()):
|
|
1046
|
+
depth += 1 if delimiter_match.group() == "/*" else -1
|
|
1047
|
+
if depth == 0:
|
|
1048
|
+
position = delimiter_match.end()
|
|
1049
|
+
break
|
|
1050
|
+
parts.append(" ")
|
|
1051
|
+
elif token.startswith("--"):
|
|
1052
|
+
parts.append(" ")
|
|
1053
|
+
position = token_match.end()
|
|
1054
|
+
else:
|
|
1055
|
+
parts.append(SQL_QUOTED_TEXT_PLACEHOLDER)
|
|
1056
|
+
position = token_match.end()
|
|
1057
|
+
parts.append(query[position:])
|
|
1058
|
+
return "".join(parts)
|
|
1059
|
+
|
|
1060
|
+
@staticmethod
|
|
1061
|
+
def _get_main_statement_text(query: str) -> str:
|
|
1062
|
+
"""The query's main statement with comments and quoted text blanked out, every
|
|
1063
|
+
parenthesized group removed and any leading ``WITH`` CTE list skipped.
|
|
1064
|
+
|
|
1065
|
+
Args:
|
|
1066
|
+
query: The SQL text to inspect.
|
|
1067
|
+
|
|
1068
|
+
Returns:
|
|
1069
|
+
The main statement's remaining top-level text.
|
|
1070
|
+
"""
|
|
1071
|
+
remaining = PostgresqlClient._strip_comments_and_quoted_text(query)
|
|
1072
|
+
while True:
|
|
1073
|
+
reduced = PARENTHESIZED_GROUP_RE.sub(" ", remaining)
|
|
1074
|
+
if reduced == remaining:
|
|
1075
|
+
break
|
|
1076
|
+
remaining = reduced
|
|
1077
|
+
cte_introducer_match = CTE_INTRODUCER_RE.match(remaining)
|
|
1078
|
+
if cte_introducer_match is None:
|
|
1079
|
+
return remaining
|
|
1080
|
+
remaining = remaining[cte_introducer_match.end() :]
|
|
1081
|
+
while (cte_definition_match := CTE_DEFINITION_RE.match(remaining)) is not None:
|
|
1082
|
+
remaining = remaining[cte_definition_match.end() :]
|
|
1083
|
+
return remaining
|
|
1084
|
+
|
|
1085
|
+
@staticmethod
|
|
1086
|
+
def _is_write_without_returning(query: str) -> bool:
|
|
1087
|
+
"""Whether `query` is an UPDATE/DELETE/INSERT/MERGE with no top-level RETURNING clause -
|
|
1088
|
+
one that reports an affected-row count instead of result rows. Comments, quoted text,
|
|
1089
|
+
CTEs (``[NOT] MATERIALIZED`` included) and a RETURNING inside a CTE are all accounted for.
|
|
1090
|
+
Worked out once per statement text - a write of one row sends the same text every time.
|
|
1091
|
+
|
|
1092
|
+
Args:
|
|
1093
|
+
query: The SQL text to inspect.
|
|
1094
|
+
|
|
1095
|
+
Returns:
|
|
1096
|
+
True if the caller should read an affected-row count rather than fetch result rows.
|
|
1097
|
+
"""
|
|
1098
|
+
if len(query) > WRITE_STATEMENT_TYPE_CACHED_TEXT_MAX_LENGTH:
|
|
1099
|
+
return PostgresqlClient._reads_write_without_returning(query)
|
|
1100
|
+
key = (query,)
|
|
1101
|
+
is_write_without_returning = PostgresqlClient.write_statement_types.get(key)
|
|
1102
|
+
if is_write_without_returning is None:
|
|
1103
|
+
is_write_without_returning = PostgresqlClient._reads_write_without_returning(query)
|
|
1104
|
+
PostgresqlClient.write_statement_types[key] = is_write_without_returning
|
|
1105
|
+
return is_write_without_returning
|
|
1106
|
+
|
|
1107
|
+
@staticmethod
|
|
1108
|
+
def _reads_write_without_returning(query: str) -> bool:
|
|
1109
|
+
"""``_is_write_without_returning()`` read off the statement text itself.
|
|
1110
|
+
|
|
1111
|
+
Args:
|
|
1112
|
+
query: The SQL text to inspect.
|
|
1113
|
+
|
|
1114
|
+
Returns:
|
|
1115
|
+
True if the caller should read an affected-row count rather than fetch result rows.
|
|
1116
|
+
"""
|
|
1117
|
+
leading_word_match = LEADING_WORD_RE.match(query)
|
|
1118
|
+
leading_word = leading_word_match.group(1).upper() if leading_word_match else ""
|
|
1119
|
+
if leading_word in WRITE_STATEMENT_KEYWORDS:
|
|
1120
|
+
if RETURNING_CLAUSE_RE.search(query) is None:
|
|
1121
|
+
return True
|
|
1122
|
+
elif leading_word_match is not None and leading_word != "WITH":
|
|
1123
|
+
return False
|
|
1124
|
+
main_statement = PostgresqlClient._get_main_statement_text(query)
|
|
1125
|
+
main_keyword_match = LEADING_WORD_RE.match(main_statement)
|
|
1126
|
+
if main_keyword_match is None or main_keyword_match.group(1).upper() not in WRITE_STATEMENT_KEYWORDS:
|
|
1127
|
+
return False
|
|
1128
|
+
return RETURNING_CLAUSE_RE.search(main_statement) is None
|
|
1129
|
+
|
|
1130
|
+
async def _ensure_connection(self) -> None:
|
|
1131
|
+
"""Creates the pool on first use - once, whichever task gets there first.
|
|
1132
|
+
|
|
1133
|
+
Raises:
|
|
1134
|
+
DBConnectionError: The connection was closed and dropped, or - for a setup statement of the
|
|
1135
|
+
pool being opened - closed meanwhile.
|
|
1136
|
+
"""
|
|
1137
|
+
opening_task = self.opening_task
|
|
1138
|
+
if self._pool and opening_task is not None and opening_task is not asyncio.current_task():
|
|
1139
|
+
# Another task's pool is open but still being set up - the server's version and features,
|
|
1140
|
+
# the checks of the connection: a statement runs once that is done.
|
|
1141
|
+
async with self._pool_init_lock:
|
|
1142
|
+
pass
|
|
1143
|
+
if not self._pool:
|
|
1144
|
+
if self.opening_task is not None and self.opening_task is asyncio.current_task():
|
|
1145
|
+
# A setup statement of the pool being opened, closed meanwhile - the opening task holds
|
|
1146
|
+
# the lock opening it would wait on, and opens it anew.
|
|
1147
|
+
raise DBConnectionError(POSTGRES_POOL_CLOSED_WHILE_OPENING_MESSAGE)
|
|
1148
|
+
async with self._pool_init_lock:
|
|
1149
|
+
if not self._pool:
|
|
1150
|
+
# A pool that opened across a close (Connections.reconnect()) was closed again -
|
|
1151
|
+
# the query runs on a new one.
|
|
1152
|
+
while not self._pool and not self.discarded:
|
|
1153
|
+
await self.open_across_closes()
|
|
1154
|
+
if self.discarded:
|
|
1155
|
+
# Dropped while its pool opened - closed again, never left open.
|
|
1156
|
+
await self._close()
|
|
1157
|
+
raise DBConnectionError(
|
|
1158
|
+
f"The connection {self.connection_alias!r} was closed and dropped - a query runs on "
|
|
1159
|
+
"the connection the context gives now"
|
|
1160
|
+
)
|
|
1161
|
+
|
|
1162
|
+
async def acquire_from_open_pool(self) -> tuple[Any, Any]:
|
|
1163
|
+
"""Checks out one connection of the pool, opening it first - of the new pool when the one it
|
|
1164
|
+
waited on was closed meanwhile (``Connections.reconnect()``): a query that had no connection
|
|
1165
|
+
yet runs on the new pool.
|
|
1166
|
+
|
|
1167
|
+
Returns:
|
|
1168
|
+
The pool and the connection.
|
|
1169
|
+
"""
|
|
1170
|
+
while True:
|
|
1171
|
+
if self.discarded and (successor := self.get_successor()) is not None:
|
|
1172
|
+
# Discarded by a repeated Hare.init() - the client replacing it gives the connection.
|
|
1173
|
+
return await successor.acquire_from_open_pool()
|
|
1174
|
+
try:
|
|
1175
|
+
await self._ensure_connection()
|
|
1176
|
+
except DBConnectionError:
|
|
1177
|
+
if self.get_successor() is None:
|
|
1178
|
+
raise
|
|
1179
|
+
continue
|
|
1180
|
+
pool = self._pool
|
|
1181
|
+
if pool is None:
|
|
1182
|
+
continue
|
|
1183
|
+
try:
|
|
1184
|
+
connection = await self._pool_acquire()
|
|
1185
|
+
except Exception:
|
|
1186
|
+
if self.get_successor() is not None:
|
|
1187
|
+
continue
|
|
1188
|
+
if self._pool is pool or self.discarded:
|
|
1189
|
+
raise
|
|
1190
|
+
continue
|
|
1191
|
+
if self._pool is not pool:
|
|
1192
|
+
# The pool was closed while this waited for it - a connection it hands out once its close
|
|
1193
|
+
# began is closed under the query; given back, and the new pool gives one.
|
|
1194
|
+
await self._pool_release(pool, connection)
|
|
1195
|
+
continue
|
|
1196
|
+
return pool, connection
|
|
1197
|
+
|
|
1198
|
+
@abc.abstractmethod
|
|
1199
|
+
async def execute_many(self, query: str, values: list[Any]) -> None:
|
|
1200
|
+
raise NotImplementedError("execute_many is not implemented")
|
|
1201
|
+
|
|
1202
|
+
@abc.abstractmethod
|
|
1203
|
+
async def execute(
|
|
1204
|
+
self,
|
|
1205
|
+
query: str,
|
|
1206
|
+
values: list[Any] | None = None,
|
|
1207
|
+
*,
|
|
1208
|
+
returns_rows: bool | None = None,
|
|
1209
|
+
rows_by_position: bool = False,
|
|
1210
|
+
) -> StatementResult:
|
|
1211
|
+
raise NotImplementedError("execute is not implemented")
|
|
1212
|
+
|
|
1213
|
+
async def notify(self, channel: str, payload: str = "") -> None:
|
|
1214
|
+
"""Sends a Postgres ``NOTIFY`` on ``channel`` via parameterized ``SELECT pg_notify($1, $2)``.
|
|
1215
|
+
|
|
1216
|
+
On a transaction client (inside ``Transactions.atomic()``) the notification is
|
|
1217
|
+
queued by Postgres and delivered only if and when that transaction commits - never on
|
|
1218
|
+
rollback. Outside a transaction it is delivered immediately.
|
|
1219
|
+
|
|
1220
|
+
Args:
|
|
1221
|
+
channel: Channel name (any string - no identifier quoting needed).
|
|
1222
|
+
payload: Notification payload, delivered to listeners as-is.
|
|
1223
|
+
"""
|
|
1224
|
+
await self.execute("SELECT pg_notify($1, $2)", [channel, payload])
|