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