querysource 4.5.7__tar.gz → 4.5.8__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.
- {querysource-4.5.7 → querysource-4.5.8}/PKG-INFO +1 -1
- {querysource-4.5.7 → querysource-4.5.8}/querysource/_version.py +3 -3
- {querysource-4.5.7 → querysource-4.5.8}/querysource/handlers/executor.py +6 -1
- {querysource-4.5.7 → querysource-4.5.8}/querysource/providers/abstract.py +15 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/providers/cassandra.py +7 -1
- {querysource-4.5.7 → querysource-4.5.8}/querysource/providers/default.py +7 -1
- {querysource-4.5.7 → querysource-4.5.8}/querysource/providers/documentdb.py +8 -1
- {querysource-4.5.7 → querysource-4.5.8}/querysource/providers/mysql.py +7 -1
- {querysource-4.5.7 → querysource-4.5.8}/querysource/providers/sql.py +14 -2
- {querysource-4.5.7 → querysource-4.5.8}/querysource/providers/sqlserver.py +7 -1
- {querysource-4.5.7 → querysource-4.5.8}/querysource/version.py +1 -1
- {querysource-4.5.7 → querysource-4.5.8}/querysource.egg-info/PKG-INFO +1 -1
- {querysource-4.5.7 → querysource-4.5.8}/querysource.egg-info/SOURCES.txt +2 -1
- {querysource-4.5.7 → querysource-4.5.8}/querysource.egg-info/scm_file_list.json +1 -0
- querysource-4.5.8/querysource.egg-info/scm_version.json +8 -0
- querysource-4.5.8/rust/Cargo.toml +34 -0
- {querysource-4.5.7 → querysource-4.5.8}/rust/src/safe_dict.rs +69 -0
- {querysource-4.5.7 → querysource-4.5.8}/rust/src/validators.rs +23 -3
- querysource-4.5.8/tests/unit/test_raw_query_cond_definition_wiring.py +182 -0
- querysource-4.5.7/querysource.egg-info/scm_version.json +0 -8
- querysource-4.5.7/rust/Cargo.toml +0 -23
- {querysource-4.5.7 → querysource-4.5.8}/.agent/rules/async-programming-expert.md +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/.agent/rules/code-reviewer.md +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/.agent/rules/cython-development.md +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/.agent/rules/prompt-expert.md +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/.agent/rules/python-development.md +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/.agent/rules/rust-development.md +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/.agent/workflows/create-parrot-tool.md +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/.agent/workflows/create-workflow.md +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/.agent/workflows/debug-regressions-with-git-bisect-binary-search.md +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/.agent/workflows/generate-tests.md +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/.agent/workflows/git-new-feature.md +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/.agent/workflows/parrot-mcp-server.md +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/.agent/workflows/release_package.md +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/.agent/workflows/start-flow.md +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/.bumpversion.cfg +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/.claude/agents/code-reviewer.md +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/.claude/agents/sdd-autopilot.md +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/.claude/agents/sdd-qa.md +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/.claude/agents/sdd-research.md +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/.claude/agents/sdd-worker.md +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/.claude/commands/pr-review.md +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/.claude/commands/sdd-brainstorm.md +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/.claude/commands/sdd-codereview.md +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/.claude/commands/sdd-done.md +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/.claude/commands/sdd-fromjira.md +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/.claude/commands/sdd-next.md +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/.claude/commands/sdd-proposal.md +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/.claude/commands/sdd-spec.md +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/.claude/commands/sdd-start.md +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/.claude/commands/sdd-status.md +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/.claude/commands/sdd-task.md +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/.claude/commands/sdd-tojira.md +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/.claude/rules/aws-cost-optimization.md +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/.claude/rules/code-reviewer.md +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/.claude/rules/cython-development.md +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/.claude/rules/python-development.md +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/.claude/rules/rust-development.md +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/.claude/rules/using-git-worktrees.md +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/.claude/rules/worktree-pr-and-clean.md +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/.claude/rules/worktree-start-feature.md +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/.claude/rules/worktree-status.md +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/.github/dependabot.yml +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/.github/workflows/codeql-analysis.yml +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/.github/workflows/release.yml +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/.isort.cfg +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/.jupyter/jupyter_notebook_config.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/.pre-commit-config.yaml +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/.pylintrc +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/CHANGES.rst +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/CODE_OF_CONDUCT.md +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/CONTRIBUTING.md +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/INSTALL +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/JOIN_CONDITIONS_FEATURE.md +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/JOIN_CONDITIONS_SUMMARY.md +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/LICENSE +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/MANIFEST.in +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/Makefile +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/README.md +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/app.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/bin/README.md +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/conftest.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/generated/AirtableSource.json +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/generated/Concat.json +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/generated/DWHDestination.json +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/generated/DropCols.json +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/generated/FileSource.json +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/generated/Filter.json +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/generated/FilterCols.json +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/generated/Forecast.json +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/generated/GoogleMaps.json +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/generated/GroupBy.json +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/generated/Info.json +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/generated/Join.json +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/generated/Map.json +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/generated/Melt.json +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/generated/Merge.json +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/generated/NormalizeColumns.json +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/generated/PluckCols.json +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/generated/Query.json +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/generated/S3Source.json +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/generated/SharepointSource.json +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/generated/SmartSheetSource.json +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/generated/Table.json +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/generated/TableDestination.json +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/generated/TableOutput.json +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/generated/TableOutputAdapter.json +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/generated/TableSource.json +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/generated/ToS3.json +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/generated/ToSharepoint.json +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/generated/correlation.json +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/generated/crosstab.json +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/generated/pivot.json +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/generated/tExplode.json +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/generated/tOrder.json +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/generated/tPandas.json +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/gunicorn_config.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/mypy.ini +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/nav.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/policies/HARDENING.md +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/policies/authorized.yaml +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/policies/baseline.yaml +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/policies/datasources.yaml +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/policies/defaults.yaml +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/policies/drivers.yaml +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/policies/raw_queries.yaml +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/policies/slugs.yaml +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/policies/superusers.yaml +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/pyproject.toml +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/pytest.ini +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/__cli__.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/__init__.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/auth/__init__.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/auth/_resource_types.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/auth/credentials.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/auth/pbac.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/cache/__init__.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/cache/backends/__init__.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/cache/backends/abstract.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/cache/backends/memcache.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/cache/backends/redis.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/cache/base.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/cli/__init__.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/cli/generate_docs.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/conf.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/connections.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/datasources/__init__.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/datasources/drivers/__init__.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/datasources/drivers/abstract.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/datasources/drivers/arangodb.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/datasources/drivers/athena.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/datasources/drivers/bigquery.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/datasources/drivers/cassandra.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/datasources/drivers/clickhouse.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/datasources/drivers/cockroachdb.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/datasources/drivers/couchbase.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/datasources/drivers/couchdb.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/datasources/drivers/countries.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/datasources/drivers/delta.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/datasources/drivers/documentdb.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/datasources/drivers/dynamodb.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/datasources/drivers/elastic.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/datasources/drivers/ga.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/datasources/drivers/gcalc.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/datasources/drivers/hazel.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/datasources/drivers/iceberg.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/datasources/drivers/influx.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/datasources/drivers/jdbc.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/datasources/drivers/jira.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/datasources/drivers/mariadb.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/datasources/drivers/memcached.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/datasources/drivers/mongo.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/datasources/drivers/mysql.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/datasources/drivers/odbc.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/datasources/drivers/openweather.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/datasources/drivers/oracle.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/datasources/drivers/pg.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/datasources/drivers/pg_admin.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/datasources/drivers/postgres.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/datasources/drivers/py.typed +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/datasources/drivers/qs.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/datasources/drivers/redis.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/datasources/drivers/rest.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/datasources/drivers/rethink.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/datasources/drivers/sa.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/datasources/drivers/salesforce.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/datasources/drivers/scylladb.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/datasources/drivers/sqlalchemy.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/datasources/drivers/sqlite.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/datasources/drivers/sqlserver.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/datasources/drivers/upc.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/datasources/drivers/zipcodeapi.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/datasources/handlers/__init__.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/datasources/handlers/datasource.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/datasources/handlers/utils.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/datasources/introspection.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/datasources/models.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/events/__init__.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/exceptions.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/handlers/__init__.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/handlers/_pagination.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/handlers/abstract.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/handlers/components.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/handlers/integrations/__init__.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/handlers/integrations/airtable.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/handlers/log.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/handlers/manager.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/handlers/multi.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/handlers/outputs/__init__.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/handlers/outputs/tableOutput/__init__.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/handlers/outputs/tableOutput/postgres.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/handlers/outputs/tableOutput/table.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/handlers/scheduler.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/handlers/service.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/handlers/variables.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/interfaces/__init__.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/interfaces/airtable.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/interfaces/connections.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/interfaces/credentials.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/interfaces/databases/__init__.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/interfaces/databases/abstract.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/interfaces/databases/bigquery.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/interfaces/databases/db.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/interfaces/databases/mongo.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/interfaces/databases/rethink.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/interfaces/http.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/interfaces/playwright_service.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/interfaces/queries.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/interfaces/selenium_service.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/libs/__init__.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/libs/encoders.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/libs/functions/__init__.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/libs/py.typed +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/models.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/outputs/__init__.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/outputs/destinations/__init__.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/outputs/destinations/abstract.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/outputs/destinations/dwh.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/outputs/destinations/s3.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/outputs/destinations/sharepoint.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/outputs/destinations/table.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/outputs/dt/__init__.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/outputs/dt/abstract.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/outputs/dt/arrow.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/outputs/dt/dt.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/outputs/dt/factory.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/outputs/dt/iter.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/outputs/dt/modin.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/outputs/dt/pandas.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/outputs/dt/polars.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/outputs/output.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/outputs/tables/TableOutput/__init__.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/outputs/tables/TableOutput/abstract.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/outputs/tables/TableOutput/bigquery.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/outputs/tables/TableOutput/documentdb.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/outputs/tables/TableOutput/mongodb.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/outputs/tables/TableOutput/mysql.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/outputs/tables/TableOutput/postgres.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/outputs/tables/TableOutput/rethink.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/outputs/tables/TableOutput/sa.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/outputs/tables/TableOutput/table.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/outputs/tables/__init__.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/outputs/writers/__init__.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/outputs/writers/abstract.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/outputs/writers/bokeh.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/outputs/writers/clustering.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/outputs/writers/csv.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/outputs/writers/describe.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/outputs/writers/eda.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/outputs/writers/excel.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/outputs/writers/html.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/outputs/writers/json.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/outputs/writers/pdf.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/outputs/writers/pickle.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/outputs/writers/plotly.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/outputs/writers/profiling.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/outputs/writers/report.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/outputs/writers/table.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/outputs/writers/tsv.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/outputs/writers/txt.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/outputs/writers/xml.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/parsers/__init__.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/parsers/abstract.c +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/parsers/abstract.pxd +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/parsers/abstract.pyx +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/parsers/arangodb.c +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/parsers/arangodb.pxd +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/parsers/arangodb.pyx +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/parsers/bigquery.c +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/parsers/bigquery.pxd +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/parsers/bigquery.pyx +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/parsers/cql.c +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/parsers/cql.pxd +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/parsers/cql.pyx +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/parsers/deltatbl.c +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/parsers/deltatbl.pxd +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/parsers/deltatbl.pyx +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/parsers/elastic.cpp +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/parsers/elastic.pxd +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/parsers/elastic.pyx +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/parsers/iceberg.c +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/parsers/iceberg.pxd +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/parsers/iceberg.pyx +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/parsers/influx.c +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/parsers/influx.pxd +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/parsers/influx.pyx +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/parsers/mongo.cpp +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/parsers/mongo.pxd +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/parsers/mongo.pyx +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/parsers/parser.c +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/parsers/parser.pxd +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/parsers/parser.pyx +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/parsers/pgsql.c +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/parsers/pgsql.pxd +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/parsers/pgsql.pyx +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/parsers/rethink.c +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/parsers/rethink.pxd +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/parsers/rethink.pyx +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/parsers/sosql.c +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/parsers/sosql.pxd +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/parsers/sosql.pyx +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/parsers/sql.c +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/parsers/sql.pxd +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/parsers/sql.pyx +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/parsers/sqlserver.c +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/parsers/sqlserver.pxd +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/parsers/sqlserver.pyx +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/plugins/__init__.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/plugins/importer.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/plugins/sources/__init__.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/providers/__init__.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/providers/arangodb.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/providers/bigquery.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/providers/db.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/providers/deltatbl.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/providers/dummy.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/providers/elastic.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/providers/external.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/providers/http.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/providers/iceberg.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/providers/influx.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/providers/pg.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/providers/py.typed +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/providers/rest.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/providers/rethink.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/providers/salesforce.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/providers/scylladb.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/providers/sources/__init__.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/providers/sources/abstract.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/providers/sources/amazon.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/providers/sources/countries.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/providers/sources/ga.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/providers/sources/geofcc.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/providers/sources/gmaps.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/providers/sources/graphcountries.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/providers/sources/graphql.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/providers/sources/http.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/providers/sources/hubspot.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/providers/sources/openweather.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/providers/sources/parsers/__init__.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/providers/sources/parsers/amproduct.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/providers/sources/parsers/xpath.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/providers/sources/pokemon.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/providers/sources/populartimes.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/providers/sources/py.typed +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/providers/sources/rest.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/providers/sources/retailnext.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/providers/sources/rssapp.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/providers/sources/salesforce.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/providers/sources/scrapper.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/providers/sources/shoppertrack.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/providers/sources/swop.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/providers/sources/uap.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/providers/sources/upc.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/providers/sources/wm_stores.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/providers/sources/zammad.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/providers/sources/zipcodeapi.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/py.typed +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/qs_parsers/__init__.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/queries/__init__.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/queries/base.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/queries/executor.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/queries/models.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/queries/multi/__init__.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/queries/multi/_introspect.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/queries/multi/abstract.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/queries/multi/components/__init__.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/queries/multi/components/abstract.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/queries/multi/destinations/__init__.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/queries/multi/destinations/dwh.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/queries/multi/destinations/s3.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/queries/multi/destinations/sharepoint.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/queries/multi/destinations/table.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/queries/multi/operators/Concat.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/queries/multi/operators/GroupBy.catalog.yaml +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/queries/multi/operators/GroupBy.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/queries/multi/operators/Info.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/queries/multi/operators/Join.catalog.yaml +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/queries/multi/operators/Join.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/queries/multi/operators/Melt.catalog.yaml +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/queries/multi/operators/Melt.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/queries/multi/operators/Merge.catalog.yaml +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/queries/multi/operators/Merge.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/queries/multi/operators/__init__.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/queries/multi/operators/abstract.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/queries/multi/operators/filter/Filter.catalog.yaml +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/queries/multi/operators/filter/__init__.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/queries/multi/operators/filter/flt.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/queries/multi/registry.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/queries/multi/sources/__init__.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/queries/multi/sources/airtable.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/queries/multi/sources/base.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/queries/multi/sources/executors.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/queries/multi/sources/file.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/queries/multi/sources/query.catalog.yaml +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/queries/multi/sources/query.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/queries/multi/sources/s3.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/queries/multi/sources/sharepoint.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/queries/multi/sources/smartsheet.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/queries/multi/sources/table.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/queries/multi/transformations/DropCols.catalog.yaml +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/queries/multi/transformations/DropCols.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/queries/multi/transformations/FilterCols.catalog.yaml +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/queries/multi/transformations/FilterCols.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/queries/multi/transformations/Forecast.catalog.yaml +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/queries/multi/transformations/Forecast.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/queries/multi/transformations/Map.catalog.yaml +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/queries/multi/transformations/Map.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/queries/multi/transformations/NormalizeColumns.catalog.yaml +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/queries/multi/transformations/NormalizeColumns.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/queries/multi/transformations/PluckCols.catalog.yaml +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/queries/multi/transformations/PluckCols.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/queries/multi/transformations/__init__.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/queries/multi/transformations/abstract.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/queries/multi/transformations/correlation.catalog.yaml +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/queries/multi/transformations/correlation.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/queries/multi/transformations/crosstab.catalog.yaml +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/queries/multi/transformations/crosstab.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/queries/multi/transformations/google/GoogleMaps.catalog.yaml +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/queries/multi/transformations/google/__init__.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/queries/multi/transformations/google/maps.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/queries/multi/transformations/pivot.catalog.yaml +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/queries/multi/transformations/pivot.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/queries/multi/transformations/tExplode.catalog.yaml +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/queries/multi/transformations/tExplode.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/queries/multi/transformations/tOrder.catalog.yaml +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/queries/multi/transformations/tOrder.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/queries/multi/transformations/tPandas.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/queries/obj.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/queries/qs.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/scheduler/__init__.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/scheduler/jobs.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/scheduler/notifications.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/scheduler/scheduler.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/services.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/template/__init__.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/template/parser.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/types/__init__.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/types/converters.cpp +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/types/converters.pyx +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/types/dt/__init__.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/types/dt/filters.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/types/dt/transforms.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/types/py.typed +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/types/typedefs.c +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/types/typedefs.pyx +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/types/validators.cpp +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/types/validators.pyx +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/utils/__init__.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/utils/cache_serialization.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/utils/errors.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/utils/events.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/utils/fn.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/utils/functions.cpp +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/utils/functions.pyx +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/utils/getfunc.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/utils/handlers.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/utils/parseqs.cpp +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/utils/parseqs.pyx +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource/utils/validators.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource.egg-info/dependency_links.txt +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource.egg-info/entry_points.txt +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource.egg-info/not-zip-safe +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource.egg-info/requires.txt +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/querysource.egg-info/top_level.txt +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/run.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/rust/Cargo.lock +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/rust/pyproject.toml +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/rust/src/arangodb_parser.rs +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/rust/src/bigquery_parser.rs +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/rust/src/cql_parser.rs +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/rust/src/elastic_parser.rs +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/rust/src/filter_common.rs +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/rust/src/flux_parser.rs +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/rust/src/lib.rs +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/rust/src/mongo_parser.rs +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/rust/src/mssql_parser.rs +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/rust/src/parseqs.rs +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/rust/src/pgsql_parser.rs +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/rust/src/rethink_parser.rs +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/rust/src/soql_parser.rs +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/rust/src/sql_parser.rs +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/setup.cfg +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/setup.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/static/notebook/bundle.js +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/templates/__init__.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/templates/base.html +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/templates/default.html +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/templates/default_table.html +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/templates/fontlist-v330.json +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/templates/fontlist-v390.json +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/templates/table_charts.html +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/auth/__init__.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/auth/test_credentials.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/auth/test_pbac_bootstrap.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/check_concurrent_get_slug.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/conftest.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/datasources/__init__.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/datasources/test_datasource_view_pbac.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/datasources/test_driver_factory_session.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/datasources/test_pg_admin_registration.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/datasources/test_pg_params_for.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/handlers/__init__.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/handlers/conftest.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/handlers/test_abstract_pbac_helpers.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/handlers/test_airtable_oauth.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/handlers/test_multiquery_pbac_smoke.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/handlers/test_query_param_exclusion.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/handlers/test_queryexecutor_pbac_smoke.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/handlers/test_querymanager_pagination.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/handlers/test_queryservice_pbac_smoke.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/integration/__init__.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/integration/test_datasource_endpoint.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/integration/test_pbac_credentials.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/integration/test_pbac_enforcement.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/integration/test_pbac_listing.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/integration/test_slug_injection.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/integration/test_slug_regression.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/interfaces/__init__.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/interfaces/test_airtable_interface.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/multi/__init__.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/multi/sources/__init__.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/multi/sources/test_airtable_source.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/multi/sources/test_registry.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/perf/__init__.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/perf/test_pbac_overhead.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/policies/__init__.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/policies/test_authorized_policy.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/policies/test_default_policies_load.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/scheduler/__init__.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/scheduler/test_parse_trigger_shorthands.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/scheduler/test_shorthand_loaders.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/services/__init__.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/services/test_querysource_setup_pbac.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/test_abstract_multi.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/test_abstract_refactor.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/test_api.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/test_arangodb_parser.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/test_catalog_colcols.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/test_catalog_correlation.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/test_catalog_filter.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/test_catalog_forecast.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/test_catalog_googlemaps.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/test_catalog_groupby.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/test_catalog_map.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/test_catalog_pivot.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/test_catalog_remote.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/test_catalog_texplode.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/test_catalog_torder.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/test_cli_generate_docs.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/test_column_filters.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/test_component_handler.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/test_component_registry.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/test_conf_airtable.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/test_destination_base.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/test_destination_dwh.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/test_destination_integration.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/test_destination_s3.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/test_destination_sharepoint.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/test_destination_table.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/test_destinations_documentation_endpoint.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/test_elastic_parser.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/test_error_formatter.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/test_eval.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/test_feat102_error_redaction.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/test_grouping_sync.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/test_info_eda.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/test_info_eda_e2e.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/test_info_eda_integration.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/test_join_conditions.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/test_join_with_column_filter.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/test_local_executor.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/test_multi_destinations_subpackage.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/test_multiqs_column_transforms.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/test_multiqs_destination_dispatch.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/test_multiqs_remote_dispatch.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/test_multiqs_sources_integration.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/test_queryslug_concurrency.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/test_querysource_setup_airtable.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/test_qworker_config.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/test_remote_executor.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/test_route_registration.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/test_rss.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/test_rust_parsers.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/test_scheduler_core.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/test_scheduler_handler_integration.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/test_scheduler_handler_unit.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/test_scheduler_integration.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/test_scheduler_jobs.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/test_scheduler_multi_routing.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/test_scheduler_notifications.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/test_schema_introspectable.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/test_source_registry.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/test_source_s3.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/test_source_sharepoint.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/test_source_smartsheet.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/test_source_table.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/test_sql_parser_combinations.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/test_texplode.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/test_thread_file_refactor.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/test_thread_query_refactor.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/test_thread_source_base.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/test_threadquery_executor.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/test_zammad_search.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/unit/test_cython_filter_fallback.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/unit/test_datasource_redaction.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/unit/test_provider_raw_query_validated.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tests/unit/test_qs_parsers_validated.py +0 -0
- {querysource-4.5.7 → querysource-4.5.8}/tox.ini +0 -0
|
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
|
|
|
18
18
|
commit_id: str | None
|
|
19
19
|
__commit_id__: str | None
|
|
20
20
|
|
|
21
|
-
__version__ = version = '4.5.
|
|
22
|
-
__version_tuple__ = version_tuple = (4, 5,
|
|
21
|
+
__version__ = version = '4.5.9.dev0+g5159ecc88.d20260708'
|
|
22
|
+
__version_tuple__ = version_tuple = (4, 5, 9, 'dev0', 'g5159ecc88.d20260708')
|
|
23
23
|
|
|
24
|
-
__commit_id__ = commit_id = '
|
|
24
|
+
__commit_id__ = commit_id = 'g5159ecc88'
|
|
@@ -120,6 +120,12 @@ class QueryExecutor(AbstractHandler):
|
|
|
120
120
|
response='QS: Missing driver or datasource for introspection.',
|
|
121
121
|
status=410 # bad request
|
|
122
122
|
)
|
|
123
|
+
# `table` is an introspection-only field (lazy column loading). Pull it
|
|
124
|
+
# out BEFORE building the Query model: the model is strict and rejects
|
|
125
|
+
# unknown kwargs, so leaving `table` in the payload makes get_executor
|
|
126
|
+
# fail on the columns request while the tables request (no `table`)
|
|
127
|
+
# succeeds.
|
|
128
|
+
table = payload.pop('table', None) if isinstance(payload, dict) else None
|
|
123
129
|
try:
|
|
124
130
|
query = self.get_executor(payload, request)
|
|
125
131
|
except QueryError as ex:
|
|
@@ -129,7 +135,6 @@ class QueryExecutor(AbstractHandler):
|
|
|
129
135
|
return self.critical(reason={"message": str(ex)}, status=500)
|
|
130
136
|
# PBAC: enforce the same datasource/driver checks as a query run.
|
|
131
137
|
await self._enforce_payload(request, payload, query)
|
|
132
|
-
table = payload.get('table') if isinstance(payload, dict) else None
|
|
133
138
|
try:
|
|
134
139
|
result = await query.introspect(table=table)
|
|
135
140
|
return self.json_response(
|
|
@@ -130,6 +130,21 @@ class BaseProvider(ABC):
|
|
|
130
130
|
"""
|
|
131
131
|
return self._definition
|
|
132
132
|
|
|
133
|
+
def _get_cond_definition(self) -> dict:
|
|
134
|
+
"""Return the per-placeholder type hints (`cond_definition`) declared on
|
|
135
|
+
the Query definition, used by the Rust validating substitution
|
|
136
|
+
(`safe_format_map_validated`) to type-check raw-query conditions.
|
|
137
|
+
|
|
138
|
+
Supports both `QueryModel` objects (attribute access) and plain dicts,
|
|
139
|
+
and normalizes a missing/None definition to an empty dict.
|
|
140
|
+
"""
|
|
141
|
+
definition = self._definition
|
|
142
|
+
if isinstance(definition, dict):
|
|
143
|
+
cond_definition = definition.get('cond_definition')
|
|
144
|
+
else:
|
|
145
|
+
cond_definition = getattr(definition, 'cond_definition', None)
|
|
146
|
+
return cond_definition or {}
|
|
147
|
+
|
|
133
148
|
def NotFound(self, message: str):
|
|
134
149
|
"""Raised when Data not Found.
|
|
135
150
|
"""
|
|
@@ -73,13 +73,19 @@ class cassandraProvider(BaseProvider):
|
|
|
73
73
|
sql = _rs.safe_format_map(query, self.replacement)
|
|
74
74
|
if self._conditions:
|
|
75
75
|
try:
|
|
76
|
-
sql = _rs.safe_format_map_validated(sql, self._conditions,
|
|
76
|
+
sql = _rs.safe_format_map_validated(sql, self._conditions, self._get_cond_definition())
|
|
77
77
|
except ValueError as err:
|
|
78
78
|
self._logger.warning(
|
|
79
79
|
"get_raw_query: validating substitution rejected conditions: %s", err
|
|
80
80
|
)
|
|
81
81
|
raise ParserError("Invalid query conditions") from err
|
|
82
82
|
return sql
|
|
83
|
+
# DIVERGENCE (FEAT-103): pure-Python fallback (HAS_RUST=False) has no
|
|
84
|
+
# injection validation and ignores cond_definition entirely — type
|
|
85
|
+
# hints (e.g. "array") only take effect via the Rust path. Accepted
|
|
86
|
+
# because the Rust extension is required in all supported
|
|
87
|
+
# deployments; replicating context-aware validation in pure Python
|
|
88
|
+
# would duplicate the security-critical logic in two places.
|
|
83
89
|
conditions = {**self.replacement, **(self._conditions or {})}
|
|
84
90
|
return query.format_map(
|
|
85
91
|
defaultdict(str, SafeDict(**conditions))
|
|
@@ -72,13 +72,19 @@ class defaultProvider(BaseProvider):
|
|
|
72
72
|
sql = _rs.safe_format_map(query, self.replacement)
|
|
73
73
|
if self._conditions:
|
|
74
74
|
try:
|
|
75
|
-
sql = _rs.safe_format_map_validated(sql, self._conditions,
|
|
75
|
+
sql = _rs.safe_format_map_validated(sql, self._conditions, self._get_cond_definition())
|
|
76
76
|
except ValueError as err:
|
|
77
77
|
self._logger.warning(
|
|
78
78
|
"raw_query: validating substitution rejected conditions: %s", err
|
|
79
79
|
)
|
|
80
80
|
raise ParserError("Invalid query conditions") from err
|
|
81
81
|
return sql
|
|
82
|
+
# DIVERGENCE (FEAT-103): pure-Python fallback (HAS_RUST=False) has no
|
|
83
|
+
# injection validation and ignores cond_definition entirely — type
|
|
84
|
+
# hints (e.g. "array") only take effect via the Rust path. Accepted
|
|
85
|
+
# because the Rust extension is required in all supported
|
|
86
|
+
# deployments; replicating context-aware validation in pure Python
|
|
87
|
+
# would duplicate the security-critical logic in two places.
|
|
82
88
|
conditions = {**self.replacement, **(self._conditions or {})}
|
|
83
89
|
return query.format_map(
|
|
84
90
|
defaultdict(str, SafeDict(**conditions))
|
|
@@ -97,7 +97,7 @@ class documentdbProvider(BaseProvider):
|
|
|
97
97
|
if HAS_RUST:
|
|
98
98
|
try:
|
|
99
99
|
sql = _rs.safe_format_map(query, self.replacement)
|
|
100
|
-
substituted = _rs.safe_format_map_validated(sql, self._conditions,
|
|
100
|
+
substituted = _rs.safe_format_map_validated(sql, self._conditions, self._get_cond_definition())
|
|
101
101
|
try:
|
|
102
102
|
return json_decoder(substituted)
|
|
103
103
|
except Exception:
|
|
@@ -108,6 +108,13 @@ class documentdbProvider(BaseProvider):
|
|
|
108
108
|
)
|
|
109
109
|
raise ParserError("Invalid query conditions") from err
|
|
110
110
|
# Fallback when Rust is unavailable
|
|
111
|
+
# DIVERGENCE (FEAT-103): pure-Python fallback has no injection
|
|
112
|
+
# validation and ignores cond_definition entirely — type hints
|
|
113
|
+
# (e.g. "array") only take effect via the Rust path. Accepted
|
|
114
|
+
# because the Rust extension is required in all supported
|
|
115
|
+
# deployments; replicating context-aware validation in pure
|
|
116
|
+
# Python would duplicate the security-critical logic in two
|
|
117
|
+
# places.
|
|
111
118
|
try:
|
|
112
119
|
return query.format_map(
|
|
113
120
|
defaultdict(str, SafeDict(**self._conditions))
|
|
@@ -107,13 +107,19 @@ class mysqlProvider(BaseProvider):
|
|
|
107
107
|
sql = _rs.safe_format_map(query, self.replacement)
|
|
108
108
|
if self._conditions:
|
|
109
109
|
try:
|
|
110
|
-
sql = _rs.safe_format_map_validated(sql, self._conditions,
|
|
110
|
+
sql = _rs.safe_format_map_validated(sql, self._conditions, self._get_cond_definition())
|
|
111
111
|
except ValueError as err:
|
|
112
112
|
self._logger.warning(
|
|
113
113
|
"raw_query: validating substitution rejected conditions: %s", err
|
|
114
114
|
)
|
|
115
115
|
raise ParserError("Invalid query conditions") from err
|
|
116
116
|
return sql
|
|
117
|
+
# DIVERGENCE (FEAT-103): pure-Python fallback (HAS_RUST=False) has no
|
|
118
|
+
# injection validation and ignores cond_definition entirely — type
|
|
119
|
+
# hints (e.g. "array") only take effect via the Rust path. Accepted
|
|
120
|
+
# because the Rust extension is required in all supported
|
|
121
|
+
# deployments; replicating context-aware validation in pure Python
|
|
122
|
+
# would duplicate the security-critical logic in two places.
|
|
117
123
|
conditions = {**self.replacement, **(self._conditions or {})}
|
|
118
124
|
return query.format_map(
|
|
119
125
|
defaultdict(str, SafeDict(**conditions))
|
|
@@ -172,7 +172,7 @@ class sqlProvider(BaseProvider):
|
|
|
172
172
|
# Phase 2: untrusted user-supplied conditions (if any)
|
|
173
173
|
if self._conditions:
|
|
174
174
|
try:
|
|
175
|
-
sql = _rs.safe_format_map_validated(sql, self._conditions,
|
|
175
|
+
sql = _rs.safe_format_map_validated(sql, self._conditions, self._get_cond_definition())
|
|
176
176
|
except ValueError as err:
|
|
177
177
|
self._logger.warning(
|
|
178
178
|
"raw_query: validating substitution rejected conditions: %s", err
|
|
@@ -180,6 +180,12 @@ class sqlProvider(BaseProvider):
|
|
|
180
180
|
raise ParserError("Invalid query conditions") from err
|
|
181
181
|
return sql
|
|
182
182
|
# Fallback when Rust is unavailable (should not happen in production)
|
|
183
|
+
# DIVERGENCE (FEAT-103): pure-Python fallback has no injection
|
|
184
|
+
# validation and ignores cond_definition entirely — type hints
|
|
185
|
+
# (e.g. "array") only take effect via the Rust path. Accepted
|
|
186
|
+
# because the Rust extension is required in all supported
|
|
187
|
+
# deployments; replicating context-aware validation in pure Python
|
|
188
|
+
# would duplicate the security-critical logic in two places.
|
|
183
189
|
conditions = {**self.replacement, **(self._conditions or {})}
|
|
184
190
|
return query.format_map(
|
|
185
191
|
defaultdict(str, SafeDict(**conditions))
|
|
@@ -191,13 +197,19 @@ class sqlProvider(BaseProvider):
|
|
|
191
197
|
sql = _rs.safe_format_map(query, self.replacement)
|
|
192
198
|
if self._conditions:
|
|
193
199
|
try:
|
|
194
|
-
sql = _rs.safe_format_map_validated(sql, self._conditions,
|
|
200
|
+
sql = _rs.safe_format_map_validated(sql, self._conditions, self._get_cond_definition())
|
|
195
201
|
except ValueError as err:
|
|
196
202
|
self._logger.warning(
|
|
197
203
|
"get_raw_query: validating substitution rejected conditions: %s", err
|
|
198
204
|
)
|
|
199
205
|
raise ParserError("Invalid query conditions") from err
|
|
200
206
|
return sql
|
|
207
|
+
# DIVERGENCE (FEAT-103): pure-Python fallback has no injection
|
|
208
|
+
# validation and ignores cond_definition entirely — type hints
|
|
209
|
+
# (e.g. "array") only take effect via the Rust path. Accepted
|
|
210
|
+
# because the Rust extension is required in all supported
|
|
211
|
+
# deployments; replicating context-aware validation in pure Python
|
|
212
|
+
# would duplicate the security-critical logic in two places.
|
|
201
213
|
conditions = {**self.replacement, **(self._conditions or {})}
|
|
202
214
|
return query.format_map(
|
|
203
215
|
defaultdict(str, SafeDict(**conditions))
|
|
@@ -86,13 +86,19 @@ class sqlserverProvider(BaseProvider):
|
|
|
86
86
|
sql = _rs.safe_format_map(query, self.replacement)
|
|
87
87
|
if self._conditions:
|
|
88
88
|
try:
|
|
89
|
-
sql = _rs.safe_format_map_validated(sql, self._conditions,
|
|
89
|
+
sql = _rs.safe_format_map_validated(sql, self._conditions, self._get_cond_definition())
|
|
90
90
|
except ValueError as err:
|
|
91
91
|
self._logger.warning(
|
|
92
92
|
"get_raw_query: validating substitution rejected conditions: %s", err
|
|
93
93
|
)
|
|
94
94
|
raise ParserError("Invalid query conditions") from err
|
|
95
95
|
return sql
|
|
96
|
+
# DIVERGENCE (FEAT-103): pure-Python fallback (HAS_RUST=False) has no
|
|
97
|
+
# injection validation and ignores cond_definition entirely — type
|
|
98
|
+
# hints (e.g. "array") only take effect via the Rust path. Accepted
|
|
99
|
+
# because the Rust extension is required in all supported
|
|
100
|
+
# deployments; replicating context-aware validation in pure Python
|
|
101
|
+
# would duplicate the security-critical logic in two places.
|
|
96
102
|
conditions = {**self.replacement, **(self._conditions or {})}
|
|
97
103
|
return query.format_map(
|
|
98
104
|
defaultdict(str, SafeDict(**conditions))
|
|
@@ -6,7 +6,7 @@ __description__ = (
|
|
|
6
6
|
'QuerySource Query parser and generator.'
|
|
7
7
|
'Supports SQL, NoSQL, MongoDB, Cassandra, Elasticsearch, etc.'
|
|
8
8
|
)
|
|
9
|
-
__version__ = '4.5.
|
|
9
|
+
__version__ = '4.5.8'
|
|
10
10
|
__url__ = 'https://github.com/phenobarbital/querysource'
|
|
11
11
|
__copyright__ = 'Copyright (c) 2018-2025 Jesus Lara'
|
|
12
12
|
__author__ = 'Jesus Lara'
|
|
@@ -621,4 +621,5 @@ tests/services/test_querysource_setup_pbac.py
|
|
|
621
621
|
tests/unit/test_cython_filter_fallback.py
|
|
622
622
|
tests/unit/test_datasource_redaction.py
|
|
623
623
|
tests/unit/test_provider_raw_query_validated.py
|
|
624
|
-
tests/unit/test_qs_parsers_validated.py
|
|
624
|
+
tests/unit/test_qs_parsers_validated.py
|
|
625
|
+
tests/unit/test_raw_query_cond_definition_wiring.py
|
|
@@ -595,6 +595,7 @@
|
|
|
595
595
|
"tests/unit/test_datasource_redaction.py",
|
|
596
596
|
"tests/unit/test_qs_parsers_validated.py",
|
|
597
597
|
"tests/unit/test_provider_raw_query_validated.py",
|
|
598
|
+
"tests/unit/test_raw_query_cond_definition_wiring.py",
|
|
598
599
|
"tests/interfaces/__init__.py",
|
|
599
600
|
"tests/interfaces/test_airtable_interface.py",
|
|
600
601
|
"sdd/WORKFLOW-parrot.md",
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
[package]
|
|
2
|
+
name = "qs_parsers"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
edition = "2021"
|
|
5
|
+
description = "Rust-based string processing for QuerySource parsers"
|
|
6
|
+
|
|
7
|
+
[lib]
|
|
8
|
+
name = "_qs_parsers"
|
|
9
|
+
crate-type = ["cdylib"]
|
|
10
|
+
|
|
11
|
+
[dependencies]
|
|
12
|
+
pyo3 = { version = "0.24" }
|
|
13
|
+
rayon = "1.10"
|
|
14
|
+
regex = "1.11"
|
|
15
|
+
once_cell = "1.20"
|
|
16
|
+
|
|
17
|
+
[dev-dependencies]
|
|
18
|
+
proptest = "1.4"
|
|
19
|
+
|
|
20
|
+
# `extension-module` tells PyO3 the symbols it needs (Py_InitializeEx, etc.)
|
|
21
|
+
# will be provided at dlopen time by an embedding Python process, so it must
|
|
22
|
+
# NOT link libpython itself. That's correct for the cdylib maturin builds,
|
|
23
|
+
# but it breaks `cargo test`, which links a normal executable and therefore
|
|
24
|
+
# needs those symbols resolved directly against libpython.
|
|
25
|
+
# Gate it behind a feature (on by default, so `cargo build`/`maturin build`
|
|
26
|
+
# are unaffected) and run tests with `cargo test --no-default-features`.
|
|
27
|
+
[features]
|
|
28
|
+
default = ["extension-module"]
|
|
29
|
+
extension-module = ["pyo3/extension-module"]
|
|
30
|
+
|
|
31
|
+
[profile.release]
|
|
32
|
+
opt-level = 3
|
|
33
|
+
lto = true
|
|
34
|
+
codegen-units = 1
|
|
@@ -487,4 +487,73 @@ mod tests {
|
|
|
487
487
|
// "xUNIONy" — UNION is NOT a standalone word → allow
|
|
488
488
|
assert!(check_injection("xUNIONy").is_ok());
|
|
489
489
|
}
|
|
490
|
+
|
|
491
|
+
// --- FEAT-103 cond_definition wiring tests ---
|
|
492
|
+
|
|
493
|
+
/// `array` hint in Bare context emits a pre-rendered list verbatim
|
|
494
|
+
/// (e.g. `IN ({ids})` with conditions={"ids": "'a','b','c'"}).
|
|
495
|
+
#[test]
|
|
496
|
+
fn cond_definition_array_hint_bare_context_passthrough() {
|
|
497
|
+
let r = safe_format_map_validated_rust(
|
|
498
|
+
"SELECT * FROM t WHERE id IN ({ids})",
|
|
499
|
+
&map(&[("ids", "'a','b','c'")]),
|
|
500
|
+
&map(&[("ids", "array")]),
|
|
501
|
+
)
|
|
502
|
+
.unwrap();
|
|
503
|
+
assert_eq!(r, "SELECT * FROM t WHERE id IN ('a','b','c')");
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
/// `array` hint does NOT bypass injection checks: check_injection runs
|
|
507
|
+
/// before the type-hint dispatch, so a `;`/comment/keyword payload is
|
|
508
|
+
/// still rejected even though the hint would otherwise pass the value
|
|
509
|
+
/// through unquoted.
|
|
510
|
+
#[test]
|
|
511
|
+
fn cond_definition_array_hint_rejects_injection_payload() {
|
|
512
|
+
let r = safe_format_map_validated_rust(
|
|
513
|
+
"SELECT * FROM t WHERE id IN ({ids})",
|
|
514
|
+
&map(&[("ids", "'a'); DROP TABLE t;--")]),
|
|
515
|
+
&map(&[("ids", "array")]),
|
|
516
|
+
);
|
|
517
|
+
assert!(r.is_err(), "Expected rejection of injection payload under array hint");
|
|
518
|
+
|
|
519
|
+
let r2 = safe_format_map_validated_rust(
|
|
520
|
+
"SELECT * FROM t WHERE id IN ({ids})",
|
|
521
|
+
&map(&[("ids", "1 UNION SELECT password FROM users")]),
|
|
522
|
+
&map(&[("ids", "array")]),
|
|
523
|
+
);
|
|
524
|
+
assert!(r2.is_err(), "Expected rejection of UNION payload under array hint");
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
/// cond_definition hints in upper case (as persisted by the Navigator
|
|
528
|
+
/// frontend) match the same as lower case.
|
|
529
|
+
#[test]
|
|
530
|
+
fn cond_definition_uppercase_hint_matches_lowercase() {
|
|
531
|
+
let upper = safe_format_map_validated_rust(
|
|
532
|
+
"WHERE id IN ({ids})",
|
|
533
|
+
&map(&[("ids", "'a','b'")]),
|
|
534
|
+
&map(&[("ids", "ARRAY")]),
|
|
535
|
+
)
|
|
536
|
+
.unwrap();
|
|
537
|
+
let lower = safe_format_map_validated_rust(
|
|
538
|
+
"WHERE id IN ({ids})",
|
|
539
|
+
&map(&[("ids", "'a','b'")]),
|
|
540
|
+
&map(&[("ids", "array")]),
|
|
541
|
+
)
|
|
542
|
+
.unwrap();
|
|
543
|
+
assert_eq!(upper, lower);
|
|
544
|
+
assert_eq!(upper, "WHERE id IN ('a','b')");
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
/// Regression: with an empty cond_definition (pre-fix behavior), a bare
|
|
548
|
+
/// placeholder still falls through to the generic quoting logic.
|
|
549
|
+
#[test]
|
|
550
|
+
fn cond_definition_empty_preserves_generic_quoting() {
|
|
551
|
+
let r = safe_format_map_validated_rust(
|
|
552
|
+
"WHERE tag = {tag}",
|
|
553
|
+
&map(&[("tag", "hello")]),
|
|
554
|
+
&map(&[]),
|
|
555
|
+
)
|
|
556
|
+
.unwrap();
|
|
557
|
+
assert_eq!(r, "WHERE tag = 'hello'");
|
|
558
|
+
}
|
|
490
559
|
}
|
|
@@ -250,7 +250,8 @@ pub fn to_unquoted(value: &str) -> String {
|
|
|
250
250
|
/// Mirrors `is_valid()` from validators.pyx.
|
|
251
251
|
/// Returns the properly formatted value for SQL inclusion.
|
|
252
252
|
///
|
|
253
|
-
/// Type dispatch
|
|
253
|
+
/// Type dispatch (case-insensitive — callers such as the Navigator frontend
|
|
254
|
+
/// persist `cond_definition` hints in upper case, e.g. `"STRING"`):
|
|
254
255
|
/// - `literal` → escape_string
|
|
255
256
|
/// - `integer`/`int`/`float`/`numeric`/`decimal` → unquoted
|
|
256
257
|
/// - `string`/`varchar`/`field` → quote_string(escape_string(v))
|
|
@@ -271,9 +272,10 @@ pub fn is_valid(
|
|
|
271
272
|
type_hint: Option<&str>,
|
|
272
273
|
noquote: bool,
|
|
273
274
|
) -> String {
|
|
274
|
-
// Type hint dispatch
|
|
275
|
+
// Type hint dispatch (case-insensitive)
|
|
275
276
|
if let Some(t) = type_hint {
|
|
276
|
-
|
|
277
|
+
let lowered = t.to_lowercase();
|
|
278
|
+
match lowered.as_str() {
|
|
277
279
|
"literal" => return escape_string(value),
|
|
278
280
|
"int" | "integer" | "float" | "numeric" | "decimal" | "epoch" => {
|
|
279
281
|
return to_unquoted(value);
|
|
@@ -416,6 +418,24 @@ mod tests {
|
|
|
416
418
|
assert_eq!(is_valid("x", "hello", Some("string"), false), "'hello'");
|
|
417
419
|
}
|
|
418
420
|
|
|
421
|
+
/// FEAT-103: cond_definition hints arrive upper-cased from the Navigator
|
|
422
|
+
/// frontend (`"STRING"`, `"INTEGER"`, `"BOOLEAN"`, `"ARRAY"`) — dispatch
|
|
423
|
+
/// must be case-insensitive.
|
|
424
|
+
#[test]
|
|
425
|
+
fn test_is_valid_uppercase_hint_matches_lowercase() {
|
|
426
|
+
assert_eq!(is_valid("x", "42", Some("INTEGER"), false), "42");
|
|
427
|
+
assert_eq!(is_valid("x", "hello", Some("STRING"), false), "'hello'");
|
|
428
|
+
assert_eq!(is_valid("x", "true", Some("BOOLEAN"), false), "TRUE");
|
|
429
|
+
assert_eq!(
|
|
430
|
+
is_valid("x", "'a','b','c'", Some("ARRAY"), false),
|
|
431
|
+
"'a','b','c'"
|
|
432
|
+
);
|
|
433
|
+
assert_eq!(
|
|
434
|
+
is_valid("x", "'a','b','c'", Some("array"), false),
|
|
435
|
+
is_valid("x", "'a','b','c'", Some("ARRAY"), false)
|
|
436
|
+
);
|
|
437
|
+
}
|
|
438
|
+
|
|
419
439
|
#[test]
|
|
420
440
|
fn test_is_valid_null() {
|
|
421
441
|
assert_eq!(is_valid("x", "null", None, false), "null");
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
"""Integration tests for cond_definition wiring in raw_query() (FEAT-103).
|
|
2
|
+
|
|
3
|
+
Prior to this fix, providers called
|
|
4
|
+
`safe_format_map_validated(sql, self._conditions, {})` with a hard-coded
|
|
5
|
+
empty dict, so the `cond_definition` type hints saved on a slug's
|
|
6
|
+
QueryModel (e.g. {"ids": "ARRAY"}) never reached the Rust validator and
|
|
7
|
+
had no effect on substitution.
|
|
8
|
+
|
|
9
|
+
These tests exercise the real `defaultProvider.raw_query()` (and, as a
|
|
10
|
+
cross-provider sanity check, `cassandraProvider.get_raw_query()`) against
|
|
11
|
+
a fixture QueryModel carrying `cond_definition`, verifying:
|
|
12
|
+
- the "array" type hint now takes effect (values pass through unquoted,
|
|
13
|
+
e.g. for a pre-rendered `IN (...)` list), fixing Bug 1;
|
|
14
|
+
- hints persisted in upper case (as the Navigator frontend does) are
|
|
15
|
+
honored the same as lower case, fixing Bug 2;
|
|
16
|
+
- the injection check still runs even when the "array" hint applies.
|
|
17
|
+
|
|
18
|
+
`BaseProvider.__init__` requires a running asyncio loop (it calls
|
|
19
|
+
`asyncio.get_running_loop()`), so provider-instantiating tests are
|
|
20
|
+
`async def` — `asyncio_mode = auto` (pytest.ini) runs them under one.
|
|
21
|
+
"""
|
|
22
|
+
import sys
|
|
23
|
+
import types
|
|
24
|
+
import logging as _stdlib_logging
|
|
25
|
+
|
|
26
|
+
import pytest
|
|
27
|
+
|
|
28
|
+
# Importing `querysource.providers.*` pulls in `navconfig.logging`, whose
|
|
29
|
+
# module-level init does a live socket check against LOGSTASH_HOST. In
|
|
30
|
+
# offline/sandboxed environments (no route to the internal logstash host)
|
|
31
|
+
# that raises `socket.gaierror` and aborts the import entirely. Only when
|
|
32
|
+
# the real import fails do we substitute a minimal stand-in — in a normal
|
|
33
|
+
# dev/CI environment (where the logstash host resolves or is disabled) this
|
|
34
|
+
# has no effect and the real navconfig.logging module is used untouched.
|
|
35
|
+
try:
|
|
36
|
+
import navconfig.logging # noqa: F401
|
|
37
|
+
except Exception:
|
|
38
|
+
_fake = types.ModuleType('navconfig.logging')
|
|
39
|
+
_fake.logging = _stdlib_logging
|
|
40
|
+
sys.modules['navconfig.logging'] = _fake
|
|
41
|
+
|
|
42
|
+
from querysource.providers.default import defaultProvider # noqa: E402
|
|
43
|
+
from querysource.providers.cassandra import cassandraProvider # noqa: E402
|
|
44
|
+
from querysource.providers.abstract import BaseProvider # noqa: E402
|
|
45
|
+
from querysource.models import QueryModel # noqa: E402
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def _slug_definition(query_raw: str, cond_definition: dict | None = None) -> QueryModel:
|
|
49
|
+
return QueryModel(
|
|
50
|
+
query_slug='test_slug',
|
|
51
|
+
query_raw=query_raw,
|
|
52
|
+
is_raw=True,
|
|
53
|
+
cond_definition=cond_definition or {},
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
# ---------------------------------------------------------------------------
|
|
58
|
+
# Bug 1 — cond_definition reaches the Rust validator
|
|
59
|
+
# ---------------------------------------------------------------------------
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
async def test_default_provider_array_hint_renders_prerendered_list():
|
|
63
|
+
"""Fixture scenario from the bug report: IN ({ids}) + ARRAY hint +
|
|
64
|
+
a pre-rendered '(...)' value substitutes verbatim (unquoted)."""
|
|
65
|
+
definition = _slug_definition(
|
|
66
|
+
"SELECT * FROM t WHERE id IN ({ids})",
|
|
67
|
+
cond_definition={"ids": "ARRAY"},
|
|
68
|
+
)
|
|
69
|
+
provider = defaultProvider(
|
|
70
|
+
slug='test_slug',
|
|
71
|
+
qstype='slug',
|
|
72
|
+
definition=definition,
|
|
73
|
+
conditions={"ids": "'a','b','c'"},
|
|
74
|
+
)
|
|
75
|
+
sql = provider.raw_query(provider._query)
|
|
76
|
+
assert sql == "SELECT * FROM t WHERE id IN ('a','b','c')"
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
async def test_default_provider_without_cond_definition_uses_generic_quoting():
|
|
80
|
+
"""Regression: no cond_definition (default {}) behaves like before the
|
|
81
|
+
fix — a bare placeholder still falls through to generic quoting."""
|
|
82
|
+
definition = _slug_definition("SELECT * FROM t WHERE tag = {tag}")
|
|
83
|
+
provider = defaultProvider(
|
|
84
|
+
slug='test_slug',
|
|
85
|
+
qstype='slug',
|
|
86
|
+
definition=definition,
|
|
87
|
+
conditions={"tag": "hello"},
|
|
88
|
+
)
|
|
89
|
+
sql = provider.raw_query(provider._query)
|
|
90
|
+
assert sql == "SELECT * FROM t WHERE tag = 'hello'"
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
async def test_cassandra_provider_also_wires_cond_definition():
|
|
94
|
+
"""Cross-provider check: the same _get_cond_definition() wiring is used
|
|
95
|
+
by every provider's raw_query/get_raw_query, not just Postgres."""
|
|
96
|
+
definition = _slug_definition(
|
|
97
|
+
"SELECT * FROM t WHERE id IN ({ids})",
|
|
98
|
+
cond_definition={"ids": "array"},
|
|
99
|
+
)
|
|
100
|
+
provider = cassandraProvider(
|
|
101
|
+
slug='test_slug',
|
|
102
|
+
qstype='slug',
|
|
103
|
+
definition=definition,
|
|
104
|
+
conditions={"ids": "'a','b','c'"},
|
|
105
|
+
)
|
|
106
|
+
sql = provider.get_raw_query(provider._query)
|
|
107
|
+
assert sql == "SELECT * FROM t WHERE id IN ('a','b','c')"
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
# ---------------------------------------------------------------------------
|
|
111
|
+
# Bug 2 — cond_definition hints are case-insensitive
|
|
112
|
+
# ---------------------------------------------------------------------------
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
@pytest.mark.parametrize("hint", ["ARRAY", "array", "Array"])
|
|
116
|
+
async def test_array_hint_matches_regardless_of_case(hint):
|
|
117
|
+
definition = _slug_definition(
|
|
118
|
+
"SELECT * FROM t WHERE id IN ({ids})",
|
|
119
|
+
cond_definition={"ids": hint},
|
|
120
|
+
)
|
|
121
|
+
provider = defaultProvider(
|
|
122
|
+
slug='test_slug',
|
|
123
|
+
qstype='slug',
|
|
124
|
+
definition=definition,
|
|
125
|
+
conditions={"ids": "'a','b','c'"},
|
|
126
|
+
)
|
|
127
|
+
sql = provider.raw_query(provider._query)
|
|
128
|
+
assert sql == "SELECT * FROM t WHERE id IN ('a','b','c')"
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
# ---------------------------------------------------------------------------
|
|
132
|
+
# Security — injection checks still run under an "array" hint
|
|
133
|
+
# ---------------------------------------------------------------------------
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
async def test_array_hint_does_not_bypass_injection_check():
|
|
137
|
+
definition = _slug_definition(
|
|
138
|
+
"SELECT * FROM t WHERE id IN ({ids})",
|
|
139
|
+
cond_definition={"ids": "ARRAY"},
|
|
140
|
+
)
|
|
141
|
+
provider = defaultProvider(
|
|
142
|
+
slug='test_slug',
|
|
143
|
+
qstype='slug',
|
|
144
|
+
definition=definition,
|
|
145
|
+
conditions={"ids": "'a'); DROP TABLE t;--"},
|
|
146
|
+
)
|
|
147
|
+
with pytest.raises(Exception):
|
|
148
|
+
provider.raw_query(provider._query)
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
# ---------------------------------------------------------------------------
|
|
152
|
+
# _get_cond_definition() helper — handles both QueryModel and plain-dict
|
|
153
|
+
# definitions, and normalizes a missing/None definition to {}.
|
|
154
|
+
# ---------------------------------------------------------------------------
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
async def test_get_cond_definition_from_query_model():
|
|
158
|
+
definition = _slug_definition("SELECT 1", cond_definition={"x": "INTEGER"})
|
|
159
|
+
provider = defaultProvider(slug='test_slug', qstype='slug', definition=definition, conditions={})
|
|
160
|
+
assert provider._get_cond_definition() == {"x": "INTEGER"}
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
class _ConcreteProvider(BaseProvider):
|
|
164
|
+
"""Minimal concrete subclass — BaseProvider.query() is abstract, so it
|
|
165
|
+
can't be instantiated (even via __new__) without a real implementation.
|
|
166
|
+
Only used here to exercise _get_cond_definition() in isolation, without
|
|
167
|
+
going through __init__ (and its event-loop/parser requirements)."""
|
|
168
|
+
|
|
169
|
+
async def query(self):
|
|
170
|
+
raise NotImplementedError
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def test_get_cond_definition_from_plain_dict():
|
|
174
|
+
provider = _ConcreteProvider.__new__(_ConcreteProvider)
|
|
175
|
+
provider._definition = {"cond_definition": {"x": "STRING"}}
|
|
176
|
+
assert provider._get_cond_definition() == {"x": "STRING"}
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def test_get_cond_definition_defaults_to_empty_dict():
|
|
180
|
+
provider = _ConcreteProvider.__new__(_ConcreteProvider)
|
|
181
|
+
provider._definition = None
|
|
182
|
+
assert provider._get_cond_definition() == {}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
[package]
|
|
2
|
-
name = "qs_parsers"
|
|
3
|
-
version = "0.1.0"
|
|
4
|
-
edition = "2021"
|
|
5
|
-
description = "Rust-based string processing for QuerySource parsers"
|
|
6
|
-
|
|
7
|
-
[lib]
|
|
8
|
-
name = "_qs_parsers"
|
|
9
|
-
crate-type = ["cdylib"]
|
|
10
|
-
|
|
11
|
-
[dependencies]
|
|
12
|
-
pyo3 = { version = "0.24", features = ["extension-module"] }
|
|
13
|
-
rayon = "1.10"
|
|
14
|
-
regex = "1.11"
|
|
15
|
-
once_cell = "1.20"
|
|
16
|
-
|
|
17
|
-
[dev-dependencies]
|
|
18
|
-
proptest = "1.4"
|
|
19
|
-
|
|
20
|
-
[profile.release]
|
|
21
|
-
opt-level = 3
|
|
22
|
-
lto = true
|
|
23
|
-
codegen-units = 1
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|