hierarchy diff tests
This commit is contained in:
parent
a286385e57
commit
1853921330
|
@ -1,4 +1,4 @@
|
||||||
import { getFlattenedHierarchy, isRecord, isIndex } from "./hierarchy"
|
import { getFlattenedHierarchy, isRecord, isIndex, isAncestor } from "./hierarchy"
|
||||||
import { $, none } from "../common"
|
import { $, none } from "../common"
|
||||||
import { map, filter, some, find } from "lodash/fp"
|
import { map, filter, some, find } from "lodash/fp"
|
||||||
|
|
||||||
|
@ -17,15 +17,18 @@ export const diffHierarchy = (oldHierarchy, newHierarchy) => {
|
||||||
const oldHierarchyFlat = getFlattenedHierarchy(oldHierarchy)
|
const oldHierarchyFlat = getFlattenedHierarchy(oldHierarchy)
|
||||||
const newHierarchyFlat = getFlattenedHierarchy(newHierarchy)
|
const newHierarchyFlat = getFlattenedHierarchy(newHierarchy)
|
||||||
|
|
||||||
|
const createdRecords = findCreatedRecords(oldHierarchyFlat, newHierarchyFlat)
|
||||||
|
const deletedRecords = findDeletedRecords(oldHierarchyFlat, newHierarchyFlat)
|
||||||
|
|
||||||
return [
|
return [
|
||||||
...createdRecords(oldHierarchyFlat, newHierarchyFlat),
|
...createdRecords,
|
||||||
...deletedRecords(oldHierarchyFlat, newHierarchyFlat),
|
...deletedRecords,
|
||||||
...renamedRecords(oldHierarchyFlat, newHierarchyFlat),
|
...findRenamedRecords(oldHierarchyFlat, newHierarchyFlat),
|
||||||
...recordsWithFieldsChanged(oldHierarchyFlat, newHierarchyFlat),
|
...findRecordsWithFieldsChanged(oldHierarchyFlat, newHierarchyFlat),
|
||||||
...recordsWithEstimatedRecordTypeChanged(oldHierarchyFlat, newHierarchyFlat),
|
...findRecordsWithEstimatedRecordTypeChanged(oldHierarchyFlat, newHierarchyFlat),
|
||||||
...createdIndexes(oldHierarchyFlat, newHierarchyFlat),
|
...findCreatedIndexes(oldHierarchyFlat, newHierarchyFlat, createdRecords),
|
||||||
...deletedIndexes(oldHierarchyFlat, newHierarchyFlat),
|
...findDeletedIndexes(oldHierarchyFlat, newHierarchyFlat, deletedRecords),
|
||||||
...updatedIndexes(oldHierarchyFlat, newHierarchyFlat),
|
...findUpdatedIndexes(oldHierarchyFlat, newHierarchyFlat),
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,33 +36,43 @@ const changeItem = (type, oldNode, newNode) => ({
|
||||||
type, oldNode, newNode,
|
type, oldNode, newNode,
|
||||||
})
|
})
|
||||||
|
|
||||||
const createdRecords = (oldHierarchyFlat, newHierarchyFlat) =>
|
const findCreatedRecords = (oldHierarchyFlat, newHierarchyFlat) => {
|
||||||
$(newHierarchyFlat, [
|
const allCreated = $(newHierarchyFlat, [
|
||||||
filter(isRecord),
|
filter(isRecord),
|
||||||
filter(nodeDoesNotExistIn(oldHierarchyFlat)),
|
filter(nodeDoesNotExistIn(oldHierarchyFlat)),
|
||||||
map(n => changeItem(HierarchyChangeTypes.recordCreated, null, n))
|
map(n => changeItem(HierarchyChangeTypes.recordCreated, null, n))
|
||||||
])
|
])
|
||||||
|
|
||||||
const deletedRecords = (oldHierarchyFlat, newHierarchyFlat) =>
|
return $(allCreated, [
|
||||||
$(oldHierarchyFlat, [
|
filter(r => none(r2 => isAncestor(r.newNode)(r2.newNode))(allCreated))
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
const findDeletedRecords = (oldHierarchyFlat, newHierarchyFlat) => {
|
||||||
|
const allDeleted = $(oldHierarchyFlat, [
|
||||||
filter(isRecord),
|
filter(isRecord),
|
||||||
filter(nodeDoesNotExistIn(newHierarchyFlat)),
|
filter(nodeDoesNotExistIn(newHierarchyFlat)),
|
||||||
map(n => changeItem(HierarchyChangeTypes.recordDeleted, n, null))
|
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, [
|
$(oldHierarchyFlat, [
|
||||||
filter(isRecord),
|
filter(isRecord),
|
||||||
filter(nodeExistsIn(newHierarchyFlat)),
|
filter(nodeExistsIn(newHierarchyFlat)),
|
||||||
filter(nodeChanged(newHierarchyFlat, (_new,old) =>_new.collectionKey !== old.collectionKey )),
|
filter(nodeChanged(newHierarchyFlat, (_new,old) =>_new.collectionKey !== old.collectionKey )),
|
||||||
map(n => changeItem(
|
map(n => changeItem(
|
||||||
HierarchyChangeTypes.recordDeleted,
|
HierarchyChangeTypes.recordRenamed,
|
||||||
n,
|
n,
|
||||||
findNodeIn(n, newHierarchyFlat))
|
findNodeIn(n, newHierarchyFlat))
|
||||||
)
|
)
|
||||||
])
|
])
|
||||||
|
|
||||||
const recordsWithFieldsChanged = (oldHierarchyFlat, newHierarchyFlat) =>
|
const findRecordsWithFieldsChanged = (oldHierarchyFlat, newHierarchyFlat) =>
|
||||||
$(oldHierarchyFlat, [
|
$(oldHierarchyFlat, [
|
||||||
filter(isRecord),
|
filter(isRecord),
|
||||||
filter(nodeExistsIn(newHierarchyFlat)),
|
filter(nodeExistsIn(newHierarchyFlat)),
|
||||||
|
@ -71,7 +84,7 @@ const recordsWithFieldsChanged = (oldHierarchyFlat, newHierarchyFlat) =>
|
||||||
)
|
)
|
||||||
])
|
])
|
||||||
|
|
||||||
const recordsWithEstimatedRecordTypeChanged = (oldHierarchyFlat, newHierarchyFlat) =>
|
const findRecordsWithEstimatedRecordTypeChanged = (oldHierarchyFlat, newHierarchyFlat) =>
|
||||||
$(oldHierarchyFlat, [
|
$(oldHierarchyFlat, [
|
||||||
filter(isRecord),
|
filter(isRecord),
|
||||||
filter(nodeExistsIn(newHierarchyFlat)),
|
filter(nodeExistsIn(newHierarchyFlat)),
|
||||||
|
@ -83,22 +96,32 @@ const recordsWithEstimatedRecordTypeChanged = (oldHierarchyFlat, newHierarchyFla
|
||||||
)
|
)
|
||||||
])
|
])
|
||||||
|
|
||||||
const createdIndexes = (oldHierarchyFlat, newHierarchyFlat) =>
|
const findCreatedIndexes = (oldHierarchyFlat, newHierarchyFlat, createdRecords) => {
|
||||||
$(newHierarchyFlat, [
|
const allCreated = $(newHierarchyFlat, [
|
||||||
filter(isIndex),
|
filter(isIndex),
|
||||||
filter(nodeDoesNotExistIn(oldHierarchyFlat)),
|
filter(nodeDoesNotExistIn(oldHierarchyFlat)),
|
||||||
map(n => changeItem(HierarchyChangeTypes.indexCreated, null, n))
|
map(n => changeItem(HierarchyChangeTypes.indexCreated, null, n))
|
||||||
])
|
])
|
||||||
|
|
||||||
const deletedIndexes = (oldHierarchyFlat, newHierarchyFlat) =>
|
return $(allCreated, [
|
||||||
$(oldHierarchyFlat, [
|
filter(r => none(r2 => isAncestor(r.newNode)(r2.newNode))(createdRecords))
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
const findDeletedIndexes = (oldHierarchyFlat, newHierarchyFlat, deletedRecords) => {
|
||||||
|
const allDeleted = $(oldHierarchyFlat, [
|
||||||
filter(isIndex),
|
filter(isIndex),
|
||||||
filter(nodeDoesNotExistIn(newHierarchyFlat)),
|
filter(nodeDoesNotExistIn(newHierarchyFlat)),
|
||||||
map(n => changeItem(HierarchyChangeTypes.indexDeleted, n, null))
|
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, [
|
$(oldHierarchyFlat, [
|
||||||
filter(isRecord),
|
filter(isRecord),
|
||||||
filter(nodeExistsIn(newHierarchyFlat)),
|
filter(nodeExistsIn(newHierarchyFlat)),
|
||||||
|
@ -114,7 +137,7 @@ const hasDifferentFields = otherFlatHierarchy => record1 => {
|
||||||
|
|
||||||
const record2 = findNodeIn(record1, otherFlatHierarchy)
|
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) {
|
for(let f1 of record1.fields) {
|
||||||
if (none(isFieldSame(f1))(record2.fields)) return true
|
if (none(isFieldSame(f1))(record2.fields)) return true
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { getMemoryTemplateApi } from "./specHelpers"
|
import { getMemoryTemplateApi } from "./specHelpers"
|
||||||
import { diffHierarchy } from "../src/templateApi/diffHierarchy"
|
import { diffHierarchy, HierarchyChangeTypes } from "../src/templateApi/diffHierarchy"
|
||||||
import { getFlattenedHierarchy } from "../src/templateApi/hierarchy"
|
import { getFlattenedHierarchy } from "../src/templateApi/hierarchy"
|
||||||
|
|
||||||
describe("diffHierarchy", () => {
|
describe("diffHierarchy", () => {
|
||||||
|
@ -11,22 +11,205 @@ describe("diffHierarchy", () => {
|
||||||
expect(diff).toEqual([])
|
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 setup = async () => {
|
||||||
const { templateApi } = await getMemoryTemplateApi()
|
const { templateApi } = await getMemoryTemplateApi()
|
||||||
const root = templateApi.getNewRootLevel()
|
const root = templateApi.getNewRootLevel()
|
||||||
const contact = templateApi.getNewRecordTemplate(root, "contact", true)
|
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 lead = templateApi.getNewRecordTemplate(root, "lead", true)
|
||||||
const deal = templateApi.getNewRecordTemplate(contact, "deal", true)
|
const deal = templateApi.getNewRecordTemplate(contact, "deal", true)
|
||||||
|
|
||||||
|
templateApi.addField(deal, {...nameField})
|
||||||
|
templateApi.addField(deal, {...statusField})
|
||||||
|
|
||||||
getFlattenedHierarchy(root)
|
getFlattenedHierarchy(root)
|
||||||
return {
|
return {
|
||||||
root, contact, lead, deal,
|
root, contact, lead, deal, templateApi,
|
||||||
all_contacts: root.indexes[0],
|
all_contacts: root.indexes[0],
|
||||||
all_leads: root.indexes[1],
|
all_leads: root.indexes[1],
|
||||||
deals_for_contacts: contact.indexes[0]
|
deals_for_contacts: contact.indexes[0]
|
||||||
|
|
Loading…
Reference in New Issue