pytrilogy 0.0.2.35__py3-none-any.whl → 0.0.2.37__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.
- {pytrilogy-0.0.2.35.dist-info → pytrilogy-0.0.2.37.dist-info}/METADATA +1 -1
- {pytrilogy-0.0.2.35.dist-info → pytrilogy-0.0.2.37.dist-info}/RECORD +14 -14
- {pytrilogy-0.0.2.35.dist-info → pytrilogy-0.0.2.37.dist-info}/WHEEL +1 -1
- trilogy/__init__.py +1 -1
- trilogy/constants.py +8 -0
- trilogy/core/models.py +22 -17
- trilogy/dialect/base.py +8 -1
- trilogy/executor.py +78 -8
- trilogy/parsing/parse_engine.py +6 -2
- trilogy/parsing/render.py +9 -3
- trilogy/parsing/trilogy.lark +3 -2
- {pytrilogy-0.0.2.35.dist-info → pytrilogy-0.0.2.37.dist-info}/LICENSE.md +0 -0
- {pytrilogy-0.0.2.35.dist-info → pytrilogy-0.0.2.37.dist-info}/entry_points.txt +0 -0
- {pytrilogy-0.0.2.35.dist-info → pytrilogy-0.0.2.37.dist-info}/top_level.txt +0 -0
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
trilogy/__init__.py,sha256=
|
|
1
|
+
trilogy/__init__.py,sha256=Keq-D-sl-p9mpGadAtrLKltDPbZTIiu4FdY6d8qJ4kk,291
|
|
2
2
|
trilogy/compiler.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
-
trilogy/constants.py,sha256=
|
|
3
|
+
trilogy/constants.py,sha256=UPymm94T2c6a55XdDaXw0aleTe1pOJ6lf6gOWLKZyKg,1430
|
|
4
4
|
trilogy/engine.py,sha256=R5ubIxYyrxRExz07aZCUfrTsoXCHQ8DKFTDsobXdWdA,1102
|
|
5
|
-
trilogy/executor.py,sha256=
|
|
5
|
+
trilogy/executor.py,sha256=FXxtBOAFFPY20fsyoDeLHr7DWHHBxxCOnQwpSeyODzI,14757
|
|
6
6
|
trilogy/parser.py,sha256=UtuqSiGiCjpMAYgo1bvNq-b7NSzCA5hzbUW31RXaMII,281
|
|
7
7
|
trilogy/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
8
8
|
trilogy/utility.py,sha256=zM__8r29EsyDW7K9VOHz8yvZC2bXFzh7xKy3cL7GKsk,707
|
|
@@ -16,7 +16,7 @@ trilogy/core/exceptions.py,sha256=NvV_4qLOgKXbpotgRf7c8BANDEvHxlqRPaA53IThQ2o,56
|
|
|
16
16
|
trilogy/core/functions.py,sha256=IhVpt3n6wEanKHnGu3oA2w6-hKIlxWpEyz7fHN66mpo,10720
|
|
17
17
|
trilogy/core/graph_models.py,sha256=mameUTiuCajtihDw_2-W218xyJlvTusOWrEKP1yAWgk,2003
|
|
18
18
|
trilogy/core/internal.py,sha256=jNGFHKENnbMiMCtAgsnLZYVSENDK4b5ALecXFZpTDzQ,1075
|
|
19
|
-
trilogy/core/models.py,sha256=
|
|
19
|
+
trilogy/core/models.py,sha256=GMqdaZ7FgNYsoNDPKoSWt1Xxxk2SJYBNk2yPazhIHzQ,162855
|
|
20
20
|
trilogy/core/optimization.py,sha256=VFSvJLNoCCOraip-PZUKeE4qrlxtXARjQUzJZiW-yRk,7325
|
|
21
21
|
trilogy/core/query_processor.py,sha256=mbcZlgjChrRjDHkdmMbKe-T70UpbBkJhS09MyU5a6UY,17785
|
|
22
22
|
trilogy/core/optimizations/__init__.py,sha256=bWQecbeiwiDx9LJnLsa7dkWxdbl2wcnkcTN69JyP8iI,356
|
|
@@ -50,7 +50,7 @@ trilogy/core/processing/nodes/select_node_v2.py,sha256=7WoFxeGEAzhpS4y4Zw2nH2tt7
|
|
|
50
50
|
trilogy/core/processing/nodes/unnest_node.py,sha256=mAmFluzm2yeeiQ6NfIB7BU_8atRGh-UJfPf9ROwbhr8,2152
|
|
51
51
|
trilogy/core/processing/nodes/window_node.py,sha256=ro0QfMFi4ZmIn5Q4D0M_vJWfnHH_C0MN7XkVkx8Gygg,1214
|
|
52
52
|
trilogy/dialect/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
53
|
-
trilogy/dialect/base.py,sha256=
|
|
53
|
+
trilogy/dialect/base.py,sha256=wkK8NESHfko7bUavaMFvJHzaGNoHd3r03j-kfIyD4bY,34626
|
|
54
54
|
trilogy/dialect/bigquery.py,sha256=15KJ-cOpBlk9O7FPviPgmg8xIydJeKx7WfmL3SSsPE8,2953
|
|
55
55
|
trilogy/dialect/common.py,sha256=eqJi_Si1iyb2sV0siTf8g8JOHueWu6RkdtQZtutKazk,3826
|
|
56
56
|
trilogy/dialect/config.py,sha256=tLVEMctaTDhUgARKXUNfHUcIolGaALkQ0RavUvXAY4w,2994
|
|
@@ -70,14 +70,14 @@ trilogy/parsing/common.py,sha256=_GW9LU6_4RuUgcdcr8EE1ybCRd-7cz3idZtjHZ66pYA,101
|
|
|
70
70
|
trilogy/parsing/config.py,sha256=Z-DaefdKhPDmSXLgg5V4pebhSB0h590vI0_VtHnlukI,111
|
|
71
71
|
trilogy/parsing/exceptions.py,sha256=92E5i2frv5hj9wxObJZsZqj5T6bglvPzvdvco_vW1Zk,38
|
|
72
72
|
trilogy/parsing/helpers.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
73
|
-
trilogy/parsing/parse_engine.py,sha256=
|
|
74
|
-
trilogy/parsing/render.py,sha256=
|
|
75
|
-
trilogy/parsing/trilogy.lark,sha256=
|
|
73
|
+
trilogy/parsing/parse_engine.py,sha256=9qmfqpibuIlTDrI_ywGAe2A_BgiRaU2zrec_BJaOu6k,63945
|
|
74
|
+
trilogy/parsing/render.py,sha256=dhHkwmZ5HNNJr-z81JDpN2TBe4Ktqarus5vtMn2-_B8,15502
|
|
75
|
+
trilogy/parsing/trilogy.lark,sha256=IZ-uSyTkjHtyqqYEH9fomM7yomCvP6AdH8wJSjPAuHc,12338
|
|
76
76
|
trilogy/scripts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
77
77
|
trilogy/scripts/trilogy.py,sha256=PHxvv6f2ODv0esyyhWxlARgra8dVhqQhYl0lTrSyVNo,3729
|
|
78
|
-
pytrilogy-0.0.2.
|
|
79
|
-
pytrilogy-0.0.2.
|
|
80
|
-
pytrilogy-0.0.2.
|
|
81
|
-
pytrilogy-0.0.2.
|
|
82
|
-
pytrilogy-0.0.2.
|
|
83
|
-
pytrilogy-0.0.2.
|
|
78
|
+
pytrilogy-0.0.2.37.dist-info/LICENSE.md,sha256=5ZRvtTyCCFwz1THxDTjAu3Lidds9WjPvvzgVwPSYNDo,1042
|
|
79
|
+
pytrilogy-0.0.2.37.dist-info/METADATA,sha256=7Metihqd20_keAEEW5_7V3iQDhCG61TCCKNG8hI-d1s,8424
|
|
80
|
+
pytrilogy-0.0.2.37.dist-info/WHEEL,sha256=R06PA3UVYHThwHvxuRWMqaGcr-PuniXahwjmQRFMEkY,91
|
|
81
|
+
pytrilogy-0.0.2.37.dist-info/entry_points.txt,sha256=0petKryjvvtEfTlbZC1AuMFumH_WQ9v8A19LvoS6G6c,54
|
|
82
|
+
pytrilogy-0.0.2.37.dist-info/top_level.txt,sha256=cAy__NW_eMAa_yT9UnUNlZLFfxcg6eimUAZ184cdNiE,8
|
|
83
|
+
pytrilogy-0.0.2.37.dist-info/RECORD,,
|
trilogy/__init__.py
CHANGED
trilogy/constants.py
CHANGED
|
@@ -39,6 +39,13 @@ class Comments:
|
|
|
39
39
|
partial: bool = True
|
|
40
40
|
|
|
41
41
|
|
|
42
|
+
@dataclass
|
|
43
|
+
class Rendering:
|
|
44
|
+
"""Control how the SQL is rendered"""
|
|
45
|
+
|
|
46
|
+
parameters: bool = True
|
|
47
|
+
|
|
48
|
+
|
|
42
49
|
# TODO: support loading from environments
|
|
43
50
|
@dataclass
|
|
44
51
|
class Config:
|
|
@@ -48,6 +55,7 @@ class Config:
|
|
|
48
55
|
validate_missing: bool = True
|
|
49
56
|
comments: Comments = field(default_factory=Comments)
|
|
50
57
|
optimizations: Optimizations = field(default_factory=Optimizations)
|
|
58
|
+
rendering: Rendering = field(default_factory=Rendering)
|
|
51
59
|
|
|
52
60
|
@property
|
|
53
61
|
def show_comments(self) -> bool:
|
trilogy/core/models.py
CHANGED
|
@@ -3276,7 +3276,7 @@ class EnvironmentConceptDict(dict):
|
|
|
3276
3276
|
return default
|
|
3277
3277
|
|
|
3278
3278
|
def __getitem__(
|
|
3279
|
-
self, key, line_no: int | None = None
|
|
3279
|
+
self, key, line_no: int | None = None, file: Path | None = None
|
|
3280
3280
|
) -> Concept | UndefinedConcept:
|
|
3281
3281
|
try:
|
|
3282
3282
|
return super(EnvironmentConceptDict, self).__getitem__(key)
|
|
@@ -3304,6 +3304,10 @@ class EnvironmentConceptDict(dict):
|
|
|
3304
3304
|
message += f" Suggestions: {matches}"
|
|
3305
3305
|
|
|
3306
3306
|
if line_no:
|
|
3307
|
+
if file:
|
|
3308
|
+
raise UndefinedConceptException(
|
|
3309
|
+
f"{file}: {line_no}: " + message, matches
|
|
3310
|
+
)
|
|
3307
3311
|
raise UndefinedConceptException(f"line: {line_no}: " + message, matches)
|
|
3308
3312
|
raise UndefinedConceptException(message, matches)
|
|
3309
3313
|
|
|
@@ -3377,6 +3381,21 @@ class Environment(BaseModel):
|
|
|
3377
3381
|
materialized_concepts: List[Concept] = Field(default_factory=list)
|
|
3378
3382
|
alias_origin_lookup: Dict[str, Concept] = Field(default_factory=dict)
|
|
3379
3383
|
|
|
3384
|
+
def __init__(self, **data):
|
|
3385
|
+
super().__init__(**data)
|
|
3386
|
+
self.concepts["_env_working_path"] = Concept(
|
|
3387
|
+
name="_env_working_path",
|
|
3388
|
+
namespace=self.namespace,
|
|
3389
|
+
lineage=Function(
|
|
3390
|
+
operator=FunctionType.CONSTANT,
|
|
3391
|
+
arguments=[str(self.working_path)],
|
|
3392
|
+
output_datatype=DataType.STRING,
|
|
3393
|
+
output_purpose=Purpose.CONSTANT,
|
|
3394
|
+
),
|
|
3395
|
+
datatype=DataType.STRING,
|
|
3396
|
+
purpose=Purpose.CONSTANT,
|
|
3397
|
+
)
|
|
3398
|
+
|
|
3380
3399
|
@classmethod
|
|
3381
3400
|
def from_file(cls, path: str | Path) -> "Environment":
|
|
3382
3401
|
with open(path, "r") as f:
|
|
@@ -3550,16 +3569,7 @@ class Environment(BaseModel):
|
|
|
3550
3569
|
target = target.with_suffix(".preql")
|
|
3551
3570
|
else:
|
|
3552
3571
|
target = path
|
|
3553
|
-
if
|
|
3554
|
-
imports = self.imports[alias]
|
|
3555
|
-
for x in imports:
|
|
3556
|
-
if x.path == target:
|
|
3557
|
-
return imports
|
|
3558
|
-
if env:
|
|
3559
|
-
self.imports[alias].append(
|
|
3560
|
-
ImportStatement(alias=alias, path=target, environment=env)
|
|
3561
|
-
)
|
|
3562
|
-
else:
|
|
3572
|
+
if not env:
|
|
3563
3573
|
parse_address = gen_cache_lookup(str(target), alias, str(self.working_path))
|
|
3564
3574
|
try:
|
|
3565
3575
|
with open(target, "r", encoding="utf-8") as f:
|
|
@@ -3583,13 +3593,8 @@ class Environment(BaseModel):
|
|
|
3583
3593
|
f"Unable to import file {target.parent}, parsing error: {e}"
|
|
3584
3594
|
)
|
|
3585
3595
|
env = nparser.environment
|
|
3586
|
-
for _, concept in env.concepts.items():
|
|
3587
|
-
self.add_concept(concept.with_namespace(alias))
|
|
3588
|
-
|
|
3589
|
-
for _, datasource in env.datasources.items():
|
|
3590
|
-
self.add_datasource(datasource.with_namespace(alias))
|
|
3591
3596
|
imps = ImportStatement(alias=alias, path=target, environment=env)
|
|
3592
|
-
self.
|
|
3597
|
+
self.add_import(alias, source=env, imp_stm=imps)
|
|
3593
3598
|
return imps
|
|
3594
3599
|
|
|
3595
3600
|
def parse(
|
trilogy/dialect/base.py
CHANGED
|
@@ -337,6 +337,13 @@ class BaseDialect:
|
|
|
337
337
|
" target grain"
|
|
338
338
|
)
|
|
339
339
|
rval = f"{self.FUNCTION_GRAIN_MATCH_MAP[c.lineage.function.operator](args)}"
|
|
340
|
+
elif (
|
|
341
|
+
isinstance(c.lineage, Function)
|
|
342
|
+
and c.lineage.operator == FunctionType.CONSTANT
|
|
343
|
+
and CONFIG.rendering.parameters is True
|
|
344
|
+
and c.datatype.data_type != DataType.MAP
|
|
345
|
+
):
|
|
346
|
+
rval = f":{c.safe_address}"
|
|
340
347
|
else:
|
|
341
348
|
args = [
|
|
342
349
|
self.render_expr(
|
|
@@ -541,7 +548,7 @@ class BaseDialect:
|
|
|
541
548
|
else:
|
|
542
549
|
raise ValueError(f"Unable to render type {type(e)} {e}")
|
|
543
550
|
|
|
544
|
-
def render_cte(self, cte: CTE, auto_sort: bool = True):
|
|
551
|
+
def render_cte(self, cte: CTE, auto_sort: bool = True) -> CompiledCTE:
|
|
545
552
|
if self.UNNEST_MODE in (
|
|
546
553
|
UnnestMode.CROSS_APPLY,
|
|
547
554
|
UnnestMode.CROSS_JOIN,
|
trilogy/executor.py
CHANGED
|
@@ -20,10 +20,16 @@ from trilogy.core.models import (
|
|
|
20
20
|
ConceptDeclarationStatement,
|
|
21
21
|
Datasource,
|
|
22
22
|
CopyStatement,
|
|
23
|
+
ImportStatement,
|
|
24
|
+
MergeStatementV2,
|
|
25
|
+
Function,
|
|
26
|
+
FunctionType,
|
|
27
|
+
MapWrapper,
|
|
28
|
+
ListWrapper,
|
|
23
29
|
)
|
|
24
30
|
from trilogy.dialect.base import BaseDialect
|
|
25
31
|
from trilogy.dialect.enums import Dialects
|
|
26
|
-
from trilogy.core.enums import IOType
|
|
32
|
+
from trilogy.core.enums import IOType, Granularity
|
|
27
33
|
from trilogy.parser import parse_text
|
|
28
34
|
from trilogy.hooks.base_hook import BaseHook
|
|
29
35
|
from pathlib import Path
|
|
@@ -104,6 +110,7 @@ class Executor(object):
|
|
|
104
110
|
ProcessedShowStatement,
|
|
105
111
|
ProcessedQueryPersist,
|
|
106
112
|
ProcessedCopyStatement,
|
|
113
|
+
ProcessedRawSQLStatement,
|
|
107
114
|
),
|
|
108
115
|
):
|
|
109
116
|
return None
|
|
@@ -142,7 +149,6 @@ class Executor(object):
|
|
|
142
149
|
|
|
143
150
|
@execute_query.register
|
|
144
151
|
def _(self, query: str) -> CursorResult:
|
|
145
|
-
|
|
146
152
|
return self.execute_text(query)[-1]
|
|
147
153
|
|
|
148
154
|
@execute_query.register
|
|
@@ -181,6 +187,34 @@ class Executor(object):
|
|
|
181
187
|
],
|
|
182
188
|
)
|
|
183
189
|
|
|
190
|
+
@execute_query.register
|
|
191
|
+
def _(self, query: ImportStatement) -> CursorResult:
|
|
192
|
+
return MockResult(
|
|
193
|
+
[
|
|
194
|
+
{
|
|
195
|
+
"path": query.path,
|
|
196
|
+
"alias": query.alias,
|
|
197
|
+
}
|
|
198
|
+
],
|
|
199
|
+
["path", "alias"],
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
@execute_query.register
|
|
203
|
+
def _(self, query: MergeStatementV2) -> CursorResult:
|
|
204
|
+
|
|
205
|
+
self.environment.merge_concept(
|
|
206
|
+
query.source, query.target, modifiers=query.modifiers
|
|
207
|
+
)
|
|
208
|
+
return MockResult(
|
|
209
|
+
[
|
|
210
|
+
{
|
|
211
|
+
"source": query.source.address,
|
|
212
|
+
"target": query.target.address,
|
|
213
|
+
}
|
|
214
|
+
],
|
|
215
|
+
["source", "target"],
|
|
216
|
+
)
|
|
217
|
+
|
|
184
218
|
@execute_query.register
|
|
185
219
|
def _(self, query: ProcessedRawSQLStatement) -> CursorResult:
|
|
186
220
|
return self.execute_raw_sql(query.text)
|
|
@@ -188,8 +222,7 @@ class Executor(object):
|
|
|
188
222
|
@execute_query.register
|
|
189
223
|
def _(self, query: ProcessedQuery) -> CursorResult:
|
|
190
224
|
sql = self.generator.compile_statement(query)
|
|
191
|
-
|
|
192
|
-
output = self.connection.execute(text(sql))
|
|
225
|
+
output = self.execute_raw_sql(sql)
|
|
193
226
|
return output
|
|
194
227
|
|
|
195
228
|
@execute_query.register
|
|
@@ -197,14 +230,14 @@ class Executor(object):
|
|
|
197
230
|
|
|
198
231
|
sql = self.generator.compile_statement(query)
|
|
199
232
|
|
|
200
|
-
output = self.
|
|
233
|
+
output = self.execute_raw_sql(sql)
|
|
201
234
|
self.environment.add_datasource(query.datasource)
|
|
202
235
|
return output
|
|
203
236
|
|
|
204
237
|
@execute_query.register
|
|
205
238
|
def _(self, query: ProcessedCopyStatement) -> CursorResult:
|
|
206
239
|
sql = self.generator.compile_statement(query)
|
|
207
|
-
output: CursorResult = self.
|
|
240
|
+
output: CursorResult = self.execute_raw_sql(sql)
|
|
208
241
|
if query.target_type == IOType.CSV:
|
|
209
242
|
import csv
|
|
210
243
|
|
|
@@ -213,7 +246,7 @@ class Executor(object):
|
|
|
213
246
|
outcsv.writerow(output.keys())
|
|
214
247
|
outcsv.writerows(output)
|
|
215
248
|
else:
|
|
216
|
-
raise NotImplementedError(f"Unsupported
|
|
249
|
+
raise NotImplementedError(f"Unsupported IO Type {query.target_type}")
|
|
217
250
|
# now return the query we ran through IO
|
|
218
251
|
# TODO: instead return how many rows were written?
|
|
219
252
|
return generate_result_set(
|
|
@@ -339,13 +372,50 @@ class Executor(object):
|
|
|
339
372
|
if persist and isinstance(x, ProcessedQueryPersist):
|
|
340
373
|
self.environment.add_datasource(x.datasource)
|
|
341
374
|
|
|
375
|
+
def _hydrate_param(self, param: str) -> Any:
|
|
376
|
+
matched = [
|
|
377
|
+
v
|
|
378
|
+
for v in self.environment.concepts.values()
|
|
379
|
+
if v.safe_address == param or v.address == param
|
|
380
|
+
]
|
|
381
|
+
if not matched:
|
|
382
|
+
raise SyntaxError(f"No concept found for parameter {param}")
|
|
383
|
+
|
|
384
|
+
concept: Concept = matched.pop()
|
|
385
|
+
if not concept.granularity == Granularity.SINGLE_ROW:
|
|
386
|
+
raise SyntaxError(f"Cannot bind non-singleton concept {concept.address}")
|
|
387
|
+
if (
|
|
388
|
+
isinstance(concept.lineage, Function)
|
|
389
|
+
and concept.lineage.operator == FunctionType.CONSTANT
|
|
390
|
+
):
|
|
391
|
+
rval = concept.lineage.arguments[0]
|
|
392
|
+
if isinstance(rval, ListWrapper):
|
|
393
|
+
return [x for x in rval]
|
|
394
|
+
if isinstance(rval, MapWrapper):
|
|
395
|
+
return {k: v for k, v in rval.items()}
|
|
396
|
+
return rval
|
|
397
|
+
else:
|
|
398
|
+
results = self.execute_query(f"select {concept.name} limit 1;").fetchone()
|
|
399
|
+
if not results:
|
|
400
|
+
return None
|
|
401
|
+
return results[0]
|
|
402
|
+
|
|
342
403
|
def execute_raw_sql(
|
|
343
404
|
self, command: str, variables: dict | None = None
|
|
344
405
|
) -> CursorResult:
|
|
345
406
|
"""Run a command against the raw underlying
|
|
346
407
|
execution engine"""
|
|
408
|
+
final_params = None
|
|
409
|
+
q = text(command)
|
|
347
410
|
if variables:
|
|
348
|
-
|
|
411
|
+
final_params = variables
|
|
412
|
+
else:
|
|
413
|
+
params = q.compile().params
|
|
414
|
+
if params:
|
|
415
|
+
final_params = {x: self._hydrate_param(x) for x in params}
|
|
416
|
+
|
|
417
|
+
if final_params:
|
|
418
|
+
return self.connection.execute(text(command), final_params)
|
|
349
419
|
return self.connection.execute(
|
|
350
420
|
text(command),
|
|
351
421
|
)
|
trilogy/parsing/parse_engine.py
CHANGED
|
@@ -302,6 +302,9 @@ class ParseToObjects(Transformer):
|
|
|
302
302
|
def IDENTIFIER(self, args) -> str:
|
|
303
303
|
return args.value
|
|
304
304
|
|
|
305
|
+
def QUOTED_IDENTIFIER(self, args) -> str:
|
|
306
|
+
return args.value[1:-1]
|
|
307
|
+
|
|
305
308
|
@v_args(meta=True)
|
|
306
309
|
def concept_lit(self, meta: Meta, args) -> Concept:
|
|
307
310
|
return self.environment.concepts.__getitem__(args[0], meta.line)
|
|
@@ -386,7 +389,7 @@ class ParseToObjects(Transformer):
|
|
|
386
389
|
modifiers += concept_list[:-1]
|
|
387
390
|
concept = concept_list[-1]
|
|
388
391
|
resolved = self.environment.concepts.__getitem__( # type: ignore
|
|
389
|
-
key=concept, line_no=meta.line
|
|
392
|
+
key=concept, line_no=meta.line, file=self.token_address
|
|
390
393
|
)
|
|
391
394
|
return ColumnAssignment(alias=alias, modifiers=modifiers, concept=resolved)
|
|
392
395
|
|
|
@@ -801,7 +804,8 @@ class ParseToObjects(Transformer):
|
|
|
801
804
|
|
|
802
805
|
@v_args(meta=True)
|
|
803
806
|
def rawsql_statement(self, meta: Meta, args) -> RawSQLStatement:
|
|
804
|
-
|
|
807
|
+
statement = RawSQLStatement(meta=Metadata(line_number=meta.line), text=args[0])
|
|
808
|
+
return statement
|
|
805
809
|
|
|
806
810
|
def COPY_TYPE(self, args) -> IOType:
|
|
807
811
|
return IOType(args.value)
|
trilogy/parsing/render.py
CHANGED
|
@@ -368,9 +368,15 @@ class Renderer:
|
|
|
368
368
|
|
|
369
369
|
@to_string.register
|
|
370
370
|
def _(self, arg: "ImportStatement"):
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
371
|
+
path: str = str(arg.path).replace("\\", ".")
|
|
372
|
+
path = path.replace("/", ".")
|
|
373
|
+
if path.endswith(".preql"):
|
|
374
|
+
path = path.rsplit(".", 1)[0]
|
|
375
|
+
if path.startswith("."):
|
|
376
|
+
path = path[1:]
|
|
377
|
+
if arg.alias == DEFAULT_NAMESPACE or not arg.alias:
|
|
378
|
+
return f"import {path};"
|
|
379
|
+
return f"import {path} as {arg.alias};"
|
|
374
380
|
|
|
375
381
|
@to_string.register
|
|
376
382
|
def _(self, arg: "Concept"):
|
trilogy/parsing/trilogy.lark
CHANGED
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
|
|
50
50
|
//column_assignment
|
|
51
51
|
//figure out if we want static
|
|
52
|
-
column_assignment: (raw_column_assignment | IDENTIFIER | _static_functions ) ":" concept_assignment
|
|
52
|
+
column_assignment: (raw_column_assignment | IDENTIFIER | QUOTED_IDENTIFIER | _static_functions ) ":" concept_assignment
|
|
53
53
|
|
|
54
54
|
RAW_ENTRY.1: /raw\s*\(/s
|
|
55
55
|
|
|
@@ -292,6 +292,7 @@
|
|
|
292
292
|
// base language constructs
|
|
293
293
|
concept_lit: IDENTIFIER
|
|
294
294
|
IDENTIFIER: /[a-zA-Z\_][a-zA-Z0-9\_\-\.]*/
|
|
295
|
+
QUOTED_IDENTIFIER: /`[a-zA-Z\_][a-zA-Z0-9\_\.\-\*\:\s]*`/
|
|
295
296
|
QUOTED_ADDRESS: /`[a-zA-Z\_][a-zA-Z0-9\_\.\-\*\:]*`/
|
|
296
297
|
ADDRESS: IDENTIFIER
|
|
297
298
|
|
|
@@ -301,7 +302,7 @@
|
|
|
301
302
|
SINGLE_STRING_CHARS: /(?:(?!\${)([^'\\]|\\.))+/+ // any character except '
|
|
302
303
|
_single_quote: "'" ( SINGLE_STRING_CHARS )* "'"
|
|
303
304
|
_double_quote: "\"" ( DOUBLE_STRING_CHARS )* "\""
|
|
304
|
-
string_lit: _single_quote | _double_quote
|
|
305
|
+
string_lit: _single_quote | _double_quote | MULTILINE_STRING
|
|
305
306
|
|
|
306
307
|
MINUS: "-"
|
|
307
308
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|