sql-glider 0.1.7__tar.gz → 0.1.9__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.
- {sql_glider-0.1.7 → sql_glider-0.1.9}/PKG-INFO +1 -1
- {sql_glider-0.1.7 → sql_glider-0.1.9}/src/sqlglider/_version.py +2 -2
- {sql_glider-0.1.7 → sql_glider-0.1.9}/src/sqlglider/graph/builder.py +3 -3
- {sql_glider-0.1.7 → sql_glider-0.1.9}/src/sqlglider/graph/serialization.py +5 -5
- {sql_glider-0.1.7 → sql_glider-0.1.9}/src/sqlglider/lineage/analyzer.py +22 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/tests/sqlglider/graph/test_query.py +2 -2
- {sql_glider-0.1.7 → sql_glider-0.1.9}/tests/sqlglider/lineage/test_analyzer.py +86 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/.github/workflows/ci.yml +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/.github/workflows/publish.yml +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/.gitignore +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/.python-version +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/ARCHITECTURE.md +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/CLAUDE.md +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/LICENSE +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/README.md +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/plans/2025-12-05-column-level-lineage.md +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/plans/2025-12-05-reverse-lineage.md +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/plans/2025-12-06-config-file-support.md +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/plans/2025-12-06-graph-lineage.md +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/plans/2025-12-06-unify-single-multi-query.md +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/plans/2025-12-07-sample-data-model.md +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/plans/2025-12-07-sql-templating.md +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/plans/2025-12-08-tables-command.md +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/plans/2025-12-09-graph-query-paths.md +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/plans/2025-12-13-dissect-command.md +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/plans/2025-12-14-tables-pull-command.md +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/plans/2026-01-25-fix-union-lineage-chain.md +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/plans/2026-01-26-file-scoped-schema-context.md +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/pyproject.toml +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/sample_data_model/README.md +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/sample_data_model/business/expire_dim_customer.sql +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/sample_data_model/business/load_fact_orders.sql +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/sample_data_model/business/load_fact_payments.sql +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/sample_data_model/business/merge_dim_customer.sql +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/sample_data_model/business/merge_dim_product.sql +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/sample_data_model/business/update_dim_customer_metrics.sql +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/sample_data_model/complex/conditional_merge.sql +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/sample_data_model/complex/cte_insert.sql +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/sample_data_model/complex/multi_table_transform.sql +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/sample_data_model/ddl/dim_customer.sql +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/sample_data_model/ddl/dim_product.sql +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/sample_data_model/ddl/fact_orders.sql +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/sample_data_model/ddl/fact_payments.sql +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/sample_data_model/ddl/raw_addresses.sql +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/sample_data_model/ddl/raw_customers.sql +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/sample_data_model/ddl/raw_order_items.sql +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/sample_data_model/ddl/raw_orders.sql +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/sample_data_model/ddl/raw_payments.sql +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/sample_data_model/ddl/raw_products.sql +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/sample_data_model/ddl/stg_customers.sql +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/sample_data_model/ddl/stg_orders.sql +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/sample_data_model/ddl/stg_payments.sql +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/sample_data_model/ddl/stg_products.sql +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/sample_data_model/incremental/incr_fact_orders.sql +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/sample_data_model/incremental/incr_fact_payments.sql +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/sample_data_model/incremental/incr_pres_sales_summary.sql +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/sample_data_model/maintenance/delete_expired_customers.sql +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/sample_data_model/maintenance/update_product_status.sql +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/sample_data_model/presentation/load_pres_customer_360.sql +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/sample_data_model/presentation/load_pres_customer_cohort.sql +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/sample_data_model/presentation/load_pres_product_performance.sql +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/sample_data_model/presentation/load_pres_sales_summary.sql +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/sample_data_model/staging/load_stg_customers.sql +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/sample_data_model/staging/load_stg_orders.sql +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/sample_data_model/staging/load_stg_payments.sql +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/sample_data_model/staging/load_stg_products.sql +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/sqlglider.toml.example +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/src/sqlglider/__init__.py +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/src/sqlglider/catalog/__init__.py +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/src/sqlglider/catalog/base.py +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/src/sqlglider/catalog/databricks.py +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/src/sqlglider/catalog/registry.py +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/src/sqlglider/cli.py +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/src/sqlglider/dissection/__init__.py +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/src/sqlglider/dissection/analyzer.py +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/src/sqlglider/dissection/formatters.py +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/src/sqlglider/dissection/models.py +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/src/sqlglider/global_models.py +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/src/sqlglider/graph/__init__.py +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/src/sqlglider/graph/merge.py +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/src/sqlglider/graph/models.py +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/src/sqlglider/graph/query.py +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/src/sqlglider/lineage/__init__.py +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/src/sqlglider/lineage/formatters.py +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/src/sqlglider/templating/__init__.py +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/src/sqlglider/templating/base.py +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/src/sqlglider/templating/jinja.py +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/src/sqlglider/templating/registry.py +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/src/sqlglider/templating/variables.py +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/src/sqlglider/utils/__init__.py +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/src/sqlglider/utils/config.py +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/src/sqlglider/utils/file_utils.py +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/tests/__init__.py +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/tests/fixtures/multi_file_queries/analytics_pipeline.sql +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/tests/fixtures/multi_file_queries/analytics_pipeline_union_merge.sql +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/tests/fixtures/multi_file_queries/customers.sql +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/tests/fixtures/multi_file_queries/orders.sql +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/tests/fixtures/multi_file_queries/reports.sql +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/tests/fixtures/multi_file_queries/view_based_merge.sql +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/tests/fixtures/original_queries/test_cte.sql +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/tests/fixtures/original_queries/test_cte_query.sql +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/tests/fixtures/original_queries/test_cte_view_star.sql +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/tests/fixtures/original_queries/test_generated_column_query.sql +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/tests/fixtures/original_queries/test_multi.sql +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/tests/fixtures/original_queries/test_multi_query.sql +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/tests/fixtures/original_queries/test_single_query.sql +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/tests/fixtures/original_queries/test_subquery.sql +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/tests/fixtures/original_queries/test_tables.sql +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/tests/fixtures/original_queries/test_view.sql +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/tests/fixtures/original_queries/test_view_window_cte.sql +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/tests/fixtures/sample_manifest.csv +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/tests/sqlglider/__init__.py +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/tests/sqlglider/catalog/__init__.py +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/tests/sqlglider/catalog/test_base.py +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/tests/sqlglider/catalog/test_databricks.py +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/tests/sqlglider/catalog/test_registry.py +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/tests/sqlglider/dissection/__init__.py +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/tests/sqlglider/dissection/test_analyzer.py +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/tests/sqlglider/dissection/test_formatters.py +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/tests/sqlglider/dissection/test_models.py +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/tests/sqlglider/graph/__init__.py +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/tests/sqlglider/graph/test_builder.py +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/tests/sqlglider/graph/test_merge.py +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/tests/sqlglider/graph/test_models.py +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/tests/sqlglider/graph/test_serialization.py +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/tests/sqlglider/lineage/__init__.py +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/tests/sqlglider/lineage/test_formatters.py +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/tests/sqlglider/templating/__init__.py +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/tests/sqlglider/templating/test_base.py +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/tests/sqlglider/templating/test_jinja.py +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/tests/sqlglider/templating/test_registry.py +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/tests/sqlglider/templating/test_variables.py +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/tests/sqlglider/test_cli.py +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/tests/sqlglider/utils/__init__.py +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/tests/sqlglider/utils/test_config.py +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/tests/sqlglider/utils/test_file_utils.py +0 -0
- {sql_glider-0.1.7 → sql_glider-0.1.9}/uv.lock +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sql-glider
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.9
|
|
4
4
|
Summary: SQL Utility Toolkit for better understanding, use, and governance of your queries in a native environment.
|
|
5
5
|
Project-URL: Homepage, https://github.com/rycowhi/sql-glider/
|
|
6
6
|
Project-URL: Repository, https://github.com/rycowhi/sql-glider/
|
|
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
|
|
|
28
28
|
commit_id: COMMIT_ID
|
|
29
29
|
__commit_id__: COMMIT_ID
|
|
30
30
|
|
|
31
|
-
__version__ = version = '0.1.
|
|
32
|
-
__version_tuple__ = version_tuple = (0, 1,
|
|
31
|
+
__version__ = version = '0.1.9'
|
|
32
|
+
__version_tuple__ = version_tuple = (0, 1, 9)
|
|
33
33
|
|
|
34
34
|
__commit_id__ = commit_id = None
|
|
@@ -117,8 +117,8 @@ class GraphBuilder:
|
|
|
117
117
|
edge_key = (item.source_name.lower(), item.output_name.lower())
|
|
118
118
|
if edge_key not in self._edge_set:
|
|
119
119
|
edge = GraphEdge(
|
|
120
|
-
source_node=item.source_name,
|
|
121
|
-
target_node=item.output_name,
|
|
120
|
+
source_node=item.source_name.lower(),
|
|
121
|
+
target_node=item.output_name.lower(),
|
|
122
122
|
file_path=file_path_str,
|
|
123
123
|
query_index=query_index,
|
|
124
124
|
)
|
|
@@ -285,7 +285,7 @@ class GraphBuilder:
|
|
|
285
285
|
return self._node_index_map[key]
|
|
286
286
|
|
|
287
287
|
node = GraphNode.from_identifier(
|
|
288
|
-
identifier=
|
|
288
|
+
identifier=key,
|
|
289
289
|
file_path=file_path,
|
|
290
290
|
query_index=query_index,
|
|
291
291
|
)
|
|
@@ -61,15 +61,15 @@ def to_rustworkx(graph: LineageGraph) -> Tuple[rx.PyDiGraph, Dict[str, int]]:
|
|
|
61
61
|
rx_graph: rx.PyDiGraph = rx.PyDiGraph()
|
|
62
62
|
node_map: Dict[str, int] = {}
|
|
63
63
|
|
|
64
|
-
# Add nodes
|
|
64
|
+
# Add nodes (use lowercase keys for case-insensitive lookup)
|
|
65
65
|
for node in graph.nodes:
|
|
66
66
|
idx = rx_graph.add_node(node.model_dump())
|
|
67
|
-
node_map[node.identifier] = idx
|
|
67
|
+
node_map[node.identifier.lower()] = idx
|
|
68
68
|
|
|
69
|
-
# Add edges
|
|
69
|
+
# Add edges (use lowercase for lookup to match node keys)
|
|
70
70
|
for edge in graph.edges:
|
|
71
|
-
source_idx = node_map.get(edge.source_node)
|
|
72
|
-
target_idx = node_map.get(edge.target_node)
|
|
71
|
+
source_idx = node_map.get(edge.source_node.lower())
|
|
72
|
+
target_idx = node_map.get(edge.target_node.lower())
|
|
73
73
|
if source_idx is not None and target_idx is not None:
|
|
74
74
|
rx_graph.add_edge(source_idx, target_idx, edge.model_dump())
|
|
75
75
|
|
|
@@ -615,6 +615,12 @@ class LineageAnalyzer:
|
|
|
615
615
|
if isinstance(target, exp.Table):
|
|
616
616
|
return (self._get_qualified_table_name(target), ObjectType.UNKNOWN)
|
|
617
617
|
|
|
618
|
+
# CACHE TABLE
|
|
619
|
+
elif isinstance(self.expr, exp.Cache):
|
|
620
|
+
target = self.expr.this
|
|
621
|
+
if isinstance(target, exp.Table):
|
|
622
|
+
return (self._get_qualified_table_name(target), ObjectType.TABLE)
|
|
623
|
+
|
|
618
624
|
# DELETE FROM table
|
|
619
625
|
elif isinstance(self.expr, exp.Delete):
|
|
620
626
|
target = self.expr.this
|
|
@@ -706,6 +712,10 @@ class LineageAnalyzer:
|
|
|
706
712
|
elif isinstance(self.expr, exp.Drop):
|
|
707
713
|
return table_node is self.expr.this
|
|
708
714
|
|
|
715
|
+
# For CACHE TABLE, the target is self.expr.this
|
|
716
|
+
elif isinstance(self.expr, exp.Cache):
|
|
717
|
+
return table_node is self.expr.this
|
|
718
|
+
|
|
709
719
|
return False
|
|
710
720
|
|
|
711
721
|
def _analyze_column_lineage_internal(
|
|
@@ -889,6 +899,7 @@ class LineageAnalyzer:
|
|
|
889
899
|
"Drop": f"DROP {getattr(target_expr, 'kind', '')}".strip(),
|
|
890
900
|
"Alter": "ALTER",
|
|
891
901
|
"Truncate": "TRUNCATE",
|
|
902
|
+
"Cache": "CACHE TABLE",
|
|
892
903
|
"Command": "COMMAND",
|
|
893
904
|
}
|
|
894
905
|
|
|
@@ -943,6 +954,17 @@ class LineageAnalyzer:
|
|
|
943
954
|
):
|
|
944
955
|
return (target_name, select_node)
|
|
945
956
|
|
|
957
|
+
# Check for CACHE TABLE AS SELECT
|
|
958
|
+
elif isinstance(self.expr, exp.Cache):
|
|
959
|
+
target = self.expr.this
|
|
960
|
+
if isinstance(target, exp.Table):
|
|
961
|
+
target_name = self._get_qualified_table_name(target)
|
|
962
|
+
select_node = self.expr.expression
|
|
963
|
+
if isinstance(
|
|
964
|
+
select_node, (exp.Select, exp.Union, exp.Intersect, exp.Except)
|
|
965
|
+
):
|
|
966
|
+
return (target_name, select_node)
|
|
967
|
+
|
|
946
968
|
# Check for MERGE statement
|
|
947
969
|
elif isinstance(self.expr, exp.Merge):
|
|
948
970
|
target = self.expr.this
|
|
@@ -196,7 +196,7 @@ class TestGraphQuerierUpstream:
|
|
|
196
196
|
# Query with different case
|
|
197
197
|
result = querier.find_upstream("TARGET.COLUMN")
|
|
198
198
|
|
|
199
|
-
assert result.query_column == "
|
|
199
|
+
assert result.query_column == "target.column" # Normalized to lowercase
|
|
200
200
|
assert len(result) == 1
|
|
201
201
|
|
|
202
202
|
|
|
@@ -302,7 +302,7 @@ class TestGraphQuerierDownstream:
|
|
|
302
302
|
# Query with different case
|
|
303
303
|
result = querier.find_downstream("source.column")
|
|
304
304
|
|
|
305
|
-
assert result.query_column == "
|
|
305
|
+
assert result.query_column == "source.column" # Normalized to lowercase
|
|
306
306
|
assert len(result) == 1
|
|
307
307
|
|
|
308
308
|
|
|
@@ -2820,3 +2820,89 @@ class TestSemiAntiJoinColumnResolution:
|
|
|
2820
2820
|
analyzer_semi = LineageAnalyzer(sql_semi, dialect="spark")
|
|
2821
2821
|
analyzer_semi.analyze_queries(level=AnalysisLevel.COLUMN)
|
|
2822
2822
|
assert set(analyzer_semi._file_schema["v3"].keys()) == {"a"}
|
|
2823
|
+
|
|
2824
|
+
|
|
2825
|
+
class TestCacheTableStatements:
|
|
2826
|
+
"""Tests for Spark SQL CACHE TABLE statement support."""
|
|
2827
|
+
|
|
2828
|
+
def test_cache_table_as_select_column_lineage(self):
|
|
2829
|
+
"""CACHE TABLE t AS SELECT should produce lineage with t as target."""
|
|
2830
|
+
sql = """
|
|
2831
|
+
CACHE TABLE cached_customers AS
|
|
2832
|
+
SELECT customer_id, customer_name FROM customers
|
|
2833
|
+
"""
|
|
2834
|
+
analyzer = LineageAnalyzer(sql, dialect="spark")
|
|
2835
|
+
results = analyzer.analyze_queries(level=AnalysisLevel.COLUMN)
|
|
2836
|
+
|
|
2837
|
+
assert len(results) == 1
|
|
2838
|
+
output_names = [item.output_name for item in results[0].lineage_items]
|
|
2839
|
+
assert any("cached_customers" in name for name in output_names)
|
|
2840
|
+
assert any("customer_id" in name for name in output_names)
|
|
2841
|
+
assert any("customer_name" in name for name in output_names)
|
|
2842
|
+
|
|
2843
|
+
def test_cache_table_as_select_table_extraction(self):
|
|
2844
|
+
"""CACHE TABLE t AS SELECT should show cached_orders as OUTPUT table."""
|
|
2845
|
+
sql = """
|
|
2846
|
+
CACHE TABLE cached_orders AS
|
|
2847
|
+
SELECT order_id, total FROM orders
|
|
2848
|
+
"""
|
|
2849
|
+
analyzer = LineageAnalyzer(sql, dialect="spark")
|
|
2850
|
+
results = analyzer.analyze_tables()
|
|
2851
|
+
|
|
2852
|
+
assert len(results) == 1
|
|
2853
|
+
tables_by_name = {t.name: t for t in results[0].tables}
|
|
2854
|
+
|
|
2855
|
+
assert "cached_orders" in tables_by_name
|
|
2856
|
+
assert tables_by_name["cached_orders"].usage.value == "OUTPUT"
|
|
2857
|
+
assert tables_by_name["cached_orders"].object_type.value == "TABLE"
|
|
2858
|
+
|
|
2859
|
+
assert "orders" in tables_by_name
|
|
2860
|
+
assert tables_by_name["orders"].usage.value == "INPUT"
|
|
2861
|
+
|
|
2862
|
+
def test_cache_table_as_select_with_join(self):
|
|
2863
|
+
"""CACHE TABLE with a JOIN query should trace all sources."""
|
|
2864
|
+
sql = """
|
|
2865
|
+
CACHE TABLE summary AS
|
|
2866
|
+
SELECT c.customer_id, o.total
|
|
2867
|
+
FROM customers c
|
|
2868
|
+
JOIN orders o ON c.id = o.customer_id
|
|
2869
|
+
"""
|
|
2870
|
+
analyzer = LineageAnalyzer(sql, dialect="spark")
|
|
2871
|
+
results = analyzer.analyze_tables()
|
|
2872
|
+
|
|
2873
|
+
assert len(results) == 1
|
|
2874
|
+
tables_by_name = {t.name: t for t in results[0].tables}
|
|
2875
|
+
|
|
2876
|
+
assert "summary" in tables_by_name
|
|
2877
|
+
assert tables_by_name["summary"].usage.value == "OUTPUT"
|
|
2878
|
+
assert "customers" in tables_by_name
|
|
2879
|
+
assert tables_by_name["customers"].usage.value == "INPUT"
|
|
2880
|
+
assert "orders" in tables_by_name
|
|
2881
|
+
assert tables_by_name["orders"].usage.value == "INPUT"
|
|
2882
|
+
|
|
2883
|
+
def test_bare_cache_table_is_skipped(self):
|
|
2884
|
+
"""CACHE TABLE t (without AS SELECT) should be skipped."""
|
|
2885
|
+
sql = "CACHE TABLE my_table"
|
|
2886
|
+
analyzer = LineageAnalyzer(sql, dialect="spark")
|
|
2887
|
+
results = analyzer.analyze_queries(level=AnalysisLevel.COLUMN)
|
|
2888
|
+
|
|
2889
|
+
assert len(results) == 0
|
|
2890
|
+
skipped = analyzer.skipped_queries
|
|
2891
|
+
assert len(skipped) == 1
|
|
2892
|
+
assert "CACHE" in skipped[0].statement_type
|
|
2893
|
+
|
|
2894
|
+
def test_cache_table_in_multi_query(self):
|
|
2895
|
+
"""CACHE TABLE should work alongside other statements in multi-query files."""
|
|
2896
|
+
sql = """
|
|
2897
|
+
SELECT id FROM users;
|
|
2898
|
+
CACHE TABLE cached_orders AS SELECT order_id FROM orders;
|
|
2899
|
+
DELETE FROM old_data;
|
|
2900
|
+
"""
|
|
2901
|
+
analyzer = LineageAnalyzer(sql, dialect="spark")
|
|
2902
|
+
results = analyzer.analyze_queries(level=AnalysisLevel.COLUMN)
|
|
2903
|
+
|
|
2904
|
+
# SELECT and CACHE TABLE should produce results; DELETE is skipped
|
|
2905
|
+
assert len(results) == 2
|
|
2906
|
+
skipped = analyzer.skipped_queries
|
|
2907
|
+
assert len(skipped) == 1
|
|
2908
|
+
assert "DELETE" in skipped[0].statement_type
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sql_glider-0.1.7 → sql_glider-0.1.9}/sample_data_model/business/update_dim_customer_metrics.sql
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sql_glider-0.1.7 → sql_glider-0.1.9}/sample_data_model/incremental/incr_pres_sales_summary.sql
RENAMED
|
File without changes
|
{sql_glider-0.1.7 → sql_glider-0.1.9}/sample_data_model/maintenance/delete_expired_customers.sql
RENAMED
|
File without changes
|
{sql_glider-0.1.7 → sql_glider-0.1.9}/sample_data_model/maintenance/update_product_status.sql
RENAMED
|
File without changes
|
{sql_glider-0.1.7 → sql_glider-0.1.9}/sample_data_model/presentation/load_pres_customer_360.sql
RENAMED
|
File without changes
|
{sql_glider-0.1.7 → sql_glider-0.1.9}/sample_data_model/presentation/load_pres_customer_cohort.sql
RENAMED
|
File without changes
|
|
File without changes
|
{sql_glider-0.1.7 → sql_glider-0.1.9}/sample_data_model/presentation/load_pres_sales_summary.sql
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sql_glider-0.1.7 → sql_glider-0.1.9}/tests/fixtures/multi_file_queries/analytics_pipeline.sql
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sql_glider-0.1.7 → sql_glider-0.1.9}/tests/fixtures/multi_file_queries/view_based_merge.sql
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sql_glider-0.1.7 → sql_glider-0.1.9}/tests/fixtures/original_queries/test_cte_view_star.sql
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sql_glider-0.1.7 → sql_glider-0.1.9}/tests/fixtures/original_queries/test_view_window_cte.sql
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|