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,1716 @@
1
+ """Base frontend classes for RelationalAI semantics API.
2
+ """
3
+ from __future__ import annotations
4
+
5
+ import decimal
6
+ import math
7
+ import re
8
+ import datetime as dt
9
+ from typing import TYPE_CHECKING, Any, Generic, Iterable, Iterator, NoReturn, Optional, Sequence, Tuple, Type, TypeGuard, TypeVar, cast
10
+ import itertools
11
+ from more_itertools import peekable
12
+ from pandas import DataFrame
13
+ import pandas as pd
14
+ from enum import Enum, EnumMeta
15
+
16
+ from ...util import schema as schema_util
17
+ from ...util.structures import KeyedSet
18
+ from ...util.naming import Namer, sanitize
19
+ from ...util.python import pytype_to_concept_name
20
+ from ...util.source import SourcePos
21
+ from ...util.tracing import get_tracer
22
+ from ...util.error import err, exc, warn, source
23
+ from ...util.docutils import include_in_docs
24
+ from ..metamodel.builtins import builtins
25
+ from ..metamodel.metamodel import Model as mModel
26
+
27
+ tracer = get_tracer()
28
+ tracer.start_program()
29
+
30
+ #------------------------------------------------------
31
+ # Global ID Generator
32
+ #------------------------------------------------------
33
+
34
+ _global_id = peekable(itertools.count(0))
35
+
36
+ #------------------------------------------------------
37
+ # Helpers
38
+ #------------------------------------------------------
39
+
40
+ def _find_field(fields: list[Field], field: str|int|Concept) -> tuple[Field, int]|None:
41
+ resolved = None
42
+ if isinstance(field, int):
43
+ if not (0 <= field < len(fields)):
44
+ raise IndexError(f"Field index {field} out of range for relationship with {len(fields)} fields")
45
+ resolved = fields[field]
46
+ elif isinstance(field, str):
47
+ resolved = next((f for f in fields if f.name == field), None)
48
+ elif isinstance(field, Concept):
49
+ resolved = next((f for f in fields if f.type is field), None)
50
+ if not resolved:
51
+ return None
52
+ return resolved, fields.index(resolved)
53
+
54
+ def _find_concept(model: Model, passed_type: Any, extra_types: Sequence[Concept] = [], default:Concept|None = None) -> Concept | None:
55
+ if isinstance(passed_type, Concept):
56
+ return passed_type
57
+ if isinstance(passed_type, str):
58
+ for ext_type in extra_types:
59
+ if ext_type._name == passed_type:
60
+ return ext_type
61
+ name = pytype_to_concept_name.get(passed_type, passed_type)
62
+ if name.startswith("Number(") or name.startswith("Decimal("):
63
+ return cast(Any, CoreConcepts["Number"]).parse(name)
64
+ return model._find_concept(name)
65
+ #TODO: try to find a variable in the frame that is a concept with this name
66
+ return default
67
+
68
+ #------------------------------------------------------
69
+ # Primitive
70
+ #------------------------------------------------------
71
+
72
+ Primitive = str|int|float|bool
73
+
74
+ def is_primitive(value: Any) -> TypeGuard[str | int | float | bool]:
75
+ return isinstance(value, (str, int, float, bool))
76
+
77
+ #------------------------------------------------------
78
+ # DSLBase
79
+ #------------------------------------------------------
80
+
81
+ class DSLBase:
82
+ def __init__(self, model:Model):
83
+ self._model = model
84
+ self._id = next(_global_id)
85
+ self._source = SourcePos.new()
86
+
87
+ #------------------------------------------------------
88
+ # Hashing
89
+ #------------------------------------------------------
90
+
91
+ def to_dict_key(self) -> int|tuple[int, int]:
92
+ return self._id
93
+
94
+ def __hash__(self) -> NoReturn:
95
+ exc("Unhashable type", f"{self.__class__.__name__} objects are unhashable. Use `to_dict_key()` instead.", [source(self)])
96
+
97
+ #------------------------------------------------------
98
+ # DSLDict
99
+ #------------------------------------------------------
100
+
101
+ def dsl_key(obj:Any) -> Any:
102
+ if isinstance(obj, DSLBase):
103
+ return obj.to_dict_key()
104
+ elif isinstance(obj, tuple):
105
+ return tuple(dsl_key(o) for o in obj)
106
+ return obj
107
+
108
+ #------------------------------------------------------
109
+ # Variable
110
+ #------------------------------------------------------
111
+
112
+ class Variable(DSLBase):
113
+ #--------------------------------------------------
114
+ # Infix operator overloads
115
+ #--------------------------------------------------
116
+
117
+ def _bin_op(self, op, left, right) -> Expression:
118
+ res = CoreConcepts["Numeric"].ref()
119
+ return Expression(CoreRelationships[op], [left, right, res])
120
+
121
+ def __add__(self, other):
122
+ return self._bin_op("+", self, other)
123
+ def __radd__(self, other):
124
+ return self._bin_op("+", other, self)
125
+
126
+ def __mul__(self, other):
127
+ return self._bin_op("*", self, other)
128
+ def __rmul__(self, other):
129
+ return self._bin_op("*", other, self)
130
+
131
+ def __sub__(self, other):
132
+ return self._bin_op("-", self, other)
133
+ def __rsub__(self, other):
134
+ return self._bin_op("-", other, self)
135
+
136
+ def __truediv__(self, other):
137
+ return self._bin_op("/", self, other)
138
+ def __rtruediv__(self, other):
139
+ return self._bin_op("/", other, self)
140
+
141
+ def __floordiv__(self, other):
142
+ return self._bin_op("//", self, other)
143
+ def __rfloordiv__(self, other):
144
+ return self._bin_op("//", other, self)
145
+
146
+ def __pow__(self, other):
147
+ return self._bin_op("^", self, other)
148
+ def __rpow__(self, other):
149
+ return self._bin_op("^", other, self)
150
+
151
+ def __mod__(self, other):
152
+ return self._bin_op("%", self, other)
153
+ def __rmod__(self, other):
154
+ return self._bin_op("%", other, self)
155
+
156
+ def __neg__(self):
157
+ return self._bin_op("*", self, -1)
158
+
159
+ #--------------------------------------------------
160
+ # Filter overloads
161
+ #--------------------------------------------------
162
+
163
+ def _filter(self, op, left, right) -> Expression:
164
+ return Expression(CoreRelationships[op], [left, right])
165
+
166
+ def __gt__(self, other):
167
+ return self._filter(">", self, other)
168
+ def __ge__(self, other):
169
+ return self._filter(">=", self, other)
170
+ def __lt__(self, other):
171
+ return self._filter("<", self, other)
172
+ def __le__(self, other):
173
+ return self._filter("<=", self, other)
174
+ def __eq__(self, other) -> Any:
175
+ return self._filter("=", self, other)
176
+ def __ne__(self, other) -> Any:
177
+ return self._filter("!=", self, other)
178
+
179
+ #--------------------------------------------------
180
+ # And/Or
181
+ #--------------------------------------------------
182
+
183
+ def __or__(self, other) -> Match:
184
+ return Match(self._model, self, other)
185
+
186
+ def __and__(self, other) -> Fragment:
187
+ if isinstance(other, Fragment):
188
+ new = other.where()
189
+ new._where.insert(0, self)
190
+ return new
191
+ return self._model.where(self, other)
192
+
193
+ #------------------------------------------------------
194
+ # AsBool
195
+ #------------------------------------------------------
196
+
197
+ def as_bool(self) -> AsBool:
198
+ return AsBool(self)
199
+
200
+ #------------------------------------------------------
201
+ # Alias
202
+ #------------------------------------------------------
203
+
204
+ def alias(self, alias: str) -> Alias:
205
+ return Alias(self, alias)
206
+
207
+ #--------------------------------------------------
208
+ # in_
209
+ #--------------------------------------------------
210
+
211
+ def in_(self, values:Sequence[Value]|Variable):
212
+ if isinstance(values, Variable):
213
+ return self == values
214
+ if all(isinstance(v, (str, int, float, bool)) for v in values):
215
+ data_table = self._model.data([(v,) for v in values])
216
+ return self == data_table[0]
217
+ else:
218
+ return self == self._model.union(*values)
219
+
220
+ #--------------------------------------------------
221
+ # Check value
222
+ #--------------------------------------------------
223
+
224
+ def _check_value(self) -> bool:
225
+ return True
226
+
227
+ def _to_concept(self) -> Concept|None:
228
+ return None
229
+
230
+ #------------------------------------------------------
231
+ # Error handling
232
+ #------------------------------------------------------
233
+
234
+ def __bool__(self) -> NoReturn:
235
+ cur_source = self._source.block.source or ""
236
+ invalid = next((bool_check for bool_check in ["if ", "while ", " and ", " or "] if bool_check in cur_source), "bool check").strip()
237
+ mapped = {"and": "`&` or `,`", "or": "`|`", "if": "`where`"}
238
+ if m := mapped.get(invalid):
239
+ exc(f"Invalid operator", f"Cannot use python's `{invalid}` in model expressions. Use {m} instead.", [source(self)])
240
+ else:
241
+ exc(f"Invalid operator", f"Cannot use python's `{invalid}` in model expressions.", [source(self)])
242
+
243
+ if not TYPE_CHECKING:
244
+ def __iter__(self):
245
+ common_incorrect = ["sum", "min", "max"]
246
+ for agg in common_incorrect:
247
+ if agg in self._source.block.source:
248
+ exc(f"Invalid built-in", f"The Python built-in `{agg}()` was used instead of the RAI equivalent.", [
249
+ source(self),
250
+ f"Use [cyan]`relationalai.semantics.std.aggregates.{agg}`[/cyan] instead.",
251
+ ])
252
+ exc("Invalid iteration", f"Cannot iterate over {self.__class__.__name__} objects.", [
253
+ source(self)
254
+ ])
255
+
256
+ def __len__(self) -> NoReturn:
257
+ exc("Invalid operator", "Cannot use len() on model variables.", [source(self)])
258
+
259
+ #------------------------------------------------------
260
+ # Concept
261
+ #------------------------------------------------------
262
+
263
+ class Concept(Variable):
264
+ lookup_by_id: dict[int, Concept] = {}
265
+
266
+ def __init__(self, name: str, extends: list[Concept], identify_by: dict[str, Concept], model:Model):
267
+ super().__init__(model)
268
+ Concept.lookup_by_id[self._id] = self
269
+ self._name = name
270
+ clean_extends = []
271
+ for extend in extends:
272
+ if not isinstance(extend, Concept):
273
+ exc("Invalid extend", f"Cannot extend from non-Concept type: {extend}", [source(self)])
274
+ if "Number" in CoreConcepts and extend is CoreConcepts["Number"]:
275
+ clean_extends.append(extend.size(38, 14))
276
+ else:
277
+ clean_extends.append(extend)
278
+ self._extends = clean_extends
279
+ self._annotations: list[Expression|Relationship] = []
280
+ self._relationships = {}
281
+ self._identify_by:list[Relationship] = []
282
+ for id_name, id_val in identify_by.items():
283
+ if not isinstance(id_val, (Concept, Property)):
284
+ exc("Invalid identify_by", f"identify_by values must be Concepts, got: {type(id_val)}", [source(self)])
285
+ id_val = self._dot(id_name, with_type=id_val)
286
+ self._identify_by.append(id_val)
287
+
288
+ def __setattr__(self, name: str, value: Any) -> None:
289
+ if isinstance(value, Relationship):
290
+ key = name.lower()
291
+ if self._relationships.get(key) is not None:
292
+ exc("Duplicate relationship", f"Relationship '{name}' is already defined on concept '{self._name}'", [
293
+ source(self._relationships[key])
294
+ ])
295
+ if not value._short_name:
296
+ value._short_name = name
297
+ self._relationships[key] = value
298
+ else:
299
+ super().__setattr__(name, value)
300
+
301
+ def _dot_recur(self, name: str, with_type: Any = None) -> Relationship|None:
302
+ if name.lower() in self._relationships:
303
+ return self._relationships[name.lower()]
304
+ for ext in self._extends:
305
+ rel = ext._dot_recur(name, with_type)
306
+ if rel is not None:
307
+ return rel
308
+ # We should create the relationship on the root type if it's not
309
+ # found anywhere
310
+ if self._model is not CoreLibrary:
311
+ field_type = _find_concept(self._model, with_type, default=CoreConcepts["Any"])
312
+ assert field_type is not None
313
+ rel = self._relationships[name.lower()] = Property(fields=[
314
+ Field(self._name.lower(), self),
315
+ Field(name, field_type)
316
+ ], short_name=name, model=self._model)
317
+ return rel
318
+ return None
319
+
320
+ def _dot(self, name: str, with_type: Any = None) -> Relationship:
321
+ if self._model is CoreLibrary:
322
+ exc("Invalid relationship", f"Cannot access relationships on core concept '{self._name}'.", [source(self)])
323
+ if with_type is None:
324
+ with_type = CoreConcepts["Any"]
325
+ rel = self._dot_recur(name, with_type)
326
+ assert rel is not None
327
+ return rel
328
+
329
+ def __getattr__(self, item) -> Chain:
330
+ if item.startswith("_"):
331
+ return object.__getattribute__(self, item)
332
+ return Chain(self, self._dot(item))
333
+
334
+ def __call__(self, *args: Any, **kwargs: Any) -> Expression:
335
+ return Expression(self, list(args), kwargs)
336
+
337
+ def new(self, *args: StatementAndSchema, **kwargs: Any) -> New:
338
+ return New(self, args, kwargs)
339
+
340
+ def to_identity(self, *args: Any, **kwargs: Any) -> New:
341
+ return New(self, args, kwargs, identity_only=True)
342
+
343
+ def identify_by(self, *properties: Property|Chain) -> Concept:
344
+ for prop in properties:
345
+ if isinstance(prop, Chain):
346
+ prop = prop._next
347
+ if not isinstance(prop, Property) and not (isinstance(prop, Reading) and isinstance(prop._relationship, Property)):
348
+ exc("Invalid identify_by", f"identify_by expects Properties, got: {type(prop).__name__}", [source(self)])
349
+ if prop._fields[0].type is not self:
350
+ exc("Invalid identify_by", f"Property {prop} have the first field be {self._name}", [source(self)])
351
+ self._identify_by.append(prop)
352
+ return self
353
+
354
+ def filter_by(self, **kwargs: Any) -> Expression:
355
+ return FilterBy(self, kwargs)
356
+
357
+ def require(self, *items: Variable|Fragment) -> Fragment:
358
+ return self._model.where(self).require(*items)
359
+
360
+ def ref(self, name="") -> Ref:
361
+ return Ref(self, name)
362
+
363
+ def annotate(self, *annos:Expression|Relationship) -> Concept:
364
+ self._annotations.extend(annos)
365
+ return self
366
+
367
+ def _to_concept(self) -> Concept:
368
+ return self
369
+
370
+ def __dir__(self):
371
+ default = set(super().__dir__())
372
+ return sorted(default.union(self._relationships.keys()))
373
+
374
+ def __format__(self, format_spec: str) -> str:
375
+ if not format_spec:
376
+ return f"{{{self._name}#{self._id}}}"
377
+ return f"{{{self._name}#{self._id}:{format_spec.strip()}}}"
378
+
379
+ #------------------------------------------------------
380
+ # NumberConcept
381
+ #------------------------------------------------------
382
+
383
+ class NumberConcept(Concept):
384
+ def __init__(self, name: str, precision: int, scale: int, model: Model):
385
+ super().__init__(name, extends=[CoreConcepts["Numeric"]], identify_by={}, model=model)
386
+ self._precision = precision
387
+ self._scale = scale
388
+
389
+ #------------------------------------------------------
390
+ # Ref
391
+ #------------------------------------------------------
392
+
393
+ class Ref(Variable):
394
+ def __init__(self, concept: Concept, name: str|None = None):
395
+ super().__init__(concept._model)
396
+ self._concept = concept
397
+ self._name = name or ("number" if (isinstance(concept, NumberConcept) or concept is CoreConcepts["Numeric"])
398
+ else concept._name)
399
+
400
+ def __getattr__(self, item):
401
+ if item.startswith("_"):
402
+ return object.__getattribute__(self, item)
403
+ return Chain(self, self._concept._dot(item))
404
+
405
+ def _to_concept(self) -> Concept:
406
+ return self._concept
407
+
408
+ def FilterBy(self, **kwargs: Any) -> Expression:
409
+ return FilterBy(self, kwargs)
410
+
411
+ #------------------------------------------------------
412
+ # Table
413
+ #------------------------------------------------------
414
+
415
+ class Table(Concept):
416
+ def __init__(self, name:str, schema: dict[str, Concept], model: Model):
417
+ super().__init__(name, [], {}, model)
418
+ self._known_columns = []
419
+ for col_name, col_type in schema.items():
420
+ if isinstance(col_type, Property):
421
+ col_rel = col_type
422
+ setattr(self, col_name, col_rel)
423
+ else:
424
+ col_rel = self._dot(col_name, with_type=col_type)
425
+ self._known_columns.append(col_rel)
426
+
427
+ @property
428
+ def _columns(self) -> list[Relationship]:
429
+ if self._known_columns:
430
+ return self._known_columns
431
+ schema = schema_util.fetch(self._name)
432
+ for col_name, col_type_name in schema.items():
433
+ col_type = _find_concept(self._model, col_type_name, default=CoreConcepts["Any"])
434
+ col_rel = self._dot(col_name, with_type=col_type)
435
+ self._known_columns.append(col_rel)
436
+ return self._known_columns
437
+
438
+ def __getitem__(self, index: int|str) -> Chain:
439
+ if isinstance(index, int):
440
+ if not (0 <= index < len(self._columns)):
441
+ raise IndexError(f"Column index {index} out of range, there are {len(self._columns)} columns")
442
+ return Chain(self, self._columns[index])
443
+ col = next((c for c in self._columns if c._short_name == index), None)
444
+ if col is None:
445
+ raise KeyError(f"Column name '{index}' not found, columns have names {[c._short_name for c in self._columns]}")
446
+ return Chain(self, col)
447
+
448
+ def __iter__(self) -> Iterator[Relationship]:
449
+ return iter(self._columns)
450
+
451
+ def new(self, *args:StatementAndSchema, **kwargs: Any) -> NoReturn:
452
+ exc("Invalid new call", "Cannot create new instances of Tables.", [source(self)])
453
+
454
+ def to_identity(self, *args: Any, **kwargs: Any) -> NoReturn:
455
+ exc("Invalid identity call", "Cannot create identity instances of Tables.", [source(self)])
456
+
457
+ def to_schema(self, *, exclude: list[str] = []) -> TableSchema:
458
+ return TableSchema(self, exclude=exclude)
459
+
460
+ #------------------------------------------------------
461
+ # TableSchema
462
+ #------------------------------------------------------
463
+
464
+ class TableSchema(DSLBase):
465
+ def __init__(self, table: Table, exclude: list[str] = []):
466
+ super().__init__(table._model)
467
+ self._table = table
468
+ self.exclude = set([e.lower() for e in exclude])
469
+
470
+ def get_columns(self) -> list[Relationship]:
471
+ return [col for col in self._table._columns if col._short_name.lower() not in self.exclude]
472
+
473
+ #--------------------------------------------------
474
+ # DerivedTable
475
+ #--------------------------------------------------
476
+
477
+ class DerivedTable(Variable):
478
+ def __init__(self, model: Model):
479
+ super().__init__(model)
480
+ self.__cols = []
481
+
482
+ @property
483
+ def _columns(self):
484
+ if not self.__cols:
485
+ self.__cols = self._get_cols()
486
+ if not self.__cols:
487
+ raise ValueError(f"Cannot use {self.__class__.__name__} as it has no columns")
488
+ return self.__cols
489
+
490
+ def _check_value(self):
491
+ return bool(self._columns)
492
+
493
+ def __iter__(self) -> Iterator[DerivedColumn]:
494
+ return iter(self._columns)
495
+
496
+ def __getitem__(self, index: int|str) -> DerivedColumn:
497
+ if isinstance(index, int):
498
+ if not (0 <= index < len(self._columns)):
499
+ raise IndexError(f"Column index {index} out of range, there are {len(self._columns)} columns")
500
+ return self._columns[index]
501
+ col = next((c for c in self._columns if c._name == index), None)
502
+ if not col:
503
+ raise KeyError(f"Column name '{index}' not found, columns have names {[c._name for c in self._columns]}")
504
+ return col
505
+
506
+ def _get_cols(self):
507
+ raise NotImplementedError()
508
+
509
+ #--------------------------------------------------
510
+ # DerivedColumn
511
+ #--------------------------------------------------
512
+
513
+ class DerivedColumn(Variable):
514
+ def __init__(self, table: DerivedTable, index: int, name: str|None = None, type_: Concept|None = None):
515
+ super().__init__(table._model)
516
+ self._table = table
517
+ self._index = index
518
+ self._name = name
519
+ self._type = type_
520
+ self._relationships = {}
521
+
522
+ def _dot(self, name: str) -> Relationship:
523
+ if self._type is not None:
524
+ return self._type._dot(name)
525
+ if name.lower() not in self._relationships:
526
+ self._relationships[name.lower()] = Property(fields=[
527
+ Field("entity", CoreConcepts["Any"]),
528
+ Field(name, CoreConcepts["Any"])
529
+ ], short_name=name, model=self._model)
530
+ return self._relationships[name.lower()]
531
+
532
+ def __getattr__(self, item):
533
+ if item.startswith("_"):
534
+ return object.__getattribute__(self, item)
535
+ return Chain(self, self._dot(item))
536
+
537
+ @staticmethod
538
+ def from_value(table: DerivedTable, index: int, var: Value) -> DerivedColumn:
539
+ name = None
540
+ if isinstance(var, Alias):
541
+ name = var._alias
542
+ if not isinstance(var, Variable):
543
+ var = Literal(var, table._model)
544
+ return DerivedColumn(table=table, index=index, name=name, type_=var._to_concept())
545
+
546
+ #------------------------------------------------------
547
+ # Field
548
+ #------------------------------------------------------
549
+
550
+ class Field:
551
+ def __init__(self, name: str, type_: Concept, is_input: bool = False, is_list: bool = False, source: SourcePos | None = None):
552
+ self._id = next(_global_id)
553
+ self.name = name
554
+ self.type = type_
555
+ self.is_input = is_input
556
+ self.is_list = is_list
557
+ self._source = source
558
+
559
+ @classmethod
560
+ def input(cls, name: str, concept: Concept, is_list: bool = False) -> Field:
561
+ return Field(name, concept, is_input=True, is_list=is_list)
562
+
563
+ def _match(self, other: Field) -> bool:
564
+ return self.name == other.name and self.type is other.type
565
+
566
+ #--------------------------------------------------
567
+ # Relationship
568
+ #--------------------------------------------------
569
+
570
+ class Relationship(Variable):
571
+ def __init__(self, model: Model, reading_str:str = "", fields: list[Field] = [], short_name: str = "", allow_no_fields: bool = False, overloads:list[list[Concept]]|None = None, is_unresolved: bool = False):
572
+ super().__init__(model)
573
+ if not reading_str and not fields and not allow_no_fields:
574
+ raise ValueError("Either reading_str or fields must be provided")
575
+ if not reading_str and fields:
576
+ reading_str = " and ".join([f"{{{f.type._name}#{f.type._id}:{f.name}}}" for f in fields[:-1]])
577
+ reading_str = f"{reading_str} has {{{fields[-1].type._name}#{fields[-1].type._id}:{fields[-1].name}}}"
578
+ parts = []
579
+ if not fields:
580
+ (fields, parts) = Reading.parse(model, reading_str, fields, _source=self)
581
+ self._fields = fields
582
+ if not fields and not allow_no_fields:
583
+ exc("Invalid Relationship", "A Relationship must have at least one field.", [source(self)])
584
+ self._readings = [Reading(model, self, reading_str, fields, parts)]
585
+ self._short_name = short_name
586
+ self._relationships = {}
587
+ self._annotations: list[Expression|Relationship] = []
588
+ self._overloads = overloads
589
+ self._is_unresolved = is_unresolved
590
+ for f in self._fields:
591
+ if f._source is None:
592
+ f._source = self._source
593
+
594
+ def _dot(self, name: str) -> Relationship:
595
+ field_type = self._fields[-1].type
596
+ if name.lower() in self._relationships:
597
+ return self._relationships[name.lower()]
598
+ if field_type is CoreConcepts["Any"]:
599
+ rel = Property(fields=[
600
+ Field(self._fields[-1].name, field_type),
601
+ Field(name, CoreConcepts["Any"])
602
+ ], short_name=name, model=self._model, is_unresolved=True)
603
+ self._relationships[name.lower()] = rel
604
+ return rel
605
+ return field_type._dot(name)
606
+
607
+ def __getattr__(self, item):
608
+ if item.startswith("_"):
609
+ return object.__getattribute__(self, item)
610
+ op = self._fields[-1].type._dot(item)
611
+ return Chain(self, op)
612
+
613
+ def __call__(self, *args: Any, **kwargs: Any) -> Expression:
614
+ return Expression(self, list(args), kwargs, root=self)
615
+
616
+ def __getitem__(self, field: str|int|Concept) -> FieldRef:
617
+ resolved = _find_field(self._fields, field)
618
+ if not resolved:
619
+ raise KeyError(f"Field {field} not found in relationship with fields {[f.name for f in self._fields]}")
620
+ return FieldRef(self, field, *resolved)
621
+
622
+ def alt(self, reading_str: str) -> Reading:
623
+ reading = Reading(self._model, self, reading_str)
624
+ self._readings.append(reading)
625
+ return reading
626
+
627
+ def annotate(self, *annos:Expression|Relationship) -> Relationship:
628
+ self._annotations.extend(annos)
629
+ return self
630
+
631
+ def _to_concept(self) -> Concept|None:
632
+ return self._fields[-1].type
633
+
634
+ def __dir__(self):
635
+ default = set(super().__dir__())
636
+ return sorted(default.union(self._fields[-1].type.__dir__()))
637
+
638
+ def to_df(self) -> DataFrame:
639
+ refs = [self[ix] for ix in range(len(self._fields))]
640
+ return self._model.select(*refs).where(self(*refs)).to_df()
641
+
642
+ def inspect(self):
643
+ print(self.to_df())
644
+
645
+ #------------------------------------------------------
646
+ # Reading
647
+ #------------------------------------------------------
648
+
649
+ class Reading(Relationship):
650
+ def __init__(self, model: Model, relationship: Relationship, reading_str: str, reading_fields: list[Field] = [], reading_parts: list[str|int] = []):
651
+ Variable.__init__(self, model)
652
+ self._relationship = relationship
653
+ if not reading_fields or not reading_parts:
654
+ parsed_fields, parsed_parts = Reading.parse(model, reading_str, reading_fields, _source=self)
655
+ reading_fields = reading_fields or parsed_fields
656
+ reading_parts = reading_parts or parsed_parts
657
+ # make sure we can find all these fields in the base relationship
658
+ index_map = {}
659
+ matched = []
660
+ for field_i, field in enumerate(reading_fields):
661
+ found = next(((i, f) for i, f in enumerate(relationship._fields) if f._match(field)), None)
662
+ if not found:
663
+ raise ValueError(f"Field {field.name}:{field.type._name} not found in relationship with fields {[f'{f.name}:{f.type._name}' for f in relationship._fields]}")
664
+ matched.append(found[1])
665
+ index_map[field_i] = found[0]
666
+ self._fields = matched
667
+ self._reading = reading_str
668
+ self._short_name = ""
669
+ self._parts:list[str|int] = [index_map.get(p, p) for p in reading_parts]
670
+ self._relationships = {}
671
+ self._annotations: list[Expression|Relationship] = []
672
+
673
+ #------------------------------------------------------
674
+ # Parse
675
+ #------------------------------------------------------
676
+
677
+ @classmethod
678
+ def parse(cls, model: Model, reading: str, known_fields: list[Field], _source=None) -> Tuple[list[Field], list[str|int]]:
679
+ # match <class 'foo'> which is the serialized form of a python type mistakenly passed instead of a concept
680
+ class_pattern = re.compile(r'<class \'(.*?)\'>')
681
+ match = class_pattern.search(reading)
682
+ if match:
683
+ extra: list = [source(_source)]
684
+ if match.group(1) in pytype_to_concept_name:
685
+ concept = pytype_to_concept_name[match.group(1)]
686
+ extra.append(f" Did you mean to use [cyan]relationalai.semantics.{concept}[/cyan]?")
687
+ exc("Invalid field type", f"The type '{match.group(1)}' is not a valid Concept.", extra)
688
+
689
+ # {Type} or {name:Type}, where Type can include Number(38,14)
690
+ pattern = re.compile(r'\{([a-zA-Z0-9_.#]+(?:(?:\([0-9]+,[0-9]+\))(?:[#0-9]+)?)?)(?::\s*([a-zA-Z0-9_.]+(?:\([0-9]+,[0-9]+\))?))?\}')
691
+
692
+ namer = Namer()
693
+ fields: list[Field] = []
694
+ parts: list[str|int] = []
695
+
696
+ last_end = 0
697
+ is_old_style = True
698
+ for m in pattern.finditer(reading):
699
+ # literal chunk before this match
700
+ parts.append(reading[last_end:m.start()])
701
+ field_name, field_type_name = m.group(1), m.group(2)
702
+ field_type_id = None
703
+ if "#" in field_name:
704
+ temp_name = field_type_name
705
+ field_type_name, field_type_id = field_name.split("#")
706
+ field_name = temp_name or sanitize(field_type_name.lower())
707
+ is_old_style = False
708
+
709
+ # if we don't have a type_name, then only a type was provided
710
+ if not field_type_name:
711
+ field_type_name = field_name
712
+ field_name = sanitize(field_name.lower())
713
+
714
+ field_name = namer.get_name(field_name)
715
+ field_type = Concept.lookup_by_id.get(int(field_type_id)) \
716
+ if field_type_id \
717
+ else _find_concept(model, field_type_name, extra_types=[f.type for f in known_fields])
718
+ if field_type is None:
719
+ exc("Unknown Concept", f"The Concept '{field_type_name}' couldn't be found in the model", [
720
+ source(_source),
721
+ ])
722
+
723
+ fields.append(Field(field_name, field_type))
724
+ parts.append(len(fields) - 1)
725
+ last_end = m.end()
726
+
727
+ # trailing literal after the final match
728
+ if(last_end < len(reading)):
729
+ parts.append(reading[last_end:])
730
+
731
+ if is_old_style and fields:
732
+ correct = []
733
+ for part in parts:
734
+ if isinstance(part, int):
735
+ type_name = fields[part].type._name
736
+ correct_type_name = type_name
737
+ if isinstance(fields[part].type, NumberConcept):
738
+ precision = fields[part].type._precision
739
+ scale = fields[part].type._scale
740
+ if scale == 0:
741
+ correct_type_name = f"Integer"
742
+ else:
743
+ correct_type_name = f"Number.size({precision},{scale})"
744
+ if type_name.lower() != fields[part].name and correct_type_name.lower() != fields[part].name:
745
+ correct.append(f"{{{correct_type_name}:{fields[part].name}}}")
746
+ else:
747
+ correct.append(f"{{{correct_type_name}}}")
748
+ else:
749
+ correct.append(part)
750
+ warn("Deprecated format", "Plain strings for Relationships/Properties is deprecated. Use an f-string instead.", [
751
+ source(_source),
752
+ f'For example: [cyan]f"{"".join(correct)}"',
753
+ ])
754
+
755
+ return fields, parts
756
+
757
+ #------------------------------------------------------
758
+ # Property
759
+ #------------------------------------------------------
760
+
761
+ class Property(Relationship):
762
+ pass
763
+
764
+ #------------------------------------------------------
765
+ # Literal
766
+ #------------------------------------------------------
767
+
768
+ class Literal(Variable):
769
+ def __init__(self, value: Any, model:Model, type: Concept|None = None):
770
+ super().__init__(model)
771
+ self._value = value
772
+ self._type = type if type is not None else self._get_type(value)
773
+
774
+ def _to_concept(self) -> Concept:
775
+ return self._type
776
+
777
+ @staticmethod
778
+ def _get_type(value: Any) -> Concept:
779
+ if type(value) is float and (math.isnan(value) or math.isinf(value)):
780
+ return CoreConcepts["Float"]
781
+ if type(value) is float:
782
+ fractional_digits = 0 if math.isnan(value) else min(len(str(value).split(".")[1]), 14)
783
+ return CoreConcepts["Decimal"].size(38, fractional_digits) # type: ignore
784
+ if type(value) is decimal.Decimal:
785
+ str_value = format(value, 'f')
786
+ if '.' in str_value:
787
+ _, fractional_part = str_value.split('.')
788
+ scale = min(len(fractional_part), 14)
789
+ else:
790
+ scale = 14
791
+ return CoreConcepts["Decimal"].size(38, scale) # type: ignore
792
+ if type(value) in pytype_to_concept_name:
793
+ return CoreConcepts[pytype_to_concept_name[type(value)]]
794
+ else:
795
+ raise NotImplementedError(f"Literal type not implemented for value type: {type(value)}")
796
+
797
+ #------------------------------------------------------
798
+ # Chain
799
+ #------------------------------------------------------
800
+
801
+ class Chain(Variable):
802
+ def __init__(self, start: Chain|Concept|Relationship|DerivedColumn|Table|Ref|FieldRef|Expression, next: Relationship, is_ref = False):
803
+ super().__init__(start._model)
804
+ self._start = start
805
+ self._next = next
806
+ self._is_ref = is_ref
807
+
808
+ def __getattr__(self, item):
809
+ if item.startswith("_"):
810
+ return object.__getattribute__(self._next, item)
811
+ next_rel = self._next._dot(item)
812
+ return Chain(self, next_rel)
813
+
814
+ def __call__(self, *args: Any, **kwargs: Any) -> Expression:
815
+ last = self._next
816
+ assert not isinstance(last, Chain)
817
+ if len(last._fields) > len(args):
818
+ return Expression(last, [self._start, *args], kwargs, root=self)
819
+ return Expression(last, [*args], kwargs, root=self)
820
+
821
+ def to_dict_key(self) -> int|tuple:
822
+ if self._is_ref:
823
+ return self._id
824
+ return (self._start.to_dict_key(), self._next.to_dict_key())
825
+
826
+ def __getitem__(self, field: str|int|Concept) -> FieldRef:
827
+ resolved = _find_field(self._next._fields, field)
828
+ if not resolved:
829
+ raise KeyError(f"Field {field} not found in relationship with fields {[f.name for f in self._next._fields]}")
830
+ return FieldRef(self, field, *resolved)
831
+
832
+ def ref(self) -> Chain:
833
+ return Chain(self._start, self._next, is_ref=True)
834
+
835
+ def alt(self, reading_str: str) -> Reading:
836
+ return self._next.alt(reading_str)
837
+
838
+ def annotate(self, *annos:Expression|Relationship) -> Relationship:
839
+ return self._next.annotate(*annos)
840
+
841
+ def _to_concept(self) -> Concept | None:
842
+ return self._next._to_concept()
843
+
844
+ #------------------------------------------------------
845
+ # Expression
846
+ #------------------------------------------------------
847
+
848
+ class Expression(Variable):
849
+ def __init__(self, op: Relationship|Concept, args: Sequence[Value], kwargs: dict|None = None, root: Chain|Relationship|Concept|None = None):
850
+ super().__init__(op._model)
851
+ self._op = op
852
+ self._has_output = isinstance(op, Concept) or (any(not f.is_input for f in op._fields))
853
+ self._auto_filled = False
854
+ self._root = root
855
+
856
+ # clean args
857
+ clean_args = []
858
+ for arg in args:
859
+ if isinstance(arg, (ModelEnum, Field, TupleVariable)):
860
+ pass
861
+ elif isinstance(arg, TableSchema):
862
+ exc("Invalid argument", "Cannot use a schema as an argument to an Expression.", [source(self)])
863
+ elif not isinstance(arg, Variable):
864
+ arg = Literal(arg, self._model)
865
+ elif isinstance(arg, (Match, Fragment)):
866
+ arg._columns
867
+ clean_args.append(arg)
868
+ self._args = clean_args
869
+
870
+ self._kwargs = kwargs or {}
871
+ # clean kwargs
872
+ for k, v in self._kwargs.items():
873
+ if not isinstance(v, Variable):
874
+ self._kwargs[k] = Literal(v, self._model)
875
+
876
+ if isinstance(op, Relationship):
877
+ op_len = len(op._fields)
878
+ arg_len = len(self._args)
879
+ if op_len - arg_len == 1:
880
+ self._args.append(op._fields[-1].type.ref(name=op._fields[-1].name))
881
+ self._auto_filled = True
882
+ elif op_len != arg_len:
883
+ dir = "Too few" if arg_len < op_len - 1 else "Too many"
884
+ exc(f"{dir} args", f"{op._short_name or 'Relationship'} requires {op_len - 1}-{op_len} arguments but got {arg_len}", [
885
+ source(self),
886
+ ])
887
+
888
+ def __getattr__(self, item):
889
+ if item.startswith("_"):
890
+ return object.__getattribute__(self, item)
891
+ rel = self._op._dot(item)
892
+ return Chain(self, rel)
893
+
894
+ def __getitem__(self, field: str|int|Concept) -> FieldRef:
895
+ if not isinstance(self._op, Relationship):
896
+ raise TypeError(f"Cannot index into Expression with non-Relationship: {self._op}")
897
+ resolved = _find_field(self._op._fields, field)
898
+ if not resolved:
899
+ raise KeyError(f"Field {field} not found in relationship with fields {[f.name for f in self._op._fields]}")
900
+ return FieldRef(self, field, *resolved)
901
+
902
+ def _to_concept(self) -> Concept | None:
903
+ return self._args[-1]._to_concept() if self._args else self._op._to_concept()
904
+
905
+ #------------------------------------------------------
906
+ # New
907
+ #------------------------------------------------------
908
+
909
+ class New(Expression):
910
+ def __init__(self, concept: Concept, args: Sequence[Any], kwargs: dict[str, Any], identity_only: bool = False):
911
+ clean_args = []
912
+ row_ids = []
913
+ for arg in args:
914
+ if isinstance(arg, TableSchema):
915
+ row_ids.append(arg._table)
916
+ lower_case_kwargs = {k.lower() for k, v in kwargs.items()}
917
+ # add any keyword args that aren't already in kwargs
918
+ for col in arg.get_columns():
919
+ if col._short_name and col._short_name.lower() not in lower_case_kwargs:
920
+ kwargs[col._short_name] = col(arg._table)
921
+ else:
922
+ clean_args.append(arg)
923
+ for k in list(kwargs.keys()):
924
+ concept._dot(k)
925
+ super().__init__(concept, clean_args, kwargs)
926
+ self._identity_only = identity_only
927
+ self._row_ids = row_ids
928
+
929
+ #------------------------------------------------------
930
+ # FilterBy
931
+ #------------------------------------------------------
932
+
933
+ class FilterBy(Expression):
934
+ def __init__(self, item: Concept|Ref, kwargs: dict[str, Any]):
935
+ concept = item._concept if isinstance(item, Ref) else item
936
+ super().__init__(concept, [item], kwargs)
937
+
938
+ #------------------------------------------------------
939
+ # FieldRef
940
+ #------------------------------------------------------
941
+
942
+ class FieldRef(Variable):
943
+ def __init__(self, root: Chain|Relationship|Expression, field: str|int|Concept, resolved: Field, resolved_ix:int):
944
+ super().__init__(root._model)
945
+ self._root = root
946
+ self._field = field
947
+ self._resolved = resolved
948
+ self._resolved_ix = resolved_ix
949
+
950
+ def _to_concept(self) -> Concept:
951
+ return self._resolved.type
952
+
953
+ def __getattr__(self, item):
954
+ if item.startswith("_"):
955
+ return object.__getattribute__(self, item)
956
+ return Chain(self, self._resolved.type._dot(item))
957
+
958
+ def to_dict_key(self) -> tuple:
959
+ return (self._root.to_dict_key(), self._resolved._id)
960
+
961
+
962
+ #------------------------------------------------------
963
+ # MetaRef
964
+ #------------------------------------------------------
965
+
966
+ class MetaRef(Variable):
967
+ def __init__(self, target: Concept|Relationship|Field):
968
+ model = target._model if isinstance(target, DSLBase) else target.type._model
969
+ super().__init__(model)
970
+ self._target = target
971
+
972
+ #------------------------------------------------------
973
+ # TupleVariable
974
+ #------------------------------------------------------
975
+
976
+ class TupleVariable:
977
+ def __init__(self, items: Sequence[Value|Distinct]):
978
+ self._items = list(items)
979
+ self._source = SourcePos.new()
980
+
981
+ #------------------------------------------------------
982
+ # AsBool
983
+ #------------------------------------------------------
984
+
985
+ class AsBool(Variable):
986
+ def __init__(self, item: Variable):
987
+ super().__init__(item._model)
988
+ self._item = item
989
+
990
+ def _to_concept(self) -> Concept:
991
+ return CoreConcepts["Boolean"]
992
+
993
+ #------------------------------------------------------
994
+ # Alias
995
+ #------------------------------------------------------
996
+
997
+ class Alias(Variable):
998
+ def __init__(self, source: Variable, alias: str):
999
+ super().__init__(source._model)
1000
+ self._source = source
1001
+ self._alias = alias
1002
+
1003
+ def _to_concept(self) -> Concept|None:
1004
+ return self._source._to_concept()
1005
+
1006
+ def __format__(self, format_spec: str) -> str:
1007
+ if isinstance(self._source, Concept):
1008
+ if format_spec:
1009
+ exc("Invalid alias", f"Alias already specifies an alias for this concept, you can remove `:{format_spec}`")
1010
+ return self._source.__format__(self._alias)
1011
+ return super().__format__(format_spec)
1012
+
1013
+ #------------------------------------------------------
1014
+ # Match
1015
+ #------------------------------------------------------
1016
+
1017
+ class Match(DerivedTable):
1018
+ def __init__(self, model:Model, *items: Statement):
1019
+ super().__init__(model)
1020
+ t = type(self)
1021
+ self._items = [
1022
+ x
1023
+ for item in items
1024
+ for x in (item._items if (type(item) is t and isinstance(item, Match)) else (item,))
1025
+ ] # flatten nested Matches/Unions
1026
+
1027
+ def _get_cols(self) -> list[DerivedColumn]:
1028
+ return [DerivedColumn(self, i) for i in range(self._arg_count())]
1029
+
1030
+ def _arg_count(self) -> int:
1031
+ counts = []
1032
+ for item in self._items:
1033
+ if isinstance(item, DerivedTable):
1034
+ try:
1035
+ counts.append(len(item._columns))
1036
+ except ValueError:
1037
+ counts.append(0)
1038
+ else:
1039
+ # Expressions with no output and Not are filters, do not count as returning values
1040
+ is_filter = isinstance(item, Not) or (isinstance(item, Expression) and not item._has_output)
1041
+ counts.append(0 if is_filter else 1)
1042
+ if not counts:
1043
+ return 0
1044
+ first = counts[0]
1045
+ if any(c != first for c in counts[1:]):
1046
+ exc("Inconsistent branches",
1047
+ f"All branches in a {self.__class__.__name__} must have the same number of returned values",
1048
+ [source(self)])
1049
+ return first
1050
+
1051
+ def __getattr__(self, item) -> Chain:
1052
+ if item.startswith("_"):
1053
+ return object.__getattribute__(self, item)
1054
+ return getattr(self._columns[-1], item)
1055
+
1056
+ #------------------------------------------------------
1057
+ # Union
1058
+ #------------------------------------------------------
1059
+
1060
+ class Union(Match):
1061
+ def __init__(self, model:Model, *items: Value):
1062
+ super().__init__(model, *items)
1063
+
1064
+ #------------------------------------------------------
1065
+ # Not
1066
+ #------------------------------------------------------
1067
+
1068
+ class Not(DSLBase):
1069
+ def __init__(self, *items: Value, model:Model):
1070
+ super().__init__(model)
1071
+ self._items = items
1072
+
1073
+ def __or__(self, other) -> Match:
1074
+ return Match(self._model, self, other)
1075
+
1076
+ def __and__(self, other) -> Fragment:
1077
+ if isinstance(other, Fragment):
1078
+ new = other.where()
1079
+ new._where.insert(0, self)
1080
+ return new
1081
+ return self._model.where(self, other)
1082
+
1083
+ #------------------------------------------------------
1084
+ # Distinct
1085
+ #------------------------------------------------------
1086
+
1087
+ class Distinct(DSLBase):
1088
+ def __init__(self, *items: Value, model:Model):
1089
+ super().__init__(model)
1090
+ self._items = items
1091
+
1092
+ #------------------------------------------------------
1093
+ # Aggregate
1094
+ #------------------------------------------------------
1095
+
1096
+ class Group(DSLBase):
1097
+ def __init__(self, *args: Value):
1098
+ model = [arg._model for arg in args if isinstance(arg, Variable)][0] if args else None
1099
+ super().__init__(model) # type: ignore
1100
+ self._args = list(args)
1101
+
1102
+ def _extend(self, args: Sequence[Value]) -> Group:
1103
+ new = Group(*self._args)
1104
+ new._args.extend(args)
1105
+ return new
1106
+
1107
+ def _clone(self):
1108
+ return Group(*self._args)
1109
+
1110
+ class Aggregate(Variable):
1111
+ def __init__(self, op: Relationship, *args: Value|Distinct, check_args: bool = True, distinct: bool = False):
1112
+ model = self._find_model(args) or op._model
1113
+ super().__init__(model)
1114
+ self._op = op
1115
+ self._where = Fragment(model)
1116
+ self._group = Group()
1117
+ self._args: list[Value] = []
1118
+ self._projection_args: list[Value] = []
1119
+ self._distinct = distinct
1120
+ if check_args:
1121
+ # unwrap distinct if present
1122
+ if any(isinstance(arg, Distinct) for arg in args):
1123
+ if len(args) != 1:
1124
+ exc("Invalid distinct", "Distinct must be applied to all arguments", [source(self)])
1125
+ assert isinstance(args[0], Distinct)
1126
+ args = args[0]._items
1127
+ self._distinct = True
1128
+
1129
+ args = cast(tuple[Value], args)
1130
+
1131
+ num_inputs = sum(f.is_input for f in op._fields)
1132
+ if len(args) < num_inputs:
1133
+ need = [f.name for f in op._fields if f.is_input][len(args):]
1134
+ exc("Missing argument",
1135
+ f"`{op._short_name or 'Relationship'}(..)` is missing: {', '.join(need)}",
1136
+ [source(self)])
1137
+
1138
+ self._projection_args = list(args[:-num_inputs] if num_inputs else args)
1139
+ supplied = iter(args[-num_inputs:] if num_inputs else [])
1140
+
1141
+ self._args = [
1142
+ (next(supplied) if f.is_input else f.type.ref(f.name))
1143
+ for f in op._fields
1144
+ ]
1145
+
1146
+ def _find_model(self, args: Sequence[Value|Distinct|TupleVariable]) -> Model|None:
1147
+ for arg in args:
1148
+ if isinstance(arg, (Variable, Distinct)):
1149
+ return arg._model
1150
+ elif isinstance(arg, TupleVariable):
1151
+ for item in arg._items:
1152
+ if isinstance(item, (Variable, Distinct)):
1153
+ return item._model
1154
+ return None
1155
+
1156
+
1157
+ def where(self, *args: Value) -> Aggregate:
1158
+ new = self._clone()
1159
+ new._where = new._where.where(*args)
1160
+ return new
1161
+
1162
+ def per(self, *args: Value) -> Aggregate:
1163
+ new = self._clone()
1164
+ new._group = new._group._extend(args)
1165
+ return new
1166
+
1167
+ def _clone(self):
1168
+ agg = Aggregate(self._op, check_args=False)
1169
+ agg._args = self._args
1170
+ agg._projection_args = self._projection_args
1171
+ agg._where = self._where
1172
+ agg._group = self._group
1173
+ agg._distinct = self._distinct
1174
+ return agg
1175
+
1176
+ #------------------------------------------------------
1177
+ # Data
1178
+ #------------------------------------------------------
1179
+
1180
+ class Data(Table):
1181
+ def __init__(self, df:DataFrame, model:Model):
1182
+ schema = {}
1183
+ for col in df.columns:
1184
+ _type = df[col].dtype
1185
+ if pd.api.types.is_datetime64_any_dtype(_type):
1186
+ col_type = "DateTime"
1187
+ elif pd.api.types.is_object_dtype(_type) and self._is_date_column(df[col]):
1188
+ col_type = "Date"
1189
+ else:
1190
+ col_type = pytype_to_concept_name.get(_type, "Any")
1191
+ if isinstance(col, int):
1192
+ col = f"col{col}"
1193
+ schema[col] = CoreConcepts[col_type]
1194
+ super().__init__("Data", schema, model)
1195
+ self._data = df
1196
+
1197
+ def _is_date_column(self, col) -> bool:
1198
+ sample = col.dropna()
1199
+ if sample.empty:
1200
+ return False
1201
+ sample_value = sample.iloc[0]
1202
+ return isinstance(sample_value, dt.date) and not isinstance(sample_value, dt.datetime)
1203
+
1204
+ @staticmethod
1205
+ def raw_to_df(data: DataFrame | list[tuple] | list[dict], columns:list[str]|None) -> DataFrame:
1206
+ if isinstance(data, DataFrame):
1207
+ return data
1208
+ if not data:
1209
+ return DataFrame()
1210
+ if isinstance(data, list):
1211
+ if isinstance(data[0], tuple):
1212
+ # Named tuple check
1213
+ if hasattr(data[0], '_fields'):
1214
+ return DataFrame([t._asdict() for t in data]) #type: ignore
1215
+ return DataFrame(data, columns=columns)
1216
+ elif isinstance(data[0], dict):
1217
+ return DataFrame(data)
1218
+ raise TypeError(f"Cannot convert {type(data)} to DataFrame. Use DataFrame, list of tuples, or list of dicts.")
1219
+
1220
+ #------------------------------------------------------
1221
+ # Enum
1222
+ #------------------------------------------------------
1223
+
1224
+ class ModelEnumMeta(EnumMeta):
1225
+ _concept: Concept
1226
+ def __setattr__(self, name: str, value: Any) -> None:
1227
+ if name.startswith("_") or isinstance(value, self):
1228
+ super().__setattr__(name, value)
1229
+ elif isinstance(value, (Relationship, Reading)):
1230
+ setattr(self._concept, name, value)
1231
+ else:
1232
+ raise AttributeError(f"Cannot set attribute {name} on {type(self).__name__}")
1233
+
1234
+ def __format__(self, format_spec: str) -> str:
1235
+ return format(self._concept, format_spec)
1236
+
1237
+ class ModelEnum(Enum, metaclass=ModelEnumMeta):
1238
+ _model:Model
1239
+
1240
+ def __init__(self, *args) -> None:
1241
+ super().__init__(*args)
1242
+ self._source = SourcePos.new()
1243
+
1244
+ def _compile_lookup(self):
1245
+ concept = getattr(self.__class__, "_concept")
1246
+ return concept.to_identity(name=self.name)
1247
+
1248
+ @classmethod
1249
+ def lookup(cls, value:Variable|str):
1250
+ concept = cls._concept
1251
+ return concept.to_identity(name=value)
1252
+
1253
+ # Python 3.10 doesn't correctly populate __members__ by the time it calls
1254
+ # __init_subclass__, so we need to initialize the members lazily when we
1255
+ # encounter the enum for the first time.
1256
+ @classmethod
1257
+ def _init_members(cls):
1258
+ if cls._has_inited_members:
1259
+ return
1260
+ c = cls._concept
1261
+ # Add the name and value attributes to the hashes we create for the enum
1262
+ members = [
1263
+ c.new(name=name, value=value.value)
1264
+ for name, value in cls.__members__.items()
1265
+ ]
1266
+ cls._model.define(*members)
1267
+ cls._has_inited_members = True
1268
+
1269
+ def __format__(self, format_spec: str) -> str:
1270
+ return format(self._concept, format_spec)
1271
+
1272
+ def create_enum_class(model: Model):
1273
+ class AttachedModelEnum(ModelEnum):
1274
+ def __init_subclass__(cls, **kwargs):
1275
+ super().__init_subclass__(**kwargs)
1276
+ # this is voodoo black magic that is doing meta meta programming where
1277
+ # we are plugging into anytime a new subtype of this class is created
1278
+ # and then creating a concept to represent the enum. This happens both
1279
+ # when you do `class Foo(Enum)` and when you do `Enum("Foo", [a, b, c])`
1280
+ cls._model = model
1281
+ c = model.Concept(
1282
+ cls.__name__,
1283
+ extends=[CoreConcepts["Enum"]],
1284
+ identify_by={"name": CoreConcepts["String"]}
1285
+ )
1286
+ model.enums.append(cls)
1287
+ model.enums_index[cls.__name__] = cls
1288
+ cls._has_inited_members = False
1289
+ cls._concept = c
1290
+
1291
+ return AttachedModelEnum
1292
+
1293
+ #------------------------------------------------------
1294
+ # Value
1295
+ #------------------------------------------------------
1296
+
1297
+ Value = Variable|Primitive|Field|TupleVariable
1298
+
1299
+ #------------------------------------------------------
1300
+ # Statement
1301
+ #------------------------------------------------------
1302
+
1303
+ Statement = Value | Group | Not | Distinct | Aggregate
1304
+ """Union of statement types."""
1305
+
1306
+ StatementAndSchema = Statement | TableSchema
1307
+
1308
+ #------------------------------------------------------
1309
+ # Fragment
1310
+ #------------------------------------------------------
1311
+
1312
+ @include_in_docs
1313
+ class Fragment(DerivedTable):
1314
+ """Composable chunk of a query with select/where/define state.
1315
+
1316
+ Parameters
1317
+ ----------
1318
+ model : Model
1319
+ The semantic model that provides type information and stores any
1320
+ definitions produced by this fragment.
1321
+ parent : Fragment, optional
1322
+ An existing fragment to inherit selection and filter state from when
1323
+ building chained queries.
1324
+ """
1325
+
1326
+ def __init__(self, model:Model, parent:Fragment|None=None):
1327
+ super().__init__(model)
1328
+ self._id = next(_global_id)
1329
+ self._select = []
1330
+ self._where = []
1331
+ self._require = []
1332
+ self._define = []
1333
+ self._order_by = []
1334
+ self._limit = 0
1335
+ self._model = model
1336
+ self._into:Optional[Table] = None
1337
+ self._is_into_update = False
1338
+ self._has_executed = False
1339
+ assert self._model, "Fragment must have a model"
1340
+
1341
+ self._parent = parent
1342
+ # self._source = runtime_env.get_source_pos()
1343
+ self._meta = {}
1344
+ self._annotations = []
1345
+ if parent is not None:
1346
+ self._select.extend(parent._select)
1347
+ self._where.extend(parent._where)
1348
+ self._require.extend(parent._require)
1349
+ self._define.extend(parent._define)
1350
+ self._order_by.extend(parent._order_by)
1351
+ self._limit = parent._limit
1352
+
1353
+
1354
+ def _add_items(self, items:Sequence[Statement], to_attr:list[Statement]):
1355
+ # TODO: ensure that you are _either_ a select, require, or then
1356
+ # not a mix of them
1357
+ model = self._model
1358
+
1359
+ # remove any existing rules that this consumes
1360
+ for item in itertools.chain(items, [self._parent]):
1361
+ if isinstance(item, Fragment) and item._is_effect():
1362
+ model._remove_rule(item)
1363
+
1364
+ to_attr.extend(items)
1365
+ if self._is_effect():
1366
+ model._add_rule(self)
1367
+
1368
+ return self
1369
+
1370
+ #------------------------------------------------------
1371
+ # Select arg handling
1372
+ #------------------------------------------------------
1373
+
1374
+ def _check_select_args(self, args:Sequence[StatementAndSchema]) -> Sequence[Statement]:
1375
+ clean_args = []
1376
+ for arg in args:
1377
+ # If you select x > y, treat that as AsBool(x > y)
1378
+ if isinstance(arg, Expression) and not arg._has_output:
1379
+ clean_args.append(AsBool(arg))
1380
+ elif isinstance(arg, TableSchema):
1381
+ for col in arg.get_columns():
1382
+ clean_args.append(col(arg._table))
1383
+ else:
1384
+ clean_args.append(arg)
1385
+ return clean_args
1386
+
1387
+ #------------------------------------------------------
1388
+ # Core API
1389
+ #------------------------------------------------------
1390
+
1391
+ def where(self, *args: Statement) -> Fragment:
1392
+ f = Fragment(self._model, parent=self)
1393
+ return f._add_items(args, f._where)
1394
+
1395
+ def select(self, *args: StatementAndSchema) -> Fragment:
1396
+ f = Fragment(self._model, parent=self)
1397
+ return f._add_items(self._check_select_args(args), f._select)
1398
+
1399
+ def require(self, *args: Statement) -> Fragment:
1400
+ f = Fragment(self._model, parent=self)
1401
+ return f._add_items(args, f._require)
1402
+
1403
+ def define(self, *args: Statement) -> Fragment:
1404
+ f = Fragment(self._model, parent=self)
1405
+ return f._add_items(args, f._define)
1406
+
1407
+ if not TYPE_CHECKING:
1408
+ def order_by(self, *args: Any) -> Fragment:
1409
+ exc("Feature unavailable", "The 'order_by' method is not yet available when querying RAI directly.", [
1410
+ source(self),
1411
+ "You can use [cyan]`relationalai.semantics.std.aggregates.rank`[/cyan] and select it as the first column as a temporary substitute.",
1412
+ ])
1413
+ f = Fragment(self._model, parent=self)
1414
+ return f._add_items(args, f._order_by)
1415
+
1416
+ def limit(self, n:int) -> Fragment:
1417
+ exc("Feature unavailable", "The 'order_by' method is not yet available when querying RAI directly.", [
1418
+ source(self),
1419
+ "You can use [cyan]`relationalai.semantics.std.aggregates.limit`[/cyan] in a where clause as a temporary substitute.",
1420
+ ])
1421
+ f = Fragment(self._model, parent=self)
1422
+ f._limit = n
1423
+ return f
1424
+
1425
+ # def meta(self, **kwargs: Any) -> Fragment:
1426
+ # self._meta.update(kwargs)
1427
+ # return self
1428
+
1429
+ def annotate(self, *annos:Expression|Relationship) -> Fragment:
1430
+ self._annotations.extend(annos)
1431
+ return self
1432
+
1433
+ #------------------------------------------------------
1434
+ # into
1435
+ #------------------------------------------------------
1436
+
1437
+ def into(self, table: Table, update=False) -> Fragment:
1438
+ f = Fragment(self._model, parent=self)
1439
+ f._into = table
1440
+ f._is_into_update = update
1441
+ self._model.exports.add(f)
1442
+ return f
1443
+
1444
+ #------------------------------------------------------
1445
+ # Execution
1446
+ #------------------------------------------------------
1447
+
1448
+ def exec(self):
1449
+ if self._has_executed:
1450
+ return
1451
+ if self._into is None:
1452
+ exc("Cannot execute", "Query must have an 'into' table specified to execute.", [source(self)])
1453
+ from relationalai.shims.executor import execute
1454
+ self._has_executed = True
1455
+ return execute(self, self._model, export_to=self._into._name, update=self._is_into_update)
1456
+
1457
+ def to_df(self):
1458
+ from relationalai.shims.executor import execute
1459
+ return execute(self, self._model)
1460
+
1461
+ def inspect(self):
1462
+ print(self.to_df())
1463
+
1464
+ #------------------------------------------------------
1465
+ # helpers
1466
+ #------------------------------------------------------
1467
+
1468
+ def _is_effect(self) -> bool:
1469
+ return bool(self._define or self._require)
1470
+
1471
+ def _is_where_only(self) -> bool:
1472
+ return not self._select and not self._define and not self._require and not self._order_by
1473
+
1474
+ #------------------------------------------------------
1475
+ # And/Or
1476
+ #------------------------------------------------------
1477
+
1478
+ def __or__(self, other) -> Match:
1479
+ return Match(self._model, self, other)
1480
+
1481
+ def __and__(self, other) -> Fragment:
1482
+ if not isinstance(other, Fragment):
1483
+ other = Fragment(self._model).where(other)
1484
+ if self._is_where_only() and other._is_where_only():
1485
+ return self.where(*other._where)
1486
+ elif self._is_where_only():
1487
+ return other.where(*self._where)
1488
+ elif other._is_where_only():
1489
+ return self.where(*other._where)
1490
+ else:
1491
+ raise Exception("Cannot AND two non-where-only fragments")
1492
+
1493
+ #------------------------------------------------------
1494
+ # DerivedTable cols
1495
+ #------------------------------------------------------
1496
+
1497
+ def _get_cols(self):
1498
+ return [DerivedColumn.from_value(self, i, col) for i, col in enumerate(self._select)]
1499
+
1500
+ #------------------------------------------------------
1501
+ # Marterialize
1502
+ #------------------------------------------------------
1503
+
1504
+ def to_metamodel(self):
1505
+ m = self._model
1506
+ return m._compiler.compile(self)
1507
+
1508
+ #------------------------------------------------------
1509
+ # Model
1510
+ #------------------------------------------------------
1511
+
1512
+ @include_in_docs
1513
+ class Model:
1514
+ """Class representing a semantic model.
1515
+
1516
+ Parameters
1517
+ ----------
1518
+ name : str, optional
1519
+ Name of the model.
1520
+ exclude_core : bool, optional
1521
+ If True, the core library will not be included by default.
1522
+ is_library : bool, optional
1523
+ If True, this model is a library and will not be added to the global
1524
+ list of models.
1525
+
1526
+ Examples
1527
+ --------
1528
+ Create a model object:
1529
+
1530
+ >>> from relationalai.semantics import Model
1531
+ >>> model = Model(name="MyModel")
1532
+ """
1533
+ all_models:list[Model] = []
1534
+
1535
+ def __init__(self, name: str = "", exclude_core: bool = False, is_library: bool = False):
1536
+ self.name = name
1537
+ self.defines:KeyedSet[Fragment] = KeyedSet(dsl_key)
1538
+ self.requires:KeyedSet[Fragment] = KeyedSet(dsl_key)
1539
+ self.exports:KeyedSet[Fragment] = KeyedSet(dsl_key)
1540
+ self.libraries = []
1541
+ self.concepts: list[Concept] = []
1542
+ self.tables: list[Table] = []
1543
+ self.relationships: list[Relationship] = []
1544
+ self.enums: list[Type[ModelEnum]] = []
1545
+ self.concept_index: dict[str, Concept] = {}
1546
+ self.table_index: dict[str, Table] = {}
1547
+ self.relationship_index: dict[str, Relationship] = {}
1548
+ self.enums_index: dict[str, Type[ModelEnum]] = {}
1549
+ self._source = SourcePos.new()
1550
+
1551
+ self.Enum = create_enum_class(self)
1552
+
1553
+ if not is_library:
1554
+ Model.all_models.append(self)
1555
+
1556
+ self.__compiler = None
1557
+ if not exclude_core:
1558
+ self.libraries.append(CoreLibrary)
1559
+
1560
+ #------------------------------------------------------
1561
+ # Internal
1562
+ #------------------------------------------------------
1563
+
1564
+ @property
1565
+ def _compiler(self):
1566
+ if not self.__compiler:
1567
+ from .front_compiler import FrontCompiler
1568
+ self.__compiler = FrontCompiler(self)
1569
+ return self.__compiler
1570
+
1571
+ def _find_concept(self, name: str) -> Concept|None:
1572
+ if name in self.concept_index:
1573
+ return self.concept_index[name]
1574
+ if name in self.table_index:
1575
+ return self.table_index[name]
1576
+ for lib in self.libraries:
1577
+ found = lib._find_concept(name)
1578
+ if found is not None:
1579
+ return found
1580
+
1581
+ def _remove_rule(self, fragment: Fragment) -> None:
1582
+ if fragment._define and fragment in self.defines:
1583
+ self.defines.remove(fragment)
1584
+ elif fragment._require and fragment in self.requires:
1585
+ self.requires.remove(fragment)
1586
+ else:
1587
+ raise ValueError("Fragment must have either define or require clauses to be removed as a rule")
1588
+
1589
+ def _add_rule(self, fragment: Fragment) -> None:
1590
+ if fragment._define and fragment not in self.defines:
1591
+ self.defines.add(fragment)
1592
+ elif fragment._require and fragment not in self.requires:
1593
+ self.requires.add(fragment)
1594
+ else:
1595
+ raise ValueError("Fragment must have either define or require clauses to be added as a rule")
1596
+
1597
+ #------------------------------------------------------
1598
+ # Primary API
1599
+ #------------------------------------------------------
1600
+
1601
+ def Concept(self, name: str, extends: list[Concept] = [], identify_by: dict[str, Property|Concept] = {}) -> Concept:
1602
+ c = Concept(name, extends=extends, identify_by=identify_by, model=self)
1603
+ self.concepts.append(c)
1604
+ self.concept_index[name] = c
1605
+ return c
1606
+
1607
+ def Table(self, path: str, schema: dict[str, Concept] = {}) -> Table:
1608
+ t = Table(path, schema=schema, model=self)
1609
+ self.tables.append(t)
1610
+ self.table_index[path] = t
1611
+ return t
1612
+
1613
+ def Relationship(self, reading: str = "", fields: list[Field] = [], short_name: str = "") -> Relationship:
1614
+ r = Relationship(self, reading, fields, short_name)
1615
+ self.relationships.append(r)
1616
+ self.relationship_index[short_name] = r
1617
+ return r
1618
+
1619
+ def Property(self, reading: str = "", fields: list[Field] = [], short_name: str = "") -> Property:
1620
+ p = Property(self, reading, fields, short_name)
1621
+ self.relationships.append(p)
1622
+ self.relationship_index[short_name] = p
1623
+ return p
1624
+
1625
+ def select(self, *args: StatementAndSchema) -> Fragment:
1626
+ f = Fragment(self)
1627
+ return f.select(*args)
1628
+
1629
+ def where(self, *args: Statement) -> Fragment:
1630
+ f = Fragment(self)
1631
+ return f.where(*args)
1632
+
1633
+ def require(self, *args: Statement) -> Fragment:
1634
+ f = Fragment(self)
1635
+ return f.require(*args)
1636
+
1637
+ def define(self, *args: Statement) -> Fragment:
1638
+ f = Fragment(self)
1639
+ return f.define(*args)
1640
+
1641
+ def union(self, *items: Value) -> Union:
1642
+ return Union(self, *items)
1643
+
1644
+ def data(self, data: DataFrame | list[tuple] | list[dict], columns: list[str]|None = None) -> Data:
1645
+ df = Data.raw_to_df(data, columns)
1646
+ return Data(df, self)
1647
+
1648
+ def not_(self, *items: Value) -> Not:
1649
+ return Not(*items, model=self)
1650
+
1651
+ def distinct(self, *items: Value) -> Distinct:
1652
+ return Distinct(*items, model=self)
1653
+
1654
+ #------------------------------------------------------
1655
+ # Meta
1656
+ #------------------------------------------------------
1657
+
1658
+ def to_metamodel(self) -> mModel:
1659
+ return self._compiler.compile_model(self)
1660
+
1661
+ #------------------------------------------------------
1662
+ # Library
1663
+ #------------------------------------------------------
1664
+
1665
+ class Library(Model):
1666
+ def __init__(self, name: str, exclude_core: bool = False):
1667
+ super().__init__(name=name, exclude_core=exclude_core, is_library=True)
1668
+
1669
+ def Type(self, name: str, super_types: list[Concept] = []) -> Concept:
1670
+ c = self.Concept(name, extends=super_types)
1671
+ self._register_builtin(c)
1672
+ return c
1673
+
1674
+ def Relation(self, name: str, fields: list[Field], overloads: list[list[Concept]]|None = None, annotations: list[Any]|None = None) -> Relationship:
1675
+ r = Relationship(self, "", fields, name, allow_no_fields=True, overloads=overloads)
1676
+ self.relationships.append(r)
1677
+ self.relationship_index[name] = r
1678
+ self._register_builtin(r)
1679
+ # TODO - deal with annotations
1680
+ return r
1681
+
1682
+ def _register_builtin(self, builtin: Concept|Relationship) -> None:
1683
+ """ Register a builtin concept or relationship in the global builtins registry. """
1684
+ builtins.register(self.name, self._compiler.to_relation(builtin))
1685
+
1686
+
1687
+ #------------------------------------------------------
1688
+ # Core Library
1689
+ #------------------------------------------------------
1690
+
1691
+ # Library is populated when relationalai.semantics.frontend.core is imported
1692
+ CoreLibrary: Library = Library("core", exclude_core=True)
1693
+ CoreRelationships = CoreLibrary.relationship_index
1694
+ CoreConcepts = CoreLibrary.concept_index
1695
+
1696
+
1697
+ #------------------------------------------------------
1698
+ # todo
1699
+ #------------------------------------------------------
1700
+
1701
+ """
1702
+ x new/to_identity/filter_by
1703
+ x capture all defines/requires
1704
+ x identify_by
1705
+ x figure out Table/DerivedTable
1706
+ x data node
1707
+ x in_
1708
+ x error on invalid iteration/sum/min/max
1709
+ x Aggregates
1710
+ x fill in std.agg functions when Thiago's lib stuff lands
1711
+ - Error?
1712
+ x rank stuff
1713
+ - validation checks for identify_by
1714
+ - unique
1715
+ - Enum?
1716
+ """