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

Call IS instead of Solr for PDP query ✨ #468

Open
wants to merge 4 commits into
base: v1.x
Choose a base branch
from
Open
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
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.

## [Unreleased]

### Changed
- Call IS for `product` query instead of SOLR API.

## [1.69.0] - 2024-03-21
- Parameter `groupBy` into `recommendations` and `productRecommendations` resolvers and `groupByProduct` in `crossSelling` search client.

Expand Down
2 changes: 1 addition & 1 deletion manifest.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"vendor": "vtex",
"name": "search-resolver",
"version": "1.69.0",
"version": "1.70.0-beta.0",
"title": "GraphQL resolver for the VTEX store APIs",
"description": "GraphQL resolvers for the VTEX API for the catalog and orders.",
"credentialType": "absolute",
Expand Down
13 changes: 13 additions & 0 deletions node/clients/intelligent-search-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,19 @@ export class IntelligentSearchApi extends ExternalClient {
return this.http.get(`/banners/${path}`, {params: {...params, query: params.query, locale: this.locale}, metric: 'banners'})
}

public async product(params: { field: string, value: string, salesChannel: number }) {
const { field, value, salesChannel } = params
return this.http.get('/product', {
params: {
id: value,
type: field,
locale: this.locale,
salesChannel,
},
metric: 'product',
})
}

public async facets(params: FacetsArgs, path: string, shippingHeader?: string[]) {
if (isPathTraversal(path)) {
throw new Error("Malformed URL")
Expand Down
56 changes: 0 additions & 56 deletions node/clients/search.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,44 +95,6 @@ export class Search extends AppClient {
)
}

public product = (
slug: string,
vtexSegment?: string,
salesChannel?: string | number | null
) =>
this.get<SearchProduct[]>(
this.addCompleteSpecifications(
this.addSalesChannel(
`/pub/products/search/${this.searchEncodeURI(
slug && slug.toLowerCase()
)}/p`,
salesChannel
)
),
{
metric: 'search-product',
headers: this.getVtexSegmentCookieAsHeader(vtexSegment),
}
)

public productByEan = (
id: string,
vtexSegment?: string,
salesChannel?: string | number | null
) =>
this.get<SearchProduct[]>(
this.addCompleteSpecifications(
this.addSalesChannel(
`/pub/products/search?fq=alternateIds_Ean:${id}`,
salesChannel
)
),
{
metric: 'search-productByEan',
headers: this.getVtexSegmentCookieAsHeader(vtexSegment),
}
)

public productsByEan = (
ids: string[],
vtexSegment?: string,
Expand Down Expand Up @@ -195,24 +157,6 @@ export class Search extends AppClient {
}
)

public productByReference = (
id: string,
vtexSegment?: string,
salesChannel?: string | number | null
) =>
this.get<SearchProduct[]>(
this.addCompleteSpecifications(
this.addSalesChannel(
`/pub/products/search?fq=alternateIds_RefId:${id}`,
salesChannel
)
),
{
metric: 'search-productByReference',
headers: this.getVtexSegmentCookieAsHeader(vtexSegment),
}
)

public productsByReference = (
ids: string[],
vtexSegment?: string,
Expand Down
17 changes: 9 additions & 8 deletions node/resolvers/search/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,7 @@ export const queries = {

product: async (_: any, rawArgs: ProductArgs, ctx: Context) => {
const {
clients: { search },
clients: { intelligentSearchApi },
} = ctx

const args =
Expand All @@ -394,27 +394,28 @@ export const queries = {
const { field, value } = args.identifier

let products = [] as SearchProduct[]

const vtexSegment = (!cookie || (!cookie?.regionId && rawArgs.regionId)) ? buildVtexSegment(cookie, salesChannel, rawArgs.regionId) : ctx.vtex.segmentToken
let fieldId = ''

switch (field) {
case 'id':
products = await search.productById(value, vtexSegment, salesChannel)
fieldId = 'product.id'
break
case 'slug':
products = await search.product(value, vtexSegment, salesChannel)
fieldId = 'product.link'
break
case 'ean':
products = await search.productByEan(value, vtexSegment, salesChannel)
fieldId = 'sku.ean'
break
case 'reference':
products = await search.productByReference(value, vtexSegment, salesChannel)
fieldId = 'sku.reference'
break
case 'sku':
products = await search.productBySku(value, vtexSegment, salesChannel)
fieldId = 'sku.id'
break
}

products = await intelligentSearchApi.product({ field: fieldId, value, salesChannel})

if (products.length > 0) {
return head(products)
}
Expand Down
2 changes: 1 addition & 1 deletion node/resolvers/search/offer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ export const resolvers = {
},
giftSkuIds: propOr([], 'GiftSkuIds'),
gifts: async ({ GiftSkuIds }: CommertialOffer, _: any, ctx: Context) => {
if (GiftSkuIds.length === 0) {
if (!GiftSkuIds || GiftSkuIds.length === 0) {
return []
}

Expand Down
86 changes: 50 additions & 36 deletions node/resolvers/search/product.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ const knownNotPG = [
'link',
'linkText',
'productReference',
'origin',
'cacheId',
]

const removeTrailingSlashes = (str: string) =>
Expand Down Expand Up @@ -181,7 +183,7 @@ export const resolvers = {
cacheId || linkText,

clusterHighlights: ({origin, clusterHighlights }: SearchProduct) => {
if (origin === 'intelligent-search') {
if (origin === 'intelligent-search' || origin === 'search-document') {
return clusterHighlights
}

Expand All @@ -201,7 +203,7 @@ export const resolvers = {
},

productClusters: ({origin, productClusters }: SearchProduct) => {
if (origin === 'intelligent-search') {
if (origin === 'intelligent-search' || origin === 'search-document') {
return productClusters
}

Expand All @@ -211,8 +213,8 @@ export const resolvers = {
properties: async (product: SearchProduct, _: unknown, ctx: Context) => {
let valuesUntranslated = []

if (product.origin === 'intelligent-search') {
valuesUntranslated = product.properties ?? []
if (product.origin === 'intelligent-search' || product.origin === 'search-document') {
valuesUntranslated = product.properties?.map((prop) => ({...prop, name: prop.originalName ?? prop.name })) ?? []
} else {
valuesUntranslated = (product.allSpecifications ?? []).map((name: string) => {
const value = (product as unknown as DynamicKey<string[]>)[name]
Expand Down Expand Up @@ -287,45 +289,57 @@ export const resolvers = {

specificationGroups: async (product: SearchProduct, _: unknown, ctx: Context) => {
if (product.origin === 'intelligent-search') {
return product.specificationGroups
return product.specificationGroups ?? []
}

const allSpecificationsGroups = (product.allSpecificationsGroups ?? []).concat(['allSpecifications'])

const visibleSpecifications = product.completeSpecifications
? product.completeSpecifications.reduce<Record<string, boolean>>((acc, specification) => {
acc[specification.Name] = specification.IsOnProductDetails
return acc
}, {})
: null

let noTranslationSpecificationGroups = allSpecificationsGroups.map(
(groupName: string) => {
let groupSpecifications = (product as unknown as DynamicKey<string[]>)?.[groupName] ?? []
let noTranslationSpecificationGroups = []

groupSpecifications = groupSpecifications.filter(specificationName => {
if (visibleSpecifications && visibleSpecifications[specificationName] != null)
return visibleSpecifications[specificationName]
return true
if (product.origin === 'search-document') {
noTranslationSpecificationGroups = product.specificationGroups?.map(
(group) => ({
...group,
specifications: group.specifications.map((spec) => ({...spec, name: spec.originalName }))
})

return {
originalName: groupName,
name: groupName,
specifications: groupSpecifications.map((name) => {
const values = (product as unknown as DynamicKey<string[]>)[name] || []
return {
originalName: name,
name,
values,
) ?? []
} else {
const allSpecificationsGroups = (product.allSpecificationsGroups ?? []).concat(['allSpecifications'])

const visibleSpecifications = product.completeSpecifications
? product.completeSpecifications.reduce<Record<string, boolean>>((acc, specification) => {
acc[specification.Name] = specification.IsOnProductDetails
return acc
}, {})
: null

noTranslationSpecificationGroups = allSpecificationsGroups.map(
(groupName: string) => {
let groupSpecifications = (product as unknown as DynamicKey<string[]>)?.[groupName] ?? []

groupSpecifications = groupSpecifications.filter(specificationName => {
if (visibleSpecifications && visibleSpecifications[specificationName] != null)
return visibleSpecifications[specificationName]
return true
})

return {
originalName: groupName,
name: groupName,
specifications: groupSpecifications.map((name) => {
const values = (product as unknown as DynamicKey<string[]>)[name] || []
return {
originalName: name,
name,
values,
}
}
}
),
),
}
}
}
)
)

noTranslationSpecificationGroups = noTranslationSpecificationGroups.filter(group => group.specifications.length > 0)
noTranslationSpecificationGroups = noTranslationSpecificationGroups.filter(group => group.specifications.length > 0)

}

if (!shouldTranslateToUserLocale(ctx)) {
return noTranslationSpecificationGroups
Expand Down
5 changes: 5 additions & 0 deletions node/resolvers/search/sku.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ export const resolvers = {
if (!sku) {
return sku
}

if (sku.variations?.length && typeof sku.variations[0] !== 'string') {
return sku.variations
}

const variations = (sku.variations || []).map(variationObj => {
const variationName = typeof variationObj === 'string' ? variationObj : (variationObj as {name: string}).name
const fieldId = (sku.skuSpecifications || []).find(specification => specification.field.name === variationName)?.field?.id
Expand Down
8 changes: 5 additions & 3 deletions node/typings/Catalog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ enum FacetsBehavior {
interface SpecificationGroup {
name: string
originalName: string
specifications: { name: string; originalName: string; values: string[] }
specifications: { name: string; originalName: string; values: string[] }[]
}
interface SearchProduct {
origin?: string
Expand Down Expand Up @@ -112,7 +112,9 @@ interface SearchProduct {
completeSpecifications?: CompleteSpecification[]
skuSpecifications?: SkuSpecification[]
specificationGroups?: SpecificationGroup[]
properties?: { name: string; values: string[] }[]
properties?: {
originalName?: string; name: string; values: string[]
}[]
}

interface SearchItem {
Expand Down Expand Up @@ -220,7 +222,7 @@ interface CommertialOffer {
}[]
GetInfoErrorMessage: any | null
CacheVersionUsedToCallCheckout: string
// Supports the Intelligent Search API which
// Supports the Intelligent Search API which
// uses the same name from the simulation
discountHighlights: any[]
}
Expand Down
Loading
Loading