@graphcommerce/algolia-recommend 9.0.0-canary.85 → 9.0.0-canary.87
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/mesh/getRecommendations.ts +56 -42
- package/mesh/resolvers.ts +14 -10
- package/package.json +6 -6
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# @graphcommerce/algolia-recommend
|
|
2
2
|
|
|
3
|
+
## 9.0.0-canary.87
|
|
4
|
+
|
|
5
|
+
## 9.0.0-canary.86
|
|
6
|
+
|
|
7
|
+
### Patch Changes
|
|
8
|
+
|
|
9
|
+
- [#2379](https://github.com/graphcommerce-org/graphcommerce/pull/2379) [`ce30678`](https://github.com/graphcommerce-org/graphcommerce/commit/ce30678ad353ac4c7c38d79e96a2bb3de55f6fcb) - Automatically fall back to existing upsells/related products if they are defined and Algolia returns an error ([@paales](https://github.com/paales))
|
|
10
|
+
|
|
3
11
|
## 9.0.0-canary.85
|
|
4
12
|
|
|
5
13
|
## 9.0.0-canary.84
|
|
@@ -5,9 +5,13 @@ import type {
|
|
|
5
5
|
AlgoliarecommendationsHit,
|
|
6
6
|
} from '@graphcommerce/graphql-mesh'
|
|
7
7
|
import { nonNullable } from '@graphcommerce/next-ui'
|
|
8
|
-
import type { GraphQLResolveInfo } from 'graphql'
|
|
8
|
+
import type { GraphQLError, GraphQLResolveInfo } from 'graphql'
|
|
9
9
|
import type { Simplify } from 'type-fest'
|
|
10
10
|
|
|
11
|
+
function isGraphQLError(err: unknown): err is GraphQLError {
|
|
12
|
+
return !!(err as GraphQLError)?.message
|
|
13
|
+
}
|
|
14
|
+
|
|
11
15
|
const inputToModel = {
|
|
12
16
|
Trending_items_Input: 'trending_items' as const,
|
|
13
17
|
Trending_facet_values_Input: 'trending_facets' as const,
|
|
@@ -15,29 +19,11 @@ const inputToModel = {
|
|
|
15
19
|
Looking_similar_Input: 'looking_similar' as const,
|
|
16
20
|
Related_products_Input: 'related_products' as const,
|
|
17
21
|
}
|
|
22
|
+
|
|
18
23
|
function isAlgoliaResponse<T extends object>(root: T): root is T & { uid: string } {
|
|
19
24
|
return 'uid' in root
|
|
20
25
|
}
|
|
21
|
-
function argsFromKeysInput(keys, args, context) {
|
|
22
|
-
const body = keys
|
|
23
|
-
.map(
|
|
24
|
-
(key) =>
|
|
25
|
-
({
|
|
26
|
-
[key.keyInput]: {
|
|
27
|
-
model: inputToModel[key.keyInput as string],
|
|
28
|
-
indexName: getIndexName(context),
|
|
29
|
-
|
|
30
|
-
...args,
|
|
31
|
-
objectID: key.objectId,
|
|
32
|
-
},
|
|
33
|
-
}) as unknown as AlgoliarecommendationsRequest_Input,
|
|
34
|
-
)
|
|
35
|
-
.filter(nonNullable)
|
|
36
|
-
|
|
37
|
-
const returnObject = { input: { requests: body } }
|
|
38
26
|
|
|
39
|
-
return returnObject
|
|
40
|
-
}
|
|
41
27
|
export async function getRecommendations<
|
|
42
28
|
K extends keyof AlgoliarecommendationsRequest_Input,
|
|
43
29
|
Input extends AlgoliarecommendationsRequest_Input[K],
|
|
@@ -53,29 +39,57 @@ export async function getRecommendations<
|
|
|
53
39
|
if (!isAlgoliaResponse(root)) {
|
|
54
40
|
return []
|
|
55
41
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
42
|
+
try {
|
|
43
|
+
return (
|
|
44
|
+
(await context.algoliaRecommend.Query.algolia_getRecommendations({
|
|
45
|
+
key: { keyInput, objectId: atob(root.uid) },
|
|
46
|
+
argsFromKeys: (keys) => ({
|
|
47
|
+
input: {
|
|
48
|
+
requests: keys
|
|
49
|
+
.map(
|
|
50
|
+
(key) =>
|
|
51
|
+
({
|
|
52
|
+
[key.keyInput]: {
|
|
53
|
+
model: inputToModel[key.keyInput as string],
|
|
54
|
+
indexName: getIndexName(context),
|
|
55
|
+
|
|
56
|
+
...args,
|
|
57
|
+
objectID: key.objectId,
|
|
58
|
+
},
|
|
59
|
+
}) as unknown as AlgoliarecommendationsRequest_Input,
|
|
60
|
+
)
|
|
61
|
+
.filter(nonNullable),
|
|
62
|
+
},
|
|
63
|
+
}),
|
|
64
|
+
valuesFromResults: (res, keys) =>
|
|
65
|
+
keys
|
|
66
|
+
.map((_key, index) => res?.results[index])
|
|
67
|
+
.map((r) => r?.hits.map((hit) => hit && mapper(hit)).filter(nonNullable)) ?? null,
|
|
68
|
+
selectionSet: /* GraphQL */ `
|
|
69
|
+
{
|
|
70
|
+
results {
|
|
71
|
+
nbHits
|
|
72
|
+
hits {
|
|
73
|
+
... on AlgoliarecommendHit {
|
|
74
|
+
objectID
|
|
75
|
+
additionalProperties
|
|
76
|
+
}
|
|
72
77
|
}
|
|
73
78
|
}
|
|
74
79
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
)
|
|
80
|
+
`,
|
|
81
|
+
context,
|
|
82
|
+
info,
|
|
83
|
+
})) ?? null
|
|
84
|
+
)
|
|
85
|
+
} catch (e) {
|
|
86
|
+
if (isGraphQLError(e)) {
|
|
87
|
+
console.log(
|
|
88
|
+
'There was an error retrieving Algolia Recommendations, make sure the recommendation models are created',
|
|
89
|
+
e,
|
|
90
|
+
)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return null
|
|
94
|
+
}
|
|
81
95
|
}
|
package/mesh/resolvers.ts
CHANGED
|
@@ -87,11 +87,12 @@ type ProductResolver = ResolverFn<
|
|
|
87
87
|
>
|
|
88
88
|
|
|
89
89
|
if (isEnabled(import.meta.graphCommerce.algolia.relatedProducts)) {
|
|
90
|
+
const fieldName = enumToLocation(import.meta.graphCommerce.algolia.relatedProducts)
|
|
90
91
|
const resolve: ProductResolver = async (root, args, context, info) => {
|
|
91
92
|
const { objectID, threshold, fallbackParameters, maxRecommendations, queryParameters } =
|
|
92
93
|
await getRecommendationsArgs(root, args, context)
|
|
93
94
|
|
|
94
|
-
|
|
95
|
+
const recommendations = await getRecommendations(
|
|
95
96
|
root,
|
|
96
97
|
'Related_products_Input',
|
|
97
98
|
{ objectID, threshold, fallbackParameters, maxRecommendations, queryParameters },
|
|
@@ -99,11 +100,12 @@ if (isEnabled(import.meta.graphCommerce.algolia.relatedProducts)) {
|
|
|
99
100
|
info,
|
|
100
101
|
await createProductMapper(context),
|
|
101
102
|
)
|
|
103
|
+
return recommendations ?? root[fieldName] ?? null
|
|
102
104
|
}
|
|
103
105
|
|
|
104
106
|
productInterfaceTypes.forEach((productType) => {
|
|
105
107
|
if (!resolvers[productType]) resolvers[productType] = {}
|
|
106
|
-
resolvers[productType][
|
|
108
|
+
resolvers[productType][fieldName] = {
|
|
107
109
|
selectionSet: `{ uid }`,
|
|
108
110
|
resolve,
|
|
109
111
|
}
|
|
@@ -111,10 +113,11 @@ if (isEnabled(import.meta.graphCommerce.algolia.relatedProducts)) {
|
|
|
111
113
|
}
|
|
112
114
|
|
|
113
115
|
if (isEnabled(import.meta.graphCommerce.algolia.lookingSimilar)) {
|
|
116
|
+
const fieldName = enumToLocation(import.meta.graphCommerce.algolia.lookingSimilar)
|
|
114
117
|
const resolve: ProductResolver = async (root, args, context, info) => {
|
|
115
118
|
const { objectID, threshold, fallbackParameters, maxRecommendations, queryParameters } =
|
|
116
119
|
await getRecommendationsArgs(root, args, context)
|
|
117
|
-
|
|
120
|
+
const recommendations = await getRecommendations(
|
|
118
121
|
root,
|
|
119
122
|
'Looking_similar_Input',
|
|
120
123
|
{ objectID, threshold, fallbackParameters, maxRecommendations, queryParameters },
|
|
@@ -122,11 +125,12 @@ if (isEnabled(import.meta.graphCommerce.algolia.lookingSimilar)) {
|
|
|
122
125
|
info,
|
|
123
126
|
await createProductMapper(context),
|
|
124
127
|
)
|
|
128
|
+
return recommendations ?? root[fieldName] ?? null
|
|
125
129
|
}
|
|
126
130
|
|
|
127
131
|
productInterfaceTypes.forEach((productType) => {
|
|
128
132
|
if (!resolvers[productType]) resolvers[productType] = {}
|
|
129
|
-
resolvers[productType][
|
|
133
|
+
resolvers[productType][fieldName] = {
|
|
130
134
|
selectionSet: `{ uid }`,
|
|
131
135
|
resolve,
|
|
132
136
|
}
|
|
@@ -134,11 +138,12 @@ if (isEnabled(import.meta.graphCommerce.algolia.lookingSimilar)) {
|
|
|
134
138
|
}
|
|
135
139
|
|
|
136
140
|
if (isEnabled(import.meta.graphCommerce.algolia.frequentlyBoughtTogether)) {
|
|
137
|
-
const
|
|
141
|
+
const fieldName = enumToLocation(import.meta.graphCommerce.algolia.frequentlyBoughtTogether)
|
|
142
|
+
|
|
143
|
+
const resolve: ProductResolver = async (root, args, context, info) => {
|
|
138
144
|
const { objectID, threshold, maxRecommendations, queryParameters } =
|
|
139
145
|
await getRecommendationsArgs(root, args, context)
|
|
140
|
-
|
|
141
|
-
return getRecommendations(
|
|
146
|
+
const recommendations = await getRecommendations(
|
|
142
147
|
root,
|
|
143
148
|
'Frequently_bought_together_Input',
|
|
144
149
|
{ objectID, threshold, maxRecommendations, queryParameters },
|
|
@@ -146,13 +151,12 @@ if (isEnabled(import.meta.graphCommerce.algolia.frequentlyBoughtTogether)) {
|
|
|
146
151
|
info,
|
|
147
152
|
await createProductMapper(context),
|
|
148
153
|
)
|
|
154
|
+
return recommendations ?? root[fieldName] ?? null
|
|
149
155
|
}
|
|
150
156
|
|
|
151
157
|
productInterfaceTypes.forEach((productType) => {
|
|
152
158
|
if (!resolvers[productType]) resolvers[productType] = {}
|
|
153
|
-
resolvers[productType][
|
|
154
|
-
enumToLocation(import.meta.graphCommerce.algolia.frequentlyBoughtTogether)
|
|
155
|
-
] = resolver
|
|
159
|
+
resolvers[productType][fieldName] = { selectionSet: `{ uid }`, resolve }
|
|
156
160
|
})
|
|
157
161
|
}
|
|
158
162
|
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@graphcommerce/algolia-recommend",
|
|
3
3
|
"homepage": "https://www.graphcommerce.org/",
|
|
4
4
|
"repository": "github:graphcommerce-org/graphcommerce",
|
|
5
|
-
"version": "9.0.0-canary.
|
|
5
|
+
"version": "9.0.0-canary.87",
|
|
6
6
|
"sideEffects": false,
|
|
7
7
|
"prettier": "@graphcommerce/prettier-config-pwa",
|
|
8
8
|
"eslintConfig": {
|
|
@@ -15,11 +15,11 @@
|
|
|
15
15
|
"generate": "tsx scripts/generate-recommend-spec.mts"
|
|
16
16
|
},
|
|
17
17
|
"peerDependencies": {
|
|
18
|
-
"@graphcommerce/algolia-products": "^9.0.0-canary.
|
|
19
|
-
"@graphcommerce/graphql": "^9.0.0-canary.
|
|
20
|
-
"@graphcommerce/graphql-mesh": "^9.0.0-canary.
|
|
21
|
-
"@graphcommerce/next-config": "^9.0.0-canary.
|
|
22
|
-
"@graphcommerce/next-ui": "^9.0.0-canary.
|
|
18
|
+
"@graphcommerce/algolia-products": "^9.0.0-canary.87",
|
|
19
|
+
"@graphcommerce/graphql": "^9.0.0-canary.87",
|
|
20
|
+
"@graphcommerce/graphql-mesh": "^9.0.0-canary.87",
|
|
21
|
+
"@graphcommerce/next-config": "^9.0.0-canary.87",
|
|
22
|
+
"@graphcommerce/next-ui": "^9.0.0-canary.87",
|
|
23
23
|
"react": "^18.2.0"
|
|
24
24
|
},
|
|
25
25
|
"devDependencies": {
|