Using the Data API

The Data API exposes a service that can be injected in any Angular component. For more details, please refer to the Data API documentation.

It allows interacting with scenario data.

The Data API provides services and model classes to explore the Data Model Schema of your application, to run paginated or aggregation queries, but also to run custom queries exposed by the Platform Data Service. The Data API is used by all Platform widgets to fetch data.

The following Sample Widget implements an example of performing a query to count current scenario issues.

    /**
     * This is a simple example of Data API usage. It performs an aggregation Query on GeneIssue type,
     * to count how many issue (rows) has the selected scenario.
     *
     * @param context current context containing the scenario selection
     *
     * @return an observable of the GeneIssue count for the current selected scenario. -1 if no scenario is selected
     */
    public countIssues(context: GeneContext): Observable<number> {
        // If no scenario returns -1
        if (context.scenarioIds.length === 0) {
            return of(-1);
        } else {

            const countIssuesQuery: AggregationQuery = {
                aggregationName : 'count_issues',
                fieldName : INTERNAL_ID_FIELD,
                aggregationKind : 'count',
                groupByFieldsNames : []
            };

            return this.dataApi.runAggregationQuery('GeneIssue', [countIssuesQuery], context)
                .pipe(
                    map(result => result.aggregations[0].buckets[0].value as number)
                );
        }
    }

The Data API also allows performing filtered queries, and provide helper methods to build filters. GeneContext objects contain definitions of your filters.

/*
 * Example of filtering by scenario
 */
const context = new GeneContextBuilder()
                        .withScenarioId('myScenarioId')
                        .build();

/*
* Example of filter on type 'Activity' having a field 'name' and 'duration'
* The following filter queries activities of the scenario
* having a name containing 'delivery' and a duration greater than '5'
*/
getFilteredContext(metaDataService: GeneMetaDataService, context: GeneContext): Observable<GeneContext> {
    return metaDataService.getTypeMetaData('Activity').pipe(
        map(activityType => {
            const activitiesFilter = new GeneEntityFilterBuilder(activityType);
            const attributesFilter = activitiesFilter
                                        .withNewClause()
                                        .withOperator('AND');

            attributesFilter.withNewAttributeFilter()
                                .withAttribute('name')
                                .withNewCriteria()
                                    .withOperator('CONTAINS')
                                    .withValues('delivery');

            attributesFilter.withNewAttributeFilter()
                                .withAttribute('duration')
                                .withNewCriteria()
                                    .withOperator('GREATER_THAN')
                                    .withValues('5');

            return  new GeneContextBuilder()
                        .withScenarioIds(context.scenarioIds)
                        .withEntityFilter(activitiesFilter)
                        .build();
        }
    ));
}

/*
* Example of filtering 'Activity' that are not scheduled. Supposing that we have two types, Activity and Schedule,
* and that Schedule references Activity through a field 'activity'.
* Note that operator INCLUDED_IN does the opposite filtering.
 */
getUnscheduledActivitiesContext(metaDataService: GeneMetaDataService, context: GeneContext): Observable<GeneContext> {
    return metaDataService.getTypeMetaData('Activity').pipe(
        map(activityType => {
                const activitiesFilter = new GeneEntityFilterBuilder(activityType);
                const attributesFilter = activitiesFilter
                    .withNewClause()
                    .withOperator('AND');

                // We want all Activities not having their internal id in scheduled activities
                //
                // This filter is equivalent to SQL Query:
                // SELECT a.* FROM ACTIVITY a WHERE dbGeneInternalId NOT IN (SELECT s.activity FROM SCHEDULE s)
                attributesFilter.withNewAttributeFilter()
                    .withAttribute('dbGeneInternalId')
                    .withNewCriteria()
                    .withOperator('EXCLUDED_FROM')
                    .withValue('Schedule#activity');

                return  new GeneContextBuilder()
                    .withScenarioIds(context.scenarioIds)
                    .withEntityFilter(activitiesFilter)
                    .build();
            }
        ));
}