pailingual-odata
Version:
TypeScript client for OData v4 services
243 lines • 9.82 kB
JavaScript
(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