pytrilogy 0.0.3.19__tar.gz → 0.0.3.20__tar.gz

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.
Files changed (133) hide show
  1. {pytrilogy-0.0.3.19/pytrilogy.egg-info → pytrilogy-0.0.3.20}/PKG-INFO +2 -2
  2. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/README.md +2 -2
  3. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20/pytrilogy.egg-info}/PKG-INFO +2 -2
  4. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/tests/test_parsing.py +43 -0
  5. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/__init__.py +1 -1
  6. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/core/enums.py +1 -0
  7. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/core/models/execute.py +8 -0
  8. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/dialect/base.py +3 -0
  9. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/dialect/common.py +8 -1
  10. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/dialect/snowflake.py +3 -1
  11. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/parsing/parse_engine.py +6 -1
  12. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/LICENSE.md +0 -0
  13. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/pyproject.toml +0 -0
  14. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/pytrilogy.egg-info/SOURCES.txt +0 -0
  15. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/pytrilogy.egg-info/dependency_links.txt +0 -0
  16. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/pytrilogy.egg-info/entry_points.txt +0 -0
  17. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/pytrilogy.egg-info/requires.txt +0 -0
  18. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/pytrilogy.egg-info/top_level.txt +0 -0
  19. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/setup.cfg +0 -0
  20. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/setup.py +0 -0
  21. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/tests/test_datatypes.py +0 -0
  22. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/tests/test_declarations.py +0 -0
  23. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/tests/test_derived_concepts.py +0 -0
  24. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/tests/test_discovery_nodes.py +0 -0
  25. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/tests/test_enums.py +0 -0
  26. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/tests/test_environment.py +0 -0
  27. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/tests/test_executor.py +0 -0
  28. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/tests/test_functions.py +0 -0
  29. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/tests/test_imports.py +0 -0
  30. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/tests/test_metadata.py +0 -0
  31. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/tests/test_models.py +0 -0
  32. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/tests/test_multi_join_assignments.py +0 -0
  33. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/tests/test_parse_engine.py +0 -0
  34. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/tests/test_partial_handling.py +0 -0
  35. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/tests/test_query_processing.py +0 -0
  36. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/tests/test_query_render.py +0 -0
  37. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/tests/test_select.py +0 -0
  38. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/tests/test_show.py +0 -0
  39. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/tests/test_statements.py +0 -0
  40. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/tests/test_typing.py +0 -0
  41. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/tests/test_undefined_concept.py +0 -0
  42. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/tests/test_user_functions.py +0 -0
  43. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/tests/test_where_clause.py +0 -0
  44. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/authoring/__init__.py +0 -0
  45. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/compiler.py +0 -0
  46. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/constants.py +0 -0
  47. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/core/__init__.py +0 -0
  48. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/core/constants.py +0 -0
  49. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/core/env_processor.py +0 -0
  50. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/core/environment_helpers.py +0 -0
  51. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/core/ergonomics.py +0 -0
  52. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/core/exceptions.py +0 -0
  53. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/core/functions.py +0 -0
  54. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/core/graph_models.py +0 -0
  55. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/core/internal.py +0 -0
  56. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/core/models/__init__.py +0 -0
  57. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/core/models/author.py +0 -0
  58. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/core/models/build.py +0 -0
  59. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/core/models/build_environment.py +0 -0
  60. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/core/models/core.py +0 -0
  61. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/core/models/datasource.py +0 -0
  62. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/core/models/environment.py +0 -0
  63. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/core/optimization.py +0 -0
  64. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/core/optimizations/__init__.py +0 -0
  65. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/core/optimizations/base_optimization.py +0 -0
  66. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/core/optimizations/inline_constant.py +0 -0
  67. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/core/optimizations/inline_datasource.py +0 -0
  68. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/core/optimizations/predicate_pushdown.py +0 -0
  69. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/core/processing/__init__.py +0 -0
  70. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/core/processing/concept_strategies_v3.py +0 -0
  71. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/core/processing/graph_utils.py +0 -0
  72. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/core/processing/node_generators/__init__.py +0 -0
  73. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/core/processing/node_generators/basic_node.py +0 -0
  74. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/core/processing/node_generators/common.py +0 -0
  75. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/core/processing/node_generators/filter_node.py +0 -0
  76. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/core/processing/node_generators/group_node.py +0 -0
  77. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/core/processing/node_generators/group_to_node.py +0 -0
  78. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/core/processing/node_generators/multiselect_node.py +0 -0
  79. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/core/processing/node_generators/node_merge_node.py +0 -0
  80. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/core/processing/node_generators/rowset_node.py +0 -0
  81. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/core/processing/node_generators/select_helpers/__init__.py +0 -0
  82. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/core/processing/node_generators/select_helpers/datasource_injection.py +0 -0
  83. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/core/processing/node_generators/select_merge_node.py +0 -0
  84. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/core/processing/node_generators/select_node.py +0 -0
  85. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/core/processing/node_generators/synonym_node.py +0 -0
  86. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/core/processing/node_generators/union_node.py +0 -0
  87. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/core/processing/node_generators/unnest_node.py +0 -0
  88. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/core/processing/node_generators/window_node.py +0 -0
  89. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/core/processing/nodes/__init__.py +0 -0
  90. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/core/processing/nodes/base_node.py +0 -0
  91. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/core/processing/nodes/filter_node.py +0 -0
  92. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/core/processing/nodes/group_node.py +0 -0
  93. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/core/processing/nodes/merge_node.py +0 -0
  94. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/core/processing/nodes/select_node_v2.py +0 -0
  95. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/core/processing/nodes/union_node.py +0 -0
  96. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/core/processing/nodes/unnest_node.py +0 -0
  97. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/core/processing/nodes/window_node.py +0 -0
  98. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/core/processing/utility.py +0 -0
  99. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/core/query_processor.py +0 -0
  100. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/core/statements/__init__.py +0 -0
  101. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/core/statements/author.py +0 -0
  102. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/core/statements/build.py +0 -0
  103. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/core/statements/common.py +0 -0
  104. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/core/statements/execute.py +0 -0
  105. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/dialect/__init__.py +0 -0
  106. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/dialect/bigquery.py +0 -0
  107. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/dialect/config.py +0 -0
  108. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/dialect/dataframe.py +0 -0
  109. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/dialect/duckdb.py +0 -0
  110. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/dialect/enums.py +0 -0
  111. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/dialect/postgres.py +0 -0
  112. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/dialect/presto.py +0 -0
  113. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/dialect/sql_server.py +0 -0
  114. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/engine.py +0 -0
  115. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/executor.py +0 -0
  116. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/hooks/__init__.py +0 -0
  117. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/hooks/base_hook.py +0 -0
  118. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/hooks/graph_hook.py +0 -0
  119. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/hooks/query_debugger.py +0 -0
  120. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/metadata/__init__.py +0 -0
  121. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/parser.py +0 -0
  122. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/parsing/__init__.py +0 -0
  123. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/parsing/common.py +0 -0
  124. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/parsing/config.py +0 -0
  125. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/parsing/exceptions.py +0 -0
  126. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/parsing/helpers.py +0 -0
  127. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/parsing/render.py +0 -0
  128. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/parsing/trilogy.lark +0 -0
  129. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/py.typed +0 -0
  130. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/render.py +0 -0
  131. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/scripts/__init__.py +0 -0
  132. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/scripts/trilogy.py +0 -0
  133. {pytrilogy-0.0.3.19 → pytrilogy-0.0.3.20}/trilogy/utility.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: pytrilogy
3
- Version: 0.0.3.19
3
+ Version: 0.0.3.20
4
4
  Summary: Declarative, typed query language that compiles to SQL.
5
5
  Home-page:
6
6
  Author:
@@ -44,7 +44,7 @@ pytrilogy is an experimental implementation of the Trilogy language, a higher-le
44
44
  Trilogy looks like SQL, but simpler. It's a modern SQL refresh targeted at SQL lovers who want more reusability and composability without losing the expressiveness and iterative value of SQL. It compiles to SQL - making it easy to debug or integrate into existing workflows - and can be run against any supported SQL backend.
45
45
 
46
46
  > [!TIP]
47
- > To get an overview of the language and run interactive examples, head to the [documentation](https://trilogydata.dev/).
47
+ > Try it online in a hosted [open-source studio](https://trilogydata.dev/trilogy-studio-core/). To get an overview of the language and run interactive examples, head to the [documentation](https://trilogydata.dev/).
48
48
 
49
49
  Installation: `pip install pytrilogy`
50
50
 
@@ -7,7 +7,7 @@ pytrilogy is an experimental implementation of the Trilogy language, a higher-le
7
7
  Trilogy looks like SQL, but simpler. It's a modern SQL refresh targeted at SQL lovers who want more reusability and composability without losing the expressiveness and iterative value of SQL. It compiles to SQL - making it easy to debug or integrate into existing workflows - and can be run against any supported SQL backend.
8
8
 
9
9
  > [!TIP]
10
- > To get an overview of the language and run interactive examples, head to the [documentation](https://trilogydata.dev/).
10
+ > Try it online in a hosted [open-source studio](https://trilogydata.dev/trilogy-studio-core/). To get an overview of the language and run interactive examples, head to the [documentation](https://trilogydata.dev/).
11
11
 
12
12
  Installation: `pip install pytrilogy`
13
13
 
@@ -353,4 +353,4 @@ Return generated SQL without executing.
353
353
 
354
354
  ```sql
355
355
  show <select>;
356
- ```
356
+ ```
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: pytrilogy
3
- Version: 0.0.3.19
3
+ Version: 0.0.3.20
4
4
  Summary: Declarative, typed query language that compiles to SQL.
5
5
  Home-page:
6
6
  Author:
@@ -44,7 +44,7 @@ pytrilogy is an experimental implementation of the Trilogy language, a higher-le
44
44
  Trilogy looks like SQL, but simpler. It's a modern SQL refresh targeted at SQL lovers who want more reusability and composability without losing the expressiveness and iterative value of SQL. It compiles to SQL - making it easy to debug or integrate into existing workflows - and can be run against any supported SQL backend.
45
45
 
46
46
  > [!TIP]
47
- > To get an overview of the language and run interactive examples, head to the [documentation](https://trilogydata.dev/).
47
+ > Try it online in a hosted [open-source studio](https://trilogydata.dev/trilogy-studio-core/). To get an overview of the language and run interactive examples, head to the [documentation](https://trilogydata.dev/).
48
48
 
49
49
  Installation: `pip install pytrilogy`
50
50
 
@@ -1,3 +1,5 @@
1
+ from pytest import raises
2
+
1
3
  from trilogy import Dialects
2
4
  from trilogy.constants import MagicConstants
3
5
  from trilogy.core.enums import BooleanOperator, ComparisonOperator, Purpose
@@ -661,3 +663,44 @@ select x % 10 -> x_mod_10;
661
663
 
662
664
  """
663
665
  )
666
+
667
+
668
+ def test_import_shows_source():
669
+
670
+ env = Environment(
671
+ config=EnvironmentOptions(
672
+ import_resolver=DictImportResolver(
673
+ content={
674
+ "test": """
675
+ import test_dep as test_dep;
676
+ key x int;
677
+ datasource test (
678
+ x: x)
679
+ grain(x)
680
+ query '''
681
+ select 1 as x
682
+ union all
683
+ select 11 as x
684
+ ''' TYPO
685
+ """,
686
+ "test_dep": """
687
+ key x int;
688
+ """,
689
+ }
690
+ )
691
+ )
692
+ )
693
+ assert isinstance(env.config.import_resolver, DictImportResolver)
694
+
695
+ with raises(Exception, match="Unable to import 'test', parsing error") as e:
696
+ env.parse(
697
+ """
698
+ import test;
699
+
700
+ select x % 10 -> x_mod_10;
701
+
702
+
703
+ """
704
+ )
705
+ assert "TYPO" in str(e.value)
706
+ assert 1 == 0
@@ -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.19"
7
+ __version__ = "0.0.3.20"
8
8
 
9
9
  __all__ = ["parse", "Executor", "Dialects", "Environment", "CONFIG"]
@@ -8,6 +8,7 @@ class UnnestMode(Enum):
8
8
  CROSS_APPLY = "cross_apply"
9
9
  CROSS_JOIN = "cross_join"
10
10
  CROSS_JOIN_ALIAS = "cross_join_alias"
11
+ SNOWFLAKE = "snowflake"
11
12
 
12
13
 
13
14
  class ConceptSource(Enum):
@@ -59,6 +59,14 @@ class CTE(BaseModel):
59
59
  base_name_override: Optional[str] = None
60
60
  base_alias_override: Optional[str] = None
61
61
 
62
+ @field_validator("join_derived_concepts")
63
+ def validate_join_derived_concepts(cls, v):
64
+ if len(v) > 1:
65
+ raise NotImplementedError(
66
+ "Multiple join derived concepts not yet supported."
67
+ )
68
+ return unique(v, "address")
69
+
62
70
  @property
63
71
  def identifier(self):
64
72
  return self.name
@@ -694,6 +694,7 @@ class BaseDialect:
694
694
  UnnestMode.CROSS_APPLY,
695
695
  UnnestMode.CROSS_JOIN,
696
696
  UnnestMode.CROSS_JOIN_ALIAS,
697
+ UnnestMode.SNOWFLAKE,
697
698
  ):
698
699
  # for a cross apply, derivation happens in the join
699
700
  # so we only use the alias to select
@@ -722,7 +723,9 @@ class BaseDialect:
722
723
  UnnestMode.CROSS_JOIN_ALIAS,
723
724
  UnnestMode.CROSS_JOIN,
724
725
  UnnestMode.CROSS_APPLY,
726
+ UnnestMode.SNOWFLAKE,
725
727
  ):
728
+
726
729
  source = f"{render_unnest(self.UNNEST_MODE, self.QUOTE_CHARACTER, cte.join_derived_concepts[0], self.render_concept_sql, cte)}"
727
730
  # direct - eg DUCK DB - can be directly selected inline
728
731
  elif (
@@ -25,7 +25,12 @@ def render_unnest(
25
25
  ):
26
26
  if unnest_mode == UnnestMode.CROSS_JOIN:
27
27
  return f"{render_func(concept, cte, False)} as {quote_character}{concept.safe_address}{quote_character}"
28
- return f"{render_func(concept, cte, False)} as unnest_wrapper ({quote_character}{concept.safe_address}{quote_character})"
28
+ elif unnest_mode == UnnestMode.CROSS_JOIN_ALIAS:
29
+ return f"{render_func(concept, cte, False)} as unnest_wrapper ({quote_character}{concept.safe_address}{quote_character})"
30
+ elif unnest_mode == UnnestMode.SNOWFLAKE:
31
+
32
+ return f"flatten({render_func(concept, cte, False)}) as unnest_wrapper ( unnest1, unnest2, unnest3, unnest4, {quote_character}{cte.join_derived_concepts[0].safe_address}{quote_character})"
33
+ return f"{render_func(concept, cte, False)} as {quote_character}{concept.safe_address}{quote_character}"
29
34
 
30
35
 
31
36
  def render_join_concept(
@@ -67,6 +72,8 @@ def render_join(
67
72
  return f"CROSS JOIN {render_unnest(unnest_mode, quote_character, join.concept_to_unnest, render_func, cte)}"
68
73
  if unnest_mode == UnnestMode.CROSS_JOIN_ALIAS:
69
74
  return f"CROSS JOIN {render_unnest(unnest_mode, quote_character, join.concept_to_unnest, render_func, cte)}"
75
+ if unnest_mode == UnnestMode.SNOWFLAKE:
76
+ return f"LEFT JOIN LATERAL {render_unnest(unnest_mode, quote_character, join.concept_to_unnest, render_func, cte)}"
70
77
  return f"FULL JOIN {render_unnest(unnest_mode, quote_character, join.concept_to_unnest, render_func, cte)}"
71
78
  # left_name = join.left_name
72
79
  right_name = join.right_name
@@ -30,6 +30,8 @@ FUNCTION_MAP = {
30
30
  FunctionType.QUARTER: lambda x: f"EXTRACT(QUARTER from {x[0]})",
31
31
  # math
32
32
  FunctionType.DIVIDE: lambda x: f"DIV0({x[0]},{x[1]})",
33
+ FunctionType.UNNEST: lambda x: f"table(flatten({x[0]}))",
34
+ FunctionType.ARRAY: lambda x: f"ARRAY_CONSTRUCT({', '.join(x)})",
33
35
  }
34
36
 
35
37
  FUNCTION_GRAIN_MATCH_MAP = {
@@ -83,4 +85,4 @@ class SnowflakeDialect(BaseDialect):
83
85
  }
84
86
  QUOTE_CHARACTER = '"'
85
87
  SQL_TEMPLATE = BQ_SQL_TEMPLATE
86
- UNNEST_MODE = UnnestMode.CROSS_JOIN
88
+ UNNEST_MODE = UnnestMode.SNOWFLAKE
@@ -983,7 +983,12 @@ class ParseToObjects(Transformer):
983
983
  text = self.resolve_import_address(target)
984
984
  self.text_lookup[token_lookup] = text
985
985
 
986
- raw_tokens = PARSER.parse(text)
986
+ try:
987
+ raw_tokens = PARSER.parse(text)
988
+ except Exception as e:
989
+ raise ImportError(
990
+ f"Unable to import '{target}', parsing error: {e}"
991
+ ) from e
987
992
  self.tokens[token_lookup] = raw_tokens
988
993
 
989
994
  if cache_lookup in self.parsed:
File without changes
File without changes
File without changes