UNPKG

@sap/odata-v4

Version:

OData V4.0 server library

176 lines (157 loc) 7.76 kB
'use strict'; const stream = require('stream'); const BufferedWriter = require('../utils/BufferedWriter'); const ResourceJsonDeserializer = require('./ResourceJsonDeserializer'); const ServiceResolutions = require('../core/ServiceResolutions'); const BatchContext = require('../batch/BatchContext'); const BatchRequestListBuilder = require('./BatchRequestListBuilder'); const ValueTextDeserializer = require('./ValueTextDeserializer'); const RepresentationKinds = require('../format/RepresentationKind').Kinds; const JsonContentTypeInfo = require('../format/JsonContentTypeInfo'); const EdmPrimitiveTypeKind = require('../edm/EdmPrimitiveTypeKind'); const DeserializationError = require('../errors/DeserializationError'); /** * The DeserializerFactory is responsible for creating parsing facade functions * for a specific payload type regarding to the corresponding request * representation kind like ENTITY and the corresponding request mime type. */ class DeserializerFactory { /** * Creates and returns the deserialization facade function for application/json requests. * This function is called on deserialization of the incoming payload. * * @param {Edm} edm the current EDM instance * @param {RepresentationKind.Kinds} representationKind the representation kind * @returns {Function} The deserialization facade function */ static createJsonDeserializer(edm, representationKind) { const getPropertyFunction = uriInfo => uriInfo.getLastSegment().getProperty(); function getCreateDeserializerFunction(name) { return (contract) => { const jsonContentTypeInfo = new JsonContentTypeInfo(contract.getContentTypeInfo()); let expand = []; const deserializer = new ResourceJsonDeserializer(edm, jsonContentTypeInfo); return (edmObject, value) => { return { body: deserializer[name](edmObject, value, expand), deserializer, expand }; }; }; } switch (representationKind) { case RepresentationKinds.ENTITY: return DeserializerFactory._createDeserializer(uriInfo => uriInfo.getFinalEdmType(), getCreateDeserializerFunction('deserializeEntity')); case RepresentationKinds.PRIMITIVE: return DeserializerFactory._createDeserializer(getPropertyFunction, getCreateDeserializerFunction('deserializePrimitiveProperty')); case RepresentationKinds.PRIMITIVE_COLLECTION: return DeserializerFactory._createDeserializer(getPropertyFunction, getCreateDeserializerFunction('deserializePrimitivePropertyCollection')); case RepresentationKinds.COMPLEX: return DeserializerFactory._createDeserializer(getPropertyFunction, getCreateDeserializerFunction('deserializeComplexProperty')); case RepresentationKinds.COMPLEX_COLLECTION: return DeserializerFactory._createDeserializer(getPropertyFunction, getCreateDeserializerFunction('deserializeComplexPropertyCollection')); case RepresentationKinds.ACTION_PARAMETERS: return DeserializerFactory._createDeserializer(uriInfo => uriInfo.getLastSegment().getAction(), getCreateDeserializerFunction('deserializeActionParameters')); case RepresentationKinds.REFERENCE: return DeserializerFactory._createDeserializer(uriInfo => uriInfo.getFinalEdmType(), getCreateDeserializerFunction('deserializeReference')); default: return null; } } /** * Create and return the deserialization function for text/plain requests * containing a single primitive value. * This function is called on deserialization of the incoming payload. * * @returns {Function} the deserialization function */ static createTextValueDeserializer() { return DeserializerFactory._createDeserializer( uriInfo => uriInfo.getLastSegment(-1).getProperty(), () => { const deserializer = new ValueTextDeserializer(); return (edmProperty, value) => { return { body: deserializer.convertPrimitiveValue(edmProperty, value.toString()), deserializer }; }; }); } /** * Create and return the deserialization function for binary requests. * This function is called on deserialization of the incoming payload. * * @returns {Function} the deserialization function */ static createBinaryDeserializer() { return (request, next) => { if (request.getUriInfo() && request.getUriInfo().getFinalEdmType() === EdmPrimitiveTypeKind.Stream) { next(null, request.getIncomingRequest().on('error', next).pipe(new stream.PassThrough())); } else { request.getIncomingRequest() .on('error', next) .pipe(new BufferedWriter()) .on('error', next) .on('result', rawBody => next(null, rawBody)); } }; } /** * Create and return the deserialization function for binary requests. * This function is called on deserialization of the incoming payload. * * @returns {Function} the deserialization function */ static createMultipartMixedDeserializer() { return (request, next) => { const batchRequestListBuilder = new BatchRequestListBuilder({ resolutionStrategy: ServiceResolutions.viaBasePath() }); batchRequestListBuilder.build(request, (err, list) => err ? next(err) : next(null, { boundary: batchRequestListBuilder.getBatchBoundary(), requests: list, semantic: BatchContext.SEMANTIC.MULTIPART }) ); }; } /** * Create and return a deserialization function. * @param {Function} edmFunction function to get from URI info the EDM object for the parse function * @param {Function} createDeserializerFunction function to create the deserialize function * (with parameters EDM object and input) * @returns {Function} the deserialization function */ static _createDeserializer(edmFunction, createDeserializerFunction) { return (request, next) => { request.getIncomingRequest() .on('error', next) .pipe(new BufferedWriter()) .on('error', next) .on('result', rawBody => { try { const edmObject = edmFunction(request.getUriInfo()); const deserializeFunction = createDeserializerFunction(request.getContract()); const result = deserializeFunction(edmObject, rawBody); if (result.expand && result.expand.length > 0) { request.setDeepInsertExpand(result.expand); } next(null, result.body); } catch (error) { next(new DeserializationError('Error while deserializing payload', error), rawBody); } }); }; } } module.exports = DeserializerFactory;