hierarchy diff tests

This commit is contained in:
Michael Shanks 2020-03-11 16:42:53 +00:00
parent a286385e57
commit 1853921330
2 changed files with 234 additions and 28 deletions

View File

@ -1,4 +1,4 @@
import { getFlattenedHierarchy, isRecord, isIndex } from "./hierarchy"
import { getFlattenedHierarchy, isRecord, isIndex, isAncestor } from "./hierarchy"
import { $, none } from "../common"
import { map, filter, some, find } from "lodash/fp"
@ -17,15 +17,18 @@ export const diffHierarchy = (oldHierarchy, newHierarchy) => {
const oldHierarchyFlat = getFlattenedHierarchy(oldHierarchy)
const newHierarchyFlat = getFlattenedHierarchy(newHierarchy)
const createdRecords = findCreatedRecords(oldHierarchyFlat, newHierarchyFlat)
const deletedRecords = findDeletedRecords(oldHierarchyFlat, newHierarchyFlat)
return [
...createdRecords(oldHierarchyFlat, newHierarchyFlat),
...deletedRecords(oldHierarchyFlat, newHierarchyFlat),
...renamedRecords(oldHierarchyFlat, newHierarchyFlat),
...recordsWithFieldsChanged(oldHierarchyFlat, newHierarchyFlat),
...recordsWithEstimatedRecordTypeChanged(oldHierarchyFlat, newHierarchyFlat),
...createdIndexes(oldHierarchyFlat, newHierarchyFlat),
...deletedIndexes(oldHierarchyFlat, newHierarchyFlat),
...updatedIndexes(oldHierarchyFlat, newHierarchyFlat),
...createdRecords,
...deletedRecords,
...findRenamedRecords(oldHierarchyFlat, newHierarchyFlat),
...findRecordsWithFieldsChanged(oldHierarchyFlat, newHierarchyFlat),
...findRecordsWithEstimatedRecordTypeChanged(oldHierarchyFlat, newHierarchyFlat),
...findCreatedIndexes(oldHierarchyFlat, newHierarchyFlat, createdRecords),
...findDeletedIndexes(oldHierarchyFlat, newHierarchyFlat, deletedRecords),
...findUpdatedIndexes(oldHierarchyFlat, newHierarchyFlat),
]
}
@ -33,33 +36,43 @@ const changeItem = (type, oldNode, newNode) => ({
type, oldNode, newNode,
})
const createdRecords = (oldHierarchyFlat, newHierarchyFlat) =>
$(newHierarchyFlat, [
const findCreatedRecords = (oldHierarchyFlat, newHierarchyFlat) => {
const allCreated = $(newHierarchyFlat, [
filter(isRecord),
filter(nodeDoesNotExistIn(oldHierarchyFlat)),
map(n => changeItem(HierarchyChangeTypes.recordCreated, null, n))
])
const deletedRecords = (oldHierarchyFlat, newHierarchyFlat) =>
$(oldHierarchyFlat, [
return $(allCreated, [
filter(r => none(r2 => isAncestor(r.newNode)(r2.newNode))(allCreated))
])
}
const findDeletedRecords = (oldHierarchyFlat, newHierarchyFlat) => {
const allDeleted = $(oldHierarchyFlat, [
filter(isRecord),
filter(nodeDoesNotExistIn(newHierarchyFlat)),
map(n => changeItem(HierarchyChangeTypes.recordDeleted, n, null))
])
const renamedRecords = (oldHierarchyFlat, newHierarchyFlat) =>
return $(allDeleted, [
filter(r => none(r2 => isAncestor(r.oldNode)(r2.oldNode))(allDeleted))
])
}
const findRenamedRecords = (oldHierarchyFlat, newHierarchyFlat) =>
$(oldHierarchyFlat, [
filter(isRecord),
filter(nodeExistsIn(newHierarchyFlat)),
filter(nodeChanged(newHierarchyFlat, (_new,old) =>_new.collectionKey !== old.collectionKey )),
map(n => changeItem(
HierarchyChangeTypes.recordDeleted,
HierarchyChangeTypes.recordRenamed,
n,
findNodeIn(n, newHierarchyFlat))
)
])
const recordsWithFieldsChanged = (oldHierarchyFlat, newHierarchyFlat) =>
const findRecordsWithFieldsChanged = (oldHierarchyFlat, newHierarchyFlat) =>
$(oldHierarchyFlat, [
filter(isRecord),
filter(nodeExistsIn(newHierarchyFlat)),
@ -71,7 +84,7 @@ const recordsWithFieldsChanged = (oldHierarchyFlat, newHierarchyFlat) =>
)
])
const recordsWithEstimatedRecordTypeChanged = (oldHierarchyFlat, newHierarchyFlat) =>
const findRecordsWithEstimatedRecordTypeChanged = (oldHierarchyFlat, newHierarchyFlat) =>
$(oldHierarchyFlat, [
filter(isRecord),
filter(nodeExistsIn(newHierarchyFlat)),
@ -83,22 +96,32 @@ const recordsWithEstimatedRecordTypeChanged = (oldHierarchyFlat, newHierarchyFla
)
])
const createdIndexes = (oldHierarchyFlat, newHierarchyFlat) =>
$(newHierarchyFlat, [
const findCreatedIndexes = (oldHierarchyFlat, newHierarchyFlat, createdRecords) => {
const allCreated = $(newHierarchyFlat, [
filter(isIndex),
filter(nodeDoesNotExistIn(oldHierarchyFlat)),
map(n => changeItem(HierarchyChangeTypes.indexCreated, null, n))
])
const deletedIndexes = (oldHierarchyFlat, newHierarchyFlat) =>
$(oldHierarchyFlat, [
return $(allCreated, [
filter(r => none(r2 => isAncestor(r.newNode)(r2.newNode))(createdRecords))
])
}
const findDeletedIndexes = (oldHierarchyFlat, newHierarchyFlat, deletedRecords) => {
const allDeleted = $(oldHierarchyFlat, [
filter(isIndex),
filter(nodeDoesNotExistIn(newHierarchyFlat)),
map(n => changeItem(HierarchyChangeTypes.indexDeleted, n, null))
])
return $(allDeleted, [
filter(r => none(r2 => isAncestor(r.oldNode)(r2.oldNode))(deletedRecords))
])
}
const updatedIndexes = (oldHierarchyFlat, newHierarchyFlat) =>
const findUpdatedIndexes = (oldHierarchyFlat, newHierarchyFlat) =>
$(oldHierarchyFlat, [
filter(isRecord),
filter(nodeExistsIn(newHierarchyFlat)),
@ -114,7 +137,7 @@ const hasDifferentFields = otherFlatHierarchy => record1 => {
const record2 = findNodeIn(record1, otherFlatHierarchy)
if(record1.fields.length !== record2.fields.length) return false
if(record1.fields.length !== record2.fields.length) return true
for(let f1 of record1.fields) {
if (none(isFieldSame(f1))(record2.fields)) return true

View File

@ -1,5 +1,5 @@
import { getMemoryTemplateApi } from "./specHelpers"
import { diffHierarchy } from "../src/templateApi/diffHierarchy"
import { diffHierarchy, HierarchyChangeTypes } from "../src/templateApi/diffHierarchy"
import { getFlattenedHierarchy } from "../src/templateApi/hierarchy"
describe("diffHierarchy", () => {
@ -11,22 +11,205 @@ describe("diffHierarchy", () => {
expect(diff).toEqual([])
})
it("should detect record created", async () => {
it("should detect root record created", async () => {
const oldHierarchy = (await setup()).root;
const newSetup = (await setup());
const opportunity = newSetup.templateApi.getNewRecordTemplate(newSetup.root, "opportunity", false)
const diff = diffHierarchy(oldHierarchy, newSetup.root)
expect(diff).toEqual([{
newNode: opportunity,
oldNode: null,
type: HierarchyChangeTypes.recordCreated
}])
})
})
it("should only detect root record, when newly created root record has children ", async () => {
const oldHierarchy = (await setup()).root;
const newSetup = (await setup());
const opportunity = newSetup.templateApi.getNewRecordTemplate(newSetup.root, "opportunity", false)
newSetup.templateApi.getNewRecordTemplate(opportunity, "invoice", true)
const diff = diffHierarchy(oldHierarchy, newSetup.root)
expect(diff).toEqual([{
newNode: opportunity,
oldNode: null,
type: HierarchyChangeTypes.recordCreated
}])
})
it("should detect child record created", async () => {
const oldHierarchy = (await setup()).root;
const newSetup = (await setup());
const opportunity = newSetup.templateApi.getNewRecordTemplate(newSetup.contact, "opportunity", false)
const diff = diffHierarchy(oldHierarchy, newSetup.root)
expect(diff).toEqual([{
newNode: opportunity,
oldNode: null,
type: HierarchyChangeTypes.recordCreated
}])
})
it("should detect root record deleted", async () => {
const oldSetup = (await setup());
const newSetup = (await setup());
newSetup.root.children = newSetup.root.children.filter(n => n.name !== "contact")
const diff = diffHierarchy(oldSetup.root, newSetup.root)
expect(diff).toEqual([{
newNode: null,
oldNode: oldSetup.contact,
type: HierarchyChangeTypes.recordDeleted
}])
})
it("should detect child record deleted", async () => {
const oldSetup = (await setup());
const newSetup = (await setup());
newSetup.contact.children = newSetup.contact.children.filter(n => n.name !== "deal")
const diff = diffHierarchy(oldSetup.root, newSetup.root)
expect(diff).toEqual([{
newNode: null,
oldNode: oldSetup.deal,
type: HierarchyChangeTypes.recordDeleted
}])
})
it("should detect root record renamed", async () => {
const oldSetup = (await setup());
const newSetup = (await setup());
newSetup.contact.collectionKey = "CONTACTS"
const diff = diffHierarchy(oldSetup.root, newSetup.root)
expect(diff).toEqual([{
newNode: newSetup.contact,
oldNode: oldSetup.contact,
type: HierarchyChangeTypes.recordRenamed
}])
})
it("should detect child record renamed", async () => {
const oldSetup = (await setup());
const newSetup = (await setup());
newSetup.deal.collectionKey = "CONTACTS"
const diff = diffHierarchy(oldSetup.root, newSetup.root)
expect(diff).toEqual([{
newNode: newSetup.deal,
oldNode: oldSetup.deal,
type: HierarchyChangeTypes.recordRenamed
}])
})
it("should detect root record field removed", async () => {
const oldSetup = (await setup());
const newSetup = (await setup());
newSetup.contact.fields = newSetup.contact.fields.filter(f => f.name !== "name")
const diff = diffHierarchy(oldSetup.root, newSetup.root)
expect(diff).toEqual([{
newNode: newSetup.contact,
oldNode: oldSetup.contact,
type: HierarchyChangeTypes.recordFieldsChanged
}])
})
it("should detect child record field removed", async () => {
const oldSetup = (await setup());
const newSetup = (await setup());
newSetup.deal.fields = newSetup.deal.fields.filter(f => f.name !== "name")
const diff = diffHierarchy(oldSetup.root, newSetup.root)
expect(diff).toEqual([{
newNode: newSetup.deal,
oldNode: oldSetup.deal,
type: HierarchyChangeTypes.recordFieldsChanged
}])
})
it("should detect record field added", async () => {
const oldSetup = (await setup());
const newSetup = (await setup());
const notesField = newSetup.templateApi.getNewField("string")
notesField.name = "notes"
newSetup.templateApi.addField(newSetup.contact, notesField)
const diff = diffHierarchy(oldSetup.root, newSetup.root)
expect(diff).toEqual([{
newNode: newSetup.contact,
oldNode: oldSetup.contact,
type: HierarchyChangeTypes.recordFieldsChanged
}])
})
it("should detect 1 record field added and 1 removed (total no. fields unchanged)", async () => {
const oldSetup = (await setup());
const newSetup = (await setup());
const notesField = newSetup.templateApi.getNewField("string")
notesField.name = "notes"
newSetup.templateApi.addField(newSetup.contact, notesField)
newSetup.contact.fields = newSetup.contact.fields.filter(f => f.name !== "name")
const diff = diffHierarchy(oldSetup.root, newSetup.root)
expect(diff).toEqual([{
newNode: newSetup.contact,
oldNode: oldSetup.contact,
type: HierarchyChangeTypes.recordFieldsChanged
}])
})
it("should detect root record estimated record count changed", async () => {
const oldSetup = (await setup());
const newSetup = (await setup());
newSetup.contact.estimatedRecordCount = 987
const diff = diffHierarchy(oldSetup.root, newSetup.root)
expect(diff).toEqual([{
newNode: newSetup.contact,
oldNode: oldSetup.contact,
type: HierarchyChangeTypes.recordEstimatedRecordTypeChanged
}])
})
it("should detect root record estimated record count changed", async () => {
const oldSetup = (await setup());
const newSetup = (await setup());
newSetup.deal.estimatedRecordCount = 987
const diff = diffHierarchy(oldSetup.root, newSetup.root)
expect(diff).toEqual([{
newNode: newSetup.deal,
oldNode: oldSetup.deal,
type: HierarchyChangeTypes.recordEstimatedRecordTypeChanged
}])
})
it("should detect root record created", async () => {
const oldHierarchy = (await setup()).root;
const newSetup = (await setup());
const opportunity = newSetup.templateApi.getNewRecordTemplate(newSetup.root, "opportunity", false)
const diff = diffHierarchy(oldHierarchy, newSetup.root)
expect(diff).toEqual([{
newNode: opportunity,
oldNode: null,
type: HierarchyChangeTypes.recordCreated
}])
})
})
const setup = async () => {
const { templateApi } = await getMemoryTemplateApi()
const root = templateApi.getNewRootLevel()
const contact = templateApi.getNewRecordTemplate(root, "contact", true)
const nameField = templateApi.getNewField("string")
nameField.name = "name"
const statusField = templateApi.getNewField("string")
statusField.name = "status"
templateApi.addField(contact, nameField)
templateApi.addField(contact, statusField)
const lead = templateApi.getNewRecordTemplate(root, "lead", true)
const deal = templateApi.getNewRecordTemplate(contact, "deal", true)
templateApi.addField(deal, {...nameField})
templateApi.addField(deal, {...statusField})
getFlattenedHierarchy(root)
return {
root, contact, lead, deal,
root, contact, lead, deal, templateApi,
all_contacts: root.indexes[0],
all_leads: root.indexes[1],
deals_for_contacts: contact.indexes[0]