103 lines
2.9 KiB
TypeScript
103 lines
2.9 KiB
TypeScript
import { db as dbCore } from "@budibase/backend-core"
|
|
import {
|
|
DocumentTypesToImport,
|
|
Document,
|
|
Database,
|
|
RowValue,
|
|
} from "@budibase/types"
|
|
import backups from "../backups"
|
|
|
|
export type FileAttributes = {
|
|
type: string
|
|
path: string
|
|
}
|
|
|
|
function mergeUpdateAndDeleteDocuments(
|
|
updateDocs: Document[],
|
|
deleteDocs: Document[]
|
|
) {
|
|
// compress the documents to create and to delete (if same ID, then just update the rev)
|
|
const finalToDelete = []
|
|
for (let deleteDoc of deleteDocs) {
|
|
const found = updateDocs.find(doc => doc._id === deleteDoc._id)
|
|
if (found) {
|
|
found._rev = deleteDoc._rev
|
|
} else {
|
|
finalToDelete.push(deleteDoc)
|
|
}
|
|
}
|
|
return [...updateDocs, ...finalToDelete]
|
|
}
|
|
|
|
async function removeImportableDocuments(db: Database) {
|
|
// get the references to the documents, not the whole document
|
|
const docPromises = []
|
|
for (let docType of DocumentTypesToImport) {
|
|
docPromises.push(db.allDocs(dbCore.getDocParams(docType)))
|
|
}
|
|
let documentRefs: { _id: string; _rev: string }[] = []
|
|
for (let response of await Promise.all(docPromises)) {
|
|
documentRefs = documentRefs.concat(
|
|
response.rows.map(row => ({
|
|
_id: row.id,
|
|
_rev: (row.value as RowValue).rev,
|
|
}))
|
|
)
|
|
}
|
|
// add deletion key
|
|
return documentRefs.map(ref => ({ _deleted: true, ...ref }))
|
|
}
|
|
|
|
async function getImportableDocuments(db: Database) {
|
|
// get the whole document
|
|
const docPromises = []
|
|
for (let docType of DocumentTypesToImport) {
|
|
docPromises.push(
|
|
db.allDocs(dbCore.getDocParams(docType, null, { include_docs: true }))
|
|
)
|
|
}
|
|
// map the responses to the document itself
|
|
let documents: Document[] = []
|
|
for (let response of await Promise.all(docPromises)) {
|
|
documents = documents.concat(response.rows.map(row => row.doc))
|
|
}
|
|
// remove the _rev, stops it being written
|
|
documents.forEach(doc => {
|
|
delete doc._rev
|
|
})
|
|
return documents
|
|
}
|
|
|
|
export async function updateWithExport(
|
|
appId: string,
|
|
file: FileAttributes,
|
|
password?: string
|
|
) {
|
|
const devId = dbCore.getDevAppID(appId)
|
|
const tempAppName = `temp_${devId}`
|
|
const tempDb = dbCore.getDB(tempAppName)
|
|
const appDb = dbCore.getDB(devId)
|
|
try {
|
|
const template = {
|
|
file: {
|
|
type: file.type!,
|
|
path: file.path!,
|
|
password,
|
|
},
|
|
}
|
|
// get a temporary version of the import
|
|
// don't need obj store, the existing app already has everything we need
|
|
await backups.importApp(devId, tempDb, template, {
|
|
importObjStoreContents: false,
|
|
})
|
|
// get the documents to copy
|
|
const toUpdate = await getImportableDocuments(tempDb)
|
|
// clear out the old documents
|
|
const toDelete = await removeImportableDocuments(appDb)
|
|
// now bulk update documents - add new ones, delete old ones and update common ones
|
|
await appDb.bulkDocs(mergeUpdateAndDeleteDocuments(toUpdate, toDelete))
|
|
} finally {
|
|
await tempDb.destroy()
|
|
}
|
|
}
|