From 248988580bb45abe60a472e8bbd16ce4c8349a5c Mon Sep 17 00:00:00 2001 From: gigobyte Date: Sat, 9 May 2020 21:12:51 +0300 Subject: [PATCH] fix: ensureArray logic --- src/parsing.ts | 19 ++- src/sections/orders.ts | 104 ++++++++------- src/sections/sellers.ts | 40 +++--- test/integration/orders.test.ts | 2 +- test/integration/sellers.test.ts | 2 +- test/unit/__snapshots__/sellers.test.ts.snap | 128 +++++++++---------- test/unit/parsing.test.ts | 12 +- 7 files changed, 154 insertions(+), 153 deletions(-) diff --git a/src/parsing.ts b/src/parsing.ts index eded446b..abab5775 100644 --- a/src/parsing.ts +++ b/src/parsing.ts @@ -1,12 +1,25 @@ /** A collection of parsing codecs */ -import { array, Codec, string } from 'purify-ts/Codec' +import { array, Codec, record, string, unknown } from 'purify-ts/Codec' import { Left, Right } from 'purify-ts/Either' -export const ensureArray = (codec: Codec): Codec => { +export const ensureArray = (tag: string, codec: Codec): Codec => { const schema = codec.schema() return Codec.custom({ - decode: (x) => (x === '' ? Right([]) : array(codec).decode(Array.isArray(x) ? x : [x])), + decode: (x) => { + if (x === '') { + return Right([]) + } + + return record(string, unknown) + .decode(x) + .chain((object) => { + const possiblyElements = object[tag] + const elements = Array.isArray(possiblyElements) ? possiblyElements : [possiblyElements] + + return array(codec).decode(elements) + }) + }, encode: (x) => x, schema: () => ({ oneOf: [ diff --git a/src/sections/orders.ts b/src/sections/orders.ts index e546eeb5..8131bfd8 100644 --- a/src/sections/orders.ts +++ b/src/sections/orders.ts @@ -118,62 +118,60 @@ const ListOrders = Codec.interface({ NextToken: optional(nextToken('ListOrders')), LastUpdatedBefore: optional(date), CreatedBefore: optional(date), - Orders: Codec.interface({ - Order: ensureArray( - Codec.interface({ - AmazonOrderId: string, - SellerOrderId: optional(string), - PurchaseDate: date, - LastUpdateDate: date, - OrderStatus: orderStatus, - FulfillmentChannel: optional(fulfillmentChannel), - SalesChannel: optional(string), - ShipServiceLevel: optional(string), - ShippingAddress: optional(Address), - OrderTotal: optional(Money), - NumberOfItemsShipped: optional(number), - NumberOfItemsUnshipped: optional(number), - PaymentExecutionDetail: optional( - Codec.interface({ - PaymentExecutionDetailItem: ensureArray( - Codec.interface({ - Payment: Money, - PaymentMethod: string, - }), - ), - }), - ), - PaymentMethod: optional(string), - PaymentMethodDetails: optional( + Orders: ensureArray( + 'Order', + Codec.interface({ + AmazonOrderId: string, + SellerOrderId: optional(string), + PurchaseDate: date, + LastUpdateDate: date, + OrderStatus: orderStatus, + FulfillmentChannel: optional(fulfillmentChannel), + SalesChannel: optional(string), + ShipServiceLevel: optional(string), + ShippingAddress: optional(Address), + OrderTotal: optional(Money), + NumberOfItemsShipped: optional(number), + NumberOfItemsUnshipped: optional(number), + PaymentExecutionDetail: optional( + ensureArray( + 'PaymentExecutionDetailItem', Codec.interface({ - PaymentMethodDetail: optional(string), + Payment: Money, + PaymentMethod: string, }), ), - IsReplacementOrder: optional(boolean), - ReplacedOrderId: optional(string), - MarketplaceId: optional(string), - BuyerEmail: optional(string), - BuyerName: optional(string), - BuyerCounty: optional(string), - BuyerTaxInfo, - ShipmentServiceLevelCategory: optional(string), - EasyShipShipmentStatus: optional(string), - OrderType: optional(string), - EarliestShipDate: optional(date), - LatestShipDate: optional(date), - EarliestDeliveryDate: optional(date), - LatestDeliveryDate: optional(date), - IsBusinessOrder: optional(boolean), - IsSoldByAB: optional(boolean), - PurchaseOrderNumber: optional(string), - IsPrime: optional(boolean), - IsPremiumOrder: optional(boolean), - IsGlobalExpressEnabled: optional(boolean), - PromiseResponseDueDate: optional(date), - IsEstimatedShipDateSet: optional(boolean), - }), - ), - }), + ), + PaymentMethod: optional(string), + PaymentMethodDetails: optional( + Codec.interface({ + PaymentMethodDetail: optional(string), + }), + ), + IsReplacementOrder: optional(boolean), + ReplacedOrderId: optional(string), + MarketplaceId: optional(string), + BuyerEmail: optional(string), + BuyerName: optional(string), + BuyerCounty: optional(string), + BuyerTaxInfo, + ShipmentServiceLevelCategory: optional(string), + EasyShipShipmentStatus: optional(string), + OrderType: optional(string), + EarliestShipDate: optional(date), + LatestShipDate: optional(date), + EarliestDeliveryDate: optional(date), + LatestDeliveryDate: optional(date), + IsBusinessOrder: optional(boolean), + IsSoldByAB: optional(boolean), + PurchaseOrderNumber: optional(string), + IsPrime: optional(boolean), + IsPremiumOrder: optional(boolean), + IsGlobalExpressEnabled: optional(boolean), + PromiseResponseDueDate: optional(date), + IsEstimatedShipDateSet: optional(boolean), + }), + ), }) const ListOrdersResponse = Codec.interface({ diff --git a/src/sections/sellers.ts b/src/sections/sellers.ts index 35fb6669..120f4166 100644 --- a/src/sections/sellers.ts +++ b/src/sections/sellers.ts @@ -9,27 +9,25 @@ const SELLERS_API_VERSION = '2011-07-01' const MarketplaceParticipations = Codec.interface({ NextToken: optional(nextTokenCodec('ListMarketplaceParticipations')), - ListParticipations: Codec.interface({ - Participation: ensureArray( - Codec.interface({ - MarketplaceId: string, - SellerId: string, - HasSellerSuspendedListings: mwsBoolean, - }), - ), - }), - ListMarketplaces: Codec.interface({ - Marketplace: ensureArray( - Codec.interface({ - MarketplaceId: string, - Name: string, - DefaultCountryCode: string, - DefaultCurrencyCode: string, - DefaultLanguageCode: string, - DomainName: string, - }), - ), - }), + ListParticipations: ensureArray( + 'Participation', + Codec.interface({ + MarketplaceId: string, + SellerId: string, + HasSellerSuspendedListings: mwsBoolean, + }), + ), + ListMarketplaces: ensureArray( + 'Marketplace', + Codec.interface({ + MarketplaceId: string, + Name: string, + DefaultCountryCode: string, + DefaultCurrencyCode: string, + DefaultLanguageCode: string, + DomainName: string, + }), + ), }) const MarketplaceParticipationsResponse = Codec.interface({ diff --git a/test/integration/orders.test.ts b/test/integration/orders.test.ts index eb198b98..d407fd62 100644 --- a/test/integration/orders.test.ts +++ b/test/integration/orders.test.ts @@ -28,7 +28,7 @@ describe(`${Orders.name}`, () => { CreatedAfter: createdAfter.toISOString(), }) - expect(listOrders.Orders.Order).toStrictEqual([]) + expect(listOrders.Orders).toStrictEqual([]) }) itci('should be able to query service status', async () => { diff --git a/test/integration/sellers.test.ts b/test/integration/sellers.test.ts index b15a256c..2370c119 100644 --- a/test/integration/sellers.test.ts +++ b/test/integration/sellers.test.ts @@ -23,7 +23,7 @@ describe(`${Sellers.name}`, () => { const [marketplaceParticipations] = await sellers.listMarketplaceParticipations() - expect(marketplaceParticipations.ListMarketplaces.Marketplace).toContainEqual( + expect(marketplaceParticipations.ListMarketplaces).toContainEqual( expect.objectContaining({ MarketplaceId: amazonMarketplaces.CA.id }), ) }) diff --git a/test/unit/__snapshots__/sellers.test.ts.snap b/test/unit/__snapshots__/sellers.test.ts.snap index 1cf1dffb..cad1bffe 100644 --- a/test/unit/__snapshots__/sellers.test.ts.snap +++ b/test/unit/__snapshots__/sellers.test.ts.snap @@ -19,40 +19,36 @@ Array [ exports[`sellers listMarketplaceParticipations returns a parsed model when the response is valid 1`] = ` Array [ Object { - "ListMarketplaces": Object { - "Marketplace": Array [ - Object { - "DefaultCountryCode": "CA", - "DefaultCurrencyCode": "CAD", - "DefaultLanguageCode": "en_CA", - "DomainName": "www.amazon.ca", - "MarketplaceId": "A2EUQ1WTGCTBG2", - "Name": "Amazon.ca", - }, - Object { - "DefaultCountryCode": "US", - "DefaultCurrencyCode": "USD", - "DefaultLanguageCode": "en_US", - "DomainName": "iba.login.amazon.com", - "MarketplaceId": "A6W85IYQ5WB1C", - "Name": "IBA", - }, - ], - }, - "ListParticipations": Object { - "Participation": Array [ - Object { - "HasSellerSuspendedListings": false, - "MarketplaceId": "A2EUQ1WTGCTBG2", - "SellerId": "x", - }, - Object { - "HasSellerSuspendedListings": false, - "MarketplaceId": "A6W85IYQ5WB1C", - "SellerId": "x", - }, - ], - }, + "ListMarketplaces": Array [ + Object { + "DefaultCountryCode": "CA", + "DefaultCurrencyCode": "CAD", + "DefaultLanguageCode": "en_CA", + "DomainName": "www.amazon.ca", + "MarketplaceId": "A2EUQ1WTGCTBG2", + "Name": "Amazon.ca", + }, + Object { + "DefaultCountryCode": "US", + "DefaultCurrencyCode": "USD", + "DefaultLanguageCode": "en_US", + "DomainName": "iba.login.amazon.com", + "MarketplaceId": "A6W85IYQ5WB1C", + "Name": "IBA", + }, + ], + "ListParticipations": Array [ + Object { + "HasSellerSuspendedListings": false, + "MarketplaceId": "A2EUQ1WTGCTBG2", + "SellerId": "x", + }, + Object { + "HasSellerSuspendedListings": false, + "MarketplaceId": "A6W85IYQ5WB1C", + "SellerId": "x", + }, + ], "NextToken": undefined, }, Object { @@ -68,40 +64,36 @@ Array [ exports[`sellers listMarketplaceParticipationsByNextToken returns a parsed model when the response is valid 1`] = ` Array [ Object { - "ListMarketplaces": Object { - "Marketplace": Array [ - Object { - "DefaultCountryCode": "CA", - "DefaultCurrencyCode": "CAD", - "DefaultLanguageCode": "en_CA", - "DomainName": "www.amazon.ca", - "MarketplaceId": "A2EUQ1WTGCTBG2", - "Name": "Amazon.ca", - }, - Object { - "DefaultCountryCode": "US", - "DefaultCurrencyCode": "USD", - "DefaultLanguageCode": "en_US", - "DomainName": "iba.login.amazon.com", - "MarketplaceId": "A6W85IYQ5WB1C", - "Name": "IBA", - }, - ], - }, - "ListParticipations": Object { - "Participation": Array [ - Object { - "HasSellerSuspendedListings": false, - "MarketplaceId": "A2EUQ1WTGCTBG2", - "SellerId": "x", - }, - Object { - "HasSellerSuspendedListings": false, - "MarketplaceId": "A6W85IYQ5WB1C", - "SellerId": "x", - }, - ], - }, + "ListMarketplaces": Array [ + Object { + "DefaultCountryCode": "CA", + "DefaultCurrencyCode": "CAD", + "DefaultLanguageCode": "en_CA", + "DomainName": "www.amazon.ca", + "MarketplaceId": "A2EUQ1WTGCTBG2", + "Name": "Amazon.ca", + }, + Object { + "DefaultCountryCode": "US", + "DefaultCurrencyCode": "USD", + "DefaultLanguageCode": "en_US", + "DomainName": "iba.login.amazon.com", + "MarketplaceId": "A6W85IYQ5WB1C", + "Name": "IBA", + }, + ], + "ListParticipations": Array [ + Object { + "HasSellerSuspendedListings": false, + "MarketplaceId": "A2EUQ1WTGCTBG2", + "SellerId": "x", + }, + Object { + "HasSellerSuspendedListings": false, + "MarketplaceId": "A6W85IYQ5WB1C", + "SellerId": "x", + }, + ], "NextToken": undefined, }, Object { diff --git a/test/unit/parsing.test.ts b/test/unit/parsing.test.ts index 48022cfa..c8083270 100644 --- a/test/unit/parsing.test.ts +++ b/test/unit/parsing.test.ts @@ -13,28 +13,28 @@ import { const ajv = new Ajv() describe('ensureArray', () => { - it('acts like an idenity if the value to be decoded is already an array', () => { + it('just extracts the elements if the value to be decoded is already an array', () => { expect.assertions(1) - expect(ensureArray(number).decode([1])).toStrictEqual(Right([1])) + expect(ensureArray('A', number).decode({ A: [1] })).toStrictEqual(Right([1])) }) - it("wraps the value to be decoded in an array if it's not already", () => { + it("extracts the elements and wraps the value to be decoded in an array if it's not already", () => { expect.assertions(1) - expect(ensureArray(number).decode(1)).toStrictEqual(Right([1])) + expect(ensureArray('A', number).decode({ A: 1 })).toStrictEqual(Right([1])) }) it('handles empty arrays which get deserialized as empty string', () => { expect.assertions(1) - expect(ensureArray(number).decode('')).toStrictEqual(Right([])) + expect(ensureArray('A', number).decode('')).toStrictEqual(Right([])) }) it('has an encode that does nothing', () => { expect.assertions(1) - expect(ensureArray(number).encode([1])).toStrictEqual([1]) + expect(ensureArray('A', number).encode([1])).toStrictEqual([1]) }) })