budibase/packages/core/src/indexing/relevant.js

127 lines
3.1 KiB
JavaScript

import { orderBy } from "lodash"
import {
reduce,
find,
includes,
flatten,
union,
filter,
each,
map,
} from "lodash/fp"
import {
joinKey,
splitKey,
isNonEmptyString,
isNothing,
$,
isSomething,
} from "../common"
import {
getFlattenedHierarchy,
getNode,
getRecordNodeId,
getExactNodeForKey,
recordNodeIdIsAllowed,
isModel,
isGlobalIndex,
} from "../templateApi/hierarchy"
import { indexTypes } from "../templateApi/indexes"
import { getIndexDir } from "../indexApi/getIndexDir"
import { getRecordInfo } from "../recordApi/recordInfo"
export const getRelevantAncestorIndexes = (hierarchy, record) => {
const key = record.key
const keyParts = splitKey(key)
const nodeId = getRecordNodeId(key)
const flatHierarchy = orderBy(
getFlattenedHierarchy(hierarchy),
[node => node.pathRegx().length],
["desc"]
)
const makeindexNodeAndDir_ForAncestorIndex = (indexNode, parentRecordDir) =>
makeIndexNodeAndDir(indexNode, joinKey(parentRecordDir, indexNode.name))
const traverseAncestorIndexesInPath = () =>
reduce(
(acc, part) => {
const currentIndexKey = joinKey(acc.lastIndexKey, part)
acc.lastIndexKey = currentIndexKey
const testPathRegx = p =>
new RegExp(`${p.pathRegx()}$`).test(currentIndexKey)
const nodeMatch = find(testPathRegx)(flatHierarchy)
if (isNothing(nodeMatch)) {
return acc
}
if (!isModel(nodeMatch) || nodeMatch.indexes.length === 0) {
return acc
}
const indexes = $(nodeMatch.indexes, [
filter(
i =>
i.indexType === indexTypes.ancestor &&
(i.allowedModelNodeIds.length === 0 ||
includes(nodeId)(i.allowedModelNodeIds))
),
])
const currentRecordDir = getRecordInfo(hierarchy, currentIndexKey).dir
each(v =>
acc.nodesAndKeys.push(
makeindexNodeAndDir_ForAncestorIndex(v, currentRecordDir)
)
)(indexes)
return acc
},
{ lastIndexKey: "", nodesAndKeys: [] }
)(keyParts).nodesAndKeys
const rootIndexes = $(flatHierarchy, [
filter(n => isGlobalIndex(n) && recordNodeIdIsAllowed(n)(nodeId)),
map(i => makeIndexNodeAndDir(i, getIndexDir(hierarchy, i.nodeKey()))),
])
return union(traverseAncestorIndexesInPath())(rootIndexes)
}
export const getRelevantReverseReferenceIndexes = (hierarchy, record) =>
$(record.key, [
getExactNodeForKey(hierarchy),
n => n.fields,
filter(
f =>
f.type === "reference" &&
isSomething(record[f.name]) &&
isNonEmptyString(record[f.name].key)
),
map(f =>
$(f.typeOptions.reverseIndexNodeKeys, [
map(n => ({
recordNode: getNode(hierarchy, n),
field: f,
})),
])
),
flatten,
map(n =>
makeIndexNodeAndDir(
n.recordNode,
joinKey(
getRecordInfo(hierarchy, record[n.field.name].key).dir,
n.recordNode.name
)
)
),
])
const makeIndexNodeAndDir = (indexNode, indexDir) => ({ indexNode, indexDir })
export default getRelevantAncestorIndexes