Merge remote-tracking branch 'upstream/master' into feature/builder-organization
This commit is contained in:
commit
f0be216840
|
@ -198,7 +198,10 @@ export const saveCurrentNode = store => () => {
|
||||||
const defaultIndex = templateApi(state.hierarchy).getNewIndexTemplate(
|
const defaultIndex = templateApi(state.hierarchy).getNewIndexTemplate(
|
||||||
cloned.parent()
|
cloned.parent()
|
||||||
)
|
)
|
||||||
defaultIndex.name = `all_${cloned.name}s`
|
defaultIndex.name = hierarchyFunctions.isTopLevelIndex(cloned)
|
||||||
|
? `all_${cloned.name}s`
|
||||||
|
: `${cloned.parent().name}_${cloned.name}s`
|
||||||
|
|
||||||
defaultIndex.allowedRecordNodeIds = [cloned.nodeId]
|
defaultIndex.allowedRecordNodeIds = [cloned.nodeId]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
import ButtonGroup from "../common/ButtonGroup.svelte"
|
import ButtonGroup from "../common/ButtonGroup.svelte"
|
||||||
import Button from "../common/Button.svelte"
|
import Button from "../common/Button.svelte"
|
||||||
import ActionButton from "../common/ActionButton.svelte"
|
import ActionButton from "../common/ActionButton.svelte"
|
||||||
import { validateAccessLevels } from "../common/core"
|
import { validateAccessLevels, nodeNameFromNodeKey } from "../common/core"
|
||||||
import ErrorsBox from "../common/ErrorsBox.svelte"
|
import ErrorsBox from "../common/ErrorsBox.svelte"
|
||||||
|
|
||||||
export let level
|
export let level
|
||||||
|
@ -38,7 +38,9 @@
|
||||||
)
|
)
|
||||||
|
|
||||||
const getPermissionName = perm =>
|
const getPermissionName = perm =>
|
||||||
perm.nodeKey ? `${perm.type} - ${perm.nodeKey}` : perm.type
|
perm.nodeKey
|
||||||
|
? `${perm.type} - ${nodeNameFromNodeKey(hierarchy, perm.nodeKey)}`
|
||||||
|
: perm.type
|
||||||
|
|
||||||
const save = () => {
|
const save = () => {
|
||||||
const newLevels = isNew
|
const newLevels = isNew
|
||||||
|
|
|
@ -79,6 +79,7 @@ export const getPotentialReferenceIndexes = (hierarchy, record) =>
|
||||||
|
|
||||||
export const isIndex = hierarchyFunctions.isIndex
|
export const isIndex = hierarchyFunctions.isIndex
|
||||||
export const isRecord = hierarchyFunctions.isRecord
|
export const isRecord = hierarchyFunctions.isRecord
|
||||||
|
export const nodeNameFromNodeKey = hierarchyFunctions.nodeNameFromNodeKey
|
||||||
|
|
||||||
export const getDefaultTypeOptions = type =>
|
export const getDefaultTypeOptions = type =>
|
||||||
!type ? {} : allTypes[type].getDefaultOptions()
|
!type ? {} : allTypes[type].getDefaultOptions()
|
||||||
|
|
|
@ -48,6 +48,11 @@ const nodeKeyMaker = node => () =>
|
||||||
[defaultCase, n => joinKey(node.parent().nodeKey(), n.name)]
|
[defaultCase, n => joinKey(node.parent().nodeKey(), n.name)]
|
||||||
)(node)
|
)(node)
|
||||||
|
|
||||||
|
const nodeNameMaker = node => () =>
|
||||||
|
isRoot(node)
|
||||||
|
? "/"
|
||||||
|
: joinKey(node.parent().nodeName(), node.name)
|
||||||
|
|
||||||
const validate = parent => node => {
|
const validate = parent => node => {
|
||||||
if (
|
if (
|
||||||
isIndex(node) &&
|
isIndex(node) &&
|
||||||
|
@ -71,6 +76,7 @@ const validate = parent => node => {
|
||||||
|
|
||||||
const construct = parent => node => {
|
const construct = parent => node => {
|
||||||
node.nodeKey = nodeKeyMaker(node)
|
node.nodeKey = nodeKeyMaker(node)
|
||||||
|
node.nodeName = nodeNameMaker(node)
|
||||||
node.pathRegx = pathRegxMaker(node)
|
node.pathRegx = pathRegxMaker(node)
|
||||||
node.parent = constant(parent)
|
node.parent = constant(parent)
|
||||||
node.isRoot = () =>
|
node.isRoot = () =>
|
||||||
|
|
|
@ -244,6 +244,11 @@ export const fieldReversesReferenceToIndex = indexNode => field =>
|
||||||
intersection(field.typeOptions.reverseIndexNodeKeys)([indexNode.nodeKey()])
|
intersection(field.typeOptions.reverseIndexNodeKeys)([indexNode.nodeKey()])
|
||||||
.length > 0
|
.length > 0
|
||||||
|
|
||||||
|
export const nodeNameFromNodeKey = (hierarchy, nodeKey) => {
|
||||||
|
const node = getNode(hierarchy, nodeKey)
|
||||||
|
return node ? node.nodeName() : ""
|
||||||
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
getLastPartInKey,
|
getLastPartInKey,
|
||||||
getNodesInPath,
|
getNodesInPath,
|
||||||
|
@ -279,4 +284,7 @@ export default {
|
||||||
fieldReversesReferenceToNode,
|
fieldReversesReferenceToNode,
|
||||||
fieldReversesReferenceToIndex,
|
fieldReversesReferenceToIndex,
|
||||||
getFlattenedHierarchy,
|
getFlattenedHierarchy,
|
||||||
|
isTopLevelIndex,
|
||||||
|
isTopLevelRecord,
|
||||||
|
nodeNameFromNodeKey,
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,18 +44,22 @@ import {
|
||||||
} from "../templateApi/hierarchy"
|
} from "../templateApi/hierarchy"
|
||||||
import { getRecordInfo } from "../recordApi/recordInfo"
|
import { getRecordInfo } from "../recordApi/recordInfo"
|
||||||
import { getIndexDir } from "../indexApi/getIndexDir"
|
import { getIndexDir } from "../indexApi/getIndexDir"
|
||||||
|
import { _deleteIndex } from "../indexApi/delete"
|
||||||
import { initialiseIndex } from "../indexing/initialiseIndex"
|
import { initialiseIndex } from "../indexing/initialiseIndex"
|
||||||
|
|
||||||
export const executeTransactions = app => async transactions => {
|
export const executeTransactions = app => async transactions => {
|
||||||
const recordsByShard = mappedRecordsByIndexShard(app.hierarchy, transactions)
|
const recordsByShard = mappedRecordsByIndexShard(app.hierarchy, transactions)
|
||||||
|
|
||||||
for (const shard of keys(recordsByShard)) {
|
for (const shard of keys(recordsByShard)) {
|
||||||
if (recordsByShard[shard].isRebuild)
|
if (recordsByShard[shard].isRebuild) {
|
||||||
|
if (await app.datastore.exists(shard))
|
||||||
|
await app.datastore.deleteFile(shard)
|
||||||
await initialiseIndex(
|
await initialiseIndex(
|
||||||
app.datastore,
|
app.datastore,
|
||||||
getParentKey(recordsByShard[shard].indexDir),
|
getParentKey(recordsByShard[shard].indexDir),
|
||||||
recordsByShard[shard].indexNode
|
recordsByShard[shard].indexNode
|
||||||
)
|
)
|
||||||
|
}
|
||||||
await applyToShard(
|
await applyToShard(
|
||||||
app.hierarchy,
|
app.hierarchy,
|
||||||
app.datastore,
|
app.datastore,
|
||||||
|
@ -76,7 +80,11 @@ const mappedRecordsByIndexShard = (hierarchy, transactions) => {
|
||||||
|
|
||||||
const indexBuild = getBuildIndexTransactionsByShard(hierarchy, transactions)
|
const indexBuild = getBuildIndexTransactionsByShard(hierarchy, transactions)
|
||||||
|
|
||||||
const toRemove = [...deletes, ...updates.toRemove, ...indexBuild.toRemove]
|
const toRemove = [
|
||||||
|
...deletes,
|
||||||
|
...updates.toRemove,
|
||||||
|
...indexBuild.toRemove,
|
||||||
|
]
|
||||||
|
|
||||||
const toWrite = [...created, ...updates.toWrite, ...indexBuild.toWrite]
|
const toWrite = [...created, ...updates.toWrite, ...indexBuild.toWrite]
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@ describe("hierarchy node creation", () => {
|
||||||
expect(root.parent).toBeDefined()
|
expect(root.parent).toBeDefined()
|
||||||
expect(root.isRoot()).toBeTruthy()
|
expect(root.isRoot()).toBeTruthy()
|
||||||
expect(root.indexes).toEqual([])
|
expect(root.indexes).toEqual([])
|
||||||
|
expect(root.nodeName()).toBe("/")
|
||||||
})
|
})
|
||||||
|
|
||||||
it("> getNewRecordTemplate > should be initialise with correct members", async () => {
|
it("> getNewRecordTemplate > should be initialise with correct members", async () => {
|
||||||
|
@ -33,6 +34,7 @@ describe("hierarchy node creation", () => {
|
||||||
expect(record.collectionNodeKey()).toBe("/records")
|
expect(record.collectionNodeKey()).toBe("/records")
|
||||||
expect(record.collectionPathRegx()).toBe("/records")
|
expect(record.collectionPathRegx()).toBe("/records")
|
||||||
expect(record.nodeKey()).toBe(`/records/${record.nodeId}-{id}`)
|
expect(record.nodeKey()).toBe(`/records/${record.nodeId}-{id}`)
|
||||||
|
expect(record.nodeName()).toBe(`/${record.name}`)
|
||||||
expect(record.pathRegx()).toBe(`/records/${record.nodeId}-[a-zA-Z0-9_\-]+`)
|
expect(record.pathRegx()).toBe(`/records/${record.nodeId}-[a-zA-Z0-9_\-]+`)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -60,6 +62,16 @@ describe("hierarchy node creation", () => {
|
||||||
expect(parentRecord.children[0]).toBe(record)
|
expect(parentRecord.children[0]).toBe(record)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it("> getNewrecordTemplate > child should get correct nodeName ", async () => {
|
||||||
|
const { templateApi } = await getMemoryTemplateApi()
|
||||||
|
const root = templateApi.getNewRootLevel()
|
||||||
|
const parentRecord = templateApi.getNewRecordTemplate(root)
|
||||||
|
parentRecord.name = "parent"
|
||||||
|
const record = templateApi.getNewRecordTemplate(parentRecord)
|
||||||
|
record.name = "child"
|
||||||
|
expect(record.nodeName()).toBe(`/${parentRecord.name}/${record.name}`)
|
||||||
|
})
|
||||||
|
|
||||||
it("> getNewrecordTemplate > should add itself to parents's default index allowedNodeIds", async () => {
|
it("> getNewrecordTemplate > should add itself to parents's default index allowedNodeIds", async () => {
|
||||||
const { templateApi } = await getMemoryTemplateApi()
|
const { templateApi } = await getMemoryTemplateApi()
|
||||||
const root = templateApi.getNewRootLevel()
|
const root = templateApi.getNewRootLevel()
|
||||||
|
|
|
@ -240,6 +240,40 @@ describe("upgradeData", () => {
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it("should rebuild affected index when field is removed", async () => {
|
||||||
|
const { oldSetup, newSetup, records } = await configure()
|
||||||
|
newSetup.contact.fields = newSetup.contact.fields.filter(f => f.name !== "status")
|
||||||
|
|
||||||
|
let itemsInIndex = await _listItems(oldSetup.app, "/contact_index")
|
||||||
|
expect(itemsInIndex.length).toBe(2)
|
||||||
|
expect(itemsInIndex[0].status).toBeDefined()
|
||||||
|
expect(itemsInIndex[0].status).toBe(records.contact1.status)
|
||||||
|
|
||||||
|
await upgradeData(oldSetup.app)(newSetup.root)
|
||||||
|
|
||||||
|
itemsInIndex = await _listItems(newSetup.app, "/contact_index")
|
||||||
|
expect(itemsInIndex.length).toBe(2)
|
||||||
|
expect(itemsInIndex[0].status).toBeUndefined()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should rebuild affected index when field is added", async () => {
|
||||||
|
const { oldSetup, newSetup, records } = await configure()
|
||||||
|
|
||||||
|
const aliveField = newSetup.templateApi.getNewField("string")
|
||||||
|
aliveField.name = "isalive"
|
||||||
|
newSetup.templateApi.addField(newSetup.contact, aliveField)
|
||||||
|
|
||||||
|
let itemsInIndex = await _listItems(oldSetup.app, "/contact_index")
|
||||||
|
expect(itemsInIndex.length).toBe(2)
|
||||||
|
expect(itemsInIndex[0].isalive).toBeUndefined()
|
||||||
|
|
||||||
|
await upgradeData(oldSetup.app)(newSetup.root)
|
||||||
|
|
||||||
|
itemsInIndex = await _listItems(newSetup.app, "/contact_index")
|
||||||
|
expect(itemsInIndex.length).toBe(2)
|
||||||
|
expect(itemsInIndex[0].isalive).toBe(null)
|
||||||
|
})
|
||||||
|
|
||||||
const configure = async () => {
|
const configure = async () => {
|
||||||
const oldSetup = await setup()
|
const oldSetup = await setup()
|
||||||
|
|
||||||
|
@ -256,8 +290,10 @@ const configure = async () => {
|
||||||
const createSomeRecords = async recordApi => {
|
const createSomeRecords = async recordApi => {
|
||||||
const contact1 = recordApi.getNew("/contacts", "contact")
|
const contact1 = recordApi.getNew("/contacts", "contact")
|
||||||
contact1.name = "bobby"
|
contact1.name = "bobby"
|
||||||
|
contact1.status = "New"
|
||||||
const contact2 = recordApi.getNew("/contacts", "contact")
|
const contact2 = recordApi.getNew("/contacts", "contact")
|
||||||
contact2.name = "poppy"
|
contact2.name = "poppy"
|
||||||
|
contact2.status = "Complete"
|
||||||
|
|
||||||
await recordApi.save(contact1)
|
await recordApi.save(contact1)
|
||||||
await recordApi.save(contact2)
|
await recordApi.save(contact2)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
export default ({ indexes, helpers }) =>
|
export default ({ indexes, helpers }) =>
|
||||||
indexes.map(i => ({
|
indexes.map(i => ({
|
||||||
name: `Table based on index: ${i.name} `,
|
name: `Table based on view: ${i.name} `,
|
||||||
props: tableProps(
|
props: tableProps(
|
||||||
i,
|
i,
|
||||||
helpers.indexSchema(i).filter(c => !excludedColumns.includes(c.name))
|
helpers.indexSchema(i).filter(c => !excludedColumns.includes(c.name))
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
export default ({ records }) =>
|
export default ({ records }) =>
|
||||||
records.map(r => ({
|
records.map(r => ({
|
||||||
name: `Form for Record: ${r.nodeKey()}`,
|
name: `Form for Record: ${r.nodeName()}`,
|
||||||
props: outerContainer(r),
|
props: outerContainer(r),
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue