pailingual-odata
Version:
TypeScript client for OData v4 services
342 lines • 16.1 kB
JavaScript
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
(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", "./utils"], factory);
}
})(function (require, exports) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("./utils");
const COLLECTION_TYPE_PREFIX = "Collection(";
var EdmTypes;
(function (EdmTypes) {
EdmTypes["Int32"] = "Edm.Int32";
EdmTypes["Int16"] = "Edm.Int16";
EdmTypes["Boolean"] = "Edm.Boolean";
EdmTypes["String"] = "Edm.String";
EdmTypes["Single"] = "Edm.Single";
EdmTypes["Guid"] = "Edm.Guid";
EdmTypes["DateTimeOffset"] = "Edm.DateTimeOffset";
EdmTypes["Date"] = "Edm.Date";
EdmTypes["Double"] = "Edm.Double";
EdmTypes["TimeOfDay"] = "Edm.TimeOfDay";
EdmTypes["Decimal"] = "Edm.Decimal";
EdmTypes["Unknown"] = "Unknown";
})(EdmTypes = exports.EdmTypes || (exports.EdmTypes = {}));
class EdmEntityType {
constructor(name, properties, navProperties = {}, keys, baseType, openType) {
this.name = name;
this.properties = properties;
this.navProperties = navProperties;
this.keys = keys;
this.baseType = baseType;
this.openType = openType;
this.getFullName = () => getFullName(this);
}
}
exports.EdmEntityType = EdmEntityType;
class EdmComplexType extends EdmEntityType {
}
exports.EdmComplexType = EdmComplexType;
class EdmEnumType {
constructor(name, members) {
this.name = name;
this.members = members;
this.getFullName = () => getFullName(this);
}
}
exports.EdmEnumType = EdmEnumType;
class EdmEntityTypeReference {
constructor(type, nullable = true, collection = false) {
this.type = type;
this.nullable = nullable;
this.collection = collection;
}
static fromTypeReference(typeReference) {
if (typeReference.type instanceof EdmEntityType) {
return typeReference;
}
throw new Error("Instance must be reference to EdmEntityType");
}
}
exports.EdmEntityTypeReference = EdmEntityTypeReference;
class EdmTypeReference {
constructor(type, nullable = true, collection = false) {
this.type = type;
this.nullable = nullable;
this.collection = collection;
}
}
exports.EdmTypeReference = EdmTypeReference;
;
class OperationMetadata {
constructor(name, isAction, parameters, returnType, bindingTo) {
this.name = name;
this.isAction = isAction;
this.parameters = parameters;
this.returnType = returnType;
this.bindingTo = bindingTo;
this.getFullName = () => getFullName(this);
}
}
exports.OperationMetadata = OperationMetadata;
function getFullName(obj) {
if (obj.namespace)
return [obj.namespace.name, obj.name].join(".");
return obj.name;
}
class Namespace {
constructor(name) {
this.name = name;
this.operations = [];
this.types = {};
}
addTypes(...types) {
for (let type of types) {
type.namespace = this;
this.types[type.name] = type;
}
}
addOperations(...operations) {
for (let operation of operations) {
operation.namespace = this;
this.operations.push(operation);
}
}
}
exports.Namespace = Namespace;
;
var __metadataCache = {};
function loadMetadata(apiRoot, options, cache = true) {
if (utils_1.endsWith(apiRoot, "/"))
apiRoot = apiRoot.substr(0, apiRoot.length - 1);
const normalizedApiRoot = apiRoot.toLowerCase(), res = __metadataCache[normalizedApiRoot];
if (res == null || !cache) {
return ApiMetadata.loadAsync(apiRoot, options)
.then(md => {
if (cache)
__metadataCache[normalizedApiRoot] = md;
return md;
});
}
return Promise.resolve(res);
}
exports.loadMetadata = loadMetadata;
class ApiMetadata {
constructor(apiRoot, containerName, namespaces = {}, entitySets = {}, singletons = {}) {
this.apiRoot = apiRoot;
this.containerName = containerName;
this.namespaces = namespaces;
this.entitySets = entitySets;
this.singletons = singletons;
}
static loadFromXml(apiRoot, metadataXml) {
const parser = new DOMParser();
const metadataDoc = parser.parseFromString(metadataXml, "text/xml");
const namespaces = ApiMetadata.parseEntityTypes(metadataDoc);
const entitySets = {};
const singletons = {};
const container = metadataDoc.querySelector("Schema>EntityContainer");
const containerName = container && getRequiredAttributeValue(container, "Name");
if (container) {
const list = container.querySelectorAll("EntitySet,Singleton");
for (var i = 0; i < list.length; i++) {
const e = list.item(i);
const isSingleton = e.tagName.toUpperCase() === "SINGLETON";
let name = getRequiredAttributeValue(e, "Name");
let typeName = getRequiredAttributeValue(e, isSingleton ? "Type" : "EntityType");
const target = isSingleton ? singletons : entitySets;
target[name] = ApiMetadata.getEntitySetMetadata(typeName, namespaces);
}
}
const list3 = metadataDoc.querySelectorAll("Schema>Function,Schema>Action");
for (var i = 0; i < list3.length; i++) {
const e = list3.item(i);
const metadata = ApiMetadata.parseOperationMetadata(e, namespaces);
const namespaceName = getRequiredAttributeValue(e.parentElement, "Namespace");
if (!namespaces[namespaceName])
namespaces[namespaceName] = new Namespace(namespaceName);
namespaces[namespaceName].addOperations(metadata);
}
return new ApiMetadata(apiRoot, containerName, namespaces, entitySets, singletons);
}
static loadAsync(apiRoot, options) {
return __awaiter(this, void 0, void 0, function* () {
const uri = apiRoot + "/$metadata";
const opt = options || {};
const fetchApi = opt.fetch || fetch;
const credentials = opt.credentials;
const response = yield fetchApi(uri, { credentials });
return this.loadFromXml(apiRoot, yield response.text());
});
}
static parseEntityTypes(metadataDoc) {
let namespaces = {};
let entityTypes = [];
const list = metadataDoc.querySelectorAll("Schema>ComplexType,Schema>EntityType,Schema>EnumType");
for (var i = 0; i < list.length; i++) {
const e = list.item(i);
const getOrAddEdmEntityType = function (namespace, name) {
let namespaceMD = namespaces[namespace];
if (!namespaceMD)
namespaces[namespace] = namespaceMD = new Namespace(namespace);
let typeMetadata = namespaceMD.types[name];
if (!typeMetadata) {
typeMetadata = e.tagName.toLowerCase() == "complextype"
? new EdmComplexType(name, {})
: new EdmEntityType(name, {});
namespaceMD.addTypes(typeMetadata);
}
return typeMetadata;
};
let ns = getRequiredAttributeValue(e.parentElement, "Namespace");
let name = getRequiredAttributeValue(e, "Name");
if (!(ns in namespaces))
namespaces[ns] = new Namespace(ns);
if (e.tagName.toLowerCase() === "enumtype") {
const enumType = new EdmEnumType(name, ApiMetadata.parseEnumMembers(e));
namespaces[ns].addTypes(enumType);
}
else {
let typeMetadata = getOrAddEdmEntityType(ns, name);
typeMetadata.openType = getAttributeBoolValue(e, "OpenType");
const baseType = getAttributeValue(e, "BaseType");
if (baseType) {
const baseTypeNS = baseType.substring(0, baseType.lastIndexOf("."));
const baseTypeName = baseType.substr(baseTypeNS.length + 1);
let bt = getOrAddEdmEntityType(baseTypeNS, baseTypeName);
typeMetadata.baseType = bt;
}
entityTypes.push({ element: e, typeMetadata });
}
}
for (let e of entityTypes) {
Object.assign(e.typeMetadata, ApiMetadata.getEntityTypeProperties(e.element, namespaces));
e.typeMetadata.keys = this.parseEntityKeys(e.element);
}
return namespaces;
}
static parseEntityKeys(typeElement) {
var res = new Array();
var list = typeElement.querySelectorAll("Key>PropertyRef");
for (var i = 0; i < list.length; i++) {
res.push(getRequiredAttributeValue(list.item(i), "Name"));
}
return res;
}
static parseEnumMembers(element) {
const res = {};
var list = element.querySelectorAll("Member");
for (var i = 0; i < list.length; i++) {
const e = list.item(i);
const name = getRequiredAttributeValue(e, "Name");
const rawValue = getRequiredAttributeValue(e, "Value");
res[name] = (rawValue.match(/\d/)) ? parseInt(rawValue) : rawValue;
}
return res;
}
static getEntityTypeProperties(typeElement, namespaces) {
let properties = {};
let navProperties = {};
var list = typeElement.querySelectorAll("Property,NavigationProperty");
for (var i = 0; i < list.length; i++) {
const e = list.item(i);
const name = getRequiredAttributeValue(e, "Name");
let metadata = ApiMetadata.parseType(e, namespaces);
if (e.tagName.toLowerCase() == "property")
properties[name] = metadata;
else
navProperties[name] = EdmEntityTypeReference.fromTypeReference(metadata);
}
return { properties, navProperties };
}
getEntitySetMetadata(typeName) {
return ApiMetadata.getEntitySetMetadata(typeName, this.namespaces);
}
static getEntitySetMetadata(typeName, namespaces) {
const res = ApiMetadata.getEdmTypeMetadata(typeName, namespaces);
if (res instanceof EdmEntityType)
return res;
throw new Error("EntitySet item type must be entity");
}
getEdmTypeMetadata(typeName) {
return ApiMetadata.getEdmTypeMetadata(typeName, this.namespaces);
}
static getEdmTypeMetadata(typeName, namespaces) {
if (utils_1.startsWith(typeName, COLLECTION_TYPE_PREFIX))
typeName = typeName.substring(COLLECTION_TYPE_PREFIX.length, typeName.length - 1);
const namespace = typeName.substring(0, typeName.lastIndexOf("."));
const typeNameNoNs = typeName.substr(namespace.length + 1);
if (namespace == "Edm") {
let t = EdmTypes[typeNameNoNs];
if (!t)
throw new Error("Not registred Edm type: " + typeNameNoNs);
return t;
}
const nsMeta = namespaces[namespace];
if (!nsMeta)
throw new Error(`Namespace '${namespace}' not found`);
let typeElement = nsMeta.types[typeNameNoNs];
return typeElement;
}
static parseOperationMetadata(operationElement, namespaces) {
const isAction = operationElement.tagName.toLowerCase() === "action";
const name = getRequiredAttributeValue(operationElement, "Name");
const returnTypeElement = operationElement.querySelector("ReturnType");
const returnType = returnTypeElement
? ApiMetadata.parseType(returnTypeElement, namespaces)
: undefined;
const parameters = new Array();
let bindingTo;
const list = operationElement.querySelectorAll("Parameter");
for (var i = 0; i < list.length; i++) {
const e = list.item(i);
const type = ApiMetadata.parseType(e, namespaces);
const name = getRequiredAttributeValue(e, "Name");
if (getAttributeBoolValue(operationElement, "IsBound") && !bindingTo)
bindingTo = EdmEntityTypeReference.fromTypeReference(type);
else
parameters.push({ name, type });
}
return new OperationMetadata(name, isAction, parameters, returnType, bindingTo);
}
static parseType(element, namespaces) {
let typeName = getRequiredAttributeValue(element, "Type");
let collection = utils_1.startsWith(typeName, COLLECTION_TYPE_PREFIX);
if (collection)
typeName = typeName.substring(COLLECTION_TYPE_PREFIX.length, typeName.length - 1);
const typeMetadata = ApiMetadata.getEdmTypeMetadata(typeName, namespaces);
const res = new EdmTypeReference(typeMetadata, true, collection);
res.nullable = getAttributeBoolValue(element, "Nullable") != false;
return res;
}
}
exports.ApiMetadata = ApiMetadata;
function getRequiredAttributeValue(element, attrName) {
return getAttributeValue(element, attrName) || (() => {
throw new Error(`Metadata: Attribute '${attrName}' in element '${element.tagName}' not found `);
})();
}
function getAttributeBoolValue(element, attrName) {
var r = getAttributeValue(element, attrName);
if (r != undefined)
return r.toLowerCase() == "true";
}
function getAttributeValue(element, attrName) {
var attr = element.attributes.getNamedItem(attrName);
if (attr)
return attr.value;
}
});
//# sourceMappingURL=metadata.js.map