UNPKG

@sanity/import

Version:

Import documents to a Sanity dataset

127 lines (103 loc) 5.09 kB
import createDebug from 'debug' import {absolutifyPaths, getAssetRefs, unsetAssetRefs} from './assetRefs.js' import {assignArrayKeys} from './assignArrayKeys.js' import {assignDocumentId} from './assignDocumentId.js' import {batchDocuments} from './batchDocuments.js' import {documentHasError} from './documentHasErrors.js' import {importBatches} from './importBatches.js' import { cleanupReferences, getStrongRefs, strengthenReferences, type StrongRefsTask, weakenStrongRefs, } from './references.js' import {type ImportOptions, type ImportResult, type SanityDocument} from './types.js' import {uploadAssets} from './uploadAssets.js' import {ensureUniqueIds} from './util/ensureUniqueIds.js' import {validateAssetMapForReplacementChars} from './util/validateReplacementCharacters.js' import {validateAssetDocuments} from './validateAssetDocuments.js' import {validateCdrDatasets} from './validateCdrDatasets.js' const debug = createDebug('sanity:import:array') async function importDocuments( documents: SanityDocument[], options: ImportOptions, ): Promise<ImportResult> { options.onProgress({step: 'Reading/validating data file'}) for (const [i, doc] of documents.entries()) { documentHasError(doc, i) } // Validate assetMap for replacement characters if (options.assetMap && options.allowReplacementCharacters !== true) { validateAssetMapForReplacementChars(options.assetMap) } // Validate that there are no duplicate IDs in the documents ensureUniqueIds(documents) // Ensure that any cross-dataset references has datasets to point to if (!options.skipCrossDatasetReferences) { await validateCdrDatasets(documents, options) } let filteredDocuments = documents // Always filter out system documents unless explicitly allowed. // Release system documents are an exception to this flag. if (options.allowSystemDocuments !== true) { filteredDocuments = documents.filter( (doc) => doc._id?.startsWith('_.releases.') || !doc._id?.startsWith('_.'), ) } // Replace relative asset paths if one is defined // (file://./images/foo-bar.png -> file:///abs/olute/images/foo-bar.png) const absPathed = filteredDocuments.map((doc) => absolutifyPaths(doc, options.assetsBase)) // Assign document IDs for document that do not have one. This is necessary // for us to strengthen references and import assets properly. const ided = absPathed.map((doc) => assignDocumentId(doc)) // User might not have applied `_key` on array elements which are objects; // if this is the case, generate random keys to help realtime engine const keyed = ided.map((doc) => assignArrayKeys(doc)) // Sanity prefers to have a `_type` on every object. Make sure references // has `_type` set to `reference`, and that there are no `_projectId` keys const docs = keyed.map((doc) => cleanupReferences(doc, options)) // Find references that will need strengthening when import is done const strongRefs = docs .map((doc) => getStrongRefs(doc)) .filter((ref): ref is StrongRefsTask => ref !== null) // Extract asset references from the documents const assetRefs = docs.flatMap((doc) => getAssetRefs(doc)) // Remove asset references from the documents const assetless = docs.map((doc) => unsetAssetRefs(doc)) // Make strong references weak so they can be imported in any order const weakened = assetless.map((doc) => weakenStrongRefs(doc)) // Create batches of documents to import. Try to keep batches below a certain // byte-size (since document may vary greatly in size depending on type etc) const batches = batchDocuments(weakened) // Ensure that we don't reference missing assets, or assets in different datasets debug('Validating asset documents') await validateAssetDocuments(docs, options) // Trigger actual import process debug('Starting import of documents') const {count: docsImported, importedIds} = await importBatches(batches, options) // When using createIfNotExists (--missing), only upload assets for documents // that were actually created. Documents that already existed in the dataset // are assumed to already have their assets in place. let filteredAssetRefs = assetRefs if (options.operation === 'createIfNotExists') { const importedIdSet = new Set(importedIds) filteredAssetRefs = assetRefs.filter((ref) => importedIdSet.has(ref.documentId)) const skipped = assetRefs.length - filteredAssetRefs.length if (skipped > 0) { debug('Skipping %d asset refs for %d already-existing documents', skipped, skipped) } } // Documents are imported, now proceed with post-import operations debug('Uploading assets') const {failures: assetWarnings} = await uploadAssets(filteredAssetRefs, options) // Strengthen references debug('Strengthening references') await strengthenReferences(strongRefs, options) // Return number of documents imported return { numDocs: docsImported, warnings: assetWarnings.map((warning) => ({message: `Failed to upload asset: ${warning.url}`})), } } export {importDocuments}