Adding Custom Dimension Configuration

Overview

This section explains how to customize the cube’s schema. You can add, remove, or modify fields from new or default stores by creating specific Beans and importing them into LimitsAppConfig.class.

note

Any customizations to the default schema may cause issues with the default cube configuration.

Customizing the schema selection

1. (Optional) Modify the schema selection description

If the field we want to turn into a level is not currently in our schema selection, we need to add it first. To see an example of adding a new store and reference to the schema, see Adding new stores and references.

info

The cube selection is created by retrieving all fields from a datastore, so adding an extra field to an existing store will also add it to the selection. Only fields in new datastores need a change on the selection.

You can add fields to the schema selection by creating a Spring Bean with type UnaryOperator<CanUseOtherReference>.

For example:

@Bean
  @Primary
  UnaryOperator<ISelectionDescriptionBuilder.CanUseOtherReference> extraSchemaSelections() {
    return builder -> builder.usingReference(TARGET_STORE_TO_DESTINATION_STORE_REFERNCE).withAllFields();
  }

note

Depending on the new store being added, fields may need to be excluded from the selection to avoid a conflict.

2. Add new dimensions, hierarchies, and levels

You can now turn the field in the schema selection into a level in the cube.

Dimensions, hierarchies, and levels can be added to the cube configuration by creating Spring Beans with type DimensionsAdder.

For example:

 /**
   * Adds a dimension to the datastore
   *
   * @return The dimension adder
   */
  @Primary
  @Bean
  @Order(50)
  public ICanStartBuildingDimensions.DimensionsAdder dimensions() {
    return builder ->
        builder.withDimension(DESTINATION_DIMENSION).withHierarchyOfSameName().withLevelOfSameName();
  }

note

The order has been set to 50 so that this dimension is added after the existing dimensions (order=20) and before the epoch dimension (order=99).

Other datastore customizations

To add a new store and reference to the schema, create a Spring Bean with type List<DatastoreConfiguratorSetup.DatastoreConfiguratorConsumer>. This Spring Bean will contain all customizations we want to apply to the datastore.

The example below contains the following customizations:

/**
 * Applies all extra datastore configurations.
 */
@Bean
  public List<DatastoreConfiguratorSetup.DatastoreConfiguratorConsumer> extraDatastoreConfigs() {
    return List.of(
        addNewStoreAndReference(),
        addFieldToDefaultStore(),
        updateFieldFromDefaultStore(),
        removeFieldFromDefaultStore());
  }

  /**
   * Adds a new store and reference to the datastore
   *
   * @return List of {@link DatastoreConfiguratorSetup.DatastoreConfiguratorConsumer}s
   */
  private DatastoreConfiguratorSetup.DatastoreConfiguratorConsumer addNewStoreAndReference() {
    return configurator -> {
      configurator.addStore(LIMITS_STORE_NAME, createStoreCustomization(configurator));
      configurator.addReference(LIMITS_STORE_NAME, createReferenceCustomization(configurator));
    };
  }

  /**
   * Adds a "Count" field to the As Of Date store.
   *
   * @return {@link DatastoreConfiguratorSetup.DatastoreConfiguratorConsumer}
   */
  private DatastoreConfiguratorSetup.DatastoreConfiguratorConsumer addFieldToDefaultStore() {
    return configurator ->
        configurator.insertField(
            SCHEMA,
            AS_OF_DATE_STORE_NAME,
            INCIDENTS_AS_OF_DATE,
            new CustomField("Count", ILiteralType.DOUBLE).asNullable());
  }

  /**
   * Removes the Timestamp field from the Incidents Store.
   *
   * @return {@link DatastoreConfiguratorSetup.DatastoreConfiguratorConsumer}
   */
  private DatastoreConfiguratorSetup.DatastoreConfiguratorConsumer removeFieldFromDefaultStore() {
    return configurator -> {
      configurator.removeField(
          SCHEMA, SCOPE_LEVEL_MEMBERS_STORE_NAME, SCOPE_LEVEL_MEMBERS_LEVEL_NAME_IDS);
    };
  }

  /**
   * Updates the ScopeIndex field in the LimitsScope store, changing its type to String.
   *
   * @return {@link DatastoreConfiguratorSetup.DatastoreConfiguratorConsumer}
   */
  private DatastoreConfiguratorSetup.DatastoreConfiguratorConsumer updateFieldFromDefaultStore() {
    return configurator ->
        configurator.updateField(
            SCHEMA, LIMITS_SCOPE_STORE_NAME, new CustomField(SCOPE_INDEX, STRING));
  }

/**
 * Creates a Reference Description for the new reference.
 * @param configurator The datastore configurator
 * @return {@link IReferenceDescription}
 */
private IReferenceDescription createReferenceCustomization(IDatastoreConfigurator configurator) {
    return configurator.referenceBuilder(SCHEMA)
            .fromStore(LIMITS_STORE_NAME)
            .toStore(DEMO_STORE)
            .withName(DEMO_REFERENCE)
            .withMapping(LIMIT_KEY, DEMO_DIMENSION)
            .build();
}

/**
 * Creates a Store Description for the new store.
 * @param configurator The datastore configurator
 * @return {@link IStoreDescription}
 */
private IStoreDescription createStoreCustomization(IDatastoreConfigurator configurator) {
    return configurator
            .storeBuilder(SCHEMA)
            .withStoreName(DEMO_STORE)
            .withField(DEMO_DIMENSION)
            .asKeyField()
            .build();
}

3. Import the Spring Bean

Once the bean is created, import it into the project. See Importing Spring Beans into the Project on how to do this. Once done, Spring will use the custom bean when configuring the schema.