UNPKG

pailingual-odata

Version:

TypeScript client for OData v4 services

341 lines 13.4 kB
(function (factory) { if (typeof module === "object" && typeof module.exports === "object") { var v = factory(require, exports); if (v !== undefined) module.exports = v; } else if (typeof define === "function" && define.amd) { define(["require", "exports", "./metadata", "./serialization", "./utils"], factory); } })(function (require, exports) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const metadata_1 = require("./metadata"); const serialization_1 = require("./serialization"); const utils_1 = require("./utils"); class Query { constructor(_apiMetadata, _entityMetadata, _options) { this._apiMetadata = _apiMetadata; this._entityMetadata = _entityMetadata; this._options = _options; this._segments = []; this.params = {}; this._method = "get"; } static create(apiMetadata, entityMetadata, options) { return new Query(apiMetadata, entityMetadata, options)._freeze(); } _clone(beforeFreeze) { let res = new Query(this._apiMetadata, this._entityMetadata, this._options); res._segments = [...this._segments]; let cloneArray = (a) => a ? [...a] : null; for (const name of Object.getOwnPropertyNames(this.params)) { let val = this.params[name]; if (val != undefined) { res.params[name] = Array.isArray(val) ? cloneArray(val) : val; } } res._method = this._method; res._payload = this._payload; if (beforeFreeze) beforeFreeze(res); return res._freeze(); } _freeze() { //freeze segments this._segments = Object.freeze(this._segments); //freeze params Object.getOwnPropertyNames(this.params).forEach(n => { var v = this.params[n]; if (v !== null && typeof v === "object") Object.freeze(v); }); this.params = Object.freeze(this.params); this._payload = Object.freeze(this._payload); //freze query return Object.freeze(this); } _action(metadata, args) { return this._clone(q => { q._segments.push(new ActionSegment(metadata)); q._method = "post"; q._entityMetadata = metadata.returnType && metadata.returnType.type; if (args && args.length > 0) { let payload = {}; let edmProps = {}; if (metadata.parameters) { for (let i = 0; i < args.length; i++) { const param = metadata.parameters[i]; payload[param.name] = args[i]; edmProps[param.name] = param.type; } } q._entityMetadata = new metadata_1.EdmEntityType("", edmProps); q._payload = payload; } }); } _func(metadata, args) { return this._clone(q => { q._entityMetadata = metadata.returnType && metadata.returnType.type; q._segments.push(new FuncSegment(metadata, args)); }); } byKey(keyExpr) { return this._clone(q => { let pos = q._segments.length; if (q._segments[pos - 1] instanceof CastSegment) pos--; q._segments.splice(pos, 0, new KeySegment(keyExpr)); }); } cast(fullTypeName) { return this._clone(q => q._segments.push(new CastSegment(fullTypeName))); } navigate(property, entityMetadata) { return this._clone(q => { q._entityMetadata = entityMetadata; q._segments.push(new NavigationSegment(property)); }); } operation(metadata, args) { return metadata.isAction ? this._action(metadata, args) : this._func(metadata, args); } count(o = { inline: false }) { return this._clone(q => { if (o.inline) q.params.count = true; else q._segments.push(new CountSegment()); }); } delete() { return this._clone(q => { q._method = "delete"; }); } expand(expand, expr) { return this._clone(q => { let expandParam = q.params.expand == null ? q.params.expand = [] : q.params.expand; expandParam.push({ expand, expr }); }); } filter(expr) { return this._clone(q => { let filters = (q.params.filter == null) ? q.params.filter = new Array() : q.params.filter; filters.push(expr); }); } insert(payload) { return this._clone(q => { q._payload = payload; q._method = "post"; }); } orderBy(expressions) { return this._clone(q => { if (expressions) { if (!q.params.orderBy) q.params.orderBy = []; q.params.orderBy.push(...expressions); } }); } search(expr) { return this._clone(q => { if (!q.params.search) q.params.search = []; q.params.search.push(expr); }); } select(fields) { return this._clone(q => q.params.select = fields); } skip(num) { return this._clone(q => q.params.skip = num); } top(num) { return this._clone(q => q.params.top = num); } update(payload, put) { return this._clone(q => { q._payload = payload; q._method = put ? "put" : "patch"; }); } url(queryParams = true, options) { const apiRoot = (this._apiMetadata && this._apiMetadata.apiRoot) || ""; const params = queryParams ? this.params : undefined; const opt = Object.assign({}, this._options, options); let url = apiRoot + this._segments .map(s => s.toUrlFragment(opt)) .join(""); if (params) { const urlParams = this.buildParams(opt, '&'); if (urlParams) return url + "?" + urlParams; } return url; } buildParams(options, separator = "&") { return Object.getOwnPropertyNames(this.params) .map(n => this.params[n] && this.processParameter(n, this.params[n], options)) .filter(v => v) .join(separator); } processParameter(name, value, options) { switch (name) { case "select": return "$select=" + value.join(","); case "expand": return "$expand=" + value.map((e) => this.expandToString(e, options)).join(","); case "filter": return "$filter=" + value.join(" and "); case "orderBy": return "$orderby=" + value.join(","); case "skip": return "$skip=" + value; case "top": return "$top=" + value; case "count": return value === true ? "$count=true" : undefined; case "search": return "$search=" + value.join(" AND "); } } expandToString(e, options) { if (e.expr) return utils_1.expandExpressionBuild(e.expand, e.expr, this._apiMetadata, this._entityMetadata, options); return e.expand; } exec(options) { var opt = Object.assign({}, this._options, options); var url = this.url(true, opt); return this._fetchData(url, opt); } _fetchData(url, options) { const fetchApi = (options && options.fetch) || fetch; const inputFormatter = serialization_1.getFormatter(options.format || "application/json"); const body = this._payload ? inputFormatter.serialize(this._payload, this._entityMetadata, options) : null; return fetchApi(url, { method: this._method, body, headers: { "Content-Type": inputFormatter.contentType, "X-Requested-With": "XMLHttpRequest" }, credentials: options.credentials }) .then(response => new Promise((resolve, reject) => { if (response.body) response.text().then(body => resolve({ response, body }), reject); else resolve({ response }); })) .then(data => { const bodyStr = data.body; const response = data.response; let contentType = response.headers.get("Content-Type"); if (response.ok) { if (bodyStr && bodyStr.length > 0) { if (!contentType) { if (utils_1.startsWith(bodyStr, "{")) contentType = "application/json"; } else contentType = contentType.split(";")[0].trim(); const outputFormatter = serialization_1.getFormatter(contentType); return outputFormatter.deserialize(bodyStr, this._apiMetadata, options); } else return null; } else { try { var odError = bodyStr && JSON.parse(bodyStr); } catch (_a) { } let error = (odError && odError.error) || response.statusText; throw { status: response.status, error }; } }); } } exports.Query = Query; class Segment { } class NavigationSegment extends Segment { constructor(property) { super(); this.property = property; } toUrlFragment() { return "/" + this.property; } } class KeySegment extends Segment { constructor(key) { super(); this.key = key; } toUrlFragment() { return "(" + this.key + ")"; } } class ActionSegment extends Segment { constructor(_metadata) { super(); this._metadata = _metadata; } toUrlFragment(options) { const actionName = this._metadata.bindingTo && options.enableUnqualifiedNameCall != true ? this._metadata.getFullName() : this._metadata.name; return "/" + actionName; } } class FuncSegment extends Segment { constructor(__metadata, __args) { super(); this.__metadata = __metadata; this.__args = __args; } toUrlFragment(options) { const actionName = this.__metadata.bindingTo && options.enableUnqualifiedNameCall != true ? this.__metadata.getFullName() : this.__metadata.name; const serializedArgs = this.__args.map((a, i) => { if (this.__metadata.parameters) { const paramMetadata = this.__metadata.parameters[i]; if (paramMetadata != null) { const v = serialization_1.serializeValue(a, paramMetadata.type.type, true); return [paramMetadata.name, v].join("="); } } throw new Error(`Parameter '${i}', for function '${actionName}', not defined in metadata`); }); return `/${actionName}(${serializedArgs.join(",")})`; } } class CountSegment extends Segment { toUrlFragment() { return "/$count"; } } class CastSegment extends Segment { constructor(__fullTypeName) { super(); this.__fullTypeName = __fullTypeName; } toUrlFragment() { return "/" + this.__fullTypeName; } } }); //# sourceMappingURL=query.js.map