@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
JavaScript
;
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