datajunction 0.0.181__tar.gz → 0.0.183__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.
- {datajunction-0.0.181 → datajunction-0.0.183}/PKG-INFO +1 -1
- {datajunction-0.0.181 → datajunction-0.0.183}/datajunction/__about__.py +1 -1
- {datajunction-0.0.181 → datajunction-0.0.183}/datajunction/cli.py +105 -37
- datajunction-0.0.183/datajunction/skills/datajunction-api.md +232 -0
- datajunction-0.0.183/datajunction/skills/datajunction-query.md +248 -0
- datajunction-0.0.183/datajunction/skills/datajunction-repo.md +692 -0
- datajunction-0.0.183/datajunction/skills/datajunction-semantic-model.md +379 -0
- datajunction-0.0.183/datajunction/skills/datajunction.md +253 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/test_cli.py +42 -26
- datajunction-0.0.183/tests/test_skills.py +193 -0
- datajunction-0.0.181/datajunction/skills/datajunction.md +0 -1823
- {datajunction-0.0.181 → datajunction-0.0.183}/.coveragerc +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/.gitignore +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/.pre-commit-config.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/LICENSE.txt +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/Makefile +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/README.md +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/claude_desktop_config.example.json +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/datajunction/__init__.py +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/datajunction/_base.py +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/datajunction/_internal.py +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/datajunction/admin.py +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/datajunction/builder.py +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/datajunction/client.py +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/datajunction/compile.py +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/datajunction/deployment.py +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/datajunction/exceptions.py +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/datajunction/mcp/__init__.py +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/datajunction/mcp/cli.py +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/datajunction/mcp/config.py +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/datajunction/models.py +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/datajunction/nodes.py +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/datajunction/rendering.py +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/datajunction/seed/init_system_nodes.py +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/datajunction/seed/nodes/date.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/datajunction/seed/nodes/deployment.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/datajunction/seed/nodes/dimension_link.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/datajunction/seed/nodes/distinct_node_authors.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/datajunction/seed/nodes/distinct_node_editors.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/datajunction/seed/nodes/dj.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/datajunction/seed/nodes/is_active.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/datajunction/seed/nodes/materialization.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/datajunction/seed/nodes/median_deployment_duration_seconds.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/datajunction/seed/nodes/median_dim_links_per_node.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/datajunction/seed/nodes/median_dimension_indegree.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/datajunction/seed/nodes/median_downstream_count.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/datajunction/seed/nodes/median_revisions_per_node.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/datajunction/seed/nodes/median_upstream_count.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/datajunction/seed/nodes/namespace.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/datajunction/seed/nodes/node_revision.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/datajunction/seed/nodes/node_type.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/datajunction/seed/nodes/nodes.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/datajunction/seed/nodes/number_of_branches.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/datajunction/seed/nodes/number_of_deployments.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/datajunction/seed/nodes/number_of_materializations.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/datajunction/seed/nodes/number_of_namespaces.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/datajunction/seed/nodes/number_of_nodes.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/datajunction/seed/nodes/number_of_orphan_nodes.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/datajunction/seed/nodes/number_of_unused_dimensions.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/datajunction/seed/nodes/repo.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/datajunction/seed/nodes/user.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/datajunction/tags.py +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/pyproject.toml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/setup.cfg +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/__init__.py +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/conftest.py +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/deploy0/dj.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/deploy0/roads/companies.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/deploy0/roads/companies_dim.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/deploy0/roads/contractor.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/deploy0/roads/contractors.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/deploy0/roads/us_state.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/deploy0/roads/us_states.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project1/dj.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project1/roads/avg_length_of_employment.metric.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project1/roads/avg_repair_price.metric.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project1/roads/avg_time_to_dispatch.metric.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project1/roads/contractor.dimension.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project1/roads/contractors.source.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project1/roads/date.source.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project1/roads/date_dim.dimension.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project1/roads/dispatcher.dimension.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project1/roads/dispatchers.source.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project1/roads/hard_hat.dimension.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project1/roads/hard_hat_state.source.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project1/roads/hard_hats.source.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project1/roads/local_hard_hats.dimension.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project1/roads/municipality.source.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project1/roads/municipality_dim.dimension.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project1/roads/municipality_municipality_type.source.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project1/roads/municipality_type.source.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project1/roads/national_level_agg.transform.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project1/roads/num_repair_orders.metric.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project1/roads/regional_level_agg.transform.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project1/roads/regional_repair_efficiency.metric.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project1/roads/repair_order.dimension.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project1/roads/repair_order_details.source.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project1/roads/repair_order_transform.transform.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project1/roads/repair_orders.source.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project1/roads/repair_orders_cube.cube.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project1/roads/repair_type.source.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project1/roads/total_repair_cost.metric.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project1/roads/total_repair_order_discounts.metric.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project1/roads/us_region.source.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project1/roads/us_state.dimension.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project1/roads/us_states.source.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project10/dj.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project11/avg_length_of_employment.metric.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project11/avg_repair_price.metric.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project11/avg_time_to_dispatch.metric.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project11/contractor.dimension.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project11/contractors.source.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project11/date.source.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project11/date_dim.dimension.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project11/dispatcher.dimension.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project11/dispatchers.source.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project11/dj.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project11/hard_hat.dimension.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project11/hard_hat_state.source.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project11/hard_hats.source.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project11/local_hard_hats.dimension.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project11/municipality.source.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project11/municipality_dim.dimension.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project11/municipality_municipality_type.source.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project11/municipality_type.source.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project11/national_level_agg.transform.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project11/num_repair_orders.metric.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project11/regional_level_agg.transform.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project11/regional_repair_efficiency.metric.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project11/repair_order.dimension.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project11/repair_order_details.source.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project11/repair_order_transform.transform.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project11/repair_orders.source.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project11/repair_orders_cube.cube.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project11/repair_type.source.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project11/total_repair_cost.metric.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project11/total_repair_order_discounts.metric.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project11/us_region.source.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project11/us_state.dimension.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project11/us_states.source.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project12/dj.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project12/roads/companies.source.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project12/roads/companies_dim.dimension.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project12/roads/contractor.dimension.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project12/roads/contractors.source.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project12/roads/us_state.dimension.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project12/roads/us_states.source.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project2/dj.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project2/some_node.source.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project3/dj.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project3/some_node.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project4/dj.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project4/very/very/deeply/nested/namespace/some_node.source.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project5/dj.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project5/some_node.a.b.c.source.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project6/dj.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project6/roads/contractor.dimension.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project6/roads/contractors.source.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project7/dj.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project7/roads/contractor.dimension.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project7/roads/contractors.source.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project8/dj.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project9/dj.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project9/roads/companies.source.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project9/roads/companies_dim.dimension.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project9/roads/contractor.dimension.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project9/roads/contractors.source.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project9/roads/us_state.dimension.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples/project9/roads/us_states.source.yaml +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/examples.py +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/mcp/README.md +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/mcp/__init__.py +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/mcp/test_cli.py +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/test__internal.py +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/test_admin.py +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/test_base.py +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/test_builder.py +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/test_client.py +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/test_compile.py +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/test_deploy.py +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/test_generated_client.py +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/test_integration.py +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tests/test_models.py +0 -0
- {datajunction-0.0.181 → datajunction-0.0.183}/tox.ini +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: datajunction
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.183
|
|
4
4
|
Summary: DataJunction client library for connecting to a DataJunction server
|
|
5
5
|
Project-URL: repository, https://github.com/DataJunction/dj
|
|
6
6
|
Author-email: DataJunction Authors <yian.shang@gmail.com>
|
|
@@ -5,7 +5,7 @@ import json
|
|
|
5
5
|
import logging
|
|
6
6
|
import os
|
|
7
7
|
from pathlib import Path
|
|
8
|
-
from typing import Optional
|
|
8
|
+
from typing import Any, Optional
|
|
9
9
|
|
|
10
10
|
from rich import box
|
|
11
11
|
from rich.console import Console, Group
|
|
@@ -1620,52 +1620,115 @@ class DJCLI:
|
|
|
1620
1620
|
output_dir.mkdir(parents=True, exist_ok=True)
|
|
1621
1621
|
|
|
1622
1622
|
console.print(
|
|
1623
|
-
"[bold]📚 Installing DJ
|
|
1623
|
+
"[bold]📚 Installing DJ skills[/bold]\n",
|
|
1624
1624
|
)
|
|
1625
1625
|
|
|
1626
|
-
# Load bundled skill from package
|
|
1627
|
-
dir_name = "datajunction"
|
|
1628
|
-
skill_dir = output_dir / dir_name
|
|
1629
|
-
skill_file = skill_dir / "SKILL.md"
|
|
1630
|
-
|
|
1631
|
-
console.print(f"Installing [cyan]{dir_name}[/cyan]...")
|
|
1632
|
-
|
|
1633
|
-
# Find bundled skill file
|
|
1634
1626
|
from datajunction import __version__ as dj_version
|
|
1635
1627
|
from importlib.resources import files
|
|
1636
1628
|
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1629
|
+
# All bundled DJ skills. ``datajunction`` is the core concepts
|
|
1630
|
+
# skill (always loaded); the others are audience-specific
|
|
1631
|
+
# extensions that compose on top of it.
|
|
1632
|
+
bundled_skills: list[dict[str, Any]] = [
|
|
1633
|
+
{
|
|
1634
|
+
"name": "datajunction",
|
|
1635
|
+
"filename": "datajunction.md",
|
|
1636
|
+
"description": "Core DataJunction concepts and vocabulary",
|
|
1637
|
+
"keywords": [
|
|
1638
|
+
"DataJunction",
|
|
1639
|
+
"DJ",
|
|
1640
|
+
"semantic layer",
|
|
1641
|
+
"dimension link",
|
|
1642
|
+
"star schema",
|
|
1643
|
+
"node types",
|
|
1644
|
+
],
|
|
1645
|
+
},
|
|
1646
|
+
{
|
|
1647
|
+
"name": "datajunction-query",
|
|
1648
|
+
"filename": "datajunction-query.md",
|
|
1649
|
+
"description": "Querying DJ metrics via MCP tools and APIs",
|
|
1650
|
+
"keywords": [
|
|
1651
|
+
"query metric",
|
|
1652
|
+
"generate SQL",
|
|
1653
|
+
"get metric data",
|
|
1654
|
+
"search_nodes",
|
|
1655
|
+
"build_metric_sql",
|
|
1656
|
+
"common dimensions",
|
|
1657
|
+
],
|
|
1658
|
+
},
|
|
1659
|
+
{
|
|
1660
|
+
"name": "datajunction-semantic-model",
|
|
1661
|
+
"filename": "datajunction-semantic-model.md",
|
|
1662
|
+
"description": "DJ semantic modeling: query-to-nodes decomposition, ratio decomposition, naming, ownership",
|
|
1663
|
+
"keywords": [
|
|
1664
|
+
"semantic modeling",
|
|
1665
|
+
"decompose query",
|
|
1666
|
+
"ratio metric",
|
|
1667
|
+
"derived metric",
|
|
1668
|
+
"base metric",
|
|
1669
|
+
"metric naming",
|
|
1670
|
+
"namespace organization",
|
|
1671
|
+
"node ownership",
|
|
1672
|
+
],
|
|
1673
|
+
},
|
|
1674
|
+
{
|
|
1675
|
+
"name": "datajunction-repo",
|
|
1676
|
+
"filename": "datajunction-repo.md",
|
|
1677
|
+
"description": "Authoring DJ nodes via YAML in a git-backed repository",
|
|
1678
|
+
"keywords": [
|
|
1679
|
+
"YAML nodes",
|
|
1680
|
+
"repo-backed namespace",
|
|
1681
|
+
"feature branch",
|
|
1682
|
+
"git workflow",
|
|
1683
|
+
"cube YAML",
|
|
1684
|
+
"metric YAML",
|
|
1685
|
+
"temporal partition",
|
|
1686
|
+
],
|
|
1687
|
+
},
|
|
1688
|
+
{
|
|
1689
|
+
"name": "datajunction-api",
|
|
1690
|
+
"filename": "datajunction-api.md",
|
|
1691
|
+
"description": "Direct REST API authoring of DJ nodes for exploration / prototyping",
|
|
1692
|
+
"keywords": [
|
|
1693
|
+
"DJ API",
|
|
1694
|
+
"REST API",
|
|
1695
|
+
"curl",
|
|
1696
|
+
"POST nodes",
|
|
1697
|
+
"API authoring",
|
|
1698
|
+
"prototyping",
|
|
1699
|
+
],
|
|
1700
|
+
},
|
|
1701
|
+
]
|
|
1702
|
+
|
|
1703
|
+
missing: list[str] = []
|
|
1704
|
+
for skill in bundled_skills:
|
|
1705
|
+
dir_name = skill["name"]
|
|
1706
|
+
skill_dir = output_dir / dir_name
|
|
1707
|
+
skill_file = skill_dir / "SKILL.md"
|
|
1708
|
+
|
|
1709
|
+
console.print(f"Installing [cyan]{dir_name}[/cyan]...")
|
|
1710
|
+
|
|
1711
|
+
try:
|
|
1712
|
+
skill_file_path = files("datajunction").joinpath(
|
|
1713
|
+
f"skills/{skill['filename']}",
|
|
1714
|
+
)
|
|
1715
|
+
bundled_skill = skill_file_path.read_text(encoding="utf-8")
|
|
1716
|
+
except FileNotFoundError: # pragma: no cover
|
|
1717
|
+
missing.append(skill["filename"])
|
|
1718
|
+
continue
|
|
1643
1719
|
|
|
1644
|
-
# Create directory
|
|
1645
1720
|
skill_dir.mkdir(parents=True, exist_ok=True)
|
|
1646
1721
|
|
|
1647
|
-
# Write SKILL.md
|
|
1648
1722
|
with open(skill_file, "w") as f:
|
|
1649
1723
|
f.write(bundled_skill)
|
|
1650
1724
|
|
|
1651
|
-
# Write metadata
|
|
1652
1725
|
metadata_file = skill_dir / "metadata.json"
|
|
1653
1726
|
with open(metadata_file, "w") as f:
|
|
1654
1727
|
metadata = {
|
|
1655
|
-
"name": "
|
|
1728
|
+
"name": skill["name"],
|
|
1656
1729
|
"version": dj_version,
|
|
1657
|
-
"description": "
|
|
1658
|
-
"keywords": [
|
|
1659
|
-
"DataJunction",
|
|
1660
|
-
"DJ",
|
|
1661
|
-
"semantic layer",
|
|
1662
|
-
"dimension link",
|
|
1663
|
-
"metric",
|
|
1664
|
-
"SQL generation",
|
|
1665
|
-
"YAML nodes",
|
|
1666
|
-
"git workflow",
|
|
1667
|
-
"repo-backed namespace",
|
|
1668
|
-
],
|
|
1730
|
+
"description": skill["description"],
|
|
1731
|
+
"keywords": skill["keywords"],
|
|
1669
1732
|
"metadata": {
|
|
1670
1733
|
"source": "bundled",
|
|
1671
1734
|
"dj_version": dj_version,
|
|
@@ -1681,13 +1744,14 @@ class DJCLI:
|
|
|
1681
1744
|
f" [dim]└─ metadata.json (v{dj_version})[/dim]\n",
|
|
1682
1745
|
)
|
|
1683
1746
|
|
|
1747
|
+
if missing: # pragma: no cover
|
|
1684
1748
|
console.print(
|
|
1685
|
-
f"[
|
|
1749
|
+
f"[red]✗ Bundled skills not found: {', '.join(missing)}. "
|
|
1750
|
+
f"Please ensure datajunction is properly installed.[/red]",
|
|
1686
1751
|
)
|
|
1687
|
-
|
|
1688
|
-
except FileNotFoundError: # pragma: no cover
|
|
1752
|
+
else:
|
|
1689
1753
|
console.print(
|
|
1690
|
-
"[
|
|
1754
|
+
f"[bold green]✓ Skills installed to {output_dir}[/bold green]\n",
|
|
1691
1755
|
)
|
|
1692
1756
|
|
|
1693
1757
|
# Install subagent if requested
|
|
@@ -1704,9 +1768,13 @@ name: dj
|
|
|
1704
1768
|
description: >
|
|
1705
1769
|
DataJunction semantic layer expert. Use proactively for any DataJunction
|
|
1706
1770
|
or DJ work — querying metrics, exploring nodes and dimensions, building
|
|
1707
|
-
SQL, understanding lineage, and semantic layer design.
|
|
1771
|
+
SQL, understanding lineage, authoring metrics, and semantic layer design.
|
|
1708
1772
|
skills:
|
|
1709
1773
|
- datajunction
|
|
1774
|
+
- datajunction-query
|
|
1775
|
+
- datajunction-semantic-model
|
|
1776
|
+
- datajunction-repo
|
|
1777
|
+
- datajunction-api
|
|
1710
1778
|
model: inherit
|
|
1711
1779
|
---
|
|
1712
1780
|
"""
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: datajunction-api
|
|
3
|
+
description: |
|
|
4
|
+
Activate this skill when authoring DataJunction (DJ) nodes via the REST
|
|
5
|
+
API directly (curl, HTTP clients) — typically for exploration, ad-hoc
|
|
6
|
+
prototyping, or namespaces that aren't repo-backed. For modeling
|
|
7
|
+
decisions and the decomposition workflow, invoke `datajunction-semantic-model`.
|
|
8
|
+
For repo-backed YAML authoring (the production path), invoke
|
|
9
|
+
`datajunction-repo`. For concepts, invoke `datajunction`.
|
|
10
|
+
Keywords:
|
|
11
|
+
- DJ API, REST API, curl
|
|
12
|
+
- POST nodes/metric, POST nodes/dimension
|
|
13
|
+
- create metric, create dimension, create cube
|
|
14
|
+
- API approach, direct API changes
|
|
15
|
+
- prototyping, exploration
|
|
16
|
+
user-invocable: false
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
# DataJunction Direct API Authoring
|
|
20
|
+
|
|
21
|
+
Direct REST API authoring for DJ nodes. Use this skill for quick exploration, prototyping, or working in namespaces that don't use the repo-backed workflow.
|
|
22
|
+
|
|
23
|
+
For the modeling work upstream of any authoring (decomposition, naming, ratio decomposition, etc.), see `datajunction-semantic-model`. For the production-path equivalent of these patterns in YAML, see `datajunction-repo`.
|
|
24
|
+
|
|
25
|
+
## When to Use the API Approach
|
|
26
|
+
|
|
27
|
+
**✅ MUST use repo workflow instead** (`datajunction-repo`) for:
|
|
28
|
+
- Namespaces configured as repo-backed and read-only (`git_only: true`) — direct API changes are rejected
|
|
29
|
+
|
|
30
|
+
**✅ Should use repo workflow** for:
|
|
31
|
+
- Production changes (review required)
|
|
32
|
+
- Multi-node changes (related metrics/dimensions)
|
|
33
|
+
- Team environments (multiple contributors)
|
|
34
|
+
- Audit-trail requirements
|
|
35
|
+
- Complex refactoring
|
|
36
|
+
|
|
37
|
+
**✅ API workflow is appropriate** for:
|
|
38
|
+
- Quick exploration and prototyping
|
|
39
|
+
- Ad-hoc analysis
|
|
40
|
+
- Single-user, non-production namespaces
|
|
41
|
+
- Temporary metrics
|
|
42
|
+
- Non-production experiments
|
|
43
|
+
- Only when the target namespace is NOT read-only repo-backed
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## Checking if a Namespace Is Repo-Backed
|
|
48
|
+
|
|
49
|
+
Before authoring via API, verify the target namespace allows it.
|
|
50
|
+
|
|
51
|
+
**Best approach — `get_node_details` MCP tool** (`datajunction-query` skill):
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
get_node_details(name="finance.total_revenue")
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
The response will include git repository information:
|
|
58
|
+
```
|
|
59
|
+
Git Repository:
|
|
60
|
+
Repo: owner/dj-finance
|
|
61
|
+
Branch: main
|
|
62
|
+
Default Branch: main
|
|
63
|
+
→ This namespace is repo-backed (use git workflow for changes)
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
**Alternative — REST API** (shows read-only status):
|
|
67
|
+
```bash
|
|
68
|
+
curl -b ~/.dj/cookies.txt -X GET $DJ_URL/namespaces/finance/git
|
|
69
|
+
|
|
70
|
+
# Response:
|
|
71
|
+
{
|
|
72
|
+
"github_repo_path": "owner/dj-finance",
|
|
73
|
+
"git_branch": "main",
|
|
74
|
+
"default_branch": "main",
|
|
75
|
+
"git_path": "nodes/",
|
|
76
|
+
"git_only": true ← If true, namespace is read-only (API changes blocked)
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
**Decision tree:**
|
|
81
|
+
- **If git info is present AND `git_only: true`**: MUST use repo workflow (API changes will fail)
|
|
82
|
+
- **If git info is present AND `git_only: false`**: Can use either workflow
|
|
83
|
+
- **If git info is null**: Use API workflow (direct POST/PATCH)
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## Creating a Metric
|
|
88
|
+
|
|
89
|
+
### Metric Structure
|
|
90
|
+
|
|
91
|
+
```sql
|
|
92
|
+
SELECT <aggregation_expression> AS <metric_name>
|
|
93
|
+
FROM <single_node>
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Metrics select a **single expression** from a **single source, transform, or dimension node**. They cannot contain WHERE clauses — use CASE WHEN instead. See `datajunction-semantic-model` for the modeling rationale.
|
|
97
|
+
|
|
98
|
+
### Metric Metadata Fields
|
|
99
|
+
|
|
100
|
+
**Required:**
|
|
101
|
+
- `name` — Fully qualified metric name (e.g., `finance.total_revenue`)
|
|
102
|
+
- `query` — SQL aggregation expression
|
|
103
|
+
|
|
104
|
+
**Recommended:**
|
|
105
|
+
- `description` — Human-readable description
|
|
106
|
+
- `metric_metadata.direction` — `higher_is_better` / `lower_is_better` / `neutral`
|
|
107
|
+
- `metric_metadata.unit` — `dollar` / `unitless` (**⚠️ NOT `count`** — server rejects)
|
|
108
|
+
- `mode` — `draft` / `published`
|
|
109
|
+
- `required_dimensions` — Dimensions required for this metric to make sense
|
|
110
|
+
- `owners` — List of email addresses (prefer team emails)
|
|
111
|
+
|
|
112
|
+
### Examples
|
|
113
|
+
|
|
114
|
+
**COUNT**:
|
|
115
|
+
```bash
|
|
116
|
+
curl -b ~/.dj/cookies.txt -X POST $DJ_URL/nodes/metric/ \
|
|
117
|
+
-H 'Content-Type: application/json' \
|
|
118
|
+
-d '{
|
|
119
|
+
"name": "finance.num_transactions",
|
|
120
|
+
"description": "Total number of transactions",
|
|
121
|
+
"query": "SELECT COUNT(transaction_id) AS num_transactions FROM finance.transactions",
|
|
122
|
+
"owners": ["data-platform-team@company.com"],
|
|
123
|
+
"mode": "published"
|
|
124
|
+
}'
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
**SUM**:
|
|
128
|
+
```bash
|
|
129
|
+
curl -b ~/.dj/cookies.txt -X POST $DJ_URL/nodes/metric/ \
|
|
130
|
+
-H 'Content-Type: application/json' \
|
|
131
|
+
-d '{
|
|
132
|
+
"name": "finance.total_revenue",
|
|
133
|
+
"description": "Total revenue from all transactions",
|
|
134
|
+
"query": "SELECT SUM(amount_usd) AS total_revenue FROM finance.transactions",
|
|
135
|
+
"metric_metadata": {
|
|
136
|
+
"direction": "higher_is_better",
|
|
137
|
+
"unit": "dollar"
|
|
138
|
+
},
|
|
139
|
+
"owners": ["finance-data-team@company.com"],
|
|
140
|
+
"mode": "published"
|
|
141
|
+
}'
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
**Conditional aggregation** (CASE WHEN, not WHERE):
|
|
145
|
+
```bash
|
|
146
|
+
curl -b ~/.dj/cookies.txt -X POST $DJ_URL/nodes/metric/ \
|
|
147
|
+
-H 'Content-Type: application/json' \
|
|
148
|
+
-d '{
|
|
149
|
+
"name": "finance.completed_revenue",
|
|
150
|
+
"description": "Revenue from completed non-refund transactions",
|
|
151
|
+
"query": "
|
|
152
|
+
SELECT SUM(
|
|
153
|
+
CASE
|
|
154
|
+
WHEN status = '\''completed'\'' AND refund_flag = false
|
|
155
|
+
THEN amount_usd
|
|
156
|
+
ELSE 0
|
|
157
|
+
END
|
|
158
|
+
) AS completed_revenue
|
|
159
|
+
FROM finance.transactions
|
|
160
|
+
",
|
|
161
|
+
"metric_metadata": {
|
|
162
|
+
"direction": "higher_is_better",
|
|
163
|
+
"unit": "dollar"
|
|
164
|
+
},
|
|
165
|
+
"owners": ["finance-data-team@company.com"],
|
|
166
|
+
"mode": "published"
|
|
167
|
+
}'
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
**Ratio over base metrics** (decompose first, then derive — see `datajunction-semantic-model`):
|
|
171
|
+
```bash
|
|
172
|
+
# Step 1: create the base metrics (one curl each)
|
|
173
|
+
curl -X POST $DJ_URL/nodes/metric/ -d '{
|
|
174
|
+
"name": "finance.clicks",
|
|
175
|
+
"query": "SELECT COUNT_IF(event = '\''click'\'') FROM finance.events",
|
|
176
|
+
"owners": ["marketing@company.com"],
|
|
177
|
+
"mode": "published"
|
|
178
|
+
}'
|
|
179
|
+
|
|
180
|
+
curl -X POST $DJ_URL/nodes/metric/ -d '{
|
|
181
|
+
"name": "finance.impressions",
|
|
182
|
+
"query": "SELECT COUNT_IF(event = '\''impression'\'') FROM finance.events",
|
|
183
|
+
"owners": ["marketing@company.com"],
|
|
184
|
+
"mode": "published"
|
|
185
|
+
}'
|
|
186
|
+
|
|
187
|
+
# Step 2: derived ratio metric referencing the base metrics
|
|
188
|
+
curl -X POST $DJ_URL/nodes/metric/ -d '{
|
|
189
|
+
"name": "finance.conversion_rate",
|
|
190
|
+
"description": "Click-through rate as percentage",
|
|
191
|
+
"query": "SELECT finance.clicks * 100.0 / NULLIF(finance.impressions, 0)",
|
|
192
|
+
"metric_metadata": {
|
|
193
|
+
"direction": "higher_is_better",
|
|
194
|
+
"unit": "unitless"
|
|
195
|
+
},
|
|
196
|
+
"owners": ["marketing@company.com"],
|
|
197
|
+
"mode": "published"
|
|
198
|
+
}'
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
DJ automatically handles divide-by-zero, but `NULLIF()` is extra safety.
|
|
202
|
+
|
|
203
|
+
---
|
|
204
|
+
|
|
205
|
+
## Creating Other Node Types via API
|
|
206
|
+
|
|
207
|
+
Same pattern as metrics — POST JSON to the appropriate endpoint:
|
|
208
|
+
|
|
209
|
+
- `POST /nodes/source/` — source nodes (catalog/schema/table refs)
|
|
210
|
+
- `POST /nodes/dimension/` — dimension nodes
|
|
211
|
+
- `POST /nodes/transform/` — transform nodes
|
|
212
|
+
- `POST /nodes/cube/` — cubes (metric + dimension combinations)
|
|
213
|
+
|
|
214
|
+
For the YAML-equivalent shapes of each, see `datajunction-repo` — the field set is the same, just expressed in JSON instead of YAML.
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
## Updating and Deleting Nodes
|
|
219
|
+
|
|
220
|
+
**Update** (PATCH):
|
|
221
|
+
```bash
|
|
222
|
+
curl -b ~/.dj/cookies.txt -X PATCH $DJ_URL/nodes/finance.total_revenue/ \
|
|
223
|
+
-H 'Content-Type: application/json' \
|
|
224
|
+
-d '{"description": "Updated description"}'
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
**Deactivate** (soft delete):
|
|
228
|
+
```bash
|
|
229
|
+
curl -b ~/.dj/cookies.txt -X DELETE $DJ_URL/nodes/finance.total_revenue/
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
Deactivated nodes can be revived. For hard-delete (irreversible), use the `dj` CLI: `dj delete-node finance.total_revenue --hard`.
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: datajunction-query
|
|
3
|
+
description: |
|
|
4
|
+
Activate this skill for querying DataJunction (DJ) — finding nodes,
|
|
5
|
+
generating SQL, fetching metric data, exploring lineage, visualizing
|
|
6
|
+
results — via the DJ UI, MCP tools, or REST/GraphQL APIs. For core DJ
|
|
7
|
+
concepts and vocabulary, invoke `datajunction`. For modeling decisions
|
|
8
|
+
(what shape something should take), invoke `datajunction-semantic-model`.
|
|
9
|
+
For authoring nodes, invoke `datajunction-repo` (YAML) or
|
|
10
|
+
`datajunction-api` (REST).
|
|
11
|
+
Keywords:
|
|
12
|
+
- query metric, query metrics
|
|
13
|
+
- generate SQL, build metric SQL
|
|
14
|
+
- get metric data, fetch metric
|
|
15
|
+
- available dimensions, common dimensions
|
|
16
|
+
- search_nodes, get_node_details, get_node_lineage
|
|
17
|
+
- get_common, build_metric_sql, get_metric_data
|
|
18
|
+
- visualize metrics
|
|
19
|
+
- MCP tools, DJ API, GraphQL
|
|
20
|
+
- DJ UI, web UI, browse
|
|
21
|
+
user-invocable: false
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
# DataJunction Query
|
|
25
|
+
|
|
26
|
+
Consumer-side workflow for DJ: find existing nodes, build SQL to query them, fetch data, visualize results. For the underlying concepts (node types, dimension links, star schema), invoke the `datajunction` skill.
|
|
27
|
+
|
|
28
|
+
## DJ UI (Web)
|
|
29
|
+
|
|
30
|
+
For interactive exploration — browsing namespaces, inspecting a node's lineage / SQL / available dimensions, building queries by clicking dimensions on/off — the DJ web UI is usually the fastest path. It's hosted at the same URL as the DJ server (e.g. `https://your-dj-server.example.com/`).
|
|
31
|
+
|
|
32
|
+
**Use the UI when:**
|
|
33
|
+
- The user wants to *look around* — browse what exists, read a node's description, explore lineage visually
|
|
34
|
+
- They want to build a query interactively and copy the SQL out
|
|
35
|
+
- They're sharing a node or query with a teammate (UI URLs are shareable links)
|
|
36
|
+
|
|
37
|
+
**Use the MCP tools / API (below) when:**
|
|
38
|
+
- You need programmatic access — pulling node names into a script, generating SQL as part of a workflow, fetching data into a notebook
|
|
39
|
+
- The interaction is "give me this answer," not "let me explore"
|
|
40
|
+
|
|
41
|
+
Suggest opening the UI when the user's question is exploratory and you don't yet know the right node name. Suggest MCP tools when you have a name in hand and need data, lineage, or generated SQL.
|
|
42
|
+
|
|
43
|
+
## Discovery & Exploration (Use MCP Tools)
|
|
44
|
+
|
|
45
|
+
**When you need to explore the DJ semantic layer, use these MCP tools:**
|
|
46
|
+
|
|
47
|
+
### Find Available Nodes
|
|
48
|
+
|
|
49
|
+
**Use MCP tool**: `search_nodes`
|
|
50
|
+
- Search for metrics, dimensions, cubes by name or namespace
|
|
51
|
+
- Filter by node type
|
|
52
|
+
- Returns list of matching nodes
|
|
53
|
+
|
|
54
|
+
**Example**: `search_nodes(query="revenue", node_type="metric", namespace="finance")`
|
|
55
|
+
|
|
56
|
+
### Get Node Details
|
|
57
|
+
|
|
58
|
+
**Use MCP tool**: `get_node_details`
|
|
59
|
+
- Get comprehensive information about a specific node
|
|
60
|
+
- Returns: SQL definition, description, available dimensions, lineage, tags
|
|
61
|
+
- Input: Full node name (e.g., "finance.total_revenue")
|
|
62
|
+
|
|
63
|
+
**Example**: `get_node_details(name="finance.total_revenue")`
|
|
64
|
+
|
|
65
|
+
**What you get**:
|
|
66
|
+
- Description and SQL definition
|
|
67
|
+
- All available dimensions (via dimension links)
|
|
68
|
+
- Metric metadata (unit, direction, required dimensions)
|
|
69
|
+
- Upstream dependencies
|
|
70
|
+
- Tags and collections
|
|
71
|
+
|
|
72
|
+
### Check Common Dimensions
|
|
73
|
+
|
|
74
|
+
**Use MCP tool**: `get_common`
|
|
75
|
+
- Find dimensions shared across multiple metrics, or metrics shared across multiple dimensions (bidirectional)
|
|
76
|
+
- Essential before querying multiple metrics together
|
|
77
|
+
- Returns only entries shared by ALL of the specified inputs
|
|
78
|
+
|
|
79
|
+
**Example**: `get_common(metrics=["finance.total_revenue", "growth.daily_active_users"])`
|
|
80
|
+
|
|
81
|
+
**When to use**: Always check this before building queries with multiple metrics!
|
|
82
|
+
|
|
83
|
+
### Get Node Lineage
|
|
84
|
+
|
|
85
|
+
**Use MCP tool**: `get_node_lineage`
|
|
86
|
+
- Get upstream dependencies (what data sources this uses)
|
|
87
|
+
- Get downstream dependencies (what will break if you change this)
|
|
88
|
+
- Direction: "upstream", "downstream", or "both"
|
|
89
|
+
|
|
90
|
+
**Example**: `get_node_lineage(node_name="finance.total_revenue", direction="both")`
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## Querying & SQL Generation (Use MCP Tools)
|
|
95
|
+
|
|
96
|
+
**When you need to query metrics or generate SQL, use these MCP tools:**
|
|
97
|
+
|
|
98
|
+
### Build Metric SQL
|
|
99
|
+
|
|
100
|
+
**Use MCP tool**: `build_metric_sql`
|
|
101
|
+
- Generate executable SQL for querying metrics
|
|
102
|
+
- Supports filters, dimensions, ordering, limits
|
|
103
|
+
- Returns SQL query and metadata
|
|
104
|
+
|
|
105
|
+
**Example**:
|
|
106
|
+
```
|
|
107
|
+
build_metric_sql(
|
|
108
|
+
metrics=["finance.total_revenue"],
|
|
109
|
+
dimensions=["core.date.date"],
|
|
110
|
+
filters=["core.date.date >= '2024-01-01'"],
|
|
111
|
+
orderby=["core.date.date ASC"],
|
|
112
|
+
limit=100,
|
|
113
|
+
dialect="trino",
|
|
114
|
+
)
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
**Returns**:
|
|
118
|
+
- Generated SQL for specified engine
|
|
119
|
+
- Output columns with types
|
|
120
|
+
- Cube name (if materialized cube used)
|
|
121
|
+
|
|
122
|
+
**Performance**: always pass a filter on a date/time dimension. When the upstream cube has a temporal partition declared on that dimension, DJ pushes the filter down to the partition column, limiting the data scanned. Without a time filter, queries scan the full underlying table.
|
|
123
|
+
|
|
124
|
+
(Don't pass `include_temporal_filters=True` here — that's a parameter on `get_query_plan` for inspecting partition templates in materialization-plan SQL, not for live queries.)
|
|
125
|
+
|
|
126
|
+
### Get Metric Data
|
|
127
|
+
|
|
128
|
+
**Use MCP tool**: `get_metric_data`
|
|
129
|
+
- Execute query and get actual data
|
|
130
|
+
- Returns query results as rows
|
|
131
|
+
- **Scan-cost guardrail**: materialized cubes always run; ad-hoc queries
|
|
132
|
+
(e.g. against Trino) run only if DJ's scan estimate is under the safety
|
|
133
|
+
threshold. Over-threshold queries are refused up front and the estimate
|
|
134
|
+
is surfaced so you can narrow the query (tighter date range, fewer
|
|
135
|
+
dimensions, lower limit) and retry.
|
|
136
|
+
|
|
137
|
+
**Example**:
|
|
138
|
+
```
|
|
139
|
+
get_metric_data(
|
|
140
|
+
metrics=["finance.total_revenue", "finance.transaction_count"],
|
|
141
|
+
dimensions=["core.date.date", "core.region.region_name"],
|
|
142
|
+
filters=["core.date.date >= '2024-01-01'"],
|
|
143
|
+
orderby=["core.date.date ASC"],
|
|
144
|
+
limit=1000
|
|
145
|
+
)
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
**Best practices**:
|
|
149
|
+
- Always set a reasonable `limit`
|
|
150
|
+
- Use specific date range filters — they drive partition pushdown and
|
|
151
|
+
keep the scan estimate below the guardrail threshold
|
|
152
|
+
- Check common dimensions first for multi-metric queries
|
|
153
|
+
- If you're not sure how heavy a query will be, run `get_query_plan`
|
|
154
|
+
first (see below) — it returns the scan estimate without executing
|
|
155
|
+
|
|
156
|
+
### Visualize Metrics
|
|
157
|
+
|
|
158
|
+
**Use MCP tool**: `visualize_metrics`
|
|
159
|
+
- Query metrics and generate ASCII chart visualization
|
|
160
|
+
- Creates terminal-friendly charts (line, bar, scatter)
|
|
161
|
+
- Same scan-cost guardrails as `get_metric_data`
|
|
162
|
+
|
|
163
|
+
**Example**:
|
|
164
|
+
```
|
|
165
|
+
visualize_metrics(
|
|
166
|
+
metrics=["finance.total_revenue"],
|
|
167
|
+
dimensions=["core.date.date"],
|
|
168
|
+
filters=["core.date.date >= '2024-01-01'"],
|
|
169
|
+
orderby=["core.date.date ASC"],
|
|
170
|
+
limit=90,
|
|
171
|
+
chart_type="line"
|
|
172
|
+
)
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
**Chart types**:
|
|
176
|
+
- `line`: Time series (default)
|
|
177
|
+
- `bar`: Categorical comparisons
|
|
178
|
+
- `scatter`: Correlation analysis
|
|
179
|
+
|
|
180
|
+
### Pre-Flight: Get Query Plan
|
|
181
|
+
|
|
182
|
+
**Use MCP tool**: `get_query_plan`
|
|
183
|
+
- Returns how DJ decomposes the requested metrics into grain groups and
|
|
184
|
+
components, AND the scan estimate, without executing anything
|
|
185
|
+
- Use it before `get_metric_data` / `visualize_metrics` if you suspect
|
|
186
|
+
the query might be expensive — the same scan estimate that drives the
|
|
187
|
+
refusal guardrail is surfaced here, so you can iterate on filters
|
|
188
|
+
until the estimate is reasonable
|
|
189
|
+
|
|
190
|
+
**Example**:
|
|
191
|
+
```
|
|
192
|
+
get_query_plan(
|
|
193
|
+
metrics=["finance.total_revenue"],
|
|
194
|
+
dimensions=["core.date.date"],
|
|
195
|
+
filters=["core.date.date >= '2024-01-01'"],
|
|
196
|
+
)
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
**When to use**:
|
|
200
|
+
- "Will this query work?" — check before fetching
|
|
201
|
+
- "Why is this fetch refused?" — re-run the same args here to see the
|
|
202
|
+
estimate
|
|
203
|
+
- "What grain group will this go through?" — useful for understanding
|
|
204
|
+
multi-metric queries
|
|
205
|
+
|
|
206
|
+
---
|
|
207
|
+
|
|
208
|
+
## API Reference (Educational Context)
|
|
209
|
+
|
|
210
|
+
The MCP tools call the DJ REST and GraphQL APIs under the hood. Here's what they're doing:
|
|
211
|
+
|
|
212
|
+
### REST API Endpoints
|
|
213
|
+
|
|
214
|
+
**Node discovery**:
|
|
215
|
+
```bash
|
|
216
|
+
GET /nodes?node_type=metric&namespace=finance
|
|
217
|
+
GET /nodes/{node_name}
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
**SQL generation** (⚠️ Always use V3):
|
|
221
|
+
```bash
|
|
222
|
+
GET /sql/metrics/v3 # Generate query SQL
|
|
223
|
+
GET /sql/measures/v3 # Generate pre-aggregation SQL
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
**Dimension compatibility**:
|
|
227
|
+
```bash
|
|
228
|
+
GET /metrics/common/dimensions
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### GraphQL API
|
|
232
|
+
|
|
233
|
+
Available at `/graphql`:
|
|
234
|
+
|
|
235
|
+
```graphql
|
|
236
|
+
query {
|
|
237
|
+
nodes(nodeType: METRIC, namespace: "finance") {
|
|
238
|
+
name
|
|
239
|
+
description
|
|
240
|
+
dimensions { name type }
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
commonDimensions(nodes: ["finance.revenue", "growth.users"]) {
|
|
244
|
+
name
|
|
245
|
+
type
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
```
|