@luquimbo/bi-superpowers 1.0.0
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.
- package/.claude-plugin/plugin.json +8 -0
- package/.mcp.json +25 -0
- package/AGENTS.md +244 -0
- package/CHANGELOG.md +265 -0
- package/LICENSE +21 -0
- package/README.md +211 -0
- package/bin/build-plugin.js +30 -0
- package/bin/cli.js +1064 -0
- package/bin/commands/add.js +533 -0
- package/bin/commands/add.test.js +77 -0
- package/bin/commands/build-desktop.js +166 -0
- package/bin/commands/changelog.js +443 -0
- package/bin/commands/diff.js +325 -0
- package/bin/commands/lint.js +419 -0
- package/bin/commands/lint.test.js +103 -0
- package/bin/commands/mcp-setup.js +246 -0
- package/bin/commands/pull.js +287 -0
- package/bin/commands/pull.test.js +36 -0
- package/bin/commands/push.js +231 -0
- package/bin/commands/push.test.js +14 -0
- package/bin/commands/search.js +344 -0
- package/bin/commands/search.test.js +115 -0
- package/bin/commands/setup.js +545 -0
- package/bin/commands/setup.test.js +46 -0
- package/bin/commands/sync-profile.js +405 -0
- package/bin/commands/sync-profile.test.js +14 -0
- package/bin/commands/sync-source.js +418 -0
- package/bin/commands/sync-source.test.js +14 -0
- package/bin/commands/watch.js +206 -0
- package/bin/lib/generators/claude-plugin.js +266 -0
- package/bin/lib/generators/claude-plugin.test.js +110 -0
- package/bin/lib/generators/index.js +116 -0
- package/bin/lib/generators/shared.js +282 -0
- package/bin/lib/licensing/index.js +35 -0
- package/bin/lib/licensing/storage.js +364 -0
- package/bin/lib/licensing/storage.test.js +55 -0
- package/bin/lib/licensing/validator.js +213 -0
- package/bin/lib/licensing/validator.test.js +137 -0
- package/bin/lib/microsoft-mcp.js +176 -0
- package/bin/lib/microsoft-mcp.test.js +106 -0
- package/bin/lib/skills.js +84 -0
- package/bin/mcp/powerbi-modeling-launcher.js +38 -0
- package/bin/postinstall.js +44 -0
- package/bin/utils/errors.js +159 -0
- package/bin/utils/git.js +298 -0
- package/bin/utils/logger.js +142 -0
- package/bin/utils/mcp-detect.js +274 -0
- package/bin/utils/mcp-detect.test.js +105 -0
- package/bin/utils/pbix.js +305 -0
- package/bin/utils/pbix.test.js +37 -0
- package/bin/utils/profiles.js +312 -0
- package/bin/utils/projects.js +168 -0
- package/bin/utils/readline.js +206 -0
- package/bin/utils/readline.test.js +47 -0
- package/bin/utils/tui.js +314 -0
- package/bin/utils/tui.test.js +127 -0
- package/commands/contributions.md +265 -0
- package/commands/data-model-design.md +468 -0
- package/commands/dax-doctor.md +248 -0
- package/commands/fabric-scripts.md +452 -0
- package/commands/migration-assistant.md +290 -0
- package/commands/model-documenter.md +242 -0
- package/commands/pbi-connect.md +239 -0
- package/commands/project-kickoff.md +905 -0
- package/commands/report-layout.md +296 -0
- package/commands/rls-design.md +533 -0
- package/commands/theme-tweaker.md +624 -0
- package/config.example.json +23 -0
- package/config.json +23 -0
- package/desktop-extension/manifest.json +37 -0
- package/desktop-extension/package.json +10 -0
- package/desktop-extension/server.js +95 -0
- package/docs/openrouter-free-models.md +92 -0
- package/library/examples/README.md +151 -0
- package/library/examples/finance-reporting/README.md +351 -0
- package/library/examples/finance-reporting/data-model.md +267 -0
- package/library/examples/finance-reporting/measures.dax +557 -0
- package/library/examples/hr-analytics/README.md +371 -0
- package/library/examples/hr-analytics/data-model.md +315 -0
- package/library/examples/hr-analytics/measures.dax +460 -0
- package/library/examples/marketing-analytics/README.md +37 -0
- package/library/examples/marketing-analytics/data-model.md +62 -0
- package/library/examples/marketing-analytics/measures.dax +110 -0
- package/library/examples/retail-analytics/README.md +439 -0
- package/library/examples/retail-analytics/data-model.md +288 -0
- package/library/examples/retail-analytics/measures.dax +481 -0
- package/library/examples/supply-chain/README.md +37 -0
- package/library/examples/supply-chain/data-model.md +69 -0
- package/library/examples/supply-chain/measures.dax +77 -0
- package/library/examples/udf-library/README.md +228 -0
- package/library/examples/udf-library/functions.dax +571 -0
- package/library/snippets/dax/README.md +292 -0
- package/library/snippets/dax/business-domains.md +576 -0
- package/library/snippets/dax/calculate-patterns.md +276 -0
- package/library/snippets/dax/calculation-groups.md +489 -0
- package/library/snippets/dax/error-handling.md +495 -0
- package/library/snippets/dax/iterators-and-aggregations.md +474 -0
- package/library/snippets/dax/kpis-and-metrics.md +293 -0
- package/library/snippets/dax/rankings-and-topn.md +235 -0
- package/library/snippets/dax/security-patterns.md +413 -0
- package/library/snippets/dax/text-and-formatting.md +316 -0
- package/library/snippets/dax/time-intelligence.md +196 -0
- package/library/snippets/dax/user-defined-functions.md +477 -0
- package/library/snippets/dax/virtual-tables.md +546 -0
- package/library/snippets/excel-formulas/README.md +84 -0
- package/library/snippets/excel-formulas/aggregations.md +330 -0
- package/library/snippets/excel-formulas/dates-and-times.md +361 -0
- package/library/snippets/excel-formulas/dynamic-arrays.md +314 -0
- package/library/snippets/excel-formulas/lookups.md +169 -0
- package/library/snippets/excel-formulas/text-functions.md +363 -0
- package/library/snippets/governance/naming-conventions.md +97 -0
- package/library/snippets/governance/review-checklists.md +107 -0
- package/library/snippets/power-query/README.md +389 -0
- package/library/snippets/power-query/api-integration.md +707 -0
- package/library/snippets/power-query/connections.md +434 -0
- package/library/snippets/power-query/data-cleaning.md +298 -0
- package/library/snippets/power-query/error-handling.md +526 -0
- package/library/snippets/power-query/parameters.md +350 -0
- package/library/snippets/power-query/performance.md +506 -0
- package/library/snippets/power-query/transformations.md +330 -0
- package/library/snippets/report-design/accessibility.md +78 -0
- package/library/snippets/report-design/chart-selection.md +54 -0
- package/library/snippets/report-design/layout-patterns.md +87 -0
- package/library/templates/data-models/README.md +93 -0
- package/library/templates/data-models/finance-model.md +627 -0
- package/library/templates/data-models/retail-star-schema.md +473 -0
- package/library/templates/excel/README.md +83 -0
- package/library/templates/excel/budget-tracker.md +432 -0
- package/library/templates/excel/data-entry-form.md +533 -0
- package/library/templates/power-bi/README.md +72 -0
- package/library/templates/power-bi/finance-report.md +449 -0
- package/library/templates/power-bi/kpi-scorecard.md +461 -0
- package/library/templates/power-bi/sales-dashboard.md +281 -0
- package/library/themes/excel/README.md +436 -0
- package/library/themes/power-bi/README.md +271 -0
- package/library/themes/power-bi/accessible.json +307 -0
- package/library/themes/power-bi/bi-superpowers-default.json +858 -0
- package/library/themes/power-bi/corporate-blue.json +291 -0
- package/library/themes/power-bi/dark-mode.json +291 -0
- package/library/themes/power-bi/minimal.json +292 -0
- package/library/themes/power-bi/print-friendly.json +309 -0
- package/package.json +93 -0
- package/skills/contributions/SKILL.md +267 -0
- package/skills/data-model-design/SKILL.md +470 -0
- package/skills/data-modeling/SKILL.md +254 -0
- package/skills/data-quality/SKILL.md +664 -0
- package/skills/dax/SKILL.md +708 -0
- package/skills/dax-doctor/SKILL.md +250 -0
- package/skills/dax-udf/SKILL.md +489 -0
- package/skills/deployment/SKILL.md +320 -0
- package/skills/excel-formulas/SKILL.md +463 -0
- package/skills/fabric-scripts/SKILL.md +454 -0
- package/skills/fast-standard/SKILL.md +509 -0
- package/skills/governance/SKILL.md +205 -0
- package/skills/migration-assistant/SKILL.md +292 -0
- package/skills/model-documenter/SKILL.md +244 -0
- package/skills/pbi-connect/SKILL.md +241 -0
- package/skills/power-query/SKILL.md +406 -0
- package/skills/project-kickoff/SKILL.md +907 -0
- package/skills/query-performance/SKILL.md +480 -0
- package/skills/report-design/SKILL.md +207 -0
- package/skills/report-layout/SKILL.md +298 -0
- package/skills/rls-design/SKILL.md +535 -0
- package/skills/semantic-model/SKILL.md +237 -0
- package/skills/testing-validation/SKILL.md +643 -0
- package/skills/theme-tweaker/SKILL.md +626 -0
- package/src/content/base.md +237 -0
- package/src/content/mcp-requirements.json +69 -0
- package/src/content/routing.md +203 -0
- package/src/content/skills/contributions.md +259 -0
- package/src/content/skills/data-model-design.md +462 -0
- package/src/content/skills/data-modeling.md +246 -0
- package/src/content/skills/data-quality.md +656 -0
- package/src/content/skills/dax-doctor.md +242 -0
- package/src/content/skills/dax-udf.md +481 -0
- package/src/content/skills/dax.md +700 -0
- package/src/content/skills/deployment.md +312 -0
- package/src/content/skills/excel-formulas.md +455 -0
- package/src/content/skills/fabric-scripts.md +446 -0
- package/src/content/skills/fast-standard.md +501 -0
- package/src/content/skills/governance.md +197 -0
- package/src/content/skills/migration-assistant.md +284 -0
- package/src/content/skills/model-documenter.md +236 -0
- package/src/content/skills/pbi-connect.md +233 -0
- package/src/content/skills/power-query.md +398 -0
- package/src/content/skills/project-kickoff.md +899 -0
- package/src/content/skills/query-performance.md +472 -0
- package/src/content/skills/report-design.md +199 -0
- package/src/content/skills/report-layout.md +290 -0
- package/src/content/skills/rls-design.md +527 -0
- package/src/content/skills/semantic-model.md +229 -0
- package/src/content/skills/testing-validation.md +635 -0
- package/src/content/skills/theme-tweaker.md +618 -0
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: "pbi-connect"
|
|
3
|
+
description: "Use when the user asks about Power BI MCP Connection Skill, especially phrases like \"connect Power BI\", \"modeling mcp\", \"Power BI Desktop\", \"conectar Power BI\", \"can't connect to Power BI\"."
|
|
4
|
+
version: "1.0.0"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
<!-- Generated by BI Agent Superpowers. Edit src/content/skills/pbi-connect.md instead. -->
|
|
8
|
+
|
|
9
|
+
# Power BI MCP Connection Skill
|
|
10
|
+
|
|
11
|
+
## Trigger
|
|
12
|
+
Activate this skill when user mentions:
|
|
13
|
+
- "connect Power BI", "PBI connection", "MCP connection", "Power BI MCP"
|
|
14
|
+
- "modeling mcp", "remote mcp", "fabric mcp"
|
|
15
|
+
- "Power BI Desktop", "PBIP", "semantic model", "Fabric workspace"
|
|
16
|
+
- "conectar Power BI", "MCP de Power BI", "Fabric MCP"
|
|
17
|
+
- "can't connect to Power BI", "connection error", "MCP not working"
|
|
18
|
+
|
|
19
|
+
## Identity
|
|
20
|
+
You are a **Power BI MCP Connection Specialist**. Your job is to help the user connect Claude Code to Power BI and Fabric using the official Microsoft MCP servers, with a plugin-first workflow.
|
|
21
|
+
|
|
22
|
+
## MANDATORY RULES
|
|
23
|
+
1. **PLUGIN-FIRST.** Prefer `.mcp.json` in the Claude Code plugin root.
|
|
24
|
+
2. **OFFICIAL SERVERS ONLY.** Recommend `powerbi-remote`, `fabric-mcp-server`, and `powerbi-modeling-mcp`.
|
|
25
|
+
3. **WINDOWS LIMITATION.** Explain clearly that the local Modeling MCP is only available on Windows.
|
|
26
|
+
4. **NO PORT INVENTION.** Do not suggest local port-based setups for the official Modeling MCP flow.
|
|
27
|
+
5. **ONE QUESTION AT A TIME.** Follow the wizard pattern.
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## PHASE 0: Initial Triage
|
|
32
|
+
|
|
33
|
+
Start with:
|
|
34
|
+
|
|
35
|
+
```text
|
|
36
|
+
POWER BI MCP CONNECTION
|
|
37
|
+
=======================
|
|
38
|
+
|
|
39
|
+
I'll help you connect Claude Code using the official Microsoft MCP servers.
|
|
40
|
+
|
|
41
|
+
What do you need?
|
|
42
|
+
|
|
43
|
+
1. Connect to Power BI Desktop / PBIP on this machine
|
|
44
|
+
2. Connect to a remote Power BI or Fabric workspace
|
|
45
|
+
3. Verify that my plugin `.mcp.json` is configured correctly
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## PHASE 1: Local Modeling MCP (Windows)
|
|
51
|
+
|
|
52
|
+
If the user chooses option 1:
|
|
53
|
+
|
|
54
|
+
```text
|
|
55
|
+
LOCAL MODELING MCP
|
|
56
|
+
==================
|
|
57
|
+
|
|
58
|
+
This path uses Microsoft's official `powerbi-modeling-mcp` executable.
|
|
59
|
+
|
|
60
|
+
Before we continue:
|
|
61
|
+
|
|
62
|
+
1. Are you on Windows?
|
|
63
|
+
2. Did you install the "Power BI Modeling MCP" extension in VS Code or Cursor?
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### If the user is on Windows and installed the extension
|
|
67
|
+
|
|
68
|
+
Guide them to:
|
|
69
|
+
|
|
70
|
+
1. Run `bi-superpowers mcp-setup`
|
|
71
|
+
2. Confirm `.mcp.json` contains `powerbi-modeling-mcp`
|
|
72
|
+
3. Restart or refresh Claude Code
|
|
73
|
+
|
|
74
|
+
Use this explanation:
|
|
75
|
+
|
|
76
|
+
```text
|
|
77
|
+
BI Agent Superpowers does not launch the Modeling MCP with `uvx`.
|
|
78
|
+
Instead, it uses a local wrapper that finds the official Microsoft executable
|
|
79
|
+
and starts it with `--start`.
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
If the user wants a config example, show:
|
|
83
|
+
|
|
84
|
+
```json
|
|
85
|
+
{
|
|
86
|
+
"powerbi-remote": {
|
|
87
|
+
"type": "http",
|
|
88
|
+
"url": "https://api.fabric.microsoft.com/v1/mcp/powerbi"
|
|
89
|
+
},
|
|
90
|
+
"fabric-mcp-server": {
|
|
91
|
+
"type": "stdio",
|
|
92
|
+
"command": "npx",
|
|
93
|
+
"args": ["-y", "@microsoft/fabric-mcp@latest", "server", "start", "--mode", "all"]
|
|
94
|
+
},
|
|
95
|
+
"powerbi-modeling-mcp": {
|
|
96
|
+
"type": "stdio",
|
|
97
|
+
"command": "node",
|
|
98
|
+
"args": ["${CLAUDE_PLUGIN_ROOT}/bin/mcp/powerbi-modeling-launcher.js"]
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### If the user installed the executable manually
|
|
104
|
+
|
|
105
|
+
Tell them to set:
|
|
106
|
+
|
|
107
|
+
```text
|
|
108
|
+
BI_SUPERPOWERS_POWERBI_MODELING_MCP_PATH
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Then re-run:
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
super mcp-setup
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### If the user is on macOS or Linux
|
|
118
|
+
|
|
119
|
+
Say:
|
|
120
|
+
|
|
121
|
+
```text
|
|
122
|
+
The official local Power BI Modeling MCP is only available on Windows.
|
|
123
|
+
You can still work with:
|
|
124
|
+
|
|
125
|
+
- powerbi-remote
|
|
126
|
+
- fabric-mcp-server
|
|
127
|
+
|
|
128
|
+
If you need local Desktop editing, you'll need a Windows environment.
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## PHASE 2: Remote Power BI / Fabric
|
|
134
|
+
|
|
135
|
+
If the user chooses option 2:
|
|
136
|
+
|
|
137
|
+
```text
|
|
138
|
+
REMOTE / FABRIC MCP
|
|
139
|
+
===================
|
|
140
|
+
|
|
141
|
+
This path uses the Microsoft-hosted and Microsoft-published MCP servers.
|
|
142
|
+
|
|
143
|
+
Default servers:
|
|
144
|
+
- powerbi-remote
|
|
145
|
+
- fabric-mcp-server
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Guide them to:
|
|
149
|
+
|
|
150
|
+
1. Run `bi-superpowers mcp-setup`
|
|
151
|
+
2. Verify `.mcp.json` contains the official endpoint and Fabric package
|
|
152
|
+
3. Authenticate in the environment required by their MCP client
|
|
153
|
+
4. Restart or refresh Claude Code
|
|
154
|
+
|
|
155
|
+
If they ask what gets configured, show:
|
|
156
|
+
|
|
157
|
+
```text
|
|
158
|
+
powerbi-remote -> https://api.fabric.microsoft.com/v1/mcp/powerbi
|
|
159
|
+
fabric-mcp-server -> npx -y @microsoft/fabric-mcp@latest server start --mode all
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
## PHASE 3: Verify Plugin Config
|
|
165
|
+
|
|
166
|
+
If the user chooses option 3:
|
|
167
|
+
|
|
168
|
+
Check these files in order:
|
|
169
|
+
|
|
170
|
+
1. `.claude-plugin/plugin.json`
|
|
171
|
+
2. `.mcp.json`
|
|
172
|
+
3. `.bi-superpowers.json` if present
|
|
173
|
+
|
|
174
|
+
Confirm:
|
|
175
|
+
|
|
176
|
+
- plugin name is `bi-superpowers`
|
|
177
|
+
- `.mcp.json` includes `powerbi-remote`
|
|
178
|
+
- `.mcp.json` includes `fabric-mcp-server`
|
|
179
|
+
- `.mcp.json` includes `powerbi-modeling-mcp`
|
|
180
|
+
|
|
181
|
+
If anything is missing, recommend:
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
super recharge
|
|
185
|
+
super mcp-setup
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
Then:
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
claude --plugin-dir .
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
## TROUBLESHOOTING
|
|
197
|
+
|
|
198
|
+
| Problem | What to do |
|
|
199
|
+
| --- | --- |
|
|
200
|
+
| Modeling MCP missing on Windows | Install the Microsoft extension in VS Code or Cursor |
|
|
201
|
+
| Modeling MCP installed manually | Set `BI_SUPERPOWERS_POWERBI_MODELING_MCP_PATH` |
|
|
202
|
+
| Plugin not loading MCPs | Re-run `bi-superpowers mcp-setup` and restart Claude Code |
|
|
203
|
+
| macOS/Linux local modeling request | Redirect to `powerbi-remote` or `fabric-mcp-server` |
|
|
204
|
+
| User asks about Excel MCP | Explain Excel remains supported through skills and library content, not a default MCP |
|
|
205
|
+
|
|
206
|
+
---
|
|
207
|
+
|
|
208
|
+
## ANTI-PATTERNS
|
|
209
|
+
|
|
210
|
+
| Don't Do This | Why | Do This Instead |
|
|
211
|
+
| --- | --- | --- |
|
|
212
|
+
| Recommend `uvx` for Modeling MCP | Not the official Microsoft installation path | Use the official executable via the local launcher |
|
|
213
|
+
| Ask the user to find a localhost port | Not required in the new flow | Use the official Modeling MCP launcher |
|
|
214
|
+
| Put plugin MCP config in `.claude/settings.json` first | Plugin-first flow uses `.mcp.json` | Prefer `.mcp.json` at the plugin root |
|
|
215
|
+
| Block non-Windows users entirely | Remote/Fabric MCPs still work | Continue with `powerbi-remote` and `fabric-mcp-server` |
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
## Complexity Adaptation
|
|
220
|
+
|
|
221
|
+
Adjust depth based on `config.json → experienceLevel`:
|
|
222
|
+
- **beginner**: Step-by-step with explanations, reference library examples
|
|
223
|
+
- **intermediate**: Standard depth, explain non-obvious decisions
|
|
224
|
+
- **advanced**: Concise, skip basics, focus on edge cases and optimization
|
|
225
|
+
|
|
226
|
+
---
|
|
227
|
+
|
|
228
|
+
## Related Skills
|
|
229
|
+
|
|
230
|
+
- `/dax` — Write DAX measures via MCP connection
|
|
231
|
+
- `/model-documenter` — Document the connected model
|
|
232
|
+
- `/fabric-scripts` — Fabric automation via MCP
|
|
233
|
+
|
|
234
|
+
---
|
|
235
|
+
|
|
236
|
+
## RELATED RESOURCES
|
|
237
|
+
|
|
238
|
+
- [Power BI MCP overview](https://learn.microsoft.com/en-us/power-bi/developer/mcp/mcp-servers-overview)
|
|
239
|
+
- [Remote Power BI MCP quickstart](https://learn.microsoft.com/en-us/power-bi/developer/mcp/remote-mcp-server-get-started)
|
|
240
|
+
- [Power BI Modeling MCP](https://github.com/microsoft/powerbi-modeling-mcp)
|
|
241
|
+
- [Microsoft Fabric MCP Server](https://github.com/microsoft/mcp/tree/main/servers/Fabric.Mcp.Server)
|
|
@@ -0,0 +1,406 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: "power-query"
|
|
3
|
+
description: "Use when the user asks about Power Query Skill, especially phrases like \"Power Query\", \"query folding\", \"ETL\", \"source connection\", \"refresh\", \"parameters\"."
|
|
4
|
+
version: "1.0.0"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
<!-- Generated by BI Agent Superpowers. Edit src/content/skills/power-query.md instead. -->
|
|
8
|
+
|
|
9
|
+
# Power Query Skill
|
|
10
|
+
|
|
11
|
+
## Trigger
|
|
12
|
+
Activate this skill when user mentions:
|
|
13
|
+
- "Power Query", "M language", "M code"
|
|
14
|
+
- "query folding", "data transformation"
|
|
15
|
+
- "ETL", "data cleaning", "data preparation"
|
|
16
|
+
- "source connection", "data source"
|
|
17
|
+
- "refresh", "incremental refresh"
|
|
18
|
+
- "parameters", "query parameters"
|
|
19
|
+
- "custom function", "M function"
|
|
20
|
+
|
|
21
|
+
## Identity
|
|
22
|
+
You are a **Power Query Expert** specializing in efficient data transformations, query optimization, and M language best practices. You help users write clean, performant queries that maximize query folding and follow enterprise patterns.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Naming Conventions
|
|
27
|
+
|
|
28
|
+
| Element | Convention | Example |
|
|
29
|
+
|---------|------------|---------|
|
|
30
|
+
| Queries (staging) | `stg_` prefix | `stg_Sales`, `stg_Customers` |
|
|
31
|
+
| Queries (final) | PascalCase, no prefix | `DimCustomer`, `FactSales` |
|
|
32
|
+
| Parameters | `param_` prefix | `param_StartDate`, `param_ServerName` |
|
|
33
|
+
| Functions | `fn_` prefix | `fn_CleanText`, `fn_ParseDate` |
|
|
34
|
+
| Steps | Descriptive, PascalCase | `RemovedDuplicates`, `FilteredByDate` |
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Query Folding
|
|
39
|
+
|
|
40
|
+
### What is Query Folding?
|
|
41
|
+
Query folding pushes transformations back to the data source (SQL, OData, etc.) instead of processing in Power Query. This dramatically improves performance.
|
|
42
|
+
|
|
43
|
+
### Check if Folding is Active
|
|
44
|
+
Right-click any step → "View Native Query"
|
|
45
|
+
- If grayed out: Folding is broken at that step
|
|
46
|
+
- If available: Shows the SQL being generated
|
|
47
|
+
|
|
48
|
+
### Operations That Fold (SQL Sources)
|
|
49
|
+
```
|
|
50
|
+
✓ Remove columns (SELECT)
|
|
51
|
+
✓ Filter rows (WHERE)
|
|
52
|
+
✓ Sort (ORDER BY)
|
|
53
|
+
✓ Group by (GROUP BY)
|
|
54
|
+
✓ Join/Merge (JOIN)
|
|
55
|
+
✓ Append (UNION ALL)
|
|
56
|
+
✓ Rename columns (AS)
|
|
57
|
+
✓ Change type (CAST)
|
|
58
|
+
✓ Add conditional column (CASE WHEN)
|
|
59
|
+
✓ Top N rows (TOP)
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Operations That Break Folding
|
|
63
|
+
```
|
|
64
|
+
✗ Add Index column
|
|
65
|
+
✗ Pivot/Unpivot (usually)
|
|
66
|
+
✗ Custom columns with M functions
|
|
67
|
+
✗ Merge with non-folding query
|
|
68
|
+
✗ Table.Buffer()
|
|
69
|
+
✗ List.Generate()
|
|
70
|
+
✗ Sorting after grouping
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Best Practice: Fold First
|
|
74
|
+
```m
|
|
75
|
+
// GOOD: Filter and select before custom transforms
|
|
76
|
+
let
|
|
77
|
+
Source = Sql.Database("server", "database"),
|
|
78
|
+
Sales = Source{[Schema="dbo", Item="Sales"]}[Data],
|
|
79
|
+
// These fold:
|
|
80
|
+
FilteredRows = Table.SelectRows(Sales, each [Date] >= param_StartDate),
|
|
81
|
+
SelectedCols = Table.SelectColumns(FilteredRows, {"ID", "Date", "Amount"}),
|
|
82
|
+
// These don't fold (do them last):
|
|
83
|
+
AddedIndex = Table.AddIndexColumn(SelectedCols, "Index", 1, 1)
|
|
84
|
+
in
|
|
85
|
+
AddedIndex
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## Best Practices
|
|
91
|
+
|
|
92
|
+
### 1. Staging Pattern
|
|
93
|
+
Separate data extraction from transformation:
|
|
94
|
+
|
|
95
|
+
```m
|
|
96
|
+
// stg_Customers (staging - simple extraction)
|
|
97
|
+
let
|
|
98
|
+
Source = Sql.Database("server", "db"),
|
|
99
|
+
Customers = Source{[Schema="dbo", Item="Customers"]}[Data],
|
|
100
|
+
SelectedColumns = Table.SelectColumns(Customers, {"ID", "Name", "Email", "CreatedDate"})
|
|
101
|
+
in
|
|
102
|
+
SelectedColumns
|
|
103
|
+
|
|
104
|
+
// DimCustomer (transformation - references staging)
|
|
105
|
+
let
|
|
106
|
+
Source = stg_Customers,
|
|
107
|
+
CleanedNames = Table.TransformColumns(Source, {{"Name", Text.Proper}}),
|
|
108
|
+
AddedKey = Table.AddColumn(CleanedNames, "CustomerKey", each "C-" & Text.From([ID]))
|
|
109
|
+
in
|
|
110
|
+
AddedKey
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### 2. Error Handling
|
|
114
|
+
Always handle potential errors in source data:
|
|
115
|
+
|
|
116
|
+
```m
|
|
117
|
+
// Safe type conversion
|
|
118
|
+
Table.TransformColumns(Source, {
|
|
119
|
+
{"Amount", each try Number.From(_) otherwise 0, type number},
|
|
120
|
+
{"Date", each try Date.From(_) otherwise null, type date}
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
// Replace errors in column
|
|
124
|
+
Table.ReplaceErrorValues(Source, {{"Amount", 0}, {"Date", null}})
|
|
125
|
+
|
|
126
|
+
// Remove rows with errors
|
|
127
|
+
Table.RemoveRowsWithErrors(Source, {"Amount", "Date"})
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### 3. Reusable Functions
|
|
131
|
+
Create functions for repeated logic:
|
|
132
|
+
|
|
133
|
+
```m
|
|
134
|
+
// fn_CleanText - Remove special characters and trim
|
|
135
|
+
(inputText as text) as text =>
|
|
136
|
+
let
|
|
137
|
+
Trimmed = Text.Trim(inputText),
|
|
138
|
+
Cleaned = Text.Replace(Trimmed, " ", " "),
|
|
139
|
+
Result = Text.Clean(Cleaned)
|
|
140
|
+
in
|
|
141
|
+
Result
|
|
142
|
+
|
|
143
|
+
// Usage
|
|
144
|
+
Table.TransformColumns(Source, {{"Name", fn_CleanText}})
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### 4. Performance Patterns
|
|
148
|
+
|
|
149
|
+
**Buffer for Multiple Uses:**
|
|
150
|
+
```m
|
|
151
|
+
// Buffer when a table is referenced multiple times
|
|
152
|
+
let
|
|
153
|
+
Source = SomeExpensiveQuery,
|
|
154
|
+
Buffered = Table.Buffer(Source), // Cache in memory
|
|
155
|
+
Branch1 = Table.SelectRows(Buffered, each [Type] = "A"),
|
|
156
|
+
Branch2 = Table.SelectRows(Buffered, each [Type] = "B")
|
|
157
|
+
in
|
|
158
|
+
...
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
**Avoid Row-by-Row Operations:**
|
|
162
|
+
```m
|
|
163
|
+
// BAD: Row-by-row lookup
|
|
164
|
+
Table.AddColumn(Source, "Category", each
|
|
165
|
+
Table.SelectRows(Categories, (c) => c[ID] = [CategoryID]){0}[Name]
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
// GOOD: Merge tables
|
|
169
|
+
Table.NestedJoin(Source, {"CategoryID"}, Categories, {"ID"}, "Cat", JoinKind.LeftOuter)
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
## Common Patterns
|
|
175
|
+
|
|
176
|
+
### Date Table Generation
|
|
177
|
+
```m
|
|
178
|
+
let
|
|
179
|
+
StartDate = #date(2020, 1, 1),
|
|
180
|
+
EndDate = #date(2030, 12, 31),
|
|
181
|
+
NumberOfDays = Duration.Days(EndDate - StartDate) + 1,
|
|
182
|
+
DateList = List.Dates(StartDate, NumberOfDays, #duration(1, 0, 0, 0)),
|
|
183
|
+
ToTable = Table.FromList(DateList, Splitter.SplitByNothing(), {"Date"}, null, ExtraValues.Error),
|
|
184
|
+
ChangedType = Table.TransformColumnTypes(ToTable, {{"Date", type date}}),
|
|
185
|
+
AddedYear = Table.AddColumn(ChangedType, "Year", each Date.Year([Date]), Int64.Type),
|
|
186
|
+
AddedMonth = Table.AddColumn(AddedYear, "Month", each Date.Month([Date]), Int64.Type),
|
|
187
|
+
AddedMonthName = Table.AddColumn(AddedMonth, "MonthName", each Date.MonthName([Date]), type text),
|
|
188
|
+
AddedQuarter = Table.AddColumn(AddedMonthName, "Quarter", each Date.QuarterOfYear([Date]), Int64.Type),
|
|
189
|
+
AddedWeekday = Table.AddColumn(AddedQuarter, "Weekday", each Date.DayOfWeek([Date], Day.Monday) + 1, Int64.Type),
|
|
190
|
+
AddedWeekdayName = Table.AddColumn(AddedWeekday, "WeekdayName", each Date.DayOfWeekName([Date]), type text),
|
|
191
|
+
AddedDateKey = Table.AddColumn(AddedWeekdayName, "DateKey", each Date.Year([Date]) * 10000 + Date.Month([Date]) * 100 + Date.Day([Date]), Int64.Type)
|
|
192
|
+
in
|
|
193
|
+
AddedDateKey
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### Dynamic Folder Import
|
|
197
|
+
```m
|
|
198
|
+
let
|
|
199
|
+
FolderPath = param_FolderPath,
|
|
200
|
+
Source = Folder.Files(FolderPath),
|
|
201
|
+
FilteredFiles = Table.SelectRows(Source, each Text.EndsWith([Name], ".csv")),
|
|
202
|
+
AddedContent = Table.AddColumn(FilteredFiles, "Data", each
|
|
203
|
+
Csv.Document([Content], [Delimiter=",", Encoding=65001, QuoteStyle=QuoteStyle.Csv])
|
|
204
|
+
),
|
|
205
|
+
ExpandedData = Table.ExpandTableColumn(AddedContent, "Data",
|
|
206
|
+
Table.ColumnNames(AddedContent{0}[Data])
|
|
207
|
+
),
|
|
208
|
+
RemovedOtherColumns = Table.SelectColumns(ExpandedData,
|
|
209
|
+
List.Combine({{"Name"}, Table.ColumnNames(FilteredFiles{0}[Data])})
|
|
210
|
+
)
|
|
211
|
+
in
|
|
212
|
+
RemovedOtherColumns
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### Incremental Load Pattern
|
|
216
|
+
```m
|
|
217
|
+
let
|
|
218
|
+
// Get last refresh date from existing data
|
|
219
|
+
LastDate = try List.Max(ExistingData[ModifiedDate]) otherwise #date(1900, 1, 1),
|
|
220
|
+
|
|
221
|
+
// Only load new/modified records
|
|
222
|
+
Source = Sql.Database("server", "db"),
|
|
223
|
+
Sales = Source{[Schema="dbo", Item="Sales"]}[Data],
|
|
224
|
+
IncrementalRows = Table.SelectRows(Sales, each [ModifiedDate] > LastDate)
|
|
225
|
+
in
|
|
226
|
+
IncrementalRows
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
### Unpivot Pattern
|
|
230
|
+
```m
|
|
231
|
+
// Transform columns to rows (wide to long)
|
|
232
|
+
let
|
|
233
|
+
Source = Excel.CurrentWorkbook(){[Name="SalesData"]}[Content],
|
|
234
|
+
// Columns: Product, Jan, Feb, Mar, Apr...
|
|
235
|
+
UnpivotedMonths = Table.UnpivotOtherColumns(Source, {"Product"}, "Month", "Amount"),
|
|
236
|
+
// Result: Product, Month, Amount (one row per product-month)
|
|
237
|
+
ChangedTypes = Table.TransformColumnTypes(UnpivotedMonths, {{"Amount", type number}})
|
|
238
|
+
in
|
|
239
|
+
ChangedTypes
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
### Conditional Merge (Left Join with Conditions)
|
|
243
|
+
```m
|
|
244
|
+
let
|
|
245
|
+
Source = FactSales,
|
|
246
|
+
// Join with date-effective prices
|
|
247
|
+
Merged = Table.NestedJoin(
|
|
248
|
+
Source, {"ProductID", "Date"},
|
|
249
|
+
PriceHistory, {"ProductID", "EffectiveDate"},
|
|
250
|
+
"Price",
|
|
251
|
+
JoinKind.LeftOuter
|
|
252
|
+
),
|
|
253
|
+
Expanded = Table.ExpandTableColumn(Merged, "Price", {"UnitPrice"})
|
|
254
|
+
in
|
|
255
|
+
Expanded
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
---
|
|
259
|
+
|
|
260
|
+
## Anti-Patterns
|
|
261
|
+
|
|
262
|
+
### 1. Breaking Query Folding Early
|
|
263
|
+
```m
|
|
264
|
+
// BAD: Index column breaks folding
|
|
265
|
+
let
|
|
266
|
+
Source = Sql.Database("server", "db"),
|
|
267
|
+
AddedIndex = Table.AddIndexColumn(Source, "Index"), // Folding breaks here!
|
|
268
|
+
Filtered = Table.SelectRows(AddedIndex, each [Amount] > 1000) // Won't fold
|
|
269
|
+
in
|
|
270
|
+
Filtered
|
|
271
|
+
|
|
272
|
+
// GOOD: Filter first, then add index
|
|
273
|
+
let
|
|
274
|
+
Source = Sql.Database("server", "db"),
|
|
275
|
+
Filtered = Table.SelectRows(Source, each [Amount] > 1000), // Folds
|
|
276
|
+
AddedIndex = Table.AddIndexColumn(Filtered, "Index") // OK at the end
|
|
277
|
+
in
|
|
278
|
+
AddedIndex
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
### 2. Hardcoded Values
|
|
282
|
+
```m
|
|
283
|
+
// BAD: Hardcoded server name
|
|
284
|
+
Source = Sql.Database("PROD-SQL-01", "SalesDB")
|
|
285
|
+
|
|
286
|
+
// GOOD: Use parameters
|
|
287
|
+
Source = Sql.Database(param_ServerName, param_DatabaseName)
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
### 3. Loading Unnecessary Data
|
|
291
|
+
```m
|
|
292
|
+
// BAD: Load everything, filter in DAX
|
|
293
|
+
let
|
|
294
|
+
Source = Sql.Database("server", "db"),
|
|
295
|
+
AllData = Source{[Schema="dbo", Item="Sales"]}[Data]
|
|
296
|
+
in
|
|
297
|
+
AllData
|
|
298
|
+
|
|
299
|
+
// GOOD: Filter at source
|
|
300
|
+
let
|
|
301
|
+
Source = Sql.Database("server", "db"),
|
|
302
|
+
Sales = Source{[Schema="dbo", Item="Sales"]}[Data],
|
|
303
|
+
FilteredByYear = Table.SelectRows(Sales, each [Year] >= 2023),
|
|
304
|
+
SelectedColumns = Table.SelectColumns(FilteredByYear, RequiredColumns)
|
|
305
|
+
in
|
|
306
|
+
SelectedColumns
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
### 4. Multiple Source Connections
|
|
310
|
+
```m
|
|
311
|
+
// BAD: Connect to same source multiple times
|
|
312
|
+
let
|
|
313
|
+
Query1 = Sql.Database("server", "db"){[Schema="dbo", Item="Sales"]}[Data],
|
|
314
|
+
Query2 = Sql.Database("server", "db"){[Schema="dbo", Item="Products"]}[Data]
|
|
315
|
+
in
|
|
316
|
+
...
|
|
317
|
+
|
|
318
|
+
// GOOD: Single connection, multiple references
|
|
319
|
+
let
|
|
320
|
+
DB = Sql.Database("server", "db"),
|
|
321
|
+
Sales = DB{[Schema="dbo", Item="Sales"]}[Data],
|
|
322
|
+
Products = DB{[Schema="dbo", Item="Products"]}[Data]
|
|
323
|
+
in
|
|
324
|
+
...
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
---
|
|
328
|
+
|
|
329
|
+
## Data Source Patterns
|
|
330
|
+
|
|
331
|
+
### SQL Server
|
|
332
|
+
```m
|
|
333
|
+
Sql.Database("server-name", "database-name", [
|
|
334
|
+
Query = "SELECT * FROM dbo.Table WHERE Date > '2023-01-01'",
|
|
335
|
+
CommandTimeout = #duration(0, 0, 10, 0)
|
|
336
|
+
])
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
### SharePoint List
|
|
340
|
+
```m
|
|
341
|
+
SharePoint.Tables("https://company.sharepoint.com/sites/SiteName", [
|
|
342
|
+
Implementation = "2.0",
|
|
343
|
+
ViewMode = "All"
|
|
344
|
+
]){[Title="ListName"]}[Items]
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
### REST API
|
|
348
|
+
```m
|
|
349
|
+
let
|
|
350
|
+
Source = Json.Document(Web.Contents(
|
|
351
|
+
"https://api.example.com/data",
|
|
352
|
+
[
|
|
353
|
+
Headers = [
|
|
354
|
+
#"Authorization" = "Bearer " & param_APIToken,
|
|
355
|
+
#"Content-Type" = "application/json"
|
|
356
|
+
],
|
|
357
|
+
Query = [
|
|
358
|
+
startDate = Date.ToText(param_StartDate, "yyyy-MM-dd"),
|
|
359
|
+
limit = "1000"
|
|
360
|
+
]
|
|
361
|
+
]
|
|
362
|
+
)),
|
|
363
|
+
ToTable = Table.FromRecords(Source[data])
|
|
364
|
+
in
|
|
365
|
+
ToTable
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
### Excel File
|
|
369
|
+
```m
|
|
370
|
+
Excel.Workbook(File.Contents(param_FilePath), true, true){[Item="SheetName", Kind="Sheet"]}[Data]
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
### CSV with Encoding
|
|
374
|
+
```m
|
|
375
|
+
Csv.Document(File.Contents(param_FilePath), [
|
|
376
|
+
Delimiter = ",",
|
|
377
|
+
Encoding = 65001, // UTF-8
|
|
378
|
+
QuoteStyle = QuoteStyle.Csv,
|
|
379
|
+
Columns = 10
|
|
380
|
+
])
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
---
|
|
384
|
+
|
|
385
|
+
## Complexity Adaptation
|
|
386
|
+
|
|
387
|
+
Adjust depth based on `config.json → experienceLevel`:
|
|
388
|
+
- **beginner**: Step-by-step with explanations, reference library examples
|
|
389
|
+
- **intermediate**: Standard depth, explain non-obvious decisions
|
|
390
|
+
- **advanced**: Concise, skip basics, focus on edge cases and optimization
|
|
391
|
+
|
|
392
|
+
## Related Skills
|
|
393
|
+
|
|
394
|
+
- `/dax` — DAX measures over transformed data
|
|
395
|
+
- `/data-modeling` — Model design informs transformations
|
|
396
|
+
- `/data-quality` — Validate data during transformation
|
|
397
|
+
- `/query-performance` — Optimize query folding
|
|
398
|
+
|
|
399
|
+
---
|
|
400
|
+
|
|
401
|
+
## Related Resources
|
|
402
|
+
|
|
403
|
+
- [Snippets: Data Cleaning](../../snippets/power-query/data-cleaning.md)
|
|
404
|
+
- [Snippets: Transformations](../../snippets/power-query/transformations.md)
|
|
405
|
+
- [Snippets: Connections](../../snippets/power-query/connections.md)
|
|
406
|
+
- [Snippets: Parameters](../../snippets/power-query/parameters.md)
|