UNPKG

@odata2ts/odata-query-objects

Version:

Q-Objects are the magic sauce for the odata-query-builder and allow for renaming and type conversion

166 lines 7.02 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.QFunction = void 0; const OperationReturnType_1 = require("./OperationReturnType"); // const REGEXP_PATH = /(^[^(]+)\(.*/; const REGEXP_PARAMS = /.*\(([^)]+)\)/; const REGEXP_V2_PARAMS = /.*\?(.+)/; const SINGLE_VALUE_TYPES = ["string", "number", "boolean"]; function compileUrlParams(params, notEncoded = false) { if (!params || !Object.keys(params).length) { return "()"; } const queryParams = []; const pathParams = Object.entries(params).map(([key, value]) => { const isComplex = value.startsWith("{") || value.startsWith("["); const [safeKey, safeValue] = notEncoded ? [key, value] : [encodeURIComponent(key), encodeURIComponent(value)]; if (isComplex) { queryParams.push(`@${safeKey}=${safeValue}`); return `${safeKey}=@${safeKey}`; } return `${safeKey}=${safeValue}`; }); return `(${pathParams.join(",")})` + (queryParams.length > 0 ? `?${queryParams.join("&")}` : ""); } function compileQueryParams(params, notEncoded = false) { return !params || !Object.keys(params).length ? "" : "?" + Object.entries(params) .map(([key, value]) => { return notEncoded ? key + "=" + value : encodeURIComponent(key) + "=" + encodeURIComponent(value); }) .join("&"); } /** * Base class for handling an OData function (v2 and V4). * * This includes handling of entity id paths (same format as V4 functions). */ class QFunction { constructor(name, qReturnType = OperationReturnType_1.emptyOperationReturnType, config = {}) { this.name = name; this.qReturnType = qReturnType; this.config = config; } getParamSets() { const params = this.getParams(); if (params.length) { const elemZero = params[0]; if (!Array.isArray(elemZero)) { return [params]; } } return params; } getName() { return this.name; } isV2() { return !!this.config.v2Mode; } buildUrl(params, notEncoded = false) { let paramsString; // short form of id: just primitive value for single key entities if (SINGLE_VALUE_TYPES.includes(typeof params)) { const qParam = this.findSingleParam(); if (!qParam) { throw new Error("Only one primitive value was provided, but the function requires multiple parameters!"); } const singleParam = qParam.formatUrlValue(params) || ""; paramsString = `(${notEncoded ? singleParam : encodeURIComponent(singleParam)})`; } // complex form or undefined else { const fParams = this.formatParams(params); paramsString = this.isV2() ? compileQueryParams(fParams, notEncoded) : compileUrlParams(fParams, notEncoded); } return this.name + paramsString; } formatParams(params) { if (!params) { return undefined; } const qParams = this.findBestMatchingParamSet(Object.keys(params), true); if (!qParams.length) { return undefined; } return Object.entries(params) .map(([key, value]) => { const qParam = qParams.find((q) => q.getMappedName() === key); if (!qParam) { throw new Error(`Unknown parameter "${key}"!`); } return [qParam.getName(), qParam.formatUrlValue(value)]; }) .filter((p) => p[1] !== undefined) .reduce((collector, [key, value]) => { collector[key] = value; return collector; }, {}); } parseUrl(url, notDecoded = false) { const paramSets = this.getParamSets(); if (!(paramSets === null || paramSets === void 0 ? void 0 : paramSets.length)) { return undefined; } // const pathMatcher = url.match(REGEXP_PATH); // const path = pathMatcher?.length === 2 ? pathMatcher[1] : undefined; const paramMatcher = url.match(this.isV2() ? REGEXP_V2_PARAMS : REGEXP_PARAMS); const rawParams = (paramMatcher === null || paramMatcher === void 0 ? void 0 : paramMatcher.length) === 2 ? paramMatcher[1].split(this.isV2() ? "&" : ",") : []; if (!rawParams.length) { throw new Error(`Parsing url "${url}" did not yield any params!`); } // handle short form => myEntity(123) if (rawParams.length === 1 && rawParams[0].indexOf("=") === -1) { const qParam = this.findSingleParam(); if (!qParam) { throw new Error("Only one primitive value was provided, but the function requires multiple parameters!"); } return qParam.parseUrlValue(notDecoded ? rawParams[0] : decodeURIComponent(rawParams[0])); } // regular form const params = rawParams.reduce((model, param) => { const keyAndValue = param.split("="); if (keyAndValue.length !== 2) { throw new Error(`Failed to parse function params: Key and value must be specified!`); } const key = notDecoded ? keyAndValue[0] : decodeURIComponent(keyAndValue[0]); const value = notDecoded ? keyAndValue[1] : decodeURIComponent(keyAndValue[1]); model[key] = value; return model; }, {}); const qParams = this.findBestMatchingParamSet(Object.keys(params), false); return Object.entries(params).reduce((model, [key, value]) => { const qParam = qParams.find((q) => q.getName() === key); if (!qParam) { throw new Error(`Failed to parse function params: Param "${key}" is not part of this function's method signature!`); } model[qParam.getMappedName()] = qParam.parseUrlValue(value); return model; }, {}); } convertResponse(response) { return this.isV2() ? this.qReturnType.convertResponseV2(response) : this.qReturnType.convertResponse(response); } findSingleParam() { const result = this.getParamSets().find((pSet) => pSet.length === 1); return result ? result[0] : undefined; } findBestMatchingParamSet(paramKeys, findByMappedName) { var _a; const paramSets = this.getParamSets(); if (!paramKeys.length || !paramSets.length) { return []; } else if (paramSets.length === 1) { return paramSets[0]; } return ((_a = this.getParamSets().find((pSet) => { const qParamKeys = pSet.map((p) => (findByMappedName ? p.getMappedName() : p.getName())); return !paramKeys.find((pKey) => !qParamKeys.includes(pKey)); })) !== null && _a !== void 0 ? _a : []); } } exports.QFunction = QFunction; //# sourceMappingURL=QFunction.js.map