data-flow-control 0.1.5__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.5 → data_flow_control-0.1.6}/Cargo.lock +3 -3
  2. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/Cargo.toml +1 -1
  3. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/PKG-INFO +1 -1
  4. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/src/aggregate_registry.rs +2 -0
  5. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/src/full_push.rs +7 -1
  6. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/src/rewrite_strategy.rs +64 -17
  7. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/src/rewriter/aggregates.rs +3 -0
  8. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/src/rewriter/plan/mod.rs +81 -0
  9. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/src/rewriter/policy_expr.rs +34 -0
  10. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/pyproject.toml +1 -1
  11. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/LICENSE +0 -0
  12. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/Cargo.toml +0 -0
  13. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/benches/rewrite_perf.rs +0 -0
  14. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/src/catalog.rs +0 -0
  15. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/src/diagnostics.rs +0 -0
  16. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/src/explain.rs +0 -0
  17. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/src/identifiers.rs +0 -0
  18. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/src/intern.rs +0 -0
  19. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/src/ir.rs +0 -0
  20. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/src/lib.rs +0 -0
  21. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/src/optimizer.rs +0 -0
  22. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/src/parser.rs +0 -0
  23. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/src/partial_push.rs +0 -0
  24. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/src/planner.rs +0 -0
  25. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/src/policy.rs +0 -0
  26. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/src/policy_compile.rs +0 -0
  27. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/src/policy_index.rs +0 -0
  28. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/src/policy_parser.rs +0 -0
  29. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/src/policy_pgn.pest +0 -0
  30. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/src/policy_store/branch.rs +0 -0
  31. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/src/policy_store/compiled.rs +0 -0
  32. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/src/policy_store/delete.rs +0 -0
  33. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/src/policy_store/indexes.rs +0 -0
  34. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/src/policy_store/memory.rs +0 -0
  35. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/src/policy_store/mod.rs +0 -0
  36. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/src/query_analysis.rs +0 -0
  37. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/src/rewrite_stats.rs +0 -0
  38. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/src/rewriter/columns.rs +0 -0
  39. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/src/rewriter/constraint_preprocess.rs +0 -0
  40. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/src/rewriter/derived_policy.rs +0 -0
  41. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/src/rewriter/dimensions.rs +0 -0
  42. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/src/rewriter/exists.rs +0 -0
  43. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/src/rewriter/expr.rs +0 -0
  44. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/src/rewriter/helpers.rs +0 -0
  45. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/src/rewriter/limit.rs +0 -0
  46. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/src/rewriter/mod.rs +0 -0
  47. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/src/rewriter/plan/actions.rs +0 -0
  48. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/src/rewriter/plan/applicability.rs +0 -0
  49. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/src/rewriter/plan/dominance.rs +0 -0
  50. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/src/rewriter/plan/scope_plan.rs +0 -0
  51. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/src/rewriter/plan/write_plan.rs +0 -0
  52. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/src/rewriter/projection.rs +0 -0
  53. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/src/rewriter/resolution.rs +0 -0
  54. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/src/rewriter/scope.rs +0 -0
  55. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/src/rewriter/select.rs +0 -0
  56. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/src/rewriter/types.rs +0 -0
  57. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/src/rewriter/write_path.rs +0 -0
  58. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/src/semiring.rs +0 -0
  59. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/src/source_set_index.rs +0 -0
  60. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/src/source_sets/analysis.rs +0 -0
  61. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/src/source_sets/annotations.rs +0 -0
  62. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/src/source_sets/branch.rs +0 -0
  63. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/src/source_sets/mod.rs +0 -0
  64. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/src/source_sets/rewrites.rs +0 -0
  65. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/src/source_sets/split.rs +0 -0
  66. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/src/sql/ast_stats.rs +0 -0
  67. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/src/sql/builders.rs +0 -0
  68. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/src/sql/columns.rs +0 -0
  69. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/src/sql/dialect.rs +0 -0
  70. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/src/sql/expr.rs +0 -0
  71. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/src/sql/expr_key.rs +0 -0
  72. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/src/sql/mod.rs +0 -0
  73. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/src/sql/parse.rs +0 -0
  74. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/src/sql/render.rs +0 -0
  75. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/src/statement_tables.rs +0 -0
  76. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/src/threshold.rs +0 -0
  77. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/tests/common/duckdb.rs +0 -0
  78. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/tests/common/mod.rs +0 -0
  79. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/tests/completion/conformance.rs +0 -0
  80. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/tests/completion/main.rs +0 -0
  81. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/tests/completion/partial_push.rs +0 -0
  82. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/tests/completion/pgn.rs +0 -0
  83. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/tests/completion/pgn_unique.rs +0 -0
  84. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/tests/completion/policy_storage.rs +0 -0
  85. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/tests/completion/rewrite_api_parity.rs +0 -0
  86. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/tests/completion/semiring.rs +0 -0
  87. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/tests/completion/source_sets.rs +0 -0
  88. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/tests/completion/symmetric_self_join.rs +0 -0
  89. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/tests/completion/threshold.rs +0 -0
  90. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/tests/completion/unique_not_unique.rs +0 -0
  91. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/tests/dialect.rs +0 -0
  92. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/tests/execution/insert.rs +0 -0
  93. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/tests/execution/kill.rs +0 -0
  94. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/tests/execution/main.rs +0 -0
  95. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/tests/execution/oracle.rs +0 -0
  96. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/tests/execution/remove.rs +0 -0
  97. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/tests/execution/update.rs +0 -0
  98. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/tests/expected/duckdb/remove_scan.sql +0 -0
  99. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/tests/expected/postgres/remove_scan.sql +0 -0
  100. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/tests/expected/sqlite/remove_scan.sql +0 -0
  101. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/tests/explain_strategy.rs +0 -0
  102. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/tests/gaps/column_propagation.rs +0 -0
  103. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/tests/gaps/dimensions.rs +0 -0
  104. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/tests/gaps/exists_join.rs +0 -0
  105. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/tests/gaps/having_where.rs +0 -0
  106. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/tests/gaps/identifiers.rs +0 -0
  107. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/tests/gaps/insert_shapes.rs +0 -0
  108. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/tests/gaps/main.rs +0 -0
  109. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/tests/gaps/multi_source.rs +0 -0
  110. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/tests/gaps/operators.rs +0 -0
  111. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/tests/gaps/query_shapes.rs +0 -0
  112. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/tests/gaps/scalar_subquery.rs +0 -0
  113. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/tests/indexed_candidate_differential.rs +0 -0
  114. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/tests/insert_values_body.rs +0 -0
  115. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/tests/paper_examples.rs +0 -0
  116. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/tests/parser.rs +0 -0
  117. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/tests/planner.rs +0 -0
  118. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/tests/policy.rs +0 -0
  119. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/tests/policy_dialect.rs +0 -0
  120. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/tests/policy_store_memory.rs +0 -0
  121. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/tests/rewrite/derived_policy.rs +0 -0
  122. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/tests/rewrite/in_semijoin.rs +0 -0
  123. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/tests/rewrite/insert.rs +0 -0
  124. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/tests/rewrite/joins.rs +0 -0
  125. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/tests/rewrite/main.rs +0 -0
  126. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/tests/rewrite/output.rs +0 -0
  127. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/tests/rewrite/recursive.rs +0 -0
  128. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/tests/rewrite/scan.rs +0 -0
  129. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/tests/rewrite/update.rs +0 -0
  130. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/tests/rewrite_candidate_regression.rs +0 -0
  131. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/tests/rewrite_fast_paths.rs +0 -0
  132. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/tests/rewrite_large_registry.rs +0 -0
  133. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/tests/rewrite_stats_timings.rs +0 -0
  134. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/tests/scan_ready_expr.rs +0 -0
  135. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/tests/source_set_split_no_parse.rs +0 -0
  136. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/tests/sql_builders.rs +0 -0
  137. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/tests/sql_columns.rs +0 -0
  138. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-core/tests/ui_resolution.rs +0 -0
  139. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-py/Cargo.toml +0 -0
  140. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-py/src/bindings/catalog.rs +0 -0
  141. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-py/src/bindings/errors.rs +0 -0
  142. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-py/src/bindings/mod.rs +0 -0
  143. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-py/src/bindings/planner.rs +0 -0
  144. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-py/src/bindings/policy.rs +0 -0
  145. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-py/src/bindings/stats.rs +0 -0
  146. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/passant-py/src/lib.rs +0 -0
  147. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/python/data_flow_control/__init__.py +0 -0
  148. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/python/data_flow_control/_rust.py +0 -0
  149. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/python/data_flow_control/adapters/__init__.py +0 -0
  150. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/python/data_flow_control/adapters/base.py +0 -0
  151. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/python/data_flow_control/adapters/clickhouse.py +0 -0
  152. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/python/data_flow_control/adapters/datafusion.py +0 -0
  153. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/python/data_flow_control/adapters/duckdb.py +0 -0
  154. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/python/data_flow_control/adapters/kill.py +0 -0
  155. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/python/data_flow_control/adapters/pg_catalog.py +0 -0
  156. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/python/data_flow_control/adapters/postgres.py +0 -0
  157. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/python/data_flow_control/adapters/registry.py +0 -0
  158. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/python/data_flow_control/adapters/sqlite.py +0 -0
  159. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/python/data_flow_control/adapters/umbra.py +0 -0
  160. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/python/data_flow_control/aggregate_introspection.py +0 -0
  161. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/python/data_flow_control/catalog.py +0 -0
  162. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/python/data_flow_control/connection.py +0 -0
  163. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/python/data_flow_control/dialect.py +0 -0
  164. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/python/data_flow_control/langchain/__init__.py +0 -0
  165. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/python/data_flow_control/langchain/agent.py +0 -0
  166. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/python/data_flow_control/langchain/call_tool_with_dataflow.py +0 -0
  167. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/python/data_flow_control/langchain/database.py +0 -0
  168. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/python/data_flow_control/langchain/middleware.py +0 -0
  169. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/python/data_flow_control/langchain/schema.py +0 -0
  170. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/python/data_flow_control/langchain/sql_validation.py +0 -0
  171. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/python/data_flow_control/langchain/tool_spec.py +0 -0
  172. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/python/data_flow_control/langchain/wrapper.py +0 -0
  173. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/python/data_flow_control/options.py +0 -0
  174. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/python/data_flow_control/planner.py +0 -0
  175. {data_flow_control-0.1.5 → data_flow_control-0.1.6}/python/data_flow_control/policy.py +0 -0
  176. {data_flow_control-0.1.5 → 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.5"
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.5"
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.5"
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.5"
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.5
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
@@ -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 {
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "data-flow-control"
3
- version = "0.1.5"
3
+ version = "0.1.6"
4
4
  description = "Rust-backed Data Flow Control rewrite engine"
5
5
  license = "MIT"
6
6
  license-files = ["LICENSE"]