Skip to content

Commit

Permalink
Merge pull request #149 from tosh2230/string-template
Browse files Browse the repository at this point in the history
Supports string.Template
  • Loading branch information
tosh2230 authored Nov 7, 2023
2 parents 8c75267 + d5d133a commit 33f2c15
Show file tree
Hide file tree
Showing 6 changed files with 340 additions and 151 deletions.
4 changes: 2 additions & 2 deletions src/stairlight/map.py
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ def add_unmapped_params(
"""
if not params:
template_str = template.get_template_str()
params = template.detect_jinja_params(template_str=template_str)
params = template.get_jinja_params(template_str=template_str)
self.unmapped.append(
{
MapKey.TEMPLATE: template,
Expand All @@ -314,7 +314,7 @@ def detect_unmapped_params(
list[str]: Unmapped parameters
"""
template_str: str = template.get_template_str()
template_params: list[str] = template.detect_jinja_params(template_str)
template_params: list[str] = template.get_jinja_params(template_str)
if not template_params:
return []

Expand Down
135 changes: 95 additions & 40 deletions src/stairlight/source/template.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import re
from abc import ABC, abstractmethod
from logging import getLogger
from string import Template as StringTemplate
from typing import Any, Iterator

from jinja2 import BaseLoader, Environment
Expand Down Expand Up @@ -125,8 +126,8 @@ def mapped(self) -> bool:
return result

@staticmethod
def detect_jinja_params(template_str: str) -> list:
"""Detect jinja parameters from template string
def get_jinja_params(template_str: str) -> list:
"""get jinja parameters from template string
Args:
template_str (str): Template string
Expand All @@ -142,18 +143,14 @@ def detect_jinja_params(template_str: str) -> list:
for param in re.findall("[^{}]+", jinja_expressions, re.IGNORECASE)
]

@staticmethod
def render_by_base_loader(
source_type: TemplateSourceType,
key: str,
def render_by_jinja(
self,
template_str: str,
params: dict[str, Any],
) -> str:
"""Render query string from template string
"""Render query string by jinja2
Args:
source_type (str): source type
key (str): key path
template_str (str): template string
params (dict[str, Any]): Jinja parameters
Expand All @@ -163,42 +160,93 @@ def render_by_base_loader(
Returns:
str: rendered query string
"""
result: str = ""
jinja_template = Environment(loader=BaseLoader()).from_string(template_str)
if not self.get_jinja_params(template_str=template_str):
return template_str

rendered_str: str = template_str
try:
result = jinja_template.render(params)
env = Environment(loader=BaseLoader())
template = env.from_string(template_str)
rendered_str = template.render(params)
except UndefinedError as undefined_error:
logger.warning(
(
f"{undefined_error.message}, "
f"source_type: {source_type}, "
f"key: {key}"
f"source_type: {self.source_type}, "
f"key: {self.key}"
)
)
result = template_str
return result
return rendered_str

@staticmethod
def ignore_params_from_template_str(
template_str: str, ignore_params: list[str]
def render_by_string_template(
self,
template_str: str,
params: dict[str, Any],
) -> str:
"""ignore parameters from template string
"""_summary_
Args:
template_str (str): template string
params (dict[str, Any]): mapping dict
Returns:
str: rendered query string
"""
s = StringTemplate(template=template_str)

try:
rendered_str = s.substitute(params)
except KeyError as e:
logger.warning(
(
f"{e.with_traceback}, "
f"source_type: {self.source_type}, "
f"key: {self.key}"
)
)
rendered_str = s.safe_substitute(params)
return rendered_str

@staticmethod
def ignore_jinja_params(template_str: str, ignore_params: list[str]) -> str:
"""ignore jinja parameters
Args:
template_str (str): template string
ignore_params (list[str]): ignore parameters
Returns:
str: replaced template string
str: ignored template string
"""
if not ignore_params:
ignore_params = []
replaced_str = template_str
return template_str

ignored_str = template_str
for ignore_param in ignore_params:
replaced_str = replaced_str.replace(
ignored_str = ignored_str.replace(
"{{{{ {} }}}}".format(ignore_param), "ignored"
)
return replaced_str
return ignored_str

@staticmethod
def ignore_string_template_params(
template_str: str, ignore_params: list[str]
) -> str:
"""ignore string.Template parameters
Args:
template_str (str): template string
ignore_params (list[str]): ignore parameters
Returns:
str: ignored template string
"""
if not ignore_params:
return template_str

s = StringTemplate(template=template_str)
ignore_mapping = {k: "ignored" for k in ignore_params}
return s.safe_substitute(ignore_mapping)

@abstractmethod
def get_uri(self) -> str:
Expand All @@ -218,23 +266,30 @@ def render(self, params: dict[str, Any], ignore_params: list[str] = None) -> str
Returns:
str: Query statement
"""
if not ignore_params:
ignore_params = []
template_str = self.get_template_str()
replaced_template_str = self.ignore_params_from_template_str(
template_str=template_str,
rendered_str = self.get_template_str()
rendered_str = self.ignore_jinja_params(
template_str=rendered_str,
ignore_params=ignore_params,
)
if params:
results = self.render_by_base_loader(
source_type=self.source_type,
key=self.key,
template_str=replaced_template_str,
params=params,
)
else:
results = replaced_template_str
return results
rendered_str = self.ignore_string_template_params(
template_str=rendered_str,
ignore_params=ignore_params,
)

if not params:
return rendered_str

rendered_str = self.render_by_jinja(
template_str=rendered_str,
params=params,
)

rendered_str = self.render_by_string_template(
template_str=rendered_str,
params=params,
)

return rendered_str


class RenderingTemplateException(Exception):
Expand Down
38 changes: 38 additions & 0 deletions tests/sql/cte_multi_line_identifiers.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
WITH c AS (
SELECT
test_id,
col_c
FROM
$sub_table_01
WHERE
0 = 0
),
d AS (
SELECT
test_id,
col_d
FROM
${sub_table_02}
WHERE
0 = 0
),
e AS (
SELECT
test_id,
col_d
FROM
$sub_table_02
WHERE
0 = 0
)

SELECT
*
FROM
${main_table} AS b
INNER JOIN c
ON b.test_id = c.test_id
INNER JOIN d
ON b.test_id = d.test_id
WHERE
1 = 1
Loading

0 comments on commit 33f2c15

Please sign in to comment.