relationalai 1.0.0a3__py3-none-any.whl → 1.0.0a5__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/config/config.py +47 -21
- relationalai/config/connections/__init__.py +5 -2
- relationalai/config/connections/duckdb.py +2 -2
- relationalai/config/connections/local.py +31 -0
- relationalai/config/connections/snowflake.py +0 -1
- relationalai/config/external/raiconfig_converter.py +235 -0
- relationalai/config/external/raiconfig_models.py +202 -0
- relationalai/config/external/utils.py +31 -0
- relationalai/config/shims.py +1 -0
- relationalai/semantics/__init__.py +10 -8
- relationalai/semantics/backends/sql/sql_compiler.py +1 -4
- relationalai/semantics/experimental/__init__.py +0 -0
- relationalai/semantics/experimental/builder.py +295 -0
- relationalai/semantics/experimental/builtins.py +154 -0
- relationalai/semantics/frontend/base.py +67 -42
- relationalai/semantics/frontend/core.py +34 -6
- relationalai/semantics/frontend/front_compiler.py +209 -37
- relationalai/semantics/frontend/pprint.py +6 -2
- relationalai/semantics/metamodel/__init__.py +7 -0
- relationalai/semantics/metamodel/metamodel.py +2 -0
- relationalai/semantics/metamodel/metamodel_analyzer.py +58 -16
- relationalai/semantics/metamodel/pprint.py +6 -1
- relationalai/semantics/metamodel/rewriter.py +11 -7
- relationalai/semantics/metamodel/typer.py +116 -41
- relationalai/semantics/reasoners/__init__.py +11 -0
- relationalai/semantics/reasoners/graph/__init__.py +35 -0
- relationalai/semantics/reasoners/graph/core.py +9028 -0
- relationalai/semantics/std/__init__.py +30 -10
- relationalai/semantics/std/aggregates.py +641 -12
- relationalai/semantics/std/common.py +146 -13
- relationalai/semantics/std/constraints.py +71 -1
- relationalai/semantics/std/datetime.py +904 -21
- relationalai/semantics/std/decimals.py +143 -2
- relationalai/semantics/std/floats.py +57 -4
- relationalai/semantics/std/integers.py +98 -4
- relationalai/semantics/std/math.py +857 -35
- relationalai/semantics/std/numbers.py +216 -20
- relationalai/semantics/std/re.py +213 -5
- relationalai/semantics/std/strings.py +437 -44
- relationalai/shims/executor.py +60 -52
- relationalai/shims/fixtures.py +85 -0
- relationalai/shims/helpers.py +26 -2
- relationalai/shims/hoister.py +28 -9
- relationalai/shims/mm2v0.py +204 -173
- relationalai/tools/cli/cli.py +192 -10
- relationalai/tools/cli/components/progress_reader.py +1 -1
- relationalai/tools/cli/docs.py +394 -0
- relationalai/tools/debugger.py +11 -4
- relationalai/tools/qb_debugger.py +435 -0
- relationalai/tools/typer_debugger.py +1 -2
- relationalai/util/dataclasses.py +3 -5
- relationalai/util/docutils.py +1 -2
- relationalai/util/error.py +2 -5
- relationalai/util/python.py +23 -0
- relationalai/util/runtime.py +1 -2
- relationalai/util/schema.py +2 -4
- relationalai/util/structures.py +4 -2
- relationalai/util/tracing.py +8 -2
- {relationalai-1.0.0a3.dist-info → relationalai-1.0.0a5.dist-info}/METADATA +8 -5
- {relationalai-1.0.0a3.dist-info → relationalai-1.0.0a5.dist-info}/RECORD +118 -95
- {relationalai-1.0.0a3.dist-info → relationalai-1.0.0a5.dist-info}/WHEEL +1 -1
- v0/relationalai/__init__.py +1 -1
- v0/relationalai/clients/client.py +52 -18
- v0/relationalai/clients/exec_txn_poller.py +122 -0
- v0/relationalai/clients/local.py +23 -8
- v0/relationalai/clients/resources/azure/azure.py +36 -11
- v0/relationalai/clients/resources/snowflake/__init__.py +4 -4
- v0/relationalai/clients/resources/snowflake/cli_resources.py +12 -1
- v0/relationalai/clients/resources/snowflake/direct_access_resources.py +124 -100
- v0/relationalai/clients/resources/snowflake/engine_service.py +381 -0
- v0/relationalai/clients/resources/snowflake/engine_state_handlers.py +35 -29
- v0/relationalai/clients/resources/snowflake/error_handlers.py +43 -2
- v0/relationalai/clients/resources/snowflake/snowflake.py +277 -179
- v0/relationalai/clients/resources/snowflake/use_index_poller.py +8 -0
- v0/relationalai/clients/types.py +5 -0
- v0/relationalai/errors.py +19 -1
- v0/relationalai/semantics/lqp/algorithms.py +173 -0
- v0/relationalai/semantics/lqp/builtins.py +199 -2
- v0/relationalai/semantics/lqp/executor.py +68 -37
- v0/relationalai/semantics/lqp/ir.py +28 -2
- v0/relationalai/semantics/lqp/model2lqp.py +215 -45
- v0/relationalai/semantics/lqp/passes.py +13 -658
- v0/relationalai/semantics/lqp/rewrite/__init__.py +12 -0
- v0/relationalai/semantics/lqp/rewrite/algorithm.py +385 -0
- v0/relationalai/semantics/lqp/rewrite/constants_to_vars.py +70 -0
- v0/relationalai/semantics/lqp/rewrite/deduplicate_vars.py +104 -0
- v0/relationalai/semantics/lqp/rewrite/eliminate_data.py +108 -0
- v0/relationalai/semantics/lqp/rewrite/extract_keys.py +25 -3
- v0/relationalai/semantics/lqp/rewrite/period_math.py +77 -0
- v0/relationalai/semantics/lqp/rewrite/quantify_vars.py +65 -31
- v0/relationalai/semantics/lqp/rewrite/unify_definitions.py +317 -0
- v0/relationalai/semantics/lqp/utils.py +11 -1
- v0/relationalai/semantics/lqp/validators.py +14 -1
- v0/relationalai/semantics/metamodel/builtins.py +2 -1
- v0/relationalai/semantics/metamodel/compiler.py +2 -1
- v0/relationalai/semantics/metamodel/dependency.py +12 -3
- v0/relationalai/semantics/metamodel/executor.py +11 -1
- v0/relationalai/semantics/metamodel/factory.py +2 -2
- v0/relationalai/semantics/metamodel/helpers.py +7 -0
- v0/relationalai/semantics/metamodel/ir.py +3 -2
- v0/relationalai/semantics/metamodel/rewrite/dnf_union_splitter.py +30 -20
- v0/relationalai/semantics/metamodel/rewrite/flatten.py +50 -13
- v0/relationalai/semantics/metamodel/rewrite/format_outputs.py +9 -3
- v0/relationalai/semantics/metamodel/typer/checker.py +6 -4
- v0/relationalai/semantics/metamodel/typer/typer.py +4 -3
- v0/relationalai/semantics/metamodel/visitor.py +4 -3
- v0/relationalai/semantics/reasoners/optimization/solvers_dev.py +1 -1
- v0/relationalai/semantics/reasoners/optimization/solvers_pb.py +336 -86
- v0/relationalai/semantics/rel/compiler.py +2 -1
- v0/relationalai/semantics/rel/executor.py +3 -2
- v0/relationalai/semantics/tests/lqp/__init__.py +0 -0
- v0/relationalai/semantics/tests/lqp/algorithms.py +345 -0
- v0/relationalai/tools/cli.py +339 -186
- v0/relationalai/tools/cli_controls.py +216 -67
- v0/relationalai/tools/cli_helpers.py +410 -6
- v0/relationalai/util/format.py +5 -2
- {relationalai-1.0.0a3.dist-info → relationalai-1.0.0a5.dist-info}/entry_points.txt +0 -0
- {relationalai-1.0.0a3.dist-info → relationalai-1.0.0a5.dist-info}/top_level.txt +0 -0
relationalai/shims/mm2v0.py
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from collections import defaultdict
|
|
4
|
-
from dataclasses import dataclass, field
|
|
5
|
-
from typing import Dict, Sequence as seq
|
|
4
|
+
from dataclasses import dataclass, field
|
|
5
|
+
from typing import Dict, Sequence as seq
|
|
6
6
|
from enum import Enum
|
|
7
7
|
from math import pi
|
|
8
|
+
from urllib.parse import urlparse
|
|
8
9
|
|
|
9
10
|
# PyRel imports
|
|
10
11
|
from ..util.naming import sanitize
|
|
@@ -12,13 +13,9 @@ from ..semantics.metamodel import metamodel as mm
|
|
|
12
13
|
from ..semantics.metamodel.builtins import builtins as b, is_abstract
|
|
13
14
|
from ..semantics.metamodel.metamodel_analyzer import Normalize
|
|
14
15
|
# ensure std libs are loaded
|
|
15
|
-
from ..semantics.metamodel.metamodel_analyzer import VarFinder
|
|
16
|
-
from ..semantics.metamodel.rewriter import Walker
|
|
17
|
-
from ..semantics.std import aggregates, common, math, numbers, re, strings, decimals, datetime, floats
|
|
18
|
-
from ..semantics.backends.lqp import annotations as lqp_annotations
|
|
19
16
|
|
|
20
17
|
# V0 imports
|
|
21
|
-
from v0.relationalai.semantics.metamodel import ir as v0, builtins as v0_builtins, types as v0_types
|
|
18
|
+
from v0.relationalai.semantics.metamodel import ir as v0, builtins as v0_builtins, types as v0_types
|
|
22
19
|
from v0.relationalai.semantics.metamodel.util import FrozenOrderedSet, frozen, ordered_set, filter_by_type, OrderedSet
|
|
23
20
|
from v0.relationalai.semantics.internal.internal import literal_value_to_type
|
|
24
21
|
from v0.relationalai.semantics.metamodel.typer import typer as v0_typer
|
|
@@ -73,7 +70,10 @@ class Translator():
|
|
|
73
70
|
maintenance_rules: list[v0.Logical] = field(default_factory=list)
|
|
74
71
|
|
|
75
72
|
# outputs that are exports
|
|
76
|
-
exports:
|
|
73
|
+
exports: dict[v0.Output, mm.Table] = field(default_factory=dict)
|
|
74
|
+
|
|
75
|
+
# output column order
|
|
76
|
+
output_column_order: Dict[v0.Output, int] = field(default_factory=dict)
|
|
77
77
|
|
|
78
78
|
hoister = Hoister()
|
|
79
79
|
normalize = Normalize()
|
|
@@ -141,7 +141,7 @@ class Translator():
|
|
|
141
141
|
# produces. If there's a quote in the table name, then we take it verbatim, otherwise we lowercase it.
|
|
142
142
|
def translate_table_name(self, table: mm.Table) -> str:
|
|
143
143
|
name = IdentityParser(table.name).identifier
|
|
144
|
-
name = name.lower() if '"' not in table.name else table.name.replace('"', '_')
|
|
144
|
+
name = name.lower() if '"' not in table.name else table.name.replace('"', '_').replace("-", "_")
|
|
145
145
|
return sanitize(name)
|
|
146
146
|
|
|
147
147
|
#-----------------------------------------------------------------------------
|
|
@@ -194,9 +194,9 @@ class Translator():
|
|
|
194
194
|
def translate_overload(self, o: mm.Overload, parent: mm.Relation, ctx) -> v0.Relation:
|
|
195
195
|
# Overloads in v0 are represented as separate Relation nodes with different types
|
|
196
196
|
fields = []
|
|
197
|
-
for
|
|
197
|
+
for fld, typ in zip(parent.fields, o.types):
|
|
198
198
|
fields.append(
|
|
199
|
-
v0.Field(name=
|
|
199
|
+
v0.Field(name=fld.name, type=self.translate_node(typ, fld, ctx), input=fld.input) # type: ignore
|
|
200
200
|
)
|
|
201
201
|
return v0.Relation(
|
|
202
202
|
name=parent.name,
|
|
@@ -217,7 +217,9 @@ class Translator():
|
|
|
217
217
|
"like": "like_match",
|
|
218
218
|
"regex_escape": "escape_regex_metachars",
|
|
219
219
|
}
|
|
220
|
-
for lib in ["core", "aggregates", "common", "datetime", "floats", "math", "numbers", "strings", "re", "lqp"]:
|
|
220
|
+
for lib in ["core", "aggregates", "constraints", "common", "datetime", "floats", "graph", "math", "numbers", "strings", "re", "lqp"]:
|
|
221
|
+
if lib not in b._libraries:
|
|
222
|
+
continue
|
|
221
223
|
for x in b._libraries[lib].data.values():
|
|
222
224
|
v0_name = RENAMES.get(x.name, x.name)
|
|
223
225
|
if v0_name in v0_builtins.builtin_relations_by_name:
|
|
@@ -320,7 +322,13 @@ class Translator():
|
|
|
320
322
|
|
|
321
323
|
def translate_annotation(self, a: mm.Annotation, parent, ctx) -> v0.Annotation:
|
|
322
324
|
if a.relation.name in v0_builtins.builtin_annotations_by_name:
|
|
323
|
-
|
|
325
|
+
if not a.args:
|
|
326
|
+
return getattr(v0_builtins, a.relation.name + "_annotation") # type: ignore
|
|
327
|
+
else:
|
|
328
|
+
return v0.Annotation(
|
|
329
|
+
relation=getattr(v0_builtins, a.relation.name), # type: ignore
|
|
330
|
+
args=tuple(self.translate_value(arg, a, ctx) for arg in a.args)
|
|
331
|
+
)
|
|
324
332
|
|
|
325
333
|
return v0.Annotation(
|
|
326
334
|
relation=self.translate_node(a.relation, a, Context.MODEL), # type: ignore
|
|
@@ -335,7 +343,7 @@ class Translator():
|
|
|
335
343
|
# Abstract types (should be removed once our typer is done because they should not
|
|
336
344
|
# show up in the typed metamodel.)
|
|
337
345
|
b.core.Any: v0_types.Any,
|
|
338
|
-
|
|
346
|
+
b.core.AnyEntity: v0_types.AnyEntity,
|
|
339
347
|
b.core.Number: v0_types.Number, # v0 typer can figure the rest out
|
|
340
348
|
# Concrete types
|
|
341
349
|
b.core.Boolean: v0_types.Bool,
|
|
@@ -362,6 +370,7 @@ class Translator():
|
|
|
362
370
|
annotations.append(v0_builtins.external_annotation)
|
|
363
371
|
name = self.translate_table_name(t)
|
|
364
372
|
fields.insert(0, v0.Field(name="symbol", type=v0_types.Symbol, input=False)) # type: ignore
|
|
373
|
+
annotations.extend(self.translate_seq(t.annotations, t, ctx)) # type: ignore
|
|
365
374
|
|
|
366
375
|
type_relation = v0.Relation(
|
|
367
376
|
name=name,
|
|
@@ -372,9 +381,8 @@ class Translator():
|
|
|
372
381
|
)
|
|
373
382
|
for super_type in t.super_types:
|
|
374
383
|
super_rel = self.translate_node(super_type, t, Context.TASK)
|
|
375
|
-
if not super_rel:
|
|
384
|
+
if not isinstance(super_rel, v0.Relation):
|
|
376
385
|
continue
|
|
377
|
-
assert isinstance(super_rel, v0.Relation)
|
|
378
386
|
v = v0.Var(type=actual_type, name=type_relation.name.lower())
|
|
379
387
|
self.maintenance_rules.append(v0.Logical(
|
|
380
388
|
engine=None,
|
|
@@ -456,15 +464,15 @@ class Translator():
|
|
|
456
464
|
def translate_table(self, t: mm.Table, parent, ctx):
|
|
457
465
|
return self.translate_scalartype(t, parent, ctx)
|
|
458
466
|
|
|
459
|
-
def rewrite_cdc_args(self,
|
|
467
|
+
def rewrite_cdc_args(self, lookup_node: mm.Lookup, args, parent, ctx):
|
|
460
468
|
# If this is a lookup for an external table column,
|
|
461
469
|
# we have to prepend the column symbol to the args
|
|
462
|
-
root_type =
|
|
470
|
+
root_type = lookup_node.relation.fields[0].type
|
|
463
471
|
if isinstance(root_type, mm.Table):
|
|
464
472
|
self.used_tables.add(root_type)
|
|
465
|
-
is_table =
|
|
466
|
-
if is_table or
|
|
467
|
-
sym = "METADATA$KEY" if is_table else
|
|
473
|
+
is_table = lookup_node.relation == root_type
|
|
474
|
+
if is_table or lookup_node.relation in root_type.columns:
|
|
475
|
+
sym = "METADATA$KEY" if is_table else lookup_node.relation.name
|
|
468
476
|
args = (v0.Literal(type=v0_types.Symbol, value=sym), *args)
|
|
469
477
|
return args
|
|
470
478
|
|
|
@@ -488,22 +496,22 @@ class Translator():
|
|
|
488
496
|
name=v.name
|
|
489
497
|
)
|
|
490
498
|
|
|
491
|
-
def translate_literal(self,
|
|
499
|
+
def translate_literal(self, literal_node: mm.Literal, parent, ctx) -> v0.Literal:
|
|
492
500
|
typ = None
|
|
493
|
-
if
|
|
501
|
+
if literal_node.type is None or is_abstract(literal_node.type):
|
|
494
502
|
# force int64 for literals, it can be widened later if needed
|
|
495
|
-
if
|
|
503
|
+
if isinstance(literal_node.value, int):
|
|
496
504
|
typ = v0_types.Int64
|
|
497
505
|
else:
|
|
498
506
|
# using v0's map of literal to type
|
|
499
|
-
typ = literal_value_to_type(
|
|
507
|
+
typ = literal_value_to_type(literal_node.value)
|
|
500
508
|
else:
|
|
501
|
-
typ = self.translate_node(
|
|
509
|
+
typ = self.translate_node(literal_node.type, literal_node, Context.MODEL)
|
|
502
510
|
if type is None:
|
|
503
511
|
pass
|
|
504
512
|
return v0.Literal(
|
|
505
513
|
type=typ, # type: ignore
|
|
506
|
-
value=
|
|
514
|
+
value=literal_node.value
|
|
507
515
|
)
|
|
508
516
|
|
|
509
517
|
# Value = _Union[Var, Literal, Type, Relation, seq["Value"], None]
|
|
@@ -531,7 +539,8 @@ class Translator():
|
|
|
531
539
|
# merge all outputs, accumulating keys and aliases
|
|
532
540
|
keys = ordered_set()
|
|
533
541
|
aliases = ordered_set()
|
|
534
|
-
|
|
542
|
+
sorted_outputs = sorted(outputs, key=lambda o: self.output_column_order.get(o, -1))
|
|
543
|
+
for output in sorted_outputs:
|
|
535
544
|
assert isinstance(output, v0.Output)
|
|
536
545
|
children.remove(output)
|
|
537
546
|
if output.keys is not None:
|
|
@@ -539,9 +548,15 @@ class Translator():
|
|
|
539
548
|
aliases.update(output.aliases)
|
|
540
549
|
|
|
541
550
|
# add a single, merged output
|
|
542
|
-
|
|
543
|
-
annos = (
|
|
544
|
-
if
|
|
551
|
+
export_output = next((output for output in outputs if output in self.exports), None)
|
|
552
|
+
annos = ()
|
|
553
|
+
if export_output:
|
|
554
|
+
uri = urlparse(self.exports[export_output].uri)
|
|
555
|
+
if uri.scheme == "table":
|
|
556
|
+
fqn = uri.hostname
|
|
557
|
+
annos = (v0.Annotation(v0_builtins.export, (v0.Literal(type=v0_types.String, value=fqn,),)),)
|
|
558
|
+
|
|
559
|
+
if export_output and not keys:
|
|
545
560
|
key_var = v0.Var(type=v0_types.Hash, name="export_key")
|
|
546
561
|
vals = [alias[1] for alias in aliases]
|
|
547
562
|
children.append(v0.Construct(
|
|
@@ -564,9 +579,9 @@ class Translator():
|
|
|
564
579
|
def get_outputs(self, children: seq[v0.Node]) -> list[v0.Output]:
|
|
565
580
|
return list(filter(lambda o: isinstance(o, v0.Output), children)) # type: ignore
|
|
566
581
|
|
|
567
|
-
def translate_logical(self,
|
|
582
|
+
def translate_logical(self, logical_node: mm.Logical, parent, ctx):
|
|
568
583
|
# first process children
|
|
569
|
-
children = self.translate_seq(
|
|
584
|
+
children = self.translate_seq(logical_node.body, logical_node, ctx)
|
|
570
585
|
|
|
571
586
|
# inline logicals if possible
|
|
572
587
|
new_children = []
|
|
@@ -579,34 +594,45 @@ class Translator():
|
|
|
579
594
|
children = tuple(new_children)
|
|
580
595
|
|
|
581
596
|
# compute variables to hoist, wrapping in Default if the logical is optional
|
|
582
|
-
|
|
583
|
-
|
|
597
|
+
# NOTE: the v0 compiler stack expects the aggregate body to hoist optionally or it doesn't work
|
|
598
|
+
if logical_node.optional or isinstance(parent, mm.Aggregate):
|
|
599
|
+
hoisted = tuple([v0.Default(self.translate_node(v, logical_node, ctx), None) for v in self.hoister.hoisted(logical_node)]) # type: ignore
|
|
584
600
|
else:
|
|
585
|
-
hoisted = tuple([self.translate_node(v,
|
|
601
|
+
hoisted = tuple([self.translate_node(v, logical_node, ctx) for v in self.hoister.hoisted(logical_node)]) # type: ignore
|
|
586
602
|
|
|
587
603
|
# Nots can never hoist variables upwards
|
|
588
604
|
if isinstance(parent, mm.Not):
|
|
589
605
|
hoisted = ()
|
|
590
606
|
|
|
607
|
+
# Loops can never hoist variables upwards
|
|
608
|
+
if isinstance(parent, mm.Loop):
|
|
609
|
+
hoisted = ()
|
|
610
|
+
# Sequences can never hoist variables upwards
|
|
611
|
+
if isinstance(parent, mm.Sequence):
|
|
612
|
+
hoisted = ()
|
|
613
|
+
# Breaks can never hoist variables upwards
|
|
614
|
+
if isinstance(parent, mm.Break):
|
|
615
|
+
hoisted = ()
|
|
616
|
+
|
|
591
617
|
# if there are no outputs, just return the logical
|
|
592
618
|
outputs = self.get_outputs(children)
|
|
593
619
|
if not outputs:
|
|
594
620
|
return v0.Logical(
|
|
595
|
-
engine=self.translate_reasoner(
|
|
621
|
+
engine=self.translate_reasoner(logical_node.reasoner, logical_node, Context.MODEL),
|
|
596
622
|
hoisted=hoisted, # type: ignore
|
|
597
623
|
body=children, # type: ignore
|
|
598
|
-
annotations=self.translate_frozen(
|
|
624
|
+
annotations=self.translate_frozen(logical_node.annotations, logical_node, ctx) # type: ignore
|
|
599
625
|
)
|
|
600
626
|
|
|
601
627
|
|
|
602
628
|
# if there's a main output here, we need to merge all outputs as a single one
|
|
603
|
-
has_main_output = any(is_main_output(c) for c in
|
|
629
|
+
has_main_output = any(is_main_output(c) for c in logical_node.body)
|
|
604
630
|
if has_main_output:
|
|
605
631
|
return v0.Logical(
|
|
606
|
-
engine=self.translate_reasoner(
|
|
632
|
+
engine=self.translate_reasoner(logical_node.reasoner, logical_node, Context.MODEL),
|
|
607
633
|
hoisted=hoisted, # type: ignore
|
|
608
634
|
body=self._merge_outputs(children, outputs), # type: ignore
|
|
609
|
-
annotations=self.translate_frozen(
|
|
635
|
+
annotations=self.translate_frozen(logical_node.annotations, logical_node, ctx) # type: ignore
|
|
610
636
|
)
|
|
611
637
|
else:
|
|
612
638
|
# this logical has an output but it's not the main one; so we return the outputs
|
|
@@ -623,7 +649,7 @@ class Translator():
|
|
|
623
649
|
# then it's possible we're filtering an outer variable, but only for this column. If
|
|
624
650
|
# so, we need to alias the output and hoist it.
|
|
625
651
|
# this is important because the LQP stack blows up if there's a logical with no effect
|
|
626
|
-
if
|
|
652
|
+
if logical_node.optional and not hoisted and not any(isinstance(c, v0.Update) for c in children):
|
|
627
653
|
# if there are no lookups, then this really is a no-op, just return outputs
|
|
628
654
|
# LQP blows up with e.g. a match-only logical
|
|
629
655
|
if not any(isinstance(c, v0.Lookup) for c in children):
|
|
@@ -650,6 +676,7 @@ class Translator():
|
|
|
650
676
|
keys=output.keys,
|
|
651
677
|
annotations=output.annotations
|
|
652
678
|
)
|
|
679
|
+
self.output_column_order[new_output] = self.output_column_order.get(output, -1)
|
|
653
680
|
eq = v0.Lookup(
|
|
654
681
|
engine=None,
|
|
655
682
|
relation=v0_builtins.eq,
|
|
@@ -667,10 +694,10 @@ class Translator():
|
|
|
667
694
|
# return outputs + a logical with the other children
|
|
668
695
|
outputs.append(
|
|
669
696
|
v0.Logical(
|
|
670
|
-
engine=self.translate_reasoner(
|
|
697
|
+
engine=self.translate_reasoner(logical_node.reasoner, logical_node, Context.MODEL),
|
|
671
698
|
hoisted=hoisted, # type: ignore
|
|
672
699
|
body=children, # type: ignore
|
|
673
|
-
annotations=self.translate_frozen(
|
|
700
|
+
annotations=self.translate_frozen(logical_node.annotations, logical_node, ctx) # type: ignore
|
|
674
701
|
))
|
|
675
702
|
return outputs
|
|
676
703
|
|
|
@@ -718,15 +745,15 @@ class Translator():
|
|
|
718
745
|
annotations=self.translate_frozen(w.annotations, w, ctx) # type: ignore
|
|
719
746
|
)
|
|
720
747
|
|
|
721
|
-
def translate_loop(self,
|
|
748
|
+
def translate_loop(self, loop_node: mm.Loop, parent, ctx) -> v0.Loop:
|
|
722
749
|
# TODO - loop is incompatible because over has multiple vars, so this is a best
|
|
723
750
|
# attempt (does not matter much as this is not used in practice)
|
|
724
751
|
return v0.Loop(
|
|
725
|
-
engine=self.translate_reasoner(
|
|
726
|
-
hoisted=self.translate_seq(self.hoister.hoisted(
|
|
727
|
-
iter=self.
|
|
728
|
-
body=self.translate_node(
|
|
729
|
-
annotations=self.translate_frozen(
|
|
752
|
+
engine=self.translate_reasoner(loop_node.reasoner, loop_node, Context.MODEL),
|
|
753
|
+
hoisted=self.translate_seq(self.hoister.hoisted(loop_node), loop_node, ctx), # type: ignore
|
|
754
|
+
iter=self.translate_seq(loop_node.over, loop_node, ctx), # type: ignore
|
|
755
|
+
body=self.translate_node(loop_node.body, loop_node, ctx), # type: ignore
|
|
756
|
+
annotations=self.translate_frozen(loop_node.annotations, loop_node, ctx) # type: ignore
|
|
730
757
|
)
|
|
731
758
|
|
|
732
759
|
def translate_break(self, b: mm.Break, parent, ctx) -> v0.Break:
|
|
@@ -745,7 +772,6 @@ class Translator():
|
|
|
745
772
|
assert isinstance(r.domain, mm.Logical)
|
|
746
773
|
assert isinstance(r.check, mm.Logical)
|
|
747
774
|
if not r.domain.body and all(isinstance(c, mm.Lookup) and c.relation is b.constraints.unique_fields for c in r.check.body):
|
|
748
|
-
return
|
|
749
775
|
v0_reqs = []
|
|
750
776
|
# v0 expects a check with both the domain and the relation in it followed by the unique
|
|
751
777
|
# constraint, so we construct a logical with all of that in it
|
|
@@ -754,7 +780,7 @@ class Translator():
|
|
|
754
780
|
fields = c.args[0] # tuple of fields
|
|
755
781
|
assert isinstance(fields, tuple) and all(isinstance(f, mm.Field) for f in fields)
|
|
756
782
|
first_field = fields[0]
|
|
757
|
-
if isinstance(first_field.type, mm.Table):
|
|
783
|
+
if isinstance(first_field.type, mm.Table): #type: ignore
|
|
758
784
|
# skip union types for now
|
|
759
785
|
continue
|
|
760
786
|
assert isinstance(first_field, mm.Field)
|
|
@@ -779,17 +805,17 @@ class Translator():
|
|
|
779
805
|
))
|
|
780
806
|
return v0_reqs # type: ignore
|
|
781
807
|
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
808
|
+
check = v0.Check(
|
|
809
|
+
check=self.translate_node(r.check, r, ctx), # type: ignore
|
|
810
|
+
error=self.translate_node(r.error, r, ctx) if r.error else None, # type: ignore
|
|
811
|
+
annotations=self.translate_frozen(r.annotations, r, ctx) # type: ignore
|
|
812
|
+
)
|
|
813
|
+
return v0.Require(
|
|
814
|
+
engine=self.translate_reasoner(r.reasoner, r, Context.MODEL),
|
|
815
|
+
domain=self.translate_node(r.domain, r, ctx), # type: ignore
|
|
816
|
+
checks=(check,), # type: ignore
|
|
817
|
+
annotations=self.translate_frozen(r.annotations, r, ctx) # type: ignore
|
|
818
|
+
)
|
|
793
819
|
return None
|
|
794
820
|
|
|
795
821
|
# -----------------------------
|
|
@@ -823,56 +849,56 @@ class Translator():
|
|
|
823
849
|
elif e == mm.Effect.delete:
|
|
824
850
|
return v0.Effect.delete
|
|
825
851
|
|
|
826
|
-
def translate_lookup(self,
|
|
852
|
+
def translate_lookup(self, lookup_node: mm.Lookup, parent, ctx):
|
|
827
853
|
# Data Node lookups
|
|
828
|
-
if isinstance(
|
|
829
|
-
vars = [self.translate_value(
|
|
830
|
-
for col in
|
|
854
|
+
if isinstance(lookup_node.relation, mm.Data):
|
|
855
|
+
vars = [self.translate_value(lookup_node.args[0], lookup_node, ctx)]
|
|
856
|
+
for col in lookup_node.relation.columns:
|
|
831
857
|
v = v0.Var(
|
|
832
858
|
type=self.translate_node(col.fields[-1].type, col, Context.MODEL), # type: ignore
|
|
833
859
|
name=f"{col.name}"
|
|
834
860
|
)
|
|
835
861
|
vars.append(v)
|
|
836
|
-
assert isinstance(
|
|
837
|
-
self.column_map[
|
|
862
|
+
assert isinstance(lookup_node.args[0], mm.Var)
|
|
863
|
+
self.column_map[lookup_node.args[0]][col] = v
|
|
838
864
|
return v0.Data(
|
|
839
|
-
engine=self.translate_reasoner(
|
|
840
|
-
data=
|
|
865
|
+
engine=self.translate_reasoner(lookup_node.reasoner, lookup_node, Context.MODEL),
|
|
866
|
+
data=lookup_node.relation.data,
|
|
841
867
|
vars=frozen(*vars) # type: ignore
|
|
842
868
|
)
|
|
843
|
-
elif
|
|
844
|
-
assert isinstance(
|
|
845
|
-
var = self.translate_value(
|
|
846
|
-
col_var = self.column_map[
|
|
869
|
+
elif lookup_node.args and lookup_node.args[0] in self.column_map and lookup_node.relation in self.column_map[lookup_node.args[0]]: # type: ignore
|
|
870
|
+
assert isinstance(lookup_node.args[0], mm.Var)
|
|
871
|
+
var = self.translate_value(lookup_node.args[1], lookup_node, ctx)
|
|
872
|
+
col_var = self.column_map[lookup_node.args[0]][lookup_node.relation] # ensure entry exists
|
|
847
873
|
if var != col_var:
|
|
848
874
|
return v0.Lookup(
|
|
849
|
-
engine=self.translate_reasoner(
|
|
875
|
+
engine=self.translate_reasoner(lookup_node.reasoner, lookup_node, Context.MODEL),
|
|
850
876
|
relation=v0_builtins.eq,
|
|
851
877
|
args=(var, col_var), # type: ignore
|
|
852
|
-
annotations=self.translate_frozen(
|
|
878
|
+
annotations=self.translate_frozen(lookup_node.annotations, lookup_node, ctx) # type: ignore
|
|
853
879
|
)
|
|
854
880
|
# if this is a data column, we just ignore it as the data node already binds the variables
|
|
855
|
-
elif isinstance(
|
|
881
|
+
elif isinstance(lookup_node.args[0].type, mm.Data):
|
|
856
882
|
return None
|
|
857
883
|
# Otherwise we keep the lookup because that's what the LQP stack expect (the lookup gets repeated for
|
|
858
884
|
# each column)
|
|
859
885
|
|
|
860
886
|
|
|
861
|
-
relation, args = self._resolve_reading(
|
|
887
|
+
relation, args = self._resolve_reading(lookup_node, ctx)
|
|
862
888
|
if relation is None:
|
|
863
889
|
return None
|
|
864
890
|
|
|
865
891
|
|
|
866
892
|
# Specific rewrites
|
|
867
|
-
rewrite = self.rewrite_lookup(
|
|
893
|
+
rewrite = self.rewrite_lookup(lookup_node, parent, ctx)
|
|
868
894
|
if rewrite is None:
|
|
869
|
-
args = self.rewrite_cdc_args(
|
|
895
|
+
args = self.rewrite_cdc_args(lookup_node, args, parent, ctx)
|
|
870
896
|
# General translation
|
|
871
897
|
rewrite = v0.Lookup(
|
|
872
|
-
engine=self.translate_reasoner(
|
|
898
|
+
engine=self.translate_reasoner(lookup_node.reasoner, lookup_node, Context.MODEL),
|
|
873
899
|
relation=relation, # type: ignore
|
|
874
900
|
args=args,
|
|
875
|
-
annotations=self.translate_frozen(
|
|
901
|
+
annotations=self.translate_frozen(lookup_node.annotations, lookup_node, ctx) # type: ignore
|
|
876
902
|
)
|
|
877
903
|
|
|
878
904
|
return rewrite
|
|
@@ -910,8 +936,10 @@ class Translator():
|
|
|
910
936
|
annotations=self.translate_frozen(u.annotations, u, ctx) # type: ignore
|
|
911
937
|
)
|
|
912
938
|
table = u.relation.fields[0].type
|
|
913
|
-
|
|
914
|
-
|
|
939
|
+
assert isinstance(table, mm.Table)
|
|
940
|
+
if not table.uri.startswith("dataframe://"):
|
|
941
|
+
self.exports[out] = table
|
|
942
|
+
self.output_column_order[out] = table.columns.index(u.relation)
|
|
915
943
|
return out
|
|
916
944
|
else:
|
|
917
945
|
relation, args = self._resolve_reading(u, ctx)
|
|
@@ -943,14 +971,14 @@ class Translator():
|
|
|
943
971
|
|
|
944
972
|
# hoist the return variables (those that are not inputs to the aggregation)
|
|
945
973
|
return_args = []
|
|
946
|
-
for
|
|
947
|
-
if not
|
|
974
|
+
for fld, arg in zip(a.aggregation.fields, a.args):
|
|
975
|
+
if not fld.input:
|
|
948
976
|
return_args.append(arg)
|
|
949
977
|
hoisted=self.translate_seq(return_args, a, ctx)
|
|
950
978
|
|
|
951
979
|
# body must contain the aggregate body plus the aggregate itself
|
|
952
980
|
body = self.translate_node(a.body, a, ctx)
|
|
953
|
-
body =
|
|
981
|
+
body = [body]
|
|
954
982
|
|
|
955
983
|
# construct the aggregate node
|
|
956
984
|
engine = self.translate_reasoner(a.reasoner, a, Context.MODEL)
|
|
@@ -964,13 +992,13 @@ class Translator():
|
|
|
964
992
|
if a.aggregation == b.aggregates.rank:
|
|
965
993
|
assert isinstance(args[0], tuple)
|
|
966
994
|
assert isinstance(args[1], tuple)
|
|
967
|
-
v0_agg = v0.Rank(engine, projection, group, args[0], tuple(
|
|
995
|
+
v0_agg = v0.Rank(engine, projection, group, args[0], tuple(lit.value for lit in args[1]), args[-1], 0, annotations,) # type: ignore
|
|
968
996
|
elif a.aggregation == b.aggregates.limit:
|
|
969
997
|
assert isinstance(args[0], v0.Literal)
|
|
970
998
|
assert isinstance(args[1], tuple)
|
|
971
999
|
assert isinstance(args[2], tuple)
|
|
972
1000
|
result = v0.Var(type=v0_types.Int64, name="limit_result")
|
|
973
|
-
v0_agg = v0.Rank(engine, projection, group, args[1], tuple(
|
|
1001
|
+
v0_agg = v0.Rank(engine, projection, group, args[1], tuple(lit.value for lit in args[2]), result, args[0].value, annotations,) # type: ignore
|
|
974
1002
|
else:
|
|
975
1003
|
v0_agg = v0.Aggregate(engine, aggregation, projection, group, args, annotations) # type: ignore
|
|
976
1004
|
|
|
@@ -1077,7 +1105,7 @@ class Translator():
|
|
|
1077
1105
|
# Library-specific rewrites
|
|
1078
1106
|
# -----------------------------------------------------------------------------
|
|
1079
1107
|
|
|
1080
|
-
def adjust_index(self,
|
|
1108
|
+
def adjust_index(self, lookup_node: mm.Lookup, indices: list[int], ctx, args=None, no_outputs=False):
|
|
1081
1109
|
""" Rewrite the lookup such that the args at `indices` are adjusted to convert from
|
|
1082
1110
|
0-based indexing (as in the mm) to 1-based indexing (as in v0's backend).
|
|
1083
1111
|
|
|
@@ -1085,16 +1113,16 @@ class Translator():
|
|
|
1085
1113
|
it to the lookup. If the field is output, we create a tmp var to hold the result
|
|
1086
1114
|
of the lookup, and then create a subsequent task to decrement the tmp var by 1.
|
|
1087
1115
|
|
|
1088
|
-
`args` can be used to provide a different set of args than
|
|
1116
|
+
`args` can be used to provide a different set of args than lookup_node.args, in case they need
|
|
1089
1117
|
reordering (e.g. strings.split).
|
|
1090
1118
|
"""
|
|
1091
1119
|
if args is None:
|
|
1092
|
-
args =
|
|
1120
|
+
args = lookup_node.args
|
|
1093
1121
|
# vars to hold the result from the v0 lookup
|
|
1094
1122
|
tmps = {}
|
|
1095
1123
|
for i in indices:
|
|
1096
|
-
index_type =
|
|
1097
|
-
tmps[i] = mm.Var(type=index_type, name=
|
|
1124
|
+
index_type = lookup_node.relation.fields[i].type
|
|
1125
|
+
tmps[i] = mm.Var(type=index_type, name="tmp")
|
|
1098
1126
|
# insert tmp at index
|
|
1099
1127
|
replaced_args = []
|
|
1100
1128
|
for i, arg in enumerate(args):
|
|
@@ -1103,37 +1131,37 @@ class Translator():
|
|
|
1103
1131
|
else:
|
|
1104
1132
|
replaced_args.append(arg)
|
|
1105
1133
|
# translate the lookup
|
|
1106
|
-
args = tuple(self.translate_value(arg,
|
|
1107
|
-
args = self.rewrite_cdc_args(
|
|
1134
|
+
args = tuple(self.translate_value(arg, lookup_node, ctx) for arg in replaced_args)
|
|
1135
|
+
args = self.rewrite_cdc_args(lookup_node, args, lookup_node, ctx)
|
|
1108
1136
|
lookup = v0.Lookup(
|
|
1109
|
-
engine=self.translate_reasoner(
|
|
1110
|
-
relation=self.translate_node(
|
|
1137
|
+
engine=self.translate_reasoner(lookup_node.reasoner, lookup_node, Context.MODEL),
|
|
1138
|
+
relation=self.translate_node(lookup_node.relation), # type: ignore
|
|
1111
1139
|
args=args,
|
|
1112
|
-
annotations=self.translate_frozen(
|
|
1140
|
+
annotations=self.translate_frozen(lookup_node.annotations, lookup_node, ctx) # type: ignore
|
|
1113
1141
|
)
|
|
1114
1142
|
# subtract 1 from the index to convert from 1-based to 0-based
|
|
1115
1143
|
tasks = []
|
|
1116
1144
|
for index in indices:
|
|
1117
|
-
arg = args[index]
|
|
1145
|
+
arg = lookup_node.args[index]
|
|
1118
1146
|
if isinstance(arg, mm.Literal):
|
|
1119
|
-
if
|
|
1147
|
+
if lookup_node.relation.fields[index].input:
|
|
1120
1148
|
new = mm.Literal(arg.type, arg.value + 1) # type: ignore
|
|
1121
1149
|
else:
|
|
1122
1150
|
new = mm.Literal(arg.type, arg.value + 1) # type: ignore
|
|
1123
1151
|
tasks.append(v0.Lookup(
|
|
1124
1152
|
engine=None,
|
|
1125
|
-
relation=v0_builtins.eq,
|
|
1153
|
+
relation=v0_builtins.eq,
|
|
1126
1154
|
args=(
|
|
1127
1155
|
self.translate_value(tmps[index], lookup, ctx),
|
|
1128
1156
|
self.translate_value(new, lookup, ctx),
|
|
1129
1157
|
)
|
|
1130
1158
|
))
|
|
1131
|
-
elif
|
|
1159
|
+
elif lookup_node.relation.fields[index].input:
|
|
1132
1160
|
tasks.append(v0.Lookup(
|
|
1133
1161
|
engine=None,
|
|
1134
|
-
relation=v0_builtins.plus,
|
|
1162
|
+
relation=v0_builtins.plus,
|
|
1135
1163
|
args=(
|
|
1136
|
-
self.translate_value(
|
|
1164
|
+
self.translate_value(arg, lookup, ctx),
|
|
1137
1165
|
v0.Literal(v0_types.Int128, 1),
|
|
1138
1166
|
self.translate_value(tmps[index], lookup, ctx),
|
|
1139
1167
|
),
|
|
@@ -1146,7 +1174,7 @@ class Translator():
|
|
|
1146
1174
|
args=(
|
|
1147
1175
|
self.translate_value(tmps[index], lookup, ctx),
|
|
1148
1176
|
v0.Literal(v0_types.Int128, 1),
|
|
1149
|
-
self.translate_value(
|
|
1177
|
+
self.translate_value(arg, lookup, ctx),
|
|
1150
1178
|
),
|
|
1151
1179
|
)
|
|
1152
1180
|
)
|
|
@@ -1155,37 +1183,37 @@ class Translator():
|
|
|
1155
1183
|
|
|
1156
1184
|
return tasks
|
|
1157
1185
|
|
|
1158
|
-
def decrement(self,
|
|
1186
|
+
def decrement(self, lookup_node: mm.Lookup, index: int, ctx):
|
|
1159
1187
|
""" Rewrite the lookup such that the arg at `index` is decremented by 1 before the
|
|
1160
1188
|
lookup. """
|
|
1161
|
-
x =
|
|
1189
|
+
x = lookup_node.args[index]
|
|
1162
1190
|
if isinstance(x, mm.Literal):
|
|
1163
1191
|
# if the arg is a literal, just decrement the literal directly
|
|
1164
1192
|
new_literal = mm.Literal(type=x.type, value=x.value - 1) # type: ignore
|
|
1165
1193
|
return v0.Lookup(
|
|
1166
1194
|
engine=None,
|
|
1167
|
-
relation=self.translate_node(
|
|
1168
|
-
args=tuple(self.translate_value(arg,
|
|
1169
|
-
annotations=self.translate_frozen(
|
|
1195
|
+
relation=self.translate_node(lookup_node.relation), # type: ignore
|
|
1196
|
+
args=tuple(self.translate_value(arg, lookup_node, ctx) if i != index else self.translate_value(new_literal, lookup_node, ctx) for i, arg in enumerate(lookup_node.args)),
|
|
1197
|
+
annotations=self.translate_frozen(lookup_node.annotations, lookup_node, ctx) # type: ignore
|
|
1170
1198
|
)
|
|
1171
1199
|
|
|
1172
1200
|
# arg is not a literal, so we need to create a tmp var to store the decremented value
|
|
1173
|
-
tmp = self.translate_value(mm.Var(type=b.core.Number, name="tmp"),
|
|
1201
|
+
tmp = self.translate_value(mm.Var(type=b.core.Number, name="tmp"), lookup_node, ctx)
|
|
1174
1202
|
# lookup(..., tmp, ...)
|
|
1175
1203
|
new = v0.Lookup(
|
|
1176
1204
|
engine=None,
|
|
1177
|
-
relation=self.translate_node(
|
|
1178
|
-
args=tuple(self.translate_value(arg,
|
|
1179
|
-
annotations=self.translate_frozen(
|
|
1205
|
+
relation=self.translate_node(lookup_node.relation), # type: ignore
|
|
1206
|
+
args=tuple(self.translate_value(arg, lookup_node, ctx) if i != index else tmp for i, arg in enumerate(lookup_node.args)),
|
|
1207
|
+
annotations=self.translate_frozen(lookup_node.annotations, lookup_node, ctx) # type: ignore
|
|
1180
1208
|
)
|
|
1181
1209
|
casted = self.cast(new, ctx)
|
|
1182
1210
|
return (
|
|
1183
|
-
# tmp =
|
|
1211
|
+
# tmp = lookup_node.args[index] - 1
|
|
1184
1212
|
v0.Lookup(
|
|
1185
1213
|
engine=None,
|
|
1186
1214
|
relation=v0_builtins.minus, # type: ignore
|
|
1187
1215
|
args=(
|
|
1188
|
-
self.translate_value(
|
|
1216
|
+
self.translate_value(lookup_node.args[index], lookup_node, ctx),
|
|
1189
1217
|
v0.Literal(v0_types.Int128, 1),
|
|
1190
1218
|
tmp,
|
|
1191
1219
|
),
|
|
@@ -1193,31 +1221,34 @@ class Translator():
|
|
|
1193
1221
|
*casted
|
|
1194
1222
|
)
|
|
1195
1223
|
|
|
1196
|
-
def cast(self,
|
|
1224
|
+
def cast(self, lookup_node: v0.Lookup, ctx, no_outputs=False):
|
|
1197
1225
|
# note that everything here is in v0
|
|
1198
1226
|
inputs = []
|
|
1199
1227
|
outputs = []
|
|
1200
1228
|
args = []
|
|
1201
|
-
fields =
|
|
1229
|
+
fields = lookup_node.relation.fields
|
|
1202
1230
|
# if there are overloads, we need to cast based on the most compatible overload
|
|
1203
|
-
if
|
|
1231
|
+
if lookup_node.relation.overloads:
|
|
1204
1232
|
inf = float("inf")
|
|
1205
1233
|
min_cost = inf
|
|
1206
|
-
for overload in
|
|
1234
|
+
for overload in lookup_node.relation.overloads:
|
|
1207
1235
|
total = 0
|
|
1208
|
-
for arg, field in zip(
|
|
1236
|
+
for arg, field in zip(lookup_node.args, overload.fields):
|
|
1209
1237
|
if v0_typer.to_type(arg) != field.type:
|
|
1210
1238
|
total += 1
|
|
1211
1239
|
if total < min_cost:
|
|
1212
1240
|
min_cost = total
|
|
1213
1241
|
fields = overload.fields
|
|
1214
1242
|
|
|
1215
|
-
for arg, field in zip(
|
|
1243
|
+
for arg, field in zip(lookup_node.args, fields):
|
|
1216
1244
|
target_type = field.type
|
|
1217
1245
|
if target_type is None or not isinstance(arg, (v0.Var, v0.Literal)) or arg.type == target_type:
|
|
1218
1246
|
args.append(arg)
|
|
1219
1247
|
continue
|
|
1220
|
-
if
|
|
1248
|
+
if isinstance(arg, v0.Literal):
|
|
1249
|
+
# for literals, we can just create a new literal with the target type
|
|
1250
|
+
args.append(v0.Literal(type=target_type, value=arg.value))
|
|
1251
|
+
elif field.input:
|
|
1221
1252
|
cast_var = v0.Var(type=target_type, name="cast_var")
|
|
1222
1253
|
args.append(cast_var)
|
|
1223
1254
|
inputs.append(v0.Lookup(
|
|
@@ -1241,16 +1272,16 @@ class Translator():
|
|
|
1241
1272
|
args.append(arg)
|
|
1242
1273
|
|
|
1243
1274
|
lookup = v0.Lookup(
|
|
1244
|
-
engine=
|
|
1245
|
-
relation=
|
|
1275
|
+
engine=lookup_node.engine,
|
|
1276
|
+
relation=lookup_node.relation,
|
|
1246
1277
|
args=tuple(args),
|
|
1247
|
-
annotations=
|
|
1278
|
+
annotations=lookup_node.annotations
|
|
1248
1279
|
)
|
|
1249
1280
|
if no_outputs:
|
|
1250
1281
|
outputs = []
|
|
1251
1282
|
return [*inputs, lookup, *outputs]
|
|
1252
1283
|
|
|
1253
|
-
def rewrite_lookup(self,
|
|
1284
|
+
def rewrite_lookup(self, lookup_node: mm.Lookup, parent, ctx):
|
|
1254
1285
|
""" Special cases for v1 builtins that either have some different shape in v0 or
|
|
1255
1286
|
do not exist as a primitive in the engine, so we want to compose the result so that
|
|
1256
1287
|
LQP works. Return None if no rewrite is needed.
|
|
@@ -1263,113 +1294,113 @@ class Translator():
|
|
|
1263
1294
|
# -----------------------------------------------------------------------------
|
|
1264
1295
|
# Common
|
|
1265
1296
|
# -----------------------------------------------------------------------------
|
|
1266
|
-
if
|
|
1297
|
+
if lookup_node.relation == b.common.range:
|
|
1267
1298
|
# python/PyRel range has inclusive start but exclusive stop, whereas LQP/Rel has
|
|
1268
1299
|
# inclusive stop, so we have to decrement the stop index by 1
|
|
1269
|
-
# tmp, lookup = self.decrement(
|
|
1300
|
+
# tmp, lookup = self.decrement(lookup_node, 1, ctx)
|
|
1270
1301
|
# return [tmp] + self.cast(lookup, [v0_types.Int64, v0_types.Int64, v0_types.Int64, v0_types.Int64], ctx)
|
|
1271
|
-
return self.decrement(
|
|
1302
|
+
return self.decrement(lookup_node, 1, ctx)
|
|
1272
1303
|
|
|
1273
|
-
elif
|
|
1304
|
+
elif lookup_node.relation == b.core.cast:
|
|
1274
1305
|
return v0.Lookup(
|
|
1275
|
-
engine=self.translate_reasoner(
|
|
1306
|
+
engine=self.translate_reasoner(lookup_node.reasoner, lookup_node, Context.TASK),
|
|
1276
1307
|
relation=v0_builtins.builtin_relations_by_name["cast"], # type: ignore
|
|
1277
1308
|
args=(
|
|
1278
|
-
self.translate_value(
|
|
1279
|
-
self.translate_value(
|
|
1280
|
-
self.translate_value(
|
|
1309
|
+
self.translate_value(lookup_node.args[0], lookup_node, Context.MODEL),
|
|
1310
|
+
self.translate_value(lookup_node.args[1], lookup_node, Context.TASK),
|
|
1311
|
+
self.translate_value(lookup_node.args[2], lookup_node, Context.TASK)
|
|
1281
1312
|
),
|
|
1282
|
-
annotations=self.translate_frozen(
|
|
1313
|
+
annotations=self.translate_frozen(lookup_node.annotations, lookup_node, ctx) # type: ignore
|
|
1283
1314
|
)
|
|
1284
1315
|
|
|
1285
1316
|
# -----------------------------------------------------------------------------
|
|
1286
1317
|
# Strings
|
|
1287
1318
|
# -----------------------------------------------------------------------------
|
|
1288
1319
|
|
|
1289
|
-
elif
|
|
1320
|
+
elif lookup_node.relation == b.strings.len:
|
|
1290
1321
|
lookup = v0.Lookup(
|
|
1291
|
-
engine=self.translate_reasoner(
|
|
1322
|
+
engine=self.translate_reasoner(lookup_node.reasoner, lookup_node, Context.MODEL),
|
|
1292
1323
|
relation=v0_builtins.builtin_relations_by_name["num_chars"], # type: ignore
|
|
1293
1324
|
args=(
|
|
1294
|
-
self.translate_value(
|
|
1295
|
-
self.translate_value(
|
|
1325
|
+
self.translate_value(lookup_node.args[0], lookup_node, ctx),
|
|
1326
|
+
self.translate_value(lookup_node.args[1], lookup_node, ctx),
|
|
1296
1327
|
),
|
|
1297
|
-
annotations=self.translate_frozen(
|
|
1328
|
+
annotations=self.translate_frozen(lookup_node.annotations, lookup_node, ctx) # type: ignore
|
|
1298
1329
|
)
|
|
1299
1330
|
return self.cast(lookup, ctx)
|
|
1300
1331
|
|
|
1301
|
-
elif
|
|
1332
|
+
elif lookup_node.relation == b.strings.split:
|
|
1302
1333
|
# swap first two args because that's how rel and v0 expect them
|
|
1303
|
-
args =
|
|
1304
|
-
return self.adjust_index(
|
|
1334
|
+
args = lookup_node.args[1], lookup_node.args[0], lookup_node.args[2], lookup_node.args[3]
|
|
1335
|
+
return self.adjust_index(lookup_node, [2], ctx, args=args)
|
|
1305
1336
|
|
|
1306
|
-
elif
|
|
1307
|
-
return self.adjust_index(
|
|
1337
|
+
elif lookup_node.relation == b.strings.substring:
|
|
1338
|
+
return self.adjust_index(lookup_node, [1], ctx)
|
|
1308
1339
|
|
|
1309
1340
|
# -----------------------------------------------------------------------------
|
|
1310
1341
|
# RE
|
|
1311
1342
|
# -----------------------------------------------------------------------------
|
|
1312
|
-
elif
|
|
1313
|
-
return self.adjust_index(
|
|
1343
|
+
elif lookup_node.relation == b.re.regex_match_all:
|
|
1344
|
+
return self.adjust_index(lookup_node, [2], ctx)
|
|
1314
1345
|
|
|
1315
1346
|
# -----------------------------------------------------------------------------
|
|
1316
1347
|
# Math
|
|
1317
1348
|
# -----------------------------------------------------------------------------
|
|
1318
|
-
elif
|
|
1349
|
+
elif lookup_node.relation == b.math.degrees:
|
|
1319
1350
|
# degrees(radians, x) = /(radians, (pi/180.0), x)
|
|
1320
1351
|
return v0.Lookup(
|
|
1321
|
-
engine=self.translate_reasoner(
|
|
1352
|
+
engine=self.translate_reasoner(lookup_node.reasoner, lookup_node, Context.MODEL),
|
|
1322
1353
|
relation=v0_builtins.builtin_relations_by_name["/"], # type: ignore
|
|
1323
1354
|
args=(
|
|
1324
|
-
self.translate_value(
|
|
1355
|
+
self.translate_value(lookup_node.args[0], lookup_node, ctx),
|
|
1325
1356
|
v0.Literal(v0_types.Float, pi / 180.0),
|
|
1326
|
-
self.translate_value(
|
|
1357
|
+
self.translate_value(lookup_node.args[1], lookup_node, ctx)
|
|
1327
1358
|
),
|
|
1328
|
-
annotations=self.translate_frozen(
|
|
1359
|
+
annotations=self.translate_frozen(lookup_node.annotations, lookup_node, ctx) # type: ignore
|
|
1329
1360
|
)
|
|
1330
|
-
elif
|
|
1361
|
+
elif lookup_node.relation == b.math.radians:
|
|
1331
1362
|
# radians(degrees, x) = /(degrees, (180.0/pi), x)
|
|
1332
1363
|
return v0.Lookup(
|
|
1333
|
-
engine=self.translate_reasoner(
|
|
1364
|
+
engine=self.translate_reasoner(lookup_node.reasoner, lookup_node, Context.MODEL),
|
|
1334
1365
|
relation=v0_builtins.builtin_relations_by_name["/"], # type: ignore
|
|
1335
1366
|
args=(
|
|
1336
|
-
self.translate_value(
|
|
1367
|
+
self.translate_value(lookup_node.args[0], lookup_node, ctx),
|
|
1337
1368
|
v0.Literal(v0_types.Float, 180.0 / pi),
|
|
1338
|
-
self.translate_value(
|
|
1369
|
+
self.translate_value(lookup_node.args[1], lookup_node, ctx)
|
|
1339
1370
|
),
|
|
1340
|
-
annotations=self.translate_frozen(
|
|
1371
|
+
annotations=self.translate_frozen(lookup_node.annotations, lookup_node, ctx) # type: ignore
|
|
1341
1372
|
)
|
|
1342
1373
|
|
|
1343
1374
|
# -----------------------------------------------------------------------------
|
|
1344
1375
|
# Datetime
|
|
1345
1376
|
# -----------------------------------------------------------------------------
|
|
1346
1377
|
#
|
|
1347
|
-
# elif
|
|
1348
|
-
# return self.rewrite_date_range(
|
|
1349
|
-
# elif
|
|
1378
|
+
# elif lookup_node.relation == b.datetime.date_range:
|
|
1379
|
+
# return self.rewrite_date_range(lookup_node, parent, ctx)
|
|
1380
|
+
# elif lookup_node.relation == b.datetime.datetime_range:
|
|
1350
1381
|
# pass
|
|
1351
1382
|
|
|
1352
|
-
elif
|
|
1383
|
+
elif lookup_node.relation == b.datetime.date_add:
|
|
1353
1384
|
return v0.Lookup(
|
|
1354
|
-
engine=self.translate_reasoner(
|
|
1355
|
-
relation=self.translate_relation(
|
|
1356
|
-
args=self.translate_seq(
|
|
1357
|
-
annotations=self.translate_frozen(
|
|
1385
|
+
engine=self.translate_reasoner(lookup_node.reasoner, lookup_node, Context.MODEL),
|
|
1386
|
+
relation=self.translate_relation(lookup_node.relation, lookup_node, ctx), # type: ignore
|
|
1387
|
+
args=self.translate_seq(lookup_node.args, lookup_node, ctx), # type: ignore
|
|
1388
|
+
annotations=self.translate_frozen(lookup_node.annotations, lookup_node, ctx) # type: ignore
|
|
1358
1389
|
)
|
|
1359
1390
|
|
|
1360
|
-
if b.datetime[
|
|
1361
|
-
return self.adjust_index(
|
|
1391
|
+
if b.datetime[lookup_node.relation.name] is lookup_node.relation:
|
|
1392
|
+
return self.adjust_index(lookup_node, [], ctx, no_outputs=True)
|
|
1362
1393
|
|
|
1363
|
-
v0_rel = self.translate_node(
|
|
1394
|
+
v0_rel = self.translate_node(lookup_node.relation, lookup_node, ctx)
|
|
1364
1395
|
if isinstance(v0_rel, v0.Relation) and any(f.type == v0_types.Int64 for f in v0_rel.fields):
|
|
1365
|
-
return self.adjust_index(
|
|
1396
|
+
return self.adjust_index(lookup_node, [], ctx)
|
|
1366
1397
|
|
|
1367
1398
|
return None
|
|
1368
1399
|
|
|
1369
1400
|
|
|
1370
1401
|
# TODO - Currently implemented in the std.datetime itself.
|
|
1371
1402
|
# def rewrite_date_range(self, l: mm.Lookup, parent, ctx: Context):
|
|
1372
|
-
# start, end, freq, date =
|
|
1403
|
+
# start, end, freq, date = lookup_node.args
|
|
1373
1404
|
# result = []
|
|
1374
1405
|
|
|
1375
1406
|
# range_end = num_days = mm.Var(type=b.core.Number, name="num_days")
|