Skip to content

Commit

Permalink
feat(store-api): Add channel support for products (#968)
Browse files Browse the repository at this point in the history
  • Loading branch information
tlgimenes authored Oct 5, 2021
1 parent 10d32a2 commit 923d343
Show file tree
Hide file tree
Showing 9 changed files with 93 additions and 90 deletions.
24 changes: 7 additions & 17 deletions packages/store-api/src/__generated__/schema.ts

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

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { fetchAPI } from '../common'
import { fetchAPI } from '../fetch'
import type {
Simulation,
SimulationArgs,
Expand Down
33 changes: 16 additions & 17 deletions packages/store-api/src/platforms/vtex/clients/search/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { fetchAPI } from '../common'
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'
Expand All @@ -13,11 +14,6 @@ export type Sort =
| 'discount:desc'
| ''

export interface SelectedFacet {
key: string
value: string
}

export interface SearchArgs {
query?: string
page: number
Expand All @@ -33,17 +29,20 @@ export interface ProductLocator {
value: string
}

export const IntelligentSearch = (options: Options) => {
const { channel } = options
const base = `http://search.biggylabs.com.br/search-api/v1/${options.account}`
export const IntelligentSearch = (opts: Options) => {
const { channel } = opts
const base = `http://search.biggylabs.com.br/search-api/v1/${opts.account}`

// TODO: change here once supporting sales channel
const defaultFacets = [
{
key: 'trade-policy',
value: channel,
},
]
const addDefaultFacets = (facets: SelectedFacet[]) => {
const facetsObj = Object.fromEntries(
facets.map(({ key, value }) => [key, value])
)

return Object.entries({
'trade-policy': channel,
...facetsObj,
}).map(([key, value]) => ({ key, value }))
}

const search = <T>({
query = '',
Expand All @@ -62,7 +61,7 @@ export const IntelligentSearch = (options: Options) => {
fuzzy,
})

const pathname = [...defaultFacets, ...selectedFacets]
const pathname = addDefaultFacets(selectedFacets)
.map(({ key, value }) => `${key}/${value}`)
.join('/')

Expand Down
19 changes: 16 additions & 3 deletions packages/store-api/src/platforms/vtex/loaders/sku.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,22 @@ import { enhanceSku } from '../utils/enhanceSku'
import type { EnhancedSku } from '../utils/enhanceSku'
import type { Options } from '..'
import type { Clients } from '../clients'
import type { SelectedFacet } from '../utils/facets'

export const getSkuLoader = (_: Options, clients: Clients) => {
const loader = async (skuIds: readonly string[]) => {
const loader = async (facetsList: readonly SelectedFacet[][]) => {
const skuIds = facetsList.map((facets) => {
const maybeFacet = facets.find(({ key }) => key === 'id')

if (!maybeFacet) {
throw new Error(
'Error while loading SKU. Needs to pass an id to selected facets'
)
}

return maybeFacet.value
})

const indexById = skuIds.reduce(
(acc, id, index) => ({ ...acc, [id]: index }),
{} as Record<string, number>
Expand Down Expand Up @@ -42,7 +55,7 @@ export const getSkuLoader = (_: Options, clients: Clients) => {
return sorted
}

return new DataLoader<string, EnhancedSku>(loader, {
maxBatchSize: 50, // Warning: Don't change this value, this the max allowed batch size of Search API
return new DataLoader<SelectedFacet[], EnhancedSku>(loader, {
maxBatchSize: 99, // Max allowed batch size of Search API
})
}
56 changes: 18 additions & 38 deletions packages/store-api/src/platforms/vtex/resolvers/query.ts
Original file line number Diff line number Diff line change
@@ -1,65 +1,41 @@
import { enhanceSku } from '../utils/enhanceSku'
import { transformSelectedFacet } from '../utils/facets'
import { SORT_MAP } from '../utils/sort'
import type { ProductLocator } from '../clients/search'
import type {
QueryProductArgs,
QueryAllCollectionsArgs,
QueryAllProductsArgs,
QuerySearchArgs,
} from '../../../__generated__/schema'
import type { CategoryTree } from '../clients/commerce/types/CategoryTree'
import type { Context } from '../index'

export interface SelectedFacets {
key: string
value: string
}

export interface SearchArgs {
term?: string
first: number
after?: string
sort:
| 'price_desc'
| 'price_asc'
| 'orders_desc'
| 'name_desc'
| 'name_asc'
| 'release_desc'
| 'discount_desc'
| 'score_desc'
selectedFacets: SelectedFacets[]
}

export const Query = {
product: async (
_: unknown,
{ locator }: { locator: ProductLocator },
ctx: Context
) => {
product: async (_: unknown, { locator }: QueryProductArgs, ctx: Context) => {
const {
loaders: { skuLoader },
} = ctx

const skuId =
locator.field === 'id'
? locator.value
: locator.value.split('-').reverse()[0]

return skuLoader.load(skuId)
return skuLoader.load(locator.map(transformSelectedFacet))
},
search: async (
_: unknown,
{ first, after: maybeAfter, sort, term, selectedFacets }: SearchArgs
{ first, after: maybeAfter, sort, term, selectedFacets }: QuerySearchArgs
) => {
const after = maybeAfter ? Number(maybeAfter) : 0
const searchArgs = {
page: Math.ceil(after / first),
count: first,
query: term,
sort: SORT_MAP[sort],
selectedFacets,
sort: SORT_MAP[sort ?? 'score_desc'],
selectedFacets: selectedFacets?.map(transformSelectedFacet) ?? [],
}

return searchArgs
},
allProducts: async (
_: unknown,
{ first, after: maybeAfter }: { first: number; after: string | null },
{ first, after: maybeAfter }: QueryAllProductsArgs,
ctx: Context
) => {
const {
Expand Down Expand Up @@ -91,7 +67,11 @@ export const Query = {
})),
}
},
allCollections: async (_: unknown, __: unknown, ctx: Context) => {
allCollections: async (
_: unknown,
__: QueryAllCollectionsArgs,
ctx: Context
) => {
const {
clients: { commerce },
} = ctx
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ export const validateCart = async (
orderNumber: updatedOrderForm.orderFormId,
acceptedOffer: updatedOrderForm.items.map((item) => ({
...item,
product: skuLoader.load(item.id),
product: skuLoader.load([{ key: 'id', value: item.id }]), // TODO: add channel
})),
},
messages: updatedOrderForm.messages.map(({ text, status }) => ({
Expand Down
31 changes: 31 additions & 0 deletions packages/store-api/src/platforms/vtex/utils/facets.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
export interface SelectedFacet {
key: string
value: string
}

const getIdFromSlug = (slug: string) => {
const id = slug.split('-').pop()

if (id == null) {
throw new Error('Error while extracting sku id from product slug')
}

return id
}

/**
* Transform facets from the store to VTEX platform facets.
* For instance, the channel in Store becames trade-policy in VTEX's realm
* */
export const transformSelectedFacet = ({ key, value }: SelectedFacet) => {
switch (key) {
case 'channel':
return { key: 'trade-policy', value }

case 'slug':
return { key: 'id', value: getIdFromSlug(key) }

default:
return { key, value }
}
}
16 changes: 3 additions & 13 deletions packages/store-api/src/typeDefs/query.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,6 @@ type StoreCollectionConnection {
edges: [StoreCollectionEdge!]!
}

enum StoreProductIDField {
id
slug
}

input StoreProductID {
field: StoreProductIDField!
value: ID!
}

enum StoreSort {
price_desc
price_asc
Expand All @@ -40,7 +30,7 @@ enum StoreSort {
score_desc
}

input StoreSelectedFacet {
input IStoreSelectedFacet {
key: String!
value: String!
}
Expand All @@ -56,7 +46,7 @@ type StoreSearchResult {
}

type Query {
product(locator: StoreProductID!): StoreProduct!
product(locator: [IStoreSelectedFacet!]!): StoreProduct!

search(
# Relay style pagination args. To know more: https://relay.dev/graphql/connections.htm
Expand All @@ -65,7 +55,7 @@ type Query {
after: String
sort: StoreSort = score_desc
term: String = ""
selectedFacets: [StoreSelectedFacet!]
selectedFacets: [IStoreSelectedFacet!]
): StoreSearchResult!

allProducts(first: Int!, after: String): StoreProductConnection!
Expand Down

0 comments on commit 923d343

Please sign in to comment.