SuperAPI AI Directory

data-discovery

Data & analytics

View repository

Updated 10-16 06:47

About this skill

Table of Contents

Task Reference Notes
Must/Prefer/Avoid SKILL.md: Must/Prefer/Avoid Guardrails for schema discovery and DAX generation
Progressive Discovery Strategy SKILL.md: Progressive Schema Discovery Decision tree for on-demand metadata fetching
Recommended Discovery Order SKILL.md: Recommended Discovery Order Start with scope estimation -> tables -> columns -> measures -> relationships
Metadata Object -> INFO Function Map SKILL.md: Metadata Object -> INFO Function Map Tables, columns, measures, relationships, calc groups, calendars, UDFs, variations
Scope Estimation Queries discovery-queries.md: Scope Estimation Queries Probe table/column/measure/relationship counts before deep discovery
INFO Output Columns discovery-queries.md: INFO Output Columns INFO.VIEW.* (read access); INFO.* (may need elevated access)
Narrowing Results (Projection + Filtering) discovery-queries.md: Narrowing Results SELECTCOLUMNS + FILTER to reduce output volume
Advanced Metadata (Calc Groups, Calendars, UDFs) discovery-queries.md: Advanced Metadata Queries INFO.CALCULATIONGROUPS, INFO.CALENDARS, INFO.USERDEFINEDFUNCTIONS, INFO.VARIATIONS
Complete INFO Function Catalog discovery-queries.md: Complete INFO Function Catalog Dynamic query to enumerate all INFO functions in the engine
Generating DAX Queries SKILL.md: Generating DAX Queries Core rules, inline examples, EVALUATE/DEFINE patterns
DAX Query Structure & Syntax dax-query-patterns.md: Query Structure DEFINE / EVALUATE / ORDER BY / START AT
DAX Query Key Components dax-query-patterns.md: Key Components DEFINE VAR, DEFINE MEASURE, table expressions
DAX Query Worked Examples dax-query-patterns.md: Common Patterns 11 annotated examples from simple aggregation to cross-table joins
DAX Query Anti-Patterns dax-query-patterns.md: Anti-Patterns What to avoid in DAX queries
CALCULATE & CALCULATETABLE dax-core-reference.md: CALCULATE & CALCULATETABLE Context transition, filter types, boolean restrictions, common patterns
SUMMARIZECOLUMNS dax-core-reference.md: SUMMARIZECOLUMNS Argument order, auto-blank elimination, filter args, vs SUMMARIZE
ALL & ALLEXCEPT dax-core-reference.md: ALL & ALLEXCEPT CALCULATE modifier vs table function; percentage patterns
TREATAS dax-core-reference.md: TREATAS Virtual relationships, multi-column filtering
DAX Syntax Rules dax-core-reference.md: DAX Syntax Rules EVALUATE, CALCULATE, naming, SQL keywords, DEFINE rules
Common Mistakes dax-core-reference.md: Common Mistakes Variable naming, quoting, escaping, scalar EVALUATE, multi-table SUMMARIZECOLUMNS
BLANK Semantics dax-core-reference.md: BLANK Semantics BLANK vs NULL, propagation, equality, ISBLANK, DIVIDE, non-empty semantics
Time Intelligence Patterns SKILL.md: Time Intelligence When to consult TI reference
Date Table Prerequisites dax-time-intelligence.md: Prerequisites Date table requirements, mark as date table
YTD / QTD / MTD dax-time-intelligence.md: Period-to-Date TOTALYTD, DATESYTD, DATESINPERIOD patterns
Year-over-Year / Period Comparisons dax-time-intelligence.md: Period Comparisons SAMEPERIODLASTYEAR, DATEADD, PARALLELPERIOD
Rolling Windows dax-time-intelligence.md: Rolling Windows DATESINPERIOD rolling 12-month patterns
Opening/Closing Balances dax-time-intelligence.md: Balances Semi-additive measures, LASTDATE, LASTNONBLANK
TI in DAX Queries (Critical Rules) dax-time-intelligence.md: Critical Rules for TI in Queries CALCULATETABLE + TREATAS pattern for query context
TI Common Mistakes dax-time-intelligence.md: Common Mistakes Missing date table, wrong granularity, fiscal calendar
Testing & Iteration SKILL.md: Testing & Iteration Execute -> inspect -> fix -> re-test workflow
Query Execution SKILL.md: Query Execution CLI execute command
Query File Convention SKILL.md: Query File Convention .dax + .json + .ts barrel in src/queries/
Troubleshooting SKILL.md: Troubleshooting CLI issues, permission errors, syntax errors, unexpected results

Must / Prefer / Avoid

Must

  • Always test generated DAX via npx fabric-app-data query <alias> --query '<DAX>' before using in app code
  • Use fully-qualified 'Table'[Column] for column references
  • Use simple [Measure] for measure references
  • Use DEFINE for VAR and local MEASURE declarations (single DEFINE block, no commas)
  • Prefer existing model measures over re-aggregating raw data

Prefer

  • INFO.VIEW functions for initial metadata discovery (read access, lightweight)
  • SUMMARIZECOLUMNS as the primary grouping function for queries
  • TREATAS for filter arguments in SUMMARIZECOLUMNS
  • Variables (VAR) to improve readability and avoid repeated calculations
  • Progressive schema discovery over full schema dumps

Avoid

  • SQL keywords (SELECT, WHERE, HAVING, etc.) within DAX expressions
  • EVALUATE with scalar functions directly (wrap in ROW or table function)
  • Fetching full schema upfront - discover incrementally based on need
  • Re-fetching metadata already discovered in this conversation
  • Using GetSemanticModelSchema, DiscoverArtifacts, or GenerateQuery MCP tools (these are not available)

Progressive Schema Discovery

Discover metadata incrementally based on what the user actually needs.

Strategy (Decision Tree)

User asks a question
  -> Do I know which tables are relevant?
    -> NO: Run INFO.VIEW.TABLES() to get table inventory
    -> YES: Do I know the columns/measures for those tables?
      -> NO: Run filtered INFO.VIEW.COLUMNS() and INFO.VIEW.MEASURES() for those tables
      -> YES: Do I need relationships?
        -> YES: Run INFO.VIEW.RELATIONSHIPS() filtered to those tables
        -> NO: Do I need advanced metadata?
          -> Have elevated INFO functions already failed in this session?
            -> YES: Skip - assume no permission for all elevated queries
            -> NO: Try the relevant elevated query:
              -> Calculation groups: INFO.CALCULATIONGROUPS() + INFO.CALCULATIONITEMS()
              -> Calendars: INFO.CALENDARS()
              -> User-defined functions: INFO.USERDEFINEDFUNCTIONS()
              -> Variations: INFO.VARIATIONS()
              -> If query fails with permission error: mark elevated access as unavailable
  -> Generate DAX using discovered schema
  -> Test via ExecuteQuery

Rules

  • Start with scope estimation - Run the scope probe query first to understand model size
  • Discover on demand - Only fetch tables/columns/measures relevant to the current user request
  • Use INFO.VIEW functions first (read access) - tables, columns, measures, relationships
  • Use INFO functions (may need elevated access) for: calculation groups, calculation items, variations, user-defined functions, calendars
  • Handle permission failures gracefully - If an elevated INFO function fails but INFO.VIEW.* functions succeeded, assume the user lacks elevated permissions and skip all elevated discoveries entirely
  • Always narrow results - Use SELECTCOLUMNS + FILTER to fetch only needed columns and rows
  • Cache discovered schema mentally - Don't re-fetch what you've already discovered in this conversation

Recommended Discovery Order

  1. Scope estimation - Count tables, columns, measures, relationships
  2. Tables - Get table names, identify relevant ones
  3. Columns - Get columns for relevant tables only
  4. Measures - Get measures (prefer using these over raw aggregations)
  5. Relationships - Get relationships between relevant tables
  6. Advanced metadata (if needed) - Calculation groups, calendars, UDFs, variations

Scope Estimation Query

EVALUATE
ROW(
    "TableCount", COUNTROWS(INFO.VIEW.TABLES()),
    "ColumnCount", COUNTROWS(INFO.VIEW.COLUMNS()),
    "MeasureCount", COUNTROWS(INFO.VIEW.MEASURES()),
    "RelationshipCount", COUNTROWS(INFO.VIEW.RELATIONSHIPS())
)

Metadata Object -> INFO Function Map

Metadata Object Primary INFO Functions Access Level
Tables INFO.VIEW.TABLES() Read
Columns INFO.VIEW.COLUMNS() Read
Measures INFO.VIEW.MEASURES() Read
Relationships INFO.VIEW.RELATIONSHIPS() Read
Model config INFO.MODEL() May need elevated
Calculation groups INFO.CALCULATIONGROUPS(), INFO.CALCULATIONITEMS() May need elevated
Calendars INFO.CALENDARS(), INFO.CALENDARCOLUMNGROUPS(), INFO.CALENDARCOLUMNREFERENCES() May need elevated
User-defined functions INFO.USERDEFINEDFUNCTIONS() May need elevated
Variations INFO.VARIATIONS() May need elevated

For the full query catalog and output column details, see discovery-queries.md.

Generating DAX Queries

DAX Syntax Rules

  • Measures are named objects in the semantic model. They specify how to aggregate data. Measures should be used first to answer user requests before a new DAX formula is used to aggregate data.
  • EVALUATE Statement: Not a function but a statement. It must always precede a table expression. Avoid pairing EVALUATE with scalar functions like CONCATENATEX, SUMX, DISTINCTCOUNT, etc.
  • Use the fully-qualified name 'Table'[Column] for column references, and the simple name [Measure] for measure references.
  • CALCULATE takes a scalar expression as its first argument. CALCULATETABLE takes a table expression as its first argument.
  • SUMMARIZECOLUMNS requires a specific order: groupby columns, then filters, then aggregations/measures.
  • Do not use SUMMARIZECOLUMNS when there is no aggregation and the groupby columns belong to more than one table; use VALUES, SUMMARIZE, or SELECTCOLUMNS instead.
  • When using SELECTCOLUMNS or CALCULATETABLE, include any columns needed downstream (ORDER BY, FILTER).
  • Filters propagate across relationships based on unidirectional or bidirectional settings.
  • INTERSECT, UNION, EXCEPT require identical column counts in both inputs.
  • For current date/time, use TODAY() or NOW().

Inline Examples

Simple filtered aggregation:

// Total sales for red products
EVALUATE
  ROW("Total Sales Amount", CALCULATE([Total Amount], 'Product'[Color] == "Red"))

Multi-filter grouping with SUMMARIZECOLUMNS:

DEFINE
  VAR _Filter1 = TREATAS({"Consumer Electronics"}, 'Product'[Category])
  VAR _Filter2 = FILTER(ALL('Calendar'[Year]), 'Calendar'[Year] >= 2022 && 'Calendar'[Year] <= 2023)

EVALUATE
  SUMMARIZECOLUMNS(
    'Calendar'[Year],
    'Calendar'[Month],
    _Filter1,
    _Filter2,
    "Total Quantity", SUM('Sales'[Order Quantity]),
    "Discount", [Total Discount]
  )

TopN with filtering:

DEFINE
  VAR _Filter = TREATAS({"Red", "Black"}, 'Product'[Color])
  VAR _Core = SUMMARIZECOLUMNS('Product'[Name], _Filter, "Total Sales", [Total Amount])

EVALUATE
  TOPN(10, _Core, [Total Sales], DESC)

For full syntax reference, worked examples, and anti-patterns, see dax-query-patterns.md. For function details, see dax-core-reference.md.

Time Intelligence

Time intelligence functions enable period-based analysis (YTD, YoY, rolling windows, etc.). They require a properly configured Date table.

Consult dax-time-intelligence.md whenever the user's request involves:

  • Period-to-date calculations (YTD, QTD, MTD)
  • Period comparisons (Year-over-Year, Month-over-Month)
  • Rolling windows (last 12 months, last 30 days)
  • Opening/closing balances
  • Custom date ranges

Testing & Iteration

  1. Generate the DAX query expression
  2. Execute via npx fabric-app-data query <alias> --query '<DAX>'
  3. Inspect results: check column names, data types, row counts, and actual data values
  4. If error: consult dax-core-reference.md, fix, and re-test
  5. Iterate until the query returns expected results
  6. Promote finalized queries to the app codebase (see below)

Query Execution

Use npx fabric-app-data query <alias> --query '<DAX>' to run queries. This uses the same SDK pipeline as the running app, so results are identical to what the app produces at runtime. To re-test an existing .dax file without copying the query text, use --file: npx fabric-app-data query <alias> --file src/queries/revenue.dax.

Result trimming: The CLI returns at most 1000 rows by default. When the result is trimmed, the output includes a _cliWarning field (e.g., "Result trimmed to first 1000 of 5000 rows"). This is a CLI-only limitation — the full dataset is available in the running app. If you need to see more data, refine your DAX with filters or aggregations.

Promoting queries to the app

Once a query is validated, save it to the app codebase:

  • Store each query as a .dax file and its Vega-Lite spec as a .json file under src/queries/, grouped by page or domain. A barrel .ts file imports both and exports a factory function that returns { connection, query, columnMetadata, vegaLiteSpec }. The function accepts optional use-case-specific parameters that can modify the DAX query and/or the Vega-Lite spec. See the "Query & Spec Organization" section in AGENTS.md for the full convention.
  • Name files after the visualization they drive using kebab-case (e.g., revenue-by-region.dax, revenue-by-region.json, revenue-by-region.ts). The factory function name is the camelCase version of the file name (e.g., revenueByRegion).
  • Import .dax files with Vite's ?raw suffix to get them as strings.
  • Capture column metadata in the barrel .ts file as a columnMetadata: ColumnMetadataMap constant (import ColumnMetadataMap from @/lib/to-data-table). The dictionary must be keyed by the exact column name from the CLI query output (the name field in table.columns). Do not guess or clean these keys — copy them verbatim from the query result. Each value is a ColumnDef (from @microsoft/fabric-visuals-core) containing:
    • name — a cleaned-up identifier derived from the original column name by removing ., [, ], \, ", and ' characters. E.g., "Products[Region]" → "ProductsRegion", "[Total Revenue]" → "Total Revenue" - to be used when building visual specs.
    • displayName — a human-readable label sourced from the semantic model schema (e.g., "Region", "Total Revenue"). Used for axis titles, grid headers, and tooltips.
    • format — a VBA/ECMA-376 format string for number/date formatting (e.g., #,##0.00, 0.00%, and mm/dd/yyyy). Omit for text type columns.

Example workflow: Run npx fabric-app-data query myModel --query '<DAX>', observe the output columns are [SalesPersonID] and [Name], then use those exact strings as metadata keys:

export const columnMetadata: ColumnMetadataMap = {
  "[SalesPersonID]": { name: "SalesPersonID", displayName: "Sales Person ID" },
  "[Name]": { name: "Name", displayName: "Name" },
};

After promoting queries, switch to the data-fetching skill to wire them into React components.

Troubleshooting

Problem Solution
CLI execute fails with "not signed in" Run az login to sign in to Azure CLI
CLI execute fails with "Azure CLI is not installed" Install from https://aka.ms/install-azure-cli
CLI execute fails with "alias not found" Run npx fabric-app-data list to check available aliases, then npx fabric-app-data add to register
INFO functions return permission errors Fall back to INFO.VIEW functions; mark elevated access as unavailable for this session
Metadata output too large Use scope estimation + narrowing patterns from discovery-queries.md
DAX syntax errors Consult dax-core-reference.md - check reserved keywords, quoting rules, EVALUATE/scalar mistakes
Unexpected query results Check filter context, relationship direction, BLANK handling in dax-core-reference.md
Time intelligence returns wrong values Check date table prerequisites and critical rules in dax-time-intelligence.md