# Model - Store

## API Store Presets

Presets are reusable Store templates for API data sources. Mprove has a [Store preset for Google Analytics](https://github.com/mprove-io/mprove/blob/master/apps/blockml/src/presets/google_analytics.store.preset).

Minimal Store file that uses the preset looks like this.

```yaml
store: google_analytics
connection: c7_google
preset: google_analytics
```

Additional parameters specified in the Store file will override those taken from the preset.

## Store Model

**Store Model** defines the schema and logic for retrieving query data via an HTTP request.

To use **Google Analytics** integration create a Store file that references a Store Preset. For custom API data sources (when no preset is available), you need to create a full Store file.

This page shows how to create a custom integration from scratch. **Google Analytics** is used as an example.

Each Store must be stored as **store_name.store** YAML file:

```yaml
store: ga
connection: c7_google
# preset: google_analytics
label: Google Analytics
description: 'Google Analytics Reporting'
access_roles: []
method: POST
request: |
  <createRequest.js content>
response: |
  <processRequest.js content>
date_range_includes_right_side: true
parameters:
- filter: top_config
  required: true
  max_fractions: 1
  fraction_controls:
  - selector: ga_property
    label: Property
    value: '123456789'
    options:
    - value: '123456789'
  - date_picker: start_date
    label: Start Date
    value: $METRICS_DATE_FROM
  - date_picker: end_date
    label: End Date
    value: $METRICS_DATE_TO

results:
- result: number
  fraction_types:
  - type: equal
    label: Equal
    meta: 
      operation: EQUAL
      filter_type: numericFilter
    controls: 
    - input: value_input

  - type: less_than
    meta: 
      operation: LESS_THAN
      filter_type: numericFilter
    controls: 
    - input: value_input

  - type: less_than_or_equal
    meta: 
      operation: LESS_THAN_OR_EQUAL
      filter_type: numericFilter
    controls: 
    - input: value_input

  - type: greater_than
    meta: 
      operation: GREATER_THAN
      filter_type: numericFilter
    controls: 
    - input: value_input

  - type: greater_than_or_equal
    meta: 
      operation: GREATER_THAN_OR_EQUAL
      filter_type: numericFilter
    controls: 
    - input: value_input

  - type: between
    meta: 
      operation: BETWEEN
      filter_type: betweenFilter
    controls:
    - input: value_from_input
    - input: value_to_input

- result: string
  fraction_types:
  - type: exact
    meta: 
      match_type: EXACT
      filter_type: stringFilter
    controls:
    - input: value_input

  - type: begins_with
    meta: 
      match_type: BEGINS_WITH
      filter_type: stringFilter
    controls:
    - input: value_input

  - type: ends_with
    meta: 
      match_type: ENDS_WITH
      filter_type: stringFilter
    controls:
    - input: value_input

  - type: contains
    meta: 
      match_type: CONTAINS
      filter_type: stringFilter
    controls:
    - input: value_input

  - type: full_regexp
    meta: 
      match_type: FULL_REGEXP
      filter_type: stringFilter
    controls:
    - input: value_input

  - type: partial_regexp
    meta: 
      match_type: PARTIAL_REGEXP
      filter_type: stringFilter
    controls:
    - input: value_input

  - type: in_list
    meta: 
      match_type: IN_LIST
      filter_type: inListFilter
    controls:
    - list_input: values_input

field_groups:
  - group: "attribution"
    label: "Attribution"
  - group: "demographics"
    label: "Demographics"
  - group: "ecommerce"
    label: "Ecommerce"
  - group: "event"
    label: "Event"
  - group: "geography"
    label: "Geography"
  - group: "other"
    label: "Other"
  - group: "page_screen"
    label: "Page Screen"
  - group: "platform_device"
    label: "Platform Device"
  - group: "publisher"
    label: "Publisher"
  - group: "revenue"
    label: "Revenue"
  - group: "session"
    label: "Session"
  - group: "traffic_source"
    label: "Traffic Source"
  - group: "user"
    label: "User"
  - group: "user_lifetime"
    label: "User Lifetime"

field_time_groups:
- time: event_created_at
  group: event
  label: 'Event Created At'

build_metrics:
- time: event_created_at

fields: <Store Fields array>
```

### Store Fields

```yaml
fields:  
# Time Dimensions

- dimension: date # "20250127"
  result: string
  time_group: event_created_at
  detail: days
  description: 'The date of the event, formatted as YYYYMMDD'
  meta:
    apiName: date

- dimension: iso_year_iso_week # "202504"
  label: 'Week Monday'
  result: string
  time_group: event_created_at
  detail: weeksMonday
  description: 'The combined values of isoWeek and isoYear. Example values include 201652 & 201701'
  meta:
    apiName: isoYearIsoWeek

- dimension: year_week # "202505"
  label: 'Week Sunday'
  result: string
  time_group: event_created_at
  detail: weeksSunday
  description: 'The combined values of year and week. Example values include 202253 or 202301'
  meta:
    apiName: yearWeek

- dimension: year_month # "202501"
  label: 'Month'
  result: string
  time_group: event_created_at
  detail: months
  description: 'The combined values of year and month. Example values include 202212 or 202301'
  meta:
    apiName: yearMonth

- dimension: year # "2025"
  label: 'Year'
  result: string
  time_group: event_created_at
  detail: years
  description: 'The four-digit year of the event. For example, 2020 or 2024'
  meta:
    apiName: year

- dimension: date_hour # "2025012722"
  label: 'Hour'
  result: string
  time_group: event_created_at
  detail: hours
  description: 'The combined values of date and hour formatted as YYYYMMDDHH'
  meta:
    apiName: dateHour

- dimension: date_hour_minute # "202501272212"
  label: 'Minute'
  result: string
  time_group: event_created_at
  detail: minutes
  description: 'The combined values of date, hour, and minute formatted as YYYYMMDDHHMM'
  meta:
    apiName: dateHourMinute

- dimension: hour # "4"
  result: string
  group: event
  description: "The two-digit hour of the day that the event was logged. This dimension ranges from 0-23 and is reported in your property's timezone"
  meta:
    apiName: hour

- dimension: minute # "40"
  result: string
  group: event
  description: "The two-digit minute of the hour that the event was logged. This dimension ranges from 0-59 and is reported in your property's timezone"
  meta:
    apiName: minute

- dimension: day # "26"
  result: string
  group: event
  description: 'The day of the month, a two-digit number from 01 to 31'
  meta:
    apiName: day

- dimension: day_of_week # "0"
  label: 'Day of week'
  result: string
  group: event
  description: 'The integer day of the week. It returns values in the range 0 to 6 with Sunday as the first day of the week'
  meta:
    apiName: dayOfWeek

- dimension: day_of_week_name # "Sunday"
  label: 'Day of week name'
  result: string
  group: event
  description: 'The day of the week in English. This dimension has values such as Sunday or Monday'
  meta:
    apiName: dayOfWeekName

- dimension: week # "05"
  label: 'Week'
  result: string
  group: event
  description: 'The week of the event, a two-digit number from 01 to 53. Each week starts on Sunday. January 1st is always in week 01. The first and last week of the year have fewer than 7 days in most years. Weeks other than the first and the last week of the year always have 7 days. For years where January 1st is a Sunday, the first week of that year and the last week of the prior year have 7 days'
  meta:
    apiName: week

- dimension: month # "01"
  result: string
  group: event
  description: 'The month of the event, a two digit integer from 01 to 12'
  meta:
    apiName: month

- dimension: iso_year # "2025"
  label: 'ISO year'
  result: string
  group: event
  description: 'The ISO year of the event. For details, see http://en.wikipedia.org/wiki/ISO_week_date. Example values include 2022 & 2023'
  meta:
    apiName: isoYear

- dimension: iso_week # "04"
  label: 'ISO week of the year'
  result: string
  group: event
  description: 'ISO week number, where each week starts on Monday. For details, see http://en.wikipedia.org/wiki/ISO_week_date. Example values include 01, 02, & 53'
  meta:
    apiName: isoWeek

- dimension: nth_year # "0000"
  label: 'Nth year'
  result: string
  description: 'The number of years since the start of the date range. The starting year is 0000'
  group: event
  meta:
    apiName: nthYear

- dimension: nth_month # "0000"
  label: 'Nth month'
  result: string
  group: event
  description: 'The number of months since the start of a date range. The starting month is 0000'
  meta:
    apiName: nthMonth

- dimension: nth_week # "0001"
  label: 'Nth week'
  result: string
  group: event
  description: 'A number representing the number of weeks since the start of a date range'
  meta:
    apiName: nthWeek

- dimension: nth_day # "0004"
  label: 'Nth day'
  result: string
  group: event
  description: 'The number of days since the start of the date range'
  meta:
    apiName: nthDay

- dimension: nth_hour # "0142"
  label: 'Nth hour'
  result: string
  group: event
  description: 'The number of hours since the start of the date range. The starting hour is 0000'
  meta:
    apiName: nthHour

- dimension: nth_minute # "8532"
  label: 'Nth minute'
  result: string
  group: event
  description: 'The number of minutes since the start of the date range. The starting minute is 0000'
  meta:
    apiName: nthMinute

# Dimensions (full list is available on github)

- dimension: "country"
  result: "string"
  description: "The country from which the user activity originated."
  group: "geography"
  label: "Country"
  meta:
    apiName: "country"
    uiName: "Country"

- dimension: "city"
  result: "string"
  description: "The city from which the user activity originated."
  group: "geography"
  label: "City"
  meta:
    apiName: "city"
    uiName: "City"
    
# Measures (full list is available on github)

- measure: "active_users"
  result: "number"
  description: "The number of distinct users who visited your site or app."
  group: "user"
  label: "Active Users"
  meta:
    apiName: "activeUsers"
    uiName: "Active users"
    type: "TYPE_INTEGER"

- measure: "sessions"
  result: "number"
  description: "The number of sessions that began on your site or app (event triggered: session_start)."
  group: "session"
  label: "Sessions"
  meta:
    apiName: "sessions"
    uiName: "Sessions"
    type: "TYPE_INTEGER"

- measure: "screen_page_views"
  result: "number"
  description: "The number of app screens or web pages your users viewed. Repeated views of a single page or screen are counted. (screen_view + page_view events)."
  group: "page_screen"
  label: "Views"
  meta:
    apiName: "screenPageViews"
    uiName: "Views"
    type: "TYPE_INTEGER"
```

### Store createRequest.js

```js
let storeFields = $STORE_FIELDS;
let queryOrderBy = $QUERY_ORDER_BY;
let selectedDimensions = $QUERY_SELECTED_DIMENSIONS;
let selectedMeasures = $QUERY_SELECTED_MEASURES;
let queryParameters = $QUERY_PARAMETERS;
let queryLimit = $QUERY_LIMIT;

let orderByElements = [];

queryOrderBy.forEach(x=> {
  let orderBy;

  if (selectedDimensions.map(field => field.name).indexOf(x.field.name) > -1) {
    orderBy = {
      dimension: { dimensionName: x.field.meta.apiName },
      desc: x.desc
    }
  } else if (selectedMeasures.map(field => field.name).indexOf(x.field.name) > -1) {
    orderBy = {
      metric: { metricName: x.field.meta.apiName },
      desc: x.desc
    } 
  }

  orderByElements.push(orderBy);
});

let dimOrExpressions = [];
let dimAndNotExpressions = [];

let mcOrExpressions = [];
let mcAndNotExpressions = [];

queryParameters.map(filter => {
  let field = storeFields.find(x => x.name === filter.fieldId);

  filter.fractions.forEach(fraction => {
    let apiFilter;
    let apiFilterType = fraction.meta?.filter_type;

    if (apiFilterType === 'stringFilter') {
      apiFilter = {
        fieldName: field.meta.apiName,
        stringFilter: {
          matchType: fraction.meta.match_type,
          value: fraction.controls.find(control => 
            control['name'] === 'value_input')?.value,
          caseSensitive: $PROJECT_CONFIG_CASE_SENSITIVE
        }
      }
    }

    if (apiFilterType === 'inListFilter') {
      apiFilter = {
        fieldName: field.meta.apiName,
        inListFilter: {
          values: fraction.controls.find(control => 
            control['name'] === 'values_input')?.values,
          caseSensitive: $PROJECT_CONFIG_CASE_SENSITIVE
        }
      }
    }

    if (apiFilterType === 'numericFilter') {
      apiFilter = {
        fieldName: field.meta.apiName,
        numericFilter: {
          operation: fraction.meta.operation,
          value: {
            doubleValue: Number(fraction.controls.find(control => 
              control['name'] === 'value_input')?.value)
          }
        }
      }
    }

    if (apiFilterType === 'betweenFilter') {
      apiFilter = {
        fieldName: field.meta.apiName,
        betweenFilter: {
          fromValue: {
            doubleValue: Number(fraction.controls.find(control => 
              control['name'] === 'value_from_input')?.value)
          },
          toValue: {
            doubleValue: Number(fraction.controls.find(control => 
              control['name'] === 'value_to_input')?.value)
          },
        }
      }
    } 

    if (field.fieldClass === 'dimension') {
      if (fraction.logicGroup === 'OR') {
        dimOrExpressions.push({ filter: apiFilter })
      } 
      if (fraction.logicGroup === 'AND_NOT') {
        dimAndNotExpressions.push({
          notExpression: {
            filter: apiFilter
          }
        })
      }
    }

    if (field.fieldClass === 'measure') {
      if (fraction.logicGroup === 'OR') {
        mcOrExpressions.push({ filter: apiFilter })
      } 
      if (fraction.logicGroup === 'AND_NOT') {
        mcAndNotExpressions.push({
          notExpression: {
            filter: apiFilter
          }
        })
      }
    }
  });
});

let dateRanges = [{
  startDate: queryParameters.find(x => x['fieldId'] === 'top_config')?.fractions[0]
    .controls.find(control => control.name === 'start_date')?.value,
  endDate: queryParameters.find(x => x['fieldId'] === 'top_config')?.fractions[0]
    .controls.find(control => control.name === 'end_date')?.value
}];

let dimAndGroupExpressions = [];
let mcAndGroupExpressions = [];

if (dimOrExpressions.length > 0) {
  dimAndGroupExpressions.push({
    orGroup: { expressions: dimOrExpressions }
  });
}

if (dimAndNotExpressions.length > 0) {
  dimAndGroupExpressions = [
    ...dimAndGroupExpressions,
    ...dimAndNotExpressions
  ];
}

if (mcOrExpressions.length > 0) {
  mcAndGroupExpressions.push({
    orGroup: { expressions: mcOrExpressions }
  });
}

if (mcAndNotExpressions.length > 0) {
  mcAndGroupExpressions = [
    ...mcAndGroupExpressions,
    ...mcAndNotExpressions
  ];
}

let body = {
  dimensions: selectedDimensions.map(x => ({ name: x.meta['apiName'] })), 
  metrics: selectedMeasures.map(x => ({ name: x.meta['apiName'] })),
  dateRanges: dateRanges,
  dimensionFilter: (dimOrExpressions.length > 0 || dimAndNotExpressions.length > 0)
    ? {
        andGroup: {
          expressions: dimAndGroupExpressions
        }
      }
    : undefined,
  metricFilter: (mcOrExpressions.length > 0 || mcAndNotExpressions.length > 0)
    ? {
        andGroup: {
          expressions: mcAndGroupExpressions
        }
      }
    : undefined,
  limit: queryLimit,
  orderBys: orderByElements,
  currencyCode: 'USD',
  keepEmptyRows: true,
  returnPropertyQuota: false,
  cohortSpec: undefined, // supported in ga_cohorts.store
  metricAggregations: undefined, // not supported
  comparisons: undefined, // not supported
  offset: undefined // not supported
}

let propertyId = queryParameters.find(x => x['fieldId'] === 'top_config')?.fractions[0]
  .controls.find(control => control.name === 'ga_property')?.value;

let urlPath = \`/v1beta/properties/\$\{propertyId\}:runReport\`;

return { urlPath: urlPath, body: body };
```

### Store processResponse.js

```js
let data = $RESPONSE_DATA;
  let storeFields = $STORE_FIELDS;
  
  let dimensionHeaders = data.dimensionHeaders?.map(header => header.name);
  let metricHeaders = data.metricHeaders?.map(header => header.name);
  
  newData = data.rows?.map(row => {
    let newRow = {};
    
    row.dimensionValues?.forEach((dimension, index) => {
      let dimensionName = dimensionHeaders[index];
      let value = dimension.value;
      let date;

      if (dimensionName === 'year') {
        date = new Date(\`\${value}-01-01T00:00:00Z\`);
        
      } else if (dimensionName === 'yearMonth') {
        date = new Date(\`\${value.slice(0, 4)}-\${value.slice(4, 6)}-01T00:00:00Z\`);
        
      } else if (dimensionName === 'isoYearIsoWeek') {
        // Parse ISO year and week (e.g., "202504" -> year=2025, week=4)
        // Create a date in week 1 of the ISO year (January 4th is always in week 1)
        // Get the Monday of week 1
        // Add weeks to reach the target week
        let year = parseInt(value.slice(0, 4), 10);
        let week = parseInt(value.slice(4, 6), 10);
        
        date = new Date(Date.UTC(year, 0, 4));
        
        let day = date.getUTCDay(); // 0 (Sunday) to 6 (Saturday)
        date.setUTCDate(date.getUTCDate() - (day === 0 ? 6 : day - 1));
        
        date.setUTCDate(date.getUTCDate() + (week - 1) * 7);
        
      } else if (dimensionName === 'yearWeek') {
        // Parse year and week (e.g., "202505" -> year=2025, week=5)
        // Find the first Sunday of the year
        // Add weeks to reach the target week
        let year = parseInt(value.slice(0, 4), 10);
        let week = parseInt(value.slice(4, 6), 10);
        
        let firstDay = new Date(Date.UTC(year, 0, 1));
        let day = firstDay.getUTCDay(); // 0 (Sunday) to 6 (Saturday)
        let firstSunday = new Date(firstDay);
        firstSunday.setUTCDate(firstDay.getUTCDate() - day);
        
        date = new Date(firstSunday);
        date.setUTCDate(firstSunday.getUTCDate() + (week - 1) * 7);
        
      } else if (dimensionName === 'date') {
        date = new Date(\`\${value.slice(0, 4)}-\${value.slice(4, 6)}-\${value.slice(6, 8)}T00:00:00Z\`);
        
      } else if (dimensionName === 'dateHour') {
        date = new Date(\`\${value.slice(0, 4)}-\${value.slice(4, 6)}-\${value.slice(6, 8)}T\${value.slice(8, 10)}:00:00Z\`);
        
      } else if (dimensionName === 'dateHourMinute') {
        date = new Date(\`\${value.slice(0, 4)}-\${value.slice(4, 6)}-\${value.slice(6, 8)}T\${value.slice(8, 10)}:\${value.slice(10, 12)}:00Z\`);
      } 

      let storeField = storeFields.find(x => !!x.meta && x.meta['apiName'] === dimensionName);

      if (!!storeField) {
        let fieldId = storeField.name;
        newRow[fieldId] = !!date ? date.getTime()/1000 : value;
      }
    });
    
    row.metricValues?.forEach((metric, index) => {
      let metricName = metricHeaders[index];
      let value = metric.value;
      let storeField = storeFields.find(x => !!x.meta && x.meta['apiName'] === metricName);
      if (!!storeField) {
        let fieldId = storeField.name;
        newRow[fieldId] = value;
      }
    });
    
    return newRow;
  });

  return newData || [];
```

## Reference

### Store Constants

These constants are provided based on Store file, [Project Config](/content/docs/reference/project-config#project) and UI control values set by user for a specific query.

| Name                            | Type                                | Default         | Description                                                                                                                                               |
| ------------------------------- | ----------------------------------- | --------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `PROJECT_CONFIG_CASE_SENSITIVE` | boolean                             | false           | Should string filter be case sensitive or not                                                                                                             |
| `METRICS_DATE_FROM`             | YYYY-MM-DD                          | today's date    | The start date of time range (based on the time filter on the Reports page, otherwise today's date)                                                       |
| `METRICS_DATE_TO`               | YYYY-MM-DD                          | tomorrow's date | The end date of time range (based on the time filter on the Reports page, otherwise tomorrow's date)                                                      |
| `STORE_FIELDS`                  | \<storeField \| storeParameter\> [] | []              | [STORE_FIELDS](/content/docs/reference/model-store#store_fields) - all store parameters and fields in a single array                                                    |
| `QUERY_ORDER_BY`                | orderByField []                     | []              | [QUERY_ORDER_BY](/content/docs/reference/model-store#query_order_by) - fields by which the user wants to sort the data                                                  |
| `QUERY_SELECTED_DIMENSIONS`     | storeField []                       | []              | [QUERY_SELECTED_DIMENSIONS](/content/docs/reference/model-store#query_selected_dimensions) - dimensions selected by user                                                |
| `QUERY_SELECTED_MEASURES`       | storeField []                       | []              | [QUERY_SELECTED_MEASURES](/content/docs/reference/model-store#query_selected_measures) - measures selected by user                                                      |
| `QUERY_PARAMETERS`              | storeParameter []                   | []              | [QUERY_PARAMETERS](/content/docs/reference/model-store#query_parameters) - filters set by user                                                                          |
| `QUERY_LIMIT`                   | number                              | 500             | Max number of rows in response                                                                                                                            |
| `RESPONSE_DATA`                 | any                                 | -               | Response data that needs to be converted into Mprove compatible format as a result of [processResponse.js](/content/docs/reference/model-store#store-processresponsejs) |

#### STORE_FIELDS

```js
const STORE_FIELDS = [
  // list of store parameters and store fields definitions in a single array
  {
    required: 'true',
    max_fractions: '1',
    fraction_controls: [
      {
        label: 'Property',
        value: '123123123',
        options: [
          { value: '123123123' }
        ],
        name: 'ga_property',
        controlClass: 'selector'
      },
      {
        label: 'Start Date',
        value: '2025-02-24',
        name: 'start_date',
        controlClass: 'date_picker'
      },
      {
        label: 'End Date',
        value: '2025-02-24',
        name: 'end_date',
        controlClass: 'date_picker'
      }
    ],
    name: 'top_config',
    fieldClass: 'filter',
    label: 'Top Config',
    group: 'mf'
  },
  {
    result: 'string',
    group: 'geo',
    description: 'The country from which the user activity originated',
    meta: { name: 'country' },
    name: 'country',
    fieldClass: 'dimension',
    label: 'Country',
    type: 'custom',
  },
  {
    result: 'number',
    group: 'users',
    description: 'The number of distinct users who visited your site or app',
    meta: {
      name: 'activeUsers',
      type: 'TYPE_INTEGER',
    },
    name: 'active_users',
    fieldClass: 'measure',
    label: 'Active Users',
    format_number: ',.0f',
    currency_prefix: '$',
    currency_suffix: '',
  },
  // ... other store parameters definitions
  // ... other store fields definitions
];
```

#### QUERY_ORDER_BY

```js
const QUERY_ORDER_BY = [
    {
      fieldId: 'city',
      field: {
        result: 'string',
        group: 'geo',
        description: 'The city from which the user activity originated',
        meta: { name: 'city' },
        name: 'city',
        fieldClass: 'dimension',
        label: 'City',
        type: 'custom',
      },
      desc: false
    }
  ];
```

#### QUERY_SELECTED_DIMENSIONS

```js
const QUERY_SELECTED_DIMENSIONS = [
 {
    result: 'string',
    group: 'geo',
    description: 'The city from which the user activity originated',
    meta: { apiName: 'city', uiName: 'City' },
    name: 'city',
    fieldClass: 'dimension',
    label: 'City',
    type: 'custom',
  }
];
```

#### QUERY_SELECTED_MEASURES

```js
const QUERY_SELECTED_MEASURES = [
  {
    result: 'number',
    group: 'users',
    description: 'The number of distinct users who visited your site or app',
    meta: {
      apiName: 'activeUsers',
      uiName: 'Active users',
      type: 'TYPE_INTEGER',
    },
    name: 'active_users',
    fieldClass: 'measure',
    label: 'Active Users',
    format_number: ',.0f',
    currency_prefix: '$',
    currency_suffix: '',
  }
];
```

#### QUERY_PARAMETERS

```js
const QUERY_PARAMETERS = [
  {
    fieldId: 'city',
    fractions: [
      {
        operator: 'Or',
        type: 'StoreFraction',
        storeResult: 'string',
        storeFractionSubType: 'exact',
        meta: {
          match_type: 'EXACT',
          filter_type: 'stringFilter',
        },
        logicGroup: 'AND_NOT',
        storeFractionSubTypeOptions: [
          { value: 'exact' },
          { value: 'begins_with' },
          { value: 'ends_with' },
          { value: 'contains' },
          { value: 'full_regexp' },
          { value: 'partial_regexp' },
          { value: 'in_list' }
        ],
        controls: [
          { name: 'value_input', controlClass: 'input', value: 'h' },
          {
            value: false,
            label: 'Case Sensitive',
            name: 'case_sensitive_switch',
            controlClass: 'switch'
          }
        ]
      }
    ],
    field: {
      id: 'city',
      hidden: false,
      label: 'City',
      fieldClass: 'dimension',
      result: 'string',
      sqlName: 'city',
      topId: 'geo',
      topLabel: 'geo',
      description: 'The city from which the user activity originated',
      type: 'custom'
    }
  },
  {
    fieldId: 'top_config',
    fractions: [
      {
        type: 'StoreFraction',
        controls: [
          {
            options: [
              { value: '123123123' }
            ],
            value: '123123123',
            label: 'Property',
            name: 'ga_property',
            controlClass: 'selector'
          },
          {
            value: '2025-02-24',
            label: 'Start Date',
            name: 'start_date',
            controlClass: 'date_picker'
          },
          {
            value: '2025-02-24',
            label: 'End Date',
            name: 'end_date',
            controlClass: 'date_picker'
          }
        ]
      }
    ]
  },
];
```

### Store

| Name                             | Type                                                 | Default | Description                                                                                                                                                                                      |
| -------------------------------- | ---------------------------------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| store\*                          | string                                               | -       | Store name                                                                                                                                                                                       |
| connection\*                     | string                                               | -       | Connection name                                                                                                                                                                                  |
| preset                           | string                                               | -       | <span>When you specify a preset, all missing definitions in the current store will be set to the same values ​​as in the preset. Available presets:</span><ul><li>**google_analytics**</li></ul> |
| label                            | string                                               | -       | Store label in UI                                                                                                                                                                                |
| description                      | string                                               | -       | Store description in UI                                                                                                                                                                          |
| access_roles                     | string []                                            | -       | If specified, only users with the listed roles will have access to Store Model                                                                                                                   |
| method\*                         | enum                                                 | -       | <span>Request method:</span><ul><li>**POST** </li><li>**GET** (does not have a payload)</li></ul>                                                                                                |
| request\*                        | string                                               | -       | JavaScript function to build Request JSON payload body and URL path. Must return \{ urlPath: string, body: any \};                                                                               |
| response\*                       | string                                               | -       | JavaScript function to convert Response payload data into the required Mprove format                                                                                                             |
| date_range_includes_right_side\* | boolean                                              | -       | Specify whether the API time filter includes the right range boundary                                                                                                                            |
| parameters                       | [Store Filter []](#store-filter)                     | -       | Begin a section of store parameters                                                                                                                                                              |
| results\*                        | [Store Result []](#store-result)                     | -       | Begin a section of store results                                                                                                                                                                 |
| field_groups\*                   | [Store Field Group []](#store-field-group)           | -       | Begin a section of store field groups                                                                                                                                                            |
| field_time_groups                | [Store Field Time Group []](#store-field-time-group) | -       | Begin a section of store field time groups                                                                                                                                                       |
| build_metrics                    | [Store Build Metric []](#store-build-metric)         | -       | Begin a section of store BuildMetrics                                                                                                                                                            |
| fields\*                         | [Store Field []](#store-field)                       | -       | Begin a section of store fields                                                                                                                                                                  |

### Store Filter

| Name              | Type                                                         | Default | Description                |
| ----------------- | ------------------------------------------------------------ | ------- | -------------------------- |
| filter\*          | string                                                       | -       | Filter name                |
| label             | string                                                       | -       | Override filter name in UI |
| description       | string                                                       | -       | Filter description in UI   |
| max_fractions     | number                                                       | -       | Max number of fractions    |
| required          | boolean                                                      | -       | Always select filter       |
| fraction_controls | [Fraction Control []](/content/docs/reference/parameters#fraction-control) | -       | List of fraction controls  |

### Store Result

| Name              | Type                                             | Default | Description                   |
| ----------------- | ------------------------------------------------ | ------- | ----------------------------- |
| result\*          | string                                           | -       | Result name                   |
| fractions_types\* | [Result Fraction Type []](#result-fraction-type) | -       | List of result fraction types |

### Result Fraction Type

| Name     | Type                                                         | Default | Description               |
| -------- | ------------------------------------------------------------ | ------- | ------------------------- |
| type\*   | string                                                       | -       | Type name                 |
| label    | string                                                       | -       | Override type name in UI  |
| meta     | any                                                          | -       | Custom metadata           |
| controls | [Fraction Control []](/content/docs/reference/parameters#fraction-control) | -       | List of fraction controls |

### Store Field Group

| Name    | Type   | Default | Description               |
| ------- | ------ | ------- | ------------------------- |
| group\* | string | -       | Group name                |
| label   | string | -       | Override group name in UI |

### Store Field Time Group

| Name   | Type   | Default | Description               |
| ------ | ------ | ------- | ------------------------- |
| time\* | string | -       | Time group name           |
| group  | string | -       | Parent group name         |
| label  | string | -       | Override group name in UI |

### Store Build Metric

| Name   | Type   | Default | Description                                   |
| ------ | ------ | ------- | --------------------------------------------- |
| time\* | string | -       | Specify the field time group to build Metrics |

### Store Field

| Name            | Type    | Default | Description                                                                                                                                                   |
| --------------- | ------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| dimension       | string  | -       | Field name                                                                                                                                                    |
| measure         | string  | -       | Field name                                                                                                                                                    |
| label           | string  | -       | Override field name in UI                                                                                                                                     |
| description     | string  | -       | Field descripiton in UI                                                                                                                                       |
| result\*        | string  | -       | Store field result                                                                                                                                            |
| group           | string  | -       | Parent group name                                                                                                                                             |
| time_group      | string  | -       | Parent time_group name                                                                                                                                        |
| detail          | enum    | -       | <ul><li>years</li><li>quarters</li><li>months</li><li>weeksMonday</li><li>weeksSunday</li><li>days</li><li>hours</li><li>minutes</li><li>timestamps</li></ul> |
| required        | boolean | -       | Always select field                                                                                                                                           |
| meta            | any     | -       | Custom metadata                                                                                                                                               |
| format_number   | string  | -       | [Format Number](/content/docs/reference/format-number)                                                                                                                      |
| currency_prefix | string  | -       | [Format Number - Symbol](/content/docs/reference/format-number#symbol)                                                                                                      |
| currency_suffix | string  | -       | [Format Number - Symbol](/content/docs/reference/format-number#symbol)                                                                                                      |
