velocity-python 0.1.123__tar.gz → 0.1.125__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {velocity_python-0.1.123 → velocity_python-0.1.125}/PKG-INFO +1 -1
- {velocity_python-0.1.123 → velocity_python-0.1.125}/pyproject.toml +1 -1
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/__init__.py +1 -1
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/facets.py +26 -1
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/handlers/mixins/data_service.py +38 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/core/table.py +30 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/servers/postgres/sql.py +22 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity_python.egg-info/PKG-INFO +1 -1
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity_python.egg-info/SOURCES.txt +2 -1
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_facets.py +32 -1
- velocity_python-0.1.125/tests/test_write_hook_empty_strings.py +146 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/LICENSE +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/README.md +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/setup.cfg +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/__init__.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/amplify.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/amplify_build.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/assets/__init__.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/assets/backfill.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/assets/indexing.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/assets/references.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/assets/service.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/assets/usage_index.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/blobs.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/capabilities/__init__.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/capabilities/base.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/capabilities/dispatch.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/capabilities/infra.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/capabilities/jobs.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/capabilities/provisioning.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/capabilities/retention.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/capabilities/security.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/capabilities/single_session.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/deploy/__init__.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/deploy/config.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/deploy/operations.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/deploy/policies.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/deploy/reconcile.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/deploy/targets.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/dirty_pipeline.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/email.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/feature_flags.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/handlers/__init__.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/handlers/base_handler.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/handlers/context.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/handlers/context_factory.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/handlers/exceptions.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/handlers/lambda_handler.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/handlers/masquerade.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/handlers/mixins/__init__.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/handlers/mixins/job_handler.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/handlers/mixins/session_control.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/handlers/mixins/web_handler.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/handlers/perf.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/handlers/response.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/handlers/sqs_handler.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/job_lifecycle.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/job_results.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/mirror.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/ops.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/s3.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/sms.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/ssm_config.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/tests/__init__.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/tests/test_amplify_build_policy_size.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/tests/test_amplify_build_shim.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/tests/test_base_handler_error_response.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/tests/test_deploy_policies.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/tests/test_deploy_reconcile.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/tests/test_email.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/tests/test_lambda_handler_json_serialization.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/tests/test_response.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/tests/test_sms.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/cache.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/__init__.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/core/__init__.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/core/async_support.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/core/column.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/core/database.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/core/decorators.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/core/engine.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/core/jsonproxy.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/core/lazy_engine.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/core/result.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/core/row.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/core/sequence.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/core/transaction.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/core/view.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/exceptions.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/maintenance.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/migrations.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/servers/__init__.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/servers/base/__init__.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/servers/base/initializer.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/servers/base/operators.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/servers/base/sql.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/servers/base/types.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/servers/mysql/__init__.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/servers/mysql/operators.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/servers/mysql/reserved.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/servers/mysql/sql.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/servers/mysql/types.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/servers/postgres/__init__.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/servers/postgres/operators.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/servers/postgres/reserved.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/servers/postgres/types.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/servers/sqlite/__init__.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/servers/sqlite/operators.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/servers/sqlite/reserved.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/servers/sqlite/sql.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/servers/sqlite/types.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/servers/sqlserver/__init__.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/servers/sqlserver/operators.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/servers/sqlserver/reserved.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/servers/sqlserver/sql.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/servers/sqlserver/types.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/servers/tablehelper.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/tests/__init__.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/tests/common_db_test.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/tests/postgres/__init__.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/tests/postgres/common.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/tests/postgres/conftest.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/tests/postgres/test_column.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/tests/postgres/test_connections.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/tests/postgres/test_database.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/tests/postgres/test_engine.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/tests/postgres/test_general_usage.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/tests/postgres/test_imports.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/tests/postgres/test_result.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/tests/postgres/test_row.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/tests/postgres/test_row_comprehensive.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/tests/postgres/test_schema_locking.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/tests/postgres/test_schema_locking_unit.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/tests/postgres/test_sequence.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/tests/postgres/test_sql_comprehensive.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/tests/postgres/test_table.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/tests/postgres/test_table_comprehensive.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/tests/postgres/test_transaction.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/tests/sql/__init__.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/tests/sql/common.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/tests/sql/test_postgres_select_advanced.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/tests/sql/test_postgres_select_variances.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/tests/test_cursor_rowcount_fix.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/tests/test_db_utils.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/tests/test_postgres.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/tests/test_postgres_unchanged.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/tests/test_process_error_robustness.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/tests/test_result_caching.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/tests/test_result_sql_aware.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/tests/test_row_get_missing_column.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/tests/test_schema_locking_initializers.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/tests/test_schema_locking_simple.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/tests/test_sql_builder.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/tests/test_tablehelper.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/tests/test_view_helper.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/utils.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/logging.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/misc/__init__.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/misc/conv/__init__.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/misc/conv/iconv.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/misc/conv/oconv.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/misc/db.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/misc/export.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/misc/format.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/misc/mail.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/misc/merge.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/misc/pdf.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/misc/tests/__init__.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/misc/tests/test_db.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/misc/tests/test_fix.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/misc/tests/test_format.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/misc/tests/test_iconv.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/misc/tests/test_mail_send.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/misc/tests/test_merge.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/misc/tests/test_oconv.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/misc/tests/test_original_error.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/misc/tests/test_timer.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/misc/timer.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/misc/tools.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/nosql/__init__.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/nosql/core/__init__.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/nosql/core/capabilities.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/nosql/core/store.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/nosql/core/where.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/nosql/exceptions.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/nosql/servers/__init__.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/nosql/servers/base/__init__.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/nosql/servers/cassandra/__init__.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/nosql/servers/cassandra/translation.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/nosql/servers/couchbase/__init__.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/nosql/servers/couchbase/translation.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/nosql/servers/dynamodb/__init__.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/nosql/servers/dynamodb/translation.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/nosql/servers/elasticsearch/__init__.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/nosql/servers/elasticsearch/translation.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/nosql/servers/memory/__init__.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/nosql/servers/mongodb/__init__.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/nosql/servers/mongodb/translation.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/nosql/servers/redis/__init__.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/payment/__init__.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/payment/authorizenet_adapter.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/payment/authorizenet_mirror.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/payment/base_adapter.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/payment/braintree_adapter.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/payment/braintree_mirror.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/payment/charge_rules.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/payment/stripe_adapter.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/payment/stripe_mirror.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity_python.egg-info/dependency_links.txt +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity_python.egg-info/entry_points.txt +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity_python.egg-info/requires.txt +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity_python.egg-info/top_level.txt +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_access_error_403.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_activity_tracking_aborted_tx.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_amplify_build.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_asset_indexing.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_asset_references.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_assets_service.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_async_support.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_batch_operations.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_blob_store.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_capabilities.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_capability_catalog.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_cognito_user_cache.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_column_tx_arg.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_concurrency_safety.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_connection_pool.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_connection_resilience.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_context_flags_loader.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_context_job_descriptions.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_data_service_query_cap.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_data_service_renumber.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_data_service_save_as.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_db_credentials_ssm_cascade.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_db_maintenance.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_decorators.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_delete_hook_fk_blocked.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_dirty_pipeline_fast_path.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_email_processing.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_enqueue_metric_namespace.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_enqueue_send_failures.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_feature_flags.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_get_cognito_user_provider.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_http_handler_rollback.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_iconv_money_to_cents.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_identifier_injection_guard.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_job_handler.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_job_lifecycle.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_job_results.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_json_columns.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_jsonb_dict_adapter.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_lambda_handler.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_lambda_handler_auth.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_lambda_handler_masquerade.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_lambda_handler_user_cache.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_lazy_engine.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_masquerade_grant.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_mirror.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_mixins_import.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_n_plus_one.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_nosql_dynamodb.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_nosql_memory.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_nosql_mongodb.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_nosql_redis.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_nosql_translation.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_nosql_where.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_observability.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_on_commit.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_ops.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_payment_authorizenet_adapter.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_payment_braintree_adapter.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_payment_braintree_mirror.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_payment_mirror_empty_table.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_payment_profile_sorting.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_payment_stripe_adapter.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_pdf.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_prepared_statements.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_psycopg3_upgrade.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_query_cache.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_query_missing_table_unlocked.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_read_cache.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_response.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_restricted_direct_tables.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_result_returning.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_retry_side_effect_guard.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_return_default_safety.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_row_batch_update.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_row_cache_staleness.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_s3_bucket_config.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_schema_migrations.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_security_capability.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_security_hardening.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_server_cursor.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_session_control.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_single_autocommit_safety.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_single_session_capability.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_spreadsheet_functions.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_sqlite_backend.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_sqs_per_record_transactions.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_ssm_config.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_store_user_data.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_sys_modified_count_postgres_demo.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_table_alter.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_table_find_cache.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_table_purge.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_transaction_class_wrapping.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_transaction_commit_and_ownership.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_transaction_edge_cases.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_where_clause_validation.py +0 -0
- {velocity_python-0.1.123 → velocity_python-0.1.125}/tests/test_write_hook_create_flow.py +0 -0
|
@@ -34,6 +34,9 @@ Facets AND together; the values of one facet OR together. Kinds:
|
|
|
34
34
|
``since`` a period ending now: ``today``, ``Nd`` (``7d``, ``30d`` …, up to
|
|
35
35
|
3660 days), ``year`` (this calendar year). Evaluated in the
|
|
36
36
|
database's session time zone.
|
|
37
|
+
``before`` strictly before a day (``YYYY-MM-DD``) or older than a period
|
|
38
|
+
(``Nd``): ``{"field": "sys_created", "kind": "before", "value":
|
|
39
|
+
"2026-09-01"}``. With ``since`` it brackets a range.
|
|
37
40
|
``text`` a write-in, case-insensitive, against ``field::text``:
|
|
38
41
|
``match`` is ``contains`` (default), ``equals``, ``starts`` or
|
|
39
42
|
``words`` — every whitespace-separated word of the term must
|
|
@@ -72,7 +75,7 @@ from velocity.db.servers.tablehelper import TableHelper
|
|
|
72
75
|
|
|
73
76
|
PARAM_KEY = "facets"
|
|
74
77
|
|
|
75
|
-
KINDS = ("values", "contains", "presence", "since", "text", "domain")
|
|
78
|
+
KINDS = ("values", "contains", "presence", "since", "before", "text", "domain")
|
|
76
79
|
MATCHES = ("contains", "equals", "starts", "words")
|
|
77
80
|
PRESENCE = ("present", "absent")
|
|
78
81
|
|
|
@@ -199,6 +202,27 @@ def _kind_since(column: str, entry: Dict[str, Any], field: str) -> Optional[Pred
|
|
|
199
202
|
return f"{column} >= now() - make_interval(days => %s)", (days,)
|
|
200
203
|
|
|
201
204
|
|
|
205
|
+
_ISO_DATE = re.compile(r"^\d{4}-\d{2}-\d{2}$")
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
def _kind_before(column: str, entry: Dict[str, Any], field: str) -> Optional[Predicate]:
|
|
209
|
+
"""Rows strictly before a day (``YYYY-MM-DD``: anything earlier than that
|
|
210
|
+
day's midnight) or older than a period (``Nd``: before N days ago). The
|
|
211
|
+
complement of ``since`` — together they bracket a date range."""
|
|
212
|
+
value = _one(entry, field).lower()
|
|
213
|
+
if not value:
|
|
214
|
+
return None
|
|
215
|
+
if _ISO_DATE.match(value):
|
|
216
|
+
return f"{column} < %s::date", (value,)
|
|
217
|
+
match = _DAYS.match(value)
|
|
218
|
+
if not match:
|
|
219
|
+
raise FacetError(f"facet {field}: before must be YYYY-MM-DD or <N>d")
|
|
220
|
+
days = int(match.group(1))
|
|
221
|
+
if not 1 <= days <= MAX_DAYS:
|
|
222
|
+
raise FacetError(f"facet {field}: period must be 1 to {MAX_DAYS} days")
|
|
223
|
+
return f"{column} < now() - make_interval(days => %s)", (days,)
|
|
224
|
+
|
|
225
|
+
|
|
202
226
|
def _columns(entry: Dict[str, Any], column: str, field: str) -> List[str]:
|
|
203
227
|
"""The column(s) a text facet matches: ``fields`` when given, else the field."""
|
|
204
228
|
fields = entry.get("fields")
|
|
@@ -282,6 +306,7 @@ _BUILDERS = {
|
|
|
282
306
|
"contains": _kind_contains,
|
|
283
307
|
"presence": _kind_presence,
|
|
284
308
|
"since": _kind_since,
|
|
309
|
+
"before": _kind_before,
|
|
285
310
|
"text": _kind_text,
|
|
286
311
|
"domain": _kind_domain,
|
|
287
312
|
}
|
{velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/handlers/mixins/data_service.py
RENAMED
|
@@ -56,6 +56,39 @@ def _fk_blocked_delete_message(table, exc):
|
|
|
56
56
|
_IDENTIFIER_RE = re.compile(r"^[A-Za-z_][A-Za-z0-9_]*$")
|
|
57
57
|
|
|
58
58
|
|
|
59
|
+
TEXT_TYPES = frozenset(
|
|
60
|
+
{"text", "character varying", "character", "varchar", "char", "citext", "name"}
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def coerce_empty_strings(column_types, incoming):
|
|
65
|
+
"""The subset of ``incoming`` whose empty-string values must become
|
|
66
|
+
``None`` because their column is not a text type — ``{}`` when nothing
|
|
67
|
+
needs changing or the types are unknown."""
|
|
68
|
+
if not column_types:
|
|
69
|
+
return {}
|
|
70
|
+
out = {}
|
|
71
|
+
for key, value in incoming.items():
|
|
72
|
+
if not isinstance(value, str) or value.strip() != "":
|
|
73
|
+
continue
|
|
74
|
+
dtype = column_types.get(key)
|
|
75
|
+
if dtype is None:
|
|
76
|
+
continue
|
|
77
|
+
if str(dtype).lower() in TEXT_TYPES:
|
|
78
|
+
continue
|
|
79
|
+
out[key] = None
|
|
80
|
+
return out
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def _column_types(tx, table):
|
|
84
|
+
"""The table's ``{column: data_type}`` map, ``{}`` when unavailable —
|
|
85
|
+
a lookup failure must never block a write."""
|
|
86
|
+
try:
|
|
87
|
+
return tx.table(table).column_types(cache_ttl=300) or {}
|
|
88
|
+
except Exception: # noqa: BLE001 — best effort, the write proceeds
|
|
89
|
+
return {}
|
|
90
|
+
|
|
91
|
+
|
|
59
92
|
def _bump_sys_id_sequence(tx, table):
|
|
60
93
|
"""Keep the table's serial/identity sequence ahead of MAX(sys_id) so a
|
|
61
94
|
future auto-generated id can never collide with an explicitly chosen one
|
|
@@ -338,6 +371,11 @@ class DataServiceMixin:
|
|
|
338
371
|
def write_hook(self, tx, table, sys_id, incoming, context, save_as=False):
|
|
339
372
|
row = {}
|
|
340
373
|
incoming.pop("sys_id", None)
|
|
374
|
+
# A form posts every field it shows; untouched NULLs come back as ''.
|
|
375
|
+
# Postgres refuses '' for boolean/date/timestamp/numeric columns
|
|
376
|
+
# (found live: UPDATE studio SET inactive = '' — 2026-09-26), so
|
|
377
|
+
# empty strings become NULL wherever the column is not text.
|
|
378
|
+
incoming.update(coerce_empty_strings(_column_types(tx, table), incoming))
|
|
341
379
|
if sys_id == "@new":
|
|
342
380
|
self._call_rwx_hook(
|
|
343
381
|
"before_new", "common", tx, table, sys_id, incoming, context
|
|
@@ -641,6 +641,36 @@ class Table:
|
|
|
641
641
|
)
|
|
642
642
|
return load()
|
|
643
643
|
|
|
644
|
+
def column_types(self, **kwds):
|
|
645
|
+
"""``{column_name: data_type}`` (information_schema names, e.g.
|
|
646
|
+
``boolean``, ``timestamp with time zone``, ``text``). ``{}`` when the
|
|
647
|
+
server module has no ``column_types`` SQL. ``cache_ttl=N`` as in
|
|
648
|
+
``sys_columns``."""
|
|
649
|
+
builder = getattr(self.sql, "column_types", None)
|
|
650
|
+
if builder is None:
|
|
651
|
+
return {}
|
|
652
|
+
sql, vals = builder(self.name)
|
|
653
|
+
if kwds.get("sql_only", False):
|
|
654
|
+
return sql, vals
|
|
655
|
+
|
|
656
|
+
def load():
|
|
657
|
+
result = self.tx.execute(sql, vals, cursor=self.cursor())
|
|
658
|
+
return {name: dtype for name, dtype in result.as_tuple()}
|
|
659
|
+
|
|
660
|
+
cache_ttl = kwds.get("cache_ttl")
|
|
661
|
+
if cache_ttl:
|
|
662
|
+
from velocity.cache import SCHEMA_TAG, read_cache
|
|
663
|
+
|
|
664
|
+
return dict(
|
|
665
|
+
read_cache.memo(
|
|
666
|
+
("column_types", self._cache_scope(), self.name),
|
|
667
|
+
load,
|
|
668
|
+
cache_ttl,
|
|
669
|
+
tables=(self.name, SCHEMA_TAG),
|
|
670
|
+
)
|
|
671
|
+
)
|
|
672
|
+
return load()
|
|
673
|
+
|
|
644
674
|
def columns(self):
|
|
645
675
|
"""
|
|
646
676
|
Returns non-system column names.
|
|
@@ -1392,6 +1392,28 @@ class SQL(BaseSQLDialect):
|
|
|
1392
1392
|
]
|
|
1393
1393
|
)
|
|
1394
1394
|
|
|
1395
|
+
@classmethod
|
|
1396
|
+
def column_types(cls, name):
|
|
1397
|
+
"""``(column_name, data_type)`` rows for a table — the type map the
|
|
1398
|
+
write path uses to turn a form's empty strings into NULL for
|
|
1399
|
+
non-text columns."""
|
|
1400
|
+
if "." in name:
|
|
1401
|
+
return """
|
|
1402
|
+
select column_name, data_type
|
|
1403
|
+
from information_schema.columns
|
|
1404
|
+
where UPPER(table_schema) = UPPER(%s)
|
|
1405
|
+
and UPPER(table_name) = UPPER(%s)
|
|
1406
|
+
""", tuple(
|
|
1407
|
+
name.split(".")
|
|
1408
|
+
)
|
|
1409
|
+
return """
|
|
1410
|
+
select column_name, data_type
|
|
1411
|
+
from information_schema.columns
|
|
1412
|
+
where UPPER(table_name) = UPPER(%s)
|
|
1413
|
+
""", (
|
|
1414
|
+
name,
|
|
1415
|
+
)
|
|
1416
|
+
|
|
1395
1417
|
@classmethod
|
|
1396
1418
|
def column_info(cls, table, name):
|
|
1397
1419
|
params = table.split(".")
|
{velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity_python.egg-info/SOURCES.txt
RENAMED
|
@@ -304,4 +304,5 @@ tests/test_transaction_class_wrapping.py
|
|
|
304
304
|
tests/test_transaction_commit_and_ownership.py
|
|
305
305
|
tests/test_transaction_edge_cases.py
|
|
306
306
|
tests/test_where_clause_validation.py
|
|
307
|
-
tests/test_write_hook_create_flow.py
|
|
307
|
+
tests/test_write_hook_create_flow.py
|
|
308
|
+
tests/test_write_hook_empty_strings.py
|
|
@@ -47,6 +47,34 @@ def test_presence_treats_null_and_empty_alike_for_any_column_type():
|
|
|
47
47
|
facets.predicate({"field": "x", "kind": "presence", "value": "maybe"})
|
|
48
48
|
|
|
49
49
|
|
|
50
|
+
def test_before_day_or_period():
|
|
51
|
+
assert facets.predicate(
|
|
52
|
+
{"field": "sys_created", "kind": "before", "value": "2026-09-01"}
|
|
53
|
+
) == ("sys_created < %s::date", ("2026-09-01",))
|
|
54
|
+
assert facets.predicate(
|
|
55
|
+
{"field": "sys_created", "kind": "before", "value": "30d"}
|
|
56
|
+
) == ("sys_created < now() - make_interval(days => %s)", (30,))
|
|
57
|
+
assert (
|
|
58
|
+
facets.predicate({"field": "sys_created", "kind": "before", "value": ""})
|
|
59
|
+
is None
|
|
60
|
+
)
|
|
61
|
+
for bad in ("2026-9-1", "yesterday", "0d", "9999d", "2026-09-01; drop"):
|
|
62
|
+
with pytest.raises(facets.FacetError):
|
|
63
|
+
facets.predicate({"field": "sys_created", "kind": "before", "value": bad})
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def test_since_and_before_bracket_a_range():
|
|
67
|
+
sql, params = facets.build_where(
|
|
68
|
+
[
|
|
69
|
+
{"field": "sys_created", "kind": "since", "value": "60d"},
|
|
70
|
+
{"field": "sys_created", "kind": "before", "value": "2026-09-01"},
|
|
71
|
+
]
|
|
72
|
+
)
|
|
73
|
+
assert "sys_created >= now() - make_interval(days => %s)" in sql
|
|
74
|
+
assert "sys_created < %s::date" in sql
|
|
75
|
+
assert params == (60, "2026-09-01")
|
|
76
|
+
|
|
77
|
+
|
|
50
78
|
def test_since_periods():
|
|
51
79
|
assert facets.predicate(
|
|
52
80
|
{"field": "internal_date", "kind": "since", "value": "today"}
|
|
@@ -173,7 +201,10 @@ def test_domain_refuses_an_address_or_whitespace_and_ignores_blanks():
|
|
|
173
201
|
for bad in ("user@example.com", "two words.com", "a\tb.com"):
|
|
174
202
|
with pytest.raises(facets.FacetError):
|
|
175
203
|
facets.predicate({"field": "d", "kind": "domain", "values": [bad]})
|
|
176
|
-
assert
|
|
204
|
+
assert (
|
|
205
|
+
facets.predicate({"field": "d", "kind": "domain", "values": ["", ".", " "]})
|
|
206
|
+
is None
|
|
207
|
+
)
|
|
177
208
|
|
|
178
209
|
|
|
179
210
|
def test_exclude_negates_null_safely_for_any_kind():
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
"""write_hook turns a form's empty strings into NULL for non-text columns
|
|
2
|
+
(found live 2026-09-26: UPDATE studio SET inactive = '' — "invalid input
|
|
3
|
+
syntax for type boolean"). Text columns keep '' (a cleared note is a note
|
|
4
|
+
that is empty); unknown columns and unknown types are left alone.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import importlib.util
|
|
8
|
+
import unittest
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
MODULE_PATH = (
|
|
12
|
+
Path(__file__).resolve().parents[1]
|
|
13
|
+
/ "src"
|
|
14
|
+
/ "velocity"
|
|
15
|
+
/ "aws"
|
|
16
|
+
/ "handlers"
|
|
17
|
+
/ "mixins"
|
|
18
|
+
/ "data_service.py"
|
|
19
|
+
)
|
|
20
|
+
_spec = importlib.util.spec_from_file_location("test_write_hook_empty", MODULE_PATH)
|
|
21
|
+
_mod = importlib.util.module_from_spec(_spec)
|
|
22
|
+
_spec.loader.exec_module(_mod)
|
|
23
|
+
|
|
24
|
+
TYPES = {
|
|
25
|
+
"description": "text",
|
|
26
|
+
"notes": "character varying",
|
|
27
|
+
"inactive": "boolean",
|
|
28
|
+
"inactivated_on": "timestamp with time zone",
|
|
29
|
+
"start_date": "date",
|
|
30
|
+
"amount": "numeric",
|
|
31
|
+
"payload": "jsonb",
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class CoerceTests(unittest.TestCase):
|
|
36
|
+
def test_empty_strings_become_null_for_non_text_columns(self):
|
|
37
|
+
incoming = {
|
|
38
|
+
"description": "Magnify 1",
|
|
39
|
+
"notes": "",
|
|
40
|
+
"inactive": "",
|
|
41
|
+
"inactivated_on": " ",
|
|
42
|
+
"start_date": "",
|
|
43
|
+
"amount": "",
|
|
44
|
+
"payload": "",
|
|
45
|
+
"unknown_col": "",
|
|
46
|
+
}
|
|
47
|
+
self.assertEqual(
|
|
48
|
+
_mod.coerce_empty_strings(TYPES, incoming),
|
|
49
|
+
{
|
|
50
|
+
"inactive": None,
|
|
51
|
+
"inactivated_on": None,
|
|
52
|
+
"start_date": None,
|
|
53
|
+
"amount": None,
|
|
54
|
+
"payload": None,
|
|
55
|
+
},
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
def test_real_values_and_unknown_types_untouched(self):
|
|
59
|
+
self.assertEqual(
|
|
60
|
+
_mod.coerce_empty_strings(TYPES, {"inactive": False, "amount": "0"}), {}
|
|
61
|
+
)
|
|
62
|
+
self.assertEqual(_mod.coerce_empty_strings({}, {"inactive": ""}), {})
|
|
63
|
+
self.assertEqual(_mod.coerce_empty_strings(None, {"inactive": ""}), {})
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class FakeRow:
|
|
67
|
+
def __init__(self, data):
|
|
68
|
+
self.data = dict(data)
|
|
69
|
+
self.updates = []
|
|
70
|
+
|
|
71
|
+
def update(self, payload):
|
|
72
|
+
self.updates.append(dict(payload))
|
|
73
|
+
self.data.update(payload)
|
|
74
|
+
|
|
75
|
+
def to_dict(self):
|
|
76
|
+
return dict(self.data)
|
|
77
|
+
|
|
78
|
+
def __getitem__(self, k):
|
|
79
|
+
return self.data[k]
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
class FakeTable:
|
|
83
|
+
def __init__(self, row, types):
|
|
84
|
+
self.row = row
|
|
85
|
+
self.types = types
|
|
86
|
+
|
|
87
|
+
def find(self, sys_id):
|
|
88
|
+
return self.row
|
|
89
|
+
|
|
90
|
+
def column_types(self, **kwds):
|
|
91
|
+
return self.types
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
class FakeTx:
|
|
95
|
+
def __init__(self, table):
|
|
96
|
+
self._table = table
|
|
97
|
+
|
|
98
|
+
def table(self, name):
|
|
99
|
+
return self._table
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
class FakeContext:
|
|
103
|
+
def get_feature_flags(self, tx):
|
|
104
|
+
return {}
|
|
105
|
+
|
|
106
|
+
def enqueue_dirty(self, table, sys_id):
|
|
107
|
+
pass
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
class Service(_mod.DataServiceMixin):
|
|
111
|
+
def _call_rwx_hook(self, *args, **kwargs):
|
|
112
|
+
pass
|
|
113
|
+
|
|
114
|
+
def _get_dirty_pipeline_excluded_tables(self, tx, context):
|
|
115
|
+
return set()
|
|
116
|
+
|
|
117
|
+
def _dirty_pipeline_enabled(self, *a, **k):
|
|
118
|
+
return False
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
class WriteHookTests(unittest.TestCase):
|
|
122
|
+
def test_update_writes_null_not_empty_string(self):
|
|
123
|
+
row = FakeRow({"sys_id": 6, "description": "Magnify", "inactive": None})
|
|
124
|
+
tx = FakeTx(FakeTable(row, TYPES))
|
|
125
|
+
incoming = {
|
|
126
|
+
"sys_id": 6,
|
|
127
|
+
"description": "Magnify 1",
|
|
128
|
+
"inactive": "",
|
|
129
|
+
"inactivated_on": "",
|
|
130
|
+
"inactivated_by": "",
|
|
131
|
+
}
|
|
132
|
+
try:
|
|
133
|
+
Service().write_hook(tx, "studio", 6, incoming, FakeContext())
|
|
134
|
+
except AttributeError:
|
|
135
|
+
# the tail of write_hook touches dirty-pipeline plumbing the fake
|
|
136
|
+
# does not model; the update itself has already happened
|
|
137
|
+
pass
|
|
138
|
+
self.assertEqual(row.updates[0]["inactive"], None)
|
|
139
|
+
self.assertEqual(row.updates[0]["inactivated_on"], None)
|
|
140
|
+
# a text column keeps its empty string
|
|
141
|
+
self.assertEqual(row.updates[0]["inactivated_by"], "")
|
|
142
|
+
self.assertEqual(row.updates[0]["description"], "Magnify 1")
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
if __name__ == "__main__":
|
|
146
|
+
unittest.main()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/capabilities/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/capabilities/dispatch.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/capabilities/provisioning.py
RENAMED
|
File without changes
|
{velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/capabilities/retention.py
RENAMED
|
File without changes
|
{velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/capabilities/security.py
RENAMED
|
File without changes
|
{velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/capabilities/single_session.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/handlers/base_handler.py
RENAMED
|
File without changes
|
|
File without changes
|
{velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/handlers/context_factory.py
RENAMED
|
File without changes
|
|
File without changes
|
{velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/handlers/lambda_handler.py
RENAMED
|
File without changes
|
|
File without changes
|
{velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/handlers/mixins/__init__.py
RENAMED
|
File without changes
|
{velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/handlers/mixins/job_handler.py
RENAMED
|
File without changes
|
|
File without changes
|
{velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/handlers/mixins/web_handler.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/handlers/sqs_handler.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/tests/test_deploy_policies.py
RENAMED
|
File without changes
|
{velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/aws/tests/test_deploy_reconcile.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/servers/base/__init__.py
RENAMED
|
File without changes
|
{velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/servers/base/initializer.py
RENAMED
|
File without changes
|
{velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/servers/base/operators.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{velocity_python-0.1.123 → velocity_python-0.1.125}/src/velocity/db/servers/mysql/__init__.py
RENAMED
|
File without changes
|