relationalai 0.13.5__py3-none-any.whl → 1.0.0a2__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.
- relationalai/__init__.py +1 -256
- relationalai/config/__init__.py +56 -0
- relationalai/config/config.py +289 -0
- relationalai/config/config_fields.py +86 -0
- relationalai/config/connections/__init__.py +46 -0
- relationalai/config/connections/base.py +23 -0
- relationalai/config/connections/duckdb.py +29 -0
- relationalai/config/connections/snowflake.py +243 -0
- relationalai/config/external/__init__.py +17 -0
- relationalai/config/external/dbt_converter.py +101 -0
- relationalai/config/external/dbt_models.py +93 -0
- relationalai/config/external/snowflake_converter.py +41 -0
- relationalai/config/external/snowflake_models.py +85 -0
- relationalai/config/external/utils.py +19 -0
- relationalai/config/shims.py +1 -0
- relationalai/semantics/__init__.py +146 -22
- relationalai/semantics/backends/lqp/annotations.py +11 -0
- relationalai/semantics/backends/sql/sql_compiler.py +327 -0
- relationalai/semantics/frontend/base.py +1719 -0
- relationalai/semantics/frontend/core.py +179 -0
- relationalai/semantics/frontend/front_compiler.py +1316 -0
- relationalai/semantics/frontend/pprint.py +408 -0
- relationalai/semantics/metamodel/__init__.py +6 -40
- relationalai/semantics/metamodel/builtins.py +206 -772
- relationalai/semantics/metamodel/metamodel.py +465 -0
- relationalai/semantics/metamodel/metamodel_analyzer.py +519 -0
- relationalai/semantics/metamodel/pprint.py +414 -0
- relationalai/semantics/metamodel/rewriter.py +266 -0
- relationalai/semantics/metamodel/typer.py +1213 -0
- relationalai/semantics/std/__init__.py +60 -40
- relationalai/semantics/std/aggregates.py +148 -0
- relationalai/semantics/std/common.py +44 -0
- relationalai/semantics/std/constraints.py +37 -43
- relationalai/semantics/std/datetime.py +249 -135
- relationalai/semantics/std/decimals.py +45 -52
- relationalai/semantics/std/floats.py +13 -5
- relationalai/semantics/std/integers.py +26 -11
- relationalai/semantics/std/math.py +183 -112
- relationalai/semantics/std/numbers.py +86 -0
- relationalai/semantics/std/re.py +80 -62
- relationalai/semantics/std/strings.py +101 -46
- relationalai/shims/executor.py +179 -0
- relationalai/shims/helpers.py +126 -0
- relationalai/shims/hoister.py +221 -0
- relationalai/shims/mm2v0.py +1394 -0
- relationalai/tools/cli/__init__.py +6 -0
- relationalai/tools/cli/cli.py +90 -0
- relationalai/tools/cli/components/__init__.py +5 -0
- relationalai/tools/cli/components/progress_reader.py +1524 -0
- relationalai/tools/cli/components/utils.py +58 -0
- relationalai/tools/cli/config_template.py +45 -0
- relationalai/tools/cli/dev.py +19 -0
- relationalai/tools/debugger.py +289 -183
- relationalai/tools/typer_debugger.py +93 -0
- relationalai/util/dataclasses.py +43 -0
- relationalai/util/docutils.py +40 -0
- relationalai/util/error.py +199 -0
- relationalai/util/format.py +48 -109
- relationalai/util/naming.py +145 -0
- relationalai/util/python.py +35 -0
- relationalai/util/runtime.py +156 -0
- relationalai/util/schema.py +197 -0
- relationalai/util/source.py +185 -0
- relationalai/util/structures.py +163 -0
- relationalai/util/tracing.py +261 -0
- relationalai-1.0.0a2.dist-info/METADATA +44 -0
- relationalai-1.0.0a2.dist-info/RECORD +489 -0
- relationalai-1.0.0a2.dist-info/WHEEL +5 -0
- relationalai-1.0.0a2.dist-info/entry_points.txt +3 -0
- relationalai-1.0.0a2.dist-info/top_level.txt +2 -0
- v0/relationalai/__init__.py +216 -0
- v0/relationalai/clients/__init__.py +5 -0
- v0/relationalai/clients/azure.py +477 -0
- v0/relationalai/clients/client.py +912 -0
- v0/relationalai/clients/config.py +673 -0
- v0/relationalai/clients/direct_access_client.py +118 -0
- v0/relationalai/clients/hash_util.py +31 -0
- v0/relationalai/clients/local.py +571 -0
- v0/relationalai/clients/profile_polling.py +73 -0
- v0/relationalai/clients/result_helpers.py +420 -0
- v0/relationalai/clients/snowflake.py +3869 -0
- v0/relationalai/clients/types.py +113 -0
- v0/relationalai/clients/use_index_poller.py +980 -0
- v0/relationalai/clients/util.py +356 -0
- v0/relationalai/debugging.py +389 -0
- v0/relationalai/dsl.py +1749 -0
- v0/relationalai/early_access/builder/__init__.py +30 -0
- v0/relationalai/early_access/builder/builder/__init__.py +35 -0
- v0/relationalai/early_access/builder/snowflake/__init__.py +12 -0
- v0/relationalai/early_access/builder/std/__init__.py +25 -0
- v0/relationalai/early_access/builder/std/decimals/__init__.py +12 -0
- v0/relationalai/early_access/builder/std/integers/__init__.py +12 -0
- v0/relationalai/early_access/builder/std/math/__init__.py +12 -0
- v0/relationalai/early_access/builder/std/strings/__init__.py +14 -0
- v0/relationalai/early_access/devtools/__init__.py +12 -0
- v0/relationalai/early_access/devtools/benchmark_lqp/__init__.py +12 -0
- v0/relationalai/early_access/devtools/extract_lqp/__init__.py +12 -0
- v0/relationalai/early_access/dsl/adapters/orm/adapter_qb.py +427 -0
- v0/relationalai/early_access/dsl/adapters/orm/parser.py +636 -0
- v0/relationalai/early_access/dsl/adapters/owl/adapter.py +176 -0
- v0/relationalai/early_access/dsl/adapters/owl/parser.py +160 -0
- v0/relationalai/early_access/dsl/bindings/common.py +402 -0
- v0/relationalai/early_access/dsl/bindings/csv.py +170 -0
- v0/relationalai/early_access/dsl/bindings/legacy/binding_models.py +143 -0
- v0/relationalai/early_access/dsl/bindings/snowflake.py +64 -0
- v0/relationalai/early_access/dsl/codegen/binder.py +411 -0
- v0/relationalai/early_access/dsl/codegen/common.py +79 -0
- v0/relationalai/early_access/dsl/codegen/helpers.py +23 -0
- v0/relationalai/early_access/dsl/codegen/relations.py +700 -0
- v0/relationalai/early_access/dsl/codegen/weaver.py +417 -0
- v0/relationalai/early_access/dsl/core/builders/__init__.py +47 -0
- v0/relationalai/early_access/dsl/core/builders/logic.py +19 -0
- v0/relationalai/early_access/dsl/core/builders/scalar_constraint.py +11 -0
- v0/relationalai/early_access/dsl/core/constraints/predicate/atomic.py +455 -0
- v0/relationalai/early_access/dsl/core/constraints/predicate/universal.py +73 -0
- v0/relationalai/early_access/dsl/core/constraints/scalar.py +310 -0
- v0/relationalai/early_access/dsl/core/context.py +13 -0
- v0/relationalai/early_access/dsl/core/cset.py +132 -0
- v0/relationalai/early_access/dsl/core/exprs/__init__.py +116 -0
- v0/relationalai/early_access/dsl/core/exprs/relational.py +18 -0
- v0/relationalai/early_access/dsl/core/exprs/scalar.py +412 -0
- v0/relationalai/early_access/dsl/core/instances.py +44 -0
- v0/relationalai/early_access/dsl/core/logic/__init__.py +193 -0
- v0/relationalai/early_access/dsl/core/logic/aggregation.py +98 -0
- v0/relationalai/early_access/dsl/core/logic/exists.py +223 -0
- v0/relationalai/early_access/dsl/core/logic/helper.py +163 -0
- v0/relationalai/early_access/dsl/core/namespaces.py +32 -0
- v0/relationalai/early_access/dsl/core/relations.py +276 -0
- v0/relationalai/early_access/dsl/core/rules.py +112 -0
- v0/relationalai/early_access/dsl/core/std/__init__.py +45 -0
- v0/relationalai/early_access/dsl/core/temporal/recall.py +6 -0
- v0/relationalai/early_access/dsl/core/types/__init__.py +270 -0
- v0/relationalai/early_access/dsl/core/types/concepts.py +128 -0
- v0/relationalai/early_access/dsl/core/types/constrained/__init__.py +267 -0
- v0/relationalai/early_access/dsl/core/types/constrained/nominal.py +143 -0
- v0/relationalai/early_access/dsl/core/types/constrained/subtype.py +124 -0
- v0/relationalai/early_access/dsl/core/types/standard.py +92 -0
- v0/relationalai/early_access/dsl/core/types/unconstrained.py +50 -0
- v0/relationalai/early_access/dsl/core/types/variables.py +203 -0
- v0/relationalai/early_access/dsl/ir/compiler.py +318 -0
- v0/relationalai/early_access/dsl/ir/executor.py +260 -0
- v0/relationalai/early_access/dsl/ontologies/constraints.py +88 -0
- v0/relationalai/early_access/dsl/ontologies/export.py +30 -0
- v0/relationalai/early_access/dsl/ontologies/models.py +453 -0
- v0/relationalai/early_access/dsl/ontologies/python_printer.py +303 -0
- v0/relationalai/early_access/dsl/ontologies/readings.py +60 -0
- v0/relationalai/early_access/dsl/ontologies/relationships.py +322 -0
- v0/relationalai/early_access/dsl/ontologies/roles.py +87 -0
- v0/relationalai/early_access/dsl/ontologies/subtyping.py +55 -0
- v0/relationalai/early_access/dsl/orm/constraints.py +438 -0
- v0/relationalai/early_access/dsl/orm/measures/dimensions.py +200 -0
- v0/relationalai/early_access/dsl/orm/measures/initializer.py +16 -0
- v0/relationalai/early_access/dsl/orm/measures/measure_rules.py +275 -0
- v0/relationalai/early_access/dsl/orm/measures/measures.py +299 -0
- v0/relationalai/early_access/dsl/orm/measures/role_exprs.py +268 -0
- v0/relationalai/early_access/dsl/orm/models.py +256 -0
- v0/relationalai/early_access/dsl/orm/object_oriented_printer.py +344 -0
- v0/relationalai/early_access/dsl/orm/printer.py +469 -0
- v0/relationalai/early_access/dsl/orm/reasoners.py +480 -0
- v0/relationalai/early_access/dsl/orm/relations.py +19 -0
- v0/relationalai/early_access/dsl/orm/relationships.py +251 -0
- v0/relationalai/early_access/dsl/orm/types.py +42 -0
- v0/relationalai/early_access/dsl/orm/utils.py +79 -0
- v0/relationalai/early_access/dsl/orm/verb.py +204 -0
- v0/relationalai/early_access/dsl/physical_metadata/tables.py +133 -0
- v0/relationalai/early_access/dsl/relations.py +170 -0
- v0/relationalai/early_access/dsl/rulesets.py +69 -0
- v0/relationalai/early_access/dsl/schemas/__init__.py +450 -0
- v0/relationalai/early_access/dsl/schemas/builder.py +48 -0
- v0/relationalai/early_access/dsl/schemas/comp_names.py +51 -0
- v0/relationalai/early_access/dsl/schemas/components.py +203 -0
- v0/relationalai/early_access/dsl/schemas/contexts.py +156 -0
- v0/relationalai/early_access/dsl/schemas/exprs.py +89 -0
- v0/relationalai/early_access/dsl/schemas/fragments.py +464 -0
- v0/relationalai/early_access/dsl/serialization.py +79 -0
- v0/relationalai/early_access/dsl/serialize/exporter.py +163 -0
- v0/relationalai/early_access/dsl/snow/api.py +104 -0
- v0/relationalai/early_access/dsl/snow/common.py +76 -0
- v0/relationalai/early_access/dsl/state_mgmt/__init__.py +129 -0
- v0/relationalai/early_access/dsl/state_mgmt/state_charts.py +125 -0
- v0/relationalai/early_access/dsl/state_mgmt/transitions.py +130 -0
- v0/relationalai/early_access/dsl/types/__init__.py +40 -0
- v0/relationalai/early_access/dsl/types/concepts.py +12 -0
- v0/relationalai/early_access/dsl/types/entities.py +135 -0
- v0/relationalai/early_access/dsl/types/values.py +17 -0
- v0/relationalai/early_access/dsl/utils.py +102 -0
- v0/relationalai/early_access/graphs/__init__.py +13 -0
- v0/relationalai/early_access/lqp/__init__.py +12 -0
- v0/relationalai/early_access/lqp/compiler/__init__.py +12 -0
- v0/relationalai/early_access/lqp/constructors/__init__.py +18 -0
- v0/relationalai/early_access/lqp/executor/__init__.py +12 -0
- v0/relationalai/early_access/lqp/ir/__init__.py +12 -0
- v0/relationalai/early_access/lqp/passes/__init__.py +12 -0
- v0/relationalai/early_access/lqp/pragmas/__init__.py +12 -0
- v0/relationalai/early_access/lqp/primitives/__init__.py +12 -0
- v0/relationalai/early_access/lqp/types/__init__.py +12 -0
- v0/relationalai/early_access/lqp/utils/__init__.py +12 -0
- v0/relationalai/early_access/lqp/validators/__init__.py +12 -0
- v0/relationalai/early_access/metamodel/__init__.py +58 -0
- v0/relationalai/early_access/metamodel/builtins/__init__.py +12 -0
- v0/relationalai/early_access/metamodel/compiler/__init__.py +12 -0
- v0/relationalai/early_access/metamodel/dependency/__init__.py +12 -0
- v0/relationalai/early_access/metamodel/factory/__init__.py +17 -0
- v0/relationalai/early_access/metamodel/helpers/__init__.py +12 -0
- v0/relationalai/early_access/metamodel/ir/__init__.py +14 -0
- v0/relationalai/early_access/metamodel/rewrite/__init__.py +7 -0
- v0/relationalai/early_access/metamodel/typer/__init__.py +3 -0
- v0/relationalai/early_access/metamodel/typer/typer/__init__.py +12 -0
- v0/relationalai/early_access/metamodel/types/__init__.py +15 -0
- v0/relationalai/early_access/metamodel/util/__init__.py +15 -0
- v0/relationalai/early_access/metamodel/visitor/__init__.py +12 -0
- v0/relationalai/early_access/rel/__init__.py +12 -0
- v0/relationalai/early_access/rel/executor/__init__.py +12 -0
- v0/relationalai/early_access/rel/rel_utils/__init__.py +12 -0
- v0/relationalai/early_access/rel/rewrite/__init__.py +7 -0
- v0/relationalai/early_access/solvers/__init__.py +19 -0
- v0/relationalai/early_access/sql/__init__.py +11 -0
- v0/relationalai/early_access/sql/executor/__init__.py +3 -0
- v0/relationalai/early_access/sql/rewrite/__init__.py +3 -0
- v0/relationalai/early_access/tests/logging/__init__.py +12 -0
- v0/relationalai/early_access/tests/test_snapshot_base/__init__.py +12 -0
- v0/relationalai/early_access/tests/utils/__init__.py +12 -0
- v0/relationalai/environments/__init__.py +35 -0
- v0/relationalai/environments/base.py +381 -0
- v0/relationalai/environments/colab.py +14 -0
- v0/relationalai/environments/generic.py +71 -0
- v0/relationalai/environments/ipython.py +68 -0
- v0/relationalai/environments/jupyter.py +9 -0
- v0/relationalai/environments/snowbook.py +169 -0
- v0/relationalai/errors.py +2478 -0
- v0/relationalai/experimental/SF.py +38 -0
- v0/relationalai/experimental/inspect.py +47 -0
- v0/relationalai/experimental/pathfinder/__init__.py +158 -0
- v0/relationalai/experimental/pathfinder/api.py +160 -0
- v0/relationalai/experimental/pathfinder/automaton.py +584 -0
- v0/relationalai/experimental/pathfinder/bridge.py +226 -0
- v0/relationalai/experimental/pathfinder/compiler.py +416 -0
- v0/relationalai/experimental/pathfinder/datalog.py +214 -0
- v0/relationalai/experimental/pathfinder/diagnostics.py +56 -0
- v0/relationalai/experimental/pathfinder/filter.py +236 -0
- v0/relationalai/experimental/pathfinder/glushkov.py +439 -0
- v0/relationalai/experimental/pathfinder/options.py +265 -0
- v0/relationalai/experimental/pathfinder/rpq.py +344 -0
- v0/relationalai/experimental/pathfinder/transition.py +200 -0
- v0/relationalai/experimental/pathfinder/utils.py +26 -0
- v0/relationalai/experimental/paths/api.py +143 -0
- v0/relationalai/experimental/paths/benchmarks/grid_graph.py +37 -0
- v0/relationalai/experimental/paths/examples/basic_example.py +40 -0
- v0/relationalai/experimental/paths/examples/minimal_engine_warmup.py +3 -0
- v0/relationalai/experimental/paths/examples/movie_example.py +77 -0
- v0/relationalai/experimental/paths/examples/paths_benchmark.py +115 -0
- v0/relationalai/experimental/paths/examples/paths_example.py +116 -0
- v0/relationalai/experimental/paths/examples/pattern_to_automaton.py +28 -0
- v0/relationalai/experimental/paths/find_paths_via_automaton.py +85 -0
- v0/relationalai/experimental/paths/graph.py +185 -0
- v0/relationalai/experimental/paths/path_algorithms/find_paths.py +280 -0
- v0/relationalai/experimental/paths/path_algorithms/one_sided_ball_repetition.py +26 -0
- v0/relationalai/experimental/paths/path_algorithms/one_sided_ball_upto.py +111 -0
- v0/relationalai/experimental/paths/path_algorithms/single.py +59 -0
- v0/relationalai/experimental/paths/path_algorithms/two_sided_balls_repetition.py +39 -0
- v0/relationalai/experimental/paths/path_algorithms/two_sided_balls_upto.py +103 -0
- v0/relationalai/experimental/paths/path_algorithms/usp-old.py +130 -0
- v0/relationalai/experimental/paths/path_algorithms/usp-tuple.py +183 -0
- v0/relationalai/experimental/paths/path_algorithms/usp.py +150 -0
- v0/relationalai/experimental/paths/product_graph.py +93 -0
- v0/relationalai/experimental/paths/rpq/automaton.py +584 -0
- v0/relationalai/experimental/paths/rpq/diagnostics.py +56 -0
- v0/relationalai/experimental/paths/rpq/rpq.py +378 -0
- v0/relationalai/experimental/paths/tests/tests_limit_sp_max_length.py +90 -0
- v0/relationalai/experimental/paths/tests/tests_limit_sp_multiple.py +119 -0
- v0/relationalai/experimental/paths/tests/tests_limit_sp_single.py +104 -0
- v0/relationalai/experimental/paths/tests/tests_limit_walks_multiple.py +113 -0
- v0/relationalai/experimental/paths/tests/tests_limit_walks_single.py +149 -0
- v0/relationalai/experimental/paths/tests/tests_one_sided_ball_repetition_multiple.py +70 -0
- v0/relationalai/experimental/paths/tests/tests_one_sided_ball_repetition_single.py +64 -0
- v0/relationalai/experimental/paths/tests/tests_one_sided_ball_upto_multiple.py +115 -0
- v0/relationalai/experimental/paths/tests/tests_one_sided_ball_upto_single.py +75 -0
- v0/relationalai/experimental/paths/tests/tests_single_paths.py +152 -0
- v0/relationalai/experimental/paths/tests/tests_single_walks.py +208 -0
- v0/relationalai/experimental/paths/tests/tests_single_walks_undirected.py +297 -0
- v0/relationalai/experimental/paths/tests/tests_two_sided_balls_repetition_multiple.py +107 -0
- v0/relationalai/experimental/paths/tests/tests_two_sided_balls_repetition_single.py +76 -0
- v0/relationalai/experimental/paths/tests/tests_two_sided_balls_upto_multiple.py +76 -0
- v0/relationalai/experimental/paths/tests/tests_two_sided_balls_upto_single.py +110 -0
- v0/relationalai/experimental/paths/tests/tests_usp_nsp_multiple.py +229 -0
- v0/relationalai/experimental/paths/tests/tests_usp_nsp_single.py +108 -0
- v0/relationalai/experimental/paths/tree_agg.py +168 -0
- v0/relationalai/experimental/paths/utilities/iterators.py +27 -0
- v0/relationalai/experimental/paths/utilities/prefix_sum.py +91 -0
- v0/relationalai/experimental/solvers.py +1087 -0
- v0/relationalai/loaders/csv.py +195 -0
- v0/relationalai/loaders/loader.py +177 -0
- v0/relationalai/loaders/types.py +23 -0
- v0/relationalai/rel_emitter.py +373 -0
- v0/relationalai/rel_utils.py +185 -0
- v0/relationalai/semantics/__init__.py +29 -0
- v0/relationalai/semantics/devtools/benchmark_lqp.py +536 -0
- v0/relationalai/semantics/devtools/compilation_manager.py +294 -0
- v0/relationalai/semantics/devtools/extract_lqp.py +110 -0
- v0/relationalai/semantics/internal/internal.py +3785 -0
- v0/relationalai/semantics/internal/snowflake.py +325 -0
- v0/relationalai/semantics/lqp/builtins.py +16 -0
- v0/relationalai/semantics/lqp/compiler.py +22 -0
- v0/relationalai/semantics/lqp/constructors.py +68 -0
- v0/relationalai/semantics/lqp/executor.py +474 -0
- v0/relationalai/semantics/lqp/intrinsics.py +24 -0
- v0/relationalai/semantics/lqp/ir.py +124 -0
- v0/relationalai/semantics/lqp/model2lqp.py +877 -0
- v0/relationalai/semantics/lqp/passes.py +680 -0
- v0/relationalai/semantics/lqp/primitives.py +252 -0
- v0/relationalai/semantics/lqp/result_helpers.py +202 -0
- v0/relationalai/semantics/lqp/rewrite/__init__.py +18 -0
- v0/relationalai/semantics/lqp/rewrite/annotate_constraints.py +57 -0
- v0/relationalai/semantics/lqp/rewrite/cdc.py +216 -0
- v0/relationalai/semantics/lqp/rewrite/extract_common.py +338 -0
- v0/relationalai/semantics/lqp/rewrite/extract_keys.py +490 -0
- v0/relationalai/semantics/lqp/rewrite/function_annotations.py +114 -0
- v0/relationalai/semantics/lqp/rewrite/functional_dependencies.py +314 -0
- v0/relationalai/semantics/lqp/rewrite/quantify_vars.py +296 -0
- v0/relationalai/semantics/lqp/rewrite/splinter.py +76 -0
- v0/relationalai/semantics/lqp/types.py +101 -0
- v0/relationalai/semantics/lqp/utils.py +160 -0
- v0/relationalai/semantics/lqp/validators.py +57 -0
- v0/relationalai/semantics/metamodel/__init__.py +40 -0
- v0/relationalai/semantics/metamodel/builtins.py +776 -0
- v0/relationalai/semantics/metamodel/compiler.py +133 -0
- v0/relationalai/semantics/metamodel/dependency.py +862 -0
- v0/relationalai/semantics/metamodel/executor.py +61 -0
- v0/relationalai/semantics/metamodel/factory.py +287 -0
- v0/relationalai/semantics/metamodel/helpers.py +361 -0
- v0/relationalai/semantics/metamodel/ir.py +923 -0
- v0/relationalai/semantics/metamodel/rewrite/__init__.py +7 -0
- v0/relationalai/semantics/metamodel/rewrite/discharge_constraints.py +39 -0
- v0/relationalai/semantics/metamodel/rewrite/dnf_union_splitter.py +210 -0
- v0/relationalai/semantics/metamodel/rewrite/extract_nested_logicals.py +78 -0
- v0/relationalai/semantics/metamodel/rewrite/flatten.py +554 -0
- v0/relationalai/semantics/metamodel/rewrite/format_outputs.py +165 -0
- v0/relationalai/semantics/metamodel/typer/checker.py +353 -0
- v0/relationalai/semantics/metamodel/typer/typer.py +1395 -0
- v0/relationalai/semantics/metamodel/util.py +505 -0
- v0/relationalai/semantics/metamodel/visitor.py +944 -0
- v0/relationalai/semantics/reasoners/__init__.py +10 -0
- v0/relationalai/semantics/reasoners/graph/__init__.py +37 -0
- v0/relationalai/semantics/reasoners/graph/core.py +9019 -0
- v0/relationalai/semantics/reasoners/optimization/__init__.py +68 -0
- v0/relationalai/semantics/reasoners/optimization/common.py +88 -0
- v0/relationalai/semantics/reasoners/optimization/solvers_dev.py +568 -0
- v0/relationalai/semantics/reasoners/optimization/solvers_pb.py +1163 -0
- v0/relationalai/semantics/rel/builtins.py +40 -0
- v0/relationalai/semantics/rel/compiler.py +989 -0
- v0/relationalai/semantics/rel/executor.py +359 -0
- v0/relationalai/semantics/rel/rel.py +482 -0
- v0/relationalai/semantics/rel/rel_utils.py +276 -0
- v0/relationalai/semantics/snowflake/__init__.py +3 -0
- v0/relationalai/semantics/sql/compiler.py +2503 -0
- v0/relationalai/semantics/sql/executor/duck_db.py +52 -0
- v0/relationalai/semantics/sql/executor/result_helpers.py +64 -0
- v0/relationalai/semantics/sql/executor/snowflake.py +145 -0
- v0/relationalai/semantics/sql/rewrite/denormalize.py +222 -0
- v0/relationalai/semantics/sql/rewrite/double_negation.py +49 -0
- v0/relationalai/semantics/sql/rewrite/recursive_union.py +127 -0
- v0/relationalai/semantics/sql/rewrite/sort_output_query.py +246 -0
- v0/relationalai/semantics/sql/sql.py +504 -0
- v0/relationalai/semantics/std/__init__.py +54 -0
- v0/relationalai/semantics/std/constraints.py +43 -0
- v0/relationalai/semantics/std/datetime.py +363 -0
- v0/relationalai/semantics/std/decimals.py +62 -0
- v0/relationalai/semantics/std/floats.py +7 -0
- v0/relationalai/semantics/std/integers.py +22 -0
- v0/relationalai/semantics/std/math.py +141 -0
- v0/relationalai/semantics/std/pragmas.py +11 -0
- v0/relationalai/semantics/std/re.py +83 -0
- v0/relationalai/semantics/std/std.py +14 -0
- v0/relationalai/semantics/std/strings.py +63 -0
- v0/relationalai/semantics/tests/__init__.py +0 -0
- v0/relationalai/semantics/tests/test_snapshot_abstract.py +143 -0
- v0/relationalai/semantics/tests/test_snapshot_base.py +9 -0
- v0/relationalai/semantics/tests/utils.py +46 -0
- v0/relationalai/std/__init__.py +70 -0
- v0/relationalai/tools/__init__.py +0 -0
- v0/relationalai/tools/cli.py +1940 -0
- v0/relationalai/tools/cli_controls.py +1826 -0
- v0/relationalai/tools/cli_helpers.py +390 -0
- v0/relationalai/tools/debugger.py +183 -0
- v0/relationalai/tools/debugger_client.py +109 -0
- v0/relationalai/tools/debugger_server.py +302 -0
- v0/relationalai/tools/dev.py +685 -0
- v0/relationalai/tools/qb_debugger.py +425 -0
- v0/relationalai/util/clean_up_databases.py +95 -0
- v0/relationalai/util/format.py +123 -0
- v0/relationalai/util/list_databases.py +9 -0
- v0/relationalai/util/otel_configuration.py +25 -0
- v0/relationalai/util/otel_handler.py +484 -0
- v0/relationalai/util/snowflake_handler.py +88 -0
- v0/relationalai/util/span_format_test.py +43 -0
- v0/relationalai/util/span_tracker.py +207 -0
- v0/relationalai/util/spans_file_handler.py +72 -0
- v0/relationalai/util/tracing_handler.py +34 -0
- frontend/debugger/dist/.gitignore +0 -2
- frontend/debugger/dist/assets/favicon-Dy0ZgA6N.png +0 -0
- frontend/debugger/dist/assets/index-Cssla-O7.js +0 -208
- frontend/debugger/dist/assets/index-DlHsYx1V.css +0 -9
- frontend/debugger/dist/index.html +0 -17
- relationalai/clients/__init__.py +0 -18
- relationalai/clients/client.py +0 -946
- relationalai/clients/config.py +0 -673
- relationalai/clients/direct_access_client.py +0 -118
- relationalai/clients/exec_txn_poller.py +0 -153
- relationalai/clients/hash_util.py +0 -31
- relationalai/clients/local.py +0 -594
- relationalai/clients/profile_polling.py +0 -73
- relationalai/clients/resources/__init__.py +0 -8
- relationalai/clients/resources/azure/azure.py +0 -502
- relationalai/clients/resources/snowflake/__init__.py +0 -20
- relationalai/clients/resources/snowflake/cli_resources.py +0 -98
- relationalai/clients/resources/snowflake/direct_access_resources.py +0 -739
- relationalai/clients/resources/snowflake/engine_service.py +0 -381
- relationalai/clients/resources/snowflake/engine_state_handlers.py +0 -315
- relationalai/clients/resources/snowflake/error_handlers.py +0 -240
- relationalai/clients/resources/snowflake/export_procedure.py.jinja +0 -249
- relationalai/clients/resources/snowflake/resources_factory.py +0 -99
- relationalai/clients/resources/snowflake/snowflake.py +0 -3193
- relationalai/clients/resources/snowflake/use_index_poller.py +0 -1019
- relationalai/clients/resources/snowflake/use_index_resources.py +0 -188
- relationalai/clients/resources/snowflake/util.py +0 -387
- relationalai/clients/result_helpers.py +0 -420
- relationalai/clients/types.py +0 -118
- relationalai/clients/util.py +0 -356
- relationalai/debugging.py +0 -389
- relationalai/dsl.py +0 -1749
- relationalai/early_access/builder/__init__.py +0 -30
- relationalai/early_access/builder/builder/__init__.py +0 -35
- relationalai/early_access/builder/snowflake/__init__.py +0 -12
- relationalai/early_access/builder/std/__init__.py +0 -25
- relationalai/early_access/builder/std/decimals/__init__.py +0 -12
- relationalai/early_access/builder/std/integers/__init__.py +0 -12
- relationalai/early_access/builder/std/math/__init__.py +0 -12
- relationalai/early_access/builder/std/strings/__init__.py +0 -14
- relationalai/early_access/devtools/__init__.py +0 -12
- relationalai/early_access/devtools/benchmark_lqp/__init__.py +0 -12
- relationalai/early_access/devtools/extract_lqp/__init__.py +0 -12
- relationalai/early_access/dsl/adapters/orm/adapter_qb.py +0 -427
- relationalai/early_access/dsl/adapters/orm/parser.py +0 -636
- relationalai/early_access/dsl/adapters/owl/adapter.py +0 -176
- relationalai/early_access/dsl/adapters/owl/parser.py +0 -160
- relationalai/early_access/dsl/bindings/common.py +0 -402
- relationalai/early_access/dsl/bindings/csv.py +0 -170
- relationalai/early_access/dsl/bindings/legacy/binding_models.py +0 -143
- relationalai/early_access/dsl/bindings/snowflake.py +0 -64
- relationalai/early_access/dsl/codegen/binder.py +0 -411
- relationalai/early_access/dsl/codegen/common.py +0 -79
- relationalai/early_access/dsl/codegen/helpers.py +0 -23
- relationalai/early_access/dsl/codegen/relations.py +0 -700
- relationalai/early_access/dsl/codegen/weaver.py +0 -417
- relationalai/early_access/dsl/core/builders/__init__.py +0 -47
- relationalai/early_access/dsl/core/builders/logic.py +0 -19
- relationalai/early_access/dsl/core/builders/scalar_constraint.py +0 -11
- relationalai/early_access/dsl/core/constraints/predicate/atomic.py +0 -455
- relationalai/early_access/dsl/core/constraints/predicate/universal.py +0 -73
- relationalai/early_access/dsl/core/constraints/scalar.py +0 -310
- relationalai/early_access/dsl/core/context.py +0 -13
- relationalai/early_access/dsl/core/cset.py +0 -132
- relationalai/early_access/dsl/core/exprs/__init__.py +0 -116
- relationalai/early_access/dsl/core/exprs/relational.py +0 -18
- relationalai/early_access/dsl/core/exprs/scalar.py +0 -412
- relationalai/early_access/dsl/core/instances.py +0 -44
- relationalai/early_access/dsl/core/logic/__init__.py +0 -193
- relationalai/early_access/dsl/core/logic/aggregation.py +0 -98
- relationalai/early_access/dsl/core/logic/exists.py +0 -223
- relationalai/early_access/dsl/core/logic/helper.py +0 -163
- relationalai/early_access/dsl/core/namespaces.py +0 -32
- relationalai/early_access/dsl/core/relations.py +0 -276
- relationalai/early_access/dsl/core/rules.py +0 -112
- relationalai/early_access/dsl/core/std/__init__.py +0 -45
- relationalai/early_access/dsl/core/temporal/recall.py +0 -6
- relationalai/early_access/dsl/core/types/__init__.py +0 -270
- relationalai/early_access/dsl/core/types/concepts.py +0 -128
- relationalai/early_access/dsl/core/types/constrained/__init__.py +0 -267
- relationalai/early_access/dsl/core/types/constrained/nominal.py +0 -143
- relationalai/early_access/dsl/core/types/constrained/subtype.py +0 -124
- relationalai/early_access/dsl/core/types/standard.py +0 -92
- relationalai/early_access/dsl/core/types/unconstrained.py +0 -50
- relationalai/early_access/dsl/core/types/variables.py +0 -203
- relationalai/early_access/dsl/ir/compiler.py +0 -318
- relationalai/early_access/dsl/ir/executor.py +0 -260
- relationalai/early_access/dsl/ontologies/constraints.py +0 -88
- relationalai/early_access/dsl/ontologies/export.py +0 -30
- relationalai/early_access/dsl/ontologies/models.py +0 -453
- relationalai/early_access/dsl/ontologies/python_printer.py +0 -303
- relationalai/early_access/dsl/ontologies/readings.py +0 -60
- relationalai/early_access/dsl/ontologies/relationships.py +0 -322
- relationalai/early_access/dsl/ontologies/roles.py +0 -87
- relationalai/early_access/dsl/ontologies/subtyping.py +0 -55
- relationalai/early_access/dsl/orm/constraints.py +0 -438
- relationalai/early_access/dsl/orm/measures/dimensions.py +0 -200
- relationalai/early_access/dsl/orm/measures/initializer.py +0 -16
- relationalai/early_access/dsl/orm/measures/measure_rules.py +0 -275
- relationalai/early_access/dsl/orm/measures/measures.py +0 -299
- relationalai/early_access/dsl/orm/measures/role_exprs.py +0 -268
- relationalai/early_access/dsl/orm/models.py +0 -256
- relationalai/early_access/dsl/orm/object_oriented_printer.py +0 -344
- relationalai/early_access/dsl/orm/printer.py +0 -469
- relationalai/early_access/dsl/orm/reasoners.py +0 -480
- relationalai/early_access/dsl/orm/relations.py +0 -19
- relationalai/early_access/dsl/orm/relationships.py +0 -251
- relationalai/early_access/dsl/orm/types.py +0 -42
- relationalai/early_access/dsl/orm/utils.py +0 -79
- relationalai/early_access/dsl/orm/verb.py +0 -204
- relationalai/early_access/dsl/physical_metadata/tables.py +0 -133
- relationalai/early_access/dsl/relations.py +0 -170
- relationalai/early_access/dsl/rulesets.py +0 -69
- relationalai/early_access/dsl/schemas/__init__.py +0 -450
- relationalai/early_access/dsl/schemas/builder.py +0 -48
- relationalai/early_access/dsl/schemas/comp_names.py +0 -51
- relationalai/early_access/dsl/schemas/components.py +0 -203
- relationalai/early_access/dsl/schemas/contexts.py +0 -156
- relationalai/early_access/dsl/schemas/exprs.py +0 -89
- relationalai/early_access/dsl/schemas/fragments.py +0 -464
- relationalai/early_access/dsl/serialization.py +0 -79
- relationalai/early_access/dsl/serialize/exporter.py +0 -163
- relationalai/early_access/dsl/snow/api.py +0 -105
- relationalai/early_access/dsl/snow/common.py +0 -76
- relationalai/early_access/dsl/state_mgmt/__init__.py +0 -129
- relationalai/early_access/dsl/state_mgmt/state_charts.py +0 -125
- relationalai/early_access/dsl/state_mgmt/transitions.py +0 -130
- relationalai/early_access/dsl/types/__init__.py +0 -40
- relationalai/early_access/dsl/types/concepts.py +0 -12
- relationalai/early_access/dsl/types/entities.py +0 -135
- relationalai/early_access/dsl/types/values.py +0 -17
- relationalai/early_access/dsl/utils.py +0 -102
- relationalai/early_access/graphs/__init__.py +0 -13
- relationalai/early_access/lqp/__init__.py +0 -12
- relationalai/early_access/lqp/compiler/__init__.py +0 -12
- relationalai/early_access/lqp/constructors/__init__.py +0 -18
- relationalai/early_access/lqp/executor/__init__.py +0 -12
- relationalai/early_access/lqp/ir/__init__.py +0 -12
- relationalai/early_access/lqp/passes/__init__.py +0 -12
- relationalai/early_access/lqp/pragmas/__init__.py +0 -12
- relationalai/early_access/lqp/primitives/__init__.py +0 -12
- relationalai/early_access/lqp/types/__init__.py +0 -12
- relationalai/early_access/lqp/utils/__init__.py +0 -12
- relationalai/early_access/lqp/validators/__init__.py +0 -12
- relationalai/early_access/metamodel/__init__.py +0 -58
- relationalai/early_access/metamodel/builtins/__init__.py +0 -12
- relationalai/early_access/metamodel/compiler/__init__.py +0 -12
- relationalai/early_access/metamodel/dependency/__init__.py +0 -12
- relationalai/early_access/metamodel/factory/__init__.py +0 -17
- relationalai/early_access/metamodel/helpers/__init__.py +0 -12
- relationalai/early_access/metamodel/ir/__init__.py +0 -14
- relationalai/early_access/metamodel/rewrite/__init__.py +0 -7
- relationalai/early_access/metamodel/typer/__init__.py +0 -3
- relationalai/early_access/metamodel/typer/typer/__init__.py +0 -12
- relationalai/early_access/metamodel/types/__init__.py +0 -15
- relationalai/early_access/metamodel/util/__init__.py +0 -15
- relationalai/early_access/metamodel/visitor/__init__.py +0 -12
- relationalai/early_access/rel/__init__.py +0 -12
- relationalai/early_access/rel/executor/__init__.py +0 -12
- relationalai/early_access/rel/rel_utils/__init__.py +0 -12
- relationalai/early_access/rel/rewrite/__init__.py +0 -7
- relationalai/early_access/solvers/__init__.py +0 -19
- relationalai/early_access/sql/__init__.py +0 -11
- relationalai/early_access/sql/executor/__init__.py +0 -3
- relationalai/early_access/sql/rewrite/__init__.py +0 -3
- relationalai/early_access/tests/logging/__init__.py +0 -12
- relationalai/early_access/tests/test_snapshot_base/__init__.py +0 -12
- relationalai/early_access/tests/utils/__init__.py +0 -12
- relationalai/environments/__init__.py +0 -35
- relationalai/environments/base.py +0 -381
- relationalai/environments/colab.py +0 -14
- relationalai/environments/generic.py +0 -71
- relationalai/environments/ipython.py +0 -68
- relationalai/environments/jupyter.py +0 -9
- relationalai/environments/snowbook.py +0 -169
- relationalai/errors.py +0 -2496
- relationalai/experimental/SF.py +0 -38
- relationalai/experimental/inspect.py +0 -47
- relationalai/experimental/pathfinder/__init__.py +0 -158
- relationalai/experimental/pathfinder/api.py +0 -160
- relationalai/experimental/pathfinder/automaton.py +0 -584
- relationalai/experimental/pathfinder/bridge.py +0 -226
- relationalai/experimental/pathfinder/compiler.py +0 -416
- relationalai/experimental/pathfinder/datalog.py +0 -214
- relationalai/experimental/pathfinder/diagnostics.py +0 -56
- relationalai/experimental/pathfinder/filter.py +0 -236
- relationalai/experimental/pathfinder/glushkov.py +0 -439
- relationalai/experimental/pathfinder/options.py +0 -265
- relationalai/experimental/pathfinder/pathfinder-v0.7.0.rel +0 -1951
- relationalai/experimental/pathfinder/rpq.py +0 -344
- relationalai/experimental/pathfinder/transition.py +0 -200
- relationalai/experimental/pathfinder/utils.py +0 -26
- relationalai/experimental/paths/README.md +0 -107
- relationalai/experimental/paths/api.py +0 -143
- relationalai/experimental/paths/benchmarks/grid_graph.py +0 -37
- relationalai/experimental/paths/code_organization.md +0 -2
- relationalai/experimental/paths/examples/Movies.ipynb +0 -16328
- relationalai/experimental/paths/examples/basic_example.py +0 -40
- relationalai/experimental/paths/examples/minimal_engine_warmup.py +0 -3
- relationalai/experimental/paths/examples/movie_example.py +0 -77
- relationalai/experimental/paths/examples/movies_data/actedin.csv +0 -193
- relationalai/experimental/paths/examples/movies_data/directed.csv +0 -45
- relationalai/experimental/paths/examples/movies_data/follows.csv +0 -7
- relationalai/experimental/paths/examples/movies_data/movies.csv +0 -39
- relationalai/experimental/paths/examples/movies_data/person.csv +0 -134
- relationalai/experimental/paths/examples/movies_data/produced.csv +0 -16
- relationalai/experimental/paths/examples/movies_data/ratings.csv +0 -10
- relationalai/experimental/paths/examples/movies_data/wrote.csv +0 -11
- relationalai/experimental/paths/examples/paths_benchmark.py +0 -115
- relationalai/experimental/paths/examples/paths_example.py +0 -116
- relationalai/experimental/paths/examples/pattern_to_automaton.py +0 -28
- relationalai/experimental/paths/find_paths_via_automaton.py +0 -85
- relationalai/experimental/paths/graph.py +0 -185
- relationalai/experimental/paths/path_algorithms/find_paths.py +0 -280
- relationalai/experimental/paths/path_algorithms/one_sided_ball_repetition.py +0 -26
- relationalai/experimental/paths/path_algorithms/one_sided_ball_upto.py +0 -111
- relationalai/experimental/paths/path_algorithms/single.py +0 -59
- relationalai/experimental/paths/path_algorithms/two_sided_balls_repetition.py +0 -39
- relationalai/experimental/paths/path_algorithms/two_sided_balls_upto.py +0 -103
- relationalai/experimental/paths/path_algorithms/usp-old.py +0 -130
- relationalai/experimental/paths/path_algorithms/usp-tuple.py +0 -183
- relationalai/experimental/paths/path_algorithms/usp.py +0 -150
- relationalai/experimental/paths/product_graph.py +0 -93
- relationalai/experimental/paths/rpq/automaton.py +0 -584
- relationalai/experimental/paths/rpq/diagnostics.py +0 -56
- relationalai/experimental/paths/rpq/rpq.py +0 -378
- relationalai/experimental/paths/tests/tests_limit_sp_max_length.py +0 -90
- relationalai/experimental/paths/tests/tests_limit_sp_multiple.py +0 -119
- relationalai/experimental/paths/tests/tests_limit_sp_single.py +0 -104
- relationalai/experimental/paths/tests/tests_limit_walks_multiple.py +0 -113
- relationalai/experimental/paths/tests/tests_limit_walks_single.py +0 -149
- relationalai/experimental/paths/tests/tests_one_sided_ball_repetition_multiple.py +0 -70
- relationalai/experimental/paths/tests/tests_one_sided_ball_repetition_single.py +0 -64
- relationalai/experimental/paths/tests/tests_one_sided_ball_upto_multiple.py +0 -115
- relationalai/experimental/paths/tests/tests_one_sided_ball_upto_single.py +0 -75
- relationalai/experimental/paths/tests/tests_single_paths.py +0 -152
- relationalai/experimental/paths/tests/tests_single_walks.py +0 -208
- relationalai/experimental/paths/tests/tests_single_walks_undirected.py +0 -297
- relationalai/experimental/paths/tests/tests_two_sided_balls_repetition_multiple.py +0 -107
- relationalai/experimental/paths/tests/tests_two_sided_balls_repetition_single.py +0 -76
- relationalai/experimental/paths/tests/tests_two_sided_balls_upto_multiple.py +0 -76
- relationalai/experimental/paths/tests/tests_two_sided_balls_upto_single.py +0 -110
- relationalai/experimental/paths/tests/tests_usp_nsp_multiple.py +0 -229
- relationalai/experimental/paths/tests/tests_usp_nsp_single.py +0 -108
- relationalai/experimental/paths/tree_agg.py +0 -168
- relationalai/experimental/paths/utilities/iterators.py +0 -27
- relationalai/experimental/paths/utilities/prefix_sum.py +0 -91
- relationalai/experimental/solvers.py +0 -1095
- relationalai/loaders/csv.py +0 -195
- relationalai/loaders/loader.py +0 -177
- relationalai/loaders/types.py +0 -23
- relationalai/rel_emitter.py +0 -373
- relationalai/rel_utils.py +0 -185
- relationalai/semantics/designs/query_builder/identify_by.md +0 -106
- relationalai/semantics/devtools/benchmark_lqp.py +0 -535
- relationalai/semantics/devtools/compilation_manager.py +0 -294
- relationalai/semantics/devtools/extract_lqp.py +0 -110
- relationalai/semantics/internal/internal.py +0 -3785
- relationalai/semantics/internal/snowflake.py +0 -329
- relationalai/semantics/lqp/README.md +0 -34
- relationalai/semantics/lqp/algorithms.py +0 -173
- relationalai/semantics/lqp/builtins.py +0 -213
- relationalai/semantics/lqp/compiler.py +0 -22
- relationalai/semantics/lqp/constructors.py +0 -68
- relationalai/semantics/lqp/executor.py +0 -518
- relationalai/semantics/lqp/export_rewriter.py +0 -40
- relationalai/semantics/lqp/intrinsics.py +0 -24
- relationalai/semantics/lqp/ir.py +0 -150
- relationalai/semantics/lqp/model2lqp.py +0 -1056
- relationalai/semantics/lqp/passes.py +0 -38
- relationalai/semantics/lqp/primitives.py +0 -252
- relationalai/semantics/lqp/result_helpers.py +0 -266
- relationalai/semantics/lqp/rewrite/__init__.py +0 -32
- relationalai/semantics/lqp/rewrite/algorithm.py +0 -385
- relationalai/semantics/lqp/rewrite/annotate_constraints.py +0 -69
- relationalai/semantics/lqp/rewrite/cdc.py +0 -216
- relationalai/semantics/lqp/rewrite/constants_to_vars.py +0 -70
- relationalai/semantics/lqp/rewrite/deduplicate_vars.py +0 -104
- relationalai/semantics/lqp/rewrite/eliminate_data.py +0 -108
- relationalai/semantics/lqp/rewrite/extract_common.py +0 -340
- relationalai/semantics/lqp/rewrite/extract_keys.py +0 -577
- relationalai/semantics/lqp/rewrite/flatten_script.py +0 -301
- relationalai/semantics/lqp/rewrite/function_annotations.py +0 -114
- relationalai/semantics/lqp/rewrite/functional_dependencies.py +0 -348
- relationalai/semantics/lqp/rewrite/period_math.py +0 -77
- relationalai/semantics/lqp/rewrite/quantify_vars.py +0 -339
- relationalai/semantics/lqp/rewrite/splinter.py +0 -76
- relationalai/semantics/lqp/rewrite/unify_definitions.py +0 -323
- relationalai/semantics/lqp/types.py +0 -101
- relationalai/semantics/lqp/utils.py +0 -170
- relationalai/semantics/lqp/validators.py +0 -70
- relationalai/semantics/metamodel/compiler.py +0 -134
- relationalai/semantics/metamodel/dependency.py +0 -880
- relationalai/semantics/metamodel/executor.py +0 -78
- relationalai/semantics/metamodel/factory.py +0 -287
- relationalai/semantics/metamodel/helpers.py +0 -368
- relationalai/semantics/metamodel/ir.py +0 -924
- relationalai/semantics/metamodel/rewrite/__init__.py +0 -8
- relationalai/semantics/metamodel/rewrite/discharge_constraints.py +0 -39
- relationalai/semantics/metamodel/rewrite/dnf_union_splitter.py +0 -220
- relationalai/semantics/metamodel/rewrite/extract_nested_logicals.py +0 -78
- relationalai/semantics/metamodel/rewrite/flatten.py +0 -590
- relationalai/semantics/metamodel/rewrite/format_outputs.py +0 -256
- relationalai/semantics/metamodel/rewrite/handle_aggregations_and_ranks.py +0 -237
- relationalai/semantics/metamodel/typer/checker.py +0 -355
- relationalai/semantics/metamodel/typer/typer.py +0 -1396
- relationalai/semantics/metamodel/util.py +0 -506
- relationalai/semantics/metamodel/visitor.py +0 -945
- relationalai/semantics/reasoners/__init__.py +0 -10
- relationalai/semantics/reasoners/graph/README.md +0 -620
- relationalai/semantics/reasoners/graph/__init__.py +0 -37
- relationalai/semantics/reasoners/graph/core.py +0 -9019
- relationalai/semantics/reasoners/graph/design/beyond_demand_transform.md +0 -797
- relationalai/semantics/reasoners/graph/tests/README.md +0 -21
- relationalai/semantics/reasoners/optimization/__init__.py +0 -68
- relationalai/semantics/reasoners/optimization/common.py +0 -88
- relationalai/semantics/reasoners/optimization/solvers_dev.py +0 -568
- relationalai/semantics/reasoners/optimization/solvers_pb.py +0 -1407
- relationalai/semantics/rel/builtins.py +0 -40
- relationalai/semantics/rel/compiler.py +0 -994
- relationalai/semantics/rel/executor.py +0 -363
- relationalai/semantics/rel/rel.py +0 -482
- relationalai/semantics/rel/rel_utils.py +0 -276
- relationalai/semantics/snowflake/__init__.py +0 -3
- relationalai/semantics/sql/compiler.py +0 -2503
- relationalai/semantics/sql/executor/duck_db.py +0 -52
- relationalai/semantics/sql/executor/result_helpers.py +0 -64
- relationalai/semantics/sql/executor/snowflake.py +0 -149
- relationalai/semantics/sql/rewrite/denormalize.py +0 -222
- relationalai/semantics/sql/rewrite/double_negation.py +0 -49
- relationalai/semantics/sql/rewrite/recursive_union.py +0 -127
- relationalai/semantics/sql/rewrite/sort_output_query.py +0 -246
- relationalai/semantics/sql/sql.py +0 -504
- relationalai/semantics/std/pragmas.py +0 -11
- relationalai/semantics/std/std.py +0 -14
- relationalai/semantics/tests/lqp/algorithms.py +0 -345
- relationalai/semantics/tests/test_snapshot_abstract.py +0 -144
- relationalai/semantics/tests/test_snapshot_base.py +0 -9
- relationalai/semantics/tests/utils.py +0 -46
- relationalai/std/__init__.py +0 -70
- relationalai/tools/cli.py +0 -2089
- relationalai/tools/cli_controls.py +0 -1975
- relationalai/tools/cli_helpers.py +0 -802
- relationalai/tools/debugger_client.py +0 -109
- relationalai/tools/debugger_server.py +0 -302
- relationalai/tools/dev.py +0 -685
- relationalai/tools/notes +0 -7
- relationalai/tools/qb_debugger.py +0 -425
- relationalai/tools/txn_progress.py +0 -188
- relationalai/util/clean_up_databases.py +0 -95
- relationalai/util/list_databases.py +0 -9
- relationalai/util/otel_configuration.py +0 -26
- relationalai/util/otel_handler.py +0 -484
- relationalai/util/snowflake_handler.py +0 -88
- relationalai/util/span_format_test.py +0 -43
- relationalai/util/span_tracker.py +0 -207
- relationalai/util/spans_file_handler.py +0 -72
- relationalai/util/tracing_handler.py +0 -34
- relationalai-0.13.5.dist-info/METADATA +0 -74
- relationalai-0.13.5.dist-info/RECORD +0 -473
- relationalai-0.13.5.dist-info/WHEEL +0 -4
- relationalai-0.13.5.dist-info/entry_points.txt +0 -3
- relationalai-0.13.5.dist-info/licenses/LICENSE +0 -202
- relationalai_test_util/__init__.py +0 -4
- relationalai_test_util/fixtures.py +0 -233
- relationalai_test_util/snapshot.py +0 -252
- relationalai_test_util/traceback.py +0 -118
- /relationalai/{analysis → semantics/frontend}/__init__.py +0 -0
- /relationalai/{auth/__init__.py → semantics/metamodel/metamodel_compiler.py} +0 -0
- /relationalai/{early_access → shims}/__init__.py +0 -0
- {relationalai/early_access/dsl/adapters → v0/relationalai/analysis}/__init__.py +0 -0
- {relationalai → v0/relationalai}/analysis/mechanistic.py +0 -0
- {relationalai → v0/relationalai}/analysis/whynot.py +0 -0
- {relationalai/early_access/dsl/adapters/orm → v0/relationalai/auth}/__init__.py +0 -0
- {relationalai → v0/relationalai}/auth/jwt_generator.py +0 -0
- {relationalai → v0/relationalai}/auth/oauth_callback_server.py +0 -0
- {relationalai → v0/relationalai}/auth/token_handler.py +0 -0
- {relationalai → v0/relationalai}/auth/util.py +0 -0
- {relationalai/clients/resources/snowflake → v0/relationalai/clients}/cache_store.py +0 -0
- {relationalai → v0/relationalai}/compiler.py +0 -0
- {relationalai → v0/relationalai}/dependencies.py +0 -0
- {relationalai → v0/relationalai}/docutils.py +0 -0
- {relationalai/early_access/dsl/adapters/owl → v0/relationalai/early_access}/__init__.py +0 -0
- {relationalai → v0/relationalai}/early_access/dsl/__init__.py +0 -0
- {relationalai/early_access/dsl/bindings → v0/relationalai/early_access/dsl/adapters}/__init__.py +0 -0
- {relationalai/early_access/dsl/bindings/legacy → v0/relationalai/early_access/dsl/adapters/orm}/__init__.py +0 -0
- {relationalai → v0/relationalai}/early_access/dsl/adapters/orm/model.py +0 -0
- {relationalai/early_access/dsl/codegen → v0/relationalai/early_access/dsl/adapters/owl}/__init__.py +0 -0
- {relationalai → v0/relationalai}/early_access/dsl/adapters/owl/model.py +0 -0
- {relationalai/early_access/dsl/core/temporal → v0/relationalai/early_access/dsl/bindings}/__init__.py +0 -0
- {relationalai/early_access/dsl/ir → v0/relationalai/early_access/dsl/bindings/legacy}/__init__.py +0 -0
- {relationalai/early_access/dsl/ontologies → v0/relationalai/early_access/dsl/codegen}/__init__.py +0 -0
- {relationalai → v0/relationalai}/early_access/dsl/constants.py +0 -0
- {relationalai → v0/relationalai}/early_access/dsl/core/__init__.py +0 -0
- {relationalai → v0/relationalai}/early_access/dsl/core/constraints/__init__.py +0 -0
- {relationalai → v0/relationalai}/early_access/dsl/core/constraints/predicate/__init__.py +0 -0
- {relationalai → v0/relationalai}/early_access/dsl/core/stack.py +0 -0
- {relationalai/early_access/dsl/orm → v0/relationalai/early_access/dsl/core/temporal}/__init__.py +0 -0
- {relationalai → v0/relationalai}/early_access/dsl/core/utils.py +0 -0
- {relationalai/early_access/dsl/orm/measures → v0/relationalai/early_access/dsl/ir}/__init__.py +0 -0
- {relationalai/early_access/dsl/physical_metadata → v0/relationalai/early_access/dsl/ontologies}/__init__.py +0 -0
- {relationalai → v0/relationalai}/early_access/dsl/ontologies/raw_source.py +0 -0
- {relationalai/early_access/dsl/serialize → v0/relationalai/early_access/dsl/orm}/__init__.py +0 -0
- {relationalai/early_access/dsl/snow → v0/relationalai/early_access/dsl/orm/measures}/__init__.py +0 -0
- {relationalai → v0/relationalai}/early_access/dsl/orm/reasoner_errors.py +0 -0
- {relationalai/loaders → v0/relationalai/early_access/dsl/physical_metadata}/__init__.py +0 -0
- {relationalai/semantics/tests → v0/relationalai/early_access/dsl/serialize}/__init__.py +0 -0
- {relationalai → v0/relationalai}/early_access/dsl/serialize/binding_model.py +0 -0
- {relationalai → v0/relationalai}/early_access/dsl/serialize/model.py +0 -0
- {relationalai/semantics/tests/lqp → v0/relationalai/early_access/dsl/snow}/__init__.py +0 -0
- {relationalai → v0/relationalai}/early_access/tests/__init__.py +0 -0
- {relationalai → v0/relationalai}/environments/ci.py +0 -0
- {relationalai → v0/relationalai}/environments/hex.py +0 -0
- {relationalai → v0/relationalai}/environments/terminal.py +0 -0
- {relationalai → v0/relationalai}/experimental/__init__.py +0 -0
- {relationalai → v0/relationalai}/experimental/graphs.py +0 -0
- {relationalai → v0/relationalai}/experimental/paths/__init__.py +0 -0
- {relationalai → v0/relationalai}/experimental/paths/benchmarks/__init__.py +0 -0
- {relationalai → v0/relationalai}/experimental/paths/path_algorithms/__init__.py +0 -0
- {relationalai → v0/relationalai}/experimental/paths/rpq/__init__.py +0 -0
- {relationalai → v0/relationalai}/experimental/paths/rpq/filter.py +0 -0
- {relationalai → v0/relationalai}/experimental/paths/rpq/glushkov.py +0 -0
- {relationalai → v0/relationalai}/experimental/paths/rpq/transition.py +0 -0
- {relationalai → v0/relationalai}/experimental/paths/utilities/__init__.py +0 -0
- {relationalai → v0/relationalai}/experimental/paths/utilities/utilities.py +0 -0
- {relationalai/tools → v0/relationalai/loaders}/__init__.py +0 -0
- {relationalai → v0/relationalai}/metagen.py +0 -0
- {relationalai → v0/relationalai}/metamodel.py +0 -0
- {relationalai → v0/relationalai}/rel.py +0 -0
- {relationalai → v0/relationalai}/semantics/devtools/__init__.py +0 -0
- {relationalai → v0/relationalai}/semantics/internal/__init__.py +0 -0
- {relationalai → v0/relationalai}/semantics/internal/annotations.py +0 -0
- {relationalai → v0/relationalai}/semantics/lqp/__init__.py +0 -0
- {relationalai → v0/relationalai}/semantics/lqp/pragmas.py +0 -0
- {relationalai → v0/relationalai}/semantics/metamodel/dataflow.py +0 -0
- {relationalai → v0/relationalai}/semantics/metamodel/typer/__init__.py +0 -0
- {relationalai → v0/relationalai}/semantics/metamodel/types.py +0 -0
- {relationalai → v0/relationalai}/semantics/reasoners/experimental/__init__.py +0 -0
- {relationalai → v0/relationalai}/semantics/rel/__init__.py +0 -0
- {relationalai → v0/relationalai}/semantics/sql/__init__.py +0 -0
- {relationalai → v0/relationalai}/semantics/sql/executor/__init__.py +0 -0
- {relationalai → v0/relationalai}/semantics/sql/rewrite/__init__.py +0 -0
- {relationalai → v0/relationalai}/semantics/tests/logging.py +0 -0
- {relationalai → v0/relationalai}/std/aggregates.py +0 -0
- {relationalai → v0/relationalai}/std/dates.py +0 -0
- {relationalai → v0/relationalai}/std/graphs.py +0 -0
- {relationalai → v0/relationalai}/std/inspect.py +0 -0
- {relationalai → v0/relationalai}/std/math.py +0 -0
- {relationalai → v0/relationalai}/std/re.py +0 -0
- {relationalai → v0/relationalai}/std/strings.py +0 -0
- {relationalai → v0/relationalai}/tools/cleanup_snapshots.py +0 -0
- {relationalai → v0/relationalai}/tools/constants.py +0 -0
- {relationalai → v0/relationalai}/tools/query_utils.py +0 -0
- {relationalai → v0/relationalai}/tools/snapshot_viewer.py +0 -0
- {relationalai → v0/relationalai}/util/__init__.py +0 -0
- {relationalai → v0/relationalai}/util/constants.py +0 -0
- {relationalai → v0/relationalai}/util/graph.py +0 -0
- {relationalai → v0/relationalai}/util/timeout.py +0 -0
|
@@ -0,0 +1,1316 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from contextlib import contextmanager
|
|
3
|
+
from enum import Enum
|
|
4
|
+
from functools import lru_cache, wraps
|
|
5
|
+
from itertools import chain
|
|
6
|
+
from re import sub
|
|
7
|
+
from typing import Any, Optional, Sequence, cast
|
|
8
|
+
from collections.abc import Iterable
|
|
9
|
+
|
|
10
|
+
from ...util.naming import Namer, sanitize
|
|
11
|
+
from ...util.source import SourcePos
|
|
12
|
+
from ...util.structures import KeyedDict, KeyedSet, OrderedSet
|
|
13
|
+
from .pprint import pprint
|
|
14
|
+
from ..metamodel.builtins import builtins as bt
|
|
15
|
+
from ..metamodel.pprint import pprint as mmpp, print_tree
|
|
16
|
+
from ...util.error import Diagnostic, Part, err, warn, source as err_source, exc
|
|
17
|
+
|
|
18
|
+
from .base import (
|
|
19
|
+
Alias, AsBool, CoreConcepts, CoreRelationships, DSLBase, Data, DerivedColumn, Distinct, Field, FieldRef, FilterBy, Group, Library, Literal, Model, Fragment, ModelEnum, New, Not, Chain,
|
|
20
|
+
Property, Ref, Relationship, Concept, Expression, Statement, Table, TableSchema, TupleVariable, Value, Variable, Match, Union, dsl_key, is_primitive,
|
|
21
|
+
NumberConcept, Reading, Aggregate, MetaRef
|
|
22
|
+
)
|
|
23
|
+
from ..metamodel.metamodel import (
|
|
24
|
+
Aggregate as mAggregate, Annotation, Construct, Effect, FieldType, ISeq, ListType, Logical, Node, NoneType, NumberType, Relation, RelationType, Require, ScalarType, Overload,
|
|
25
|
+
Lookup, TupleType, TypeNode, UnresolvedRelation, Var, Task, Literal as mLiteral, Value as mValue, Table as mTable, Update,
|
|
26
|
+
Field as mField, Not as mNot, Reading as mReading, Match as mMatch, Union as mUnion, Data as mData, Model as mModel
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
#------------------------------------------------------
|
|
30
|
+
# Memoize
|
|
31
|
+
#------------------------------------------------------
|
|
32
|
+
|
|
33
|
+
def memoize_in_ctx(method):
|
|
34
|
+
"""Cache results in ctx.seen using id(node) as the key."""
|
|
35
|
+
@wraps(method)
|
|
36
|
+
def wrapper(self, ctx, node, *args, **kwargs):
|
|
37
|
+
seen = ctx.seen
|
|
38
|
+
key = id(node)
|
|
39
|
+
if key in seen:
|
|
40
|
+
return seen[key]
|
|
41
|
+
seen[key] = result = method(self, ctx, node, *args, **kwargs)
|
|
42
|
+
return result
|
|
43
|
+
return wrapper
|
|
44
|
+
|
|
45
|
+
#------------------------------------------------------
|
|
46
|
+
# Helpers
|
|
47
|
+
#------------------------------------------------------
|
|
48
|
+
|
|
49
|
+
def find_keys(item: Value | Statement, root_only: bool = False) -> list[Value]:
|
|
50
|
+
if isinstance(item, (Concept, Ref)):
|
|
51
|
+
return [item]
|
|
52
|
+
if isinstance(item, Chain):
|
|
53
|
+
keys = []
|
|
54
|
+
if not root_only and not isinstance(item._next, Property) and len(item._next._fields) > 1:
|
|
55
|
+
keys.extend([FieldRef(item, ix + 1, field, ix + 1) for ix, field in enumerate(item._next._fields[1:-1])])
|
|
56
|
+
keys.append(item)
|
|
57
|
+
keys.extend(find_keys(item._start, root_only))
|
|
58
|
+
return keys
|
|
59
|
+
if isinstance(item, Relationship):
|
|
60
|
+
if root_only:
|
|
61
|
+
return [item]
|
|
62
|
+
return list(item._fields[:-1])
|
|
63
|
+
if isinstance(item, FieldRef):
|
|
64
|
+
return find_keys(item._root, root_only)
|
|
65
|
+
if isinstance(item, Expression):
|
|
66
|
+
root = item._root if item._root is not None else item._op
|
|
67
|
+
is_func = isinstance(root, Relationship) and any(field.is_input for field in root._fields)
|
|
68
|
+
if root_only and item._root is not None and not(is_func):
|
|
69
|
+
# We ignore "function-like relationships" (those with inputs) since they are never a root
|
|
70
|
+
if isinstance(item._root, Relationship):
|
|
71
|
+
return [item]
|
|
72
|
+
return find_keys(item._root, root_only=True)
|
|
73
|
+
args = item._args[:-1] if isinstance(item._op, Property) else item._args
|
|
74
|
+
if is_func:
|
|
75
|
+
assert isinstance(root, Relationship)
|
|
76
|
+
args = [item._args[ix] for ix, field in enumerate(root._fields) if field.is_input]
|
|
77
|
+
keys = []
|
|
78
|
+
for arg in args:
|
|
79
|
+
keys.extend(find_keys(arg, root_only))
|
|
80
|
+
return keys
|
|
81
|
+
if isinstance(item, Fragment):
|
|
82
|
+
keys = []
|
|
83
|
+
for subitem in item._select:
|
|
84
|
+
keys.extend(find_keys(subitem, root_only))
|
|
85
|
+
return keys
|
|
86
|
+
if isinstance(item, DerivedColumn):
|
|
87
|
+
return find_keys(item._table, root_only)
|
|
88
|
+
if isinstance(item, Union):
|
|
89
|
+
# Unions should always act as sets and so have no keys
|
|
90
|
+
return []
|
|
91
|
+
if isinstance(item, Match):
|
|
92
|
+
keys = []
|
|
93
|
+
if root_only:
|
|
94
|
+
keys.extend(find_keys(item._items[0], root_only))
|
|
95
|
+
else:
|
|
96
|
+
for subitem in item._items:
|
|
97
|
+
keys.extend(find_keys(subitem, root_only))
|
|
98
|
+
return keys
|
|
99
|
+
if isinstance(item, TupleVariable):
|
|
100
|
+
keys = []
|
|
101
|
+
for subitem in item._items:
|
|
102
|
+
keys.extend(find_keys(subitem, root_only))
|
|
103
|
+
return keys
|
|
104
|
+
return []
|
|
105
|
+
|
|
106
|
+
def mm_value_type(value: mValue) -> TypeNode:
|
|
107
|
+
if isinstance(value, (Var, mLiteral)):
|
|
108
|
+
return value.type
|
|
109
|
+
elif isinstance(value, TypeNode):
|
|
110
|
+
return value
|
|
111
|
+
elif isinstance(value, Relation):
|
|
112
|
+
return RelationType
|
|
113
|
+
elif isinstance(value, Field):
|
|
114
|
+
return FieldType
|
|
115
|
+
elif isinstance(value, Iterable):
|
|
116
|
+
return TupleType(element_types=tuple(mm_value_type(v) for v in value))
|
|
117
|
+
elif value is None:
|
|
118
|
+
return NoneType
|
|
119
|
+
else:
|
|
120
|
+
raise NotImplementedError(f"mm_value_type not implemented for value type: {type(value)}")
|
|
121
|
+
|
|
122
|
+
@lru_cache(maxsize=1)
|
|
123
|
+
def _get_core():
|
|
124
|
+
from . import core
|
|
125
|
+
return core
|
|
126
|
+
|
|
127
|
+
@lru_cache(maxsize=1)
|
|
128
|
+
def _get_constraints():
|
|
129
|
+
from ..std import constraints
|
|
130
|
+
return constraints
|
|
131
|
+
|
|
132
|
+
def is_core_concept(concept):
|
|
133
|
+
core = _get_core()
|
|
134
|
+
if concept._model is core.Core:
|
|
135
|
+
return True
|
|
136
|
+
return any(is_core_concept(a) for a in concept._extends)
|
|
137
|
+
|
|
138
|
+
def concept_var_name(concept: Concept|Relationship) -> str:
|
|
139
|
+
if isinstance(concept, Relationship):
|
|
140
|
+
return sanitize(concept._short_name).lower()
|
|
141
|
+
core = _get_core()
|
|
142
|
+
if isinstance(concept, core.NumberConcept) or concept is core.Numeric:
|
|
143
|
+
return "number"
|
|
144
|
+
return sanitize(concept._name).lower()
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
#------------------------------------------------------
|
|
148
|
+
# Reference scheme handling
|
|
149
|
+
#------------------------------------------------------
|
|
150
|
+
|
|
151
|
+
def report_missing(concept:Concept, missing:OrderedSet[str], required:OrderedSet[str], source, ctx:Context):
|
|
152
|
+
if missing:
|
|
153
|
+
missing_str = ", ".join([f"`{name}`" for name in missing])
|
|
154
|
+
required_str = ", ".join([f"[bold red]{name}[/bold red]" if name in missing else name for name in required])
|
|
155
|
+
message = "values for properties" if len(missing) > 1 else "a value for property"
|
|
156
|
+
ctx.err("Missing identity", f"Missing {message} {missing_str} in concept `{concept._name}`.", [
|
|
157
|
+
err_source(source),
|
|
158
|
+
f"{concept._name} requires {required_str}"
|
|
159
|
+
])
|
|
160
|
+
return True
|
|
161
|
+
return False
|
|
162
|
+
|
|
163
|
+
def make_construct(compiler:FrontCompiler,ctx:Context, concept:Concept, kwargs:dict[str, Any], ident_args:list[str], target:Var, source:Any=None):
|
|
164
|
+
construct_args:list[mValue] = [
|
|
165
|
+
ctx.to_value(concept._name),
|
|
166
|
+
*[compiler.lookup(ctx, kwargs[ident]) for ident in ident_args]
|
|
167
|
+
]
|
|
168
|
+
return Construct(tuple(construct_args), target, source=source)
|
|
169
|
+
|
|
170
|
+
def handle_concept_expression(compiler:FrontCompiler, ctx:Context, expr:Expression) -> Var:
|
|
171
|
+
assert isinstance(expr._op, Concept)
|
|
172
|
+
source = expr._source
|
|
173
|
+
passed_concept = expr._op
|
|
174
|
+
kwargs = {k.lower(): v for k, v in expr._kwargs.items()}
|
|
175
|
+
|
|
176
|
+
root_concept = None
|
|
177
|
+
hierarchy:list[Concept] = []
|
|
178
|
+
constructs = KeyedDict[Concept, list[str]](dsl_key)
|
|
179
|
+
required = OrderedSet[str]()
|
|
180
|
+
missing = OrderedSet[str]()
|
|
181
|
+
|
|
182
|
+
def walk_extends(c:Concept):
|
|
183
|
+
nonlocal root_concept
|
|
184
|
+
if c in hierarchy:
|
|
185
|
+
return
|
|
186
|
+
for ext in c._extends:
|
|
187
|
+
walk_extends(ext)
|
|
188
|
+
hierarchy.append(c)
|
|
189
|
+
if c._identify_by and root_concept is None:
|
|
190
|
+
root_concept = c
|
|
191
|
+
ident_args = []
|
|
192
|
+
for ident_rel in c._identify_by:
|
|
193
|
+
ident = ident_rel._short_name.lower()
|
|
194
|
+
required.add(ident)
|
|
195
|
+
if ident in kwargs:
|
|
196
|
+
ident_args.append(ident)
|
|
197
|
+
else:
|
|
198
|
+
missing.add(ident)
|
|
199
|
+
constructs[c] = ident_args
|
|
200
|
+
|
|
201
|
+
walk_extends(passed_concept)
|
|
202
|
+
|
|
203
|
+
if root_concept is None:
|
|
204
|
+
root_concept = hierarchy[0]
|
|
205
|
+
if isinstance(expr, New) and expr._row_ids:
|
|
206
|
+
names = [f"_row_id_{t._name}" for t in expr._row_ids]
|
|
207
|
+
kwargs.update({name: expr._row_ids[ix] for ix, name in enumerate(names)})
|
|
208
|
+
constructs[root_concept] = list(sorted(names))
|
|
209
|
+
else:
|
|
210
|
+
constructs[root_concept] = list(sorted(kwargs.keys()))
|
|
211
|
+
|
|
212
|
+
root_id = ctx.to_value(expr)
|
|
213
|
+
assert isinstance(root_id, Var)
|
|
214
|
+
root_args = constructs[root_concept]
|
|
215
|
+
|
|
216
|
+
if isinstance(expr, New) and ctx.in_update:
|
|
217
|
+
# New requires that none of the identity args are missing
|
|
218
|
+
if report_missing(passed_concept, missing, required, source, ctx):
|
|
219
|
+
return root_id
|
|
220
|
+
|
|
221
|
+
# construct the root identity
|
|
222
|
+
ctx.add(make_construct(compiler, ctx, root_concept, kwargs, root_args, root_id, source=source))
|
|
223
|
+
if expr not in ctx.construct_handled:
|
|
224
|
+
ctx.add_update(passed_concept, [root_id], source=source)
|
|
225
|
+
|
|
226
|
+
# Update identity and non-identity attributes
|
|
227
|
+
for k, v in kwargs.items():
|
|
228
|
+
with ctx.subcontext():
|
|
229
|
+
rel = passed_concept._dot(k)
|
|
230
|
+
ctx.add_update(rel, [root_id, compiler.lookup(ctx, v)], source=source)
|
|
231
|
+
nodes = tuple(ctx.nodes)
|
|
232
|
+
ctx.add(Logical(nodes, source=source, optional=True))
|
|
233
|
+
|
|
234
|
+
ctx.construct_handled.add(expr)
|
|
235
|
+
|
|
236
|
+
elif isinstance(expr, New):
|
|
237
|
+
# New requires that none of the identity args are missing
|
|
238
|
+
if report_missing(passed_concept, missing, required, source, ctx):
|
|
239
|
+
return root_id
|
|
240
|
+
|
|
241
|
+
# just construct the root identity and then look it up in the subtype
|
|
242
|
+
# population
|
|
243
|
+
ctx.add(make_construct(compiler, ctx, root_concept, kwargs, root_args, root_id, source=source))
|
|
244
|
+
ctx.add_lookup(passed_concept, [root_id], source=source)
|
|
245
|
+
|
|
246
|
+
# Any non-identity attributes are filters
|
|
247
|
+
for k, v in kwargs.items():
|
|
248
|
+
if k not in root_args:
|
|
249
|
+
rel = passed_concept._dot(k)
|
|
250
|
+
ctx.add_lookup(rel, [root_id, compiler.lookup(ctx, v)], source=source)
|
|
251
|
+
|
|
252
|
+
elif isinstance(expr, FilterBy):
|
|
253
|
+
# check if _any_ concept has all the identity args it needs as a
|
|
254
|
+
if len(root_args) == len(root_concept._identify_by):
|
|
255
|
+
ctx.add(make_construct(compiler, ctx, root_concept, kwargs, root_args, root_id, source=source))
|
|
256
|
+
else:
|
|
257
|
+
# if we don't have all the identity args for the root, we need to look up any partials
|
|
258
|
+
root_args = []
|
|
259
|
+
|
|
260
|
+
ctx.add_lookup(passed_concept, [root_id], source=source)
|
|
261
|
+
for k, v in kwargs.items():
|
|
262
|
+
if k not in root_args:
|
|
263
|
+
rel = passed_concept._dot(k)
|
|
264
|
+
ctx.add_lookup(rel, [root_id, compiler.lookup(ctx, v)], source=source)
|
|
265
|
+
else:
|
|
266
|
+
exc("Invalid concept expression", f"Expected a `New` or `FilterBy` expression, got `{type(expr).__name__}`.", [err_source(source)])
|
|
267
|
+
|
|
268
|
+
return root_id
|
|
269
|
+
|
|
270
|
+
#------------------------------------------------------
|
|
271
|
+
# Match union branch keys
|
|
272
|
+
#------------------------------------------------------
|
|
273
|
+
|
|
274
|
+
def get_branch_keys(compiler:FrontCompiler, ctx:Context, branch:Match|Union) -> list[tuple[Value, Var]]:
|
|
275
|
+
keys = KeyedSet(dsl_key)
|
|
276
|
+
for item in branch._items:
|
|
277
|
+
if not isinstance(item, Fragment):
|
|
278
|
+
keys.update(find_keys(item))
|
|
279
|
+
branch_keys = []
|
|
280
|
+
seen_keys = set()
|
|
281
|
+
for key in keys:
|
|
282
|
+
k_var = ctx.to_value(key)
|
|
283
|
+
if k_var not in seen_keys and isinstance(k_var, Var) and not ctx.is_var_available(k_var, ignore_current=True):
|
|
284
|
+
seen_keys.add(k_var)
|
|
285
|
+
branch_keys.append((key, k_var))
|
|
286
|
+
return branch_keys
|
|
287
|
+
|
|
288
|
+
def normalize_branch_keys(compiler:FrontCompiler, ctx:Context, branch_keys:list[tuple[Value, Var]], branch:Statement):
|
|
289
|
+
for key, var in branch_keys:
|
|
290
|
+
if var not in ctx.frame_vars:
|
|
291
|
+
source = branch._source if isinstance(branch, DSLBase) else var.source
|
|
292
|
+
if not isinstance(key, (Concept, Ref)):
|
|
293
|
+
return ctx.err("Invalid branch", "Branch key must be a concept or reference.", [err_source(source)])
|
|
294
|
+
concept = key._to_concept()
|
|
295
|
+
if is_core_concept(concept):
|
|
296
|
+
return ctx.err("Invalid branch", "Branch key must be an entity, not a primitive.", [err_source(source)])
|
|
297
|
+
else:
|
|
298
|
+
ctx.add(Construct((ctx.to_value(concept._name + "_NONE_SENTINEL"),), var, source=key._source))
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
#------------------------------------------------------
|
|
302
|
+
# Context
|
|
303
|
+
#------------------------------------------------------
|
|
304
|
+
|
|
305
|
+
class Frame:
|
|
306
|
+
def __init__(self):
|
|
307
|
+
self.nodes:OrderedSet[Task] = OrderedSet()
|
|
308
|
+
self.in_update = False
|
|
309
|
+
self.used_vars:OrderedSet[Var] = OrderedSet()
|
|
310
|
+
self.seen:dict[Value, mValue] = {}
|
|
311
|
+
|
|
312
|
+
class Context:
|
|
313
|
+
def __init__(self, compiler:FrontCompiler):
|
|
314
|
+
self.compiler = compiler
|
|
315
|
+
self.stack:list[Frame] = [Frame()]
|
|
316
|
+
self.value_map:KeyedDict[Value|tuple[Value, Value], mValue] = KeyedDict(dsl_key)
|
|
317
|
+
self.has_error = False
|
|
318
|
+
self._in_update = False
|
|
319
|
+
self.construct_handled:KeyedSet[New] = KeyedSet(dsl_key)
|
|
320
|
+
|
|
321
|
+
#------------------------------------------------------
|
|
322
|
+
# subcontext
|
|
323
|
+
#------------------------------------------------------
|
|
324
|
+
|
|
325
|
+
@contextmanager
|
|
326
|
+
def subcontext(self):
|
|
327
|
+
self.stack.append(Frame())
|
|
328
|
+
try:
|
|
329
|
+
yield
|
|
330
|
+
finally:
|
|
331
|
+
prev = self.stack.pop()
|
|
332
|
+
self.stack[-1].used_vars.update(prev.used_vars)
|
|
333
|
+
|
|
334
|
+
#------------------------------------------------------
|
|
335
|
+
# in_update
|
|
336
|
+
#------------------------------------------------------
|
|
337
|
+
|
|
338
|
+
@contextmanager
|
|
339
|
+
def updating(self):
|
|
340
|
+
prev = self.in_update
|
|
341
|
+
self._in_update = True
|
|
342
|
+
try:
|
|
343
|
+
yield
|
|
344
|
+
finally:
|
|
345
|
+
self._in_update = prev
|
|
346
|
+
if not self._in_update:
|
|
347
|
+
self.construct_handled.clear()
|
|
348
|
+
|
|
349
|
+
@property
|
|
350
|
+
def in_update(self) -> bool:
|
|
351
|
+
return self._in_update
|
|
352
|
+
|
|
353
|
+
#------------------------------------------------------
|
|
354
|
+
# Errors/warnings
|
|
355
|
+
#------------------------------------------------------
|
|
356
|
+
|
|
357
|
+
def err(self, name: str, message: str, parts: Optional[list[Part]] = None) -> Diagnostic:
|
|
358
|
+
self.has_error = True
|
|
359
|
+
return err(name, message, parts)
|
|
360
|
+
|
|
361
|
+
def warn(self, name: str, message: str, parts: Optional[list[Part]] = None) -> Diagnostic:
|
|
362
|
+
self.has_error = True
|
|
363
|
+
return warn(name, message, parts)
|
|
364
|
+
|
|
365
|
+
#------------------------------------------------------
|
|
366
|
+
# Task capture
|
|
367
|
+
#------------------------------------------------------
|
|
368
|
+
|
|
369
|
+
def _check_frames(self, node:Task):
|
|
370
|
+
for frame in reversed(self.stack[:-1]):
|
|
371
|
+
if node in frame.nodes:
|
|
372
|
+
return True
|
|
373
|
+
return False
|
|
374
|
+
|
|
375
|
+
def add(self, node:Task):
|
|
376
|
+
if self._check_frames(node):
|
|
377
|
+
return
|
|
378
|
+
self.stack[-1].nodes.add(node)
|
|
379
|
+
|
|
380
|
+
def extend(self, nodes:Sequence[Task]):
|
|
381
|
+
for node in nodes:
|
|
382
|
+
self.add(node)
|
|
383
|
+
|
|
384
|
+
def add_lookup(self, relationship:Relationship|Concept, args:Sequence[mValue], source:Any=None):
|
|
385
|
+
op = self.compiler.to_relation(relationship)
|
|
386
|
+
hint = None
|
|
387
|
+
if isinstance(relationship, Reading):
|
|
388
|
+
hint = self.compiler.find_reading(relationship)
|
|
389
|
+
# reorder the args to match the correct ordering
|
|
390
|
+
new_args:list[Any] = [None] * len(hint.field_order)
|
|
391
|
+
for cur, new in enumerate(hint.field_order):
|
|
392
|
+
new_args[new] = args[cur]
|
|
393
|
+
args = new_args
|
|
394
|
+
self.add(Lookup(op, tuple(args), reading_hint=hint, source=source))
|
|
395
|
+
|
|
396
|
+
def add_update(self, relationship:Relationship|Concept, args:Sequence[mValue], effect=Effect.derive, source:Any=None):
|
|
397
|
+
op = self.compiler.to_relation(relationship)
|
|
398
|
+
hint = None
|
|
399
|
+
if isinstance(relationship, Reading):
|
|
400
|
+
hint = self.compiler.reading_map[relationship]
|
|
401
|
+
# reorder the args to match the correct ordering
|
|
402
|
+
new_args:list[Any] = [None] * len(hint.field_order)
|
|
403
|
+
for cur, new in enumerate(hint.field_order):
|
|
404
|
+
new_args[new] = args[cur]
|
|
405
|
+
args = new_args
|
|
406
|
+
self.add(Update(op, tuple(args), effect=effect, reading_hint=hint, source=source))
|
|
407
|
+
|
|
408
|
+
def add_eq(self, left:mValue, right:mValue, source:Any=None):
|
|
409
|
+
self.add(Lookup(getattr(bt.core, "="), (left, right), source=source))
|
|
410
|
+
|
|
411
|
+
@property
|
|
412
|
+
def nodes(self):
|
|
413
|
+
return self.stack[-1].nodes
|
|
414
|
+
|
|
415
|
+
#------------------------------------------------------
|
|
416
|
+
# Value mapping
|
|
417
|
+
#------------------------------------------------------
|
|
418
|
+
|
|
419
|
+
def to_value(self, value:Value, source:Optional[Value]=None) -> mValue:
|
|
420
|
+
key = (source, value) if source is not None else value
|
|
421
|
+
if res := self.value_map.get(key):
|
|
422
|
+
if isinstance(res, Var):
|
|
423
|
+
self.stack[-1].used_vars.add(res)
|
|
424
|
+
return res
|
|
425
|
+
|
|
426
|
+
node = None
|
|
427
|
+
if isinstance(value, Concept):
|
|
428
|
+
value_type = self.compiler.to_type(value)
|
|
429
|
+
node = Var(value_type, concept_var_name(value), source=value._source)
|
|
430
|
+
elif isinstance(value, Chain):
|
|
431
|
+
node = self.to_value(value._next._fields[-1], value)
|
|
432
|
+
elif isinstance(value, Ref):
|
|
433
|
+
value_type = self.compiler.to_type(value._concept)
|
|
434
|
+
name = sanitize(value._name).lower() if value._name else f"{concept_var_name(value._concept)}{value._id}"
|
|
435
|
+
node = Var(value_type, name, source=value._source)
|
|
436
|
+
elif isinstance(value, Field):
|
|
437
|
+
value_type = self.compiler.to_type(value.type)
|
|
438
|
+
node = Var(value_type, sanitize(value.name).lower())
|
|
439
|
+
elif isinstance(value, New):
|
|
440
|
+
value_type = self.compiler.to_type(value._op)
|
|
441
|
+
node = Var(value_type, f"{concept_var_name(value._op)}", source=value._source)
|
|
442
|
+
elif isinstance(value, FieldRef):
|
|
443
|
+
node = self.to_value(value._resolved, source=value._root)
|
|
444
|
+
elif isinstance(value, Expression):
|
|
445
|
+
node = self.to_value(value._args[-1])
|
|
446
|
+
elif isinstance(value, Aggregate):
|
|
447
|
+
node = self.to_value(value._args[-1])
|
|
448
|
+
elif isinstance(value, DerivedColumn):
|
|
449
|
+
value_type = self.compiler.to_type(value._type) if value._type is not None else bt.core.Any
|
|
450
|
+
node = Var(value_type, f"v", source=value._source)
|
|
451
|
+
elif isinstance(value, Literal):
|
|
452
|
+
value_type = self.compiler.to_type(value._type)
|
|
453
|
+
node = mLiteral(type=value_type, value=value._value, source=value._source)
|
|
454
|
+
elif isinstance(value, AsBool):
|
|
455
|
+
node = Var(bt.core.Boolean, f"v", source=value._source)
|
|
456
|
+
elif isinstance(value, MetaRef):
|
|
457
|
+
if isinstance(value._target, Concept):
|
|
458
|
+
node = self.compiler.to_type(value._target)
|
|
459
|
+
elif isinstance(value._target, Relationship):
|
|
460
|
+
node = self.compiler.to_relation(value._target)
|
|
461
|
+
elif isinstance(value._target, Field):
|
|
462
|
+
node = self.compiler.to_field(value._target)
|
|
463
|
+
else:
|
|
464
|
+
node = self.to_value(value._target)
|
|
465
|
+
elif is_primitive(value):
|
|
466
|
+
type_ = self.compiler.to_type(Literal._get_type(value))
|
|
467
|
+
node = mLiteral(type=type_, value=value)
|
|
468
|
+
else:
|
|
469
|
+
raise NotImplementedError(f"to_value not implemented for value type: {type(value)}")
|
|
470
|
+
|
|
471
|
+
if isinstance(node, Var):
|
|
472
|
+
self.stack[-1].used_vars.add(node)
|
|
473
|
+
self.value_map[key] = node
|
|
474
|
+
return node
|
|
475
|
+
|
|
476
|
+
@property
|
|
477
|
+
def frame_vars(self) -> OrderedSet[Var]:
|
|
478
|
+
return self.stack[-1].used_vars
|
|
479
|
+
|
|
480
|
+
def is_var_available(self, var:Var, ignore_current=False) -> bool:
|
|
481
|
+
stack = self.stack[:-1] if ignore_current else self.stack
|
|
482
|
+
for frame in reversed(stack):
|
|
483
|
+
if var in frame.used_vars:
|
|
484
|
+
return True
|
|
485
|
+
return False
|
|
486
|
+
|
|
487
|
+
@property
|
|
488
|
+
def seen(self) -> dict[Value, mValue]:
|
|
489
|
+
return self.stack[-1].seen
|
|
490
|
+
|
|
491
|
+
#------------------------------------------------------
|
|
492
|
+
# Compiler
|
|
493
|
+
#------------------------------------------------------
|
|
494
|
+
|
|
495
|
+
class FrontCompiler:
|
|
496
|
+
def __init__(self, model: Model):
|
|
497
|
+
self.model = model
|
|
498
|
+
self.relations:KeyedDict[DSLBase, Relation] = KeyedDict(dsl_key)
|
|
499
|
+
self.fields:KeyedDict[Field, mField] = KeyedDict(dsl_key)
|
|
500
|
+
self.reading_map: KeyedDict[Reading, mReading] = KeyedDict(dsl_key)
|
|
501
|
+
self.imported_libraries: set[Model] = set()
|
|
502
|
+
self.relation_constraints: OrderedSet[Lookup] = OrderedSet()
|
|
503
|
+
self.global_namer = Namer()
|
|
504
|
+
|
|
505
|
+
#------------------------------------------------------
|
|
506
|
+
# Library handling
|
|
507
|
+
#------------------------------------------------------
|
|
508
|
+
|
|
509
|
+
def check_import(self, node: Any):
|
|
510
|
+
if not isinstance(node, DSLBase):
|
|
511
|
+
return
|
|
512
|
+
if isinstance(node, Aggregate):
|
|
513
|
+
self.check_import(node._op)
|
|
514
|
+
model = node._model
|
|
515
|
+
if model and model != self.model and model not in self.imported_libraries:
|
|
516
|
+
if model not in self.model.libraries:
|
|
517
|
+
self.model.libraries.append(model)
|
|
518
|
+
self.imported_libraries.add(model)
|
|
519
|
+
self.relations.update(model._compiler.relations)
|
|
520
|
+
self.relation_constraints.update(model._compiler.relation_constraints)
|
|
521
|
+
return True
|
|
522
|
+
|
|
523
|
+
#------------------------------------------------------
|
|
524
|
+
# Model elements
|
|
525
|
+
#------------------------------------------------------
|
|
526
|
+
|
|
527
|
+
def find_reading(self, reading:Reading) -> mReading:
|
|
528
|
+
if found := self.reading_map.get(reading):
|
|
529
|
+
return found
|
|
530
|
+
# It's possible that readings were added after the first time we encounter
|
|
531
|
+
# the relationship, so we need to re-create them here and update the relationship
|
|
532
|
+
root = reading._relationship
|
|
533
|
+
rel = self.to_relation(root)
|
|
534
|
+
readings = self.to_readings(root, start=len(rel.readings))
|
|
535
|
+
rel._dangerous_set_readings(rel.readings + readings)
|
|
536
|
+
return self.reading_map[reading]
|
|
537
|
+
|
|
538
|
+
def to_readings(self, relationship: Relationship, start=0) -> tuple[mReading, ...]:
|
|
539
|
+
readings = tuple(mReading(name=reading._short_name, parts=tuple(reading._parts), source=reading._source) for reading in relationship._readings[start:])
|
|
540
|
+
self.reading_map.update((reading, mreading) for reading, mreading in zip(relationship._readings[start:], readings))
|
|
541
|
+
return readings
|
|
542
|
+
|
|
543
|
+
def to_annotation(self, node: Expression | Relationship) -> Annotation:
|
|
544
|
+
if isinstance(node, Expression):
|
|
545
|
+
args = []
|
|
546
|
+
for arg in node._args:
|
|
547
|
+
if isinstance(arg, Literal):
|
|
548
|
+
args.append(mLiteral(type=self.to_type(arg._type), value=arg._value, source=arg._source))
|
|
549
|
+
elif isinstance(arg, Concept) or isinstance(arg, Relationship):
|
|
550
|
+
args.append(self.to_relation(arg))
|
|
551
|
+
elif isinstance(arg, Chain):
|
|
552
|
+
args.append(self.to_relation(arg._next))
|
|
553
|
+
else:
|
|
554
|
+
exc("Invalid annotation", f"Invalid annotation argument type: {type(arg).__name__}", [
|
|
555
|
+
err_source(arg._source),
|
|
556
|
+
"Only Concepts, Relationships, and Literals are allowed as annotation arguments."
|
|
557
|
+
])
|
|
558
|
+
return Annotation(relation=self.to_relation(node._op), args=tuple(args), source=node._source)
|
|
559
|
+
elif isinstance(node, Relationship):
|
|
560
|
+
return Annotation(relation=self.to_relation(node), args=(), source=node._source)
|
|
561
|
+
else:
|
|
562
|
+
raise ValueError(f"Unknown annotation type: {type(node)} - {node}")
|
|
563
|
+
|
|
564
|
+
def to_field(self, node: Field) -> mField:
|
|
565
|
+
if res := self.fields.get(node):
|
|
566
|
+
return res
|
|
567
|
+
field_type = self.to_type(node.type)
|
|
568
|
+
if node.is_list:
|
|
569
|
+
field_type = ListType(element_type=field_type)
|
|
570
|
+
field = mField(name=node.name, type=field_type, input=node.is_input, source=node._source)
|
|
571
|
+
self.fields[node] = field
|
|
572
|
+
return field
|
|
573
|
+
|
|
574
|
+
def to_relation(self, node: Any) -> Relation:
|
|
575
|
+
if res := self.relations.get(node):
|
|
576
|
+
return res
|
|
577
|
+
elif self.check_import(node) and (res := self.relations.get(node)):
|
|
578
|
+
return res
|
|
579
|
+
|
|
580
|
+
rel = None
|
|
581
|
+
if isinstance(node, Reading):
|
|
582
|
+
rel = self.to_relation(node._relationship)
|
|
583
|
+
elif isinstance(node, Relationship):
|
|
584
|
+
annos = tuple(self.to_annotation(anno) for anno in node._annotations)
|
|
585
|
+
readings = self.to_readings(node)
|
|
586
|
+
fields = [self.to_field(field) for field in node._fields]
|
|
587
|
+
if node._short_name == '':
|
|
588
|
+
name = self.global_namer.get_name(sub(r"[{}: ]", "_", str(node._readings[0]._reading)).strip("_"))
|
|
589
|
+
else:
|
|
590
|
+
name = node._short_name
|
|
591
|
+
overloads = []
|
|
592
|
+
if node._overloads:
|
|
593
|
+
for overload in node._overloads:
|
|
594
|
+
overload_types = tuple(self.to_type(concept) for concept in overload)
|
|
595
|
+
overloads.append(Overload(overload_types))
|
|
596
|
+
if node._is_unresolved:
|
|
597
|
+
rel = UnresolvedRelation(name=name, fields=tuple(fields), source=node._source, readings=readings, annotations=annos, overloads=tuple(overloads))
|
|
598
|
+
else:
|
|
599
|
+
rel = Relation(name=name, fields=tuple(fields), source=node._source, readings=readings, annotations=annos, overloads=tuple(overloads))
|
|
600
|
+
if isinstance(node, Property):
|
|
601
|
+
# Add a uniqueness constraint for properties
|
|
602
|
+
_get_constraints()
|
|
603
|
+
self.relation_constraints.add(Lookup(bt.constraints.unique_fields, (tuple(fields[:-1]),)))
|
|
604
|
+
elif isinstance(node, Data):
|
|
605
|
+
rel = mData(name=f"Data{node._id}", data=node._data, source=node._source)
|
|
606
|
+
self.relations[node] = rel
|
|
607
|
+
rel._force_columns(tuple(self.to_relation(col) for col in node._columns))
|
|
608
|
+
elif isinstance(node, Table):
|
|
609
|
+
rel = mTable(name=node._name, source=node._source)
|
|
610
|
+
self.relations[node] = rel
|
|
611
|
+
rel._force_columns(tuple(self.to_relation(col) for col in node._columns))
|
|
612
|
+
elif isinstance(node, NumberConcept):
|
|
613
|
+
super_types=tuple(self.to_type(ancestor) for ancestor in node._extends)
|
|
614
|
+
rel = NumberType(name=node._name, precision=node._precision, scale=node._scale, source=node._source, super_types=super_types)
|
|
615
|
+
elif isinstance(node, Concept):
|
|
616
|
+
annos = tuple(self.to_annotation(anno) for anno in node._annotations)
|
|
617
|
+
super_types=tuple(self.to_type(ancestor) for ancestor in node._extends)
|
|
618
|
+
rel = ScalarType(name=node._name, annotations=annos, source=node._source, super_types=super_types)
|
|
619
|
+
self.relations[node] = rel
|
|
620
|
+
identify_by_rels = tuple(self.to_relation(rel) for rel in node._identify_by)
|
|
621
|
+
rel._force_identify_by(identify_by_rels)
|
|
622
|
+
else:
|
|
623
|
+
raise ValueError(f"Unknown node type: {type(node)} - {node}")
|
|
624
|
+
self.relations[node] = rel
|
|
625
|
+
return rel
|
|
626
|
+
|
|
627
|
+
def to_type(self, node: Any) -> ScalarType:
|
|
628
|
+
rel = self.to_relation(node)
|
|
629
|
+
if not isinstance(rel, ScalarType):
|
|
630
|
+
raise ValueError(f"Node is not a ScalarType: {node}")
|
|
631
|
+
return rel
|
|
632
|
+
|
|
633
|
+
#------------------------------------------------------
|
|
634
|
+
# Compile
|
|
635
|
+
#------------------------------------------------------
|
|
636
|
+
|
|
637
|
+
def compile(self, fragment: Fragment) -> Task|list[Task]:
|
|
638
|
+
ctx = Context(self)
|
|
639
|
+
# pprint(fragment)
|
|
640
|
+
return self.fragment(ctx, fragment)
|
|
641
|
+
|
|
642
|
+
def compile_model(self, model: Model) -> mModel:
|
|
643
|
+
def as_seq(x):
|
|
644
|
+
return x if isinstance(x, (list, tuple)) else (x,)
|
|
645
|
+
|
|
646
|
+
# init enums
|
|
647
|
+
for enum in model.enums:
|
|
648
|
+
enum._init_members()
|
|
649
|
+
|
|
650
|
+
self.check_invariants(model)
|
|
651
|
+
|
|
652
|
+
for concept in model.concepts:
|
|
653
|
+
self.to_relation(concept)
|
|
654
|
+
for relationship in model.relationships:
|
|
655
|
+
self.to_relation(relationship)
|
|
656
|
+
for table in model.tables:
|
|
657
|
+
self.to_relation(table)
|
|
658
|
+
|
|
659
|
+
# compile + flatten defines/requires in one pass
|
|
660
|
+
compiled:list[Task] = []
|
|
661
|
+
compiled.extend(chain.from_iterable(
|
|
662
|
+
as_seq(self.compile(item)) for item in chain(model.defines, model.requires)
|
|
663
|
+
))
|
|
664
|
+
# partition relation values into types vs non-types
|
|
665
|
+
rel_vals = list(self.relations.values())
|
|
666
|
+
types = tuple(r for r in rel_vals if isinstance(r, TypeNode))
|
|
667
|
+
relations = tuple(r for r in rel_vals if not isinstance(r, TypeNode))
|
|
668
|
+
|
|
669
|
+
compiled.insert(0, Require(check=Logical(tuple(self.relation_constraints), source=model._source)))
|
|
670
|
+
|
|
671
|
+
source = model._source
|
|
672
|
+
root = Logical(tuple(compiled), source=source)
|
|
673
|
+
|
|
674
|
+
return mModel(
|
|
675
|
+
reasoners=(),
|
|
676
|
+
relations=relations,
|
|
677
|
+
types=types,
|
|
678
|
+
root=root,
|
|
679
|
+
source=source,
|
|
680
|
+
)
|
|
681
|
+
|
|
682
|
+
#------------------------------------------------------
|
|
683
|
+
# Invariants
|
|
684
|
+
#------------------------------------------------------
|
|
685
|
+
|
|
686
|
+
def check_invariants(self, model: Model):
|
|
687
|
+
# Ensure that all concepts with identify_by have at least one relationship
|
|
688
|
+
has_errors = False
|
|
689
|
+
for concept in model.concepts:
|
|
690
|
+
for k, v in concept._relationships.items():
|
|
691
|
+
for ext in concept._extends:
|
|
692
|
+
if k in ext._relationships:
|
|
693
|
+
kind = "Property" if isinstance(v, Property) else "Relationship"
|
|
694
|
+
parent_kind = "property" if isinstance(ext._relationships[k], Property) else "relationship"
|
|
695
|
+
err(f"{kind} conflict",
|
|
696
|
+
f"{kind} `{k}` in concept `{concept._name}` conflicts with {parent_kind} in parent concept `{ext._name}`.",
|
|
697
|
+
[
|
|
698
|
+
f"Parent {parent_kind}",
|
|
699
|
+
err_source(ext._relationships[k]),
|
|
700
|
+
f"Child {kind.lower()}",
|
|
701
|
+
err_source(v)
|
|
702
|
+
])
|
|
703
|
+
has_errors = True
|
|
704
|
+
|
|
705
|
+
if has_errors:
|
|
706
|
+
exc("Invalid model", "Model has invariant violations, see errors for details.")
|
|
707
|
+
|
|
708
|
+
#------------------------------------------------------
|
|
709
|
+
# Fragment
|
|
710
|
+
#------------------------------------------------------
|
|
711
|
+
|
|
712
|
+
def fragment(self, ctx: Context, fragment: Fragment):
|
|
713
|
+
if fragment._require:
|
|
714
|
+
return self.require(ctx, fragment, scope=True)
|
|
715
|
+
else:
|
|
716
|
+
annos = tuple(self.to_annotation(anno) for anno in fragment._annotations)
|
|
717
|
+
self.where(ctx, fragment, fragment._where)
|
|
718
|
+
self.select(ctx, fragment, fragment._select)
|
|
719
|
+
self.define(ctx, fragment, fragment._define)
|
|
720
|
+
return Logical(tuple(ctx.nodes), scope=True, annotations=annos, source=fragment._source)
|
|
721
|
+
|
|
722
|
+
#------------------------------------------------------
|
|
723
|
+
# Where
|
|
724
|
+
#------------------------------------------------------
|
|
725
|
+
|
|
726
|
+
def where(self, ctx: Context, fragment:Fragment, exprs: list[Value]):
|
|
727
|
+
for expr in exprs:
|
|
728
|
+
self.lookup(ctx, expr)
|
|
729
|
+
|
|
730
|
+
#------------------------------------------------------
|
|
731
|
+
# Select
|
|
732
|
+
#------------------------------------------------------
|
|
733
|
+
|
|
734
|
+
def select(self, ctx: Context, fragment:Fragment, exprs: Sequence[Value]):
|
|
735
|
+
if not exprs:
|
|
736
|
+
return
|
|
737
|
+
|
|
738
|
+
source = fragment._source
|
|
739
|
+
output_name = f"output{fragment._id}"
|
|
740
|
+
|
|
741
|
+
uri = f"dataframe://{output_name}" if fragment._into is None else f"table://{fragment._into._name}"
|
|
742
|
+
table = mTable(name=f"Output{fragment._id}", uri=uri, source=source)
|
|
743
|
+
table_var = Var(type=table, name=output_name, source=source)
|
|
744
|
+
|
|
745
|
+
keys:KeyedSet[Value] = KeyedSet(dsl_key)
|
|
746
|
+
items:list[Task] = []
|
|
747
|
+
|
|
748
|
+
# Unwrap distinct if present
|
|
749
|
+
is_distinct = any(isinstance(expr, Distinct) for expr in exprs)
|
|
750
|
+
if is_distinct:
|
|
751
|
+
if len(exprs) != 1 or not isinstance(exprs[0], Distinct):
|
|
752
|
+
return ctx.err("Invalid distinct", "Distinct must be applied to the entire select.", [
|
|
753
|
+
err_source(source)
|
|
754
|
+
])
|
|
755
|
+
exprs = exprs[0]._items
|
|
756
|
+
|
|
757
|
+
# Build out the table columns
|
|
758
|
+
# v0, v1, etc, for generic elements like literals or the unnamed result of union/matches
|
|
759
|
+
range_namer = Namer(range=True)
|
|
760
|
+
# v, v_2, v_3, etc, for elements where we want to preserve the original name if there
|
|
761
|
+
# are no collisions, like chain expressions, aggregates, etc
|
|
762
|
+
namer = Namer()
|
|
763
|
+
|
|
764
|
+
# we have to first find all the roots, the roots need to be looked up in the outer scope
|
|
765
|
+
# we then need to find the keys for each expr, any keys that aren't roots need to be added
|
|
766
|
+
# to the column relation
|
|
767
|
+
roots = KeyedSet(dsl_key)
|
|
768
|
+
for expr in exprs:
|
|
769
|
+
if is_distinct:
|
|
770
|
+
roots.add(expr)
|
|
771
|
+
else:
|
|
772
|
+
roots.update(find_keys(expr, root_only=True))
|
|
773
|
+
|
|
774
|
+
# look the roots up in the outer scope
|
|
775
|
+
root_vars:OrderedSet[mValue] = OrderedSet()
|
|
776
|
+
for root in roots:
|
|
777
|
+
root_v = self.lookup(ctx, root)
|
|
778
|
+
# For top-level relationships, the fields of the relationship are
|
|
779
|
+
# the root vars, since all of them behave like keys. For Properties,
|
|
780
|
+
# we ignore the last field since it's functionally determined by the others.
|
|
781
|
+
# Expressions use their args
|
|
782
|
+
if isinstance(root, Property):
|
|
783
|
+
root_vars.update(ctx.to_value(field) for field in root._fields[:-1])
|
|
784
|
+
elif isinstance(root, Relationship):
|
|
785
|
+
root_vars.update(ctx.to_value(field) for field in root._fields)
|
|
786
|
+
elif isinstance(root, Expression):
|
|
787
|
+
root_vars.update(ctx.to_value(arg) for arg in root._args)
|
|
788
|
+
else:
|
|
789
|
+
root_vars.add(root_v)
|
|
790
|
+
|
|
791
|
+
# handle order_by/limit
|
|
792
|
+
if fragment._order_by or fragment._limit != 0:
|
|
793
|
+
from ..std.aggregates import _sort_agg
|
|
794
|
+
args = fragment._order_by if fragment._order_by else fragment._select
|
|
795
|
+
sort_agg = _sort_agg(fragment._limit, *args)
|
|
796
|
+
self.lookup(ctx, sort_agg)
|
|
797
|
+
|
|
798
|
+
# build columns
|
|
799
|
+
table_cols = []
|
|
800
|
+
for expr in exprs:
|
|
801
|
+
expr_keys = [expr] if is_distinct else find_keys(expr)
|
|
802
|
+
|
|
803
|
+
with ctx.subcontext():
|
|
804
|
+
col = self.lookup(ctx, expr)
|
|
805
|
+
# Columns may need their own keys beyond the roots to guarantee that multiple values end up
|
|
806
|
+
# available for the same root. E.g. people having multiple pets
|
|
807
|
+
maybe_col_keys = [ctx.to_value(col_key) for col_key in expr_keys]
|
|
808
|
+
col_keys = [col_key for col_key in maybe_col_keys
|
|
809
|
+
if isinstance(col_key, Var) and col_key != col and col_key not in root_vars]
|
|
810
|
+
col_key_fields = [mField(name=key.name, type=key.type) for key in col_keys]
|
|
811
|
+
|
|
812
|
+
# build the relation
|
|
813
|
+
col_name = (expr._alias if isinstance(expr, Alias) else
|
|
814
|
+
range_namer.get_name(col.name) if isinstance(col, Var) and isinstance(expr, (Union, Match)) else
|
|
815
|
+
namer.get_name(self.to_relation(expr._op).name) if isinstance(expr, Aggregate) else
|
|
816
|
+
namer.get_name(col.name) if isinstance(col, Var) else
|
|
817
|
+
range_namer.get_name("v"))
|
|
818
|
+
col_type = mm_value_type(col)
|
|
819
|
+
col_relation = Relation(col_name, (
|
|
820
|
+
mField(name="table", type=table),
|
|
821
|
+
*col_key_fields,
|
|
822
|
+
mField(name=col_name, type=col_type)
|
|
823
|
+
), source=source)
|
|
824
|
+
table_cols.append(col_relation)
|
|
825
|
+
|
|
826
|
+
# The shim needs a hint that this output is both a key and a value
|
|
827
|
+
annos = ()
|
|
828
|
+
if col in maybe_col_keys and col not in root_vars:
|
|
829
|
+
annos = (Annotation(relation=bt.core["output_value_is_key"], args=(), source=source),)
|
|
830
|
+
ctx.add(Update(col_relation, args=tuple([table_var, *col_keys, col]), annotations=annos, source=source))
|
|
831
|
+
|
|
832
|
+
optional = True
|
|
833
|
+
# rank and limit should always just get pushed to the root - they can never be null
|
|
834
|
+
if isinstance(expr, Aggregate):
|
|
835
|
+
op = self.to_relation(expr._op)
|
|
836
|
+
optional = not (op is bt.aggregates.rank or op is bt.aggregates.limit)
|
|
837
|
+
|
|
838
|
+
node_tuple = tuple(ctx.nodes)
|
|
839
|
+
if len(ctx.nodes) == 1:
|
|
840
|
+
items.append(node_tuple[0])
|
|
841
|
+
else:
|
|
842
|
+
items.append(Logical(node_tuple, source=source, optional=optional))
|
|
843
|
+
|
|
844
|
+
# add the columns to the output table
|
|
845
|
+
table._force_columns(tuple(table_cols))
|
|
846
|
+
|
|
847
|
+
# Construct followed by adding the row to the table and then each column
|
|
848
|
+
ctx.add(Construct(tuple(root_vars), table_var, source=source))
|
|
849
|
+
ctx.add(Update(table, tuple([table_var]), source=source))
|
|
850
|
+
ctx.extend(items)
|
|
851
|
+
|
|
852
|
+
#------------------------------------------------------
|
|
853
|
+
# Define
|
|
854
|
+
#------------------------------------------------------
|
|
855
|
+
|
|
856
|
+
def define(self, ctx: Context, fragment:Fragment, exprs: list[Value]):
|
|
857
|
+
with ctx.updating():
|
|
858
|
+
for expr in exprs:
|
|
859
|
+
source = expr._source if isinstance(expr, DSLBase) else fragment._source
|
|
860
|
+
with ctx.subcontext():
|
|
861
|
+
self.update(ctx, expr, root_source=fragment._source)
|
|
862
|
+
nodes = tuple(ctx.nodes)
|
|
863
|
+
ctx.add(Logical(nodes, source=source, optional=True))
|
|
864
|
+
|
|
865
|
+
#------------------------------------------------------
|
|
866
|
+
# Require
|
|
867
|
+
#------------------------------------------------------
|
|
868
|
+
|
|
869
|
+
def require(self, ctx: Context, fragment:Fragment, scope:bool=False):
|
|
870
|
+
source = fragment._source
|
|
871
|
+
reqs = []
|
|
872
|
+
annos = tuple(self.to_annotation(anno) for anno in fragment._annotations)
|
|
873
|
+
with ctx.subcontext():
|
|
874
|
+
self.where(ctx, fragment, fragment._where)
|
|
875
|
+
domain_body = tuple(ctx.nodes)
|
|
876
|
+
domain_vars = ctx.frame_vars
|
|
877
|
+
for expr in fragment._require:
|
|
878
|
+
with ctx.subcontext():
|
|
879
|
+
self.lookup(ctx, expr)
|
|
880
|
+
check = Logical(tuple(ctx.nodes), source=source)
|
|
881
|
+
hoisted = tuple(v for v in ctx.frame_vars if v in domain_vars)
|
|
882
|
+
reqs.append(Require(Logical(domain_body, source=source), check, scope=scope, annotations=annos, source=source))
|
|
883
|
+
if len(reqs) == 1:
|
|
884
|
+
return reqs[0]
|
|
885
|
+
return reqs
|
|
886
|
+
|
|
887
|
+
#------------------------------------------------------
|
|
888
|
+
# Lookup
|
|
889
|
+
#------------------------------------------------------
|
|
890
|
+
|
|
891
|
+
# @memoize_in_ctx
|
|
892
|
+
def lookup(self, ctx: Context, node: Any) -> mValue:
|
|
893
|
+
source = node._source if not is_primitive(node) else None
|
|
894
|
+
self.check_import(node)
|
|
895
|
+
|
|
896
|
+
#------------------------------------------------------
|
|
897
|
+
# Concept / Concept expressions (includes Data and Table)
|
|
898
|
+
#------------------------------------------------------
|
|
899
|
+
|
|
900
|
+
if isinstance(node, Concept):
|
|
901
|
+
final_var = ctx.to_value(node)
|
|
902
|
+
if not is_core_concept(node):
|
|
903
|
+
ctx.add_lookup(node, [final_var], source=source)
|
|
904
|
+
return final_var
|
|
905
|
+
|
|
906
|
+
elif isinstance(node, Ref):
|
|
907
|
+
final_var = ctx.to_value(node)
|
|
908
|
+
if not is_core_concept(node._concept):
|
|
909
|
+
ctx.add_lookup(node._concept, [final_var], source=source)
|
|
910
|
+
return final_var
|
|
911
|
+
|
|
912
|
+
elif isinstance(node, New):
|
|
913
|
+
# If we encounter a New nested inside of an update, we want to treat this
|
|
914
|
+
# new as an update as well so that you can write Person.new(.., pet=Pet.new(..))
|
|
915
|
+
if ctx.in_update and not node._identity_only:
|
|
916
|
+
return self.update(ctx, node, root_source=node._source)
|
|
917
|
+
|
|
918
|
+
# Otherwise we're just checking this exists
|
|
919
|
+
return handle_concept_expression(self, ctx, node)
|
|
920
|
+
|
|
921
|
+
elif isinstance(node, FilterBy):
|
|
922
|
+
return handle_concept_expression(self, ctx, node)
|
|
923
|
+
|
|
924
|
+
#------------------------------------------------------
|
|
925
|
+
# Relationship
|
|
926
|
+
#------------------------------------------------------
|
|
927
|
+
|
|
928
|
+
elif isinstance(node, Relationship):
|
|
929
|
+
# we need vars for each field, but how do we store them?
|
|
930
|
+
args = [ctx.to_value(field) for field in node._fields]
|
|
931
|
+
ctx.add_lookup(node, args, source=source)
|
|
932
|
+
return args[-1]
|
|
933
|
+
|
|
934
|
+
elif isinstance(node, FieldRef):
|
|
935
|
+
self.lookup(ctx, node._root)
|
|
936
|
+
# If the source of the field ref is an expression, this is an ArgumentRef, so
|
|
937
|
+
# return the expression var directly
|
|
938
|
+
if isinstance(node._root, Expression):
|
|
939
|
+
return self.lookup(ctx, node._root._args[node._resolved_ix])
|
|
940
|
+
# If this is a reference to the relationship itself, then we want that to
|
|
941
|
+
# unify with any other references to the given field. If it's through a chain
|
|
942
|
+
# or expression, then it should be sourced from there.
|
|
943
|
+
field_source = node._root if not isinstance(node._root, Relationship) else None
|
|
944
|
+
return ctx.to_value(node._resolved, source=field_source)
|
|
945
|
+
|
|
946
|
+
#------------------------------------------------------
|
|
947
|
+
# Expressions
|
|
948
|
+
#------------------------------------------------------
|
|
949
|
+
|
|
950
|
+
elif isinstance(node, Expression):
|
|
951
|
+
# For auto-filled expressions, there's no reason to lookup the last ref and
|
|
952
|
+
# do a population check
|
|
953
|
+
if node._auto_filled:
|
|
954
|
+
args = [self.lookup(ctx, arg) for arg in node._args[:-1]] + [ctx.to_value(node._args[-1])]
|
|
955
|
+
ctx.add_lookup(node._op, args, source=source)
|
|
956
|
+
return args[-1]
|
|
957
|
+
# if we are casting e.g. with something like `Discount(0.6)` we should return a literal with that
|
|
958
|
+
# type
|
|
959
|
+
elif isinstance(node._op, Concept) and is_core_concept(node._op):
|
|
960
|
+
if isinstance(node._args[0], Literal):
|
|
961
|
+
return mLiteral(type=self.to_type(node._op), value=node._args[0]._value, source=source)
|
|
962
|
+
else:
|
|
963
|
+
cur = self.lookup(ctx, node._args[-1])
|
|
964
|
+
ret = ctx.to_value(node._op, source=node)
|
|
965
|
+
ctx.add_lookup(CoreRelationships["cast"], [self.to_type(node._op), cur, ret], source=source)
|
|
966
|
+
return ret
|
|
967
|
+
# Normal expression
|
|
968
|
+
else:
|
|
969
|
+
args = [self.lookup(ctx, a) for a in node._args]
|
|
970
|
+
ctx.add_lookup(node._op, args, source=source)
|
|
971
|
+
return args[-1]
|
|
972
|
+
|
|
973
|
+
elif isinstance(node, Chain):
|
|
974
|
+
start = self.lookup(ctx, node._start)
|
|
975
|
+
final_var = ctx.to_value(node)
|
|
976
|
+
# Unaries are special, the chain's var is just the start var
|
|
977
|
+
if len(node._next._fields) == 1:
|
|
978
|
+
ctx.add_lookup(node._next, [start], source=source)
|
|
979
|
+
return start
|
|
980
|
+
else:
|
|
981
|
+
# If the relation has more than 2 fields, we need to create vars for the
|
|
982
|
+
# unreferrenced ones in the middle
|
|
983
|
+
middle_args = [ctx.to_value(field, source=node) for field in node._next._fields[1:-1]]
|
|
984
|
+
args = [start, *middle_args, final_var]
|
|
985
|
+
ctx.add_lookup(node._next, args, source=source)
|
|
986
|
+
return final_var
|
|
987
|
+
|
|
988
|
+
#------------------------------------------------------
|
|
989
|
+
# Aggregates
|
|
990
|
+
#------------------------------------------------------
|
|
991
|
+
|
|
992
|
+
elif isinstance(node, Aggregate):
|
|
993
|
+
agg = self.to_relation(node._op)
|
|
994
|
+
input_args = [arg for ix, arg in enumerate(node._args) if agg.fields[ix].input]
|
|
995
|
+
|
|
996
|
+
proj_set:KeyedSet[Value] = KeyedSet(dsl_key)
|
|
997
|
+
if not node._distinct:
|
|
998
|
+
for item in [*node._projection_args, *input_args]:
|
|
999
|
+
proj_set.update(find_keys(item))
|
|
1000
|
+
proj_set.update(node._projection_args)
|
|
1001
|
+
proj = cast(OrderedSet[Var], OrderedSet([ctx.to_value(p) for p in proj_set]))
|
|
1002
|
+
group = cast(list[Var], [self.lookup(ctx, arg) for arg in node._group._args])
|
|
1003
|
+
|
|
1004
|
+
if agg is bt.aggregates.rank:
|
|
1005
|
+
assert isinstance(node._args[0], TupleVariable)
|
|
1006
|
+
for arg in node._args[0]._items:
|
|
1007
|
+
self.lookup(ctx, arg)
|
|
1008
|
+
elif agg is bt.aggregates.limit:
|
|
1009
|
+
assert isinstance(node._args[1], TupleVariable)
|
|
1010
|
+
for arg in node._args[1]._items:
|
|
1011
|
+
self.lookup(ctx, arg)
|
|
1012
|
+
|
|
1013
|
+
with ctx.subcontext():
|
|
1014
|
+
for item in node._where._where:
|
|
1015
|
+
self.lookup(ctx, item)
|
|
1016
|
+
for projected in proj_set:
|
|
1017
|
+
self.lookup(ctx, projected)
|
|
1018
|
+
args = cast(list[Var], [self.lookup(ctx, arg) for arg in node._args])
|
|
1019
|
+
where = Logical(tuple(ctx.nodes), source=source)
|
|
1020
|
+
|
|
1021
|
+
ctx.add(mAggregate(agg, tuple(proj), tuple(group), tuple(args), where, source=source))
|
|
1022
|
+
return args[-1] if not isinstance(args[-1], tuple) else None
|
|
1023
|
+
|
|
1024
|
+
elif isinstance(node, Group):
|
|
1025
|
+
for arg in node._args:
|
|
1026
|
+
self.lookup(ctx, arg)
|
|
1027
|
+
return
|
|
1028
|
+
|
|
1029
|
+
#------------------------------------------------------
|
|
1030
|
+
# Quantifiers
|
|
1031
|
+
#------------------------------------------------------
|
|
1032
|
+
|
|
1033
|
+
elif isinstance(node, Not):
|
|
1034
|
+
with ctx.subcontext():
|
|
1035
|
+
for item in node._items:
|
|
1036
|
+
self.lookup(ctx, item)
|
|
1037
|
+
not_ = mNot(Logical(tuple(ctx.nodes)), source=source)
|
|
1038
|
+
ctx.add(not_)
|
|
1039
|
+
return
|
|
1040
|
+
|
|
1041
|
+
#------------------------------------------------------
|
|
1042
|
+
# Nested fragment
|
|
1043
|
+
#------------------------------------------------------
|
|
1044
|
+
|
|
1045
|
+
elif isinstance(node, Fragment):
|
|
1046
|
+
if node._require or node._define:
|
|
1047
|
+
ctx.err("Invalid subquery", "Nested queries with `require` or `define` are not supported.", [
|
|
1048
|
+
err_source(source)
|
|
1049
|
+
])
|
|
1050
|
+
if node._select:
|
|
1051
|
+
with ctx.subcontext():
|
|
1052
|
+
for where in node._where:
|
|
1053
|
+
self.lookup(ctx, where)
|
|
1054
|
+
# cols = cast(ISeq[Var], tuple(ctx.to_value(col) for col in node._columns))
|
|
1055
|
+
vals = [self.lookup(ctx, sel) for sel in node._select]
|
|
1056
|
+
ctx.value_map.update(zip(node._columns, vals))
|
|
1057
|
+
# for col, val in zip(cols, vals):
|
|
1058
|
+
# ctx.add_eq(col, val, source=source)
|
|
1059
|
+
nodes = tuple(ctx.nodes)
|
|
1060
|
+
ctx.add(Logical(nodes, source=source))
|
|
1061
|
+
return vals[-1]
|
|
1062
|
+
else:
|
|
1063
|
+
for where in node._where:
|
|
1064
|
+
self.lookup(ctx, where)
|
|
1065
|
+
return None
|
|
1066
|
+
|
|
1067
|
+
#------------------------------------------------------
|
|
1068
|
+
# Match / Union
|
|
1069
|
+
#------------------------------------------------------
|
|
1070
|
+
|
|
1071
|
+
elif isinstance(node, (Match, Union)):
|
|
1072
|
+
branches = []
|
|
1073
|
+
outputs = cast(ISeq[Var], tuple(ctx.to_value(col) for col in node._columns) if node._arg_count() > 0 else tuple())
|
|
1074
|
+
branch_keys = get_branch_keys(self, ctx, node)
|
|
1075
|
+
for item in node._items:
|
|
1076
|
+
item_source = item._source if isinstance(item, Variable) else source
|
|
1077
|
+
if isinstance(item, Fragment):
|
|
1078
|
+
if item._select:
|
|
1079
|
+
# map the select columns to the match/union outputs
|
|
1080
|
+
for ix, col in enumerate(item._columns):
|
|
1081
|
+
ctx.value_map[col] = outputs[ix]
|
|
1082
|
+
with ctx.subcontext():
|
|
1083
|
+
self.lookup(ctx, item)
|
|
1084
|
+
# unwrap the nested logical
|
|
1085
|
+
wrapper = ctx.nodes[0]
|
|
1086
|
+
assert isinstance(wrapper, Logical)
|
|
1087
|
+
for subnode in wrapper.body:
|
|
1088
|
+
ctx.add(subnode)
|
|
1089
|
+
|
|
1090
|
+
normalize_branch_keys(self, ctx, branch_keys, item)
|
|
1091
|
+
# add the output column equalities
|
|
1092
|
+
for ix, col in enumerate(item._columns):
|
|
1093
|
+
ctx.add_eq(outputs[ix], ctx.to_value(col), source=item_source)
|
|
1094
|
+
branches.append(Logical(tuple(ctx.nodes)[1:], source=item_source))
|
|
1095
|
+
else:
|
|
1096
|
+
with ctx.subcontext():
|
|
1097
|
+
for where in item._where:
|
|
1098
|
+
self.lookup(ctx, where)
|
|
1099
|
+
branches.append(Logical(tuple(ctx.nodes), source=item_source))
|
|
1100
|
+
else:
|
|
1101
|
+
with ctx.subcontext():
|
|
1102
|
+
res = self.lookup(ctx, item)
|
|
1103
|
+
normalize_branch_keys(self, ctx, branch_keys, item)
|
|
1104
|
+
if outputs:
|
|
1105
|
+
ctx.add_eq(outputs[0], res, source=item_source)
|
|
1106
|
+
branches.append(Logical(tuple(ctx.nodes), source=item_source))
|
|
1107
|
+
|
|
1108
|
+
if isinstance(node, Union):
|
|
1109
|
+
ctx.add(mUnion(tuple(branches), source=source))
|
|
1110
|
+
else:
|
|
1111
|
+
ctx.add(mMatch(tuple(branches), source=source))
|
|
1112
|
+
|
|
1113
|
+
return outputs[-1] if outputs else None
|
|
1114
|
+
|
|
1115
|
+
#------------------------------------------------------
|
|
1116
|
+
# Value-likes
|
|
1117
|
+
#------------------------------------------------------
|
|
1118
|
+
|
|
1119
|
+
elif isinstance(node, (Field, MetaRef)):
|
|
1120
|
+
return ctx.to_value(node)
|
|
1121
|
+
|
|
1122
|
+
elif isinstance(node, TupleVariable):
|
|
1123
|
+
# exc("TupleVariable unsupported", "TupleVariable is not supported yet.", [err_source(source)])
|
|
1124
|
+
items = [self.lookup(ctx, item) for item in node._items]
|
|
1125
|
+
return tuple(items)
|
|
1126
|
+
|
|
1127
|
+
elif isinstance(node, TableSchema):
|
|
1128
|
+
exc("Invalid value", "A schema cannot be used as a value outside of a `.new(..)` or `.select(..)` call.", [err_source(source)])
|
|
1129
|
+
return None
|
|
1130
|
+
|
|
1131
|
+
elif is_primitive(node):
|
|
1132
|
+
type_ = self.to_type(Literal._get_type(node))
|
|
1133
|
+
return mLiteral(type_, node)
|
|
1134
|
+
|
|
1135
|
+
elif isinstance(node, DerivedColumn):
|
|
1136
|
+
self.lookup(ctx, node._table)
|
|
1137
|
+
return ctx.to_value(node)
|
|
1138
|
+
|
|
1139
|
+
elif isinstance(node, Literal):
|
|
1140
|
+
return mLiteral(type=self.to_type(node._type), value=node._value, source=source)
|
|
1141
|
+
|
|
1142
|
+
elif isinstance(node, ModelEnum):
|
|
1143
|
+
return self.lookup(ctx, node._compile_lookup())
|
|
1144
|
+
|
|
1145
|
+
elif isinstance(node, Alias):
|
|
1146
|
+
return self.lookup(ctx, node._source)
|
|
1147
|
+
|
|
1148
|
+
elif isinstance(node, AsBool):
|
|
1149
|
+
# we need to create a match with two branches that returns true/false
|
|
1150
|
+
out = ctx.to_value(node)
|
|
1151
|
+
assert isinstance(out, Var)
|
|
1152
|
+
with ctx.subcontext():
|
|
1153
|
+
self.lookup(ctx, node._item)
|
|
1154
|
+
ctx.add_eq(out, mLiteral(bt.core.Boolean, True), source=node._source)
|
|
1155
|
+
true_branch = Logical(tuple(ctx.nodes), source=source)
|
|
1156
|
+
with ctx.subcontext():
|
|
1157
|
+
ctx.add_eq(out, mLiteral(bt.core.Boolean, False), source=node._source)
|
|
1158
|
+
false_branch = Logical(tuple(ctx.nodes), source=source)
|
|
1159
|
+
ctx.add(mMatch((true_branch, false_branch), source=source))
|
|
1160
|
+
return out
|
|
1161
|
+
|
|
1162
|
+
#------------------------------------------------------
|
|
1163
|
+
# Invalid nodes
|
|
1164
|
+
#------------------------------------------------------
|
|
1165
|
+
|
|
1166
|
+
elif isinstance(node, Distinct):
|
|
1167
|
+
ctx.err("Invalid distinct", "Distinct can only be used in `select(distinct(..))` or aggregates like `count(distinct(..))`.", [
|
|
1168
|
+
err_source(source)
|
|
1169
|
+
])
|
|
1170
|
+
return None
|
|
1171
|
+
|
|
1172
|
+
else:
|
|
1173
|
+
raise NotImplementedError(f"Lookup not implemented for node type: {type(node)}")
|
|
1174
|
+
|
|
1175
|
+
#------------------------------------------------------
|
|
1176
|
+
# Update
|
|
1177
|
+
#------------------------------------------------------
|
|
1178
|
+
|
|
1179
|
+
def update(self, ctx: Context, node: Any, root_source:SourcePos) -> mValue:
|
|
1180
|
+
source = node._source if not is_primitive(node) else root_source
|
|
1181
|
+
self.check_import(node)
|
|
1182
|
+
|
|
1183
|
+
#------------------------------------------------------
|
|
1184
|
+
# Concept / Concept expressions (includes Data and Table)
|
|
1185
|
+
#------------------------------------------------------
|
|
1186
|
+
|
|
1187
|
+
if isinstance(node, Concept):
|
|
1188
|
+
final_var = ctx.to_value(node)
|
|
1189
|
+
ctx.add_update(node, [final_var], source=source)
|
|
1190
|
+
return final_var
|
|
1191
|
+
|
|
1192
|
+
elif isinstance(node, New):
|
|
1193
|
+
if node._identity_only:
|
|
1194
|
+
ctx.err("Invalid define", "Cannot define just an identity.", [
|
|
1195
|
+
err_source(source),
|
|
1196
|
+
"Did you mean to use `.new(..)`?"
|
|
1197
|
+
])
|
|
1198
|
+
return
|
|
1199
|
+
return handle_concept_expression(self, ctx, node)
|
|
1200
|
+
|
|
1201
|
+
#------------------------------------------------------
|
|
1202
|
+
# Relationship
|
|
1203
|
+
#------------------------------------------------------
|
|
1204
|
+
|
|
1205
|
+
elif isinstance(node, Relationship):
|
|
1206
|
+
ctx.err("Invalid define", "Cannot define a relationship without values for its fields.", [
|
|
1207
|
+
err_source(root_source),
|
|
1208
|
+
])
|
|
1209
|
+
|
|
1210
|
+
#------------------------------------------------------
|
|
1211
|
+
# Expressions
|
|
1212
|
+
#------------------------------------------------------
|
|
1213
|
+
|
|
1214
|
+
elif isinstance(node, Expression):
|
|
1215
|
+
if node._auto_filled or len(node._args) == 0:
|
|
1216
|
+
field_name = node._op._fields[-1].name if isinstance(node._op, Relationship) else node._op._name.lower()
|
|
1217
|
+
ctx.err("Invalid define", f"Define requires that all args be provided, but the value for the `{field_name}` field is missing.", [
|
|
1218
|
+
err_source(source),
|
|
1219
|
+
])
|
|
1220
|
+
return
|
|
1221
|
+
args = [self.lookup(ctx, arg) for arg in node._args]
|
|
1222
|
+
if node._op is CoreRelationships["="]:
|
|
1223
|
+
if isinstance(node._args[0], (Relationship, Chain)):
|
|
1224
|
+
return self.update(ctx, node._args[0](node._args[1]), root_source=source)
|
|
1225
|
+
elif isinstance(node._args[1], (Relationship, Chain)):
|
|
1226
|
+
return self.update(ctx, node._args[1](node._args[0]), root_source=source)
|
|
1227
|
+
else:
|
|
1228
|
+
ctx.err("Invalid define", "Cannot set a non-relationship via `=` in a define.", [
|
|
1229
|
+
err_source(source),
|
|
1230
|
+
])
|
|
1231
|
+
else:
|
|
1232
|
+
if isinstance(node._op, Concept) and is_core_concept(node._op):
|
|
1233
|
+
return self.lookup(ctx, node)
|
|
1234
|
+
ctx.add_update(node._op, args, source=source)
|
|
1235
|
+
return args[-1]
|
|
1236
|
+
|
|
1237
|
+
elif isinstance(node, Chain):
|
|
1238
|
+
# all fields have to be specified for a define, so a chain only works
|
|
1239
|
+
# if the relationship is unary
|
|
1240
|
+
if len(node._next._fields) > 1:
|
|
1241
|
+
ctx.err("Invalid define", "All fields must have a value when defining a relationship.", [
|
|
1242
|
+
err_source(source),
|
|
1243
|
+
f"You need something like [cyan]`.{node._next._short_name}(" + ", ".join([field.name for field in node._next._fields[1:]]) + ")`"
|
|
1244
|
+
])
|
|
1245
|
+
return
|
|
1246
|
+
|
|
1247
|
+
start = self.lookup(ctx, node._start)
|
|
1248
|
+
ctx.add_update(node._next, [start], source=source)
|
|
1249
|
+
return start
|
|
1250
|
+
|
|
1251
|
+
#------------------------------------------------------
|
|
1252
|
+
# Invalids
|
|
1253
|
+
#------------------------------------------------------
|
|
1254
|
+
|
|
1255
|
+
elif is_primitive(node):
|
|
1256
|
+
ctx.err("Invalid define", "Cannot define a primitive value.", [
|
|
1257
|
+
err_source(source)
|
|
1258
|
+
])
|
|
1259
|
+
return
|
|
1260
|
+
|
|
1261
|
+
elif isinstance(node, (FilterBy, Ref, FieldRef, Aggregate, Group, Not, Fragment, Match, Field, DerivedColumn, Literal, Alias, Distinct)):
|
|
1262
|
+
ctx.err("Invalid define", f"Cannot define a value of type `{type(node).__name__}`.", [
|
|
1263
|
+
err_source(node._source)
|
|
1264
|
+
])
|
|
1265
|
+
return
|
|
1266
|
+
|
|
1267
|
+
else:
|
|
1268
|
+
raise NotImplementedError(f"Lookup not implemented for node type: {type(node)}")
|
|
1269
|
+
|
|
1270
|
+
|
|
1271
|
+
|
|
1272
|
+
#------------------------------------------------------
|
|
1273
|
+
# TODO
|
|
1274
|
+
#------------------------------------------------------
|
|
1275
|
+
"""
|
|
1276
|
+
- vars shared between columns need to end up as column keys
|
|
1277
|
+
- check sub-selects now that we went back to optional logicals
|
|
1278
|
+
- roots for union/matches/fragments
|
|
1279
|
+
- ref scheme mappings
|
|
1280
|
+
- what do we want to do about Error/require errors?
|
|
1281
|
+
- None columns in selects
|
|
1282
|
+
|
|
1283
|
+
x Concept
|
|
1284
|
+
x DerivedColumn
|
|
1285
|
+
x Field
|
|
1286
|
+
x Relationship
|
|
1287
|
+
x Reading
|
|
1288
|
+
x Property
|
|
1289
|
+
x Literal
|
|
1290
|
+
x Chain
|
|
1291
|
+
x Expression
|
|
1292
|
+
x FieldRef
|
|
1293
|
+
x Alias
|
|
1294
|
+
x Match / Union
|
|
1295
|
+
x Not
|
|
1296
|
+
x Distinct
|
|
1297
|
+
x nested Fragments
|
|
1298
|
+
x New
|
|
1299
|
+
x Concept expression with kwargs
|
|
1300
|
+
x select
|
|
1301
|
+
x where
|
|
1302
|
+
x Data
|
|
1303
|
+
x Table
|
|
1304
|
+
x Group
|
|
1305
|
+
x Aggregate
|
|
1306
|
+
x defining an expression allows you to have one fewer var than you should
|
|
1307
|
+
x define
|
|
1308
|
+
x require
|
|
1309
|
+
x distinct for aggregates
|
|
1310
|
+
x don't do pop checks on primitives
|
|
1311
|
+
x handle library imports
|
|
1312
|
+
x nested news
|
|
1313
|
+
x bool handling (as_bool, select(x > y))
|
|
1314
|
+
x generate constraints for Property?
|
|
1315
|
+
x wrong arg count in an update isn't providing an error
|
|
1316
|
+
"""
|