Replaces MongoDB support with PostgreSQL (#151)
- All schemas have been rewritten to a relational model - All services have been rewritten to accommodate the new data model - Adds idempotency keys to core endpoints allowing you to retry requests with no additional side effects - Adds staged jobs to avoid putting jobs in the queue when transactions abort - Adds atomic transactions to all methods with access to the data layer Co-authored-by: Oliver Windall Juhl <oliver@mrbltech.com>
This commit is contained in:
co-authored by
Oliver Windall Juhl
parent
5f819486fc
commit
f1baca3cbd
@@ -46,21 +46,16 @@ class ContentfulService extends BaseService {
|
||||
}
|
||||
}
|
||||
|
||||
async getVariantEntries_(productId) {
|
||||
async getVariantEntries_(variants) {
|
||||
try {
|
||||
const productVariants = await this.productService_.retrieveVariants(
|
||||
productId
|
||||
)
|
||||
|
||||
const contentfulVariants = await Promise.all(
|
||||
productVariants.map((variant) =>
|
||||
variants.map((variant) =>
|
||||
this.updateProductVariantInContentful(variant)
|
||||
)
|
||||
)
|
||||
|
||||
return contentfulVariants
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
@@ -118,79 +113,33 @@ class ContentfulService extends BaseService {
|
||||
|
||||
async createProductInContentful(product) {
|
||||
try {
|
||||
const p = await this.productService_.retrieve(product.id, {
|
||||
relations: ["variants", "options"],
|
||||
})
|
||||
|
||||
const environment = await this.getContentfulEnvironment_()
|
||||
const variantEntries = await this.getVariantEntries_(product._id)
|
||||
const variantEntries = await this.getVariantEntries_(p.variants)
|
||||
const variantLinks = this.getVariantLinks_(variantEntries)
|
||||
|
||||
const fieldsObject = {
|
||||
title: {
|
||||
"en-US": product.title,
|
||||
},
|
||||
variants: {
|
||||
"en-US": variantLinks,
|
||||
},
|
||||
options: {
|
||||
"en-US": product.options,
|
||||
},
|
||||
objectId: {
|
||||
"en-US": product._id,
|
||||
},
|
||||
}
|
||||
|
||||
if (product.images.length > 0) {
|
||||
const imageLinks = await this.createImageAssets(product)
|
||||
|
||||
const thumbnailAsset = await environment.createAsset({
|
||||
fields: {
|
||||
title: {
|
||||
"en-US": `${product.title}`,
|
||||
},
|
||||
description: {
|
||||
"en-US": "",
|
||||
},
|
||||
file: {
|
||||
"en-US": {
|
||||
contentType: "image/xyz",
|
||||
fileName: product.thumbnail,
|
||||
upload: product.thumbnail,
|
||||
},
|
||||
},
|
||||
const result = await environment.createEntryWithId("product", p.id, {
|
||||
fields: {
|
||||
title: {
|
||||
"en-US": p.title,
|
||||
},
|
||||
})
|
||||
|
||||
await thumbnailAsset.processForAllLocales()
|
||||
|
||||
const thumbnailLink = {
|
||||
sys: {
|
||||
type: "Link",
|
||||
linkType: "Asset",
|
||||
id: thumbnailAsset.sys.id,
|
||||
variants: {
|
||||
"en-US": variantLinks,
|
||||
},
|
||||
}
|
||||
|
||||
fieldsObject.thumbnail = {
|
||||
"en-US": thumbnailLink,
|
||||
}
|
||||
|
||||
if (imageLinks) {
|
||||
fieldsObject.images = {
|
||||
"en-US": imageLinks,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const result = await environment.createEntryWithId(
|
||||
"product",
|
||||
product._id,
|
||||
{
|
||||
fields: {
|
||||
...fieldsObject,
|
||||
options: {
|
||||
"en-US": p.options,
|
||||
},
|
||||
}
|
||||
)
|
||||
objectId: {
|
||||
"en-US": p.id,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
const ignoreIds = (await this.getIgnoreIds_("product")) || []
|
||||
ignoreIds.push(product._id)
|
||||
ignoreIds.push(product.id)
|
||||
this.redis_.set("product_ignore_ids", JSON.stringify(ignoreIds))
|
||||
return result
|
||||
} catch (error) {
|
||||
@@ -200,33 +149,37 @@ class ContentfulService extends BaseService {
|
||||
|
||||
async createProductVariantInContentful(variant) {
|
||||
try {
|
||||
const v = await this.productVariantService_.retrieve(variant.id, {
|
||||
relations: ["prices", "options"],
|
||||
})
|
||||
|
||||
const environment = await this.getContentfulEnvironment_()
|
||||
const result = await environment.createEntryWithId(
|
||||
"productVariant",
|
||||
variant._id,
|
||||
v.id,
|
||||
{
|
||||
fields: {
|
||||
title: {
|
||||
"en-US": variant.title,
|
||||
"en-US": v.title,
|
||||
},
|
||||
sku: {
|
||||
"en-US": variant.sku,
|
||||
"en-US": v.sku,
|
||||
},
|
||||
prices: {
|
||||
"en-US": variant.prices,
|
||||
"en-US": v.prices,
|
||||
},
|
||||
options: {
|
||||
"en-US": variant.options,
|
||||
"en-US": v.options,
|
||||
},
|
||||
objectId: {
|
||||
"en-US": variant._id,
|
||||
"en-US": v.id,
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
const ignoreIds = (await this.getIgnoreIds_("product_variant")) || []
|
||||
ignoreIds.push(variant._id)
|
||||
ignoreIds.push(v.id)
|
||||
this.redis_.set("product_variant_ignore_ids", JSON.stringify(ignoreIds))
|
||||
return result
|
||||
} catch (error) {
|
||||
@@ -238,12 +191,12 @@ class ContentfulService extends BaseService {
|
||||
try {
|
||||
const ignoreIds = (await this.getIgnoreIds_("product")) || []
|
||||
|
||||
if (ignoreIds.includes(product._id)) {
|
||||
const newIgnoreIds = ignoreIds.filter((id) => id !== product._id)
|
||||
if (ignoreIds.includes(product.id)) {
|
||||
const newIgnoreIds = ignoreIds.filter((id) => id !== product.id)
|
||||
this.redis_.set("product_ignore_ids", JSON.stringify(newIgnoreIds))
|
||||
return
|
||||
} else {
|
||||
ignoreIds.push(product._id)
|
||||
ignoreIds.push(product.id)
|
||||
this.redis_.set("product_ignore_ids", JSON.stringify(ignoreIds))
|
||||
}
|
||||
|
||||
@@ -251,27 +204,31 @@ class ContentfulService extends BaseService {
|
||||
// check if product exists
|
||||
let productEntry = undefined
|
||||
try {
|
||||
productEntry = await environment.getEntry(product._id)
|
||||
productEntry = await environment.getEntry(product.id)
|
||||
} catch (error) {
|
||||
return this.createProductInContentful(product)
|
||||
}
|
||||
|
||||
const variantEntries = await this.getVariantEntries_(product._id)
|
||||
const p = await this.productService_.retrieve(product.id, {
|
||||
relations: ["options", "variants"],
|
||||
})
|
||||
|
||||
const variantEntries = await this.getVariantEntries_(p.variants)
|
||||
const variantLinks = this.getVariantLinks_(variantEntries)
|
||||
|
||||
const productEntryFields = {
|
||||
...productEntry.fields,
|
||||
title: {
|
||||
"en-US": product.title,
|
||||
"en-US": p.title,
|
||||
},
|
||||
options: {
|
||||
"en-US": product.options,
|
||||
"en-US": p.options,
|
||||
},
|
||||
variants: {
|
||||
"en-US": variantLinks,
|
||||
},
|
||||
objectId: {
|
||||
"en-US": product._id,
|
||||
"en-US": p.id,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -290,15 +247,15 @@ class ContentfulService extends BaseService {
|
||||
try {
|
||||
const ignoreIds = (await this.getIgnoreIds_("product_variant")) || []
|
||||
|
||||
if (ignoreIds.includes(variant._id)) {
|
||||
const newIgnoreIds = ignoreIds.filter((id) => id !== variant._id)
|
||||
if (ignoreIds.includes(variant.id)) {
|
||||
const newIgnoreIds = ignoreIds.filter((id) => id !== variant.id)
|
||||
this.redis_.set(
|
||||
"product_variant_ignore_ids",
|
||||
JSON.stringify(newIgnoreIds)
|
||||
)
|
||||
return
|
||||
} else {
|
||||
ignoreIds.push(variant._id)
|
||||
ignoreIds.push(variant.id)
|
||||
this.redis_.set("product_variant_ignore_ids", JSON.stringify(ignoreIds))
|
||||
}
|
||||
|
||||
@@ -307,32 +264,31 @@ class ContentfulService extends BaseService {
|
||||
let variantEntry = undefined
|
||||
// if not, we create a new one
|
||||
try {
|
||||
variantEntry = await environment.getEntry(variant._id)
|
||||
variantEntry = await environment.getEntry(variant.id)
|
||||
} catch (error) {
|
||||
return this.createProductVariantInContentful(variant)
|
||||
}
|
||||
|
||||
const cleanPrices = variant.prices.map((price) => ({
|
||||
...price,
|
||||
sale_amount: price.sale_amount || undefined,
|
||||
}))
|
||||
const v = await this.productVariantService_.retrieve(variant.id, {
|
||||
relations: ["prices", "options"],
|
||||
})
|
||||
|
||||
const variantEntryFields = {
|
||||
...variantEntry.fields,
|
||||
title: {
|
||||
"en-US": variant.title,
|
||||
"en-US": v.title,
|
||||
},
|
||||
sku: {
|
||||
"en-US": variant.sku,
|
||||
"en-US": v.sku,
|
||||
},
|
||||
options: {
|
||||
"en-US": variant.options,
|
||||
"en-US": v.options,
|
||||
},
|
||||
prices: {
|
||||
"en-US": cleanPrices,
|
||||
"en-US": v.prices,
|
||||
},
|
||||
objectId: {
|
||||
"en-US": variant._id,
|
||||
"en-US": v.id,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
class ContentfulSubscriber {
|
||||
constructor({ contentfulService, eventBusService }) {
|
||||
constructor({
|
||||
contentfulService,
|
||||
productVariantService,
|
||||
productService,
|
||||
eventBusService,
|
||||
}) {
|
||||
this.productVariantService_ = productVariantService
|
||||
this.productService_ = productService
|
||||
this.contentfulService_ = contentfulService
|
||||
this.eventBus_ = eventBusService
|
||||
|
||||
|
||||
Reference in New Issue
Block a user