pytrilogy 0.0.3.28__py3-none-any.whl → 0.0.3.30__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.

Potentially problematic release.


This version of pytrilogy might be problematic. Click here for more details.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pytrilogy
3
- Version: 0.0.3.28
3
+ Version: 0.0.3.30
4
4
  Summary: Declarative, typed query language that compiles to SQL.
5
5
  Home-page:
6
6
  Author:
@@ -1,5 +1,5 @@
1
- pytrilogy-0.0.3.28.dist-info/licenses/LICENSE.md,sha256=5ZRvtTyCCFwz1THxDTjAu3Lidds9WjPvvzgVwPSYNDo,1042
2
- trilogy/__init__.py,sha256=BWRnSblH31X0EL041UhPaq_TRiA9hEJGt6VMVN-XBsg,303
1
+ pytrilogy-0.0.3.30.dist-info/licenses/LICENSE.md,sha256=5ZRvtTyCCFwz1THxDTjAu3Lidds9WjPvvzgVwPSYNDo,1042
2
+ trilogy/__init__.py,sha256=N2ia8yWHecF0aH0-BYA1rcIjOwSIhR5Igw8b5lKDinc,303
3
3
  trilogy/compiler.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
4
  trilogy/constants.py,sha256=5eQxk1A0pv-TQk3CCvgZCFA9_K-6nxrOm7E5Lxd7KIY,1652
5
5
  trilogy/engine.py,sha256=OK2RuqCIUId6yZ5hfF8J1nxGP0AJqHRZiafcowmW0xc,1728
@@ -11,19 +11,19 @@ trilogy/utility.py,sha256=euQccZLKoYBz0LNg5tzLlvv2YHvXh9HArnYp1V3uXsM,763
11
11
  trilogy/authoring/__init__.py,sha256=ohkYA3_LGYZh3fwzEYKTN6ofACDI5GYl3VCbGxVvlzY,2233
12
12
  trilogy/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
13
  trilogy/core/constants.py,sha256=7XaCpZn5mQmjTobbeBn56SzPWq9eMNDfzfsRU-fP0VE,171
14
- trilogy/core/enums.py,sha256=zpXhm8qk6i_ih4O6ro5sPMbIQSQDtzLcBcX5eKWQZU4,7197
14
+ trilogy/core/enums.py,sha256=jepT1QpOvLbz6HNWvAoEyxvaMPLRbaOkIWjOkwJ15uo,7215
15
15
  trilogy/core/env_processor.py,sha256=pFsxnluKIusGKx1z7tTnfsd_xZcPy9pZDungkjkyvI0,3170
16
16
  trilogy/core/environment_helpers.py,sha256=i0oyxfLjFQW6ZbD6g2wa0DXUoEvd2sHG28TZ1UBs2os,7573
17
17
  trilogy/core/ergonomics.py,sha256=e-7gE29vPLFdg0_A1smQ7eOrUwKl5VYdxRSTddHweRA,1631
18
18
  trilogy/core/exceptions.py,sha256=JPYyBcit3T_pRtlHdtKSeVJkIyWUTozW2aaut25A2xI,673
19
- trilogy/core/functions.py,sha256=Ke8-d2RtHZszAQdx_6dNyHtELbvMIGZo2CsglxqtvEQ,26890
19
+ trilogy/core/functions.py,sha256=z5uyC5sAS_vnFBJcky7TjA0QAy-xI4Z9uD_9vK_XP1s,27134
20
20
  trilogy/core/graph_models.py,sha256=z17EoO8oky2QOuO6E2aMWoVNKEVJFhLdsQZOhC4fNLU,2079
21
21
  trilogy/core/internal.py,sha256=iicDBlC6nM8d7e7jqzf_ZOmpUsW8yrr2AA8AqEiLx-s,1577
22
22
  trilogy/core/optimization.py,sha256=xGO8piVsLrpqrx-Aid_Y56_5slSv4eZmlP64hCHRiEc,7957
23
23
  trilogy/core/query_processor.py,sha256=Do8YpdPBdsbKtl9n37hobzk8SORMGqH-e_zNNxd-BE4,19456
24
24
  trilogy/core/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
25
- trilogy/core/models/author.py,sha256=-90COW7QY6w-g8GkjivPZqG2yNitn74e13m5KYgB1IU,73985
26
- trilogy/core/models/build.py,sha256=tky6ryVPcAECt53Sk9TGzmGCumxdbfY9Uxn0oVi50VA,57854
25
+ trilogy/core/models/author.py,sha256=2lkuKm6FKEMoYx6h03g7WhCTCooT5sCbKJmlVfAlMG8,75876
26
+ trilogy/core/models/build.py,sha256=3_n6qxoMuzX3Ahu9HLfoyPbtH0Wb--6crZNwCnZhu7k,58104
27
27
  trilogy/core/models/build_environment.py,sha256=8UggvlPU708GZWYPJMc_ou2r7M3TY2g69eqGvz03YX0,5528
28
28
  trilogy/core/models/core.py,sha256=wx6hJcFECMG-Ij972ADNkr-3nFXkYESr82ObPiC46_U,10875
29
29
  trilogy/core/models/datasource.py,sha256=6RjJUd2u4nYmEwFBpJlM9LbHVYDv8iHJxqiBMZqUrwI,9422
@@ -65,12 +65,12 @@ trilogy/core/processing/nodes/union_node.py,sha256=fDFzLAUh5876X6_NM7nkhoMvHEdGJ
65
65
  trilogy/core/processing/nodes/unnest_node.py,sha256=oLKMMNMx6PLDPlt2V5neFMFrFWxET8r6XZElAhSNkO0,2181
66
66
  trilogy/core/processing/nodes/window_node.py,sha256=JXJ0iVRlSEM2IBr1TANym2RaUf_p5E_l2sNykRzXWDo,1710
67
67
  trilogy/core/statements/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
68
- trilogy/core/statements/author.py,sha256=sPrItQEKXzE7IR3SGOTVN4OBvGHldUCqXCzbcmEpb7I,14575
68
+ trilogy/core/statements/author.py,sha256=75ZIMOfQFAahtVLpv3qYJre2SAIdf0vrGBsTR5qweDg,14638
69
69
  trilogy/core/statements/build.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
70
70
  trilogy/core/statements/common.py,sha256=KxEmz2ySySyZ6CTPzn0fJl5NX2KOk1RPyuUSwWhnK1g,759
71
71
  trilogy/core/statements/execute.py,sha256=cSlvpHFOqpiZ89pPZ5GDp9Hu6j6uj-5_h21FWm_L-KM,1248
72
72
  trilogy/dialect/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
73
- trilogy/dialect/base.py,sha256=ogBNUDt0UEmx-F8EXGG65i6fcz2KcIz8a3gwE7YXCVw,40956
73
+ trilogy/dialect/base.py,sha256=lm3rUjmGENoW9wyXAzzJmBohXLVv4sLvvtfB-YCeHPY,41006
74
74
  trilogy/dialect/bigquery.py,sha256=PkjFcNGZHYOe655PmJhb8a0afdFULuovqP0qQVO8m0I,2953
75
75
  trilogy/dialect/common.py,sha256=XjHkP8Dqezjkd2JU5xoAlMRS_6HNyXQCF4CykLK3C8o,5011
76
76
  trilogy/dialect/config.py,sha256=olnyeVU5W5T6b9-dMeNAnvxuPlyc2uefb7FRME094Ec,3834
@@ -87,22 +87,22 @@ trilogy/hooks/graph_hook.py,sha256=c-vC-IXoJ_jDmKQjxQyIxyXPOuUcLIURB573gCsAfzQ,2
87
87
  trilogy/hooks/query_debugger.py,sha256=1npRjww94sPV5RRBBlLqMJRaFkH9vhEY6o828MeoEcw,5583
88
88
  trilogy/metadata/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
89
89
  trilogy/parsing/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
90
- trilogy/parsing/common.py,sha256=JN8pPjtoEMyURAtp7fttm-8iFkaAvuinUKyQs05FqoM,21615
90
+ trilogy/parsing/common.py,sha256=_61lUd6DONwteY_D6lanZZgi2NoEWivAxJtrOYrmw34,21915
91
91
  trilogy/parsing/config.py,sha256=Z-DaefdKhPDmSXLgg5V4pebhSB0h590vI0_VtHnlukI,111
92
92
  trilogy/parsing/exceptions.py,sha256=92E5i2frv5hj9wxObJZsZqj5T6bglvPzvdvco_vW1Zk,38
93
93
  trilogy/parsing/helpers.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
94
- trilogy/parsing/parse_engine.py,sha256=Ffm3YB2jTPcA81CZTkpQ7iAwD1LP10QQpjoKk9fey4I,61849
95
- trilogy/parsing/render.py,sha256=o_XuQWhcwx1lD9eGVqkqZEwkmQK0HdmWWokGBtdeH4I,17837
96
- trilogy/parsing/trilogy.lark,sha256=GYRO0LJYUtzf1__d2b0L2EJzRGfnsI2SaQHzh9RgxnA,12945
94
+ trilogy/parsing/parse_engine.py,sha256=wkHQ7FrFLV0508I88qJk7nfqNZCpzclLYHlJcguDwQE,62220
95
+ trilogy/parsing/render.py,sha256=ElpmCWUhGs8h489S7cdlbI8bilJlnBgHZ8KMR8y1FrM,18840
96
+ trilogy/parsing/trilogy.lark,sha256=h7mJiad7GgTTXnrjntE6OF7xpND5TQlvHqZFfx0nkyk,12993
97
97
  trilogy/scripts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
98
98
  trilogy/scripts/trilogy.py,sha256=1L0XrH4mVHRt1C9T1HnaDv2_kYEfbWTb5_-cBBke79w,3774
99
99
  trilogy/std/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
100
100
  trilogy/std/dashboard.preql,sha256=eJJTs3xPjYKmp-U5SUxCXAAbp55NlmmC3kECaNg4ya4,128
101
101
  trilogy/std/date.preql,sha256=0MHeGLp2mG4QBKtmozcBZ7qVjOAdWOtrliIKn6hz1Pc,95
102
- trilogy/std/geography.preql,sha256=KavDw4wbTJcgooo30vWF-MYg5WvD7dZYIWuBQtSaPxg,441
102
+ trilogy/std/geography.preql,sha256=-fqAGnBL6tR-UtT8DbSek3iMFg66ECR_B_41pODxv-k,504
103
103
  trilogy/std/money.preql,sha256=ZHW-csTX-kYbOLmKSO-TcGGgQ-_DMrUXy0BjfuJSFxM,80
104
- pytrilogy-0.0.3.28.dist-info/METADATA,sha256=yyfDxvVnQCKioM0j6JT07GLQpwwRAtwFwPukuUz6HsI,9100
105
- pytrilogy-0.0.3.28.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
106
- pytrilogy-0.0.3.28.dist-info/entry_points.txt,sha256=ewBPU2vLnVexZVnB-NrVj-p3E-4vukg83Zk8A55Wp2w,56
107
- pytrilogy-0.0.3.28.dist-info/top_level.txt,sha256=cAy__NW_eMAa_yT9UnUNlZLFfxcg6eimUAZ184cdNiE,8
108
- pytrilogy-0.0.3.28.dist-info/RECORD,,
104
+ pytrilogy-0.0.3.30.dist-info/METADATA,sha256=we5JHKvw-U_4BLL35Nzk6KBi_GiiPP3FsL89wzy0B94,9100
105
+ pytrilogy-0.0.3.30.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
106
+ pytrilogy-0.0.3.30.dist-info/entry_points.txt,sha256=ewBPU2vLnVexZVnB-NrVj-p3E-4vukg83Zk8A55Wp2w,56
107
+ pytrilogy-0.0.3.30.dist-info/top_level.txt,sha256=cAy__NW_eMAa_yT9UnUNlZLFfxcg6eimUAZ184cdNiE,8
108
+ pytrilogy-0.0.3.30.dist-info/RECORD,,
trilogy/__init__.py CHANGED
@@ -4,6 +4,6 @@ from trilogy.dialect.enums import Dialects
4
4
  from trilogy.executor import Executor
5
5
  from trilogy.parser import parse
6
6
 
7
- __version__ = "0.0.3.28"
7
+ __version__ = "0.0.3.30"
8
8
 
9
9
  __all__ = ["parse", "Executor", "Dialects", "Environment", "CONFIG"]
trilogy/core/enums.py CHANGED
@@ -153,6 +153,7 @@ class FunctionType(Enum):
153
153
  MOD = "mod"
154
154
  ROUND = "round"
155
155
  ABS = "abs"
156
+ SQRT = "sqrt"
156
157
 
157
158
  # Aggregates
158
159
  ## group is not a real aggregate - it just means group by this + some other set of fields
trilogy/core/functions.py CHANGED
@@ -607,7 +607,15 @@ FUNCTION_REGISTRY: dict[FunctionType, FunctionConfig] = {
607
607
  ],
608
608
  output_purpose=Purpose.PROPERTY,
609
609
  output_type=DataType.INTEGER,
610
- arg_count=InfiniteFunctionArgs,
610
+ arg_count=2,
611
+ ),
612
+ FunctionType.SQRT: FunctionConfig(
613
+ valid_inputs=[
614
+ {DataType.INTEGER, DataType.FLOAT, DataType.NUMBER, DataType.NUMERIC},
615
+ ],
616
+ output_purpose=Purpose.PROPERTY,
617
+ output_type=DataType.INTEGER,
618
+ arg_count=1,
611
619
  ),
612
620
  FunctionType.ROUND: FunctionConfig(
613
621
  valid_inputs=[
@@ -376,7 +376,7 @@ class Conditional(Mergeable, ConceptArgs, Namespaced, DataTyped, BaseModel):
376
376
 
377
377
 
378
378
  class WhereClause(Mergeable, ConceptArgs, Namespaced, BaseModel):
379
- conditional: Union[SubselectComparison, Comparison, Conditional, "Parenthetical"]
379
+ conditional: Union[SubselectComparison, Comparison, Conditional, Parenthetical]
380
380
 
381
381
  def __repr__(self):
382
382
  return str(self.conditional)
@@ -564,6 +564,7 @@ class Comparison(ConceptArgs, Mergeable, DataTyped, Namespaced, BaseModel):
564
564
  "Conditional",
565
565
  DataType,
566
566
  "Comparison",
567
+ FunctionCallWrapper,
567
568
  "Parenthetical",
568
569
  MagicConstants,
569
570
  WindowItem,
@@ -583,6 +584,7 @@ class Comparison(ConceptArgs, Mergeable, DataTyped, Namespaced, BaseModel):
583
584
  Conditional,
584
585
  DataType,
585
586
  Comparison,
587
+ FunctionCallWrapper,
586
588
  Parenthetical,
587
589
  MagicConstants,
588
590
  WindowItem,
@@ -1622,7 +1624,6 @@ class Function(DataTyped, ConceptArgs, Mergeable, Namespaced, BaseModel):
1622
1624
  elif not valid_inputs:
1623
1625
  return v
1624
1626
  for idx, arg in enumerate(v):
1625
-
1626
1627
  if (
1627
1628
  isinstance(arg, ConceptRef)
1628
1629
  and get_basic_type(arg.datatype.data_type) not in valid_inputs[idx]
@@ -1753,6 +1754,69 @@ class Function(DataTyped, ConceptArgs, Mergeable, Namespaced, BaseModel):
1753
1754
  return base_grain
1754
1755
 
1755
1756
 
1757
+ class FunctionCallWrapper(
1758
+ DataTyped,
1759
+ ConceptArgs,
1760
+ Mergeable,
1761
+ Namespaced,
1762
+ BaseModel,
1763
+ ):
1764
+ content: Expr
1765
+ name: str
1766
+ args: List[Expr]
1767
+
1768
+ def __str__(self):
1769
+ return f'@{self.name}({",".join([str(x) for x in self.args])})'
1770
+
1771
+ def with_namespace(self, namespace) -> "FunctionCallWrapper":
1772
+ return FunctionCallWrapper.model_construct(
1773
+ content=(
1774
+ self.content.with_namespace(namespace)
1775
+ if isinstance(self.content, Namespaced)
1776
+ else self.content
1777
+ ),
1778
+ name=self.name,
1779
+ args=[
1780
+ x.with_namespace(namespace) if isinstance(x, Namespaced) else x
1781
+ for x in self.args
1782
+ ],
1783
+ )
1784
+
1785
+ def with_merge(
1786
+ self, source: Concept, target: Concept, modifiers: List[Modifier]
1787
+ ) -> "FunctionCallWrapper":
1788
+ return FunctionCallWrapper.model_construct(
1789
+ content=(
1790
+ self.content.with_merge(source, target, modifiers)
1791
+ if isinstance(self.content, Mergeable)
1792
+ else self.content
1793
+ ),
1794
+ name=self.name,
1795
+ args=[
1796
+ (
1797
+ x.with_merge(source, target, modifiers)
1798
+ if isinstance(x, Mergeable)
1799
+ else x
1800
+ )
1801
+ for x in self.args
1802
+ ],
1803
+ )
1804
+
1805
+ @property
1806
+ def concept_arguments(self) -> Sequence[ConceptRef]:
1807
+ base: List[ConceptRef] = []
1808
+ x = self.content
1809
+ if isinstance(x, ConceptRef):
1810
+ base += [x]
1811
+ elif isinstance(x, ConceptArgs):
1812
+ base += x.concept_arguments
1813
+ return base
1814
+
1815
+ @property
1816
+ def output_datatype(self):
1817
+ return arg_to_datatype(self.content)
1818
+
1819
+
1756
1820
  class AggregateWrapper(Mergeable, DataTyped, ConceptArgs, Namespaced, BaseModel):
1757
1821
  function: Function
1758
1822
  by: List[ConceptRef] = Field(default_factory=list)
@@ -2278,6 +2342,7 @@ Expr = (
2278
2342
  | ConceptRef
2279
2343
  | Comparison
2280
2344
  | Conditional
2345
+ | FunctionCallWrapper
2281
2346
  | Parenthetical
2282
2347
  | Function
2283
2348
  | AggregateWrapper
@@ -2289,6 +2354,7 @@ FuncArgs = (
2289
2354
  ConceptRef
2290
2355
  | AggregateWrapper
2291
2356
  | Function
2357
+ | FunctionCallWrapper
2292
2358
  | Parenthetical
2293
2359
  | CaseWhen
2294
2360
  | CaseElse
@@ -53,6 +53,7 @@ from trilogy.core.models.author import (
53
53
  FilterItem,
54
54
  FuncArgs,
55
55
  Function,
56
+ FunctionCallWrapper,
56
57
  Grain,
57
58
  HavingClause,
58
59
  Metadata,
@@ -1608,6 +1609,12 @@ class Factory:
1608
1609
  def _(self, base: OrderBy) -> BuildOrderBy:
1609
1610
  return BuildOrderBy.model_construct(items=[self.build(x) for x in base.items])
1610
1611
 
1612
+ @build.register
1613
+ def _(self, base: FunctionCallWrapper) -> BuildExpr:
1614
+ # function calls are kept around purely for the parse tree
1615
+ # so discard at the build point
1616
+ return self.build(base.content)
1617
+
1611
1618
  @build.register
1612
1619
  def _(self, base: OrderItem) -> BuildOrderItem:
1613
1620
  from trilogy.parsing.common import arbitrary_to_concept
@@ -22,6 +22,7 @@ from trilogy.core.models.author import (
22
22
  Expr,
23
23
  FilterItem,
24
24
  Function,
25
+ FunctionCallWrapper,
25
26
  Grain,
26
27
  HasUUID,
27
28
  HavingClause,
@@ -44,7 +45,9 @@ from trilogy.utility import unique
44
45
 
45
46
 
46
47
  class ConceptTransform(BaseModel):
47
- function: Function | FilterItem | WindowItem | AggregateWrapper
48
+ function: (
49
+ Function | FilterItem | WindowItem | AggregateWrapper | FunctionCallWrapper
50
+ )
48
51
  output: Concept # this has to be a full concept, as it may not exist in environment
49
52
  modifiers: List[Modifier] = Field(default_factory=list)
50
53
 
trilogy/dialect/base.py CHANGED
@@ -171,6 +171,7 @@ FUNCTION_MAP = {
171
171
  FunctionType.MULTIPLY: lambda x: " * ".join(x),
172
172
  FunctionType.ROUND: lambda x: f"round({x[0]},{x[1]})",
173
173
  FunctionType.MOD: lambda x: f"({x[0]} % {x[1]})",
174
+ FunctionType.SQRT: lambda x: f"sqrt({x[0]})",
174
175
  # aggregate types
175
176
  FunctionType.COUNT_DISTINCT: lambda x: f"count(distinct {x[0]})",
176
177
  FunctionType.COUNT: lambda x: f"count({x[0]})",
trilogy/parsing/common.py CHANGED
@@ -27,6 +27,7 @@ from trilogy.core.models.author import (
27
27
  ConceptRef,
28
28
  FilterItem,
29
29
  Function,
30
+ FunctionCallWrapper,
30
31
  Grain,
31
32
  HavingClause,
32
33
  ListWrapper,
@@ -595,6 +596,7 @@ def rowset_to_concepts(rowset: RowsetDerivationStatement, environment: Environme
595
596
  def arbitrary_to_concept(
596
597
  parent: (
597
598
  AggregateWrapper
599
+ | FunctionCallWrapper
598
600
  | WindowItem
599
601
  | FilterItem
600
602
  | Function
@@ -610,7 +612,12 @@ def arbitrary_to_concept(
610
612
  metadata: Metadata | None = None,
611
613
  ) -> Concept:
612
614
  namespace = namespace or environment.namespace
613
- if isinstance(parent, AggregateWrapper):
615
+ # this is purely for the parse tree, discard from derivation
616
+ if isinstance(parent, FunctionCallWrapper):
617
+ return arbitrary_to_concept(
618
+ parent.content, environment, namespace, name, metadata # type: ignore
619
+ )
620
+ elif isinstance(parent, AggregateWrapper):
614
621
  if not name:
615
622
  name = f"{VIRTUAL_CONCEPT_PREFIX}_agg_{parent.function.operator.value}_{string_to_hash(str(parent))}"
616
623
  return agg_wrapper_to_concept(
@@ -64,6 +64,7 @@ from trilogy.core.models.author import (
64
64
  Expr,
65
65
  FilterItem,
66
66
  Function,
67
+ FunctionCallWrapper,
67
68
  Grain,
68
69
  HavingClause,
69
70
  Metadata,
@@ -202,7 +203,7 @@ def expr_to_boolean(
202
203
  def unwrap_transformation(
203
204
  input: Expr,
204
205
  environment: Environment,
205
- ) -> Function | FilterItem | WindowItem | AggregateWrapper:
206
+ ) -> Function | FilterItem | WindowItem | AggregateWrapper | FunctionCallWrapper:
206
207
  if isinstance(input, Function):
207
208
  return input
208
209
  elif isinstance(input, AggregateWrapper):
@@ -219,6 +220,8 @@ def unwrap_transformation(
219
220
  return input
220
221
  elif isinstance(input, WindowItem):
221
222
  return input
223
+ elif isinstance(input, FunctionCallWrapper):
224
+ return input
222
225
  elif isinstance(input, Parenthetical):
223
226
  return unwrap_transformation(input.content, environment)
224
227
  else:
@@ -810,7 +813,6 @@ class ParseToObjects(Transformer):
810
813
  )
811
814
 
812
815
  metadata = Metadata(line_number=meta.line, concept_source=ConceptSource.SELECT)
813
-
814
816
  concept = arbitrary_to_concept(
815
817
  transformation,
816
818
  environment=self.environment,
@@ -1248,10 +1250,12 @@ class ParseToObjects(Transformer):
1248
1250
  )
1249
1251
  return FunctionDeclaration(name=identity, args=function_arguments, expr=output)
1250
1252
 
1251
- def custom_function(self, args):
1253
+ def custom_function(self, args) -> FunctionCallWrapper:
1252
1254
  name = args[0]
1253
1255
  args = args[1:]
1254
- remapped = self.environment.functions[name](*args)
1256
+ remapped = FunctionCallWrapper(
1257
+ content=self.environment.functions[name](*args), name=name, args=args
1258
+ )
1255
1259
  return remapped
1256
1260
 
1257
1261
  @v_args(meta=True)
@@ -1723,6 +1727,10 @@ class ParseToObjects(Transformer):
1723
1727
  def fmod(self, meta: Meta, args) -> Function:
1724
1728
  return self.function_factory.create_function(args, FunctionType.MOD, meta)
1725
1729
 
1730
+ @v_args(meta=True)
1731
+ def fsqrt(self, meta: Meta, args) -> Function:
1732
+ return self.function_factory.create_function(args, FunctionType.SQRT, meta)
1733
+
1726
1734
  @v_args(meta=True)
1727
1735
  def fround(self, meta, args) -> Function:
1728
1736
  return self.function_factory.create_function(args, FunctionType.ROUND, meta)
trilogy/parsing/render.py CHANGED
@@ -18,6 +18,7 @@ from trilogy.core.models.author import (
18
18
  Conditional,
19
19
  FilterItem,
20
20
  Function,
21
+ FunctionCallWrapper,
21
22
  Grain,
22
23
  OrderBy,
23
24
  OrderItem,
@@ -31,6 +32,7 @@ from trilogy.core.models.core import (
31
32
  ListType,
32
33
  ListWrapper,
33
34
  NumericType,
35
+ TraitDataType,
34
36
  TupleWrapper,
35
37
  )
36
38
  from trilogy.core.models.datasource import (
@@ -42,10 +44,12 @@ from trilogy.core.models.datasource import (
42
44
  )
43
45
  from trilogy.core.models.environment import Environment, Import
44
46
  from trilogy.core.statements.author import (
47
+ ArgBinding,
45
48
  ConceptDeclarationStatement,
46
49
  ConceptDerivationStatement,
47
50
  ConceptTransform,
48
51
  CopyStatement,
52
+ FunctionDeclaration,
49
53
  ImportStatement,
50
54
  MergeStatementV2,
51
55
  MultiSelectStatement,
@@ -54,6 +58,7 @@ from trilogy.core.statements.author import (
54
58
  RowsetDerivationStatement,
55
59
  SelectItem,
56
60
  SelectStatement,
61
+ TypeDeclaration,
57
62
  )
58
63
 
59
64
  QUERY_TEMPLATE = Template(
@@ -149,6 +154,21 @@ class Renderer:
149
154
  final = "\n\n".join("\n".join(x) for x in components)
150
155
  return final
151
156
 
157
+ @to_string.register
158
+ def _(self, arg: TypeDeclaration):
159
+ return f"type {arg.type.name} {self.to_string(arg.type.type)};"
160
+
161
+ @to_string.register
162
+ def _(self, arg: ArgBinding):
163
+ if arg.default:
164
+ return f"{arg.name}={self.to_string(arg.default)}"
165
+ return f"{arg.name}"
166
+
167
+ @to_string.register
168
+ def _(self, arg: FunctionDeclaration):
169
+ args = ", ".join([self.to_string(x) for x in arg.args])
170
+ return f"def {arg.name}({args}) -> {self.to_string(arg.expr)};"
171
+
152
172
  @to_string.register
153
173
  def _(self, arg: Datasource):
154
174
  assignments = ",\n ".join([self.to_string(x) for x in arg.columns])
@@ -198,6 +218,12 @@ class Renderer:
198
218
  def _(self, arg: "CaseElse"):
199
219
  return f"""ELSE {self.to_string(arg.expr)}"""
200
220
 
221
+ @to_string.register
222
+ def _(self, arg: "FunctionCallWrapper"):
223
+ args = [self.to_string(c) for c in arg.args]
224
+ arg_string = ", ".join(args)
225
+ return f"""@{arg.name}({arg_string})"""
226
+
201
227
  @to_string.register
202
228
  def _(self, arg: "Parenthetical"):
203
229
  return f"""({self.to_string(arg.content)})"""
@@ -210,6 +236,11 @@ class Renderer:
210
236
  def _(self, arg: "NumericType"):
211
237
  return f"""Numeric({arg.precision},{arg.scale})"""
212
238
 
239
+ @to_string.register
240
+ def _(self, arg: TraitDataType):
241
+ traits = "::".join([x for x in arg.traits])
242
+ return f"{self.to_string(arg.data_type)}::{traits}"
243
+
213
244
  @to_string.register
214
245
  def _(self, arg: ListWrapper):
215
246
  return "[" + ", ".join([self.to_string(x) for x in arg]) + "]"
@@ -180,6 +180,7 @@
180
180
  map_key_access: expr "[" string_lit "]"
181
181
  attr_access: expr "." string_lit
182
182
 
183
+
183
184
  expr: _constant_functions | window_item | filter_item | subselect_comparison | between_comparison | fgroup | aggregate_functions | unnest | union | _static_functions | literal | concept_lit | index_access | map_key_access | attr_access | parenthetical | expr_tuple | comparison | alt_like | custom_function
184
185
 
185
186
  // functions
@@ -191,8 +192,9 @@
191
192
  fmod: ( "mod"i "(" expr "," (int_lit | concept_lit ) ")") | ( expr "%" (int_lit | concept_lit ) )
192
193
  fround: "round"i "(" expr "," expr ")"
193
194
  fabs: "abs"i "(" expr ")"
195
+ fsqrt: "sqrt"i "(" expr ")"
194
196
 
195
- _math_functions: fmul | fdiv | fadd | fsub | fround | fmod | fabs
197
+ _math_functions: fmul | fdiv | fadd | fsub | fround | fmod | fabs | fsqrt
196
198
 
197
199
  //generic
198
200
  _fcast_primary: "cast"i "(" expr "as"i data_type ")"
@@ -306,7 +308,7 @@
306
308
  custom_function: "@" IDENTIFIER "(" (expr ",")* expr ")"
307
309
 
308
310
  // base language constructs
309
- concept_lit: IDENTIFIER
311
+ concept_lit: MINUS? IDENTIFIER
310
312
  IDENTIFIER: /[a-zA-Z\_][a-zA-Z0-9\_\.]*/
311
313
  WILDCARD_IDENTIFIER: /[a-zA-Z\_][a-zA-Z0-9\_\-\.\*]*/
312
314
  QUOTED_IDENTIFIER: /`[a-zA-Z\_][a-zA-Z0-9\_\.\-\*\:\s]*`/
@@ -1,10 +1,10 @@
1
1
 
2
2
 
3
3
  ## us types
4
- type us_state string; # US state abbreviation
5
- type us_zip_code string; # US ZIP code
6
- type us_state string; # US state name
4
+ type us_state_short string; # US state abbreviation - ex MA, CA, NY
5
+ type us_state string; # US state name - ex Massachusetts, California, New York
7
6
 
7
+ type us_zip_code string; # US ZIP code
8
8
 
9
9
  ## generic types
10
10
  type latitude float; # Latitude in degrees