Skip to content

Commit

Permalink
feat(sync-utils): type safety improvements, fix syncing problems
Browse files Browse the repository at this point in the history
  • Loading branch information
good-idea committed Jun 8, 2020
1 parent cab4293 commit ebaf0e1
Show file tree
Hide file tree
Showing 10 changed files with 254 additions and 188 deletions.
54 changes: 34 additions & 20 deletions packages/sync-utils/src/sanity/archive.ts
Original file line number Diff line number Diff line change
@@ -1,33 +1,47 @@
import { SanityClient, SanityShopifyDocument } from '@sane-shopify/types'
import { isSanityProduct, isSanityCollection } from '../typeGuards'

const getRelationshipsToRemove = (
sourceDoc: SanityShopifyDocument,
relatedDoc: SanityShopifyDocument
) => {
if (isSanityProduct(relatedDoc)) {
const related = relatedDoc.collections.find(
(reference) => reference._ref === sourceDoc._id
)
if (!related) return
const relationshipsToRemove = [`collections[_key=="${related._key}"]`]
return relationshipsToRemove
} else if (isSanityCollection(relatedDoc)) {
const related = relatedDoc.products.find(
(reference) => reference._ref === sourceDoc._id
)
if (!related) return
const relationshipsToRemove = [`products[_key=="${related._key}"]`]
return relationshipsToRemove
}
throw new Error('Could not get relationships for this document')
}

export const createArchiveSanityDocument = (client: SanityClient) => async (
doc: SanityShopifyDocument
): Promise<SanityShopifyDocument> => {
const relationshipsKey =
doc.sourceData.__typename === 'Collection' ? 'products' : 'collections'

const removeRelationships = async (relatedDoc?: SanityShopifyDocument) => {
if (!relatedDoc) return
const type =
relatedDoc.sourceData.__typename === 'Collection'
? 'products'
: 'collections'

const related = relatedDoc[type].find(
(reference) => reference._ref === doc._id
)
if (!related) return

const relationshipsToRemove = [`${type}[_key=="${related._key}"]`]

await client
.patch(relatedDoc._id)
// @ts-ignore
.unset(relationshipsToRemove)
.commit()
const removeRelationships = async (relatedDoc: SanityShopifyDocument) => {
const relationshipsToRemove = getRelationshipsToRemove(doc, relatedDoc)
if (!relationshipsToRemove) return
await client.patch(relatedDoc._id).unset(relationshipsToRemove).commit()
}
const relationships = doc[relationshipsKey]

const relationships = isSanityProduct(doc)
? doc.collections
: isSanityCollection(doc)
? doc.products
: undefined
if (!relationships) return doc
// @ts-ignore
await Promise.all(relationships.map((r) => removeRelationships(r)))
try {
await client.delete(doc._id)
Expand Down
40 changes: 28 additions & 12 deletions packages/sync-utils/src/sanity/syncRelationships.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import {
SanityPair,
SanityShopifyDocument,
} from '@sane-shopify/types'
import { isSanityProduct, isSanityCollection } from '../typeGuards'
import { definitely } from '../utils'

const arrayify = <T>(i: T | T[]) => (Array.isArray(i) ? i : [i])

Expand All @@ -20,21 +22,27 @@ export const createRemoveRelationships = (
from: SanityShopifyDocument,
toRemove: SanityShopifyDocument | SanityShopifyDocument[]
): Promise<null> => {
const type = from._type === 'shopifyProduct' ? 'collections' : 'products'
const keys =
from._type === 'shopifyProduct' ? 'collectionKeys' : 'productKeys'
const related = isSanityProduct(from)
? from.collections
: isSanityCollection(from)
? from.products
: []

const relationshipsToRemove = arrayify(toRemove)
.map((itemToRemove) =>
from[keys].find((reference) => reference._ref === itemToRemove._id)
// @ts-ignore
related.find((reference) => reference._ref === itemToRemove._id)
)
.map((reference) => `${type}[_key=="${reference._key}"]`)
await client
.patch(from._id)
// @ts-ignore
.unset(relationshipsToRemove)
.commit()
.map((reference) =>
reference && isSanityProduct(from)
? `collections[_key=="${reference._key}"]`
: reference && isSanityCollection(from)
? `products[_key=${reference._key}]`
: ''
)
.filter(Boolean)

await client.patch(from._id).unset(relationshipsToRemove).commit()
return null
}

Expand All @@ -47,13 +55,18 @@ export const createSyncRelationships = (
const toDocs = arrayify(to).map(removeDraftId)

const aToBKey = from._type === 'shopifyProduct' ? 'collections' : 'products'
const existingRelationships: SanityShopifyDocument[] = from[aToBKey] || []
const existingRelationships = isSanityProduct(from)
? from.collections || []
: isSanityCollection(from)
? from.products || []
: []
// determine if the FROM doc already has the
// links in place. If so, skip the patch.
const alreadyLinked =
toDocs.length === existingRelationships.length &&
toDocs.every((toDoc) =>
Boolean(
// @ts-ignore
existingRelationships.find((er) => toDoc.shopifyId === er.shopifyId)
)
)
Expand All @@ -69,6 +82,7 @@ export const createSyncRelationships = (
const newLinks = toDocs.filter(
(toDoc) =>
!Boolean(
// @ts-ignore
existingRelationships.find((er) => toDoc.shopifyId === er.shopifyId)
)
)
Expand All @@ -81,6 +95,7 @@ export const createSyncRelationships = (
_key: `${toDoc._rev}-${toDoc._id}`,
}))
.filter(
// @ts-ignore
(toDoc) => !existingRelationships.some((er) => er._id === toDoc._ref)
)

Expand All @@ -91,7 +106,9 @@ export const createSyncRelationships = (
.commit()
}

// @ts-ignore
const archivedRelationships = existingRelationships.filter(
// @ts-ignore
(er) => er.archived === true || er.shopifyId === null
)

Expand All @@ -113,7 +130,6 @@ export const createSyncRelationships = (

client
.patch(toDoc._id)
// @ts-ignore
.setIfMissing({ [bToAKey]: [] })
.append(bToAKey, [
{
Expand Down
140 changes: 74 additions & 66 deletions packages/sync-utils/src/sanity/syncSanityDocument.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,24 @@ import {
SanityClient,
SyncOperation,
SanityShopifyDocument,
SanityShopifyDocumentPartial,
SanityShopifyCollectionDocumentPartial,
SanityShopifyProductDocumentPartial,
} from '@sane-shopify/types'
import deepMerge from 'deepmerge'
import { omit } from 'lodash'
import { definitely } from '../utils'
import { prepareDocument, sleep, isMatch, uniqueObjects } from './utils'
import { SanityCache } from './sanityUtils'
import { isSanityProduct, isSanityCollection } from '../typeGuards'

const mergeExistingFields = (
docInfo: any,
existingDoc: SanityShopifyDocument
): SanityShopifyDocument => {
// @ts-ignore
const merged = deepMerge(docInfo, existingDoc)
if (existingDoc._type !== 'shopifyProduct') {
return {
docInfo: SanityShopifyDocumentPartial,
existingDoc: SanityShopifyDocumentPartial
): SanityShopifyDocumentPartial => {
if (isSanityCollection(docInfo) && isSanityCollection(existingDoc)) {
const merged = deepMerge(existingDoc, docInfo)
const doc: SanityShopifyCollectionDocumentPartial = {
...merged,
sourceData: {
...docInfo.sourceData,
Expand All @@ -27,56 +31,68 @@ const mergeExistingFields = (
},
},
}
return doc
}
const variants = docInfo.variants || []
const options = docInfo.options || []
return {
...merged,
sourceData: {
...docInfo.sourceData,
collections: {
...docInfo.sourceData.collections,
edges: uniqueObjects(docInfo.sourceData.collections.edges),
},
images: {
...docInfo.sourceData.images,
edges: uniqueObjects(docInfo.sourceData.images.edges),
if (isSanityProduct(docInfo) && isSanityProduct(existingDoc)) {
const merged = deepMerge(existingDoc, docInfo)
const variants = docInfo.variants || []
const options = docInfo.options || []
const doc: SanityShopifyProductDocumentPartial = {
...merged,
sourceData: {
...docInfo.sourceData,
collections: {
...docInfo.sourceData.collections,
edges: uniqueObjects(
definitely(docInfo?.sourceData?.collections?.edges)
),
},
images: {
...docInfo.sourceData.images,
edges: uniqueObjects(docInfo.sourceData.images.edges),
},
},
},

options: options.map((updatedOption) => {
const existingOption = existingDoc.options
? existingDoc.options.find((o) => o._key === updatedOption._key) || {}
: {}

const existingOptionValues = existingOption.values || []

return {
...existingOption,
...updatedOption,
values: updatedOption.values.map((updatedOptionValue) => {
const existingOptionValue = existingOptionValues.find(
(v) => v._key === updatedOptionValue._key
)
return {
...existingOptionValue,
...updatedOptionValue,
}
}),
}
}),

variants: variants.map((variant) => {
const existingVariant = existingDoc.variants
? existingDoc.variants.find((v) => v.id === variant.id) || {}
: {}

return {
...existingVariant,
...variant,
}
}),
options: options.map((updatedOption) => {
const existingOption = existingDoc.options
? existingDoc?.options.find((o) => o._key === updatedOption._key)
: undefined

const existingOptionValues = existingOption ? existingOption.values : []

return {
...existingOption,
...updatedOption,
values: updatedOption.values.map((updatedOptionValue) => {
const existingOptionValue = existingOptionValues.find(
(v) => v._key === updatedOptionValue._key
)
return {
...existingOptionValue,
...updatedOptionValue,
}
}),
}
}),

variants: variants.map((variant) => {
const existingVariant = existingDoc.variants
? existingDoc.variants.find(
(v) => v.shopifyVariantID === variant.shopifyVariantID
) || {}
: {}

return {
...existingVariant,
...variant,
}
}),
}
return doc
}
throw new Error(
`The document with the shopifyId "${existingDoc.shopifyId}" could not be merged. Be sure that the document includes a _type property`
)
}

export const createSyncSanityDocument = (
Expand Down Expand Up @@ -121,13 +137,15 @@ export const createSyncSanityDocument = (
existingDoc &&
isMatch(docInfo, existingDoc, {
keys: [
'_type',
'title',
'handle',
'shopifyId',
'minVariantPrice',
'maxVariantPrice',
'sourceData',
'_type',
'options',
'variants',
],
})
) {
Expand All @@ -143,8 +161,7 @@ export const createSyncSanityDocument = (

/* Create a new document if none exists */
if (!existingDoc) {
// @ts-ignore
const newDoc = await client.create<SanityShopifyDocument>(docInfo)
const newDoc = await client.create<SanityShopifyDocumentPartial>(docInfo)
const refetchedDoc = await getSanityDocByShopifyId(newDoc.shopifyId)
if (!refetchedDoc) {
throw new Error(
Expand All @@ -155,6 +172,7 @@ export const createSyncSanityDocument = (
cache.set(refetchedDoc)
return {
type: 'create' as 'create',
// @ts-ignore
sanityDocument: newDoc,
shopifySource: item,
}
Expand All @@ -174,16 +192,6 @@ export const createSyncSanityDocument = (
.set(patchData)
.commit()

if (
existingDoc._type === 'shopifyCollection' &&
(existingDoc.variants || existingDoc.options)
) {
await client
.patch(existingDoc._id)
.unset(['variants', 'options'])
.commit()
}

const refetchedDoc = await getSanityDocByShopifyId(updatedDoc.shopifyId)
if (!refetchedDoc) {
throw new Error(
Expand Down
Loading

0 comments on commit ebaf0e1

Please sign in to comment.