Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(api): improve attachments performance #1317

Merged
merged 2 commits into from
May 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions packages/api/mocks/ValidateCartMutation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ export const checkoutOrderFormItemsValidFetch = {
init: {
method: 'PATCH',
headers: { 'content-type': 'application/json' },
body: `{"orderItems":[{"quantity":1,"seller":"1","id":"18643698"},{"quantity":1,"seller":"1","id":"97907082"},{"quantity":1,"seller":"1","id":"64953394"},{"quantity":1,"seller":"1","id":"85095548"},{"quantity":1,"seller":"1","id":"1191988"},{"quantity":0,"seller":"1","id":"2737806","index":0}]}`,
body: `{"orderItems":[{"quantity":1,"seller":"1","id":"18643698","attachments":[]},{"quantity":1,"seller":"1","id":"97907082","attachments":[]},{"quantity":1,"seller":"1","id":"64953394","attachments":[]},{"quantity":1,"seller":"1","id":"85095548","attachments":[]},{"quantity":1,"seller":"1","id":"1191988","attachments":[]},{"quantity":0,"seller":"1","id":"2737806","index":0,"attachments":[]}]}`,
},

result: JSON.parse(
Expand Down Expand Up @@ -339,7 +339,7 @@ export const checkoutOrderFormItemsInvalidFetch = {
method: 'PATCH',
headers: { 'content-type': 'application/json' },
body:
'{"orderItems":[{"quantity":1,"seller":"1","id":"18643698","index":0},{"quantity":1,"seller":"1","id":"97907082","index":1},{"quantity":1,"seller":"1","id":"64953394","index":2},{"quantity":1,"seller":"1","id":"85095548","index":3},{"quantity":1,"seller":"1","id":"1191988","index":4}]}',
'{"orderItems":[{"quantity":1,"seller":"1","id":"18643698","index":0,"attachments":[]},{"quantity":1,"seller":"1","id":"97907082","index":1,"attachments":[]},{"quantity":1,"seller":"1","id":"64953394","index":2,"attachments":[]},{"quantity":1,"seller":"1","id":"85095548","index":3,"attachments":[]},{"quantity":1,"seller":"1","id":"1191988","index":4,"attachments":[]}]}',
},
result: JSON.parse(
'{"orderFormId":"edbe3b03c8c94827a37ec5a6a4648fd2","salesChannel":"1","loggedIn":false,"isCheckedIn":false,"storeId":null,"checkedInPickupPointId":null,"allowManualPrice":false,"canEditData":true,"userProfileId":null,"userType":null,"ignoreProfileData":false,"value":69824,"messages":[],"items":[{"uniqueId":"90276D2ADB274F12B61A4ADE11874A0A","id":"2737806","productId":"43559243","productRefId":"6327601885574","refId":"6464716212392","ean":null,"name":"Fantastic Soft Cheese plum","skuName":"plum","modalType":null,"parentItemIndex":null,"parentAssemblyBinding":null,"assemblies":[],"priceValidUntil":"2023-03-29T14:32:10Z","tax":0,"price":34912,"listPrice":55757,"manualPrice":null,"manualPriceAppliedBy":null,"sellingPrice":34912,"rewardValue":0,"isGift":false,"additionalInfo":{"dimension":null,"brandName":"Acer","brandId":"2000002","offeringInfo":null,"offeringType":null,"offeringTypeId":null},"preSaleDate":null,"productCategoryIds":"/9285/9294/","productCategories":{"9285":"Kitchen and Home Appliances","9294":"Appliances"},"quantity":2,"seller":"1","sellerChain":["1"],"imageUrl":"http://storeframework.vteximg.com.br/arquivos/ids/168396-55-55/nihil.jpg?v=637753027573130000","detailUrl":"/fantastic-soft-cheese/p","components":[],"bundleItems":[],"attachments":[],"attachmentOfferings":[],"offerings":[],"priceTags":[],"availability":"available","measurementUnit":"un","unitMultiplier":1,"manufacturerCode":null,"priceDefinition":{"calculatedSellingPrice":34912,"total":69824,"sellingPrices":[{"value":34912,"quantity":2}]}}],"selectableGifts":[],"totalizers":[{"id":"Items","name":"Items Total","value":69824}],"shippingData":{"address":null,"logisticsInfo":[{"itemIndex":0,"selectedSla":null,"selectedDeliveryChannel":null,"addressId":null,"slas":[],"shipsTo":["BRA","USA"],"itemId":"2737806","deliveryChannels":[{"id":"delivery"}]}],"selectedAddresses":[],"availableAddresses":[],"pickupPoints":[]},"clientProfileData":null,"paymentData":{"updateStatus":"updated","installmentOptions":[{"paymentSystem":"6","bin":null,"paymentName":null,"paymentGroupName":null,"value":69824,"installments":[{"count":1,"hasInterestRate":false,"interestRate":0,"value":69824,"total":69824,"sellerMerchantInstallments":[{"id":"STOREFRAMEWORK","count":1,"hasInterestRate":false,"interestRate":0,"value":69824,"total":69824}]}]},{"paymentSystem":"201","bin":null,"paymentName":null,"paymentGroupName":null,"value":69824,"installments":[{"count":1,"hasInterestRate":false,"interestRate":0,"value":69824,"total":69824,"sellerMerchantInstallments":[{"id":"STOREFRAMEWORK","count":1,"hasInterestRate":false,"interestRate":0,"value":69824,"total":69824}]}]}],"paymentSystems":[{"id":6,"name":"Boleto Bancário","groupName":"bankInvoicePaymentGroup","validator":{"regex":null,"mask":null,"cardCodeRegex":null,"cardCodeMask":null,"weights":null,"useCvv":false,"useExpirationDate":false,"useCardHolderName":false,"useBillingAddress":false},"stringId":"6","template":"bankInvoicePaymentGroup-template","requiresDocument":false,"isCustom":false,"description":null,"requiresAuthentication":false,"dueDate":"2022-04-05T14:18:23.1569301Z","availablePayments":null},{"id":201,"name":"Free","groupName":"custom201PaymentGroupPaymentGroup","validator":{"regex":null,"mask":null,"cardCodeRegex":null,"cardCodeMask":null,"weights":null,"useCvv":false,"useExpirationDate":false,"useCardHolderName":false,"useBillingAddress":false},"stringId":"201","template":"custom201PaymentGroupPaymentGroup-template","requiresDocument":false,"isCustom":true,"description":"Free pay to test checkout payments","requiresAuthentication":false,"dueDate":"2022-04-05T14:18:23.1569301Z","availablePayments":null}],"payments":[],"giftCards":[],"giftCardMessages":[],"availableAccounts":[],"availableTokens":[],"availableAssociations":{}},"marketingData":null,"sellers":[{"id":"1","name":"VTEX","logo":""}],"clientPreferencesData":{"locale":"en-US","optinNewsLetter":null},"commercialConditionData":null,"storePreferencesData":{"countryCode":"USA","saveUserData":true,"timeZone":"Central Standard Time","currencyCode":"USD","currencyLocale":1033,"currencySymbol":"$","currencyFormatInfo":{"currencyDecimalDigits":2,"currencyDecimalSeparator":".","currencyGroupSeparator":",","currencyGroupSize":3,"startsWithCurrencySymbol":true}},"giftRegistryData":null,"openTextField":null,"invoiceData":null,"customData":{"customApps":[{"fields":{"cartEtag":"b7442f1dbacbc50fb2eb0e512b7bfdf0"},"id":"faststore","major":1}]},"itemMetadata":{"items":[{"id":"2737806","seller":"1","name":"Fantastic Soft Cheese plum","skuName":"plum","productId":"43559243","refId":"6464716212392","ean":null,"imageUrl":"http://storeframework.vteximg.com.br/arquivos/ids/168396-55-55/nihil.jpg?v=637753027573130000","detailUrl":"/fantastic-soft-cheese/p","assemblyOptions":[]}]},"hooksData":null,"ratesAndBenefitsData":{"rateAndBenefitsIdentifiers":[],"teaser":[]},"subscriptionData":null,"itemsOrdination":null}'
Expand Down
2 changes: 2 additions & 0 deletions packages/api/src/__generated__/schema.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions packages/api/src/platforms/vtex/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { StoreReview } from './resolvers/review'
import { StoreSearchResult } from './resolvers/searchResult'
import { StoreSeo } from './resolvers/seo'
import { ObjectOrString } from './resolvers/objectOrString'
import { StorePropertyValue } from './resolvers/propertyValue'
import type { Loaders } from './loaders'
import type { Clients } from './clients'
import type { Channel } from './utils/channel'
Expand Down Expand Up @@ -68,6 +69,7 @@ const Resolvers = {
StoreReview,
StoreProductGroup,
StoreSearchResult,
StorePropertyValue,
ObjectOrString,
Query,
Mutation,
Expand Down
34 changes: 19 additions & 15 deletions packages/api/src/platforms/vtex/resolvers/product.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ import type { EnhancedCommercialOffer } from '../utils/enhanceCommercialOffer'
import type { Resolver } from '..'
import type { PromiseType } from '../../../typings'
import type { Query } from './query'
import { VALUE_REFERENCES } from '../utils/propertyValue'
import {
attachmentToPropertyValue,
VALUE_REFERENCES,
} from '../utils/propertyValue'
import type { Attachment } from '../clients/commerce/types/OrderForm'

type QueryProduct = PromiseType<ReturnType<typeof Query.product>>
Expand Down Expand Up @@ -91,23 +94,24 @@ export const StoreProduct: Record<string, Resolver<Root>> & {
)
.sort(bestOfferFirst),
isVariantOf: (root) => root,
additionalProperty: ({ variations = [], attachmentsValues }) => {
const propertyValueVariations = variations.flatMap(({ name, values }) =>
values.map((value) => ({
name,
value,
valueReference: VALUE_REFERENCES.variation,
}))
additionalProperty: ({
// Search uses the name variations for specifications
variations: specifications = [],
attachmentsValues = [],
}) => {
const propertyValueSpecifications = specifications.flatMap(
({ name, values }) =>
values.map((value) => ({
name,
value,
valueReference: VALUE_REFERENCES.specification,
}))
)

const propertyValueAttachments = (attachmentsValues ?? []).map(
(attachment) => ({
name: attachment.name,
value: attachment.content,
valueReference: VALUE_REFERENCES.attachment,
})
const propertyValueAttachments = attachmentsValues.map(
attachmentToPropertyValue
)

return [...propertyValueVariations, ...propertyValueAttachments]
return [...propertyValueSpecifications, ...propertyValueAttachments]
},
}
12 changes: 12 additions & 0 deletions packages/api/src/platforms/vtex/resolvers/propertyValue.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import type { Resolver } from '..'
import type { IStorePropertyValue } from '../../../__generated__/schema'
import { getPropertyId } from '../utils/propertyValue'

type Root = IStorePropertyValue

export const StorePropertyValue: Record<string, Resolver<Root>> = {
propertyID: (root) => getPropertyId(root),
name: ({ name }) => name,
value: ({ value }) => value,
valueReference: ({ valueReference }) => valueReference,
}
25 changes: 8 additions & 17 deletions packages/api/src/platforms/vtex/resolvers/validateCart.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@ import type {
OrderFormItem,
} from '../clients/commerce/types/OrderForm'
import type { Context } from '..'
import { VALUE_REFERENCES } from '../utils/propertyValue'
import {
attachmentToPropertyValue,
getPropertyId,
VALUE_REFERENCES,
} from '../utils/propertyValue'

type Indexed<T> = T & { index?: number }

Expand All @@ -21,26 +25,12 @@ const getAttachments = (item: IStoreOffer) =>
(i) => i.valueReference === VALUE_REFERENCES.attachment
)

const serializeAttachment = (item: IStoreOffer) => {
const attachments = getAttachments(item)

if (attachments?.length === 0) {
return null
}

return attachments
?.map(
(attachment) => `${attachment.name}:${JSON.stringify(attachment.value)}`
)
.join('-')
}

const getId = (item: IStoreOffer) =>
[
item.itemOffered.sku,
item.seller.identifier,
item.price,
serializeAttachment(item),
item.itemOffered.additionalProperty?.map(getPropertyId).join('-'),
]
.filter(Boolean)
.join('::')
Expand All @@ -57,6 +47,7 @@ const orderFormItemToOffer = (
sku: item.id,
image: [],
name: item.name,
additionalProperty: item.attachments.map(attachmentToPropertyValue),
},
index,
})
Expand All @@ -68,7 +59,7 @@ const offerToOrderItemInput = (
seller: offer.seller.identifier,
id: offer.itemOffered.sku,
index: offer.index,
attachments: getAttachments(offer)?.map((attachment) => ({
attachments: (getAttachments(offer) ?? []).map((attachment) => ({
name: attachment.name,
content: attachment.value,
})),
Expand Down
19 changes: 18 additions & 1 deletion packages/api/src/platforms/vtex/utils/propertyValue.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,22 @@
import type { IStorePropertyValue } from '../../../__generated__/schema'
import type { Attachment } from '../clients/commerce/types/OrderForm'
import { md5 } from './md5'

export const VALUE_REFERENCES = {
variation: 'VARIATION',
attachment: 'ATTACHMENT',
specification: 'SPECIFICATION',
} as const

export function attachmentToPropertyValue(attachment: Attachment) {
return {
name: attachment.name,
value: attachment.content,
valueReference: VALUE_REFERENCES.attachment,
}
}

export function getPropertyId(item: IStorePropertyValue) {
return md5(
`${item.name}:${JSON.stringify(item.value)}:${item.valueReference}`
)
}
4 changes: 4 additions & 0 deletions packages/api/src/typeDefs/propertyValue.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
Properties that can be associated with products and products groups.
"""
type StorePropertyValue {
"""
Property id. This propert changes according to the content of the object.
"""
propertyID: String!
"""
Property value. May hold a string or the string representation of an object.
"""
Expand Down