relationalai 0.13.0.dev0__py3-none-any.whl → 0.13.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (838) hide show
  1. frontend/debugger/dist/.gitignore +2 -0
  2. frontend/debugger/dist/assets/favicon-Dy0ZgA6N.png +0 -0
  3. frontend/debugger/dist/assets/index-Cssla-O7.js +208 -0
  4. frontend/debugger/dist/assets/index-DlHsYx1V.css +9 -0
  5. frontend/debugger/dist/index.html +17 -0
  6. relationalai/__init__.py +256 -1
  7. relationalai/clients/__init__.py +18 -0
  8. relationalai/clients/client.py +947 -0
  9. relationalai/clients/config.py +673 -0
  10. relationalai/clients/direct_access_client.py +118 -0
  11. relationalai/clients/exec_txn_poller.py +91 -0
  12. relationalai/clients/hash_util.py +31 -0
  13. relationalai/clients/local.py +586 -0
  14. relationalai/clients/profile_polling.py +73 -0
  15. relationalai/clients/resources/__init__.py +8 -0
  16. relationalai/clients/resources/azure/azure.py +502 -0
  17. relationalai/clients/resources/snowflake/__init__.py +20 -0
  18. relationalai/clients/resources/snowflake/cli_resources.py +98 -0
  19. relationalai/clients/resources/snowflake/direct_access_resources.py +734 -0
  20. relationalai/clients/resources/snowflake/engine_service.py +381 -0
  21. relationalai/clients/resources/snowflake/engine_state_handlers.py +315 -0
  22. relationalai/clients/resources/snowflake/error_handlers.py +240 -0
  23. relationalai/clients/resources/snowflake/export_procedure.py.jinja +249 -0
  24. relationalai/clients/resources/snowflake/resources_factory.py +99 -0
  25. relationalai/clients/resources/snowflake/snowflake.py +3185 -0
  26. relationalai/clients/resources/snowflake/use_index_poller.py +1019 -0
  27. relationalai/clients/resources/snowflake/use_index_resources.py +188 -0
  28. relationalai/clients/resources/snowflake/util.py +387 -0
  29. relationalai/clients/result_helpers.py +420 -0
  30. relationalai/clients/types.py +118 -0
  31. relationalai/clients/util.py +356 -0
  32. relationalai/debugging.py +389 -0
  33. relationalai/dsl.py +1749 -0
  34. relationalai/early_access/builder/__init__.py +30 -0
  35. relationalai/early_access/builder/builder/__init__.py +35 -0
  36. relationalai/early_access/builder/snowflake/__init__.py +12 -0
  37. relationalai/early_access/builder/std/__init__.py +25 -0
  38. relationalai/early_access/builder/std/decimals/__init__.py +12 -0
  39. relationalai/early_access/builder/std/integers/__init__.py +12 -0
  40. relationalai/early_access/builder/std/math/__init__.py +12 -0
  41. relationalai/early_access/builder/std/strings/__init__.py +14 -0
  42. relationalai/early_access/devtools/__init__.py +12 -0
  43. relationalai/early_access/devtools/benchmark_lqp/__init__.py +12 -0
  44. relationalai/early_access/devtools/extract_lqp/__init__.py +12 -0
  45. relationalai/early_access/dsl/adapters/orm/adapter_qb.py +427 -0
  46. relationalai/early_access/dsl/adapters/orm/parser.py +636 -0
  47. relationalai/early_access/dsl/adapters/owl/adapter.py +176 -0
  48. relationalai/early_access/dsl/adapters/owl/parser.py +160 -0
  49. relationalai/early_access/dsl/bindings/common.py +402 -0
  50. relationalai/early_access/dsl/bindings/csv.py +170 -0
  51. relationalai/early_access/dsl/bindings/legacy/binding_models.py +143 -0
  52. relationalai/early_access/dsl/bindings/snowflake.py +64 -0
  53. relationalai/early_access/dsl/codegen/binder.py +411 -0
  54. relationalai/early_access/dsl/codegen/common.py +79 -0
  55. relationalai/early_access/dsl/codegen/helpers.py +23 -0
  56. relationalai/early_access/dsl/codegen/relations.py +700 -0
  57. relationalai/early_access/dsl/codegen/weaver.py +417 -0
  58. relationalai/early_access/dsl/core/builders/__init__.py +47 -0
  59. relationalai/early_access/dsl/core/builders/logic.py +19 -0
  60. relationalai/early_access/dsl/core/builders/scalar_constraint.py +11 -0
  61. relationalai/early_access/dsl/core/constraints/predicate/atomic.py +455 -0
  62. relationalai/early_access/dsl/core/constraints/predicate/universal.py +73 -0
  63. relationalai/early_access/dsl/core/constraints/scalar.py +310 -0
  64. relationalai/early_access/dsl/core/context.py +13 -0
  65. relationalai/early_access/dsl/core/cset.py +132 -0
  66. relationalai/early_access/dsl/core/exprs/__init__.py +116 -0
  67. relationalai/early_access/dsl/core/exprs/relational.py +18 -0
  68. relationalai/early_access/dsl/core/exprs/scalar.py +412 -0
  69. relationalai/early_access/dsl/core/instances.py +44 -0
  70. relationalai/early_access/dsl/core/logic/__init__.py +193 -0
  71. relationalai/early_access/dsl/core/logic/aggregation.py +98 -0
  72. relationalai/early_access/dsl/core/logic/exists.py +223 -0
  73. relationalai/early_access/dsl/core/logic/helper.py +163 -0
  74. relationalai/early_access/dsl/core/namespaces.py +32 -0
  75. relationalai/early_access/dsl/core/relations.py +276 -0
  76. relationalai/early_access/dsl/core/rules.py +112 -0
  77. relationalai/early_access/dsl/core/std/__init__.py +45 -0
  78. relationalai/early_access/dsl/core/temporal/recall.py +6 -0
  79. relationalai/early_access/dsl/core/types/__init__.py +270 -0
  80. relationalai/early_access/dsl/core/types/concepts.py +128 -0
  81. relationalai/early_access/dsl/core/types/constrained/__init__.py +267 -0
  82. relationalai/early_access/dsl/core/types/constrained/nominal.py +143 -0
  83. relationalai/early_access/dsl/core/types/constrained/subtype.py +124 -0
  84. relationalai/early_access/dsl/core/types/standard.py +92 -0
  85. relationalai/early_access/dsl/core/types/unconstrained.py +50 -0
  86. relationalai/early_access/dsl/core/types/variables.py +203 -0
  87. relationalai/early_access/dsl/ir/compiler.py +318 -0
  88. relationalai/early_access/dsl/ir/executor.py +260 -0
  89. relationalai/early_access/dsl/ontologies/constraints.py +88 -0
  90. relationalai/early_access/dsl/ontologies/export.py +30 -0
  91. relationalai/early_access/dsl/ontologies/models.py +453 -0
  92. relationalai/early_access/dsl/ontologies/python_printer.py +303 -0
  93. relationalai/early_access/dsl/ontologies/readings.py +60 -0
  94. relationalai/early_access/dsl/ontologies/relationships.py +322 -0
  95. relationalai/early_access/dsl/ontologies/roles.py +87 -0
  96. relationalai/early_access/dsl/ontologies/subtyping.py +55 -0
  97. relationalai/early_access/dsl/orm/constraints.py +438 -0
  98. relationalai/early_access/dsl/orm/measures/dimensions.py +200 -0
  99. relationalai/early_access/dsl/orm/measures/initializer.py +16 -0
  100. relationalai/early_access/dsl/orm/measures/measure_rules.py +275 -0
  101. relationalai/early_access/dsl/orm/measures/measures.py +299 -0
  102. relationalai/early_access/dsl/orm/measures/role_exprs.py +268 -0
  103. relationalai/early_access/dsl/orm/models.py +256 -0
  104. relationalai/early_access/dsl/orm/object_oriented_printer.py +344 -0
  105. relationalai/early_access/dsl/orm/printer.py +469 -0
  106. relationalai/early_access/dsl/orm/reasoners.py +480 -0
  107. relationalai/early_access/dsl/orm/relations.py +19 -0
  108. relationalai/early_access/dsl/orm/relationships.py +251 -0
  109. relationalai/early_access/dsl/orm/types.py +42 -0
  110. relationalai/early_access/dsl/orm/utils.py +79 -0
  111. relationalai/early_access/dsl/orm/verb.py +204 -0
  112. relationalai/early_access/dsl/physical_metadata/tables.py +133 -0
  113. relationalai/early_access/dsl/relations.py +170 -0
  114. relationalai/early_access/dsl/rulesets.py +69 -0
  115. relationalai/early_access/dsl/schemas/__init__.py +450 -0
  116. relationalai/early_access/dsl/schemas/builder.py +48 -0
  117. relationalai/early_access/dsl/schemas/comp_names.py +51 -0
  118. relationalai/early_access/dsl/schemas/components.py +203 -0
  119. relationalai/early_access/dsl/schemas/contexts.py +156 -0
  120. relationalai/early_access/dsl/schemas/exprs.py +89 -0
  121. relationalai/early_access/dsl/schemas/fragments.py +464 -0
  122. relationalai/early_access/dsl/serialization.py +79 -0
  123. relationalai/early_access/dsl/serialize/exporter.py +163 -0
  124. relationalai/early_access/dsl/snow/api.py +105 -0
  125. relationalai/early_access/dsl/snow/common.py +76 -0
  126. relationalai/early_access/dsl/state_mgmt/__init__.py +129 -0
  127. relationalai/early_access/dsl/state_mgmt/state_charts.py +125 -0
  128. relationalai/early_access/dsl/state_mgmt/transitions.py +130 -0
  129. relationalai/early_access/dsl/types/__init__.py +40 -0
  130. relationalai/early_access/dsl/types/concepts.py +12 -0
  131. relationalai/early_access/dsl/types/entities.py +135 -0
  132. relationalai/early_access/dsl/types/values.py +17 -0
  133. relationalai/early_access/dsl/utils.py +102 -0
  134. relationalai/early_access/graphs/__init__.py +13 -0
  135. relationalai/early_access/lqp/__init__.py +12 -0
  136. relationalai/early_access/lqp/compiler/__init__.py +12 -0
  137. relationalai/early_access/lqp/constructors/__init__.py +18 -0
  138. relationalai/early_access/lqp/executor/__init__.py +12 -0
  139. relationalai/early_access/lqp/ir/__init__.py +12 -0
  140. relationalai/early_access/lqp/passes/__init__.py +12 -0
  141. relationalai/early_access/lqp/pragmas/__init__.py +12 -0
  142. relationalai/early_access/lqp/primitives/__init__.py +12 -0
  143. relationalai/early_access/lqp/types/__init__.py +12 -0
  144. relationalai/early_access/lqp/utils/__init__.py +12 -0
  145. relationalai/early_access/lqp/validators/__init__.py +12 -0
  146. relationalai/early_access/metamodel/__init__.py +58 -0
  147. relationalai/early_access/metamodel/builtins/__init__.py +12 -0
  148. relationalai/early_access/metamodel/compiler/__init__.py +12 -0
  149. relationalai/early_access/metamodel/dependency/__init__.py +12 -0
  150. relationalai/early_access/metamodel/factory/__init__.py +17 -0
  151. relationalai/early_access/metamodel/helpers/__init__.py +12 -0
  152. relationalai/early_access/metamodel/ir/__init__.py +14 -0
  153. relationalai/early_access/metamodel/rewrite/__init__.py +7 -0
  154. relationalai/early_access/metamodel/typer/__init__.py +3 -0
  155. relationalai/early_access/metamodel/typer/typer/__init__.py +12 -0
  156. relationalai/early_access/metamodel/types/__init__.py +15 -0
  157. relationalai/early_access/metamodel/util/__init__.py +15 -0
  158. relationalai/early_access/metamodel/visitor/__init__.py +12 -0
  159. relationalai/early_access/rel/__init__.py +12 -0
  160. relationalai/early_access/rel/executor/__init__.py +12 -0
  161. relationalai/early_access/rel/rel_utils/__init__.py +12 -0
  162. relationalai/early_access/rel/rewrite/__init__.py +7 -0
  163. relationalai/early_access/solvers/__init__.py +19 -0
  164. relationalai/early_access/sql/__init__.py +11 -0
  165. relationalai/early_access/sql/executor/__init__.py +3 -0
  166. relationalai/early_access/sql/rewrite/__init__.py +3 -0
  167. relationalai/early_access/tests/logging/__init__.py +12 -0
  168. relationalai/early_access/tests/test_snapshot_base/__init__.py +12 -0
  169. relationalai/early_access/tests/utils/__init__.py +12 -0
  170. relationalai/environments/__init__.py +35 -0
  171. relationalai/environments/base.py +381 -0
  172. relationalai/environments/colab.py +14 -0
  173. relationalai/environments/generic.py +71 -0
  174. relationalai/environments/ipython.py +68 -0
  175. relationalai/environments/jupyter.py +9 -0
  176. relationalai/environments/snowbook.py +169 -0
  177. relationalai/errors.py +2496 -0
  178. relationalai/experimental/SF.py +38 -0
  179. relationalai/experimental/inspect.py +47 -0
  180. relationalai/experimental/pathfinder/__init__.py +158 -0
  181. relationalai/experimental/pathfinder/api.py +160 -0
  182. relationalai/experimental/pathfinder/automaton.py +584 -0
  183. relationalai/experimental/pathfinder/bridge.py +226 -0
  184. relationalai/experimental/pathfinder/compiler.py +416 -0
  185. relationalai/experimental/pathfinder/datalog.py +214 -0
  186. relationalai/experimental/pathfinder/diagnostics.py +56 -0
  187. relationalai/experimental/pathfinder/filter.py +236 -0
  188. relationalai/experimental/pathfinder/glushkov.py +439 -0
  189. relationalai/experimental/pathfinder/options.py +265 -0
  190. relationalai/experimental/pathfinder/pathfinder-v0.7.0.rel +1951 -0
  191. relationalai/experimental/pathfinder/rpq.py +344 -0
  192. relationalai/experimental/pathfinder/transition.py +200 -0
  193. relationalai/experimental/pathfinder/utils.py +26 -0
  194. relationalai/experimental/paths/README.md +107 -0
  195. relationalai/experimental/paths/api.py +143 -0
  196. relationalai/experimental/paths/benchmarks/grid_graph.py +37 -0
  197. relationalai/experimental/paths/code_organization.md +2 -0
  198. relationalai/experimental/paths/examples/Movies.ipynb +16328 -0
  199. relationalai/experimental/paths/examples/basic_example.py +40 -0
  200. relationalai/experimental/paths/examples/minimal_engine_warmup.py +3 -0
  201. relationalai/experimental/paths/examples/movie_example.py +77 -0
  202. relationalai/experimental/paths/examples/movies_data/actedin.csv +193 -0
  203. relationalai/experimental/paths/examples/movies_data/directed.csv +45 -0
  204. relationalai/experimental/paths/examples/movies_data/follows.csv +7 -0
  205. relationalai/experimental/paths/examples/movies_data/movies.csv +39 -0
  206. relationalai/experimental/paths/examples/movies_data/person.csv +134 -0
  207. relationalai/experimental/paths/examples/movies_data/produced.csv +16 -0
  208. relationalai/experimental/paths/examples/movies_data/ratings.csv +10 -0
  209. relationalai/experimental/paths/examples/movies_data/wrote.csv +11 -0
  210. relationalai/experimental/paths/examples/paths_benchmark.py +115 -0
  211. relationalai/experimental/paths/examples/paths_example.py +116 -0
  212. relationalai/experimental/paths/examples/pattern_to_automaton.py +28 -0
  213. relationalai/experimental/paths/find_paths_via_automaton.py +85 -0
  214. relationalai/experimental/paths/graph.py +185 -0
  215. relationalai/experimental/paths/path_algorithms/find_paths.py +280 -0
  216. relationalai/experimental/paths/path_algorithms/one_sided_ball_repetition.py +26 -0
  217. relationalai/experimental/paths/path_algorithms/one_sided_ball_upto.py +111 -0
  218. relationalai/experimental/paths/path_algorithms/single.py +59 -0
  219. relationalai/experimental/paths/path_algorithms/two_sided_balls_repetition.py +39 -0
  220. relationalai/experimental/paths/path_algorithms/two_sided_balls_upto.py +103 -0
  221. relationalai/experimental/paths/path_algorithms/usp-old.py +130 -0
  222. relationalai/experimental/paths/path_algorithms/usp-tuple.py +183 -0
  223. relationalai/experimental/paths/path_algorithms/usp.py +150 -0
  224. relationalai/experimental/paths/product_graph.py +93 -0
  225. relationalai/experimental/paths/rpq/automaton.py +584 -0
  226. relationalai/experimental/paths/rpq/diagnostics.py +56 -0
  227. relationalai/experimental/paths/rpq/rpq.py +378 -0
  228. relationalai/experimental/paths/tests/tests_limit_sp_max_length.py +90 -0
  229. relationalai/experimental/paths/tests/tests_limit_sp_multiple.py +119 -0
  230. relationalai/experimental/paths/tests/tests_limit_sp_single.py +104 -0
  231. relationalai/experimental/paths/tests/tests_limit_walks_multiple.py +113 -0
  232. relationalai/experimental/paths/tests/tests_limit_walks_single.py +149 -0
  233. relationalai/experimental/paths/tests/tests_one_sided_ball_repetition_multiple.py +70 -0
  234. relationalai/experimental/paths/tests/tests_one_sided_ball_repetition_single.py +64 -0
  235. relationalai/experimental/paths/tests/tests_one_sided_ball_upto_multiple.py +115 -0
  236. relationalai/experimental/paths/tests/tests_one_sided_ball_upto_single.py +75 -0
  237. relationalai/experimental/paths/tests/tests_single_paths.py +152 -0
  238. relationalai/experimental/paths/tests/tests_single_walks.py +208 -0
  239. relationalai/experimental/paths/tests/tests_single_walks_undirected.py +297 -0
  240. relationalai/experimental/paths/tests/tests_two_sided_balls_repetition_multiple.py +107 -0
  241. relationalai/experimental/paths/tests/tests_two_sided_balls_repetition_single.py +76 -0
  242. relationalai/experimental/paths/tests/tests_two_sided_balls_upto_multiple.py +76 -0
  243. relationalai/experimental/paths/tests/tests_two_sided_balls_upto_single.py +110 -0
  244. relationalai/experimental/paths/tests/tests_usp_nsp_multiple.py +229 -0
  245. relationalai/experimental/paths/tests/tests_usp_nsp_single.py +108 -0
  246. relationalai/experimental/paths/tree_agg.py +168 -0
  247. relationalai/experimental/paths/utilities/iterators.py +27 -0
  248. relationalai/experimental/paths/utilities/prefix_sum.py +91 -0
  249. relationalai/experimental/solvers.py +1087 -0
  250. relationalai/loaders/csv.py +195 -0
  251. relationalai/loaders/loader.py +177 -0
  252. relationalai/loaders/types.py +23 -0
  253. relationalai/rel_emitter.py +373 -0
  254. relationalai/rel_utils.py +185 -0
  255. relationalai/semantics/__init__.py +22 -146
  256. relationalai/semantics/designs/query_builder/identify_by.md +106 -0
  257. relationalai/semantics/devtools/benchmark_lqp.py +535 -0
  258. relationalai/semantics/devtools/compilation_manager.py +294 -0
  259. relationalai/semantics/devtools/extract_lqp.py +110 -0
  260. relationalai/semantics/internal/internal.py +3785 -0
  261. relationalai/semantics/internal/snowflake.py +325 -0
  262. relationalai/semantics/lqp/README.md +34 -0
  263. relationalai/semantics/lqp/builtins.py +16 -0
  264. relationalai/semantics/lqp/compiler.py +22 -0
  265. relationalai/semantics/lqp/constructors.py +68 -0
  266. relationalai/semantics/lqp/executor.py +469 -0
  267. relationalai/semantics/lqp/intrinsics.py +24 -0
  268. relationalai/semantics/lqp/model2lqp.py +877 -0
  269. relationalai/semantics/lqp/passes.py +680 -0
  270. relationalai/semantics/lqp/primitives.py +252 -0
  271. relationalai/semantics/lqp/result_helpers.py +202 -0
  272. relationalai/semantics/lqp/rewrite/annotate_constraints.py +57 -0
  273. relationalai/semantics/lqp/rewrite/cdc.py +216 -0
  274. relationalai/semantics/lqp/rewrite/extract_common.py +338 -0
  275. relationalai/semantics/lqp/rewrite/extract_keys.py +512 -0
  276. relationalai/semantics/lqp/rewrite/function_annotations.py +114 -0
  277. relationalai/semantics/lqp/rewrite/functional_dependencies.py +314 -0
  278. relationalai/semantics/lqp/rewrite/quantify_vars.py +296 -0
  279. relationalai/semantics/lqp/rewrite/splinter.py +76 -0
  280. relationalai/semantics/lqp/types.py +101 -0
  281. relationalai/semantics/lqp/utils.py +160 -0
  282. relationalai/semantics/lqp/validators.py +57 -0
  283. relationalai/semantics/metamodel/__init__.py +40 -6
  284. relationalai/semantics/metamodel/builtins.py +771 -205
  285. relationalai/semantics/metamodel/compiler.py +133 -0
  286. relationalai/semantics/metamodel/dependency.py +862 -0
  287. relationalai/semantics/metamodel/executor.py +61 -0
  288. relationalai/semantics/metamodel/factory.py +287 -0
  289. relationalai/semantics/metamodel/helpers.py +361 -0
  290. relationalai/semantics/metamodel/rewrite/discharge_constraints.py +39 -0
  291. relationalai/semantics/metamodel/rewrite/dnf_union_splitter.py +210 -0
  292. relationalai/semantics/metamodel/rewrite/extract_nested_logicals.py +78 -0
  293. relationalai/semantics/metamodel/rewrite/flatten.py +554 -0
  294. relationalai/semantics/metamodel/rewrite/format_outputs.py +165 -0
  295. relationalai/semantics/metamodel/typer/checker.py +353 -0
  296. relationalai/semantics/metamodel/typer/typer.py +1399 -0
  297. relationalai/semantics/metamodel/util.py +506 -0
  298. relationalai/semantics/reasoners/__init__.py +10 -0
  299. relationalai/semantics/reasoners/graph/README.md +620 -0
  300. relationalai/semantics/reasoners/graph/__init__.py +37 -0
  301. relationalai/semantics/reasoners/graph/core.py +9019 -0
  302. relationalai/semantics/reasoners/graph/design/beyond_demand_transform.md +797 -0
  303. relationalai/semantics/reasoners/graph/tests/README.md +21 -0
  304. relationalai/semantics/reasoners/optimization/__init__.py +68 -0
  305. relationalai/semantics/reasoners/optimization/common.py +88 -0
  306. relationalai/semantics/reasoners/optimization/solvers_dev.py +568 -0
  307. relationalai/semantics/reasoners/optimization/solvers_pb.py +1414 -0
  308. relationalai/semantics/rel/builtins.py +40 -0
  309. relationalai/semantics/rel/compiler.py +989 -0
  310. relationalai/semantics/rel/executor.py +362 -0
  311. relationalai/semantics/rel/rel.py +482 -0
  312. relationalai/semantics/rel/rel_utils.py +276 -0
  313. relationalai/semantics/snowflake/__init__.py +3 -0
  314. relationalai/semantics/sql/compiler.py +2503 -0
  315. relationalai/semantics/sql/executor/duck_db.py +52 -0
  316. relationalai/semantics/sql/executor/result_helpers.py +64 -0
  317. relationalai/semantics/sql/executor/snowflake.py +149 -0
  318. relationalai/semantics/sql/rewrite/denormalize.py +222 -0
  319. relationalai/semantics/sql/rewrite/double_negation.py +49 -0
  320. relationalai/semantics/sql/rewrite/recursive_union.py +127 -0
  321. relationalai/semantics/sql/rewrite/sort_output_query.py +246 -0
  322. relationalai/semantics/sql/sql.py +504 -0
  323. relationalai/semantics/std/__init__.py +40 -60
  324. relationalai/semantics/std/constraints.py +43 -37
  325. relationalai/semantics/std/datetime.py +135 -246
  326. relationalai/semantics/std/decimals.py +52 -45
  327. relationalai/semantics/std/floats.py +5 -13
  328. relationalai/semantics/std/integers.py +11 -26
  329. relationalai/semantics/std/math.py +112 -183
  330. relationalai/semantics/std/pragmas.py +11 -0
  331. relationalai/semantics/std/re.py +62 -80
  332. relationalai/semantics/std/std.py +14 -0
  333. relationalai/semantics/std/strings.py +60 -117
  334. relationalai/semantics/tests/test_snapshot_abstract.py +143 -0
  335. relationalai/semantics/tests/test_snapshot_base.py +9 -0
  336. relationalai/semantics/tests/utils.py +46 -0
  337. relationalai/std/__init__.py +70 -0
  338. relationalai/tools/cli.py +2089 -0
  339. relationalai/tools/cli_controls.py +1826 -0
  340. relationalai/tools/cli_helpers.py +802 -0
  341. relationalai/tools/debugger.py +183 -289
  342. relationalai/tools/debugger_client.py +109 -0
  343. relationalai/tools/debugger_server.py +302 -0
  344. relationalai/tools/dev.py +685 -0
  345. relationalai/tools/notes +7 -0
  346. relationalai/tools/qb_debugger.py +425 -0
  347. relationalai/util/clean_up_databases.py +95 -0
  348. relationalai/util/format.py +106 -48
  349. relationalai/util/list_databases.py +9 -0
  350. relationalai/util/otel_configuration.py +26 -0
  351. relationalai/util/otel_handler.py +484 -0
  352. relationalai/util/snowflake_handler.py +88 -0
  353. relationalai/util/span_format_test.py +43 -0
  354. relationalai/util/span_tracker.py +207 -0
  355. relationalai/util/spans_file_handler.py +72 -0
  356. relationalai/util/tracing_handler.py +34 -0
  357. relationalai-0.13.2.dist-info/METADATA +74 -0
  358. relationalai-0.13.2.dist-info/RECORD +460 -0
  359. relationalai-0.13.2.dist-info/WHEEL +4 -0
  360. relationalai-0.13.2.dist-info/entry_points.txt +3 -0
  361. relationalai-0.13.2.dist-info/licenses/LICENSE +202 -0
  362. relationalai_test_util/__init__.py +4 -0
  363. relationalai_test_util/fixtures.py +233 -0
  364. relationalai_test_util/snapshot.py +252 -0
  365. relationalai_test_util/traceback.py +118 -0
  366. relationalai/config/__init__.py +0 -56
  367. relationalai/config/config.py +0 -289
  368. relationalai/config/config_fields.py +0 -86
  369. relationalai/config/connections/__init__.py +0 -46
  370. relationalai/config/connections/base.py +0 -23
  371. relationalai/config/connections/duckdb.py +0 -29
  372. relationalai/config/connections/snowflake.py +0 -243
  373. relationalai/config/external/__init__.py +0 -17
  374. relationalai/config/external/dbt_converter.py +0 -101
  375. relationalai/config/external/dbt_models.py +0 -93
  376. relationalai/config/external/snowflake_converter.py +0 -41
  377. relationalai/config/external/snowflake_models.py +0 -85
  378. relationalai/config/external/utils.py +0 -19
  379. relationalai/semantics/backends/lqp/annotations.py +0 -11
  380. relationalai/semantics/backends/sql/sql_compiler.py +0 -327
  381. relationalai/semantics/frontend/base.py +0 -1707
  382. relationalai/semantics/frontend/core.py +0 -179
  383. relationalai/semantics/frontend/front_compiler.py +0 -1313
  384. relationalai/semantics/frontend/pprint.py +0 -408
  385. relationalai/semantics/metamodel/metamodel.py +0 -437
  386. relationalai/semantics/metamodel/metamodel_analyzer.py +0 -519
  387. relationalai/semantics/metamodel/metamodel_compiler.py +0 -0
  388. relationalai/semantics/metamodel/pprint.py +0 -412
  389. relationalai/semantics/metamodel/rewriter.py +0 -266
  390. relationalai/semantics/metamodel/typer.py +0 -1378
  391. relationalai/semantics/std/aggregates.py +0 -149
  392. relationalai/semantics/std/common.py +0 -44
  393. relationalai/semantics/std/numbers.py +0 -86
  394. relationalai/shims/executor.py +0 -147
  395. relationalai/shims/helpers.py +0 -126
  396. relationalai/shims/hoister.py +0 -221
  397. relationalai/shims/mm2v0.py +0 -1290
  398. relationalai/tools/cli/__init__.py +0 -6
  399. relationalai/tools/cli/cli.py +0 -90
  400. relationalai/tools/cli/components/__init__.py +0 -5
  401. relationalai/tools/cli/components/progress_reader.py +0 -1524
  402. relationalai/tools/cli/components/utils.py +0 -58
  403. relationalai/tools/cli/config_template.py +0 -45
  404. relationalai/tools/cli/dev.py +0 -19
  405. relationalai/tools/typer_debugger.py +0 -93
  406. relationalai/util/dataclasses.py +0 -43
  407. relationalai/util/docutils.py +0 -40
  408. relationalai/util/error.py +0 -199
  409. relationalai/util/naming.py +0 -145
  410. relationalai/util/python.py +0 -35
  411. relationalai/util/runtime.py +0 -156
  412. relationalai/util/schema.py +0 -197
  413. relationalai/util/source.py +0 -185
  414. relationalai/util/structures.py +0 -163
  415. relationalai/util/tracing.py +0 -261
  416. relationalai-0.13.0.dev0.dist-info/METADATA +0 -46
  417. relationalai-0.13.0.dev0.dist-info/RECORD +0 -488
  418. relationalai-0.13.0.dev0.dist-info/WHEEL +0 -5
  419. relationalai-0.13.0.dev0.dist-info/entry_points.txt +0 -3
  420. relationalai-0.13.0.dev0.dist-info/top_level.txt +0 -2
  421. v0/relationalai/__init__.py +0 -216
  422. v0/relationalai/clients/__init__.py +0 -5
  423. v0/relationalai/clients/azure.py +0 -477
  424. v0/relationalai/clients/client.py +0 -912
  425. v0/relationalai/clients/config.py +0 -673
  426. v0/relationalai/clients/direct_access_client.py +0 -118
  427. v0/relationalai/clients/hash_util.py +0 -31
  428. v0/relationalai/clients/local.py +0 -571
  429. v0/relationalai/clients/profile_polling.py +0 -73
  430. v0/relationalai/clients/result_helpers.py +0 -420
  431. v0/relationalai/clients/snowflake.py +0 -3869
  432. v0/relationalai/clients/types.py +0 -113
  433. v0/relationalai/clients/use_index_poller.py +0 -980
  434. v0/relationalai/clients/util.py +0 -356
  435. v0/relationalai/debugging.py +0 -389
  436. v0/relationalai/dsl.py +0 -1749
  437. v0/relationalai/early_access/builder/__init__.py +0 -30
  438. v0/relationalai/early_access/builder/builder/__init__.py +0 -35
  439. v0/relationalai/early_access/builder/snowflake/__init__.py +0 -12
  440. v0/relationalai/early_access/builder/std/__init__.py +0 -25
  441. v0/relationalai/early_access/builder/std/decimals/__init__.py +0 -12
  442. v0/relationalai/early_access/builder/std/integers/__init__.py +0 -12
  443. v0/relationalai/early_access/builder/std/math/__init__.py +0 -12
  444. v0/relationalai/early_access/builder/std/strings/__init__.py +0 -14
  445. v0/relationalai/early_access/devtools/__init__.py +0 -12
  446. v0/relationalai/early_access/devtools/benchmark_lqp/__init__.py +0 -12
  447. v0/relationalai/early_access/devtools/extract_lqp/__init__.py +0 -12
  448. v0/relationalai/early_access/dsl/adapters/orm/adapter_qb.py +0 -427
  449. v0/relationalai/early_access/dsl/adapters/orm/parser.py +0 -636
  450. v0/relationalai/early_access/dsl/adapters/owl/adapter.py +0 -176
  451. v0/relationalai/early_access/dsl/adapters/owl/parser.py +0 -160
  452. v0/relationalai/early_access/dsl/bindings/common.py +0 -402
  453. v0/relationalai/early_access/dsl/bindings/csv.py +0 -170
  454. v0/relationalai/early_access/dsl/bindings/legacy/binding_models.py +0 -143
  455. v0/relationalai/early_access/dsl/bindings/snowflake.py +0 -64
  456. v0/relationalai/early_access/dsl/codegen/binder.py +0 -411
  457. v0/relationalai/early_access/dsl/codegen/common.py +0 -79
  458. v0/relationalai/early_access/dsl/codegen/helpers.py +0 -23
  459. v0/relationalai/early_access/dsl/codegen/relations.py +0 -700
  460. v0/relationalai/early_access/dsl/codegen/weaver.py +0 -417
  461. v0/relationalai/early_access/dsl/core/builders/__init__.py +0 -47
  462. v0/relationalai/early_access/dsl/core/builders/logic.py +0 -19
  463. v0/relationalai/early_access/dsl/core/builders/scalar_constraint.py +0 -11
  464. v0/relationalai/early_access/dsl/core/constraints/predicate/atomic.py +0 -455
  465. v0/relationalai/early_access/dsl/core/constraints/predicate/universal.py +0 -73
  466. v0/relationalai/early_access/dsl/core/constraints/scalar.py +0 -310
  467. v0/relationalai/early_access/dsl/core/context.py +0 -13
  468. v0/relationalai/early_access/dsl/core/cset.py +0 -132
  469. v0/relationalai/early_access/dsl/core/exprs/__init__.py +0 -116
  470. v0/relationalai/early_access/dsl/core/exprs/relational.py +0 -18
  471. v0/relationalai/early_access/dsl/core/exprs/scalar.py +0 -412
  472. v0/relationalai/early_access/dsl/core/instances.py +0 -44
  473. v0/relationalai/early_access/dsl/core/logic/__init__.py +0 -193
  474. v0/relationalai/early_access/dsl/core/logic/aggregation.py +0 -98
  475. v0/relationalai/early_access/dsl/core/logic/exists.py +0 -223
  476. v0/relationalai/early_access/dsl/core/logic/helper.py +0 -163
  477. v0/relationalai/early_access/dsl/core/namespaces.py +0 -32
  478. v0/relationalai/early_access/dsl/core/relations.py +0 -276
  479. v0/relationalai/early_access/dsl/core/rules.py +0 -112
  480. v0/relationalai/early_access/dsl/core/std/__init__.py +0 -45
  481. v0/relationalai/early_access/dsl/core/temporal/recall.py +0 -6
  482. v0/relationalai/early_access/dsl/core/types/__init__.py +0 -270
  483. v0/relationalai/early_access/dsl/core/types/concepts.py +0 -128
  484. v0/relationalai/early_access/dsl/core/types/constrained/__init__.py +0 -267
  485. v0/relationalai/early_access/dsl/core/types/constrained/nominal.py +0 -143
  486. v0/relationalai/early_access/dsl/core/types/constrained/subtype.py +0 -124
  487. v0/relationalai/early_access/dsl/core/types/standard.py +0 -92
  488. v0/relationalai/early_access/dsl/core/types/unconstrained.py +0 -50
  489. v0/relationalai/early_access/dsl/core/types/variables.py +0 -203
  490. v0/relationalai/early_access/dsl/ir/compiler.py +0 -318
  491. v0/relationalai/early_access/dsl/ir/executor.py +0 -260
  492. v0/relationalai/early_access/dsl/ontologies/constraints.py +0 -88
  493. v0/relationalai/early_access/dsl/ontologies/export.py +0 -30
  494. v0/relationalai/early_access/dsl/ontologies/models.py +0 -453
  495. v0/relationalai/early_access/dsl/ontologies/python_printer.py +0 -303
  496. v0/relationalai/early_access/dsl/ontologies/readings.py +0 -60
  497. v0/relationalai/early_access/dsl/ontologies/relationships.py +0 -322
  498. v0/relationalai/early_access/dsl/ontologies/roles.py +0 -87
  499. v0/relationalai/early_access/dsl/ontologies/subtyping.py +0 -55
  500. v0/relationalai/early_access/dsl/orm/constraints.py +0 -438
  501. v0/relationalai/early_access/dsl/orm/measures/dimensions.py +0 -200
  502. v0/relationalai/early_access/dsl/orm/measures/initializer.py +0 -16
  503. v0/relationalai/early_access/dsl/orm/measures/measure_rules.py +0 -275
  504. v0/relationalai/early_access/dsl/orm/measures/measures.py +0 -299
  505. v0/relationalai/early_access/dsl/orm/measures/role_exprs.py +0 -268
  506. v0/relationalai/early_access/dsl/orm/models.py +0 -256
  507. v0/relationalai/early_access/dsl/orm/object_oriented_printer.py +0 -344
  508. v0/relationalai/early_access/dsl/orm/printer.py +0 -469
  509. v0/relationalai/early_access/dsl/orm/reasoners.py +0 -480
  510. v0/relationalai/early_access/dsl/orm/relations.py +0 -19
  511. v0/relationalai/early_access/dsl/orm/relationships.py +0 -251
  512. v0/relationalai/early_access/dsl/orm/types.py +0 -42
  513. v0/relationalai/early_access/dsl/orm/utils.py +0 -79
  514. v0/relationalai/early_access/dsl/orm/verb.py +0 -204
  515. v0/relationalai/early_access/dsl/physical_metadata/tables.py +0 -133
  516. v0/relationalai/early_access/dsl/relations.py +0 -170
  517. v0/relationalai/early_access/dsl/rulesets.py +0 -69
  518. v0/relationalai/early_access/dsl/schemas/__init__.py +0 -450
  519. v0/relationalai/early_access/dsl/schemas/builder.py +0 -48
  520. v0/relationalai/early_access/dsl/schemas/comp_names.py +0 -51
  521. v0/relationalai/early_access/dsl/schemas/components.py +0 -203
  522. v0/relationalai/early_access/dsl/schemas/contexts.py +0 -156
  523. v0/relationalai/early_access/dsl/schemas/exprs.py +0 -89
  524. v0/relationalai/early_access/dsl/schemas/fragments.py +0 -464
  525. v0/relationalai/early_access/dsl/serialization.py +0 -79
  526. v0/relationalai/early_access/dsl/serialize/exporter.py +0 -163
  527. v0/relationalai/early_access/dsl/snow/api.py +0 -104
  528. v0/relationalai/early_access/dsl/snow/common.py +0 -76
  529. v0/relationalai/early_access/dsl/state_mgmt/__init__.py +0 -129
  530. v0/relationalai/early_access/dsl/state_mgmt/state_charts.py +0 -125
  531. v0/relationalai/early_access/dsl/state_mgmt/transitions.py +0 -130
  532. v0/relationalai/early_access/dsl/types/__init__.py +0 -40
  533. v0/relationalai/early_access/dsl/types/concepts.py +0 -12
  534. v0/relationalai/early_access/dsl/types/entities.py +0 -135
  535. v0/relationalai/early_access/dsl/types/values.py +0 -17
  536. v0/relationalai/early_access/dsl/utils.py +0 -102
  537. v0/relationalai/early_access/graphs/__init__.py +0 -13
  538. v0/relationalai/early_access/lqp/__init__.py +0 -12
  539. v0/relationalai/early_access/lqp/compiler/__init__.py +0 -12
  540. v0/relationalai/early_access/lqp/constructors/__init__.py +0 -18
  541. v0/relationalai/early_access/lqp/executor/__init__.py +0 -12
  542. v0/relationalai/early_access/lqp/ir/__init__.py +0 -12
  543. v0/relationalai/early_access/lqp/passes/__init__.py +0 -12
  544. v0/relationalai/early_access/lqp/pragmas/__init__.py +0 -12
  545. v0/relationalai/early_access/lqp/primitives/__init__.py +0 -12
  546. v0/relationalai/early_access/lqp/types/__init__.py +0 -12
  547. v0/relationalai/early_access/lqp/utils/__init__.py +0 -12
  548. v0/relationalai/early_access/lqp/validators/__init__.py +0 -12
  549. v0/relationalai/early_access/metamodel/__init__.py +0 -58
  550. v0/relationalai/early_access/metamodel/builtins/__init__.py +0 -12
  551. v0/relationalai/early_access/metamodel/compiler/__init__.py +0 -12
  552. v0/relationalai/early_access/metamodel/dependency/__init__.py +0 -12
  553. v0/relationalai/early_access/metamodel/factory/__init__.py +0 -17
  554. v0/relationalai/early_access/metamodel/helpers/__init__.py +0 -12
  555. v0/relationalai/early_access/metamodel/ir/__init__.py +0 -14
  556. v0/relationalai/early_access/metamodel/rewrite/__init__.py +0 -7
  557. v0/relationalai/early_access/metamodel/typer/__init__.py +0 -3
  558. v0/relationalai/early_access/metamodel/typer/typer/__init__.py +0 -12
  559. v0/relationalai/early_access/metamodel/types/__init__.py +0 -15
  560. v0/relationalai/early_access/metamodel/util/__init__.py +0 -15
  561. v0/relationalai/early_access/metamodel/visitor/__init__.py +0 -12
  562. v0/relationalai/early_access/rel/__init__.py +0 -12
  563. v0/relationalai/early_access/rel/executor/__init__.py +0 -12
  564. v0/relationalai/early_access/rel/rel_utils/__init__.py +0 -12
  565. v0/relationalai/early_access/rel/rewrite/__init__.py +0 -7
  566. v0/relationalai/early_access/solvers/__init__.py +0 -19
  567. v0/relationalai/early_access/sql/__init__.py +0 -11
  568. v0/relationalai/early_access/sql/executor/__init__.py +0 -3
  569. v0/relationalai/early_access/sql/rewrite/__init__.py +0 -3
  570. v0/relationalai/early_access/tests/logging/__init__.py +0 -12
  571. v0/relationalai/early_access/tests/test_snapshot_base/__init__.py +0 -12
  572. v0/relationalai/early_access/tests/utils/__init__.py +0 -12
  573. v0/relationalai/environments/__init__.py +0 -35
  574. v0/relationalai/environments/base.py +0 -381
  575. v0/relationalai/environments/colab.py +0 -14
  576. v0/relationalai/environments/generic.py +0 -71
  577. v0/relationalai/environments/ipython.py +0 -68
  578. v0/relationalai/environments/jupyter.py +0 -9
  579. v0/relationalai/environments/snowbook.py +0 -169
  580. v0/relationalai/errors.py +0 -2455
  581. v0/relationalai/experimental/SF.py +0 -38
  582. v0/relationalai/experimental/inspect.py +0 -47
  583. v0/relationalai/experimental/pathfinder/__init__.py +0 -158
  584. v0/relationalai/experimental/pathfinder/api.py +0 -160
  585. v0/relationalai/experimental/pathfinder/automaton.py +0 -584
  586. v0/relationalai/experimental/pathfinder/bridge.py +0 -226
  587. v0/relationalai/experimental/pathfinder/compiler.py +0 -416
  588. v0/relationalai/experimental/pathfinder/datalog.py +0 -214
  589. v0/relationalai/experimental/pathfinder/diagnostics.py +0 -56
  590. v0/relationalai/experimental/pathfinder/filter.py +0 -236
  591. v0/relationalai/experimental/pathfinder/glushkov.py +0 -439
  592. v0/relationalai/experimental/pathfinder/options.py +0 -265
  593. v0/relationalai/experimental/pathfinder/rpq.py +0 -344
  594. v0/relationalai/experimental/pathfinder/transition.py +0 -200
  595. v0/relationalai/experimental/pathfinder/utils.py +0 -26
  596. v0/relationalai/experimental/paths/api.py +0 -143
  597. v0/relationalai/experimental/paths/benchmarks/grid_graph.py +0 -37
  598. v0/relationalai/experimental/paths/examples/basic_example.py +0 -40
  599. v0/relationalai/experimental/paths/examples/minimal_engine_warmup.py +0 -3
  600. v0/relationalai/experimental/paths/examples/movie_example.py +0 -77
  601. v0/relationalai/experimental/paths/examples/paths_benchmark.py +0 -115
  602. v0/relationalai/experimental/paths/examples/paths_example.py +0 -116
  603. v0/relationalai/experimental/paths/examples/pattern_to_automaton.py +0 -28
  604. v0/relationalai/experimental/paths/find_paths_via_automaton.py +0 -85
  605. v0/relationalai/experimental/paths/graph.py +0 -185
  606. v0/relationalai/experimental/paths/path_algorithms/find_paths.py +0 -280
  607. v0/relationalai/experimental/paths/path_algorithms/one_sided_ball_repetition.py +0 -26
  608. v0/relationalai/experimental/paths/path_algorithms/one_sided_ball_upto.py +0 -111
  609. v0/relationalai/experimental/paths/path_algorithms/single.py +0 -59
  610. v0/relationalai/experimental/paths/path_algorithms/two_sided_balls_repetition.py +0 -39
  611. v0/relationalai/experimental/paths/path_algorithms/two_sided_balls_upto.py +0 -103
  612. v0/relationalai/experimental/paths/path_algorithms/usp-old.py +0 -130
  613. v0/relationalai/experimental/paths/path_algorithms/usp-tuple.py +0 -183
  614. v0/relationalai/experimental/paths/path_algorithms/usp.py +0 -150
  615. v0/relationalai/experimental/paths/product_graph.py +0 -93
  616. v0/relationalai/experimental/paths/rpq/automaton.py +0 -584
  617. v0/relationalai/experimental/paths/rpq/diagnostics.py +0 -56
  618. v0/relationalai/experimental/paths/rpq/rpq.py +0 -378
  619. v0/relationalai/experimental/paths/tests/tests_limit_sp_max_length.py +0 -90
  620. v0/relationalai/experimental/paths/tests/tests_limit_sp_multiple.py +0 -119
  621. v0/relationalai/experimental/paths/tests/tests_limit_sp_single.py +0 -104
  622. v0/relationalai/experimental/paths/tests/tests_limit_walks_multiple.py +0 -113
  623. v0/relationalai/experimental/paths/tests/tests_limit_walks_single.py +0 -149
  624. v0/relationalai/experimental/paths/tests/tests_one_sided_ball_repetition_multiple.py +0 -70
  625. v0/relationalai/experimental/paths/tests/tests_one_sided_ball_repetition_single.py +0 -64
  626. v0/relationalai/experimental/paths/tests/tests_one_sided_ball_upto_multiple.py +0 -115
  627. v0/relationalai/experimental/paths/tests/tests_one_sided_ball_upto_single.py +0 -75
  628. v0/relationalai/experimental/paths/tests/tests_single_paths.py +0 -152
  629. v0/relationalai/experimental/paths/tests/tests_single_walks.py +0 -208
  630. v0/relationalai/experimental/paths/tests/tests_single_walks_undirected.py +0 -297
  631. v0/relationalai/experimental/paths/tests/tests_two_sided_balls_repetition_multiple.py +0 -107
  632. v0/relationalai/experimental/paths/tests/tests_two_sided_balls_repetition_single.py +0 -76
  633. v0/relationalai/experimental/paths/tests/tests_two_sided_balls_upto_multiple.py +0 -76
  634. v0/relationalai/experimental/paths/tests/tests_two_sided_balls_upto_single.py +0 -110
  635. v0/relationalai/experimental/paths/tests/tests_usp_nsp_multiple.py +0 -229
  636. v0/relationalai/experimental/paths/tests/tests_usp_nsp_single.py +0 -108
  637. v0/relationalai/experimental/paths/tree_agg.py +0 -168
  638. v0/relationalai/experimental/paths/utilities/iterators.py +0 -27
  639. v0/relationalai/experimental/paths/utilities/prefix_sum.py +0 -91
  640. v0/relationalai/experimental/solvers.py +0 -1087
  641. v0/relationalai/loaders/csv.py +0 -195
  642. v0/relationalai/loaders/loader.py +0 -177
  643. v0/relationalai/loaders/types.py +0 -23
  644. v0/relationalai/rel_emitter.py +0 -373
  645. v0/relationalai/rel_utils.py +0 -185
  646. v0/relationalai/semantics/__init__.py +0 -29
  647. v0/relationalai/semantics/devtools/benchmark_lqp.py +0 -536
  648. v0/relationalai/semantics/devtools/compilation_manager.py +0 -294
  649. v0/relationalai/semantics/devtools/extract_lqp.py +0 -110
  650. v0/relationalai/semantics/internal/internal.py +0 -3785
  651. v0/relationalai/semantics/internal/snowflake.py +0 -324
  652. v0/relationalai/semantics/lqp/builtins.py +0 -16
  653. v0/relationalai/semantics/lqp/compiler.py +0 -22
  654. v0/relationalai/semantics/lqp/constructors.py +0 -68
  655. v0/relationalai/semantics/lqp/executor.py +0 -469
  656. v0/relationalai/semantics/lqp/intrinsics.py +0 -24
  657. v0/relationalai/semantics/lqp/model2lqp.py +0 -839
  658. v0/relationalai/semantics/lqp/passes.py +0 -680
  659. v0/relationalai/semantics/lqp/primitives.py +0 -252
  660. v0/relationalai/semantics/lqp/result_helpers.py +0 -202
  661. v0/relationalai/semantics/lqp/rewrite/annotate_constraints.py +0 -57
  662. v0/relationalai/semantics/lqp/rewrite/cdc.py +0 -216
  663. v0/relationalai/semantics/lqp/rewrite/extract_common.py +0 -338
  664. v0/relationalai/semantics/lqp/rewrite/extract_keys.py +0 -449
  665. v0/relationalai/semantics/lqp/rewrite/function_annotations.py +0 -114
  666. v0/relationalai/semantics/lqp/rewrite/functional_dependencies.py +0 -314
  667. v0/relationalai/semantics/lqp/rewrite/quantify_vars.py +0 -296
  668. v0/relationalai/semantics/lqp/rewrite/splinter.py +0 -76
  669. v0/relationalai/semantics/lqp/types.py +0 -101
  670. v0/relationalai/semantics/lqp/utils.py +0 -160
  671. v0/relationalai/semantics/lqp/validators.py +0 -57
  672. v0/relationalai/semantics/metamodel/__init__.py +0 -40
  673. v0/relationalai/semantics/metamodel/builtins.py +0 -774
  674. v0/relationalai/semantics/metamodel/compiler.py +0 -133
  675. v0/relationalai/semantics/metamodel/dependency.py +0 -862
  676. v0/relationalai/semantics/metamodel/executor.py +0 -61
  677. v0/relationalai/semantics/metamodel/factory.py +0 -287
  678. v0/relationalai/semantics/metamodel/helpers.py +0 -361
  679. v0/relationalai/semantics/metamodel/rewrite/discharge_constraints.py +0 -39
  680. v0/relationalai/semantics/metamodel/rewrite/dnf_union_splitter.py +0 -210
  681. v0/relationalai/semantics/metamodel/rewrite/extract_nested_logicals.py +0 -78
  682. v0/relationalai/semantics/metamodel/rewrite/flatten.py +0 -549
  683. v0/relationalai/semantics/metamodel/rewrite/format_outputs.py +0 -165
  684. v0/relationalai/semantics/metamodel/typer/checker.py +0 -353
  685. v0/relationalai/semantics/metamodel/typer/typer.py +0 -1395
  686. v0/relationalai/semantics/metamodel/util.py +0 -505
  687. v0/relationalai/semantics/reasoners/__init__.py +0 -10
  688. v0/relationalai/semantics/reasoners/graph/__init__.py +0 -37
  689. v0/relationalai/semantics/reasoners/graph/core.py +0 -9020
  690. v0/relationalai/semantics/reasoners/optimization/__init__.py +0 -68
  691. v0/relationalai/semantics/reasoners/optimization/common.py +0 -88
  692. v0/relationalai/semantics/reasoners/optimization/solvers_dev.py +0 -568
  693. v0/relationalai/semantics/reasoners/optimization/solvers_pb.py +0 -1163
  694. v0/relationalai/semantics/rel/builtins.py +0 -40
  695. v0/relationalai/semantics/rel/compiler.py +0 -989
  696. v0/relationalai/semantics/rel/executor.py +0 -359
  697. v0/relationalai/semantics/rel/rel.py +0 -482
  698. v0/relationalai/semantics/rel/rel_utils.py +0 -276
  699. v0/relationalai/semantics/snowflake/__init__.py +0 -3
  700. v0/relationalai/semantics/sql/compiler.py +0 -2503
  701. v0/relationalai/semantics/sql/executor/duck_db.py +0 -52
  702. v0/relationalai/semantics/sql/executor/result_helpers.py +0 -64
  703. v0/relationalai/semantics/sql/executor/snowflake.py +0 -145
  704. v0/relationalai/semantics/sql/rewrite/denormalize.py +0 -222
  705. v0/relationalai/semantics/sql/rewrite/double_negation.py +0 -49
  706. v0/relationalai/semantics/sql/rewrite/recursive_union.py +0 -127
  707. v0/relationalai/semantics/sql/rewrite/sort_output_query.py +0 -246
  708. v0/relationalai/semantics/sql/sql.py +0 -504
  709. v0/relationalai/semantics/std/__init__.py +0 -54
  710. v0/relationalai/semantics/std/constraints.py +0 -43
  711. v0/relationalai/semantics/std/datetime.py +0 -363
  712. v0/relationalai/semantics/std/decimals.py +0 -62
  713. v0/relationalai/semantics/std/floats.py +0 -7
  714. v0/relationalai/semantics/std/integers.py +0 -22
  715. v0/relationalai/semantics/std/math.py +0 -141
  716. v0/relationalai/semantics/std/pragmas.py +0 -11
  717. v0/relationalai/semantics/std/re.py +0 -83
  718. v0/relationalai/semantics/std/std.py +0 -14
  719. v0/relationalai/semantics/std/strings.py +0 -63
  720. v0/relationalai/semantics/tests/__init__.py +0 -0
  721. v0/relationalai/semantics/tests/test_snapshot_abstract.py +0 -143
  722. v0/relationalai/semantics/tests/test_snapshot_base.py +0 -9
  723. v0/relationalai/semantics/tests/utils.py +0 -46
  724. v0/relationalai/std/__init__.py +0 -70
  725. v0/relationalai/tools/__init__.py +0 -0
  726. v0/relationalai/tools/cli.py +0 -1940
  727. v0/relationalai/tools/cli_controls.py +0 -1826
  728. v0/relationalai/tools/cli_helpers.py +0 -390
  729. v0/relationalai/tools/debugger.py +0 -183
  730. v0/relationalai/tools/debugger_client.py +0 -109
  731. v0/relationalai/tools/debugger_server.py +0 -302
  732. v0/relationalai/tools/dev.py +0 -685
  733. v0/relationalai/tools/qb_debugger.py +0 -425
  734. v0/relationalai/util/clean_up_databases.py +0 -95
  735. v0/relationalai/util/format.py +0 -123
  736. v0/relationalai/util/list_databases.py +0 -9
  737. v0/relationalai/util/otel_configuration.py +0 -25
  738. v0/relationalai/util/otel_handler.py +0 -484
  739. v0/relationalai/util/snowflake_handler.py +0 -88
  740. v0/relationalai/util/span_format_test.py +0 -43
  741. v0/relationalai/util/span_tracker.py +0 -207
  742. v0/relationalai/util/spans_file_handler.py +0 -72
  743. v0/relationalai/util/tracing_handler.py +0 -34
  744. /relationalai/{semantics/frontend → analysis}/__init__.py +0 -0
  745. {v0/relationalai → relationalai}/analysis/mechanistic.py +0 -0
  746. {v0/relationalai → relationalai}/analysis/whynot.py +0 -0
  747. /relationalai/{shims → auth}/__init__.py +0 -0
  748. {v0/relationalai → relationalai}/auth/jwt_generator.py +0 -0
  749. {v0/relationalai → relationalai}/auth/oauth_callback_server.py +0 -0
  750. {v0/relationalai → relationalai}/auth/token_handler.py +0 -0
  751. {v0/relationalai → relationalai}/auth/util.py +0 -0
  752. {v0/relationalai/clients → relationalai/clients/resources/snowflake}/cache_store.py +0 -0
  753. {v0/relationalai → relationalai}/compiler.py +0 -0
  754. {v0/relationalai → relationalai}/dependencies.py +0 -0
  755. {v0/relationalai → relationalai}/docutils.py +0 -0
  756. {v0/relationalai/analysis → relationalai/early_access}/__init__.py +0 -0
  757. {v0/relationalai → relationalai}/early_access/dsl/__init__.py +0 -0
  758. {v0/relationalai/auth → relationalai/early_access/dsl/adapters}/__init__.py +0 -0
  759. {v0/relationalai/early_access → relationalai/early_access/dsl/adapters/orm}/__init__.py +0 -0
  760. {v0/relationalai → relationalai}/early_access/dsl/adapters/orm/model.py +0 -0
  761. {v0/relationalai/early_access/dsl/adapters → relationalai/early_access/dsl/adapters/owl}/__init__.py +0 -0
  762. {v0/relationalai → relationalai}/early_access/dsl/adapters/owl/model.py +0 -0
  763. {v0/relationalai/early_access/dsl/adapters/orm → relationalai/early_access/dsl/bindings}/__init__.py +0 -0
  764. {v0/relationalai/early_access/dsl/adapters/owl → relationalai/early_access/dsl/bindings/legacy}/__init__.py +0 -0
  765. {v0/relationalai/early_access/dsl/bindings → relationalai/early_access/dsl/codegen}/__init__.py +0 -0
  766. {v0/relationalai → relationalai}/early_access/dsl/constants.py +0 -0
  767. {v0/relationalai → relationalai}/early_access/dsl/core/__init__.py +0 -0
  768. {v0/relationalai → relationalai}/early_access/dsl/core/constraints/__init__.py +0 -0
  769. {v0/relationalai → relationalai}/early_access/dsl/core/constraints/predicate/__init__.py +0 -0
  770. {v0/relationalai → relationalai}/early_access/dsl/core/stack.py +0 -0
  771. {v0/relationalai/early_access/dsl/bindings/legacy → relationalai/early_access/dsl/core/temporal}/__init__.py +0 -0
  772. {v0/relationalai → relationalai}/early_access/dsl/core/utils.py +0 -0
  773. {v0/relationalai/early_access/dsl/codegen → relationalai/early_access/dsl/ir}/__init__.py +0 -0
  774. {v0/relationalai/early_access/dsl/core/temporal → relationalai/early_access/dsl/ontologies}/__init__.py +0 -0
  775. {v0/relationalai → relationalai}/early_access/dsl/ontologies/raw_source.py +0 -0
  776. {v0/relationalai/early_access/dsl/ir → relationalai/early_access/dsl/orm}/__init__.py +0 -0
  777. {v0/relationalai/early_access/dsl/ontologies → relationalai/early_access/dsl/orm/measures}/__init__.py +0 -0
  778. {v0/relationalai → relationalai}/early_access/dsl/orm/reasoner_errors.py +0 -0
  779. {v0/relationalai/early_access/dsl/orm → relationalai/early_access/dsl/physical_metadata}/__init__.py +0 -0
  780. {v0/relationalai/early_access/dsl/orm/measures → relationalai/early_access/dsl/serialize}/__init__.py +0 -0
  781. {v0/relationalai → relationalai}/early_access/dsl/serialize/binding_model.py +0 -0
  782. {v0/relationalai → relationalai}/early_access/dsl/serialize/model.py +0 -0
  783. {v0/relationalai/early_access/dsl/physical_metadata → relationalai/early_access/dsl/snow}/__init__.py +0 -0
  784. {v0/relationalai → relationalai}/early_access/tests/__init__.py +0 -0
  785. {v0/relationalai → relationalai}/environments/ci.py +0 -0
  786. {v0/relationalai → relationalai}/environments/hex.py +0 -0
  787. {v0/relationalai → relationalai}/environments/terminal.py +0 -0
  788. {v0/relationalai → relationalai}/experimental/__init__.py +0 -0
  789. {v0/relationalai → relationalai}/experimental/graphs.py +0 -0
  790. {v0/relationalai → relationalai}/experimental/paths/__init__.py +0 -0
  791. {v0/relationalai → relationalai}/experimental/paths/benchmarks/__init__.py +0 -0
  792. {v0/relationalai → relationalai}/experimental/paths/path_algorithms/__init__.py +0 -0
  793. {v0/relationalai → relationalai}/experimental/paths/rpq/__init__.py +0 -0
  794. {v0/relationalai → relationalai}/experimental/paths/rpq/filter.py +0 -0
  795. {v0/relationalai → relationalai}/experimental/paths/rpq/glushkov.py +0 -0
  796. {v0/relationalai → relationalai}/experimental/paths/rpq/transition.py +0 -0
  797. {v0/relationalai → relationalai}/experimental/paths/utilities/__init__.py +0 -0
  798. {v0/relationalai → relationalai}/experimental/paths/utilities/utilities.py +0 -0
  799. {v0/relationalai/early_access/dsl/serialize → relationalai/loaders}/__init__.py +0 -0
  800. {v0/relationalai → relationalai}/metagen.py +0 -0
  801. {v0/relationalai → relationalai}/metamodel.py +0 -0
  802. {v0/relationalai → relationalai}/rel.py +0 -0
  803. {v0/relationalai → relationalai}/semantics/devtools/__init__.py +0 -0
  804. {v0/relationalai → relationalai}/semantics/internal/__init__.py +0 -0
  805. {v0/relationalai → relationalai}/semantics/internal/annotations.py +0 -0
  806. {v0/relationalai → relationalai}/semantics/lqp/__init__.py +0 -0
  807. {v0/relationalai → relationalai}/semantics/lqp/ir.py +0 -0
  808. {v0/relationalai → relationalai}/semantics/lqp/pragmas.py +0 -0
  809. {v0/relationalai → relationalai}/semantics/lqp/rewrite/__init__.py +0 -0
  810. {v0/relationalai → relationalai}/semantics/metamodel/dataflow.py +0 -0
  811. {v0/relationalai → relationalai}/semantics/metamodel/ir.py +0 -0
  812. {v0/relationalai → relationalai}/semantics/metamodel/rewrite/__init__.py +0 -0
  813. {v0/relationalai → relationalai}/semantics/metamodel/typer/__init__.py +0 -0
  814. {v0/relationalai → relationalai}/semantics/metamodel/types.py +0 -0
  815. {v0/relationalai → relationalai}/semantics/metamodel/visitor.py +0 -0
  816. {v0/relationalai → relationalai}/semantics/reasoners/experimental/__init__.py +0 -0
  817. {v0/relationalai → relationalai}/semantics/rel/__init__.py +0 -0
  818. {v0/relationalai → relationalai}/semantics/sql/__init__.py +0 -0
  819. {v0/relationalai → relationalai}/semantics/sql/executor/__init__.py +0 -0
  820. {v0/relationalai → relationalai}/semantics/sql/rewrite/__init__.py +0 -0
  821. {v0/relationalai/early_access/dsl/snow → relationalai/semantics/tests}/__init__.py +0 -0
  822. {v0/relationalai → relationalai}/semantics/tests/logging.py +0 -0
  823. {v0/relationalai → relationalai}/std/aggregates.py +0 -0
  824. {v0/relationalai → relationalai}/std/dates.py +0 -0
  825. {v0/relationalai → relationalai}/std/graphs.py +0 -0
  826. {v0/relationalai → relationalai}/std/inspect.py +0 -0
  827. {v0/relationalai → relationalai}/std/math.py +0 -0
  828. {v0/relationalai → relationalai}/std/re.py +0 -0
  829. {v0/relationalai → relationalai}/std/strings.py +0 -0
  830. {v0/relationalai/loaders → relationalai/tools}/__init__.py +0 -0
  831. {v0/relationalai → relationalai}/tools/cleanup_snapshots.py +0 -0
  832. {v0/relationalai → relationalai}/tools/constants.py +0 -0
  833. {v0/relationalai → relationalai}/tools/query_utils.py +0 -0
  834. {v0/relationalai → relationalai}/tools/snapshot_viewer.py +0 -0
  835. {v0/relationalai → relationalai}/util/__init__.py +0 -0
  836. {v0/relationalai → relationalai}/util/constants.py +0 -0
  837. {v0/relationalai → relationalai}/util/graph.py +0 -0
  838. {v0/relationalai → relationalai}/util/timeout.py +0 -0
@@ -0,0 +1,1019 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Iterable, Dict, Optional, List, cast, TYPE_CHECKING
4
+ import json
5
+ import logging
6
+ import uuid
7
+
8
+ from .... import debugging
9
+ from .cache_store import GraphIndexCache
10
+ from .util import collect_error_messages
11
+ from ...util import (
12
+ get_pyrel_version,
13
+ normalize_datetime,
14
+ poll_with_specified_overhead,
15
+ )
16
+ from ....errors import (
17
+ ERPNotRunningError,
18
+ EngineProvisioningFailed,
19
+ SnowflakeChangeTrackingNotEnabledException,
20
+ SnowflakeTableObjectsException,
21
+ SnowflakeTableObject,
22
+ SnowflakeRaiAppNotStarted,
23
+ )
24
+ from ....tools.cli_controls import (
25
+ DebuggingSpan,
26
+ create_progress,
27
+ TASK_CATEGORY_INDEXING,
28
+ TASK_CATEGORY_PROVISIONING,
29
+ TASK_CATEGORY_CHANGE_TRACKING,
30
+ TASK_CATEGORY_CACHE,
31
+ TASK_CATEGORY_RELATIONS,
32
+ TASK_CATEGORY_STATUS,
33
+ TASK_CATEGORY_VALIDATION,
34
+ )
35
+ from ....tools.constants import WAIT_FOR_STREAM_SYNC, Generation
36
+
37
+ # Set up logger for this module
38
+ logger = logging.getLogger(__name__)
39
+
40
+
41
+ try:
42
+ from rich.console import Console
43
+ from rich.table import Table
44
+ except ImportError:
45
+ Console = None
46
+ Table = None
47
+
48
+ if TYPE_CHECKING:
49
+ from .snowflake import Resources
50
+ from .direct_access_resources import DirectAccessResources
51
+
52
+ # Maximum number of items to show individual subtasks for
53
+ # If more items than this, show a single summary subtask instead
54
+ MAX_INDIVIDUAL_SUBTASKS = 5
55
+
56
+ # Special engine name for CDC managed engine
57
+ CDC_MANAGED_ENGINE = "CDC_MANAGED_ENGINE"
58
+
59
+ # Maximum number of data source subtasks to show simultaneously
60
+ # When one completes, the next one from the queue will be added
61
+ MAX_DATA_SOURCE_SUBTASKS = 10
62
+
63
+ # How often to check ERP status (every N iterations)
64
+ # To limit performance overhead, we only check ERP status periodically
65
+ ERP_CHECK_FREQUENCY = 15
66
+
67
+ # Polling behavior constants
68
+ POLL_OVERHEAD_RATE = 0.1 # Overhead rate for exponential backoff
69
+ POLL_MAX_DELAY = 2.5 # Maximum delay between polls in seconds
70
+
71
+ # SQL query template for getting stream column hashes
72
+ # This query calculates a hash of column metadata (name, type, precision, scale, nullable)
73
+ # to detect if source table schema has changed since stream was created
74
+ STREAM_COLUMN_HASH_QUERY = """
75
+ WITH stream_columns AS (
76
+ SELECT
77
+ fq_object_name,
78
+ HASH(
79
+ value:name::VARCHAR,
80
+ CASE
81
+ WHEN value:precision IS NOT NULL AND value:scale IS NOT NULL THEN CASE value:type::VARCHAR
82
+ WHEN 'FIXED' THEN 'NUMBER'
83
+ WHEN 'REAL' THEN 'FLOAT'
84
+ WHEN 'TEXT' THEN 'TEXT'
85
+ ELSE value:type::VARCHAR
86
+ END || '(' || value:precision || ',' || value:scale || ')'
87
+ WHEN value:precision IS NOT NULL AND value:scale IS NULL THEN CASE value:type::VARCHAR
88
+ WHEN 'FIXED' THEN 'NUMBER'
89
+ WHEN 'REAL' THEN 'FLOAT'
90
+ WHEN 'TEXT' THEN 'TEXT'
91
+ ELSE value:type::VARCHAR
92
+ END || '(0,' || value:precision || ')'
93
+ WHEN value:length IS NOT NULL THEN CASE value:type::VARCHAR
94
+ WHEN 'FIXED' THEN 'NUMBER'
95
+ WHEN 'REAL' THEN 'FLOAT'
96
+ WHEN 'TEXT' THEN 'TEXT'
97
+ ELSE value:type::VARCHAR
98
+ END || '(' || value:length || ')'
99
+ ELSE CASE value:type::VARCHAR
100
+ WHEN 'FIXED' THEN 'NUMBER'
101
+ WHEN 'REAL' THEN 'FLOAT'
102
+ WHEN 'TEXT' THEN 'TEXT'
103
+ ELSE value:type::VARCHAR
104
+ END
105
+ END,
106
+ IFF(value:nullable::BOOLEAN, 'YES', 'NO')
107
+ ) AS column_signature
108
+ FROM {app_name}.api.data_streams,
109
+ LATERAL FLATTEN(input => columns)
110
+ WHERE rai_database = '{rai_database}'
111
+ AND fq_object_name IN ({fqn_list})
112
+ )
113
+ SELECT
114
+ fq_object_name AS FQ_OBJECT_NAME,
115
+ HEX_ENCODE(HASH_AGG(column_signature)) AS STREAM_HASH
116
+ FROM stream_columns
117
+ GROUP BY fq_object_name;
118
+ """
119
+
120
+
121
+ class UseIndexPoller:
122
+ """
123
+ Encapsulates the polling logic for `use_index` streams.
124
+ """
125
+
126
+ def _add_stream_subtask(self, progress, fq_name: str, status: str, batches_count: int) -> bool:
127
+ """Add a stream subtask if we haven't reached the limit.
128
+
129
+ Returns:
130
+ True if subtask was added, False if limit reached
131
+ """
132
+ if fq_name not in self.stream_task_ids and len(self.stream_task_ids) < MAX_DATA_SOURCE_SUBTASKS:
133
+ # Get the position in the stream order (should already be there)
134
+ if fq_name in self.stream_order:
135
+ stream_position = self.stream_order.index(fq_name) + 1
136
+ else:
137
+ # Fallback if not in order (shouldn't happen)
138
+ stream_position = 1
139
+
140
+ # Build initial message based on status and batch count
141
+ if status == "synced":
142
+ initial_message = f"{fq_name} already synced"
143
+ elif batches_count > 0:
144
+ # Show stream position (x/y) before batch count
145
+ initial_message = f"Syncing {fq_name} ({stream_position}/{self.total_streams}), batches: {batches_count}"
146
+ else:
147
+ initial_message = f"Syncing {fq_name} ({stream_position}/{self.total_streams})"
148
+
149
+ self.stream_task_ids[fq_name] = progress.add_sub_task(initial_message, task_id=fq_name, category=TASK_CATEGORY_INDEXING)
150
+
151
+ # Complete immediately if already synced (without recording completion time)
152
+ if status == "synced":
153
+ progress.complete_sub_task(fq_name, record_time=False)
154
+
155
+ return True
156
+ return False
157
+
158
+ def __init__(
159
+ self,
160
+ resource: "Resources",
161
+ app_name: str,
162
+ sources: Iterable[str],
163
+ model: str,
164
+ engine_name: str,
165
+ engine_size: Optional[str],
166
+ language: str = "rel",
167
+ program_span_id: Optional[str] = None,
168
+ headers: Optional[Dict] = None,
169
+ generation: Optional[Generation] = None,
170
+ ):
171
+ self.res = resource
172
+ self.app_name = app_name
173
+ self.sources = list(sources)
174
+ self.model = model
175
+ self.engine_name = engine_name
176
+ self.engine_size = engine_size or self.res.config.get_default_engine_size()
177
+ self.language = language
178
+ self.program_span_id = program_span_id
179
+ self.headers = headers or {}
180
+ self.counter = 1
181
+ self.check_ready_count = 0
182
+ self.tables_with_not_enabled_change_tracking: List = []
183
+ self.table_objects_with_other_errors: List = []
184
+ self.engine_errors: List = []
185
+ # Flag to only ensure the engine is created asynchronously the initial call
186
+ self.init_engine_async = True
187
+ # Initially, we assume that cdc is not checked,
188
+ # then on subsequent calls, if we get if cdc is enabled, if it is not, we will check it
189
+ # on every 5th iteration we reset the cdc status, so it will be checked again
190
+ self.should_check_cdc = True
191
+
192
+ # Flag to only check data stream health once in the first call
193
+ self.check_data_stream_health = True
194
+
195
+ self.wait_for_stream_sync = self.res.config.get(
196
+ "wait_for_stream_sync", WAIT_FOR_STREAM_SYNC
197
+ )
198
+ current_user = self.res.get_sf_session().get_current_user()
199
+ assert current_user is not None, "current_user must be set"
200
+ self.data_freshness = self.res.config.get_data_freshness_mins()
201
+ self.cache = GraphIndexCache(current_user, model, self.data_freshness, self.sources)
202
+ self.sources = self.cache.choose_sources()
203
+ # execution_id is allowed to group use_index call, which belongs to the same loop iteration
204
+ self.execution_id = str(uuid.uuid4())
205
+
206
+ self.pyrel_version = get_pyrel_version(generation)
207
+
208
+ self.source_info = self.res._check_source_updates(self.sources)
209
+
210
+ # Track subtask IDs for streams, engines, and relations across multiple poll iterations
211
+ self.stream_task_ids = {}
212
+ self.engine_task_ids = {}
213
+ self.relations_task_id = None
214
+ self._erp_check_task_id = None
215
+
216
+ # Track total number of streams and current stream position for (x/y) progress display
217
+ self.total_streams = 0
218
+ self.stream_position = 0
219
+ self.stream_order = [] # Track the order of streams as they appear in data
220
+
221
+ # Timing will be tracked by TaskProgress
222
+
223
+ def poll(self) -> None:
224
+ """
225
+ Standard stream-based polling for use_index.
226
+ """
227
+ # Read show_duration_summary config flag (defaults to True for backward compatibility)
228
+ show_duration_summary = bool(self.res.config.get("show_duration_summary", True))
229
+
230
+ with create_progress(
231
+ description="Initializing data index",
232
+ success_message="", # We'll handle this in the context manager
233
+ leading_newline=True,
234
+ trailing_newline=True,
235
+ show_duration_summary=show_duration_summary,
236
+ ) as progress:
237
+ # Set process start time
238
+ progress.set_process_start_time()
239
+ progress.update_main_status("Validating data sources")
240
+ self._maybe_delete_stale(progress)
241
+
242
+ # Add cache usage subtask
243
+ self._add_cache_subtask(progress)
244
+
245
+ progress.update_main_status("Initializing data index")
246
+ self._poll_loop(progress)
247
+ self._post_check(progress)
248
+
249
+ # Set process end time (summary will be automatically printed by __exit__)
250
+ progress.set_process_end_time()
251
+
252
+ def _add_cache_subtask(self, progress) -> None:
253
+ """Add a subtask showing cache usage information only when cache is used."""
254
+ if self.cache.using_cache:
255
+ # Cache was used - show how many sources were cached
256
+ total_sources = len(self.cache.sources)
257
+ cached_sources = total_sources - len(self.sources)
258
+
259
+ # Get the timestamp when sources were cached
260
+ entry = self.cache._metadata.get("cachedIndices", {}).get(self.cache.key, {})
261
+ cached_timestamp = entry.get("last_use_index_update_on", "")
262
+
263
+ message = f"Using cached data for {cached_sources}/{total_sources} data streams"
264
+ # Format the message with timestamp
265
+ if cached_timestamp:
266
+ message += f" (cached at {cached_timestamp})"
267
+
268
+ progress.add_sub_task(message, task_id="cache_usage", category=TASK_CATEGORY_CACHE)
269
+ # Complete the subtask immediately since it's just informational
270
+ progress.complete_sub_task("cache_usage")
271
+
272
+ def _get_stream_column_hashes(self, sources: List[str], progress) -> Dict[str, str]:
273
+ """
274
+ Query data_streams to get current column hashes for the given sources.
275
+
276
+ Args:
277
+ sources: List of source FQNs to query
278
+ progress: TaskProgress instance for updating status on error
279
+
280
+ Returns:
281
+ Dict mapping FQN -> column hash
282
+
283
+ Raises:
284
+ ValueError: If the query fails (permissions, table doesn't exist, etc.)
285
+ """
286
+ from relationalai.clients.resources.snowflake import PYREL_ROOT_DB
287
+
288
+ # Build FQN list for SQL IN clause
289
+ fqn_list = ", ".join([f"'{source}'" for source in sources])
290
+
291
+ # Format query template with actual values
292
+ hash_query = STREAM_COLUMN_HASH_QUERY.format(
293
+ app_name=self.app_name,
294
+ rai_database=PYREL_ROOT_DB,
295
+ fqn_list=fqn_list
296
+ )
297
+
298
+ try:
299
+ hash_results = self.res._exec(hash_query)
300
+ return {row["FQ_OBJECT_NAME"]: row["STREAM_HASH"] for row in hash_results}
301
+
302
+ except Exception as e:
303
+ logger.error(f"Failed to query stream column hashes: {e}")
304
+ logger.error(f" Query: {hash_query[:200]}...")
305
+ logger.error(f" Sources: {sources}")
306
+ progress.update_main_status("❌ Failed to validate data stream metadata")
307
+ raise ValueError(
308
+ f"Failed to validate stream column hashes. This may indicate a permissions "
309
+ f"issue or missing data_streams table. Error: {e}"
310
+ ) from e
311
+
312
+ def _filter_truly_stale_sources(self, stale_sources: List[str], progress) -> List[str]:
313
+ """
314
+ Filter stale sources to only include those with mismatched column hashes.
315
+
316
+ Args:
317
+ stale_sources: List of source FQNs marked as stale
318
+ progress: TaskProgress instance for updating status on error
319
+
320
+ Returns:
321
+ List of truly stale sources that need to be deleted/recreated
322
+
323
+ A source is truly stale if any of the following apply:
324
+ - The stream doesn't exist (needs to be created)
325
+ - The source table was recreated after the stream (table creation timestamp is newer)
326
+ - The column hashes don't match (schema drift needs cleanup)
327
+ """
328
+ stream_hashes = self._get_stream_column_hashes(stale_sources, progress)
329
+
330
+ truly_stale = []
331
+ for source in stale_sources:
332
+ source_hash = self.source_info[source].get("columns_hash")
333
+ stream_hash = stream_hashes.get(source)
334
+ table_created_at_raw = self.source_info[source].get("table_created_at")
335
+ stream_created_at_raw = self.source_info[source].get("stream_created_at")
336
+
337
+ table_created_at = normalize_datetime(table_created_at_raw)
338
+ stream_created_at = normalize_datetime(stream_created_at_raw)
339
+
340
+ recreated_table = False
341
+ if table_created_at is not None and stream_created_at is not None:
342
+ # If the source table was recreated (new creation timestamp) but kept
343
+ # the same column definitions, we still need to recycle the stream so
344
+ # that Snowflake picks up the new table instance.
345
+ recreated_table = table_created_at > stream_created_at
346
+
347
+ # Log hash comparison for debugging
348
+ logger.debug(f"Source: {source}")
349
+ logger.debug(f" Source table hash: {source_hash}")
350
+ logger.debug(f" Stream hash: {stream_hash}")
351
+ logger.debug(f" Match: {source_hash == stream_hash}")
352
+ if recreated_table:
353
+ logger.debug(" Table appears to have been recreated (table_created_at > stream_created_at)")
354
+ logger.debug(f" table_created_at: {table_created_at}")
355
+ logger.debug(f" stream_created_at: {stream_created_at}")
356
+
357
+ if stream_hash is None or source_hash != stream_hash or recreated_table:
358
+ logger.debug(" Action: DELETE (stale)")
359
+ truly_stale.append(source)
360
+ else:
361
+ logger.debug(" Action: KEEP (valid)")
362
+
363
+ logger.debug(f"Stale sources summary: {len(truly_stale)}/{len(stale_sources)} truly stale")
364
+
365
+ return truly_stale
366
+
367
+ def _add_deletion_subtasks(self, progress, sources: List[str]) -> None:
368
+ """Add progress subtasks for source deletion.
369
+
370
+ Args:
371
+ progress: TaskProgress instance
372
+ sources: List of source FQNs to be deleted
373
+ """
374
+ if len(sources) <= MAX_INDIVIDUAL_SUBTASKS:
375
+ for i, source in enumerate(sources):
376
+ progress.add_sub_task(
377
+ f"Removing stale stream {source} ({i+1}/{len(sources)})",
378
+ task_id=f"stale_source_{i}",
379
+ category=TASK_CATEGORY_VALIDATION
380
+ )
381
+ else:
382
+ progress.add_sub_task(
383
+ f"Removing {len(sources)} stale data sources",
384
+ task_id="stale_sources_summary",
385
+ category=TASK_CATEGORY_VALIDATION
386
+ )
387
+
388
+ def _complete_deletion_subtasks(self, progress, sources: List[str], deleted_count: int) -> None:
389
+ """Complete progress subtasks for source deletion.
390
+
391
+ Args:
392
+ progress: TaskProgress instance
393
+ sources: List of source FQNs that were processed
394
+ deleted_count: Number of sources successfully deleted
395
+ """
396
+ if len(sources) <= MAX_INDIVIDUAL_SUBTASKS:
397
+ for i in range(len(sources)):
398
+ if f"stale_source_{i}" in progress._tasks:
399
+ progress.complete_sub_task(f"stale_source_{i}")
400
+ else:
401
+ if "stale_sources_summary" in progress._tasks:
402
+ if deleted_count > 0:
403
+ s = "s" if deleted_count > 1 else ""
404
+ progress.update_sub_task(
405
+ "stale_sources_summary",
406
+ f"Removed {deleted_count} stale data source{s}"
407
+ )
408
+ progress.complete_sub_task("stale_sources_summary")
409
+
410
+ def _maybe_delete_stale(self, progress) -> None:
411
+ """Check for and delete stale data streams that need recreation.
412
+
413
+ Args:
414
+ progress: TaskProgress instance for tracking deletion progress
415
+ """
416
+ with debugging.span("check_sources"):
417
+ stale_sources = [
418
+ source
419
+ for source, info in self.source_info.items()
420
+ if info.get("state") == "STALE"
421
+ ]
422
+
423
+ if not stale_sources:
424
+ return
425
+
426
+ with DebuggingSpan("validate_sources"):
427
+ try:
428
+ # Validate which sources truly need deletion by comparing column hashes
429
+ truly_stale = self._filter_truly_stale_sources(stale_sources, progress)
430
+
431
+ if not truly_stale:
432
+ return
433
+
434
+ # Delete truly stale streams
435
+ from relationalai.clients.resources.snowflake import PYREL_ROOT_DB
436
+ query = f"CALL {self.app_name}.api.delete_data_streams({truly_stale}, '{PYREL_ROOT_DB}');"
437
+
438
+ self._add_deletion_subtasks(progress, truly_stale)
439
+
440
+ delete_response = self.res._exec(query)
441
+ delete_json_str = delete_response[0]["DELETE_DATA_STREAMS"].lower()
442
+ delete_data = json.loads(delete_json_str)
443
+ deleted_count = delete_data.get("deleted", 0)
444
+
445
+ self._complete_deletion_subtasks(progress, truly_stale, deleted_count)
446
+
447
+ # Check for errors
448
+ diff = len(truly_stale) - deleted_count
449
+ if diff > 0:
450
+ errors = delete_data.get("errors", None)
451
+ if errors:
452
+ raise Exception(f"Error(s) deleting streams with modified sources: {errors}")
453
+
454
+ except Exception as e:
455
+ # Complete any remaining subtasks
456
+ self._complete_deletion_subtasks(progress, stale_sources, 0)
457
+ if "stale_sources_summary" in progress._tasks:
458
+ progress.update_sub_task(
459
+ "stale_sources_summary",
460
+ f"❌ Failed to remove stale sources: {str(e)}"
461
+ )
462
+
463
+ # Don't raise if streams don't exist - this is expected
464
+ messages = collect_error_messages(e)
465
+ if not any("data streams do not exist" in msg for msg in messages):
466
+ raise e from None
467
+
468
+ def _poll_loop(self, progress) -> None:
469
+ """Main polling loop for use_index streams.
470
+
471
+ Args:
472
+ progress: TaskProgress instance for tracking polling progress
473
+ """
474
+ source_references = self.res._get_source_references(self.source_info)
475
+ sources_object_references_str = ", ".join(source_references)
476
+
477
+ def check_ready(progress) -> bool:
478
+ self.check_ready_count += 1
479
+
480
+ # To limit the performance overhead, we only check if ERP is running every N iterations
481
+ if self.check_ready_count % ERP_CHECK_FREQUENCY == 0:
482
+ with debugging.span("check_erp_status"):
483
+ # Add subtask for ERP status check
484
+ if self._erp_check_task_id is None:
485
+ self._erp_check_task_id = progress.add_sub_task("Checking system status", task_id="erp_check", category=TASK_CATEGORY_STATUS)
486
+
487
+ if not self.res.is_erp_running(self.app_name):
488
+ progress.update_sub_task("erp_check", "❌ System status check failed")
489
+ progress.complete_sub_task("erp_check")
490
+ raise ERPNotRunningError
491
+ else:
492
+ progress.update_sub_task("erp_check", "System status check complete")
493
+ progress.complete_sub_task("erp_check")
494
+
495
+ use_index_id = f"{self.model}_{self.execution_id}"
496
+
497
+ params = json.dumps({
498
+ "model": self.model,
499
+ "engine": self.engine_name,
500
+ "default_engine_size": self.engine_size, # engine_size
501
+ "user_agent": self.pyrel_version,
502
+ "use_index_id": use_index_id,
503
+ "pyrel_program_id": self.program_span_id,
504
+ "wait_for_stream_sync": self.wait_for_stream_sync,
505
+ "should_check_cdc": self.should_check_cdc,
506
+ "init_engine_async": self.init_engine_async,
507
+ "language": self.language,
508
+ "data_freshness_mins": self.data_freshness,
509
+ "check_data_stream_health": self.check_data_stream_health
510
+ })
511
+
512
+ request_headers = debugging.add_current_propagation_headers(self.headers)
513
+
514
+ sql_string = f"CALL {self.app_name}.api.use_index([{sources_object_references_str}], PARSE_JSON(?), {request_headers});"
515
+
516
+ with debugging.span("wait", counter=self.counter, use_index_id=use_index_id) as span:
517
+ results = self.res._exec(sql_string, [params])
518
+
519
+ # Extract the JSON string from the `USE_INDEX` field
520
+ use_index_json_str = results[0]["USE_INDEX"]
521
+
522
+ # Parse the JSON string into a Python dictionary
523
+ try:
524
+ use_index_data = json.loads(use_index_json_str)
525
+ except json.JSONDecodeError as e:
526
+ logger.error(f"Invalid JSON from use_index API: {e}")
527
+ logger.error(f"Raw response (first 500 chars): {use_index_json_str[:500]}")
528
+ progress.update_main_status("❌ Received invalid response from server")
529
+ raise ValueError(f"Invalid JSON response from use_index: {e}") from e
530
+
531
+ span.update(use_index_data)
532
+
533
+ # Log the full use_index_data for debugging if needed
534
+ logger.debug(f"use_index_data: {json.dumps(use_index_data, indent=4)}")
535
+
536
+ all_data = use_index_data.get("data", [])
537
+ ready = use_index_data.get("ready", False)
538
+ engines = use_index_data.get("engines", [])
539
+ errors = use_index_data.get("errors", [])
540
+ relations = use_index_data.get("relations", {})
541
+ cdc_enabled = use_index_data.get("cdcEnabled", False)
542
+ health_checked = use_index_data.get("healthChecked", False)
543
+ if self.check_ready_count % ERP_CHECK_FREQUENCY == 0 or not cdc_enabled:
544
+ self.should_check_cdc = True
545
+ else:
546
+ self.should_check_cdc = False
547
+
548
+ if engines and self.init_engine_async:
549
+ self.init_engine_async = False
550
+
551
+ if self.check_data_stream_health and health_checked:
552
+ self.check_data_stream_health = False
553
+
554
+ break_loop = False
555
+ has_stream_errors = False
556
+ has_general_errors = False
557
+
558
+ # Update main progress message
559
+ if ready:
560
+ progress.update_main_status("Done")
561
+
562
+ # Handle streams data
563
+ if not ready and all_data:
564
+ progress.update_main_status("Processing background tasks. This may take a while...")
565
+
566
+ # Build complete stream order first (only on first iteration with data)
567
+ if self.total_streams == 0:
568
+ for data in all_data:
569
+ if data is None:
570
+ continue
571
+ fq_name = data.get("fq_object_name", "Unknown")
572
+ if fq_name not in self.stream_order:
573
+ self.stream_order.append(fq_name)
574
+
575
+ # Set total streams count based on complete order (only once)
576
+ self.total_streams = len(self.stream_order)
577
+
578
+ # Add new streams as subtasks if we haven't reached the limit
579
+ for data in all_data:
580
+ fq_name = data.get("fq_object_name", "Unknown")
581
+ status = data.get("data_sync_status", "").lower() if data else ""
582
+ batches_count = data.get("pending_batches_count", 0)
583
+
584
+ # Only add if we haven't seen this stream and we're under the limit
585
+ self._add_stream_subtask(progress, fq_name, status, batches_count)
586
+
587
+ # Handle errors for existing streams
588
+ if fq_name in self.stream_task_ids and data.get("errors", []):
589
+ for error in data.get("errors", []):
590
+ error_msg = f"{error.get('error')}, source: {error.get('source')}"
591
+ # Some failures indicate the RAI app is not started/active; surface
592
+ # them as a rich, actionable error instead of aggregating.
593
+ self._raise_if_app_not_started(error_msg)
594
+ self.table_objects_with_other_errors.append(
595
+ SnowflakeTableObject(error_msg, fq_name)
596
+ )
597
+ # Mark stream as failed
598
+ progress.update_sub_task(fq_name, f"❌ Failed: {fq_name}")
599
+ has_stream_errors = True
600
+
601
+ # Update stream status (only for streams that aren't already completed)
602
+ if fq_name in self.stream_task_ids and fq_name in progress._tasks and not progress._tasks[fq_name].completed:
603
+ # Get the stream position from the stream order
604
+ if fq_name in self.stream_order:
605
+ stream_position = self.stream_order.index(fq_name) + 1
606
+ else:
607
+ # Fallback to 1 if not in order (shouldn't happen)
608
+ stream_position = 1
609
+
610
+ # Build status message
611
+ if batches_count > 0 and status == 'syncing':
612
+ status_message = f"Syncing {fq_name} ({stream_position}/{self.total_streams}), batches: {batches_count}"
613
+ else:
614
+ status_message = f"Pending {fq_name} ({stream_position}/{self.total_streams})..."
615
+
616
+ progress.update_sub_task(fq_name, status_message)
617
+
618
+ # Complete the stream if it's synced
619
+ if status == "synced":
620
+ progress.complete_sub_task(fq_name)
621
+
622
+ # Add more streams from the queue if we have space and more streams exist
623
+ if len(self.stream_task_ids) < MAX_DATA_SOURCE_SUBTASKS:
624
+ for data in all_data:
625
+ fq_name = data.get("fq_object_name", "Unknown")
626
+ status = data.get("data_sync_status", "").lower()
627
+ batches_count = data.get("pending_batches_count", 0)
628
+
629
+ self._add_stream_subtask(progress, fq_name, status, batches_count)
630
+
631
+ self.counter += 1
632
+
633
+ # Handle engines data
634
+ if not ready and engines:
635
+ # Add new engines as subtasks if they don't exist
636
+ for engine in engines:
637
+ if not engine or not isinstance(engine, dict):
638
+ continue
639
+ size = self.engine_size
640
+ name = engine.get("name", "Unknown")
641
+ status = (engine.get("status") or "").lower()
642
+ sub_task_id = self.engine_task_ids.get(name, None)
643
+ sub_task_status_message = ""
644
+
645
+ # Complete the sub task if it exists and the engine status is ready
646
+ if sub_task_id and name in progress._tasks and not progress._tasks[name].completed and (status == "ready"):
647
+ sub_task_status_message = f"Engine {name} ({size}) ready"
648
+ progress.update_sub_task(name, sub_task_status_message)
649
+ progress.complete_sub_task(name)
650
+
651
+ # Add the sub task if it doesn't exist and the engine status is pending
652
+ if not sub_task_id and status == "pending":
653
+ writer = engine.get("writer", False)
654
+ engine_type = "writer engine" if writer else "engine"
655
+ sub_task_status_message = f"Provisioning {engine_type} {name} ({size})"
656
+ self.engine_task_ids[name] = progress.add_sub_task(sub_task_status_message, task_id=name, category=TASK_CATEGORY_PROVISIONING)
657
+
658
+ # Special handling for CDC_MANAGED_ENGINE - mark ready when any stream starts processing
659
+ cdc_task = progress._tasks.get(CDC_MANAGED_ENGINE) if CDC_MANAGED_ENGINE in progress._tasks else None
660
+ if CDC_MANAGED_ENGINE in self.engine_task_ids and cdc_task and not cdc_task.completed:
661
+
662
+ has_processing_streams = any(
663
+ stream.get("next_batch_status", "") == "processing"
664
+ for stream in all_data
665
+ )
666
+ if has_processing_streams and cdc_task and not cdc_task.completed:
667
+ progress.update_sub_task(CDC_MANAGED_ENGINE, f"Engine {CDC_MANAGED_ENGINE} ({self.engine_size}) ready")
668
+ progress.complete_sub_task(CDC_MANAGED_ENGINE)
669
+
670
+ self.counter += 1
671
+
672
+ # Handle relations data
673
+ if relations and isinstance(relations, dict):
674
+ txn = relations.get("txn", {}) or {}
675
+ txn_id = txn.get("id", None)
676
+
677
+ # Only show relations subtask if there is a valid txn object
678
+ if txn_id:
679
+ status = relations.get("status", "").upper()
680
+
681
+ # Create relations subtask if it doesn't exist
682
+ if self.relations_task_id is None:
683
+ self.relations_task_id = progress.add_sub_task("Populating relations", task_id="relations", category=TASK_CATEGORY_RELATIONS)
684
+
685
+ # Set the start time from the JSON if available (always update)
686
+ start_time_ms = relations.get("start_time")
687
+ if start_time_ms:
688
+ start_time_seconds = start_time_ms / 1000.0
689
+ progress._tasks["relations"].added_time = start_time_seconds
690
+
691
+ # Update relations status
692
+ if status == "COMPLETED":
693
+ progress.update_sub_task("relations", f"Relations populated (txn: {txn_id})")
694
+
695
+ # Set the completion time from the JSON if available
696
+ end_time_ms = relations.get("end_time")
697
+ if end_time_ms:
698
+ end_time_seconds = end_time_ms / 1000.0
699
+ progress._tasks["relations"].completed_time = end_time_seconds
700
+
701
+ progress.complete_sub_task("relations", record_time=False) # Don't record local time
702
+ else:
703
+ progress.update_sub_task("relations", f"Relations populating (txn: {txn_id})")
704
+
705
+ self.counter += 1
706
+
707
+ # Handle errors
708
+ if not ready and errors:
709
+ for error in errors:
710
+ if error is None:
711
+ continue
712
+ if error.get("type") == "data":
713
+ message = error.get("message", "").lower()
714
+ if ("change_tracking" in message or "change tracking" in message):
715
+ err_source = error.get("source")
716
+ err_source_type = self.source_info.get(err_source, {}).get("type")
717
+ self.tables_with_not_enabled_change_tracking.append((err_source, err_source_type))
718
+ else:
719
+ self._raise_if_app_not_started(error.get("message", ""))
720
+ self.table_objects_with_other_errors.append(
721
+ SnowflakeTableObject(error.get("message"), error.get("source"))
722
+ )
723
+ elif error.get("type") == "engine":
724
+ self.engine_errors.append(error)
725
+ else:
726
+ # Other types of errors, e.g. "validation"
727
+ self._raise_if_app_not_started(error.get("message", ""))
728
+ self.table_objects_with_other_errors.append(
729
+ SnowflakeTableObject(error.get("message"), error.get("source"))
730
+ )
731
+ has_general_errors = True
732
+
733
+ # If ready, complete all remaining subtasks
734
+ if ready:
735
+ self.cache.record_update(self.source_info)
736
+ # Complete any remaining stream subtasks
737
+ for fq_name in self.stream_task_ids:
738
+ if fq_name in progress._tasks and not progress._tasks[fq_name].completed:
739
+ progress.complete_sub_task(fq_name)
740
+ # Complete any remaining engine subtasks
741
+ for name in self.engine_task_ids:
742
+ if name in progress._tasks and not progress._tasks[name].completed:
743
+ progress.complete_sub_task(name)
744
+ # Complete relations subtask if it exists and isn't completed
745
+ if self.relations_task_id and "relations" in progress._tasks and not progress._tasks["relations"].completed:
746
+ progress.complete_sub_task("relations")
747
+ break_loop = True
748
+ elif has_stream_errors or has_general_errors:
749
+ # Break the loop if there are errors, but only after reporting all progress
750
+ break_loop = True
751
+
752
+ return break_loop
753
+
754
+ poll_with_specified_overhead(lambda: check_ready(progress), overhead_rate=POLL_OVERHEAD_RATE, max_delay=POLL_MAX_DELAY)
755
+
756
+ def _raise_if_app_not_started(self, message: str) -> None:
757
+ """Detect Snowflake-side 'app not active / service not started' messages and raise a rich exception.
758
+
759
+ The use_index stored procedure reports many failures inside the returned JSON payload
760
+ (use_index_data['errors']) rather than raising them as Snowflake exceptions, so the
761
+ standard `_exec()` error handlers won't run. We detect the known activation-needed
762
+ signals here and raise `SnowflakeRaiAppNotStarted` for nicer formatting.
763
+ """
764
+ if not message:
765
+ return
766
+ msg = str(message).lower()
767
+ if (
768
+ "service has not been started" in msg
769
+ or "call app.activate()" in msg
770
+ or "app_not_active_exception" in msg
771
+ or "application is not active" in msg
772
+ or "use the app.activate()" in msg
773
+ ):
774
+ app_name = self.res.config.get("rai_app_name", "") if hasattr(self.res, "config") else ""
775
+ if not isinstance(app_name, str) or not app_name:
776
+ app_name = self.app_name
777
+ raise SnowflakeRaiAppNotStarted(app_name)
778
+
779
+ def _post_check(self, progress) -> None:
780
+ """Run post-processing checks including change tracking enablement.
781
+
782
+ Args:
783
+ progress: TaskProgress instance for tracking progress
784
+
785
+ Raises:
786
+ SnowflakeChangeTrackingNotEnabledException: If change tracking cannot be enabled
787
+ SnowflakeTableObjectsException: If there are table-related errors
788
+ EngineProvisioningFailed: If engine provisioning fails
789
+ """
790
+ num_tables_altered = 0
791
+ failed_tables = [] # Track tables that failed to enable change tracking
792
+
793
+ enabled_tables = []
794
+ if (
795
+ self.tables_with_not_enabled_change_tracking
796
+ and self.res.config.get("ensure_change_tracking", False)
797
+ ):
798
+ tables_to_process = self.tables_with_not_enabled_change_tracking
799
+ # Track timing for change tracking
800
+
801
+ # Add subtasks based on count
802
+ if len(tables_to_process) <= MAX_INDIVIDUAL_SUBTASKS:
803
+ # Add individual subtasks for each table
804
+ for i, table in enumerate(tables_to_process):
805
+ fqn, kind = table
806
+ progress.add_sub_task(f"Enabling change tracking on {fqn} ({i+1}/{len(tables_to_process)})", task_id=f"change_tracking_{i}", category=TASK_CATEGORY_CHANGE_TRACKING)
807
+ else:
808
+ # Add single summary subtask for many tables
809
+ progress.add_sub_task(f"Enabling change tracking on {len(tables_to_process)} tables", task_id="change_tracking_summary", category=TASK_CATEGORY_CHANGE_TRACKING)
810
+
811
+ # Process tables
812
+ for i, table in enumerate(tables_to_process):
813
+ fqn, kind = table # Unpack outside try block to ensure fqn is defined
814
+
815
+ try:
816
+ # Validate table_type to prevent SQL injection
817
+ # Should only be TABLE or VIEW
818
+ if kind not in ("TABLE", "VIEW"):
819
+ logger.error(f"Invalid table kind '{kind}' for {fqn}, skipping")
820
+ failed_tables.append((fqn, f"Invalid table kind: {kind}"))
821
+ # Mark as failed in progress
822
+ if len(tables_to_process) <= MAX_INDIVIDUAL_SUBTASKS:
823
+ if f"change_tracking_{i}" in progress._tasks:
824
+ progress.update_sub_task(f"change_tracking_{i}", f"❌ Invalid type: {fqn}")
825
+ progress.complete_sub_task(f"change_tracking_{i}")
826
+ continue
827
+
828
+ # Execute ALTER statement
829
+ # Note: fqn should already be properly quoted from source_info
830
+ self.res._exec(f"ALTER {kind} {fqn} SET CHANGE_TRACKING = TRUE;")
831
+ enabled_tables.append(table)
832
+ num_tables_altered += 1
833
+
834
+ # Update progress based on subtask type
835
+ if len(tables_to_process) <= MAX_INDIVIDUAL_SUBTASKS:
836
+ # Complete individual table subtask
837
+ progress.complete_sub_task(f"change_tracking_{i}")
838
+ else:
839
+ # Update summary subtask with progress
840
+ progress.update_sub_task("change_tracking_summary",
841
+ f"Enabling change tracking on {len(tables_to_process)} tables... ({i+1}/{len(tables_to_process)})")
842
+ except Exception as e:
843
+ # Log the error for debugging
844
+ logger.warning(f"Failed to enable change tracking on {fqn}: {e}")
845
+ failed_tables.append((fqn, str(e)))
846
+
847
+ # Handle errors based on subtask type
848
+ if len(tables_to_process) <= MAX_INDIVIDUAL_SUBTASKS:
849
+ # Mark the individual subtask as failed and complete it
850
+ if f"change_tracking_{i}" in progress._tasks:
851
+ progress.update_sub_task(f"change_tracking_{i}", f"❌ Failed: {fqn}")
852
+ progress.complete_sub_task(f"change_tracking_{i}")
853
+ # Continue processing other tables despite this failure
854
+
855
+ # Complete summary subtask if used
856
+ if len(tables_to_process) > MAX_INDIVIDUAL_SUBTASKS and "change_tracking_summary" in progress._tasks:
857
+ if num_tables_altered > 0:
858
+ s = "s" if num_tables_altered > 1 else ""
859
+ success_msg = f"Enabled change tracking on {num_tables_altered} table{s}"
860
+ if failed_tables:
861
+ success_msg += f" ({len(failed_tables)} failed)"
862
+ progress.update_sub_task("change_tracking_summary", success_msg)
863
+ elif failed_tables:
864
+ progress.update_sub_task("change_tracking_summary", f"❌ Failed on {len(failed_tables)} table(s)")
865
+ progress.complete_sub_task("change_tracking_summary")
866
+
867
+ # Log summary of failed tables
868
+ if failed_tables:
869
+ logger.warning(f"Failed to enable change tracking on {len(failed_tables)} table(s)")
870
+ for fqn, error in failed_tables:
871
+ logger.warning(f" {fqn}: {error}")
872
+
873
+ # Remove the tables that were successfully enabled from the list of not enabled tables
874
+ # so that we don't raise an exception for them later
875
+ self.tables_with_not_enabled_change_tracking = [
876
+ t for t in self.tables_with_not_enabled_change_tracking if t not in enabled_tables
877
+ ]
878
+
879
+ if self.tables_with_not_enabled_change_tracking:
880
+ progress.update_main_status("Errors found. See below for details.")
881
+ raise SnowflakeChangeTrackingNotEnabledException(
882
+ self.tables_with_not_enabled_change_tracking
883
+ )
884
+
885
+ if self.table_objects_with_other_errors:
886
+ progress.update_main_status("Errors found. See below for details.")
887
+ raise SnowflakeTableObjectsException(self.table_objects_with_other_errors)
888
+ if self.engine_errors:
889
+ progress.update_main_status("Errors found. See below for details.")
890
+ # if there is an engine error, probably auto create engine failed
891
+ # Create a synthetic exception from the first engine error
892
+ first_error = self.engine_errors[0]
893
+ error_message = first_error.get("message", "Unknown engine error")
894
+ synthetic_exception = Exception(f"Engine error: {error_message}")
895
+ raise EngineProvisioningFailed(self.engine_name, synthetic_exception)
896
+
897
+ if num_tables_altered > 0:
898
+ self._poll_loop(progress)
899
+
900
+ class DirectUseIndexPoller(UseIndexPoller):
901
+ """
902
+ Extends UseIndexPoller to handle direct-access prepare_index when no sources.
903
+ """
904
+ def __init__(
905
+ self,
906
+ resource: "DirectAccessResources",
907
+ app_name: str,
908
+ sources: Iterable[str],
909
+ model: str,
910
+ engine_name: str,
911
+ engine_size: Optional[str],
912
+ language: str = "rel",
913
+ program_span_id: Optional[str] = None,
914
+ headers: Optional[Dict] = None,
915
+ generation: Optional[Generation] = None,
916
+ ):
917
+ super().__init__(
918
+ resource=resource,
919
+ app_name=app_name,
920
+ sources=sources,
921
+ model=model,
922
+ engine_name=engine_name,
923
+ engine_size=engine_size,
924
+ language=language,
925
+ program_span_id=program_span_id,
926
+ headers=headers,
927
+ generation=generation,
928
+ )
929
+ from relationalai.clients.resources.snowflake import DirectAccessResources
930
+ self.res: DirectAccessResources = cast(DirectAccessResources, self.res)
931
+
932
+ def poll(self) -> None:
933
+ if not self.sources:
934
+ from relationalai.errors import RAIException
935
+ collected_errors: List[Dict] = []
936
+ attempt = 1
937
+
938
+ def check_direct(progress) -> bool:
939
+ nonlocal attempt
940
+ with debugging.span("wait", counter=self.counter) as span:
941
+ span.update({"attempt": attempt, "engine_name": self.engine_name, "model": self.model})
942
+ # we are skipping pulling relations here, as direct access only handle non-sources cases
943
+ # and we don't need to pull relations for that, therefore, we pass empty list for rai_relations
944
+ # and set skip_pull_relations to True
945
+ resp = self.res._prepare_index(
946
+ model=self.model,
947
+ engine_name=self.engine_name,
948
+ engine_size=self.engine_size,
949
+ language=self.language,
950
+ rai_relations=[],
951
+ pyrel_program_id=self.program_span_id,
952
+ skip_pull_relations=True,
953
+ headers=self.headers,
954
+ )
955
+ span.update(resp)
956
+ caller_engine = resp.get("caller_engine", {})
957
+ # Handle case where caller_engine might be None
958
+ ce_status = caller_engine.get("status", "").lower() if caller_engine else ""
959
+ errors = resp.get("errors", [])
960
+
961
+ ready = resp.get("ready", False)
962
+
963
+ # Update main progress message
964
+ if ready:
965
+ progress.update_main_status("Done")
966
+ else:
967
+ progress.update_main_status("Preparing your data...")
968
+
969
+ if ready:
970
+ return True
971
+ else:
972
+ if ce_status == "pending":
973
+ # Add or update engine subtask
974
+ engine_name = caller_engine.get('name', self.engine_name)
975
+ if not hasattr(progress, '_engine_task_id'):
976
+ progress._engine_task_id = progress.add_sub_task(f"Waiting for engine '{engine_name}' to be ready...", task_id=engine_name)
977
+ else:
978
+ progress.update_sub_task(engine_name, f"Waiting for engine '{engine_name}' to be ready...")
979
+ else:
980
+ # Handle errors as subtasks
981
+ if errors:
982
+ progress.update_main_status("Encountered errors during preparation...")
983
+ for i, err in enumerate(errors):
984
+ error_id = f"error_{i}"
985
+ if not hasattr(progress, f'_error_task_id_{i}'):
986
+ error_msg = err.get('message', 'Unknown error')
987
+ setattr(progress, f'_error_task_id_{i}', progress.add_sub_task(f"❌ {error_msg}", task_id=error_id))
988
+ else:
989
+ error_msg = err.get('message', 'Unknown error')
990
+ progress.update_sub_task(error_id, f"❌ {error_msg}")
991
+ collected_errors.append(err)
992
+
993
+ attempt += 1
994
+ return False
995
+
996
+ # Read show_duration_summary config flag (defaults to True for backward compatibility)
997
+ show_duration_summary = bool(self.res.config.get("show_duration_summary", True))
998
+
999
+ with create_progress(
1000
+ description="Preparing your data...",
1001
+ success_message="Done",
1002
+ leading_newline=True,
1003
+ trailing_newline=True,
1004
+ show_duration_summary=show_duration_summary,
1005
+ ) as progress:
1006
+ # Add cache usage subtask
1007
+ self._add_cache_subtask(progress)
1008
+
1009
+ with debugging.span("poll_direct"):
1010
+ poll_with_specified_overhead(lambda: check_direct(progress), overhead_rate=POLL_OVERHEAD_RATE, max_delay=POLL_MAX_DELAY)
1011
+
1012
+ # Run the same post-check logic as UseIndexPoller
1013
+ self._post_check(progress)
1014
+
1015
+ if collected_errors:
1016
+ msg = "; ".join(e.get("message", "") for e in collected_errors)
1017
+ raise RAIException(msg)
1018
+ else:
1019
+ super().poll()