From 92792a5b615e085205d15c47b2a4c82c65b450ce Mon Sep 17 00:00:00 2001 From: Tiago Gimenes Date: Wed, 3 Nov 2021 13:50:52 -0300 Subject: [PATCH 1/2] filter right channel before simulating --- packages/api/src/platforms/vtex/index.ts | 12 +++++ .../src/platforms/vtex/resolvers/product.ts | 12 ++++- .../api/src/platforms/vtex/resolvers/query.ts | 13 ++++- yarn.lock | 52 +------------------ 4 files changed, 37 insertions(+), 52 deletions(-) diff --git a/packages/api/src/platforms/vtex/index.ts b/packages/api/src/platforms/vtex/index.ts index 3faaa809ac..6fae5c3e01 100644 --- a/packages/api/src/platforms/vtex/index.ts +++ b/packages/api/src/platforms/vtex/index.ts @@ -27,6 +27,15 @@ export interface Options { export interface Context { clients: Clients loaders: Loaders + /** + * @description Storage updated at each request. + * + * Use this datastructure to store and share small values in the context. + * Use it with caution since dependecy injection leads to a more complex code + * */ + storage: { + channel: string + } } export type Resolver = ( @@ -55,6 +64,9 @@ const Resolvers = { export const getContextFactory = (options: Options) => (ctx: any) => { ctx.clients = getClients(options) ctx.loaders = getLoaders(options, ctx.clients) + ctx.storage = { + channel: options.channel, + } return ctx } diff --git a/packages/api/src/platforms/vtex/resolvers/product.ts b/packages/api/src/platforms/vtex/resolvers/product.ts index cdf9932d6e..0eb8e61d29 100644 --- a/packages/api/src/platforms/vtex/resolvers/product.ts +++ b/packages/api/src/platforms/vtex/resolvers/product.ts @@ -55,9 +55,19 @@ export const StoreProduct: Record> = { offers: async (product, _, ctx) => { const { loaders: { simulationLoader }, + storage: { channel }, } = ctx - const { sellers, id } = product + const { id, policies } = product + const sellers = policies.find((policy) => policy.id === channel)?.sellers + + if (sellers == null) { + // This error will likely happen when you forget to forward the channel somewhere in your code. + // Make sure all queries that lead to a product are forwarding the channel in context corectly + throw new Error( + `Product with id ${id} has no sellers for channel ${channel}.` + ) + } // Unique seller ids const sellerIds = sellers.map((seller) => seller.id) diff --git a/packages/api/src/platforms/vtex/resolvers/query.ts b/packages/api/src/platforms/vtex/resolvers/query.ts index a033111795..e784b48e3f 100644 --- a/packages/api/src/platforms/vtex/resolvers/query.ts +++ b/packages/api/src/platforms/vtex/resolvers/query.ts @@ -16,12 +16,23 @@ export const Query = { loaders: { skuLoader }, } = ctx + // Insert channel in context for later usage + ctx.storage.channel = + locator.find((facet) => facet.key === 'channel')?.value ?? + ctx.storage.channel + return skuLoader.load(locator.map(transformSelectedFacet)) }, search: async ( _: unknown, - { first, after: maybeAfter, sort, term, selectedFacets }: QuerySearchArgs + { first, after: maybeAfter, sort, term, selectedFacets }: QuerySearchArgs, + ctx: Context ) => { + // Insert channel in context for later usage + ctx.storage.channel = + selectedFacets?.find((facet) => facet.key === 'channel')?.value ?? + ctx.storage.channel + const after = maybeAfter ? Number(maybeAfter) : 0 const searchArgs = { page: Math.ceil(after / first), diff --git a/yarn.lock b/yarn.lock index 271ad30cb2..f028f1f227 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5883,11 +5883,6 @@ "@types/eslint" "*" "@types/estree" "*" -"@types/eslint-visitor-keys@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#1ee30d79544ca84d68d4b3cdb0af4f205663dd2d" - integrity sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag== - "@types/eslint@*", "@types/eslint@^7.2.6": version "7.2.7" resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-7.2.7.tgz#f7ef1cf0dceab0ae6f9a976a0a9af14ab1baca26" @@ -6401,17 +6396,7 @@ resolved "https://registry.yarnpkg.com/@types/yoga-layout/-/yoga-layout-1.9.2.tgz#efaf9e991a7390dc081a0b679185979a83a9639a" integrity sha512-S9q47ByT2pPvD65IvrWp7qppVMpk9WGMbVq9wbWZOHg6tnXSD4vyhao6nOSBwwfDdV2p3Kx9evA9vI+XWTfDvw== -"@typescript-eslint/eslint-plugin@^2.12.0": - version "2.34.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.34.0.tgz#6f8ce8a46c7dea4a6f1d171d2bb8fbae6dac2be9" - integrity sha512-4zY3Z88rEE99+CNvTbXSyovv2z9PNOVffTWD2W8QF5s2prBQtwN2zadqERcrHpcR7O/+KMI3fcTAmUUhK/iQcQ== - dependencies: - "@typescript-eslint/experimental-utils" "2.34.0" - functional-red-black-tree "^1.0.1" - regexpp "^3.0.0" - tsutils "^3.17.1" - -"@typescript-eslint/eslint-plugin@^4.28.1", "@typescript-eslint/eslint-plugin@^4.29.2": +"@typescript-eslint/eslint-plugin@^2.12.0", "@typescript-eslint/eslint-plugin@^4", "@typescript-eslint/eslint-plugin@^4.28.1", "@typescript-eslint/eslint-plugin@^4.29.2": version "4.33.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.33.0.tgz#c24dc7c8069c7706bc40d99f6fa87edcb2005276" integrity sha512-aINiAxGVdOl1eJyVjaWn/YcVAq4Gi/Yo35qHGCnqbWVz61g39D0h23veY/MA0rFFGfxK7TySg2uwDeNv+JgVpg== @@ -6425,16 +6410,6 @@ semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/experimental-utils@2.34.0": - version "2.34.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-2.34.0.tgz#d3524b644cdb40eebceca67f8cf3e4cc9c8f980f" - integrity sha512-eS6FTkq+wuMJ+sgtuNTtcqavWXqsflWcfBnlYhg/nS4aZ1leewkXGbvBhaapn1q6qf4M71bsR1tez5JTRMuqwA== - dependencies: - "@types/json-schema" "^7.0.3" - "@typescript-eslint/typescript-estree" "2.34.0" - eslint-scope "^5.0.0" - eslint-utils "^2.0.0" - "@typescript-eslint/experimental-utils@4.33.0": version "4.33.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.33.0.tgz#6f2a786a4209fa2222989e9380b5331b2810f7fd" @@ -6471,17 +6446,7 @@ eslint-scope "^5.1.1" eslint-utils "^3.0.0" -"@typescript-eslint/parser@^2.12.0": - version "2.34.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-2.34.0.tgz#50252630ca319685420e9a39ca05fe185a256bc8" - integrity sha512-03ilO0ucSD0EPTw2X4PntSIRFtDPWjrVq7C3/Z3VQHRC7+13YB55rcJI3Jt+YgeHbjUdJPcPa7b23rXCBokuyA== - dependencies: - "@types/eslint-visitor-keys" "^1.0.0" - "@typescript-eslint/experimental-utils" "2.34.0" - "@typescript-eslint/typescript-estree" "2.34.0" - eslint-visitor-keys "^1.1.0" - -"@typescript-eslint/parser@^4.28.1", "@typescript-eslint/parser@^4.29.2": +"@typescript-eslint/parser@^2.12.0", "@typescript-eslint/parser@^4", "@typescript-eslint/parser@^4.28.1", "@typescript-eslint/parser@^4.29.2": version "4.33.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.33.0.tgz#dfe797570d9694e560528d18eecad86c8c744899" integrity sha512-ZohdsbXadjGBSK0/r+d87X0SBmKzOq4/S5nzK6SBgJspFo9/CUDJ7hjayuze+JK7CZQLDMroqytp7pOcFKTxZA== @@ -6530,19 +6495,6 @@ resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.33.0.tgz#a1e59036a3b53ae8430ceebf2a919dc7f9af6d72" integrity sha512-zKp7CjQzLQImXEpLt2BUw1tvOMPfNoTAfb8l51evhYbOEEzdWyQNmHWWGPR6hwKJDAi+1VXSBmnhL9kyVTTOuQ== -"@typescript-eslint/typescript-estree@2.34.0": - version "2.34.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-2.34.0.tgz#14aeb6353b39ef0732cc7f1b8285294937cf37d5" - integrity sha512-OMAr+nJWKdlVM9LOqCqh3pQQPwxHAN7Du8DR6dmwCrAmxtiXQnhHJ6tBNtf+cggqfo51SG/FCwnKhXCIM7hnVg== - dependencies: - debug "^4.1.1" - eslint-visitor-keys "^1.1.0" - glob "^7.1.6" - is-glob "^4.0.1" - lodash "^4.17.15" - semver "^7.3.2" - tsutils "^3.17.1" - "@typescript-eslint/typescript-estree@4.19.0": version "4.19.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.19.0.tgz#8a709ffa400284ab72df33376df085e2e2f61147" From f2d047981358f4703edeaf4daa096baeea171eb4 Mon Sep 17 00:00:00 2001 From: Tiago Gimenes Date: Wed, 3 Nov 2021 15:29:18 -0300 Subject: [PATCH 2/2] filter right channel before simulating --- .../platforms/vtex/clients/commerce/index.ts | 21 +++++++++--------- .../api/src/platforms/vtex/clients/index.ts | 8 +++---- .../platforms/vtex/clients/search/index.ts | 9 ++++---- packages/api/src/platforms/vtex/index.ts | 4 ++-- .../api/src/platforms/vtex/loaders/index.ts | 5 ++--- .../src/platforms/vtex/resolvers/product.ts | 15 ++++++++----- .../api/src/platforms/vtex/resolvers/query.ts | 22 ++++++++++++------- 7 files changed, 46 insertions(+), 38 deletions(-) diff --git a/packages/api/src/platforms/vtex/clients/commerce/index.ts b/packages/api/src/platforms/vtex/clients/commerce/index.ts index 2874b7c9c1..3cbf51a7fb 100644 --- a/packages/api/src/platforms/vtex/clients/commerce/index.ts +++ b/packages/api/src/platforms/vtex/clients/commerce/index.ts @@ -1,3 +1,4 @@ +import type { Context, Options } from '../../index' import { fetchAPI } from '../fetch' import type { Simulation, @@ -5,7 +6,6 @@ import type { SimulationOptions, } from './types/Simulation' import type { CategoryTree } from './types/CategoryTree' -import type { Options } from '../..' import type { Brand } from './types/Brand' import type { OrderForm, OrderFormInputItem } from './types/OrderForm' @@ -16,12 +16,11 @@ const BASE_INIT = { }, } -const getBase = ({ account, environment }: Options) => - `http://${account}.${environment}.com.br` - -export const VtexCommerce = (options: Options) => { - const { channel } = options - const base = getBase(options) +export const VtexCommerce = ( + { account, environment }: Options, + ctx: Context +) => { + const base = `http://${account}.${environment}.com.br` return { catalog: { @@ -37,7 +36,9 @@ export const VtexCommerce = (options: Options) => { checkout: { simulation: ( args: SimulationArgs, - { salesChannel }: SimulationOptions = { salesChannel: channel } + { salesChannel }: SimulationOptions = { + salesChannel: ctx.storage.channel, + } ): Promise => { const params = new URLSearchParams({ sc: salesChannel, @@ -54,7 +55,7 @@ export const VtexCommerce = (options: Options) => { orderForm: ({ id, refreshOutdatedData = true, - salesChannel = channel, + salesChannel = ctx.storage.channel, }: { id: string refreshOutdatedData?: boolean @@ -74,7 +75,7 @@ export const VtexCommerce = (options: Options) => { id, orderItems, allowOutdatedData = 'paymentData', - salesChannel = channel, + salesChannel = ctx.storage.channel, }: { id: string orderItems: OrderFormInputItem[] diff --git a/packages/api/src/platforms/vtex/clients/index.ts b/packages/api/src/platforms/vtex/clients/index.ts index aca69900b0..255092da04 100644 --- a/packages/api/src/platforms/vtex/clients/index.ts +++ b/packages/api/src/platforms/vtex/clients/index.ts @@ -1,12 +1,12 @@ import { VtexCommerce } from './commerce' import { IntelligentSearch } from './search' -import type { Options } from '..' +import type { Context, Options } from '..' export type Clients = ReturnType -export const getClients = (options: Options) => { - const search = IntelligentSearch(options) - const commerce = VtexCommerce(options) +export const getClients = (options: Options, ctx: Context) => { + const search = IntelligentSearch(options, ctx) + const commerce = VtexCommerce(options, ctx) return { search, diff --git a/packages/api/src/platforms/vtex/clients/search/index.ts b/packages/api/src/platforms/vtex/clients/search/index.ts index c170e42bf2..62b7082c15 100644 --- a/packages/api/src/platforms/vtex/clients/search/index.ts +++ b/packages/api/src/platforms/vtex/clients/search/index.ts @@ -1,6 +1,6 @@ +import type { Context, Options } from '../../index' import { fetchAPI } from '../fetch' import type { SelectedFacet } from '../../utils/facets' -import type { Options } from '../..' import type { ProductSearchResult } from './types/ProductSearchResult' import type { AttributeSearchResult } from './types/AttributeSearchResult' @@ -29,9 +29,8 @@ export interface ProductLocator { value: string } -export const IntelligentSearch = (opts: Options) => { - const { channel } = opts - const base = `http://search.biggylabs.com.br/search-api/v1/${opts.account}` +export const IntelligentSearch = ({ account }: Options, ctx: Context) => { + const base = `http://search.biggylabs.com.br/search-api/v1/${account}` const addDefaultFacets = (facets: SelectedFacet[]) => { const facetsObj = Object.fromEntries( @@ -39,7 +38,7 @@ export const IntelligentSearch = (opts: Options) => { ) return Object.entries({ - 'trade-policy': channel, + 'trade-policy': ctx.storage.channel, ...facetsObj, }).map(([key, value]) => ({ key, value })) } diff --git a/packages/api/src/platforms/vtex/index.ts b/packages/api/src/platforms/vtex/index.ts index 6fae5c3e01..b03a00788d 100644 --- a/packages/api/src/platforms/vtex/index.ts +++ b/packages/api/src/platforms/vtex/index.ts @@ -62,11 +62,11 @@ const Resolvers = { } export const getContextFactory = (options: Options) => (ctx: any) => { - ctx.clients = getClients(options) - ctx.loaders = getLoaders(options, ctx.clients) ctx.storage = { channel: options.channel, } + ctx.clients = getClients(options, ctx) + ctx.loaders = getLoaders(options, ctx) return ctx } diff --git a/packages/api/src/platforms/vtex/loaders/index.ts b/packages/api/src/platforms/vtex/loaders/index.ts index e05ad0fcab..aa86ea268a 100644 --- a/packages/api/src/platforms/vtex/loaders/index.ts +++ b/packages/api/src/platforms/vtex/loaders/index.ts @@ -1,11 +1,10 @@ import { getSimulationLoader } from './simulation' import { getSkuLoader } from './sku' -import type { Options } from '..' -import type { Clients } from '../clients' +import type { Context, Options } from '..' export type Loaders = ReturnType -export const getLoaders = (options: Options, clients: Clients) => { +export const getLoaders = (options: Options, { clients }: Context) => { const skuLoader = getSkuLoader(options, clients) const simulationLoader = getSimulationLoader(options, clients) diff --git a/packages/api/src/platforms/vtex/resolvers/product.ts b/packages/api/src/platforms/vtex/resolvers/product.ts index 0eb8e61d29..467ac87e04 100644 --- a/packages/api/src/platforms/vtex/resolvers/product.ts +++ b/packages/api/src/platforms/vtex/resolvers/product.ts @@ -11,6 +11,8 @@ const DEFAULT_IMAGE = { const getSlug = (link: string, id: string) => `${link}-${id}` const getPath = (link: string, id: string) => `/${getSlug(link, id)}/p` +const nonEmptyArray = (array: T[] | null | undefined) => + Array.isArray(array) && array.length > 0 ? array : null export const StoreProduct: Record> = { productID: ({ id }) => id, @@ -38,12 +40,13 @@ export const StoreProduct: Record> = { numberOfItems: categoryTrees.length, }), image: ({ isVariantOf, images }) => - (images ?? isVariantOf.images ?? [DEFAULT_IMAGE]).map( - ({ name, value }) => ({ - alternateName: name ?? '', - url: value.replace('vteximg.com.br', 'vtexassets.com'), - }) - ), + ( + nonEmptyArray(images) ?? + nonEmptyArray(isVariantOf.images) ?? [DEFAULT_IMAGE] + ).map(({ name, value }) => ({ + alternateName: name ?? '', + url: value.replace('vteximg.com.br', 'vtexassets.com'), + })), sku: ({ isVariantOf: { skus: [sku], diff --git a/packages/api/src/platforms/vtex/resolvers/query.ts b/packages/api/src/platforms/vtex/resolvers/query.ts index e784b48e3f..0b0d32d6cc 100644 --- a/packages/api/src/platforms/vtex/resolvers/query.ts +++ b/packages/api/src/platforms/vtex/resolvers/query.ts @@ -12,15 +12,18 @@ import type { Context } from '../index' export const Query = { product: async (_: unknown, { locator }: QueryProductArgs, ctx: Context) => { + // Insert channel in context for later usage + ctx.storage = { + ...ctx.storage, + channel: + locator.find((facet) => facet.key === 'channel')?.value ?? + ctx.storage.channel, + } + const { loaders: { skuLoader }, } = ctx - // Insert channel in context for later usage - ctx.storage.channel = - locator.find((facet) => facet.key === 'channel')?.value ?? - ctx.storage.channel - return skuLoader.load(locator.map(transformSelectedFacet)) }, search: async ( @@ -29,9 +32,12 @@ export const Query = { ctx: Context ) => { // Insert channel in context for later usage - ctx.storage.channel = - selectedFacets?.find((facet) => facet.key === 'channel')?.value ?? - ctx.storage.channel + ctx.storage = { + ...ctx.storage, + channel: + selectedFacets?.find((facet) => facet.key === 'channel')?.value ?? + ctx.storage.channel, + } const after = maybeAfter ? Number(maybeAfter) : 0 const searchArgs = {