data-flow-control 0.1.4__tar.gz → 0.1.6__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (176) hide show
  1. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/Cargo.lock +3 -3
  2. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/Cargo.toml +1 -1
  3. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/PKG-INFO +2 -1
  4. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/src/aggregate_registry.rs +2 -0
  5. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/src/full_push.rs +7 -1
  6. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/src/rewrite_strategy.rs +64 -17
  7. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/src/rewriter/aggregates.rs +3 -0
  8. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/src/rewriter/plan/mod.rs +81 -0
  9. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/src/rewriter/policy_expr.rs +34 -0
  10. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/src/rewriter/resolution.rs +8 -9
  11. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/tests/gaps/insert_shapes.rs +4 -1
  12. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/tests/rewrite/scan.rs +4 -1
  13. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/pyproject.toml +2 -1
  14. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/LICENSE +0 -0
  15. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/Cargo.toml +0 -0
  16. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/benches/rewrite_perf.rs +0 -0
  17. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/src/catalog.rs +0 -0
  18. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/src/diagnostics.rs +0 -0
  19. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/src/explain.rs +0 -0
  20. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/src/identifiers.rs +0 -0
  21. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/src/intern.rs +0 -0
  22. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/src/ir.rs +0 -0
  23. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/src/lib.rs +0 -0
  24. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/src/optimizer.rs +0 -0
  25. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/src/parser.rs +0 -0
  26. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/src/partial_push.rs +0 -0
  27. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/src/planner.rs +0 -0
  28. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/src/policy.rs +0 -0
  29. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/src/policy_compile.rs +0 -0
  30. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/src/policy_index.rs +0 -0
  31. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/src/policy_parser.rs +0 -0
  32. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/src/policy_pgn.pest +0 -0
  33. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/src/policy_store/branch.rs +0 -0
  34. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/src/policy_store/compiled.rs +0 -0
  35. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/src/policy_store/delete.rs +0 -0
  36. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/src/policy_store/indexes.rs +0 -0
  37. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/src/policy_store/memory.rs +0 -0
  38. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/src/policy_store/mod.rs +0 -0
  39. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/src/query_analysis.rs +0 -0
  40. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/src/rewrite_stats.rs +0 -0
  41. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/src/rewriter/columns.rs +0 -0
  42. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/src/rewriter/constraint_preprocess.rs +0 -0
  43. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/src/rewriter/derived_policy.rs +0 -0
  44. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/src/rewriter/dimensions.rs +0 -0
  45. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/src/rewriter/exists.rs +0 -0
  46. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/src/rewriter/expr.rs +0 -0
  47. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/src/rewriter/helpers.rs +0 -0
  48. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/src/rewriter/limit.rs +0 -0
  49. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/src/rewriter/mod.rs +0 -0
  50. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/src/rewriter/plan/actions.rs +0 -0
  51. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/src/rewriter/plan/applicability.rs +0 -0
  52. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/src/rewriter/plan/dominance.rs +0 -0
  53. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/src/rewriter/plan/scope_plan.rs +0 -0
  54. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/src/rewriter/plan/write_plan.rs +0 -0
  55. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/src/rewriter/projection.rs +0 -0
  56. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/src/rewriter/scope.rs +0 -0
  57. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/src/rewriter/select.rs +1 -1
  58. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/src/rewriter/types.rs +0 -0
  59. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/src/rewriter/write_path.rs +0 -0
  60. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/src/semiring.rs +0 -0
  61. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/src/source_set_index.rs +0 -0
  62. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/src/source_sets/analysis.rs +0 -0
  63. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/src/source_sets/annotations.rs +0 -0
  64. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/src/source_sets/branch.rs +0 -0
  65. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/src/source_sets/mod.rs +0 -0
  66. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/src/source_sets/rewrites.rs +0 -0
  67. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/src/source_sets/split.rs +0 -0
  68. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/src/sql/ast_stats.rs +0 -0
  69. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/src/sql/builders.rs +0 -0
  70. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/src/sql/columns.rs +0 -0
  71. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/src/sql/dialect.rs +0 -0
  72. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/src/sql/expr.rs +0 -0
  73. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/src/sql/expr_key.rs +0 -0
  74. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/src/sql/mod.rs +0 -0
  75. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/src/sql/parse.rs +0 -0
  76. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/src/sql/render.rs +0 -0
  77. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/src/statement_tables.rs +0 -0
  78. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/src/threshold.rs +0 -0
  79. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/tests/common/duckdb.rs +0 -0
  80. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/tests/common/mod.rs +0 -0
  81. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/tests/completion/conformance.rs +0 -0
  82. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/tests/completion/main.rs +0 -0
  83. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/tests/completion/partial_push.rs +0 -0
  84. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/tests/completion/pgn.rs +0 -0
  85. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/tests/completion/pgn_unique.rs +0 -0
  86. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/tests/completion/policy_storage.rs +0 -0
  87. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/tests/completion/rewrite_api_parity.rs +0 -0
  88. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/tests/completion/semiring.rs +0 -0
  89. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/tests/completion/source_sets.rs +0 -0
  90. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/tests/completion/symmetric_self_join.rs +0 -0
  91. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/tests/completion/threshold.rs +0 -0
  92. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/tests/completion/unique_not_unique.rs +0 -0
  93. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/tests/dialect.rs +0 -0
  94. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/tests/execution/insert.rs +0 -0
  95. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/tests/execution/kill.rs +0 -0
  96. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/tests/execution/main.rs +0 -0
  97. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/tests/execution/oracle.rs +0 -0
  98. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/tests/execution/remove.rs +0 -0
  99. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/tests/execution/update.rs +0 -0
  100. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/tests/expected/duckdb/remove_scan.sql +0 -0
  101. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/tests/expected/postgres/remove_scan.sql +0 -0
  102. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/tests/expected/sqlite/remove_scan.sql +0 -0
  103. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/tests/explain_strategy.rs +0 -0
  104. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/tests/gaps/column_propagation.rs +0 -0
  105. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/tests/gaps/dimensions.rs +0 -0
  106. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/tests/gaps/exists_join.rs +0 -0
  107. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/tests/gaps/having_where.rs +0 -0
  108. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/tests/gaps/identifiers.rs +0 -0
  109. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/tests/gaps/main.rs +0 -0
  110. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/tests/gaps/multi_source.rs +0 -0
  111. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/tests/gaps/operators.rs +0 -0
  112. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/tests/gaps/query_shapes.rs +0 -0
  113. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/tests/gaps/scalar_subquery.rs +0 -0
  114. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/tests/indexed_candidate_differential.rs +0 -0
  115. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/tests/insert_values_body.rs +0 -0
  116. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/tests/paper_examples.rs +0 -0
  117. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/tests/parser.rs +0 -0
  118. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/tests/planner.rs +0 -0
  119. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/tests/policy.rs +0 -0
  120. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/tests/policy_dialect.rs +0 -0
  121. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/tests/policy_store_memory.rs +0 -0
  122. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/tests/rewrite/derived_policy.rs +0 -0
  123. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/tests/rewrite/in_semijoin.rs +0 -0
  124. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/tests/rewrite/insert.rs +0 -0
  125. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/tests/rewrite/joins.rs +0 -0
  126. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/tests/rewrite/main.rs +0 -0
  127. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/tests/rewrite/output.rs +0 -0
  128. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/tests/rewrite/recursive.rs +0 -0
  129. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/tests/rewrite/update.rs +0 -0
  130. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/tests/rewrite_candidate_regression.rs +0 -0
  131. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/tests/rewrite_fast_paths.rs +0 -0
  132. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/tests/rewrite_large_registry.rs +0 -0
  133. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/tests/rewrite_stats_timings.rs +0 -0
  134. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/tests/scan_ready_expr.rs +0 -0
  135. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/tests/source_set_split_no_parse.rs +0 -0
  136. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/tests/sql_builders.rs +0 -0
  137. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/tests/sql_columns.rs +0 -0
  138. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-core/tests/ui_resolution.rs +0 -0
  139. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-py/Cargo.toml +0 -0
  140. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-py/src/bindings/catalog.rs +0 -0
  141. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-py/src/bindings/errors.rs +0 -0
  142. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-py/src/bindings/mod.rs +0 -0
  143. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-py/src/bindings/planner.rs +0 -0
  144. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-py/src/bindings/policy.rs +0 -0
  145. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-py/src/bindings/stats.rs +0 -0
  146. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/passant-py/src/lib.rs +0 -0
  147. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/python/data_flow_control/__init__.py +0 -0
  148. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/python/data_flow_control/_rust.py +0 -0
  149. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/python/data_flow_control/adapters/__init__.py +0 -0
  150. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/python/data_flow_control/adapters/base.py +0 -0
  151. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/python/data_flow_control/adapters/clickhouse.py +0 -0
  152. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/python/data_flow_control/adapters/datafusion.py +0 -0
  153. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/python/data_flow_control/adapters/duckdb.py +0 -0
  154. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/python/data_flow_control/adapters/kill.py +0 -0
  155. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/python/data_flow_control/adapters/pg_catalog.py +0 -0
  156. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/python/data_flow_control/adapters/postgres.py +0 -0
  157. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/python/data_flow_control/adapters/registry.py +0 -0
  158. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/python/data_flow_control/adapters/sqlite.py +0 -0
  159. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/python/data_flow_control/adapters/umbra.py +0 -0
  160. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/python/data_flow_control/aggregate_introspection.py +0 -0
  161. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/python/data_flow_control/catalog.py +0 -0
  162. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/python/data_flow_control/connection.py +0 -0
  163. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/python/data_flow_control/dialect.py +0 -0
  164. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/python/data_flow_control/langchain/__init__.py +0 -0
  165. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/python/data_flow_control/langchain/agent.py +0 -0
  166. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/python/data_flow_control/langchain/call_tool_with_dataflow.py +0 -0
  167. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/python/data_flow_control/langchain/database.py +0 -0
  168. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/python/data_flow_control/langchain/middleware.py +0 -0
  169. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/python/data_flow_control/langchain/schema.py +0 -0
  170. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/python/data_flow_control/langchain/sql_validation.py +0 -0
  171. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/python/data_flow_control/langchain/tool_spec.py +0 -0
  172. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/python/data_flow_control/langchain/wrapper.py +0 -0
  173. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/python/data_flow_control/options.py +0 -0
  174. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/python/data_flow_control/planner.py +0 -0
  175. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/python/data_flow_control/policy.py +0 -0
  176. {data_flow_control-0.1.4 → data_flow_control-0.1.6}/python/data_flow_control/ui.py +0 -0
@@ -1593,7 +1593,7 @@ dependencies = [
1593
1593
 
1594
1594
  [[package]]
1595
1595
  name = "passant-cli"
1596
- version = "0.1.4"
1596
+ version = "0.1.6"
1597
1597
  dependencies = [
1598
1598
  "anyhow",
1599
1599
  "assert_cmd",
@@ -1605,7 +1605,7 @@ dependencies = [
1605
1605
 
1606
1606
  [[package]]
1607
1607
  name = "passant-core"
1608
- version = "0.1.4"
1608
+ version = "0.1.6"
1609
1609
  dependencies = [
1610
1610
  "anyhow",
1611
1611
  "criterion",
@@ -1623,7 +1623,7 @@ dependencies = [
1623
1623
 
1624
1624
  [[package]]
1625
1625
  name = "passant-py"
1626
- version = "0.1.4"
1626
+ version = "0.1.6"
1627
1627
  dependencies = [
1628
1628
  "passant-core",
1629
1629
  "pyo3",
@@ -3,7 +3,7 @@ members = ["passant-core", "passant-py"]
3
3
  resolver = "2"
4
4
 
5
5
  [workspace.package]
6
- version = "0.1.4"
6
+ version = "0.1.6"
7
7
  edition = "2024"
8
8
  license = "MIT"
9
9
  authors = ["Charlie Summers"]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: data-flow-control
3
- Version: 0.1.4
3
+ Version: 0.1.6
4
4
  Requires-Dist: boto3>=1.26.0
5
5
  Requires-Dist: duckdb>=1.3.0
6
6
  Requires-Dist: langchain>=1.3,<2
@@ -11,6 +11,7 @@ Requires-Dist: clickhouse-connect>=0.7.0 ; extra == 'clickhouse'
11
11
  Requires-Dist: datafusion>=53.0.0 ; extra == 'datafusion'
12
12
  Requires-Dist: pyarrow>=14.0.0 ; extra == 'datafusion'
13
13
  Requires-Dist: maturin>=1.7.0 ; extra == 'dev'
14
+ Requires-Dist: pre-commit>=4.0.0 ; extra == 'dev'
14
15
  Requires-Dist: pytest>=8.4.2 ; extra == 'dev'
15
16
  Requires-Dist: ruff>=0.11.0 ; extra == 'dev'
16
17
  Requires-Dist: psycopg[binary]>=3.2.0 ; extra == 'postgres'
@@ -167,6 +167,8 @@ impl AggregateRegistry {
167
167
  || lower.contains("countif")
168
168
  || lower.contains("approx_count_distinct")
169
169
  || lower.contains("approx_distinct")
170
+ || lower == "arbitrary"
171
+ || lower == "any_value"
170
172
  || is_count_like_name(&lower)
171
173
  }
172
174
 
@@ -18,6 +18,10 @@ fn semiring_allows_full_push(rewriter: &PassantRewriter, semiring: &SemiringAnal
18
18
  .all(|aggregate| count_if_style_scan_aggregate(rewriter, aggregate))
19
19
  }
20
20
 
21
+ fn aggregate_function_name(aggregate: &str) -> &str {
22
+ aggregate.split('(').next().unwrap_or(aggregate).trim()
23
+ }
24
+
21
25
  fn count_if_style_scan_aggregate(rewriter: &PassantRewriter, aggregate: &str) -> bool {
22
26
  let lower = aggregate.to_ascii_lowercase();
23
27
  if lower.contains("array_agg")
@@ -27,7 +31,9 @@ fn count_if_style_scan_aggregate(rewriter: &PassantRewriter, aggregate: &str) ->
27
31
  {
28
32
  return false;
29
33
  }
30
- rewriter.aggregate_registry.is_scan_transformable(aggregate)
34
+ rewriter
35
+ .aggregate_registry
36
+ .is_scan_transformable(aggregate_function_name(&lower))
31
37
  }
32
38
 
33
39
  /// Full-push engine — mutates the query in place, preserving its overall shape.
@@ -377,24 +377,71 @@ mod tests {
377
377
  }
378
378
 
379
379
  #[test]
380
- fn non_distributive_policy_uses_partial_push() {
380
+ fn introspected_arbitrary_in_catalog_still_rewrites_kill_insert() {
381
+ use crate::aggregate_registry::AggregateFunctionSnapshot;
382
+ use crate::catalog::{CatalogSnapshot, CatalogTableInfo};
383
+ use std::collections::HashMap;
384
+
385
+ let policy_text = "SOURCE Receipts SINK Expenses CONSTRAINT ARBITRARY(Receipts.cat) != 'Meal' OR Expenses.biz_use <= 50.0 ON FAIL KILL";
386
+ let sql = "INSERT INTO Expenses SELECT 1, 100.0 FROM Receipts";
387
+
381
388
  let mut rewriter = PassantRewriter::new();
382
- rewriter.register_policy(non_distributive_policy());
383
- let statement = sqlparser::parser::Parser::parse_sql(
384
- &sqlparser::dialect::GenericDialect {},
385
- "SELECT id FROM foo",
386
- )
387
- .expect("parse")
388
- .pop()
389
- .expect("statement");
390
- let request = RewriteRequest::analyze(
391
- "SELECT id FROM foo",
392
- &statement,
393
- RewriteOptions::default(),
394
- rewriter.policy_store(),
389
+ rewriter
390
+ .register_validated_policy(crate::parse_policy_text(policy_text).expect("parse"))
391
+ .expect("register without catalog");
392
+ let without_catalog = rewriter.rewrite(sql).expect("rewrite without catalog");
393
+ assert!(
394
+ without_catalog.contains("passant_kill"),
395
+ "baseline rewrite without catalog introspection: {without_catalog}"
396
+ );
397
+
398
+ let mut tables = HashMap::new();
399
+ tables.insert(
400
+ "Receipts".to_string(),
401
+ CatalogTableInfo {
402
+ columns: vec!["cat".into(), "biz_use".into()],
403
+ ..CatalogTableInfo::default()
404
+ },
405
+ );
406
+ tables.insert(
407
+ "Expenses".to_string(),
408
+ CatalogTableInfo {
409
+ columns: vec!["biz_use".into()],
410
+ ..CatalogTableInfo::default()
411
+ },
412
+ );
413
+ let mut rewriter = PassantRewriter::new();
414
+ rewriter.apply_catalog_snapshot(CatalogSnapshot {
415
+ dialect: Some("duckdb".to_string()),
416
+ tables,
417
+ aggregate_functions: vec![AggregateFunctionSnapshot {
418
+ name: "arbitrary".to_string(),
419
+ schema: None,
420
+ aliases: vec![],
421
+ classification: None,
422
+ source: Some("introspected".to_string()),
423
+ }],
424
+ ..CatalogSnapshot::default()
425
+ });
426
+ rewriter
427
+ .register_validated_policy(crate::parse_policy_text(policy_text).expect("parse"))
428
+ .expect("register validated policy");
429
+ assert!(
430
+ rewriter
431
+ .policy_store()
432
+ .has_enforcement_resolution_policies(),
433
+ "KILL policy should register as enforcement resolution"
434
+ );
435
+ assert_eq!(rewriter.policy_store().active_count(), 1);
436
+ let with_catalog = rewriter.rewrite(sql);
437
+ if let Err(err) = &with_catalog {
438
+ panic!("rewrite with catalog failed: {err}");
439
+ }
440
+ let with_catalog = with_catalog.expect("rewrite ok");
441
+ let summary = rewriter.last_statement_rewrite_summary();
442
+ assert!(
443
+ with_catalog.contains("passant_kill"),
444
+ "expected kill rewrite with introspected arbitrary aggregate, got: {with_catalog}; summary={summary:?}"
395
445
  );
396
- assert!(!request.semiring.all_distributive);
397
- assert!(!FullPushEngine.matches(&rewriter, &request));
398
- assert!(PartialPushEngine.matches(&rewriter, &request));
399
446
  }
400
447
  }
@@ -130,6 +130,9 @@ fn count_distinct_inner_column(expr: &Expr) -> Option<Expr> {
130
130
  }
131
131
 
132
132
  fn transform_scan_aggregates_recursive(expr: Expr, registry: &AggregateRegistry) -> Expr {
133
+ if let Ok(Some(rewritten)) = rewrite_count_distinct_equality(&expr) {
134
+ return rewritten;
135
+ }
133
136
  if let Expr::BinaryOp {
134
137
  left,
135
138
  op: BinaryOperator::Divide,
@@ -120,4 +120,85 @@ mod tests {
120
120
  assert_eq!(summary.scope_diagnostics.len(), 2);
121
121
  assert_eq!(summary.aggregate().candidate_policies, 2);
122
122
  }
123
+
124
+ #[test]
125
+ fn kill_policy_with_introspected_arbitrary_emits_tuple_action() {
126
+ use crate::aggregate_registry::AggregateFunctionSnapshot;
127
+ use crate::catalog::{CatalogSnapshot, CatalogTableInfo};
128
+ use std::collections::HashMap;
129
+
130
+ let mut tables = HashMap::new();
131
+ tables.insert(
132
+ "Receipts".to_string(),
133
+ CatalogTableInfo {
134
+ columns: vec!["cat".into()],
135
+ ..CatalogTableInfo::default()
136
+ },
137
+ );
138
+ tables.insert(
139
+ "Expenses".to_string(),
140
+ CatalogTableInfo {
141
+ columns: vec!["biz_use".into()],
142
+ ..CatalogTableInfo::default()
143
+ },
144
+ );
145
+ let mut rewriter = PassantRewriter::new();
146
+ rewriter.apply_catalog_snapshot(CatalogSnapshot {
147
+ dialect: Some("duckdb".to_string()),
148
+ tables,
149
+ aggregate_functions: vec![AggregateFunctionSnapshot {
150
+ name: "arbitrary".to_string(),
151
+ schema: None,
152
+ aliases: vec![],
153
+ classification: None,
154
+ source: Some("introspected".to_string()),
155
+ }],
156
+ ..CatalogSnapshot::default()
157
+ });
158
+ rewriter
159
+ .register_validated_policy(
160
+ crate::parse_policy_text(
161
+ "SOURCE Receipts SINK Expenses CONSTRAINT ARBITRARY(Receipts.cat) != 'Meal' OR Expenses.biz_use <= 50.0 ON FAIL KILL",
162
+ )
163
+ .expect("parse"),
164
+ )
165
+ .expect("register");
166
+ let statement =
167
+ crate::parser::parse_query("INSERT INTO Expenses SELECT 1, 100.0 FROM Receipts")
168
+ .expect("parse");
169
+ let sqlparser::ast::Statement::Insert(insert) = statement else {
170
+ panic!("expected insert");
171
+ };
172
+ let Some(mut query) = insert.source else {
173
+ panic!("expected insert source");
174
+ };
175
+ let sqlparser::ast::SetExpr::Select(select) = query.body.as_mut() else {
176
+ panic!("expected select");
177
+ };
178
+ let analysis = SelectAnalysis::from_select(select);
179
+ let context = RewriteContext {
180
+ sink: Some("Expenses".to_string()),
181
+ sink_expr_by_column: HashMap::from([(
182
+ "biz_use".to_string(),
183
+ sqlparser::ast::Expr::Value(sqlparser::ast::Value::Number("100.0".into(), false)),
184
+ )]),
185
+ ..RewriteContext::default()
186
+ };
187
+ let plan = plan_select_rewrite(
188
+ rewriter.policy_store(),
189
+ rewriter.catalog(),
190
+ None,
191
+ select.as_mut(),
192
+ &analysis,
193
+ &context,
194
+ &HashSet::new(),
195
+ )
196
+ .expect("plan should succeed");
197
+ assert_eq!(
198
+ plan.policy_actions.len(),
199
+ 1,
200
+ "expected one kill action, diagnostics={:?}",
201
+ plan.diagnostics
202
+ );
203
+ }
123
204
  }
@@ -433,7 +433,41 @@ pub(crate) fn scan_policy_expr(
433
433
  )?,
434
434
  ));
435
435
  }
436
+ if let Expr::BinaryOp {
437
+ left,
438
+ op: BinaryOperator::Or,
439
+ right,
440
+ } = &expr
441
+ {
442
+ return Ok(Expr::BinaryOp {
443
+ left: Box::new(scan_policy_expr(
444
+ *left.clone(),
445
+ sources,
446
+ context,
447
+ alias_by_base,
448
+ scan_ready,
449
+ is_aggregation,
450
+ )?),
451
+ op: BinaryOperator::Or,
452
+ right: Box::new(scan_policy_expr(
453
+ *right.clone(),
454
+ sources,
455
+ context,
456
+ alias_by_base,
457
+ scan_ready,
458
+ is_aggregation,
459
+ )?),
460
+ });
461
+ }
436
462
  let registry = &context.aggregate_registry;
463
+ if !scan_ready {
464
+ let transformed = transform_scan_aggregates(expr.clone(), registry)?;
465
+ if !registry.expr_contains_aggregate(&transformed) {
466
+ let mut transformed = transformed;
467
+ rewrite_column_qualifiers(&mut transformed, alias_by_base);
468
+ return Ok(transformed);
469
+ }
470
+ }
437
471
  let non_distributive = non_distributive_aggregates(&expr, registry)?;
438
472
  if non_distributive.is_empty() {
439
473
  if scan_ready {
@@ -60,17 +60,13 @@ fn is_kill_wrapped_select(select: &Select) -> bool {
60
60
  if select.projection.len() != 1 {
61
61
  return false;
62
62
  }
63
- if !matches!(
64
- select.projection.first(),
65
- Some(SelectItem::Wildcard(_))
66
- ) {
63
+ if !matches!(select.projection.first(), Some(SelectItem::Wildcard(_))) {
67
64
  return false;
68
65
  }
69
66
  let Some(TableWithJoins {
70
- relation:
71
- TableFactor::Derived {
72
- alias: Some(alias), ..
73
- },
67
+ relation: TableFactor::Derived {
68
+ alias: Some(alias), ..
69
+ },
74
70
  joins,
75
71
  ..
76
72
  }) = select.from.first()
@@ -753,7 +749,10 @@ mod tests {
753
749
  remap_query_order_by_after_kill_wrap(&mut query);
754
750
 
755
751
  let sql = render_statement(&crate::sql::statement_from_query(query), None);
756
- assert!(sql.contains("ORDER BY id"), "expected unqualified ORDER BY: {sql}");
752
+ assert!(
753
+ sql.contains("ORDER BY id"),
754
+ "expected unqualified ORDER BY: {sql}"
755
+ );
757
756
  assert!(
758
757
  !sql.contains("ORDER BY receipts."),
759
758
  "qualified ORDER BY should be remapped: {sql}"
@@ -88,7 +88,10 @@ fn insert_select_kill_order_by_remapped() {
88
88
  reports_catalog(),
89
89
  );
90
90
  assert!(sql.contains("passant_kill"), "expected kill wrap: {sql}");
91
- assert!(sql.contains("ORDER BY id"), "expected unqualified ORDER BY: {sql}");
91
+ assert!(
92
+ sql.contains("ORDER BY id"),
93
+ "expected unqualified ORDER BY: {sql}"
94
+ );
92
95
  assert!(
93
96
  !sql.contains("ORDER BY Receipts."),
94
97
  "qualified ORDER BY should be remapped: {sql}"
@@ -269,7 +269,10 @@ fn select_kill_order_by_remapped() {
269
269
  .rewrite("SELECT id FROM foo ORDER BY foo.id")
270
270
  .expect("query should rewrite");
271
271
  assert!(sql.contains("passant_kill"), "expected kill wrap: {sql}");
272
- assert!(sql.contains("ORDER BY id"), "expected unqualified ORDER BY: {sql}");
272
+ assert!(
273
+ sql.contains("ORDER BY id"),
274
+ "expected unqualified ORDER BY: {sql}"
275
+ );
273
276
  assert!(
274
277
  !sql.contains("ORDER BY foo."),
275
278
  "qualified ORDER BY should be remapped: {sql}"
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "data-flow-control"
3
- version = "0.1.4"
3
+ version = "0.1.6"
4
4
  description = "Rust-backed Data Flow Control rewrite engine"
5
5
  license = "MIT"
6
6
  license-files = ["LICENSE"]
@@ -17,6 +17,7 @@ dependencies = [
17
17
  [project.optional-dependencies]
18
18
  dev = [
19
19
  "maturin>=1.7.0",
20
+ "pre-commit>=4.0.0",
20
21
  "pytest>=8.4.2",
21
22
  "ruff>=0.11.0",
22
23
  ]
@@ -20,8 +20,8 @@ use super::derived_policy::{
20
20
  use super::exists::apply_in_semijoin_policy_filters;
21
21
  use super::helpers::select_output_column_mapping;
22
22
  use super::limit::wrap_limited_policy_query;
23
- use super::resolution::remap_query_order_by_after_kill_wrap;
24
23
  use super::plan::{apply_select_rewrite_plan, plan_select_rewrite};
24
+ use super::resolution::remap_query_order_by_after_kill_wrap;
25
25
  use super::types::{PassantRewriter, RewriteContext};
26
26
 
27
27
  impl PassantRewriter {