> Documentation index: https://www.gooddata.ai/docs/gooddata-ui/llms.txt lists every page of these docs as Markdown.

# Execution model

> Create, inspect, and modify execution attributes, filters, measures, and sort items with SDK model factories, builders, and accessors.

API reference: [newDefForItems()](https://www.gooddata.ai/docs/gooddata-ui/latest/api-reference/sdk-model/sdk-model.newdefforitems/index.md) (function), [newDimension()](https://www.gooddata.ai/docs/gooddata-ui/latest/api-reference/sdk-model/sdk-model.newdimension/index.md) (function)

The execution model of GoodData.UI is used to specify what data to compute on an Analytical Backend. Parts of the model
are also used as input to the visual components to tell them what data to obtain and render.

This document builds up on the [execution model basics](https://www.gooddata.ai/docs/gooddata-ui/latest/data-layer/execution/custom-executions/index.md) and goes into more detail about
the available types and functions available for their creation and manipulation.

## [Execution model concepts](https://www.gooddata.ai/docs/gooddata-ui/latest/data-layer/execution/execution-model/#execution-model-concepts)

To simplify the creation of various types of objects that specify what data to render, the model uses a combination
of two typical object creation patterns: factory function and builder.

### [Creating objects](https://www.gooddata.ai/docs/gooddata-ui/latest/data-layer/execution/execution-model/#creating-objects)

The model provides a single factory function to create each type of objects. There are several conventions:

-  The factory functions are always named `new<ObjectType>`.
-  The factory functions can create only syntactically valid objects; all essential object parameters are required
   arguments to the function call.
-  For simple objects, optional parameters follow the required arguments.
-  For complex objects (such as measures), the last parameter is a `modifications` function which you can implement.
   This function will receive an instance of the builder with methods to customize different parameters of the object
   under construction.

### [Accessing object properties](https://www.gooddata.ai/docs/gooddata-ui/latest/data-layer/execution/execution-model/#accessing-object-properties)

The model provides accessor functions to access object properties. The naming convention for an accessor function is `<objectType>Property(object)`, where the first and only parameter is the object to access.

**Examples:** `attributeAlias`, `measureLocalId`, `measureFormat`, `filterAttributeElements`

### [Modifying objects](https://www.gooddata.ai/docs/gooddata-ui/latest/data-layer/execution/execution-model/#modifying-objects)

The model provides specialized functions to allow modification of complex objects: measures and attributes. There
are several conventions:

-  The modification functions are always named `modify<ObjectType>`.
-  The first parameter is the object to modify.
-  The second parameter is the modification function. This function will receive an instance of the builder with methods
   to customize different parameters of the object.
-  The modification functions treat input as immutable. They will create new objects instead of modifying the
   inputs.

### [Local identifiers and referencing objects](https://www.gooddata.ai/docs/gooddata-ui/latest/data-layer/execution/execution-model/#local-identifiers-and-referencing-objects)

The `localIdentifier`, or `localId` for short, is a user-assigned identifier that you have to use when referencing
attributes and measures in the scope of a single visualization or execution.

The execution model automatically generates stable `localId`s as it creates the attribute and measure objects. You can pass the attribute and measure objects by value. However, if you want to use the same attribute or measure multiple times in the same visualization, you have to create a copy of the object and assign it a different `localId` yourself.

You can use the `modify<ObjectType>` functions to override the `localId` of an attribute or measure. The builder instances that your modification function receives have functions to manipulate `localId`. The behavior of the modification functions in regards to `localId` is as follows:

-  If you call `m => m.defaultLocalId()`, the default logic for `localId` generation will kick in **after** all
   other object modifications are applied.

-  If you call `m => m.localId(customValue)`, the modified object will have your custom `localId`.

-  If you do not call `defaultLocalId` or `localId`, the modification object will have the same `localId` as the
   original object.

## [Attribute](https://www.gooddata.ai/docs/gooddata-ui/latest/data-layer/execution/execution-model/#attribute)

Each attribute is defined by its `displayForm` - also known as `label` in GoodData Cloud and GoodData.CN - that will be used to
slice the data. You can create an attribute definition using the following factory function:

```ts
const attribute = newAttribute("<attribute-displayForm-identifier>");
```

Each attribute requires a `localIdentifier` that you can use to reference the attribute in the scope of the execution (for instance, when specifying sorting). The factory function assigns a stable `localIdentifier` for you.

You can optionally override the `localIdentifier` and also the title of the attribute in the factory function call:

```ts
const attribute = newAttribute("<attribute-displayForm-identifier>", (m) => m.localId("myLocalId").alias("My Attribute"));
```

You can modify an existing attribute using the `modifyAttribute` function:

```ts
import { newAttribute, modifyAttribute } from "@gooddata/sdk-model";

const attribute = newAttribute("displayFormIdentifier", m => m.alias("My Custom Name"));

// notice the call to defaultLocalId() - this ensures the new object will have a different, generated localId
const sameAttributeDifferentName = modifyAttribute(attribute, m => m.alias("Corrected Name").defaultLocalId());
```

## [Filter](https://www.gooddata.ai/docs/gooddata-ui/latest/data-layer/execution/execution-model/#filter)

You can limit the execution by providing one or more filters. Multiple filters are always interpreted as an intersection of all individual filters (`f1 AND f2 AND f3...`).

The execution model provides several factory functions to create filter objects, one function for each type of filters supported by GoodData.UI:

-  `newPositiveAttributeFilter`
-  `newNegativeAttributeFilter`
-  `newAbsoluteDateFilter`
-  `newRelativeDateFilter`
-  `newMeasureValueFilter`
-  `newRankingFilter`

## [Measure](https://www.gooddata.ai/docs/gooddata-ui/latest/data-layer/execution/execution-model/#measure)

Measures in the scope of execution indicate what values the Analytical Backend must calculate and include in the result,
potentially sliced as indicated by the different attributes in the execution.

You can construct measures of multiple types:

-  Measures created by aggregating facts in your logical data model (LDM)
-  Measures created by referencing an existing, potentially complex MAQL metric
-  Measures created from an inline MAQL expression
-  Arithmetic measures constructed by combining existing measures as operands of arithmetic operations
-  Time-over-time comparison measures constructed by "shifting" the calculation in time

The factory functions are the following:

-  `newMeasure` creates a new measure from a fact or a MAQL metric.
-  `newInlineMeasure` creates a new measure from an inline MAQL expression.
-  `newArithmeticMeasure` creates a new arithmetic measure.
-  `newPopMeasure` creates a new period-over-period comparison measure.
-  `newPreviousPeriodMeasure` creates a new previous period comparison measure.

The modification function is `modifyMeasure`. It modifies measure-agnostic parameters (format, alias, title, localId) of any type of a measure.

**Example:**

```ts
import { newMeasure, newArithmeticMeasure, modifyMeasure, newPositiveAttributeFilter } from "@gooddata/sdk-model";

const measureFromMaqlMetric = newMeasure("maqlMetricIdentifier");
const measureFromFact = newMeasure("factIdentifier", m => m.aggregation("avg").alias("Custom Name"));
const measureWithFilter = newMeasure("factIdentifier", m => m.filters(newPositiveAttributeFilter("displayFormId", ["value"])));

const arithmeticMeasure = newArithmeticMeasure(
                                [measureFromFact, measureFromMaqlMetric],
                                "sum",
                                m => m.alias("Custom Name For Arithmetic Measure").format("$#,#0.0")
                          );

// notice the call to defaultLocalId; this ensures that this new measure will have a different localId - one that reflects
// that the title and the format is different.
const modifiedArithmeticMeasure = modifyMeasure(arithmeticMeasure,
                                    m => m.alias("Different Name For Arithmetic Measure").format("$#,#0").defaultLocalId()
                                  );
```

> **Note:**
> You can find examples for the other factory functions together with a detailed description of time-over-time comparison measures in [Time-over-time comparison](https://www.gooddata.ai/docs/gooddata-ui/latest/data-layer/execution/time-over-time/index.md). Arithmetic and inline MAQL measures are described in [Working with measures](https://www.gooddata.ai/docs/gooddata-ui/latest/data-layer/data-model/measures/index.md).

### [Aggregation inside a measure](https://www.gooddata.ai/docs/gooddata-ui/latest/data-layer/execution/execution-model/#aggregation-inside-a-measure)

Each measure created from a fact can specify `aggregation` of data. Aggregation is represented by a string value that defines the aggregation type.

| Type | Description |
| :--- | :--- |
| `"sum"` | Returns a sum of all numbers in the set |
| `"count"` | Counts unique values of a selected attribute in a given dataset determined by the second attribute parameter  (ignores the measure's `format` value and uses the default value `#,##0` instead) |
| `"approximate_count"` | Approximate count of unique values; translated to the corresponding SQL function when the data source supports it, otherwise the backend falls back to the exact count |
| `"avg"` | Returns the average value of all numbers in the set; null values are ignored |
| `"min"` | Returns the minimum value of all numbers in the set |
| `"max"` | Returns the maximum value of all numbers in the set |
| `"median"` | Counts the statistical median - an order statistic that gives the "middle" value of a sample. If the "middle" falls between two values, the function returns average of the two middle values. Null values are ignored. |
| `"runsum"` | Returns a sum of numbers increased by the sum from the previous value \(accumulating a sum incrementally\) |

### [Filters in a measure definition](https://www.gooddata.ai/docs/gooddata-ui/latest/data-layer/execution/execution-model/#filters-in-a-measure-definition)

Each measure can be filtered by attribute filters. Filters are represented by an array of [`IFilter`](https://www.gooddata.ai/docs/gooddata-ui/latest/api-reference/sdk-model/sdk-model.ifilter/index.md) objects.

Only one filter of the [`DateFilter`](https://www.gooddata.ai/docs/gooddata-ui/latest/api-reference/sdk-ui-filters/sdk-ui-filters.datefilter/index.md) type is allowed in the measure's filter definition.

* When both the measure filter of the [`DateFilter`](https://www.gooddata.ai/docs/gooddata-ui/latest/api-reference/sdk-ui-filters/sdk-ui-filters.datefilter/index.md) type and the global filter of the [`DateFilter`](https://www.gooddata.ai/docs/gooddata-ui/latest/api-reference/sdk-ui-filters/sdk-ui-filters.datefilter/index.md) type are set with
  the **same** date dimension, the measure date filter overrides the global date filter for this measure
  \(global date filters are still applied to other measures that do not have a measure date filter defined\).
* When the measure filter of the [`DateFilter`](https://www.gooddata.ai/docs/gooddata-ui/latest/api-reference/sdk-ui-filters/sdk-ui-filters.datefilter/index.md) type and the global filter of the [`DateFilter`](https://www.gooddata.ai/docs/gooddata-ui/latest/api-reference/sdk-ui-filters/sdk-ui-filters.datefilter/index.md) type are set
  with **different** date dimensions, the filters are interpreted as an intersection of those filters (`f1 AND f2`).

### [Show a measure as a percentage](https://www.gooddata.ai/docs/gooddata-ui/latest/data-layer/execution/execution-model/#show-a-measure-as-a-percentage)

When the execution runs on the Analytical Backend, the result measure data is, by default, returned as raw values \(numbers\).

If you want the measures data to be displayed as a percentage instead, you can use the `modifySimpleMeasure` function
of the execution model to turn on the `computeRatio` functionality:

```ts
import { modifySimpleMeasure } from "@gooddata/sdk-model";
import * as Md from "./catalog.js";

// This will modify an existing simple measure, turn on the computeRatio functionality and associate a new, default localId
const ratioMeasure = modifySimpleMeasure(Md.$FranchiseFees, m => m.ratio().defaultLocalId());

// This will modify an existing simple measure, turn off the computeRatio functionality and associate a new, default localId
const noRatio = modifySimpleMeasure(ratioMeasure, m => m.noRatio().defaultLocalId());
```

When the property is enabled, the measure's `format` value is ignored. The default format `#,##0.00%` is used instead.

## [Sort items](https://www.gooddata.ai/docs/gooddata-ui/latest/data-layer/execution/execution-model/#sort-items)

The execution model provides factory functions to create sort items and the respective locators:

- `newAttributeSort` creates a new attribute sort item.
- `newMeasureSort` creates a new measure value sort item.

For both of these, you can specify an attribute or measure either by `localId` or by passing the actual object.

The second parameter is the sort direction (`"asc"` or `"desc"`); it defaults to `"asc"`.

When sorting by measures that are scoped for a particular attribute value (for example, in pivot tables), you must specify one or more attribute locators to pinpoint the exact measure to sort by. You can conveniently create attribute locators using the `newAttributeLocator` factory function; the second argument is the attribute element value (its primary label value).

**Example:**

```ts
import { newAttribute, newMeasure, newAttributeSort, newMeasureSort, newAttributeLocator } from "@gooddata/sdk-model";

const attribute = newAttribute("displayFormIdentifier", m => m.alias("Custom Dimension"));
const measure = newMeasure("maqlMetricIdentifier", m => m.alias("My Measure").format("#0"));

const attributeSort = newAttributeSort(attribute, "asc");

const measureSortWithoutAttributeLocator = newMeasureSort(measure, "asc");
const measureSortWithAttributeLocator = newMeasureSort(measure, "asc", [newAttributeLocator(attribute, "element-value")]);
```

### [Attribute area sorting](https://www.gooddata.ai/docs/gooddata-ui/latest/data-layer/execution/execution-model/#attribute-area-sorting)

You can specify that the attribute sort should sort attribute values based on an aggregation function applied to
all valid values belonging to each attribute value. This is extremely useful when sorting stacked visualizations such
as stacked bar charts or area charts.

Currently, only sorting by the `sum` function is supported.

The following example shows sorting a table with two measures and a `Year` attribute. You can set sorting based on the `Year` attribute with:

```ts
import { newAttribute, newAttributeAreaSort } from "@gooddata/sdk-model";

const attribute = newAttribute("displayFormIdentifier", m => m.alias("Custom Dimension"));

newAttributeAreaSort(attribute, "asc");
```

Consider the following original data:

| Year | 2006 | 2006 | 2007 | 2007 |
| :--- | :--- | :--- | :--- | :--- |
| Measures | M1 | M2 | M1 | M2 |
| Values | 1 | 2 | 3 | 4 |

The sorting function (`sum`) is applied to all attribute element values for each attribute element (`2006` and `2007`).
Notice that the area sort is summing up values across different measures (`M1` and `M2`):

| 2006 | 2007 |
| :--- | :--- |
| 1 + 2 = 3 | 3 + 4 = 7 |

Attribute values are then sorted by this computed value (`3` and `7`, respectively):

| Year | 2007 | 2007 | 2006 | 2006 |
| :--- | :--- | :--- | :--- | :--- |
| Measures | M1 | M2 | M1 | M2 |
| Values | 3 | 4 | 1 | 2 |
