Skip to main content

ModelIndex

Struct ModelIndex 

Source
pub struct ModelIndex { /* private fields */ }
Expand description

Case-insensitive lookup index over a TabularDatabase.

Build it once, after ingestion, with ModelIndex::build. Building never fails: duplicate names are invalid in a valid model but tolerated here, with the first occurrence kept and later ones ignored.

Per-table names are nested under their table rather than keyed by a (table, name) pair, so a lookup folds each half once and allocates no tuple — this is the DAX lexer’s hot path, one call per reference in every expression.

Implementations§

Source§

impl ModelIndex

Source

pub fn build(db: &TabularDatabase) -> Self

Indexes every table, column, measure, hierarchy, and shared expression.

Runs in one pass over the model, folding each name once. On a duplicate folded name the first occurrence is kept.

Source

pub fn resolve_table(&self, name: &str) -> Option<TableHandle>

Looks up a table by name, case-insensitively.

Source

pub fn resolve_qualified(&self, table: &str, name: &str) -> Option<Resolved>

Resolves a qualified reference, Table[Name].

The named table’s columns are tried first. Falling through to a measure is deliberate and conservative: measure names are model-global, so a qualified reference carrying a wrong or stale table prefix — 'Dato'[Total Sales] for a measure that lives on Sales, or a prefix naming a table that no longer exists — still keeps that measure alive. Marking one object used too many is safe; marking one too few deletes live code.

§Examples
// The model has one measure, `Total`, whose home table is `Sales`.
let index = ModelIndex::build(&db);

// A stale prefix still keeps it alive: measure names are model-global.
assert!(index.resolve_qualified("Dato", "Total").is_some());
assert!(index.resolve_qualified("No Such Table", "total").is_some());

// A name that matches nothing resolves to nothing.
assert!(index.resolve_qualified("Sales", "Nope").is_none());
Source

pub fn resolve_column(&self, table: &str, name: &str) -> Option<ColumnHandle>

Looks up a column on a specific table — how M field access #"Sales"[Amount] resolves. Unlike resolve_qualified there is no measure fallback: an M expression cannot reference a measure, so a measure of the same name must not be kept alive by one.

Source

pub fn resolve_columns(&self, name: &str) -> Vec<ColumnHandle>

Finds every column of a name, on every table — how M resolves the string arguments of its column-centric built-ins and an unqualified [Name] field access.

M string arguments carry no row context: Table.NestedJoin(Source, "Key", …) can name any table’s column, and a lexer cannot tell which without a full dataflow analysis. The conservative direction is to keep all candidates alive; the result is sorted by table, then column, so it is deterministic for a given model.

let index = ModelIndex::build(&db);

// Both tables have a `Key` column; a merge step naming "Key" keeps
// both alive.
assert_eq!(index.resolve_columns("key").len(), 2);

// An unknown name is data, not an error.
assert!(index.resolve_columns("Ukendt").is_empty());
Source

pub fn resolve_unqualified( &self, name: &str, home_table: Option<&str>, ) -> UnqualifiedMatches

Resolves an unqualified reference, [Name], to all its candidates.

home_table is the row-context table of the expression the reference was found in; pass None where there is none. See UnqualifiedMatches for why both a measure and a column can come back at once.

§Examples
// `Antal` is a measure on `Sales` and, separately, a column of `Dato`.
let index = ModelIndex::build(&db);

// Inside a `Dato` row context both are live candidates, so both come back.
let ambiguous = index.resolve_unqualified("ANTAL", Some("Dato"));
assert!(ambiguous.measure.is_some());
assert!(ambiguous.column.is_some());

// With no row context there is no column candidate to consider.
assert!(index.resolve_unqualified("antal", None).column.is_none());

// An unknown name is data, not an error.
assert!(index.resolve_unqualified("Ukendt", Some("Dato")).is_empty());
Source

pub fn resolve_hierarchy( &self, table: &str, name: &str, ) -> Option<HierarchyHandle>

Looks up a hierarchy on a specific table, as written in ISINSCOPE('Date'[Calendar]) or in a PBIR hierarchy binding. Hierarchy names are only unique per table, so there is no unqualified form and no cross-table fallback.

Source

pub fn resolve_expression(&self, name: &str) -> Option<ExpressionHandle>

Looks up a model-level shared M expression by name — how one M query references a parameter or another query.

Source

pub fn resolve_function(&self, name: &str) -> Option<FunctionHandle>

Looks up a user-defined DAX function by name — how a DAX expression calls it. Function names are model-global.

Trait Implementations§

Source§

impl Clone for ModelIndex

Source§

fn clone(&self) -> ModelIndex

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for ModelIndex

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.