@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.
Files changed (193) hide show
  1. package/.claude-plugin/plugin.json +8 -0
  2. package/.mcp.json +25 -0
  3. package/AGENTS.md +244 -0
  4. package/CHANGELOG.md +265 -0
  5. package/LICENSE +21 -0
  6. package/README.md +211 -0
  7. package/bin/build-plugin.js +30 -0
  8. package/bin/cli.js +1064 -0
  9. package/bin/commands/add.js +533 -0
  10. package/bin/commands/add.test.js +77 -0
  11. package/bin/commands/build-desktop.js +166 -0
  12. package/bin/commands/changelog.js +443 -0
  13. package/bin/commands/diff.js +325 -0
  14. package/bin/commands/lint.js +419 -0
  15. package/bin/commands/lint.test.js +103 -0
  16. package/bin/commands/mcp-setup.js +246 -0
  17. package/bin/commands/pull.js +287 -0
  18. package/bin/commands/pull.test.js +36 -0
  19. package/bin/commands/push.js +231 -0
  20. package/bin/commands/push.test.js +14 -0
  21. package/bin/commands/search.js +344 -0
  22. package/bin/commands/search.test.js +115 -0
  23. package/bin/commands/setup.js +545 -0
  24. package/bin/commands/setup.test.js +46 -0
  25. package/bin/commands/sync-profile.js +405 -0
  26. package/bin/commands/sync-profile.test.js +14 -0
  27. package/bin/commands/sync-source.js +418 -0
  28. package/bin/commands/sync-source.test.js +14 -0
  29. package/bin/commands/watch.js +206 -0
  30. package/bin/lib/generators/claude-plugin.js +266 -0
  31. package/bin/lib/generators/claude-plugin.test.js +110 -0
  32. package/bin/lib/generators/index.js +116 -0
  33. package/bin/lib/generators/shared.js +282 -0
  34. package/bin/lib/licensing/index.js +35 -0
  35. package/bin/lib/licensing/storage.js +364 -0
  36. package/bin/lib/licensing/storage.test.js +55 -0
  37. package/bin/lib/licensing/validator.js +213 -0
  38. package/bin/lib/licensing/validator.test.js +137 -0
  39. package/bin/lib/microsoft-mcp.js +176 -0
  40. package/bin/lib/microsoft-mcp.test.js +106 -0
  41. package/bin/lib/skills.js +84 -0
  42. package/bin/mcp/powerbi-modeling-launcher.js +38 -0
  43. package/bin/postinstall.js +44 -0
  44. package/bin/utils/errors.js +159 -0
  45. package/bin/utils/git.js +298 -0
  46. package/bin/utils/logger.js +142 -0
  47. package/bin/utils/mcp-detect.js +274 -0
  48. package/bin/utils/mcp-detect.test.js +105 -0
  49. package/bin/utils/pbix.js +305 -0
  50. package/bin/utils/pbix.test.js +37 -0
  51. package/bin/utils/profiles.js +312 -0
  52. package/bin/utils/projects.js +168 -0
  53. package/bin/utils/readline.js +206 -0
  54. package/bin/utils/readline.test.js +47 -0
  55. package/bin/utils/tui.js +314 -0
  56. package/bin/utils/tui.test.js +127 -0
  57. package/commands/contributions.md +265 -0
  58. package/commands/data-model-design.md +468 -0
  59. package/commands/dax-doctor.md +248 -0
  60. package/commands/fabric-scripts.md +452 -0
  61. package/commands/migration-assistant.md +290 -0
  62. package/commands/model-documenter.md +242 -0
  63. package/commands/pbi-connect.md +239 -0
  64. package/commands/project-kickoff.md +905 -0
  65. package/commands/report-layout.md +296 -0
  66. package/commands/rls-design.md +533 -0
  67. package/commands/theme-tweaker.md +624 -0
  68. package/config.example.json +23 -0
  69. package/config.json +23 -0
  70. package/desktop-extension/manifest.json +37 -0
  71. package/desktop-extension/package.json +10 -0
  72. package/desktop-extension/server.js +95 -0
  73. package/docs/openrouter-free-models.md +92 -0
  74. package/library/examples/README.md +151 -0
  75. package/library/examples/finance-reporting/README.md +351 -0
  76. package/library/examples/finance-reporting/data-model.md +267 -0
  77. package/library/examples/finance-reporting/measures.dax +557 -0
  78. package/library/examples/hr-analytics/README.md +371 -0
  79. package/library/examples/hr-analytics/data-model.md +315 -0
  80. package/library/examples/hr-analytics/measures.dax +460 -0
  81. package/library/examples/marketing-analytics/README.md +37 -0
  82. package/library/examples/marketing-analytics/data-model.md +62 -0
  83. package/library/examples/marketing-analytics/measures.dax +110 -0
  84. package/library/examples/retail-analytics/README.md +439 -0
  85. package/library/examples/retail-analytics/data-model.md +288 -0
  86. package/library/examples/retail-analytics/measures.dax +481 -0
  87. package/library/examples/supply-chain/README.md +37 -0
  88. package/library/examples/supply-chain/data-model.md +69 -0
  89. package/library/examples/supply-chain/measures.dax +77 -0
  90. package/library/examples/udf-library/README.md +228 -0
  91. package/library/examples/udf-library/functions.dax +571 -0
  92. package/library/snippets/dax/README.md +292 -0
  93. package/library/snippets/dax/business-domains.md +576 -0
  94. package/library/snippets/dax/calculate-patterns.md +276 -0
  95. package/library/snippets/dax/calculation-groups.md +489 -0
  96. package/library/snippets/dax/error-handling.md +495 -0
  97. package/library/snippets/dax/iterators-and-aggregations.md +474 -0
  98. package/library/snippets/dax/kpis-and-metrics.md +293 -0
  99. package/library/snippets/dax/rankings-and-topn.md +235 -0
  100. package/library/snippets/dax/security-patterns.md +413 -0
  101. package/library/snippets/dax/text-and-formatting.md +316 -0
  102. package/library/snippets/dax/time-intelligence.md +196 -0
  103. package/library/snippets/dax/user-defined-functions.md +477 -0
  104. package/library/snippets/dax/virtual-tables.md +546 -0
  105. package/library/snippets/excel-formulas/README.md +84 -0
  106. package/library/snippets/excel-formulas/aggregations.md +330 -0
  107. package/library/snippets/excel-formulas/dates-and-times.md +361 -0
  108. package/library/snippets/excel-formulas/dynamic-arrays.md +314 -0
  109. package/library/snippets/excel-formulas/lookups.md +169 -0
  110. package/library/snippets/excel-formulas/text-functions.md +363 -0
  111. package/library/snippets/governance/naming-conventions.md +97 -0
  112. package/library/snippets/governance/review-checklists.md +107 -0
  113. package/library/snippets/power-query/README.md +389 -0
  114. package/library/snippets/power-query/api-integration.md +707 -0
  115. package/library/snippets/power-query/connections.md +434 -0
  116. package/library/snippets/power-query/data-cleaning.md +298 -0
  117. package/library/snippets/power-query/error-handling.md +526 -0
  118. package/library/snippets/power-query/parameters.md +350 -0
  119. package/library/snippets/power-query/performance.md +506 -0
  120. package/library/snippets/power-query/transformations.md +330 -0
  121. package/library/snippets/report-design/accessibility.md +78 -0
  122. package/library/snippets/report-design/chart-selection.md +54 -0
  123. package/library/snippets/report-design/layout-patterns.md +87 -0
  124. package/library/templates/data-models/README.md +93 -0
  125. package/library/templates/data-models/finance-model.md +627 -0
  126. package/library/templates/data-models/retail-star-schema.md +473 -0
  127. package/library/templates/excel/README.md +83 -0
  128. package/library/templates/excel/budget-tracker.md +432 -0
  129. package/library/templates/excel/data-entry-form.md +533 -0
  130. package/library/templates/power-bi/README.md +72 -0
  131. package/library/templates/power-bi/finance-report.md +449 -0
  132. package/library/templates/power-bi/kpi-scorecard.md +461 -0
  133. package/library/templates/power-bi/sales-dashboard.md +281 -0
  134. package/library/themes/excel/README.md +436 -0
  135. package/library/themes/power-bi/README.md +271 -0
  136. package/library/themes/power-bi/accessible.json +307 -0
  137. package/library/themes/power-bi/bi-superpowers-default.json +858 -0
  138. package/library/themes/power-bi/corporate-blue.json +291 -0
  139. package/library/themes/power-bi/dark-mode.json +291 -0
  140. package/library/themes/power-bi/minimal.json +292 -0
  141. package/library/themes/power-bi/print-friendly.json +309 -0
  142. package/package.json +93 -0
  143. package/skills/contributions/SKILL.md +267 -0
  144. package/skills/data-model-design/SKILL.md +470 -0
  145. package/skills/data-modeling/SKILL.md +254 -0
  146. package/skills/data-quality/SKILL.md +664 -0
  147. package/skills/dax/SKILL.md +708 -0
  148. package/skills/dax-doctor/SKILL.md +250 -0
  149. package/skills/dax-udf/SKILL.md +489 -0
  150. package/skills/deployment/SKILL.md +320 -0
  151. package/skills/excel-formulas/SKILL.md +463 -0
  152. package/skills/fabric-scripts/SKILL.md +454 -0
  153. package/skills/fast-standard/SKILL.md +509 -0
  154. package/skills/governance/SKILL.md +205 -0
  155. package/skills/migration-assistant/SKILL.md +292 -0
  156. package/skills/model-documenter/SKILL.md +244 -0
  157. package/skills/pbi-connect/SKILL.md +241 -0
  158. package/skills/power-query/SKILL.md +406 -0
  159. package/skills/project-kickoff/SKILL.md +907 -0
  160. package/skills/query-performance/SKILL.md +480 -0
  161. package/skills/report-design/SKILL.md +207 -0
  162. package/skills/report-layout/SKILL.md +298 -0
  163. package/skills/rls-design/SKILL.md +535 -0
  164. package/skills/semantic-model/SKILL.md +237 -0
  165. package/skills/testing-validation/SKILL.md +643 -0
  166. package/skills/theme-tweaker/SKILL.md +626 -0
  167. package/src/content/base.md +237 -0
  168. package/src/content/mcp-requirements.json +69 -0
  169. package/src/content/routing.md +203 -0
  170. package/src/content/skills/contributions.md +259 -0
  171. package/src/content/skills/data-model-design.md +462 -0
  172. package/src/content/skills/data-modeling.md +246 -0
  173. package/src/content/skills/data-quality.md +656 -0
  174. package/src/content/skills/dax-doctor.md +242 -0
  175. package/src/content/skills/dax-udf.md +481 -0
  176. package/src/content/skills/dax.md +700 -0
  177. package/src/content/skills/deployment.md +312 -0
  178. package/src/content/skills/excel-formulas.md +455 -0
  179. package/src/content/skills/fabric-scripts.md +446 -0
  180. package/src/content/skills/fast-standard.md +501 -0
  181. package/src/content/skills/governance.md +197 -0
  182. package/src/content/skills/migration-assistant.md +284 -0
  183. package/src/content/skills/model-documenter.md +236 -0
  184. package/src/content/skills/pbi-connect.md +233 -0
  185. package/src/content/skills/power-query.md +398 -0
  186. package/src/content/skills/project-kickoff.md +899 -0
  187. package/src/content/skills/query-performance.md +472 -0
  188. package/src/content/skills/report-design.md +199 -0
  189. package/src/content/skills/report-layout.md +290 -0
  190. package/src/content/skills/rls-design.md +527 -0
  191. package/src/content/skills/semantic-model.md +229 -0
  192. package/src/content/skills/testing-validation.md +635 -0
  193. package/src/content/skills/theme-tweaker.md +618 -0
@@ -0,0 +1,495 @@
1
+ # Error Handling and Defensive DAX
2
+
3
+ Patterns for handling errors, blanks, edge cases, and creating robust measures.
4
+
5
+ ---
6
+
7
+ ## DIVIDE Function
8
+
9
+ ### Basic Safe Division
10
+
11
+ ```dax
12
+ -- Always use DIVIDE instead of /
13
+ Profit_Margin =
14
+ DIVIDE(
15
+ SUM(Sales[Profit]),
16
+ SUM(Sales[Revenue])
17
+ )
18
+ -- Returns BLANK if denominator is 0 or blank
19
+ ```
20
+
21
+ ### Custom Alternate Result
22
+
23
+ ```dax
24
+ -- Return 0 instead of BLANK
25
+ Profit_Margin_Zero =
26
+ DIVIDE(
27
+ SUM(Sales[Profit]),
28
+ SUM(Sales[Revenue]),
29
+ 0 -- Return 0 when can't divide
30
+ )
31
+ ```
32
+
33
+ ### Nested DIVIDE for Complex Calculations
34
+
35
+ ```dax
36
+ -- Multiple divisions with safety
37
+ Efficiency_Ratio =
38
+ DIVIDE(
39
+ DIVIDE(SUM(Sales[Units]), SUM(Staff[Hours])),
40
+ DIVIDE(SUM(Budget[Units]), SUM(Budget[Hours])),
41
+ 1 -- Return 1 (100%) if comparison not possible
42
+ )
43
+ ```
44
+
45
+ ---
46
+
47
+ ## BLANK Handling
48
+
49
+ ### ISBLANK / BLANK
50
+
51
+ ```dax
52
+ -- Check for blank and substitute
53
+ Sales_Display =
54
+ IF(
55
+ ISBLANK(SUM(Sales[Amount])),
56
+ 0,
57
+ SUM(Sales[Amount])
58
+ )
59
+ ```
60
+
61
+ ### COALESCE (DAX 2019+)
62
+
63
+ ```dax
64
+ -- First non-blank value
65
+ Customer_Contact =
66
+ COALESCE(
67
+ [PreferredEmail],
68
+ [WorkEmail],
69
+ [PersonalEmail],
70
+ "No Email"
71
+ )
72
+ ```
73
+
74
+ ```dax
75
+ -- Chain of fallback values
76
+ Revenue_Display =
77
+ COALESCE(
78
+ [Actual Revenue],
79
+ [Forecast Revenue],
80
+ [Budget Revenue],
81
+ 0
82
+ )
83
+ ```
84
+
85
+ ### Handle Blank in Comparisons
86
+
87
+ ```dax
88
+ -- Safe comparison with potential blanks
89
+ Has_Sales =
90
+ VAR _Sales = SUM(Sales[Amount])
91
+ RETURN
92
+ IF(
93
+ ISBLANK(_Sales) || _Sales = 0,
94
+ "No",
95
+ "Yes"
96
+ )
97
+ ```
98
+
99
+ ---
100
+
101
+ ## Error Handling
102
+
103
+ ### IFERROR - Catch All Errors
104
+
105
+ ```dax
106
+ -- Handle any calculation error
107
+ Safe_Calculation =
108
+ IFERROR(
109
+ [ComplexMeasure] / [AnotherMeasure],
110
+ BLANK()
111
+ )
112
+ ```
113
+
114
+ ### ISERROR - Test Before Calculate
115
+
116
+ ```dax
117
+ -- Test for error condition
118
+ Error_Status =
119
+ IF(
120
+ ISERROR([RiskyCalculation]),
121
+ "Error in calculation",
122
+ FORMAT([RiskyCalculation], "#,##0")
123
+ )
124
+ ```
125
+
126
+ ### Error Handling in Iterators
127
+
128
+ ```dax
129
+ -- Safe iteration with error handling
130
+ Total_Safe =
131
+ SUMX(
132
+ Sales,
133
+ IFERROR(
134
+ Sales[Quantity] * Sales[Price] / Sales[Discount],
135
+ Sales[Quantity] * Sales[Price] -- Fallback if error
136
+ )
137
+ )
138
+ ```
139
+
140
+ ---
141
+
142
+ ## Null and Empty String Handling
143
+
144
+ ### Distinguish BLANK from Empty String
145
+
146
+ ```dax
147
+ -- Check for truly empty values
148
+ Has_Value =
149
+ VAR _Value = SELECTEDVALUE(Products[Description])
150
+ RETURN
151
+ IF(
152
+ ISBLANK(_Value) || _Value = "",
153
+ FALSE(),
154
+ TRUE()
155
+ )
156
+ ```
157
+
158
+ ### Clean Text Input
159
+
160
+ ```dax
161
+ -- Handle various empty states
162
+ Clean_Name =
163
+ VAR _Raw = SELECTEDVALUE(Customers[Name])
164
+ RETURN
165
+ IF(
166
+ ISBLANK(_Raw) || TRIM(_Raw) = "" || _Raw = "N/A" || _Raw = "NULL",
167
+ "(Unknown)",
168
+ TRIM(_Raw)
169
+ )
170
+ ```
171
+
172
+ ---
173
+
174
+ ## Context Validation
175
+
176
+ ### HASONEVALUE - Single Selection Check
177
+
178
+ ```dax
179
+ -- Only calculate if single value selected
180
+ Unit_Price_Display =
181
+ IF(
182
+ HASONEVALUE(Products[ProductName]),
183
+ SELECTEDVALUE(Products[UnitPrice]),
184
+ BLANK() -- Don't show if multiple products
185
+ )
186
+ ```
187
+
188
+ ### HASONEFILTER - Filter Check
189
+
190
+ ```dax
191
+ -- Check if filter is applied
192
+ Status_Message =
193
+ IF(
194
+ HASONEFILTER(Products[Category]),
195
+ "Showing: " & SELECTEDVALUE(Products[Category]),
196
+ "All Categories"
197
+ )
198
+ ```
199
+
200
+ ### ISFILTERED / ISCROSSFILTERED
201
+
202
+ ```dax
203
+ -- Validate filter state
204
+ Contextual_Result =
205
+ SWITCH(
206
+ TRUE(),
207
+ NOT ISFILTERED(Products[Category]), [Total_All],
208
+ ISFILTERED(Products[Category]) && NOT ISCROSSFILTERED(Regions), [Total_Category],
209
+ [Total_Filtered]
210
+ )
211
+ ```
212
+
213
+ ### SELECTEDVALUE with Fallback
214
+
215
+ ```dax
216
+ -- Safe single value selection
217
+ Selected_Product =
218
+ SELECTEDVALUE(
219
+ Products[ProductName],
220
+ "(Multiple Products Selected)" -- Default when not single value
221
+ )
222
+ ```
223
+
224
+ ---
225
+
226
+ ## Date Validation
227
+
228
+ ### Check for Valid Dates
229
+
230
+ ```dax
231
+ -- Validate date exists
232
+ Days_Since_Order =
233
+ VAR _OrderDate = MAX(Sales[OrderDate])
234
+ VAR _Today = TODAY()
235
+ RETURN
236
+ IF(
237
+ ISBLANK(_OrderDate) || _OrderDate > _Today,
238
+ BLANK(),
239
+ DATEDIFF(_OrderDate, _Today, DAY)
240
+ )
241
+ ```
242
+
243
+ ### Handle Date Range Edge Cases
244
+
245
+ ```dax
246
+ -- Safe date period calculation
247
+ Period_Sales =
248
+ VAR _StartDate = MIN('Date'[Date])
249
+ VAR _EndDate = MAX('Date'[Date])
250
+ RETURN
251
+ IF(
252
+ ISBLANK(_StartDate) || ISBLANK(_EndDate) || _StartDate > _EndDate,
253
+ BLANK(),
254
+ CALCULATE(
255
+ SUM(Sales[Amount]),
256
+ 'Date'[Date] >= _StartDate && 'Date'[Date] <= _EndDate
257
+ )
258
+ )
259
+ ```
260
+
261
+ ---
262
+
263
+ ## Data Quality Measures
264
+
265
+ ### Completeness Check
266
+
267
+ ```dax
268
+ Data_Completeness =
269
+ VAR _TotalRows = COUNTROWS(Sales)
270
+ VAR _CompleteRows =
271
+ COUNTROWS(
272
+ FILTER(
273
+ Sales,
274
+ NOT ISBLANK(Sales[Amount])
275
+ && NOT ISBLANK(Sales[CustomerID])
276
+ && NOT ISBLANK(Sales[ProductID])
277
+ && NOT ISBLANK(Sales[Date])
278
+ )
279
+ )
280
+ RETURN
281
+ DIVIDE(_CompleteRows, _TotalRows)
282
+ ```
283
+
284
+ ### Duplicate Detection
285
+
286
+ ```dax
287
+ Duplicate_Orders =
288
+ VAR _UniqueOrders = DISTINCTCOUNT(Sales[OrderID])
289
+ VAR _TotalRows = COUNTROWS(Sales)
290
+ RETURN
291
+ IF(
292
+ _UniqueOrders < _TotalRows,
293
+ _TotalRows - _UniqueOrders,
294
+ 0
295
+ )
296
+ ```
297
+
298
+ ### Outlier Detection
299
+
300
+ ```dax
301
+ Outlier_Count =
302
+ VAR _Avg = AVERAGE(Sales[Amount])
303
+ VAR _StdDev =
304
+ SQRT(
305
+ AVERAGEX(Sales, POWER(Sales[Amount] - _Avg, 2))
306
+ )
307
+ VAR _LowerBound = _Avg - (3 * _StdDev)
308
+ VAR _UpperBound = _Avg + (3 * _StdDev)
309
+ RETURN
310
+ COUNTROWS(
311
+ FILTER(
312
+ Sales,
313
+ Sales[Amount] < _LowerBound || Sales[Amount] > _UpperBound
314
+ )
315
+ )
316
+ ```
317
+
318
+ ---
319
+
320
+ ## Conditional Logic Patterns
321
+
322
+ ### SWITCH with Catch-All
323
+
324
+ ```dax
325
+ -- Always include default case
326
+ Region_Group =
327
+ SWITCH(
328
+ SELECTEDVALUE(Geography[Country]),
329
+ "USA", "North America",
330
+ "Canada", "North America",
331
+ "Mexico", "North America",
332
+ "UK", "Europe",
333
+ "Germany", "Europe",
334
+ "France", "Europe",
335
+ "Other" -- Catch-all for unknown values
336
+ )
337
+ ```
338
+
339
+ ### SWITCH TRUE Pattern
340
+
341
+ ```dax
342
+ -- Complex conditional with error handling
343
+ Performance_Level =
344
+ VAR _Value = [Sales_vs_Target]
345
+ RETURN
346
+ SWITCH(
347
+ TRUE(),
348
+ ISBLANK(_Value), "No Data",
349
+ ISERROR(_Value), "Error",
350
+ _Value >= 1.2, "Exceeds",
351
+ _Value >= 1.0, "Meets",
352
+ _Value >= 0.8, "Below",
353
+ _Value < 0.8, "Critical",
354
+ "Unknown" -- Should never reach here
355
+ )
356
+ ```
357
+
358
+ ### Nested IF vs SWITCH
359
+
360
+ ```dax
361
+ -- Prefer SWITCH for multiple conditions
362
+ -- Less error-prone than nested IFs
363
+ Status_SWITCH =
364
+ SWITCH(
365
+ TRUE(),
366
+ [DaysOverdue] > 90, "Critical",
367
+ [DaysOverdue] > 60, "Severe",
368
+ [DaysOverdue] > 30, "Warning",
369
+ [DaysOverdue] > 0, "Overdue",
370
+ [DaysOverdue] = 0, "Due Today",
371
+ "On Track"
372
+ )
373
+ ```
374
+
375
+ ---
376
+
377
+ ## Debug Measures
378
+
379
+ ### Show Calculation Context
380
+
381
+ ```dax
382
+ -- Debug: Show current filter context
383
+ Debug_Context =
384
+ "Products: " & COUNTROWS(Products) &
385
+ " | Dates: " & COUNTROWS('Date') &
386
+ " | Filtered: " & IF(ISFILTERED(Products), "Yes", "No")
387
+ ```
388
+
389
+ ### Trace Measure Calculation
390
+
391
+ ```dax
392
+ -- Debug: Step-by-step calculation
393
+ Debug_Calculation =
394
+ VAR _Step1 = SUM(Sales[Quantity])
395
+ VAR _Step2 = AVERAGE(Sales[UnitPrice])
396
+ VAR _Step3 = _Step1 * _Step2
397
+ VAR _Step4 = DIVIDE(_Step3, 100)
398
+ RETURN
399
+ "Qty:" & _Step1 &
400
+ " | AvgPrice:" & _Step2 &
401
+ " | Product:" & _Step3 &
402
+ " | Result:" & _Step4
403
+ ```
404
+
405
+ ### Validate Intermediate Results
406
+
407
+ ```dax
408
+ -- Production measure with validation
409
+ Revenue_Validated =
410
+ VAR _Quantity = SUM(Sales[Quantity])
411
+ VAR _Price = AVERAGE(Sales[UnitPrice])
412
+ VAR _Result = _Quantity * _Price
413
+ RETURN
414
+ IF(
415
+ _Quantity < 0 || _Price < 0,
416
+ ERROR("Negative values detected in Revenue calculation"),
417
+ _Result
418
+ )
419
+ ```
420
+
421
+ ---
422
+
423
+ ## Best Practices
424
+
425
+ ### 1. Always Use DIVIDE
426
+
427
+ ```dax
428
+ -- Never do this
429
+ Bad_Ratio = [Sales] / [Customers]
430
+
431
+ -- Always do this
432
+ Good_Ratio = DIVIDE([Sales], [Customers])
433
+ ```
434
+
435
+ ### 2. Validate Before Calculate
436
+
437
+ ```dax
438
+ -- Check inputs before complex calculation
439
+ Complex_Result =
440
+ IF(
441
+ ISBLANK([Input1]) || ISBLANK([Input2]) || [Input2] = 0,
442
+ BLANK(),
443
+ [ComplexCalculation]
444
+ )
445
+ ```
446
+
447
+ ### 3. Use Variables for Intermediate Checks
448
+
449
+ ```dax
450
+ -- Capture values once, validate, then calculate
451
+ Safe_Growth =
452
+ VAR _Current = SUM(Sales[Amount])
453
+ VAR _Prior = [Sales_PY]
454
+ RETURN
455
+ IF(
456
+ ISBLANK(_Current) || ISBLANK(_Prior) || _Prior = 0,
457
+ BLANK(),
458
+ DIVIDE(_Current - _Prior, _Prior)
459
+ )
460
+ ```
461
+
462
+ ### 4. Handle Edge Cases Explicitly
463
+
464
+ ```dax
465
+ -- Consider all scenarios
466
+ Date_Status =
467
+ VAR _Date = SELECTEDVALUE(Sales[DueDate])
468
+ VAR _Today = TODAY()
469
+ RETURN
470
+ SWITCH(
471
+ TRUE(),
472
+ ISBLANK(_Date), "No Due Date",
473
+ _Date < DATE(1900, 1, 1), "Invalid Date",
474
+ _Date > DATE(2100, 12, 31), "Invalid Date",
475
+ _Date < _Today, "Past Due",
476
+ _Date = _Today, "Due Today",
477
+ _Date <= _Today + 7, "Due This Week",
478
+ "Upcoming"
479
+ )
480
+ ```
481
+
482
+ ---
483
+
484
+ ## Error Prevention Checklist
485
+
486
+ | Issue | Prevention |
487
+ |-------|------------|
488
+ | Division by zero | Use DIVIDE() |
489
+ | Blank values | ISBLANK() checks, COALESCE() |
490
+ | Missing data | SELECTEDVALUE with alternate |
491
+ | Invalid dates | Date range validation |
492
+ | Context errors | HASONEVALUE, ISFILTERED |
493
+ | Type mismatches | Explicit conversions |
494
+ | Calculation errors | IFERROR wrapper |
495
+ | Edge cases | SWITCH TRUE with default |