mirror of
https://github.com/enso-org/enso.git
synced 2024-12-27 04:12:56 +03:00
More consistent reactive indices (#8353)
- Renames all `ReactiveIndex` and `ReactiveDb`s into the format `<key>To<value>` - `ReactiveMapping`s (in `graphDatabase.ts`) currently have not been renamed - I'm not sure they need to be - Removes various methods that have been made unnecessary by this change - Simplifies some other methods - Changes `SuggestionDb` to extend `ReactiveDb` # Important Notes None
This commit is contained in:
parent
268e595ec1
commit
1cf5ea96d6
@ -57,7 +57,7 @@ watchEffect(() => {
|
||||
const dom = document.createElement('div')
|
||||
const astSpan = ast.span()
|
||||
let foundNode: ExprId | undefined
|
||||
for (const [id, node] of graphStore.db.allNodes()) {
|
||||
for (const [id, node] of graphStore.db.nodeIdToNode.entries()) {
|
||||
if (rangeEncloses(node.rootSpan.span(), astSpan)) {
|
||||
foundNode = id
|
||||
break
|
||||
|
@ -102,8 +102,8 @@ test.each([
|
||||
profilingInfo: [],
|
||||
})
|
||||
const mockGraphDb = GraphDb.Mock(computedValueRegistryMock)
|
||||
mockGraphDb.nodes.set(operator1Id, mockNode('operator1', operator1Id))
|
||||
mockGraphDb.nodes.set(operator2Id, mockNode('operator2', operator2Id))
|
||||
mockGraphDb.nodeIdToNode.set(operator1Id, mockNode('operator1', operator1Id))
|
||||
mockGraphDb.nodeIdToNode.set(operator2Id, mockNode('operator2', operator2Id))
|
||||
|
||||
const input = useComponentBrowserInput(mockGraphDb)
|
||||
input.code.value = code
|
||||
|
@ -58,7 +58,8 @@ const name = computed<Opt<QualifiedName>>(() => {
|
||||
// === Breadcrumbs ===
|
||||
|
||||
const color = computed(() => {
|
||||
const groupIndex = db.entries.get(props.selectedEntry)?.groupIndex
|
||||
const groupIndex =
|
||||
props.selectedEntry != null ? db.entries.get(props.selectedEntry)?.groupIndex : undefined
|
||||
return groupColorStyle(tryGetIndex(db.groups, groupIndex))
|
||||
})
|
||||
|
||||
|
@ -108,7 +108,7 @@ export function lookupDocumentation(db: SuggestionDb, id: SuggestionId): Docs {
|
||||
|
||||
function getChildren(db: SuggestionDb, id: SuggestionId, kind: SuggestionKind): Docs[] {
|
||||
if (!id) return []
|
||||
const children = Array.from(db.parent.reverseLookup(id))
|
||||
const children = Array.from(db.childIdToParentId.reverseLookup(id))
|
||||
return children.reduce((acc: Docs[], id: SuggestionId) => {
|
||||
if (db.get(id)?.kind === kind) {
|
||||
const docs = lookupDocumentation(db, id)
|
||||
|
@ -54,14 +54,14 @@ const interactionBindingsHandler = interactionBindings.handler({
|
||||
click: (e) => (e instanceof MouseEvent ? interaction.handleClick(e) : false),
|
||||
})
|
||||
|
||||
// This is where the component browser should be placed when it is opened.
|
||||
/** Where the component browser should be placed when it is opened. */
|
||||
function targetComponentBrowserPosition() {
|
||||
const editedInfo = graphStore.editedNodeInfo
|
||||
const isEditingNode = editedInfo != null
|
||||
const hasNodeSelected = nodeSelection.selected.size > 0
|
||||
const nodeSize = new Vec2(0, 24)
|
||||
if (isEditingNode) {
|
||||
const targetNode = graphStore.db.nodes.get(editedInfo.id)
|
||||
const targetNode = graphStore.db.nodeIdToNode.get(editedInfo.id)
|
||||
const targetPos = targetNode?.position ?? Vec2.Zero
|
||||
return targetPos.add(COMPONENT_BROWSER_TO_NODE_OFFSET)
|
||||
} else if (hasNodeSelected) {
|
||||
@ -75,7 +75,7 @@ function targetComponentBrowserPosition() {
|
||||
}
|
||||
}
|
||||
|
||||
// This is the current position of the component browser.
|
||||
/** The current position of the component browser. */
|
||||
const componentBrowserPosition = ref<Vec2>(Vec2.Zero)
|
||||
|
||||
const graphEditorSourceNode = computed(() => {
|
||||
@ -132,7 +132,7 @@ const graphBindingsHandler = graphBindings.handler({
|
||||
graphStore.transact(() => {
|
||||
const allVisible = set
|
||||
.toArray(nodeSelection.selected)
|
||||
.every((id) => !(graphStore.db.getNode(id)?.vis?.visible !== true))
|
||||
.every((id) => !(graphStore.db.nodeIdToNode.get(id)?.vis?.visible !== true))
|
||||
|
||||
for (const nodeId of nodeSelection.selected) {
|
||||
graphStore.setNodeVisualizationVisible(nodeId, !allVisible)
|
||||
@ -158,7 +158,7 @@ const codeEditorHandler = codeEditorBindings.handler({
|
||||
},
|
||||
})
|
||||
|
||||
/// Track play button presses.
|
||||
/** Track play button presses. */
|
||||
function onPlayButtonPress() {
|
||||
projectStore.lsRpcConnection.then(async () => {
|
||||
const modeValue = projectStore.executionMode
|
||||
@ -169,7 +169,7 @@ function onPlayButtonPress() {
|
||||
})
|
||||
}
|
||||
|
||||
/// Watch for changes in the execution mode.
|
||||
// Watch for changes in the execution mode.
|
||||
watch(
|
||||
() => projectStore.executionMode,
|
||||
(modeValue) => {
|
||||
@ -252,10 +252,10 @@ async function handleFileDrop(event: DragEvent) {
|
||||
|
||||
function onComponentBrowserCommit(content: string) {
|
||||
if (content != null && graphStore.editedNodeInfo != null) {
|
||||
/// We finish editing a node.
|
||||
// We finish editing a node.
|
||||
graphStore.setNodeContent(graphStore.editedNodeInfo.id, content)
|
||||
} else if (content != null) {
|
||||
/// We finish creating a new node.
|
||||
// We finish creating a new node.
|
||||
const nodePosition = componentBrowserPosition.value
|
||||
graphStore.createNode(nodePosition.sub(COMPONENT_BROWSER_TO_NODE_OFFSET), content)
|
||||
}
|
||||
@ -270,16 +270,13 @@ function onComponentBrowserCancel() {
|
||||
interaction.setCurrent(undefined)
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
function getNodeContent(id: ExprId): string {
|
||||
const node = graphStore.db.nodes.get(id)
|
||||
const node = graphStore.db.nodeIdToNode.get(id)
|
||||
if (node == null) return ''
|
||||
return node.rootSpan.repr()
|
||||
}
|
||||
|
||||
// Watch the editedNode in the graph store
|
||||
// Watch the `editedNode` in the graph store
|
||||
watch(
|
||||
() => graphStore.editedNodeInfo,
|
||||
(editedInfo) => {
|
||||
@ -304,25 +301,25 @@ const breadcrumbs = computed(() => {
|
||||
})
|
||||
})
|
||||
|
||||
/// === Clipboard ===
|
||||
// === Clipboard ===
|
||||
|
||||
const ENSO_MIME_TYPE = 'web application/enso'
|
||||
|
||||
/// The data that is copied to the clipboard.
|
||||
/** The data that is copied to the clipboard. */
|
||||
interface ClipboardData {
|
||||
nodes: CopiedNode[]
|
||||
}
|
||||
|
||||
/// Node data that is copied to the clipboard. Used for serializing and deserializing the node information.
|
||||
/** Node data that is copied to the clipboard. Used for serializing and deserializing the node information. */
|
||||
interface CopiedNode {
|
||||
expression: string
|
||||
metadata: NodeMetadata | undefined
|
||||
}
|
||||
|
||||
/// Copy the content of the selected node to the clipboard.
|
||||
/** Copy the content of the selected node to the clipboard. */
|
||||
function copyNodeContent() {
|
||||
const id = nodeSelection.selected.values().next().value
|
||||
const node = graphStore.db.nodes.get(id)
|
||||
const node = graphStore.db.nodeIdToNode.get(id)
|
||||
if (node == null) return
|
||||
const content = node.rootSpan.repr()
|
||||
const metadata = projectStore.module?.getNodeMetadata(id) ?? undefined
|
||||
|
@ -24,7 +24,7 @@ const sourceNode = computed(() => {
|
||||
// When the source is not set (i.e. edge is dragged), use the currently hovered over expression
|
||||
// as the source, as long as it is not from the same node as the target.
|
||||
if (setSource == null && selection?.hoveredNode != null) {
|
||||
const rawTargetNode = graph.db.getExpressionNodeId(props.edge.target)
|
||||
const rawTargetNode = props.edge.target && graph.db.getExpressionNodeId(props.edge.target)
|
||||
if (selection.hoveredNode != rawTargetNode) return selection.hoveredNode
|
||||
}
|
||||
return setSource
|
||||
@ -40,7 +40,9 @@ const targetExpr = computed(() => {
|
||||
return setTarget
|
||||
})
|
||||
|
||||
const targetNode = computed(() => graph.db.getExpressionNodeId(targetExpr.value))
|
||||
const targetNode = computed(
|
||||
() => targetExpr.value && graph.db.getExpressionNodeId(targetExpr.value),
|
||||
)
|
||||
const targetNodeRect = computed(() => targetNode.value && graph.nodeRects.get(targetNode.value))
|
||||
|
||||
const targetRect = computed<Rect | null>(() => {
|
||||
|
@ -21,7 +21,7 @@ const editingEdge: Interaction = {
|
||||
if (graph.unconnectedEdge == null) return false
|
||||
const source = graph.unconnectedEdge.source ?? selection?.hoveredNode
|
||||
const target = graph.unconnectedEdge.target ?? selection?.hoveredPort
|
||||
const targetNode = graph.db.getExpressionNodeId(target)
|
||||
const targetNode = target && graph.db.getExpressionNodeId(target)
|
||||
graph.transact(() => {
|
||||
if (source != null && source != targetNode) {
|
||||
if (target == null) {
|
||||
@ -42,11 +42,13 @@ interaction.setWhen(() => graph.unconnectedEdge != null, editingEdge)
|
||||
function disconnectEdge(target: ExprId) {
|
||||
graph.setExpressionContent(target, '_')
|
||||
}
|
||||
|
||||
function createNodeFromEdgeDrop(source: ExprId) {
|
||||
console.log(`TODO: createNodeFromEdgeDrop(${JSON.stringify(source)})`)
|
||||
}
|
||||
|
||||
function createEdge(source: ExprId, target: ExprId) {
|
||||
const sourceNode = graph.db.getNode(source)
|
||||
const sourceNode = graph.db.nodeIdToNode.get(source)
|
||||
if (sourceNode == null) return
|
||||
// TODO: Check alias analysis to see if the binding is shadowed.
|
||||
graph.setExpressionContent(target, sourceNode.binding)
|
||||
|
@ -45,7 +45,7 @@ const uploadingFiles = computed<[FileName, File][]>(() => {
|
||||
|
||||
<template>
|
||||
<GraphNode
|
||||
v-for="[id, node] in graphStore.db.allNodes()"
|
||||
v-for="[id, node] in graphStore.db.nodeIdToNode.entries()"
|
||||
:key="id"
|
||||
:node="node"
|
||||
:edited="id === graphStore.editedNodeInfo?.id"
|
||||
|
@ -105,7 +105,7 @@ export function useDragging() {
|
||||
function* draggedNodes(): Generator<[ExprId, DraggedNode]> {
|
||||
const ids = selection?.isSelected(movedId) ? selection.selected : [movedId]
|
||||
for (const id of ids) {
|
||||
const node = graphStore.db.nodes.get(id)
|
||||
const node = graphStore.db.nodeIdToNode.get(id)
|
||||
if (node != null) yield [id, { initialPos: node.position, currentPos: node.position }]
|
||||
}
|
||||
}
|
||||
@ -125,7 +125,7 @@ export function useDragging() {
|
||||
const rects: Rect[] = []
|
||||
for (const [id, { initialPos }] of this.draggedNodes) {
|
||||
const rect = graphStore.nodeRects.get(id)
|
||||
const node = graphStore.db.nodes.get(id)
|
||||
const node = graphStore.db.nodeIdToNode.get(id)
|
||||
if (rect != null && node != null) rects.push(new Rect(initialPos.add(newOffset), rect.size))
|
||||
}
|
||||
const snap = this.grid.snappedMany(rects, DRAG_SNAP_THRESHOLD)
|
||||
@ -161,7 +161,7 @@ export function useDragging() {
|
||||
|
||||
updateNodesPosition() {
|
||||
for (const [id, dragged] of this.draggedNodes) {
|
||||
const node = graphStore.db.nodes.get(id)
|
||||
const node = graphStore.db.nodeIdToNode.get(id)
|
||||
if (node == null) continue
|
||||
// If node was moved in other way than current dragging, we want to stop dragging it.
|
||||
if (node.position.distanceSquared(dragged.currentPos) > 1.0) {
|
||||
|
@ -34,7 +34,9 @@ const selection = injectGraphSelection(true)
|
||||
|
||||
const isHovered = ref(false)
|
||||
|
||||
const hasConnection = computed(() => graph.db.connections.reverseLookup(portId.value).size > 0)
|
||||
const hasConnection = computed(
|
||||
() => graph.db.sourceIdToTargetId.reverseLookup(portId.value).size > 0,
|
||||
)
|
||||
const isCurrentEdgeHoverTarget = computed(
|
||||
() => isHovered.value && graph.unconnectedEdge != null && selection?.hoveredPort === portId.value,
|
||||
)
|
||||
@ -166,6 +168,7 @@ export const widgetDefinition = defineWidget(
|
||||
},
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<span
|
||||
ref="rootNode"
|
||||
|
@ -23,8 +23,8 @@ import {
|
||||
import { ref, type Ref } from 'vue'
|
||||
|
||||
export class GraphDb {
|
||||
nodes = new ReactiveDb<ExprId, Node>()
|
||||
idents = new ReactiveIndex(this.nodes, (_id, entry) => {
|
||||
nodeIdToNode = new ReactiveDb<ExprId, Node>()
|
||||
nodeIdToBinding = new ReactiveIndex(this.nodeIdToNode, (_id, entry) => {
|
||||
const idents: [ExprId, string][] = []
|
||||
entry.rootSpan.visitRecursive((span) => {
|
||||
if (span.isTree(Ast.Tree.Type.Ident)) {
|
||||
@ -35,30 +35,31 @@ export class GraphDb {
|
||||
})
|
||||
return idents
|
||||
})
|
||||
private nodeExpressions = new ReactiveIndex(this.nodes, (id, entry) => {
|
||||
nodeIdToExprId = new ReactiveIndex(this.nodeIdToNode, (id, entry) => {
|
||||
const exprs = new Set<ExprId>()
|
||||
for (const ast of entry.rootSpan.walkRecursive()) {
|
||||
exprs.add(ast.astId)
|
||||
}
|
||||
return Array.from(exprs, (expr) => [id, expr])
|
||||
})
|
||||
nodeByBinding = new ReactiveIndex(this.nodes, (id, entry) => [[entry.binding, id]])
|
||||
connections = new ReactiveIndex(this.nodes, (id, entry) => {
|
||||
bindingToNodeId = new ReactiveIndex(this.nodeIdToNode, (id, entry) => [[entry.binding, id]])
|
||||
sourceIdToTargetId = new ReactiveIndex(this.nodeIdToNode, (id, entry) => {
|
||||
const usageEntries: [ExprId, ExprId][] = []
|
||||
const usages = this.idents.reverseLookup(entry.binding)
|
||||
const usages = this.nodeIdToBinding.reverseLookup(entry.binding)
|
||||
for (const usage of usages) {
|
||||
usageEntries.push([id, usage])
|
||||
}
|
||||
return usageEntries
|
||||
})
|
||||
nodeMainSuggestion = new ReactiveMapping(this.nodes, (id, _entry) => {
|
||||
nodeMainSuggestion = new ReactiveMapping(this.nodeIdToNode, (id, _entry) => {
|
||||
const expressionInfo = this.getExpressionInfo(id)
|
||||
const method = expressionInfo?.methodCall?.methodPointer
|
||||
if (method == null) return
|
||||
const suggestionId = this.suggestionDb.findByMethodPointer(method)
|
||||
if (suggestionId == null) return
|
||||
return this.suggestionDb.get(suggestionId)
|
||||
})
|
||||
private nodeColors = new ReactiveMapping(this.nodes, (id, _entry) => {
|
||||
nodeColor = new ReactiveMapping(this.nodeIdToNode, (id, _entry) => {
|
||||
const index = this.nodeMainSuggestion.lookup(id)?.groupIndex
|
||||
const group = tryGetIndex(this.groups.value, index)
|
||||
if (group == null) {
|
||||
@ -68,24 +69,12 @@ export class GraphDb {
|
||||
return groupColorStyle(group)
|
||||
})
|
||||
|
||||
getNode(id: ExprId): Node | undefined {
|
||||
return this.nodes.get(id)
|
||||
}
|
||||
|
||||
allNodes(): IterableIterator<[ExprId, Node]> {
|
||||
return this.nodes.entries()
|
||||
}
|
||||
|
||||
allNodeIds(): IterableIterator<ExprId> {
|
||||
return this.nodes.keys()
|
||||
}
|
||||
|
||||
getExpressionNodeId(exprId: ExprId | undefined): ExprId | undefined {
|
||||
return exprId && set.first(this.nodeExpressions.reverseLookup(exprId))
|
||||
getExpressionNodeId(exprId: ExprId): ExprId | undefined {
|
||||
return set.first(this.nodeIdToExprId.reverseLookup(exprId))
|
||||
}
|
||||
|
||||
getIdentDefiningNode(ident: string): ExprId | undefined {
|
||||
return set.first(this.nodeByBinding.lookup(ident))
|
||||
return set.first(this.bindingToNodeId.lookup(ident))
|
||||
}
|
||||
|
||||
getExpressionInfo(id: ExprId): ExpressionInfo | undefined {
|
||||
@ -102,17 +91,18 @@ export class GraphDb {
|
||||
const methodCall = this.getExpressionInfo(id)?.methodCall
|
||||
if (methodCall == null) return
|
||||
const suggestionId = this.suggestionDb.findByMethodPointer(methodCall.methodPointer)
|
||||
if (suggestionId == null) return
|
||||
const suggestion = this.suggestionDb.get(suggestionId)
|
||||
if (suggestion == null) return
|
||||
return { methodCall, suggestion }
|
||||
}
|
||||
|
||||
getNodeColorStyle(id: ExprId): string {
|
||||
return (id && this.nodeColors.lookup(id)) ?? 'var(--node-color-no-type)'
|
||||
return this.nodeColor.lookup(id) ?? 'var(--node-color-no-type)'
|
||||
}
|
||||
|
||||
moveNodeToTop(id: ExprId) {
|
||||
this.nodes.moveToLast(id)
|
||||
this.nodeIdToNode.moveToLast(id)
|
||||
}
|
||||
|
||||
getNodeWidth(node: Node) {
|
||||
@ -133,11 +123,11 @@ export class GraphDb {
|
||||
for (const nodeAst of functionAst.visit(getFunctionNodeExpressions)) {
|
||||
const newNode = nodeFromAst(nodeAst)
|
||||
const nodeId = newNode.rootSpan.astId
|
||||
const node = this.nodes.get(nodeId)
|
||||
const node = this.nodeIdToNode.get(nodeId)
|
||||
const nodeMeta = getMeta(nodeId)
|
||||
currentNodeIds.add(nodeId)
|
||||
if (node == null) {
|
||||
this.nodes.set(nodeId, newNode)
|
||||
this.nodeIdToNode.set(nodeId, newNode)
|
||||
} else {
|
||||
if (node.binding !== newNode.binding) {
|
||||
node.binding = newNode.binding
|
||||
@ -170,9 +160,9 @@ export class GraphDb {
|
||||
}
|
||||
}
|
||||
|
||||
for (const nodeId of this.allNodeIds()) {
|
||||
for (const nodeId of this.nodeIdToNode.keys()) {
|
||||
if (!currentNodeIds.has(nodeId)) {
|
||||
this.nodes.delete(nodeId)
|
||||
this.nodeIdToNode.delete(nodeId)
|
||||
}
|
||||
}
|
||||
|
||||
@ -191,10 +181,10 @@ export class GraphDb {
|
||||
},
|
||||
)
|
||||
let nodeIndex = 0
|
||||
for (const nodeId of this.allNodeIds()) {
|
||||
for (const nodeId of this.nodeIdToNode.keys()) {
|
||||
const meta = getMeta(nodeId)
|
||||
if (meta) continue
|
||||
const node = this.nodes.get(nodeId)!
|
||||
const node = this.nodeIdToNode.get(nodeId)!
|
||||
const size = new Vec2(this.getNodeWidth(node), theme.node.height)
|
||||
const position = new Vec2(
|
||||
rectsPosition.x,
|
||||
|
@ -109,7 +109,7 @@ export const useGraphStore = defineStore('graph', () => {
|
||||
for (const [id, op] of event.changes.keys) {
|
||||
if (op.action === 'update' || op.action === 'add') {
|
||||
const data = meta.get(id)
|
||||
const node = db.getNode(id as ExprId)
|
||||
const node = db.nodeIdToNode.get(id as ExprId)
|
||||
if (data != null && node != null) {
|
||||
db.assignUpdatedMetadata(node, data)
|
||||
}
|
||||
@ -121,14 +121,14 @@ export const useGraphStore = defineStore('graph', () => {
|
||||
let ident: string
|
||||
do {
|
||||
ident = randomString()
|
||||
} while (db.idents.hasValue(ident))
|
||||
} while (db.nodeIdToBinding.hasValue(ident))
|
||||
return ident
|
||||
}
|
||||
|
||||
const edges = computed(() => {
|
||||
const disconnectedEdgeTarget = unconnectedEdge.value?.disconnectedEdgeTarget
|
||||
const edges = []
|
||||
for (const [target, sources] of db.connections.allReverse()) {
|
||||
for (const [target, sources] of db.sourceIdToTargetId.allReverse()) {
|
||||
if (target === disconnectedEdgeTarget) continue
|
||||
for (const source of sources) {
|
||||
edges.push({ source, target })
|
||||
@ -177,13 +177,13 @@ export const useGraphStore = defineStore('graph', () => {
|
||||
}
|
||||
|
||||
function deleteNode(id: ExprId) {
|
||||
const node = db.getNode(id)
|
||||
const node = db.nodeIdToNode.get(id)
|
||||
if (node == null) return
|
||||
proj.module?.deleteExpression(node.outerExprId)
|
||||
}
|
||||
|
||||
function setNodeContent(id: ExprId, content: string) {
|
||||
const node = db.getNode(id)
|
||||
const node = db.nodeIdToNode.get(id)
|
||||
if (node == null) return
|
||||
setExpressionContent(node.rootSpan.astId, content)
|
||||
}
|
||||
@ -201,13 +201,13 @@ export const useGraphStore = defineStore('graph', () => {
|
||||
}
|
||||
|
||||
function replaceNodeSubexpression(nodeId: ExprId, range: ContentRange, content: string) {
|
||||
const node = db.getNode(nodeId)
|
||||
const node = db.nodeIdToNode.get(nodeId)
|
||||
if (node == null) return
|
||||
proj.module?.replaceExpressionContent(node.rootSpan.astId, content, range)
|
||||
}
|
||||
|
||||
function setNodePosition(nodeId: ExprId, position: Vec2) {
|
||||
const node = db.getNode(nodeId)
|
||||
const node = db.nodeIdToNode.get(nodeId)
|
||||
if (node == null) return
|
||||
proj.module?.updateNodeMetadata(nodeId, { x: position.x, y: -position.y })
|
||||
}
|
||||
@ -231,13 +231,13 @@ export const useGraphStore = defineStore('graph', () => {
|
||||
}
|
||||
|
||||
function setNodeVisualizationId(nodeId: ExprId, vis: Opt<VisualizationIdentifier>) {
|
||||
const node = db.getNode(nodeId)
|
||||
const node = db.nodeIdToNode.get(nodeId)
|
||||
if (node == null) return
|
||||
proj.module?.updateNodeMetadata(nodeId, { vis: normalizeVisMetadata(vis, node.vis?.visible) })
|
||||
}
|
||||
|
||||
function setNodeVisualizationVisible(nodeId: ExprId, visible: boolean) {
|
||||
const node = db.getNode(nodeId)
|
||||
const node = db.nodeIdToNode.get(nodeId)
|
||||
if (node == null) return
|
||||
proj.module?.updateNodeMetadata(nodeId, { vis: normalizeVisMetadata(node.vis, visible) })
|
||||
}
|
||||
@ -269,7 +269,7 @@ export const useGraphStore = defineStore('graph', () => {
|
||||
}
|
||||
|
||||
function getNodeBinding(id: ExprId): string {
|
||||
return db.nodes.get(id)?.binding ?? ''
|
||||
return db.nodeIdToNode.get(id)?.binding ?? ''
|
||||
}
|
||||
|
||||
return {
|
||||
|
@ -42,22 +42,22 @@ test('Parent-children indexing', () => {
|
||||
const db = new SuggestionDb()
|
||||
applyUpdates(db, test.addUpdatesForExpected(), test.groups)
|
||||
// Parent lookup.
|
||||
expect(db.parent.lookup(1)).toEqual(new Set([]))
|
||||
expect(db.parent.lookup(2)).toEqual(new Set([1]))
|
||||
expect(db.parent.lookup(3)).toEqual(new Set([2]))
|
||||
expect(db.parent.lookup(4)).toEqual(new Set([2]))
|
||||
expect(db.parent.lookup(5)).toEqual(new Set([2]))
|
||||
expect(db.parent.lookup(6)).toEqual(new Set([1]))
|
||||
expect(db.parent.lookup(7)).toEqual(new Set([1]))
|
||||
expect(db.childIdToParentId.lookup(1)).toEqual(new Set([]))
|
||||
expect(db.childIdToParentId.lookup(2)).toEqual(new Set([1]))
|
||||
expect(db.childIdToParentId.lookup(3)).toEqual(new Set([2]))
|
||||
expect(db.childIdToParentId.lookup(4)).toEqual(new Set([2]))
|
||||
expect(db.childIdToParentId.lookup(5)).toEqual(new Set([2]))
|
||||
expect(db.childIdToParentId.lookup(6)).toEqual(new Set([1]))
|
||||
expect(db.childIdToParentId.lookup(7)).toEqual(new Set([1]))
|
||||
|
||||
// Children lookup.
|
||||
expect(db.parent.reverseLookup(1)).toEqual(new Set([2, 6, 7]))
|
||||
expect(db.parent.reverseLookup(2)).toEqual(new Set([3, 4, 5]))
|
||||
expect(db.parent.reverseLookup(3)).toEqual(new Set([]))
|
||||
expect(db.parent.reverseLookup(4)).toEqual(new Set([]))
|
||||
expect(db.parent.reverseLookup(5)).toEqual(new Set([]))
|
||||
expect(db.parent.reverseLookup(6)).toEqual(new Set([]))
|
||||
expect(db.parent.reverseLookup(7)).toEqual(new Set([]))
|
||||
expect(db.childIdToParentId.reverseLookup(1)).toEqual(new Set([2, 6, 7]))
|
||||
expect(db.childIdToParentId.reverseLookup(2)).toEqual(new Set([3, 4, 5]))
|
||||
expect(db.childIdToParentId.reverseLookup(3)).toEqual(new Set([]))
|
||||
expect(db.childIdToParentId.reverseLookup(4)).toEqual(new Set([]))
|
||||
expect(db.childIdToParentId.reverseLookup(5)).toEqual(new Set([]))
|
||||
expect(db.childIdToParentId.reverseLookup(6)).toEqual(new Set([]))
|
||||
expect(db.childIdToParentId.reverseLookup(7)).toEqual(new Set([]))
|
||||
|
||||
// Add new entry.
|
||||
const modifications: lsTypes.SuggestionsDatabaseUpdate[] = [
|
||||
@ -78,22 +78,22 @@ test('Parent-children indexing', () => {
|
||||
},
|
||||
]
|
||||
applyUpdates(db, modifications, test.groups)
|
||||
expect(db.parent.lookup(8)).toEqual(new Set([2]))
|
||||
expect(db.parent.reverseLookup(8)).toEqual(new Set([]))
|
||||
expect(db.parent.reverseLookup(2)).toEqual(new Set([3, 4, 5, 8]))
|
||||
expect(db.childIdToParentId.lookup(8)).toEqual(new Set([2]))
|
||||
expect(db.childIdToParentId.reverseLookup(8)).toEqual(new Set([]))
|
||||
expect(db.childIdToParentId.reverseLookup(2)).toEqual(new Set([3, 4, 5, 8]))
|
||||
|
||||
// Remove entry.
|
||||
const modifications2: lsTypes.SuggestionsDatabaseUpdate[] = [{ type: 'Remove', id: 3 }]
|
||||
applyUpdates(db, modifications2, test.groups)
|
||||
expect(db.parent.lookup(3)).toEqual(new Set([]))
|
||||
expect(db.parent.reverseLookup(2)).toEqual(new Set([4, 5, 8]))
|
||||
expect(db.childIdToParentId.lookup(3)).toEqual(new Set([]))
|
||||
expect(db.childIdToParentId.reverseLookup(2)).toEqual(new Set([4, 5, 8]))
|
||||
|
||||
// Modify entry. Moving new method from `Standard.Base.Type` to `Standard.Base`.
|
||||
db.get(8)!.memberOf = 'Standard.Base' as QualifiedName
|
||||
expect(db.parent.reverseLookup(1)).toEqual(new Set([2, 6, 7, 8]))
|
||||
expect(db.parent.lookup(8)).toEqual(new Set([1]))
|
||||
expect(db.parent.reverseLookup(8)).toEqual(new Set([]))
|
||||
expect(db.parent.reverseLookup(2)).toEqual(new Set([4, 5]))
|
||||
expect(db.childIdToParentId.reverseLookup(1)).toEqual(new Set([2, 6, 7, 8]))
|
||||
expect(db.childIdToParentId.lookup(8)).toEqual(new Set([1]))
|
||||
expect(db.childIdToParentId.reverseLookup(8)).toEqual(new Set([]))
|
||||
expect(db.childIdToParentId.reverseLookup(2)).toEqual(new Set([4, 5]))
|
||||
})
|
||||
|
||||
test("Modifying suggestion entries' fields", () => {
|
||||
|
@ -10,10 +10,9 @@ import { LanguageServer } from 'shared/languageServer'
|
||||
import type { MethodPointer } from 'shared/languageServerTypes'
|
||||
import { markRaw, ref, type Ref } from 'vue'
|
||||
|
||||
export class SuggestionDb {
|
||||
_internal = new ReactiveDb<SuggestionId, SuggestionEntry>()
|
||||
nameToId = new ReactiveIndex(this._internal, (id, entry) => [[entryQn(entry), id]])
|
||||
parent = new ReactiveIndex(this._internal, (id, entry) => {
|
||||
export class SuggestionDb extends ReactiveDb<SuggestionId, SuggestionEntry> {
|
||||
nameToId = new ReactiveIndex(this, (id, entry) => [[entryQn(entry), id]])
|
||||
childIdToParentId = new ReactiveIndex(this, (id, entry) => {
|
||||
let qualifiedName: Opt<QualifiedName>
|
||||
if (entry.memberOf) {
|
||||
qualifiedName = entry.memberOf
|
||||
@ -27,19 +26,6 @@ export class SuggestionDb {
|
||||
return []
|
||||
})
|
||||
|
||||
set(id: SuggestionId, entry: SuggestionEntry): void {
|
||||
this._internal.set(id, entry)
|
||||
}
|
||||
get(id: SuggestionId | null | undefined): SuggestionEntry | undefined {
|
||||
return id != null ? this._internal.get(id) : undefined
|
||||
}
|
||||
delete(id: SuggestionId): boolean {
|
||||
return this._internal.delete(id)
|
||||
}
|
||||
entries(): IterableIterator<[SuggestionId, SuggestionEntry]> {
|
||||
return this._internal.entries()
|
||||
}
|
||||
|
||||
findByMethodPointer(method: MethodPointer): SuggestionId | undefined {
|
||||
if (method == null) return
|
||||
const moduleName = tryQualifiedName(method.definedOnType)
|
||||
|
@ -36,18 +36,18 @@ test('metadata index', () => {
|
||||
const b = toVisualizationId({ module: { kind: 'Builtin' }, name: 'b' })
|
||||
db.set(a, { name: 'a', inputType: 'B | C' })
|
||||
db.set(b, { name: 'b', inputType: 'C | D | E' })
|
||||
expect(db.types.lookup(a)).toEqual(new Set(['B', 'C']))
|
||||
expect(db.types.lookup(b)).toEqual(new Set(['C', 'D', 'E']))
|
||||
expect(db.types.reverseLookup('B')).toEqual(new Set([a]))
|
||||
expect(db.types.reverseLookup('C')).toEqual(new Set([a, b]))
|
||||
expect(db.types.reverseLookup('D')).toEqual(new Set([b]))
|
||||
expect(db.types.reverseLookup('E')).toEqual(new Set([b]))
|
||||
expect(db.visualizationIdToType.lookup(a)).toEqual(new Set(['B', 'C']))
|
||||
expect(db.visualizationIdToType.lookup(b)).toEqual(new Set(['C', 'D', 'E']))
|
||||
expect(db.visualizationIdToType.reverseLookup('B')).toEqual(new Set([a]))
|
||||
expect(db.visualizationIdToType.reverseLookup('C')).toEqual(new Set([a, b]))
|
||||
expect(db.visualizationIdToType.reverseLookup('D')).toEqual(new Set([b]))
|
||||
expect(db.visualizationIdToType.reverseLookup('E')).toEqual(new Set([b]))
|
||||
|
||||
db.delete(b)
|
||||
expect(db.types.lookup(a)).toEqual(new Set(['B', 'C']))
|
||||
expect(db.types.lookup(b)).toEqual(new Set())
|
||||
expect(db.types.reverseLookup('B')).toEqual(new Set([a]))
|
||||
expect(db.types.reverseLookup('C')).toEqual(new Set([a]))
|
||||
expect(db.types.reverseLookup('D')).toEqual(new Set())
|
||||
expect(db.types.reverseLookup('E')).toEqual(new Set())
|
||||
expect(db.visualizationIdToType.lookup(a)).toEqual(new Set(['B', 'C']))
|
||||
expect(db.visualizationIdToType.lookup(b)).toEqual(new Set())
|
||||
expect(db.visualizationIdToType.reverseLookup('B')).toEqual(new Set([a]))
|
||||
expect(db.visualizationIdToType.reverseLookup('C')).toEqual(new Set([a]))
|
||||
expect(db.visualizationIdToType.reverseLookup('D')).toEqual(new Set())
|
||||
expect(db.visualizationIdToType.reverseLookup('E')).toEqual(new Set())
|
||||
})
|
||||
|
@ -224,8 +224,8 @@ export const useVisualizationStore = defineStore('visualization', () => {
|
||||
type == null
|
||||
? metadata.keys()
|
||||
: new Set([
|
||||
...(metadata.types.reverseLookup(type) ?? []),
|
||||
...(metadata.types.reverseLookup('Any') ?? []),
|
||||
...(metadata.visualizationIdToType.reverseLookup(type) ?? []),
|
||||
...(metadata.visualizationIdToType.reverseLookup('Any') ?? []),
|
||||
])
|
||||
for (const type of types) yield fromVisualizationId(type)
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ export function fromVisualizationId(key: VisualizationId): VisualizationIdentifi
|
||||
}
|
||||
|
||||
export class VisualizationMetadataDb extends ReactiveDb<VisualizationId, VisualizationMetadata> {
|
||||
types = new ReactiveIndex(this, (key, metadata) =>
|
||||
visualizationIdToType = new ReactiveIndex(this, (key, metadata) =>
|
||||
getTypesFromUnion(metadata.inputType).map((type) => [key, type]),
|
||||
)
|
||||
}
|
||||
|
@ -266,7 +266,7 @@ export class ReactiveIndex<K, V, IK, IV> {
|
||||
export type Mapper<K, V, IV> = (key: K, value: V) => IV | undefined
|
||||
|
||||
/**
|
||||
* A one-to-one mapping for values in a {@link ReactiveDb} instance. Allows only one value per key.
|
||||
* A one-to-one mapping for values in a {@link ReactiveDb} instance. Allows only one value per key.
|
||||
* It can be thought of as a collection of `computed` values per each key in the `ReactiveDb`. The
|
||||
* mapping is automatically updated when any of its dependencies change, and is properly cleaned up
|
||||
* when any key is removed from {@link ReactiveDb}. Only accessed keys are ever actually computed.
|
||||
|
Loading…
Reference in New Issue
Block a user