@moltin/gatsby-source-moltin
Version:
Gatsby source plugin for building Moltin powered eCommerce websites
402 lines (339 loc) • 9.59 kB
JavaScript
const { MoltinClient } = require('@moltin/request')
const { createRemoteFileNode } = require('gatsby-source-filesystem')
const merge = require('deepmerge')
const { name: application } = require('./package')
exports.sourceNodes = async (
{ actions, createContentDigest },
{ client_id }
) => {
const { createNode } = actions
const moltin = new MoltinClient({
client_id,
application,
})
const processProduct = ({
product,
main_images,
categories,
collections,
brands,
files,
}) => {
const nodeContent = JSON.stringify(product)
let categoriesArray
let collectionsArray
let brandsArray
let filesArray
let mainImageHref
let parentId
let childrenArray
if (product.relationships) {
if (product.relationships.main_image) {
const image = main_images.find(
(main_image) =>
main_image.id === product.relationships.main_image.data.id
)
if (image && image.link) {
const {
link: { href },
} = image
mainImageHref = href
}
}
if (product.relationships.categories) {
categoriesArray = product.relationships.categories.data.map(
(relationship) => {
const category = categories.find(
(category) => category.id === relationship.id
)
if (category) {
return {
...category,
}
}
}
)
}
if (product.relationships.collections) {
collectionsArray = product.relationships.collections.data.map(
(relationship) => {
const collection = collections.find(
(collection) => collection.id === relationship.id
)
if (collection) {
return {
...collection,
}
}
}
)
}
if (product.relationships.brands) {
brandsArray = product.relationships.brands.data.map((relationship) => {
const brand = brands.find((brand) => brand.id === relationship.id)
if (brand) {
return {
...brand,
}
}
})
}
if (product.relationships.files) {
filesArray = product.relationships.files.data.map((relationship) => {
const file = files.find((file) => file.id === relationship.id)
if (file) {
return {
id: file.id,
href: file.link.href,
}
}
})
}
if (product.relationships.parent) {
parentId = product.relationships.parent.data.id
}
if (product.relationships.children) {
childrenArray = product.relationships.children.data.map((rel) => rel.id)
}
}
if (product.meta.variation_matrix) {
const { variation_matrix } = product.meta
product.meta.variation_matrix = JSON.stringify(variation_matrix)
}
const nodeData = {
...product,
id: product.id,
brands: brandsArray,
categories: categoriesArray,
collections: collectionsArray,
files: filesArray,
mainImageHref,
parent: parentId || null,
children: childrenArray || [],
internal: {
type: `MoltinProduct`,
content: nodeContent,
contentDigest: createContentDigest(product),
},
}
return nodeData
}
const processCategory = ({ category }) => {
const nodeContent = JSON.stringify(category)
let parentId
let childrenArray
if (category.relationships) {
if (category.relationships.parent) {
parentId = category.relationships.parent.data[0].id
}
if (category.relationships.children) {
childrenArray = category.relationships.children.data.map(
(rel) => rel.id
)
}
}
const nodeData = {
...category,
id: category.id,
parent: parentId || null,
children: childrenArray || [],
internal: {
type: `MoltinCategory`,
content: nodeContent,
contentDigest: createContentDigest(category),
},
}
return nodeData
}
const processCollection = ({ collection }) => {
const nodeContent = JSON.stringify(collection)
const nodeData = {
...collection,
id: collection.id,
parent: null,
children: [],
internal: {
type: `MoltinCollection`,
content: nodeContent,
contentDigest: createContentDigest(collection),
},
}
return nodeData
}
const processBrand = ({ brand }) => {
const nodeContent = JSON.stringify(brand)
const nodeData = {
...brand,
id: brand.id,
parent: null,
children: [],
internal: {
type: `MoltinBrand`,
content: nodeContent,
contentDigest: createContentDigest(brand),
},
}
return nodeData
}
const getPaginatedResource = async (resource, data = {}, search = '') => {
try {
const response = await moltin.get(`${resource}${search}`)
if (response.data === undefined || response.data.length === 0)
return response
const {
links: { next },
} = response
let merged = merge(data, response)
if (next) {
const { search } = new URL(next)
merged = getPaginatedResource(resource, merged, search)
}
return merged
} catch (error) {
console.error('gatsby-source-moltin: ERROR', error)
}
}
const getProductsById = async (productsArray = []) => {
let products = []
try {
for (const product of productsArray) {
const response = await moltin.get(`products/${product.id}`)
const responseProduct = response.data
responseProduct.relationships.children = product.relationships.children
products.push(responseProduct)
}
} catch (error) {
console.error('gatsby-source-moltin: ERROR', error)
}
return products
}
const { data: brands } = await moltin.get('brands')
const { data: categories } = await getPaginatedResource('categories')
const { data: collections } = await getPaginatedResource('collections')
const {
data: productsListing,
included: { main_images = {}, files = [] } = {},
} = await getPaginatedResource('products', {}, `?include=main_image,files`)
const products = await getProductsById(productsListing)
const createCategories = async ({ categories }) => {
categories.forEach(async (category) =>
createNode(await processCategory({ category }))
)
}
const createCollections = async ({ collections }) => {
collections.forEach(async (collection) =>
createNode(await processCollection({ collection }))
)
}
const createBrands = async ({ brands }) => {
brands.forEach(async (brand) => createNode(await processBrand({ brand })))
}
const createProducts = async ({
products,
main_images,
categories,
collections,
brands,
files,
}) => {
products.forEach(async (product) =>
createNode(
await processProduct({
product,
main_images,
categories,
collections,
brands,
files,
})
)
)
}
await createProducts({
products,
main_images,
categories,
collections,
brands,
files,
})
await createCollections({ collections })
await createCategories({ categories })
await createBrands({ brands })
}
exports.onCreateNode = async ({
node,
actions,
store,
cache,
createNodeId,
getNode,
}) => {
const { createNode } = actions
if (node.internal.type === `MoltinProduct` && node.mainImageHref) {
let mainImageNode
try {
mainImageNode = await createRemoteFileNode({
url: node.mainImageHref,
store,
cache,
createNode,
createNodeId,
})
} catch (e) {
console.error('gatsby-source-moltin: ERROR', e)
}
if (mainImageNode) {
node.mainImage___NODE = mainImageNode.id
}
}
if (node.internal.type === `MoltinProduct` && node.files) {
const getFileNodes = async () => {
const fileIds = []
let imageNodes = node.files
if (node.mainImageHref) {
imageNodes = imageNodes.filter(
(fileNode) => node.mainImageHref !== fileNode.href
)
}
const imageFetchingPromises = imageNodes.map(async (fileNode) => {
let imageNode
try {
imageNode = await createRemoteFileNode({
url: fileNode.href,
store,
cache,
createNode,
createNodeId,
})
} catch (e) {
console.error('gatsby-source-moltin: ERROR', e)
}
fileIds.push(imageNode.id)
})
await Promise.all(imageFetchingPromises)
return fileIds
}
node.images___NODE = await getFileNodes()
}
if (
[`MoltinBrand`, `MoltinCategory`, `MoltinCollection`].includes(
node.internal.type
) &&
node.relationships &&
node.relationships.products
) {
const getProductNodes = async () => {
const productIds = node.relationships.products.data.map(
(product) => product.id
)
let productNodes = []
await productIds.forEach(async (productId) => {
const productNode = await getNode(productId)
if (productNode) productNodes.push(productNode.id)
})
return productNodes
}
node.products___NODE = await getProductNodes()
}
}