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