imng-odata-client
Version:
This library was generated with [Nx](https://nx.dev).
451 lines (435 loc) • 16.6 kB
JavaScript
import * as i0 from '@angular/core';
import { inject, Injectable, NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { HttpClient, provideHttpClient, withInterceptorsFromDi } from '@angular/common/http';
import { MILLI_SECS_PER_SEC } from 'imng-nrsrx-client-utils';
import { map } from 'rxjs/operators';
function isChildFilter(source) {
return !!source?.childTable;
}
function isCompositeFilter(source) {
return !!source?.filters;
}
var ComputationOperators;
(function (ComputationOperators) {
ComputationOperators["Multiply"] = "mul";
ComputationOperators["Divide"] = "div";
ComputationOperators["Add"] = "add";
ComputationOperators["Subtract"] = "sub";
ComputationOperators["Modulus"] = "mod";
})(ComputationOperators || (ComputationOperators = {}));
function isComputation(source) {
return !!source?.operator;
}
function isExpander(source) {
return !!source?.table;
}
function serializeValue(value) {
if (typeof value === 'string') {
return `'${value}'`;
}
return value instanceof Date
? `${value.toISOString().split('T')[0]}`
: `${value}`;
}
const serializeSimpleFilter = (field, operator, value) => `${field}+${operator}+${serializeValue(value)}`;
const serializeArrayFilter = (field, operator, values) => values
? `${field}+${operator}+(${values.map((m) => serializeValue(m)).join(',')})`
: '';
const serializeFunctionFilter = (field, func, value) => (value ? `${func}(${field},${serializeValue(value)})` : '');
/**
* Represents the list of supported simple filter operators.
*/
class FilterOperators {
/**
* The `eq` operator.
*/
static { this.equals = {
name: 'equals',
toODataString: (field, value) => serializeSimpleFilter(field, 'eq', value),
}; }
/**
* The `gt` operator.
*/
static { this.greaterThan = {
name: 'greaterThan',
toODataString: (field, value) => serializeSimpleFilter(field, 'gt', value),
}; }
/**
* The `ge` operator.
*/
static { this.greaterThanOrEquals = {
name: 'greaterThanOrEquals',
toODataString: (field, value) => serializeSimpleFilter(field, 'ge', value),
}; }
/**
* The `lt` operator.
*/
static { this.lessThan = {
name: 'lessThan',
toODataString: (field, value) => serializeSimpleFilter(field, 'lt', value),
}; }
/**
* The `le` operator.
*/
static { this.lessThanOrEquals = {
name: 'lessThanOrEquals',
toODataString: (field, value) => serializeSimpleFilter(field, 'le', value),
}; }
/**
* The `ne` operator.
*/
static { this.notEquals = {
name: 'notEquals',
toODataString: (field, value) => serializeSimpleFilter(field, 'ne', value),
}; }
/**
* The `in` operator.
*/
static { this.in = {
name: 'in',
toODataString: (field, values) => serializeArrayFilter(field, 'in', values),
}; }
/**
* The `not in` operator.
*/
static { this.notIn = {
name: 'notIn',
toODataString: (field, values) => serializeArrayFilter(field, 'not+in', values),
}; }
/**
* The `is not null` operator.
*/
static { this.notNull = {
name: 'notNull',
toODataString: (field) => `${field}+ne+null`,
}; }
/**
* The `is null` operator.
*/
static { this.isNull = {
name: 'isNull',
toODataString: (field) => `${field}+eq+null`,
}; }
/**
* The `contains` operator.
*/
static { this.contains = {
name: 'contains',
toODataString: (field, value) => serializeFunctionFilter(field, 'contains', value),
}; }
/**
* The `not contain` operator.
*/
static { this.notContains = {
name: 'notContains',
toODataString: (field, value) => serializeFunctionFilter(field, 'not+contains', value),
}; }
/**
* The `ends with` operator.
*/
static { this.endsWith = {
name: 'endswith',
toODataString: (field, value) => serializeFunctionFilter(field, 'endswith', value),
}; }
/**
* The `not ends with` operator.
*/
static { this.notEndsWith = {
name: 'notEndsWith',
toODataString: (field, value) => serializeFunctionFilter(field, 'not+endswith', value),
}; }
/**
* The `startswith` operator.
*/
static { this.startsWith = {
name: 'startsWith',
toODataString: (field, value) => serializeFunctionFilter(field, 'startswith', value),
}; }
/**
* The `not start with` operator.
*/
static { this.notStartsWith = {
name: 'notStartsWith',
toODataString: (field, value) => serializeFunctionFilter(field, 'not+startswith', value),
}; }
/**
* The `empty` operator.
*/
static { this.isEmpty = {
name: 'isEmpty',
toODataString: (field) => serializeSimpleFilter(field, 'eq', ''),
}; }
/**
* The `not empty` operator.
*/
static { this.notEmpty = {
name: 'notEmpty',
toODataString: (field) => serializeSimpleFilter(field, 'ne', ''),
}; }
}
const filterOperators = {
contains: FilterOperators.contains,
endsWith: FilterOperators.endsWith,
equals: FilterOperators.equals,
dateIs: FilterOperators.equals,
greaterThan: FilterOperators.greaterThan,
gt: FilterOperators.greaterThan,
dateAfter: FilterOperators.greaterThan,
greaterThanOrEquals: FilterOperators.greaterThanOrEquals,
gte: FilterOperators.greaterThanOrEquals,
in: FilterOperators.in,
isEmpty: FilterOperators.isEmpty,
isNull: FilterOperators.isNull,
lessThan: FilterOperators.lessThan,
lt: FilterOperators.lessThan,
dateBefore: FilterOperators.lessThan,
lessThanOrEquals: FilterOperators.lessThanOrEquals,
lte: FilterOperators.lessThan,
notContains: FilterOperators.notContains,
notEmpty: FilterOperators.notEmpty,
notEndsWith: FilterOperators.notEndsWith,
notEquals: FilterOperators.notEquals,
dateIsNot: FilterOperators.notEquals,
notIn: FilterOperators.notIn,
notNull: FilterOperators.notNull,
notStartsWith: FilterOperators.notStartsWith,
startsWith: FilterOperators.startsWith,
};
function createEmptyODataResult() {
return { value: Array(), count: 0 };
}
function isODataResult(source) {
return !!source?.value;
}
const getFilterOperator = (operatorName) => filterOperators[operatorName];
const mapData = (options) => map((response) => {
if (!response) {
return { value: [], count: 0 };
}
return Array.isArray(response)
? {
value: response,
count: response.length,
}
: {
value: parseDatesInCollection(response.value, options),
count: response['@odata.count'],
};
});
function parseDatesInCollection(collection, options) {
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');
options.utcNullableProps?.forEach((t) => {
if (utcProps.indexOf(t) === -1) {
utcProps.push(t);
}
});
options.dateNullableProps?.forEach((t) => {
if (dateProps.indexOf(t) === -1) {
dateProps.push(t);
}
});
// prettier-ignore
// eslint-disable-next-line @typescript-eslint/no-explicit-any
collection.forEach((val) => {
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));
}
class ODataClientService {
constructor() {
this.httpClient = inject(HttpClient);
}
fetch(odataEndpoint, query, options = {}) {
const queryStr = this.getODataString(query, options);
return this.httpClient
.get(`${odataEndpoint}?${queryStr}`)
.pipe(mapData(options));
}
getODataString(query, options = {}) {
let queryString = '';
queryString = this.processFilters(query, options, queryString);
queryString = this.processOrderBy(query, queryString);
queryString = this.processSelectors(query, queryString);
queryString = this.processExpanders(query, queryString);
queryString = this.processSimpleParameters('top', query, queryString);
queryString = this.processSimpleParameters('skip', query, queryString);
queryString = this.processGuids(queryString);
queryString = this.processDates(queryString);
queryString = this.processCount(query, queryString);
queryString = this.processCacheBusting(options, queryString);
queryString = queryString.substring(1); // removing first &
return queryString;
}
processExpanders(query, queryString) {
if (query.expand && query.expand.length > 0) {
const expansionStrings = query.expand.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}(`;
const query = {
...element,
count: element.count ?? false,
expand: undefined,
};
result += `${this.getODataString(query).replace(/&/g, ';')};`;
if (element.expand) {
const expanders = element.expand.map((expander) => {
if (isExpander(expander)) {
return this.getExpansionString(expander);
}
return expander;
});
result += `$expand=${expanders.join(',')};`;
}
result += ')';
result = result
.replace(/\(;\$expand=/, '($expand=') //Replaces empty expand "(;$expand=" with "($expand="
.replace(/\$expand=;?\)$/, ')') //Replaces empty expand ";$expand=;)" or ";$expand=)" with ")"
.replace(/\(;\)$/, '') //Removes empty expansion clause "(;)"
.replace(/;\)$/, ')'); //Replaces ";)" with ")"
}
return result;
}
processOrderBy(query, queryString) {
if (!query.orderBy?.length) {
return queryString;
}
const sortString = query.orderBy
.map((m) => `${m.field}${m.dir === 'desc' ? '+desc' : ''}`)
.join(',');
return `${queryString}&$orderby=${sortString}`;
}
processFilters(query, _options, queryString) {
if (!query.filter?.filters?.length) {
return queryString;
}
const filterString = this.serializeCompositeFilter(query.filter);
return `${queryString}&$filter=${filterString}`;
}
serializeCompositeFilter(filter) {
const filterLogicSeperator = `+${filter.logic}+`;
return `(${filter.filters
.map((m) => isCompositeFilter(m)
? this.serializeCompositeFilter(m)
: this.serializeFilter(m))
.filter((m) => m && m !== '()')
.join(filterLogicSeperator)})`;
}
serializeFilter(filter) {
const odataStringFunction = filter.operator?.toODataString ||
getFilterOperator(filter.operator?.name || 'equals').toODataString;
if (isChildFilter(filter)) {
const childFieldName = `o/${filter.field}`;
return `${filter.childTable}/${filter.linqOperation}(o: ${odataStringFunction(childFieldName, filter.value)})`;
}
else {
return odataStringFunction(filter.field, filter.value);
}
}
processSimpleParameters(parameterName, query, queryString) {
if (query[parameterName] ||
(parameterName === 'top' && query[parameterName] === 0)) {
return `${queryString}&$${parameterName}=${query[parameterName]}`;
}
return queryString;
}
processCacheBusting(options, queryString) {
if (options.bustCache) {
const timeStamp = new Date().toISOString().replace(/[-:.TZ]/g, '');
return `${queryString}×tamp=${timeStamp}`;
}
return queryString;
}
processCount(query, queryString) {
if (query.count === false) {
return queryString;
}
return `${queryString}&$count=true`;
}
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.select && state.select.length > 0) {
return `${queryString}&$select=${state.select.join()}`;
}
return queryString;
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: ODataClientService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: ODataClientService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: ODataClientService, decorators: [{
type: Injectable,
args: [{
providedIn: 'root',
}]
}] });
class ImngODataClientModule {
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: ImngODataClientModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.1.4", ngImport: i0, type: ImngODataClientModule, imports: [CommonModule] }); }
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: ImngODataClientModule, providers: [ODataClientService, provideHttpClient(withInterceptorsFromDi())], imports: [CommonModule] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: ImngODataClientModule, decorators: [{
type: NgModule,
args: [{ imports: [CommonModule], providers: [ODataClientService, provideHttpClient(withInterceptorsFromDi())] }]
}] });
function createODataResult(t) {
return {
value: t,
count: t?.length,
};
}
/**
* Generated bundle index. Do not edit.
*/
export { ComputationOperators, FilterOperators, ImngODataClientModule, ODataClientService, createEmptyODataResult, createODataResult, filterOperators, getFilterOperator, isChildFilter, isCompositeFilter, isComputation, isExpander, isODataResult, serializeArrayFilter, serializeFunctionFilter, serializeSimpleFilter, serializeValue };
//# sourceMappingURL=imng-odata-client.mjs.map