@graphcommerce/magento-graphql 9.0.0-canary.98 → 9.0.0-canary.99

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 CHANGED
@@ -1,5 +1,13 @@
1
1
  # Change Log
2
2
 
3
+ ## 9.0.0-canary.99
4
+
5
+ ### Minor Changes
6
+
7
+ - [#2416](https://github.com/graphcommerce-org/graphcommerce/pull/2416) [`651eea0`](https://github.com/graphcommerce-org/graphcommerce/commit/651eea0bdda1ed0f46f4c73d7edf52c8c1da5b54) - Created a new field for products: `custom_attribute(attribute_code: "attribute_code")` to retrieve attribute option value labels. This field is only available in Magento 2.4.7 and up. ([@paales](https://github.com/paales))
8
+
9
+ - [#2416](https://github.com/graphcommerce-org/graphcommerce/pull/2416) [`53af256`](https://github.com/graphcommerce-org/graphcommerce/commit/53af25671d3aca7f3daa2dd45ccd2237697e9254) - Added an `attribute`-field to `AttributeValueInterface` to be able to retrieve attribute metadata from the value of an attribute. ([@paales](https://github.com/paales))
10
+
3
11
  ## 9.0.0-canary.98
4
12
 
5
13
  ## 9.0.0-canary.97
@@ -0,0 +1,31 @@
1
+ import fragments from '@graphcommerce/graphql/generated/fragments.json'
2
+ import type {
3
+ AttributeValueInterfaceResolvers,
4
+ MeshContext,
5
+ Resolvers,
6
+ } from '@graphcommerce/graphql-mesh'
7
+ import { customAttributeMetadataV2 } from './customAttributeMetadataV2'
8
+
9
+ type AttributeValueResolver = Pick<AttributeValueInterfaceResolvers<MeshContext>, 'attribute'>
10
+
11
+ const attributeValueResolver: AttributeValueResolver = {
12
+ attribute: {
13
+ selectionSet: `{ code }`,
14
+ resolve: async (root, _, context) =>
15
+ root.attribute ??
16
+ (await customAttributeMetadataV2(
17
+ { attribute_code: root.code, entity_type: 'catalog_product' },
18
+ context,
19
+ )),
20
+ },
21
+ }
22
+
23
+ type AttributeValueTypes = NonNullable<
24
+ Awaited<ReturnType<AttributeValueInterfaceResolvers['__resolveType']>>
25
+ >
26
+ const attributeValueTypes = fragments.possibleTypes.AttributeValueInterface as AttributeValueTypes[]
27
+ const resolvers: Resolvers = {}
28
+ attributeValueTypes.forEach((attributeValueType) => {
29
+ if (!resolvers[attributeValueType]) resolvers[attributeValueType] = attributeValueResolver
30
+ })
31
+ export default resolvers
@@ -0,0 +1,68 @@
1
+ import type { MeshContext, CustomAttributeMetadataInterface } from '@graphcommerce/graphql-mesh'
2
+
3
+ export type CustomAttributeInput = { attribute_code: string; entity_type: 'catalog_product' }
4
+
5
+ export async function customAttributeMetadataV2(
6
+ input: CustomAttributeInput,
7
+ context: MeshContext,
8
+ ): Promise<CustomAttributeMetadataInterface | null> {
9
+ const cacheKey = `customAttributeMetadata-${input.entity_type}-${input.attribute_code}`
10
+ const cached = await context.cache.get(cacheKey)
11
+ if (cached) return cached
12
+
13
+ if (input.entity_type !== 'catalog_product')
14
+ throw Error('Only catalog_product is supported at this moment')
15
+
16
+ if (
17
+ !('customAttributeMetadataV2' in context.m2.Query) ||
18
+ typeof context.m2.Query.customAttributeMetadataV2 !== 'function'
19
+ )
20
+ throw Error('This field is only available in Magento 2.4.7 and up')
21
+
22
+ const attribute = await context.m2.Query.customAttributeMetadataV2({
23
+ context,
24
+ key: input,
25
+ argsFromKeys: (attributes) => ({ attributes }),
26
+ selectionSet: /* GraphQL */ `
27
+ {
28
+ items {
29
+ __typename
30
+ code
31
+ label
32
+ default_value
33
+ entity_type
34
+ frontend_class
35
+ frontend_input
36
+ is_required
37
+ is_unique
38
+ label
39
+ ... on CatalogAttributeMetadata {
40
+ apply_to
41
+ is_comparable
42
+ is_filterable
43
+ is_filterable_in_search
44
+ is_html_allowed_on_front
45
+ is_searchable
46
+ is_used_for_price_rules
47
+ is_used_for_promo_rules
48
+ is_visible_in_advanced_search
49
+ is_visible_on_front
50
+ is_wysiwyg_enabled
51
+ used_in_product_listing
52
+ }
53
+ options {
54
+ label
55
+ is_default
56
+ value
57
+ }
58
+ }
59
+ }
60
+ `,
61
+ valuesFromResults: (res, attributes) =>
62
+ attributes.map((attr) => res.items?.find((v) => v?.code === attr.attribute_code)),
63
+ })
64
+
65
+ // Cache for 1 hour
66
+ await context.cache.set(cacheKey, attribute, { ttl: 60 * 60 })
67
+ return attribute ?? null
68
+ }
@@ -0,0 +1,47 @@
1
+ import fragments from '@graphcommerce/graphql/generated/fragments.json'
2
+ import type { MeshContext, ProductInterfaceResolvers, Resolvers } from '@graphcommerce/graphql-mesh'
3
+ import { Kind } from 'graphql'
4
+ import { CustomAttributeInput, customAttributeMetadataV2 } from './customAttributeMetadataV2'
5
+
6
+ type CustomAttributeV2Resolver = Pick<ProductInterfaceResolvers<MeshContext>, 'custom_attributeV2'>
7
+
8
+ const customAttributeV2Resolver: CustomAttributeV2Resolver = {
9
+ custom_attributeV2: {
10
+ selectionSet: (fieldNode) => ({
11
+ kind: Kind.SELECTION_SET,
12
+ selections: (fieldNode.arguments ?? [])
13
+ .map((arg) => arg.value)
14
+ .filter((value) => value.kind === Kind.STRING)
15
+ .map((value) => ({ kind: Kind.FIELD, name: { kind: Kind.NAME, value: value.value } })),
16
+ }),
17
+ resolve: async (root, { attribute_code: code }, context) => {
18
+ const value = String(root[code] ?? '')
19
+ const input: CustomAttributeInput = { attribute_code: code, entity_type: 'catalog_product' }
20
+ const attribute = await customAttributeMetadataV2(input, context)
21
+
22
+ if (!attribute || !value) return null
23
+
24
+ if (
25
+ attribute?.frontend_input &&
26
+ ['SELECT', 'MULTISELECT'].includes(attribute.frontend_input)
27
+ ) {
28
+ const values = attribute.frontend_input === 'SELECT' ? [value] : value.split(',')
29
+ const selected_options = values.map((v) => {
30
+ const found = attribute.options?.find((o) => o?.value === v || o?.label === v)
31
+ if (!found) return null
32
+ return { ...found, __typename: 'AttributeSelectedOption' }
33
+ })
34
+ return { __typename: 'AttributeSelectedOptions', code, selected_options, attribute }
35
+ }
36
+ return { __typename: 'AttributeValue', code, value, attribute }
37
+ },
38
+ },
39
+ }
40
+
41
+ type ProductTypes = NonNullable<Awaited<ReturnType<ProductInterfaceResolvers['__resolveType']>>>
42
+ const productInterfaceTypes = fragments.possibleTypes.ProductInterface as ProductTypes[]
43
+ const resolvers: Resolvers = {}
44
+ productInterfaceTypes.forEach((productType) => {
45
+ if (!resolvers[productType]) resolvers[productType] = customAttributeV2Resolver
46
+ })
47
+ export default resolvers
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@graphcommerce/magento-graphql",
3
3
  "homepage": "https://www.graphcommerce.org/",
4
4
  "repository": "github:graphcommerce-org/graphcommerce",
5
- "version": "9.0.0-canary.98",
5
+ "version": "9.0.0-canary.99",
6
6
  "sideEffects": false,
7
7
  "main": "index.ts",
8
8
  "prettier": "@graphcommerce/prettier-config-pwa",
@@ -13,10 +13,11 @@
13
13
  }
14
14
  },
15
15
  "peerDependencies": {
16
- "@graphcommerce/eslint-config-pwa": "^9.0.0-canary.98",
17
- "@graphcommerce/graphql": "^9.0.0-canary.98",
18
- "@graphcommerce/prettier-config-pwa": "^9.0.0-canary.98",
19
- "@graphcommerce/typescript-config-pwa": "^9.0.0-canary.98",
16
+ "@graphcommerce/eslint-config-pwa": "^9.0.0-canary.99",
17
+ "@graphcommerce/graphql": "^9.0.0-canary.99",
18
+ "@graphcommerce/prettier-config-pwa": "^9.0.0-canary.99",
19
+ "@graphcommerce/typescript-config-pwa": "^9.0.0-canary.99",
20
+ "graphql": "^16.0.0",
20
21
  "next": "*",
21
22
  "react": "^18.2.0",
22
23
  "react-dom": "^18.2.0"
@@ -0,0 +1,24 @@
1
+ import type { meshConfig as meshConfigBase } from '@graphcommerce/graphql-mesh/meshConfig'
2
+ import type { FunctionPlugin, PluginConfig } from '@graphcommerce/next-config'
3
+
4
+ export const config: PluginConfig = {
5
+ module: '@graphcommerce/graphql-mesh/meshConfig',
6
+ type: 'function',
7
+ }
8
+
9
+ export const meshConfig: FunctionPlugin<typeof meshConfigBase> = (
10
+ prev,
11
+ baseConfig,
12
+ graphCommerceConfig,
13
+ ) =>
14
+ prev(
15
+ {
16
+ ...baseConfig,
17
+ additionalResolvers: [
18
+ ...(baseConfig.additionalResolvers ?? []),
19
+ '@graphcommerce/magento-graphql/mesh/customAttributeV2Resolver.ts',
20
+ '@graphcommerce/magento-graphql/mesh/attributeValueResolver.ts',
21
+ ],
22
+ },
23
+ graphCommerceConfig,
24
+ )
@@ -0,0 +1,9 @@
1
+ extend interface AttributeValueInterface {
2
+ attribute: CustomAttributeMetadataInterface
3
+ }
4
+ extend type AttributeValue {
5
+ attribute: CustomAttributeMetadataInterface
6
+ }
7
+ extend type AttributeSelectedOptions {
8
+ attribute: CustomAttributeMetadataInterface
9
+ }
@@ -0,0 +1,49 @@
1
+ extend interface ProductInterface {
2
+ """
3
+ This is the singular version of the custom_attributesV2 and allows selecting a single attribute option value.
4
+ Available only after Magento 2.4.7 as it relies on the customAttributesV2 query.
5
+ """
6
+ custom_attributeV2(attribute_code: String!): AttributeValueInterface
7
+ }
8
+ extend type SimpleProduct {
9
+ """
10
+ This is the singular version of the custom_attributesV2 and allows selecting a single attribute option value.
11
+ Available only after Magento 2.4.7 as it relies on the customAttributesV2 query.
12
+ """
13
+ custom_attributeV2(attribute_code: String!): AttributeValueInterface
14
+ }
15
+ extend type ConfigurableProduct {
16
+ """
17
+ This is the singular version of the custom_attributesV2 and allows selecting a single attribute option value.
18
+ Available only after Magento 2.4.7 as it relies on the customAttributesV2 query.
19
+ """
20
+ custom_attributeV2(attribute_code: String!): AttributeValueInterface
21
+ }
22
+ extend type BundleProduct {
23
+ """
24
+ This is the singular version of the custom_attributesV2 and allows selecting a single attribute option value.
25
+ Available only after Magento 2.4.7 as it relies on the customAttributesV2 query.
26
+ """
27
+ custom_attributeV2(attribute_code: String!): AttributeValueInterface
28
+ }
29
+ extend type DownloadableProduct {
30
+ """
31
+ This is the singular version of the custom_attributesV2 and allows selecting a single attribute option value.
32
+ Available only after Magento 2.4.7 as it relies on the customAttributesV2 query.
33
+ """
34
+ custom_attributeV2(attribute_code: String!): AttributeValueInterface
35
+ }
36
+ extend type VirtualProduct {
37
+ """
38
+ This is the singular version of the custom_attributesV2 and allows selecting a single attribute option value.
39
+ Available only after Magento 2.4.7 as it relies on the customAttributesV2 query.
40
+ """
41
+ custom_attributeV2(attribute_code: String!): AttributeValueInterface
42
+ }
43
+ extend type GroupedProduct {
44
+ """
45
+ This is the singular version of the custom_attributesV2 and allows selecting a single attribute option value.
46
+ Available only after Magento 2.4.7 as it relies on the customAttributesV2 query.
47
+ """
48
+ custom_attributeV2(attribute_code: String!): AttributeValueInterface
49
+ }
@@ -0,0 +1,7 @@
1
+ type Query {
2
+ """
3
+ Retrieve EAV attributes metadata.
4
+ """
5
+ customAttributeMetadataV2(attributes: [AttributeInput!]): AttributesMetadataOutput!
6
+ @deprecated(reason: "Magento >= 2.4.7")
7
+ }