imng-kendo-odata
Version:
This library was generated with [Nx](https://nx.dev).
527 lines (509 loc) • 21.4 kB
JavaScript
import * as i0 from '@angular/core';
import { inject, Injectable, NgModule } from '@angular/core';
import { isCompositeFilterDescriptor, toODataString } from '@progress/kendo-data-query';
import { HttpClient } from '@angular/common/http';
import { map, filter } from 'rxjs/operators';
import { MILLI_SECS_PER_SEC, isaNumber, distinct, isaDate } from 'imng-nrsrx-client-utils';
import { CommonModule } from '@angular/common';
const emptyODataResult = { data: [], total: 0 };
function createEmptyODataResult() {
return { data: Array(), total: 0 };
}
function createODataResult(t) {
return {
data: t,
total: t?.length,
};
}
function isODataResult(source) {
return !!source?.data;
}
function createODataPayload(resultSet) {
return {
['@odata.count']: resultSet?.length,
value: resultSet,
};
}
function isExpander(source) {
return !!source?.table;
}
function isComputation(source) {
return !!source?.operator;
}
const mapToExtDataResult = (utcNullableProps = [], dateNullableProps = []) => map((response) => {
if (!response) {
return { data: [], total: 0 };
}
const result = Array.isArray(response)
? {
data: response,
total: response.length,
}
: {
data: response.value,
total: response['@odata.count'],
};
result.data = parseDatesInCollection(result.data, utcNullableProps, dateNullableProps);
return result;
});
const firstRecord = () => map((result) => result?.data?.length > 0 ? result.data[0] : {});
const findById = (id, defaultValue = {}) => map((source) => source?.data?.find((f) => f.id === id) || defaultValue);
function parseDatesInCollection(collection, utcNullableProps = [], dateNullableProps = []) {
if (collection?.length > 0) {
const utcProps = Object.keys(collection[0]).filter((x) => x.endsWith('Utc'));
const dateProps = Object.keys(collection[0]).filter((x) => x.endsWith('Date') || x === 'date');
utcNullableProps?.forEach((t) => {
if (utcProps.indexOf(t) === -1) {
utcProps.push(t);
}
});
dateNullableProps?.forEach((t) => {
if (dateProps.indexOf(t) === -1) {
dateProps.push(t);
}
});
// eslint-disable-next-line @typescript-eslint/no-explicit-any
collection.forEach((val) => {
//NOSONAR
utcProps
.filter((p) => val[p])
.forEach((p) => (val[p] = new Date(val[p])));
dateProps
.filter((p) => val[p])
.forEach((p) => (val[p] = toLocalDate(val[p])));
});
}
return collection;
}
function toLocalDate(date) {
const dt = new Date(date);
return new Date(dt.getTime() + Math.abs(dt.getTimezoneOffset() * MILLI_SECS_PER_SEC));
}
function getSubGridData(id, mappingFunction) {
// tslint:disable-next-line: space-before-function-paren
return function (source) {
return source.pipe(map((t) => t.data.find((f) => f.id === id)), map((entity) => mappingFunction(entity)), filter((t) => !!t));
};
}
function getSubData(id, mappingFunction) {
// tslint:disable-next-line: space-before-function-paren
return function (source) {
return source.pipe(map((t) => t.find((f) => f.id === id)), map((entity) => mappingFunction(entity)), filter((t) => !!t));
};
}
function isCompositeChildFilterDescriptor(source) {
return !!source?.filters;
}
function translateChildFilterExpression(odataState, childTableProperty) {
const childFieldString = `${childTableProperty.table}.${childTableProperty.field}`;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const filterPredicate = (filter) => {
return filter.field === childFieldString;
};
const childTableFilter = odataState.filter?.filters.find((t) => isCompositeFilterDescriptor(t) && t.filters?.some(filterPredicate));
if (childTableFilter && odataState.filter) {
odataState.filter = {
...odataState.filter,
filters: [
...odataState.filter.filters.filter((t) => isCompositeFilterDescriptor(t) && !t.filters?.some(filterPredicate)),
],
};
odataState.childFilters = {
logic: odataState.childFilters?.logic || 'and',
filters: odataState.childFilters?.filters?.filter((childFilterDescriptor) => !isCompositeChildFilterDescriptor(childFilterDescriptor) &&
childFilterDescriptor.childTableNavigationProperty !==
childTableProperty.table &&
childFilterDescriptor.field !== childTableProperty.field) || [],
};
odataState.childFilters.filters?.push({
logic: childTableFilter.logic,
filters: childTableFilter?.filters?.map((filter) => ({
...filter,
linqOperation: childTableProperty.linqOperation || 'any',
childTableNavigationProperty: childTableProperty.table,
field: childTableProperty.field,
})),
});
}
return odataState;
}
const filterQueryStringParamLen = 8; //"$filter="
const stringFilterOperators = [
`startswith`,
`endswith`,
`contains`,
`doesnotcontain`,
`isempty`,
`isnotempty`,
];
function processChildFilterDescriptors(state, queryString) {
if (!state.childFilters) {
return queryString;
}
else {
return transformCompositeChildFilter(state.childFilters, queryString);
}
}
function transformChildExistsFilter(childExistsFilter, logic, queryString) {
const filterString = `$filter=${childExistsFilter.childTableNavigationProperty}/${childExistsFilter.linqOperation ?? 'any'}(${childExistsFilter.filter ?? ''})`;
if (queryString.match(/\$filter=/)) {
queryString = queryString.replace(/\$filter=/, `${filterString} ${logic || 'and'} `);
}
else {
queryString += `&${filterString}`;
}
return queryString;
}
function transformCompositeChildFilter(compositeChildFilter, queryString) {
let tempFilterString = '';
compositeChildFilter.filters
?.filter((filter) => !isCompositeChildFilterDescriptor(filter))
.forEach((filter, index, array) => {
tempFilterString += index === 0 && array.length > 1 ? '(' : '';
tempFilterString += transformChildFilter(filter);
if (index === array.length - 1 && array.length > 1) {
tempFilterString += ')';
}
else if (index !== array.length - 1) {
tempFilterString += ` ${compositeChildFilter.logic || 'and'} `;
}
});
if (tempFilterString.length > 0) {
if (queryString.match(/\$filter=/)) {
queryString = queryString.replace(/\$filter=/, `$filter=${tempFilterString} and `);
}
else {
queryString += `&$filter=${tempFilterString}`;
}
}
compositeChildFilter.filters
?.filter((filter) => isCompositeChildFilterDescriptor(filter))
.forEach((filter) => {
queryString = transformCompositeChildFilter(filter, queryString);
});
compositeChildFilter.existsFilters?.forEach((filter) => {
queryString = transformChildExistsFilter(filter, compositeChildFilter.logic, queryString);
});
return queryString;
}
function transformChildFilter(childFilter) {
let filteringString;
if (-1 < stringFilterOperators.findIndex((x) => x === childFilter.operator) &&
!isaNumber(childFilter.value)) {
filteringString = `${childFilter.operator}(o/${childFilter.field}, '${childFilter.value}')`;
}
else {
filteringString = `o/${toODataString({
filter: { logic: 'and', filters: [childFilter] },
}).slice(filterQueryStringParamLen)}`;
}
return (`${childFilter.childTableNavigationProperty}/${childFilter.linqOperation}` +
`(o: ${filteringString})`);
}
function translateChildSortingExpression(odataState, childTableProperties) {
if (!childTableProperties || childTableProperties.length === 0) {
return odataState;
}
const childTableStrings = distinct(childTableProperties.map((x) => x.table));
const childTablePropertyStrings = childTableProperties.map((x) => `${x.table}.${x.field}`);
const filterPredicate = (x) => childTablePropertyStrings.indexOf(x.field) > -1;
const sortedColumns = odataState.sort
?.filter(filterPredicate)
.map((m) => ({ ...m, childProperty: m.field.split('.') }));
if (sortedColumns && sortedColumns.length > 0) {
odataState.sort = odataState.sort?.filter((x) => !filterPredicate(x));
odataState.expanders = odataState.expanders?.map((m) => (isExpander(m) ? { ...m } : m));
const expanders = odataState.expanders
?.filter((t) => childTableStrings.indexOf(t.table) > -1)
.map((t) => {
t.sort = (t.sort || []).filter((f) => !sortedColumns.find((s) => t.table === s.childProperty[0] && f.field === s.childProperty[1]));
return t;
});
sortedColumns.forEach((x) => {
const expander = expanders?.find((e) => e.table === x.childProperty[0]);
expander?.sort?.push({ field: x.childProperty[1], dir: x.dir });
});
}
return odataState;
}
class ODataService {
constructor() {
this.http = inject(HttpClient);
}
fetch(odataEndpoint, state, options = {}) {
let tempState = { ...state };
options.boundChildTableProperties?.forEach((prop) => (tempState = translateChildFilterExpression(tempState, prop)));
tempState = translateChildSortingExpression(tempState, options.boundChildTableProperties);
const countClause = tempState.count === false ? '' : '&$count=true';
const cacheBustClause = options.bustCache === true
? `×tamp=${new Date().toISOString().replace(/[-:.TZ]/g, '')}`
: '';
const queryStr = `${this.getODataString(tempState)}${countClause}${cacheBustClause}`;
return this.http
.get(`${odataEndpoint}?${queryStr}${this.getAdditionalParams(options)}`)
.pipe(mapToExtDataResult(options.utcNullableProps || [], options.dateNullableProps || []));
}
getAdditionalParams(options) {
if (options.additionalParams) {
const keys = Object.keys(options.additionalParams);
const values = Object.values(options.additionalParams);
const queryStringParams = keys.map((key, index) => `&${encodeURIComponent(key)}=${encodeURIComponent(values[index])}`);
return queryStringParams.join('');
}
return '';
}
fetchByPrimaryKey(odataEndpoint, id, state) {
const request = {
expanders: state?.expanders,
selectors: state?.selectors,
filter: {
logic: 'and',
filters: [{ operator: 'eq', field: 'id', value: id }],
},
};
const queryStr = this.getODataString(request);
return this.http
.get(`${odataEndpoint}?${queryStr}`)
.pipe(mapToExtDataResult(), firstRecord());
}
getODataString(state) {
let queryString = toODataString(state);
queryString = this.processExpanders(state, queryString);
queryString = this.processSelectors(state, queryString);
queryString = processChildFilterDescriptors(state, queryString);
queryString = this.processInFilters(state.inFilters, queryString, false);
queryString = this.processInFilters(state.notInFilters, queryString, true);
queryString = this.applyTransformations(state, queryString);
queryString = this.processComputations(state, queryString);
queryString = this.processGuids(queryString);
queryString = this.processDates(queryString);
return queryString;
}
applyTransformations(state, queryString) {
if (state.transformations) {
queryString += `&$apply=${state.transformations}`;
}
return queryString;
}
processDates(queryString) {
const dateRegex = /Date [e-t]{2} \d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z/g;
let m;
const dateMatches = [];
while ((m = dateRegex.exec(queryString)) !== null) {
// This is necessary to avoid infinite loops with zero-width matches
if (m.index === dateRegex.lastIndex) {
dateRegex.lastIndex++;
}
m.forEach((match) => {
dateMatches.push(match);
});
}
dateMatches.forEach((date) => (queryString = queryString.replace(date, date.replace(/T\d{2}:\d{2}:\d{2}.\d{3}Z/g, ''))));
return queryString;
}
processGuids(queryString) {
const guidRegex = /'[\dA-F]{8}-?[\dA-F]{4}-?[\dA-F]{4}-?[\dA-F]{4}-?[\dA-F]{12}'/gi;
let m;
const guidMatches = [];
while ((m = guidRegex.exec(queryString)) !== null) {
// This is necessary to avoid infinite loops with zero-width matches
if (m.index === guidRegex.lastIndex) {
guidRegex.lastIndex++;
}
m.forEach((match) => {
guidMatches.push(match);
});
}
guidMatches.forEach((guid) => (queryString = queryString.replace(guid, guid.replace(/'/g, ''))));
return queryString;
}
processSelectors(state, queryString) {
if (state.selectors && state.selectors.length > 0) {
queryString += `&$select=${state.selectors.join()}`;
}
return queryString;
}
processExpanders(state, queryString) {
if (state.expanders && state.expanders.length > 0) {
const expansionStrings = state.expanders.map((element) => this.getExpansionString(element));
queryString += `&$expand=${expansionStrings.join(',')}`;
}
return queryString;
}
getExpansionString(element) {
let result = '';
if (!element) {
return result;
}
if (typeof element === 'string') {
result += element;
}
else {
result += `${element.table}(`;
if (element.selectors && element.selectors.length > 0) {
result += `$select=${element.selectors.join()};`;
}
if (element.filter || element.sort) {
const state = {
sort: element.sort,
filter: element.filter,
};
result += `${toODataString(state).replace('&', ';')};`;
}
if (element.expanders) {
const expanders = element.expanders.map((expander) => {
if (isExpander(expander)) {
return this.getExpansionString(expander);
}
return expander;
});
result += `$expand=${expanders.join(',')};`;
}
if (element.count) {
result += `${/[(;]$/.exec(result) ? '' : ';'}$count=true`;
}
result += ')';
result = result.replace(/\(\)/, '').replace(/;\)/, ')');
}
return result;
}
processInFilters(inFilters, queryString, isNotIn) {
if (!inFilters) {
return queryString;
}
inFilters.forEach((inFilter) => {
const deDupedVals = Array.from(new Set(inFilter.values.filter((f) => f)));
const inVals = deDupedVals
.map((m) => {
if (isaNumber(m)) {
return `${m}`;
}
else if (isaDate(m)) {
return `${m.toISOString()}`;
}
return `'${m}'`;
})
.join(',');
const inFilterString = `(${inFilter.field} in (${inVals})${isNotIn ? ' eq false' : ''})`;
if (!queryString || queryString.trim().length === 0) {
queryString = `$filter=${inFilterString}`;
}
else if (queryString.match(/\$filter=/)) {
queryString = queryString.replace(/\$filter=/, `$filter=${inFilterString} ${inFilter.logic ?? 'and'} `);
}
else {
queryString = `${queryString}&$filter=${inFilterString}`;
}
});
return queryString;
}
processComputations(state, queryString) {
if (state.compute) {
const computeStrings = state.compute
.filter((f) => !isComputation(f))
.map((f) => f.toString());
computeStrings.push(...state.compute
.filter(isComputation)
.map((f) => `${f.fieldA} ${f.operator} ${f.fieldB} as ${f.alias}`));
queryString = `$compute=${computeStrings.join(',')}${queryString}`;
}
return queryString;
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: ODataService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: ODataService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: ODataService, decorators: [{
type: Injectable,
args: [{
providedIn: 'root',
}]
}] });
class ImngKendoODataModule {
static forRoot() {
return {
ngModule: ImngKendoODataModule,
providers: [ODataService],
};
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: ImngKendoODataModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.1.4", ngImport: i0, type: ImngKendoODataModule, imports: [CommonModule] }); }
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: ImngKendoODataModule, providers: [ODataService], imports: [CommonModule] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: ImngKendoODataModule, decorators: [{
type: NgModule,
args: [{
imports: [CommonModule],
providers: [ODataService],
}]
}] });
function isFilterDescriptor(source) {
return !!source?.field;
}
function findMatchingFilters(odataState, filterField) {
if (!odataState.filter) {
return;
}
return flattenCompositeFilters(odataState.filter).find((x) => x.field === filterField);
}
function flattenCompositeFilters(filters) {
return filters.filters.map((x) => (isCompositeFilterDescriptor(x) ? flattenCompositeFilters(x) : [x])).flat();
}
function removeMatchingFilters(odataState, filterField) {
return {
...odataState,
filter: !odataState.filter
? { logic: 'and', filters: [] }
: { ...odataState.filter, filters: filterFilters(odataState.filter, filterField) },
};
}
function filterFilters(filters, filterField) {
return [
...(isCompositeFilterDescriptor(filters)
? filters.filters
: filters).filter((m) => {
if (isCompositeFilterDescriptor(m)) {
m.filters = [...filterFilters(m.filters, filterField)];
return true;
}
else {
return m.field !== filterField;
}
}),
];
}
function updateFilter(compositefilter, newFilter) {
compositefilter.filters.forEach(subFilter => {
if (isCompositeFilterDescriptor(subFilter)) {
updateFilter(subFilter, newFilter);
}
else if (subFilter.field === newFilter.field) {
compositefilter = {
...compositefilter,
filters: [...compositefilter.filters.filter(f => isCompositeFilterDescriptor(f) ||
f.field !== newFilter.field), newFilter]
};
}
});
return compositefilter;
}
function applyFilter(odataState, filter) {
if (!odataState.filter) {
odataState.filter = { logic: 'and', filters: [] };
}
const matchedFilter = findMatchingFilters(odataState, filter.field);
if (!matchedFilter) {
odataState.filter.filters.push({
logic: 'and',
filters: [filter]
});
}
else {
updateFilter(odataState.filter, filter);
}
return odataState;
}
/**
* Generated bundle index. Do not edit.
*/
export { ImngKendoODataModule, ODataService, applyFilter, createEmptyODataResult, createODataPayload, createODataResult, emptyODataResult, filterFilters, findById, findMatchingFilters, firstRecord, flattenCompositeFilters, getSubData, getSubGridData, isCompositeChildFilterDescriptor, isComputation, isExpander, isFilterDescriptor, isODataResult, mapToExtDataResult, parseDatesInCollection, removeMatchingFilters, toLocalDate, translateChildFilterExpression, translateChildSortingExpression, updateFilter };
//# sourceMappingURL=imng-kendo-odata.mjs.map