UNPKG

pailingual-odata

Version:

TypeScript client for OData v4 services

243 lines 9.82 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", "./utils"], factory); } })(function (require, exports) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const metadata_1 = require("./metadata"); const utils_1 = require("./utils"); const guidRE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i; var converters = { "Edm.String": { toEdm: (v, forUri) => forUri ? ("'" + v.toString().replace("'", "''").replace("/", "%2F") + "'") : v }, "Edm.Guid": { toEdm: (v) => { if (v.match(guidRE)) return v; throw new Error(`Value '${v}' not parsed as Guid`); } }, "Edm.DateTimeOffset": { toEdm: (v) => v.toISOString(), fromEdm: (v) => new Date(v) }, "Edm.Boolean": { toEdm: (v) => v ? "true" : "false" } }; var formatters = {}; function addFormatter(formatter) { if (!formatter || !formatter.contentType || !formatter.serialize || !formatter.deserialize) throw new Error("All formatter properties is required"); formatters[formatter.contentType] = formatter; } exports.addFormatter = addFormatter; function getFormatter(contentType) { const f = formatters[contentType]; if (!f) throw new Error(`Not supported format: ${contentType}`); return f; } exports.getFormatter = getFormatter; addFormatter({ contentType: "application/json", serialize: jsonSerialize, deserialize: jsonDeserialize }); function enumMemberByValue(type, value) { for (let member in type.members) if (type.members[member] === value) return member; } function jsonSerialize(payload, metadata, options = {}) { let metadataMap = new MapObjToEntityType(); metadataMap.set(payload, metadata); let otMetadata = new metadata_1.EdmEntityType("$$~~openType~~$$", {}); otMetadata.openType = true; return JSON.stringify(payload, function (k, v) { if (!k || Array.isArray(this)) return v; let currentMetadata = metadataMap.get(this); if (currentMetadata != null) { const propMD = currentMetadata.properties[k] || currentMetadata.navProperties[k]; const valueType = propMD && propMD.type || ((currentMetadata.openType) ? otMetadata : undefined); if (!valueType) { throw new Error(`Property '${k}' not found in metadata`); } if (valueType instanceof metadata_1.EdmEntityType) { if (Array.isArray(v)) for (let item of v) metadataMap.set(item, valueType); else if (v != null) metadataMap.set(v, valueType); return v; } else { return convertToEdmValue(this[k], propMD.type, false) || v; } } throw new Error("Metadata for object not found"); }); } function serializeValue(value, type, forUri, opt) { if (value == null) return forUri ? "null" : null; return convertToEdmValue(value, type, forUri, opt) || value.toString(); } exports.serializeValue = serializeValue; function convertToEdmValue(value, type, forUri, opt = {}) { if (value == null) return null; if (type instanceof metadata_1.EdmEnumType) { let member = enumMemberByValue(type, value); if (member) { if (forUri) { member = "'" + member + "'"; if (!opt.enumPrefixFree) member = type.getFullName() + member; } return member; } throw new Error(`Value '${value}' not found in enum '${type.name} '`); } else { const converter = converters[type]; if (converter && converter.toEdm) return converter.toEdm(value, forUri, opt); return null; } } function convertFromEdmValue(value, type, options) { const converter = converters[type]; if (converter && converter.fromEdm) return converter.fromEdm(value, options); return null; } const ODATA_CONTEXT = "@odata.context"; const ODATA_COUNT = "@odata.count"; const ODATA_TYPE = "@odata.type"; function jsonDeserialize(response, apiMetadata, options) { const rawData = JSON.parse(response); let context = rawData[ODATA_CONTEXT]; if (context) { context = context.split("#")[1]; let count = rawData[ODATA_COUNT]; let isEntity = utils_1.endsWith(context, "$entity"); context = context.replace(/\/\$entity$/, ""); let type = getSourceType(context, apiMetadata); if (!isEntity && Array.isArray(rawData.value)) { const value = rawData.value.map((v) => convertObj(v, type, apiMetadata, options)); if (count != null) return { count, value }; return value; } else return convertObj(rawData, type, apiMetadata, options); } } function convertObj(obj, type, apiMetadata, options) { if (obj != null) { if (Array.isArray(obj)) return obj.map(v => convertObj(v, type, apiMetadata, options)); if (obj[ODATA_TYPE]) { const typeName = obj[ODATA_TYPE].substr(1); type = apiMetadata.getEdmTypeMetadata(typeName); if (type == null) throw new Error(`Metadata for type '${typeName}' not found.`); } if (typeof type == "string") { if (typeof obj == "object") obj = obj.value; return convertFromEdmValue(obj, type, options) || obj; } else { let res; if (type instanceof metadata_1.EdmEnumType) { const res = type.members[obj]; if (!res) throw new Error(`Member '${obj}' not found in enum '${type.name}'`); return res; } else { const entityType = type; res = {}; const edmProps = getEdmProperties(entityType); for (let propName in obj) { const edmPropertyType = edmProps[propName]; if (edmPropertyType) res[propName] = convertObj(obj[propName], edmPropertyType, apiMetadata, options); else if (!utils_1.startsWith(propName, "@") && entityType.openType == true) res[propName] = obj[propName]; } } return res; } } return null; } function getEdmProperties(type) { const res = type.baseType ? getEdmProperties(type.baseType) : {}; for (let prop in type.properties) { res[prop] = type.properties[prop].type; } for (let prop in type.navProperties) { res[prop] = type.navProperties[prop].type; } return res; } function getSourceType(source, apiMetadata) { if (utils_1.startsWith(source, "Collection")) source = source.substring("Collection".length + 1, source.length - 1); const pos = source.indexOf("("); if (pos > -1) source = source.substring(0, pos); const parts = source.split("/"); source = parts[parts.length - 1]; const es = apiMetadata.entitySets[source]; if (!es) { const dotPos = source.lastIndexOf('.'); if (dotPos > -1) { const ns = source.substr(0, dotPos); const type = source.substr(dotPos + 1); if (ns == "Edm") //Primitive type return source; const nsObj = apiMetadata.namespaces[ns]; if (nsObj && nsObj.types[type]) return nsObj.types[type]; } } return es; } class MapObjToEntityType { constructor() { this.__keys = []; this.__values = []; } get(key) { if (key) { const index = this.__keys.indexOf(key); if (index > -1) return this.__values[index]; } } set(key, entityType) { if (key == null) throw new Error("Key must be set"); let index = this.__keys.indexOf(key); if (index == -1) index = this.__keys.push(key) - 1; this.__values[index] = entityType; } } }); //# sourceMappingURL=serialization.js.map