UNPKG

scrivito

Version:

Scrivito is a professional, yet easy to use SaaS Enterprise Content Management Service, built for digital agencies and medium to large businesses. It is completely maintenance-free, cost-effective, and has unprecedented performance and security.

211 lines (172 loc) 5.43 kB
import { DataLocatorFilter, DataLocatorOperatorFilter, DataLocatorValueFilter, DataLocatorValueViaFilter, ViaRef, isDataLocatorOperatorFilter, } from 'scrivito_sdk/client'; import { ArgumentError } from 'scrivito_sdk/common'; import { getDataClassOrThrow } from 'scrivito_sdk/data_integration'; import { DataItem, DataScope, DataScopeError, isFilterOperator, } from 'scrivito_sdk/data_integration/data_class'; import { findItemElementInDataStackAndGlobalData, findScopeElementInDataStackAndGlobalData, } from 'scrivito_sdk/data_integration/data_context'; import { isValidDataId } from 'scrivito_sdk/data_integration/data_id'; import { DataStack, deserializeDataStackElement, } from 'scrivito_sdk/data_integration/data_stack'; import { EmptyDataScope } from 'scrivito_sdk/data_integration/empty_data_scope'; import { operatorToOpCode } from 'scrivito_sdk/data_integration/index_params'; import { DataLocator, isDataLocatorValueViaFilter } from 'scrivito_sdk/models'; export function applyDataLocator( dataStack: DataStack, dataLocator: DataLocator | null | undefined ): DataScope { if (!dataLocator) return new EmptyDataScope(); const className = dataLocator.class(); if (className === null) return new EmptyDataScope(); try { const viaRef = dataLocator.viaRef(); const sourceDataScope = viaRef ? findMatchingDataScopeOrThrow(className, dataStack, viaRef) : getDataClassOrThrow(className).all(); return applyDataLocatorDefinition(sourceDataScope, dataStack, dataLocator); } catch (error) { if (error instanceof ArgumentError) { return new EmptyDataScope({ error: new DataScopeError(error.message) }); } throw error; } } function applyDataLocatorDefinition( sourceDataScope: DataScope, dataStack: DataStack, dataLocator: DataLocator ): DataScope { let dataScope = sourceDataScope; const attributeName = dataLocator.field(); if (attributeName) { dataScope = dataScope.transform({ attributeName }); } const query = dataLocator.query(); if (query) { dataScope = query.reduce( (scope, filter) => applyFilter(scope, filter, dataStack), dataScope ); } const orderBy = dataLocator.orderBy(); if (orderBy) { dataScope = dataScope.transform({ order: orderBy }); } const size = dataLocator.size(); if (size !== undefined) { dataScope = dataScope.transform({ limit: size }); } return dataScope; } function applyFilter( scope: DataScope, filter: DataLocatorFilter, dataStack: DataStack ) { if (isDataLocatorOperatorFilter(filter)) { return applyOperatorFilter(scope, filter); } if (isDataLocatorValueViaFilter(filter)) { return applyValueViaFilter(scope, filter, dataStack); } return applyValueFilter(scope, filter); } function applyOperatorFilter( scope: DataScope, { field, operator, value }: DataLocatorOperatorFilter ) { const [fullOperator] = Object.entries(operatorToOpCode).find(([_, val]) => val === operator) || []; return scope.transform({ filters: { [field]: { operator: isFilterOperator(fullOperator) ? fullOperator : 'equals', value, }, }, }); } function applyValueFilter( scope: DataScope, { field, value }: DataLocatorValueFilter ) { return scope.transform({ filters: { [field]: value } }); } function applyValueViaFilter( scope: DataScope, { field, value_via: { class: viaClass, field: viaField }, }: DataLocatorValueViaFilter, dataStack: DataStack ) { const viaDataItem = findMatchingDataItemOrThrow(viaClass, dataStack); if (viaField === '_obj_parent_id') { const parentObj = viaDataItem.obj()?.parent(); if (parentObj) { return applyValueFilter(scope, { field: '_id', value: parentObj.id() }); } return new EmptyDataScope(); } if (viaField === '_id') { return applyValueFilter(scope, { field, value: viaDataItem.id() }); } if (field === '_id') { const value = viaDataItem.getRaw(viaField); const dataClass = scope.dataClass() ?? undefined; if (value === undefined || value === null) { return new EmptyDataScope({ dataClass, isDataItem: true, }); } if (!isValidDataId(value)) { return new EmptyDataScope({ dataClass, isDataItem: true, error: new ArgumentError( `${JSON.stringify(value)} is not a valid data ID` ), }); } return applyValueFilter(scope, { field, value }); } throw new ArgumentError('Irregular relationship'); } function findMatchingDataItemOrThrow(viaClass: string, dataStack: DataStack) { const element = findItemElementInDataStackAndGlobalData(viaClass, dataStack); if (!element) throw new ArgumentError(`No ${viaClass} item found`); const item = deserializeDataStackElement(element); if (item instanceof DataItem) return item; throw new ArgumentError(`No ${viaClass} item with ID ${element._id} found`); } function findMatchingDataScopeOrThrow( className: string, dataStack: DataStack, viaRef: ViaRef ): DataScope { const element = findScopeElementInDataStackAndGlobalData( className, dataStack, viaRef ); if (!element) throw new ArgumentError(`No ${className} scope found`); const scope = deserializeDataStackElement(element); if (scope instanceof DataScope) return scope; throw new ArgumentError(`No ${className} scope found`); }