Skip to content
This repository has been archived by the owner on Feb 6, 2024. It is now read-only.

Commit

Permalink
fix: ensureArray logic
Browse files Browse the repository at this point in the history
  • Loading branch information
gigobyte committed May 9, 2020
1 parent c0ea38d commit 2489885
Show file tree
Hide file tree
Showing 7 changed files with 154 additions and 153 deletions.
19 changes: 16 additions & 3 deletions src/parsing.ts
Original file line number Diff line number Diff line change
@@ -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 = <T>(codec: Codec<T>): Codec<T[]> => {
export const ensureArray = <T>(tag: string, codec: Codec<T>): Codec<T[]> => {
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: [
Expand Down
104 changes: 51 additions & 53 deletions src/sections/orders.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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({
Expand Down
40 changes: 19 additions & 21 deletions src/sections/sellers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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({
Expand Down
2 changes: 1 addition & 1 deletion test/integration/orders.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 () => {
Expand Down
2 changes: 1 addition & 1 deletion test/integration/sellers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 }),
)
})
Expand Down
128 changes: 60 additions & 68 deletions test/unit/__snapshots__/sellers.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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 {
Expand Down
12 changes: 6 additions & 6 deletions test/unit/parsing.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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])
})
})

Expand Down

0 comments on commit 2489885

Please sign in to comment.