From 5bd7b67e4d6796da656ca1cc97ed27a141c89e25 Mon Sep 17 00:00:00 2001 From: Rikki Gibson Date: Tue, 31 Jul 2018 13:08:24 -0700 Subject: [PATCH] Mapper interfaces (#180) * Update mapper type definitions * Fix tests * Fix CompositeType className and modelProperties * Bump to v0.17.0 --- lib/msRest.ts | 7 +- lib/operationParameter.ts | 2 +- lib/serializer.ts | 97 ++++++++++++++++---------- lib/serviceClient.ts | 4 +- package.json | 2 +- test/shared/operationParameterTests.ts | 8 +-- test/shared/serializationTests.ts | 51 +++++++------- test/shared/serviceClientTests.ts | 6 +- 8 files changed, 101 insertions(+), 76 deletions(-) diff --git a/lib/msRest.ts b/lib/msRest.ts index 8d6901af..b3173e4a 100644 --- a/lib/msRest.ts +++ b/lib/msRest.ts @@ -24,9 +24,10 @@ export { signingPolicy } from "./policies/signingPolicy"; export { msRestUserAgentPolicy } from "./policies/msRestUserAgentPolicy"; export { deserializationPolicy } from "./policies/deserializationPolicy"; export { - BaseMapperType, CompositeMapper, DictionaryMapper, EnumMapper, Mapper, - MapperConstraints, MapperType, PolymorphicDiscriminator, - SequenceMapper, Serializer, UrlParameterValue, serializeObject + MapperType, SimpleMapperType, CompositeMapperType, DictionaryMapperType, SequenceMapperType, EnumMapperType, + Mapper, BaseMapper, CompositeMapper, SequenceMapper, DictionaryMapper, EnumMapper, + MapperConstraints, PolymorphicDiscriminator, + Serializer, UrlParameterValue, serializeObject } from "./serializer"; export { stripRequest, stripResponse, delay, diff --git a/lib/operationParameter.ts b/lib/operationParameter.ts index f930f885..f99c69ac 100644 --- a/lib/operationParameter.ts +++ b/lib/operationParameter.ts @@ -65,7 +65,7 @@ export function getPathStringFromParameterPath(parameterPath: ParameterPath, map } else if (Array.isArray(parameterPath)) { result = parameterPath.join("."); } else { - result = mapper.serializedName; + result = mapper.serializedName!; } return result; } \ No newline at end of file diff --git a/lib/serializer.ts b/lib/serializer.ts index 043594c4..c5c5dbcc 100644 --- a/lib/serializer.ts +++ b/lib/serializer.ts @@ -5,7 +5,7 @@ import * as base64 from "./util/base64"; import * as utils from "./util/utils"; export class Serializer { - constructor(public readonly modelMappers?: { [key: string]: any }, public readonly isXML?: boolean) { } + constructor(public readonly modelMappers: { [key: string]: any } = {}, public readonly isXML?: boolean) { } validateConstraints(mapper: Mapper, value: any, objectName: string): void { const failValidation = (constraintName: keyof MapperConstraints, constraintValue: any) => { @@ -76,7 +76,7 @@ export class Serializer { let payload: any = {}; const mapperType = mapper.type.name as string; if (!objectName) { - objectName = mapper.serializedName; + objectName = mapper.serializedName!; } if (mapperType.match(/^Sequence$/ig) !== null) { payload = []; @@ -162,7 +162,7 @@ export class Serializer { let payload: any; const mapperType = mapper.type.name; if (!objectName) { - objectName = mapper.serializedName; + objectName = mapper.serializedName!; } if (mapperType.match(/^Number$/ig) !== null) { @@ -460,7 +460,7 @@ function serializeCompositeType(serializer: Serializer, mapper: CompositeMapper, propName = propertyMapper.xmlElementName || propertyMapper.xmlName; } } else { - const paths = splitSerializeName(propertyMapper.serializedName); + const paths = splitSerializeName(propertyMapper.serializedName!); propName = paths.pop(); for (const pathName of paths) { @@ -509,14 +509,6 @@ function deserializeCompositeType(serializer: Serializer, mapper: CompositeMappe mapper = getPolymorphicMapper(serializer, mapper, responseBody, objectName, "deserialize"); } - let instance: { [key: string]: any } = {}; - let modelMapper: Mapper = { - required: false, - serializedName: "serializedName", - type: { - name: "Composite" - } - }; responseBody = responseBody || {}; let modelProps = mapper.type.modelProperties; if (!modelProps) { @@ -525,17 +517,18 @@ function deserializeCompositeType(serializer: Serializer, mapper: CompositeMappe } // get the mapper if modelProperties of the CompositeType is not present and // then get the modelProperties from it. - modelMapper = (serializer.modelMappers as { [key: string]: any })[mapper.type.className]; + const modelMapper: CompositeMapper = serializer.modelMappers[mapper.type.className]; if (!modelMapper) { throw new Error(`mapper() cannot be null or undefined for model "${mapper.type.className}"`); } - modelProps = (modelMapper as CompositeMapper).type.modelProperties; + modelProps = modelMapper.type.modelProperties; if (!modelProps) { throw new Error(`modelProperties cannot be null or undefined in the ` + `mapper "${JSON.stringify(modelMapper)}" of type "${mapper.type.className}" for responseBody "${objectName}".`); } } + let instance: { [key: string]: any } = {}; for (const key of Object.keys(modelProps)) { const propertyMapper = modelProps[key]; const { serializedName, xmlName, xmlElementName } = propertyMapper; @@ -570,7 +563,7 @@ function deserializeCompositeType(serializer: Serializer, mapper: CompositeMappe instance[key] = serializer.deserialize(propertyMapper, unwrappedProperty, propertyObjectName); } } else { - const paths = splitSerializeName(modelProps[key].serializedName); + const paths = splitSerializeName(modelProps[key].serializedName!); // deserialize the property if it is present in the provided responseBody instance let propertyInstance; let res = responseBody; @@ -738,8 +731,51 @@ export interface MapperConstraints { MultipleOf?: number; } -export interface BaseMapperType { - name: string; +export type MapperType = SimpleMapperType | CompositeMapperType | SequenceMapperType | DictionaryMapperType | EnumMapperType; + +export interface SimpleMapperType { + name: "Base64Url" + | "Boolean" + | "ByteArray" + | "Date" + | "DateTime" + | "DateTimeRfc1123" + | "Object" + | "Stream" + | "String" + | "TimeSpan" + | "UnixTime" + | "Uuid" + | "Number" + | "any"; +} + +export interface CompositeMapperType { + name: "Composite"; + + // Only one of the two below properties should be present. + // Use className to reference another type definition, + // and use modelProperties when the reference to the other type has been resolved. + className?: string; + modelProperties?: { [propertyName: string]: Mapper }; + + uberParent?: string; + polymorphicDiscriminator?: string | PolymorphicDiscriminator; +} + +export interface SequenceMapperType { + name: "Sequence"; + element: Mapper; +} + +export interface DictionaryMapperType { + name: "Dictionary"; + value: Mapper; +} + +export interface EnumMapperType { + name: "Enum"; + allowedValues: any[]; } export interface BaseMapper { @@ -751,8 +787,8 @@ export interface BaseMapper { isConstant?: boolean; required?: boolean; nullable?: boolean; - serializedName: string; - type: BaseMapperType; + serializedName?: string; + type: MapperType; defaultValue?: any; constraints?: MapperConstraints; } @@ -766,35 +802,20 @@ export interface PolymorphicDiscriminator { } export interface CompositeMapper extends BaseMapper { - type: { - name: "Composite"; - className: string; - modelProperties: { [propertyName: string]: Mapper }; - uberParent?: string; - polymorphicDiscriminator?: string | PolymorphicDiscriminator; - }; + type: CompositeMapperType; } export interface SequenceMapper extends BaseMapper { - type: { - name: "Sequence"; - element: Mapper; - }; + type: SequenceMapperType; } export interface DictionaryMapper extends BaseMapper { - type: { - name: "Dictionary"; - value: Mapper; - }; + type: DictionaryMapperType; headerCollectionPrefix?: string; } export interface EnumMapper extends BaseMapper { - type: { - name: "Enum"; - allowedValues: Array; - }; + type: EnumMapperType; } export interface UrlParameterValue { diff --git a/lib/serviceClient.ts b/lib/serviceClient.ts index dc41b0ba..71ab5cfd 100644 --- a/lib/serviceClient.ts +++ b/lib/serviceClient.ts @@ -326,7 +326,7 @@ export function serializeRequestBody(serviceClient: ServiceClient, httpRequest: const isStream = typeName === MapperType.Stream; if (operationSpec.isXML) { if (typeName === MapperType.Sequence) { - httpRequest.body = utils.stringifyXML(utils.prepareXMLRootList(httpRequest.body, xmlElementName || xmlName || serializedName), { rootName: xmlName || serializedName }); + httpRequest.body = utils.stringifyXML(utils.prepareXMLRootList(httpRequest.body, xmlElementName || xmlName || serializedName!), { rootName: xmlName || serializedName }); } else if (!isStream) { httpRequest.body = utils.stringifyXML(httpRequest.body, { rootName: xmlName || serializedName }); @@ -430,7 +430,7 @@ export function getOperationArgumentValueFromParameterPath(serviceClient: Servic } } else { for (const propertyName in parameterPath) { - const propertyMapper: Mapper = (parameterMapper as CompositeMapper).type.modelProperties[propertyName]; + const propertyMapper: Mapper = (parameterMapper as CompositeMapper).type.modelProperties![propertyName]; const propertyPath: ParameterPath = parameterPath[propertyName]; const propertyValue: any = getOperationArgumentValueFromParameterPath(serviceClient, operationArguments, propertyPath, propertyMapper, serializer); // Serialize just for validation purposes. diff --git a/package.json b/package.json index 488ccabe..fb32283f 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "email": "azsdkteam@microsoft.com", "url": "https://github.com/Azure/ms-rest-js" }, - "version": "0.16.0", + "version": "0.17.0", "description": "Isomorphic client Runtime for Typescript/node.js/browser javascript client libraries generated using AutoRest", "tags": [ "isomorphic", diff --git a/test/shared/operationParameterTests.ts b/test/shared/operationParameterTests.ts index 4b3a602b..74e5dc32 100644 --- a/test/shared/operationParameterTests.ts +++ b/test/shared/operationParameterTests.ts @@ -20,7 +20,7 @@ describe("getParameterPathString()", () => { mapper: { serializedName: "value", type: { - name: "number" + name: "Number" } } }; @@ -33,7 +33,7 @@ describe("getParameterPathString()", () => { mapper: { serializedName: "value", type: { - name: "number" + name: "Number" } } }; @@ -46,7 +46,7 @@ describe("getParameterPathString()", () => { mapper: { serializedName: "value", type: { - name: "number" + name: "Number" } } }; @@ -62,7 +62,7 @@ describe("getParameterPathString()", () => { mapper: { serializedName: "value", type: { - name: "number" + name: "Number" } } }; diff --git a/test/shared/serializationTests.ts b/test/shared/serializationTests.ts index 3800e687..fd938dea 100644 --- a/test/shared/serializationTests.ts +++ b/test/shared/serializationTests.ts @@ -279,13 +279,13 @@ describe("msrest", function () { }); it('should correctly serialize an array of array of object types', function (done) { - const mapper = { + const mapper: msRest.SequenceMapper = { serializedName: 'arrayObj', required: true, type: { name: 'Sequence', element: { - type : { + type: { name: 'Sequence', element: { type: { @@ -303,13 +303,13 @@ describe("msrest", function () { }); it('should fail while serializing an array of array of "object" types when a null value is provided', function (done) { - const mapper = { + const mapper: msRest.Mapper = { serializedName: 'arrayObj', required: true, type: { name: 'Sequence', element: { - type : { + type: { name: 'Sequence', element: { required: true, @@ -590,8 +590,8 @@ describe("msrest", function () { }); - it("should allow null when required: true and nullable: true", function() { - const mapper = { + it("should allow null when required: true and nullable: true", function () { + const mapper: msRest.Mapper = { required: false, serializedName: 'testmodel', type: { @@ -614,8 +614,8 @@ describe("msrest", function () { should.exist(result); }); - it("should not allow undefined when required: true and nullable: true", function() { - const mapper = { + it("should not allow undefined when required: true and nullable: true", function () { + const mapper: msRest.Mapper = { required: false, serializedName: 'testmodel', type: { @@ -637,8 +637,8 @@ describe("msrest", function () { (function () { Serializer.serialize(mapper, { length: undefined }, "testobj"); }).should.throw("testobj.length cannot be undefined."); }); - it("should not allow null when required: true and nullable: false", function() { - const mapper = { + it("should not allow null when required: true and nullable: false", function () { + const mapper: msRest.Mapper = { required: false, serializedName: 'testmodel', type: { @@ -660,8 +660,8 @@ describe("msrest", function () { (function () { Serializer.serialize(mapper, { length: null }, "testobj"); }).should.throw("testobj.length cannot be null or undefined."); }); - it("should not allow undefined when required: true and nullable: false", function() { - const mapper = { + it("should not allow undefined when required: true and nullable: false", function () { + const mapper: msRest.Mapper = { required: false, serializedName: 'testmodel', type: { @@ -684,7 +684,7 @@ describe("msrest", function () { }); it("should not allow null when required: true and nullable is undefined", function() { - const mapper = { + const mapper: msRest.Mapper ={ serializedName: "foo", required: true, type: { @@ -695,7 +695,7 @@ describe("msrest", function () { }); it("should not allow undefined when required: true and nullable is undefined", function() { - const mapper = { + const mapper: msRest.Mapper ={ serializedName: "foo", required: true, type: { @@ -706,7 +706,7 @@ describe("msrest", function () { }); it("should allow null when required: false and nullable: true", function() { - const mapper = { + const mapper: msRest.Mapper ={ serializedName: "foo", required: false, nullable: true, @@ -719,7 +719,7 @@ describe("msrest", function () { }); it("should not allow null when required: false and nullable: false", function() { - const mapper = { + const mapper: msRest.Mapper ={ serializedName: "foo", required: false, nullable: false, @@ -731,7 +731,7 @@ describe("msrest", function () { }); it("should allow null when required: false and nullable is undefined", function() { - const mapper = { + const mapper: msRest.Mapper ={ serializedName: "foo", required: false, type: { @@ -743,7 +743,7 @@ describe("msrest", function () { }); it("should allow undefined when required: false and nullable: true", function() { - const mapper = { + const mapper: msRest.Mapper ={ serializedName: "foo", required: false, nullable: true, @@ -756,7 +756,7 @@ describe("msrest", function () { }); it("should allow undefined when required: false and nullable: false", function() { - const mapper = { + const mapper: msRest.Mapper ={ serializedName: "fooType", type: { name: "Composite", @@ -778,7 +778,7 @@ describe("msrest", function () { }); it("should allow undefined when required: false and nullable is undefined", function() { - const mapper = { + const mapper: msRest.Mapper ={ serializedName: "foo", required: false, type: { @@ -1049,15 +1049,17 @@ describe("msrest", function () { }); it('should correctly deserialize an array of array of object types', function (done) { - const mapper = { + const mapper: msRest.Mapper ={ serializedName: 'arrayObj', required: true, type: { name: 'Sequence', element: { - type : { + serializedName: "ObjectElementType", + type: { name: 'Sequence', element: { + serializedName: "ObjectElementType", type: { name: 'Object' } @@ -1067,7 +1069,7 @@ describe("msrest", function () { } }; var array = [[1], ["2"], [1, "2", {}, true, []]]; - var deserializedArray = Serializer.deserialize(mapper, array, mapper.serializedName); + var deserializedArray = Serializer.deserialize(mapper, array, mapper.serializedName!); assert.deepEqual(array, deserializedArray); done(); }); @@ -1114,7 +1116,7 @@ describe("msrest", function () { }); it("should deserialize headerCollectionPrefix", function() { - const mapper = { + const mapper: msRest.CompositeMapper = { serializedName: "something", type: { name: "Composite", @@ -1125,6 +1127,7 @@ describe("msrest", function () { type: { name: "Dictionary", value: { + serializedName: "element", type: { name: "String" } diff --git a/test/shared/serviceClientTests.ts b/test/shared/serviceClientTests.ts index 76b7e7c7..49089691 100644 --- a/test/shared/serviceClientTests.ts +++ b/test/shared/serviceClientTests.ts @@ -2,7 +2,7 @@ import * as assert from "assert"; import { HttpClient } from "../../lib/httpClient"; import { HttpOperationResponse } from "../../lib/httpOperationResponse"; import { QueryCollectionFormat } from "../../lib/queryCollectionFormat"; -import { DictionaryMapper, MapperType, SequenceMapper, Serializer, Mapper } from "../../lib/serializer"; +import { DictionaryMapper, MapperType, Serializer, Mapper } from "../../lib/serializer"; import { serializeRequestBody, ServiceClient, getOperationArgumentValueFromParameterPath } from "../../lib/serviceClient"; import { WebResource } from "../../lib/webResource"; import { OperationArguments } from "../../lib/msRest"; @@ -104,12 +104,12 @@ describe("ServiceClient", function () { name: "Sequence", element: { type: { - name: "number", + name: "Number", }, serializedName: "q", }, }, - } as SequenceMapper, + }, }, ], responses: {