Skip to content

Commit e500074

Browse files
committed
Fix regex LHS capture and inline join state leakage
P1: Regex rewrite used \S+ for LHS, truncating expressions with spaces/parens like (first || ' ' || last) ~ r'x'. Changed to .+? to capture the full left-hand expression. P2: Inline join source extraction didn't save/restore _timezone, _model_tags, _accept_fields, _except_fields. If the inline source had timezone: or # annotations, they leaked into the parent model.
1 parent bf9e0dd commit e500074

1 file changed

Lines changed: 18 additions & 5 deletions

File tree

sidemantic/adapters/malloy.py

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -328,19 +328,20 @@ def _transform_malloy_expr(self, expr: str) -> str:
328328
expr = re.sub(r"(\w+)!\w+\(", r"\1(", expr)
329329

330330
# ~ regex match with r'' literal: expr ~ r'pattern' -> REGEXP_MATCHES(expr, 'pattern')
331+
# Use (.+?) with lookahead to capture full LHS including spaces/parens
331332
expr = re.sub(
332-
r"(\S+)\s+~\s+r'([^']*)'",
333+
r"(.+?)\s+~\s+r'([^']*)'",
333334
r"REGEXP_MATCHES(\1, '\2')",
334335
expr,
335336
)
336337
expr = re.sub(
337-
r'(\S+)\s+~\s+r"([^"]*)"',
338+
r'(.+?)\s+~\s+r"([^"]*)"',
338339
r"REGEXP_MATCHES(\1, '\2')",
339340
expr,
340341
)
341342
# !~ negated regex
342343
expr = re.sub(
343-
r"(\S+)\s+!~\s+r'([^']*)'",
344+
r"(.+?)\s+!~\s+r'([^']*)'",
344345
r"NOT REGEXP_MATCHES(\1, '\2')",
345346
expr,
346347
)
@@ -1116,7 +1117,7 @@ def _extract_inline_join_source(self, join_name: str, sq_expr):
11161117
11171118
Handles: join_one: name is connection.table(...) extend { ... } with fk
11181119
"""
1119-
# Save current state
1120+
# Save current state (including metadata accumulators)
11201121
saved = (
11211122
self.current_model_name,
11221123
self.current_table,
@@ -1129,6 +1130,10 @@ def _extract_inline_join_source(self, join_name: str, sq_expr):
11291130
list(self.current_metrics),
11301131
list(self.current_relationships),
11311132
list(self.current_segments),
1133+
self._timezone,
1134+
list(self._model_tags),
1135+
list(self._accept_fields),
1136+
list(self._except_fields),
11321137
)
11331138

11341139
# Reset and process the inline source
@@ -1143,6 +1148,10 @@ def _extract_inline_join_source(self, join_name: str, sq_expr):
11431148
self.current_metrics = []
11441149
self.current_relationships = []
11451150
self.current_segments = []
1151+
self._timezone = None
1152+
self._model_tags = []
1153+
self._accept_fields = []
1154+
self._except_fields = []
11461155

11471156
self._process_sq_expr(sq_expr)
11481157

@@ -1166,7 +1175,7 @@ def _extract_inline_join_source(self, join_name: str, sq_expr):
11661175
)
11671176
self.models.append(inline_model)
11681177

1169-
# Restore state
1178+
# Restore state (including metadata accumulators)
11701179
(
11711180
self.current_model_name,
11721181
self.current_table,
@@ -1179,6 +1188,10 @@ def _extract_inline_join_source(self, join_name: str, sq_expr):
11791188
self.current_metrics,
11801189
self.current_relationships,
11811190
self.current_segments,
1191+
self._timezone,
1192+
self._model_tags,
1193+
self._accept_fields,
1194+
self._except_fields,
11821195
) = saved
11831196

11841197
def _process_where_as_segment(self, ctx: MalloyParser.WhereStatementContext):

0 commit comments

Comments
 (0)