forked from tsai/budibase
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
194 lines
5.6 KiB
194 lines
5.6 KiB
import { diffHierarchy, HierarchyChangeTypes } from "./diffHierarchy"
|
|
import { $, switchCase } from "../common"
|
|
import {
|
|
differenceBy,
|
|
isEqual,
|
|
some,
|
|
map,
|
|
filter,
|
|
uniqBy,
|
|
flatten
|
|
} from "lodash/fp"
|
|
import {
|
|
findRoot,
|
|
getDependantIndexes,
|
|
isTopLevelRecord,
|
|
isAncestorIndex
|
|
} from "./hierarchy"
|
|
import { generateSchema } from "../indexing/indexSchemaCreator"
|
|
import { _buildIndex } from "../indexApi/buildIndex"
|
|
import { constructHierarchy } from "./createNodes"
|
|
import { deleteAllRecordsForNode } from "./deleteAllRecordsForNode"
|
|
import { deleteAllIndexFilesForNode } from "./deleteAllIndexFilesForNode"
|
|
import { cloneApp } from "../appInitialise/cloneApp"
|
|
import { initialiseData } from "../appInitialise/initialiseData"
|
|
import { initialiseChildrenForNode } from "../recordApi/initialiseChildren"
|
|
import { initialiseNewIndex } from "./initialiseNewIndex"
|
|
import { saveApplicationHierarchy } from "../templateApi/saveApplicationHierarchy"
|
|
|
|
export const upgradeData = app => async newHierarchy => {
|
|
const diff = diffHierarchy(app.hierarchy, newHierarchy)
|
|
const changeActions = gatherChangeActions(diff)
|
|
|
|
if (changeActions.length === 0) return
|
|
|
|
newHierarchy = constructHierarchy(newHierarchy)
|
|
const newApp = newHierarchy && cloneApp(app, {
|
|
hierarchy: newHierarchy
|
|
})
|
|
await doUpgrade(app, newApp, changeActions)
|
|
await saveApplicationHierarchy(newApp)(newHierarchy)
|
|
}
|
|
|
|
const gatherChangeActions = (diff) =>
|
|
$(diff, [
|
|
map(actionForChange),
|
|
flatten,
|
|
uniqBy(a => a.compareKey)
|
|
])
|
|
|
|
const doUpgrade = async (oldApp, newApp, changeActions) => {
|
|
for(let action of changeActions) {
|
|
await action.run(oldApp, newApp, action.diff)
|
|
}
|
|
}
|
|
|
|
const actionForChange = diff =>
|
|
switchCase(
|
|
|
|
[isChangeType(HierarchyChangeTypes.recordCreated), recordCreatedAction],
|
|
|
|
[isChangeType(HierarchyChangeTypes.recordDeleted), deleteRecordsAction],
|
|
|
|
[
|
|
isChangeType(HierarchyChangeTypes.recordFieldsChanged),
|
|
rebuildAffectedIndexesAction
|
|
],
|
|
|
|
[isChangeType(HierarchyChangeTypes.recordRenamed), renameRecordAction],
|
|
|
|
[
|
|
isChangeType(HierarchyChangeTypes.recordEstimatedRecordTypeChanged),
|
|
reshardRecordsAction
|
|
],
|
|
|
|
[isChangeType(HierarchyChangeTypes.indexCreated), newIndexAction],
|
|
|
|
[isChangeType(HierarchyChangeTypes.indexDeleted), deleteIndexAction],
|
|
|
|
[isChangeType(HierarchyChangeTypes.indexChanged), rebuildIndexAction],
|
|
|
|
)(diff)
|
|
|
|
|
|
const isChangeType = changeType => change =>
|
|
change.type === changeType
|
|
|
|
const action = (diff, compareKey, run) => ({
|
|
diff,
|
|
compareKey,
|
|
run,
|
|
})
|
|
|
|
|
|
const reshardRecordsAction = diff =>
|
|
[action(diff, `reshardRecords-${diff.oldNode.nodeKey()}`, runReshardRecords)]
|
|
|
|
const rebuildIndexAction = diff =>
|
|
[action(diff, `rebuildIndex-${diff.newNode.nodeKey()}`, runRebuildIndex)]
|
|
|
|
const newIndexAction = diff => {
|
|
if (isAncestorIndex(diff.newNode)) {
|
|
return [action(diff, `rebuildIndex-${diff.newNode.nodeKey()}`, runRebuildIndex)]
|
|
} else {
|
|
return [action(diff, `newIndex-${diff.newNode.nodeKey()}`, runNewIndex)]
|
|
}
|
|
}
|
|
|
|
const deleteIndexAction = diff =>
|
|
[action(diff, `deleteIndex-${diff.oldNode.nodeKey()}`, runDeleteIndex)]
|
|
|
|
const deleteRecordsAction = diff =>
|
|
[action(diff, `deleteRecords-${diff.oldNode.nodeKey()}`, runDeleteRecords)]
|
|
|
|
const renameRecordAction = diff =>
|
|
[action(diff, `renameRecords-${diff.oldNode.nodeKey()}`, runRenameRecord)]
|
|
|
|
const recordCreatedAction = diff => {
|
|
if (isTopLevelRecord(diff.newNode)) {
|
|
return [action(diff, `initialiseRoot`, runInitialiseRoot)]
|
|
}
|
|
|
|
return [action(diff, `initialiseChildRecord-${diff.newNode.nodeKey()}`, runInitialiseChildRecord)]
|
|
}
|
|
|
|
const rebuildAffectedIndexesAction = diff =>{
|
|
const newHierarchy = findRoot(diff.newNode)
|
|
const oldHierarchy = findRoot(diff.oldNode)
|
|
const indexes = getDependantIndexes(newHierarchy, diff.newNode)
|
|
|
|
const changedFields = (() => {
|
|
const addedFields = differenceBy(f => f.name)
|
|
(diff.oldNode.fields)
|
|
(diff.newNode.fields)
|
|
|
|
const removedFields = differenceBy(f => f.name)
|
|
(diff.newNode.fields)
|
|
(diff.oldNode.fields)
|
|
|
|
return map(f => f.name)([...addedFields, ...removedFields])
|
|
})()
|
|
|
|
const isIndexAffected = i => {
|
|
if (!isEqual(
|
|
generateSchema(oldHierarchy, i),
|
|
generateSchema(newHierarchy, i))) return true
|
|
|
|
if (some(f => indexes.filter.indexOf(`record.${f}`) > -1)(changedFields))
|
|
return true
|
|
|
|
if (some(f => indexes.getShardName.indexOf(`record.${f}`) > -1)(changedFields))
|
|
return true
|
|
|
|
return false
|
|
}
|
|
|
|
return $(indexes, [
|
|
filter(isIndexAffected),
|
|
map(i => action({ newNode:i }, `rebuildIndex-${i.nodeKey()}`, runRebuildIndex))
|
|
])
|
|
}
|
|
|
|
const runReshardRecords = async change => {
|
|
throw new Error("Resharding of records is not supported yet")
|
|
}
|
|
|
|
const runRebuildIndex = async (_, newApp, diff) => {
|
|
await _buildIndex(newApp, diff.newNode.nodeKey())
|
|
}
|
|
|
|
const runDeleteIndex = async (oldApp, _, diff) => {
|
|
await deleteAllIndexFilesForNode(oldApp, diff.oldNode)
|
|
}
|
|
|
|
const runDeleteRecords = async (oldApp, _, diff) => {
|
|
await deleteAllRecordsForNode(oldApp, diff.oldNode)
|
|
}
|
|
|
|
const runNewIndex = async (_, newApp, diff) => {
|
|
await initialiseNewIndex(newApp, diff.newNode)
|
|
}
|
|
|
|
const runRenameRecord = change => {
|
|
/*
|
|
Going to disllow this in the builder. once a collection key is set... its done
|
|
*/
|
|
}
|
|
|
|
const runInitialiseRoot = async (_, newApp) => {
|
|
await initialiseData(newApp.datastore, newApp)
|
|
}
|
|
|
|
const runInitialiseChildRecord = async (_, newApp, diff) => {
|
|
await initialiseChildrenForNode(newApp.datastore, diff.newNode)
|
|
}
|