Skip to content

Instantly share code, notes, and snippets.

@akrolsmir
Created September 2, 2020 19:59
Show Gist options
  • Save akrolsmir/9452e328b4c9ce33bdafe84bab26f69a to your computer and use it in GitHub Desktop.
Save akrolsmir/9452e328b4c9ce33bdafe84bab26f69a to your computer and use it in GitHub Desktop.
DeltaParser.ts, without Immutable
/**
* @license
* Copyright 2018-2020 Streamlit Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {
BlockPath,
Delta,
IForwardMsgMetadata,
NamedDataSet,
IElement,
} from "autogen/proto"
import { List, Map as ImmutableMap } from "immutable"
import { addRows } from "lib/dataFrameProto"
// NOTE: We skipped metrics here
import { MetricsManager } from "lib/MetricsManager"
import { requireNonNull } from "lib/utils"
// The actual protobuf Element.proto
export type SimpleElement = IElement
// A list of nodes to render (e.g. main, sidebar, st.container, st.column)
export interface BlockElement extends List<Node> {}
export class Node {
element: SimpleElement | BlockElement
reportId: string
metadata?: IForwardMsgMetadata
constructor(
element: SimpleElement | BlockElement,
reportId?: string,
metadata?: IForwardMsgMetadata
) {
this.element = element
this.reportId = reportId || ""
this.metadata = metadata
}
pathFind(path: Array<number>): Node {
// Base case: we've hit the end of the path
if (path.length == 0) {
return this
}
// Recursive case
const list = this.element as BlockElement
return list.get(path[0])!.pathFind(path.slice(1))
}
pathSet(path: Array<number>, node: Node) {
if (path.length == 0) {
throw "Path must contain at least 1 index"
}
const list = this.element as BlockElement
// Base case: this is the one to set
if (path.length == 1) {
// TODO: verify this is BlockElement
this.element = list.set(path[0], node)
}
// Recursive case
list.get(path[0])!.pathSet(path.slice(1), node)
}
}
// const main = new Node(List())
// const sidebar = new Node(List())
// export const ROOT = new Node(List([main, sidebar]))
export function applyDelta(
root: Node,
reportId: string,
deltaMsg: Delta,
metadata: IForwardMsgMetadata | null | undefined
): Node {
if (!metadata) {
throw new Error("Delta metadata is required")
}
const parentBlock = requireNonNull(metadata.parentBlock)
const parentBlockPath = requireNonNull(parentBlock.path)
const path = [
BlockPath.Container.MAIN,
...parentBlockPath,
metadata.deltaId as number,
]
if (deltaMsg.type == "newElement") {
const node = new Node(deltaMsg.newElement!, reportId, metadata)
root.pathSet(path, node)
}
if (deltaMsg.type == "newBlock") {
const node = new Node(List(), reportId, metadata)
root.pathSet(path, node)
}
if (deltaMsg.type == "addRows") {
const oldElement = root.pathFind(path).element
// NOTE: this probably doesn't work, need to convert between INamedDataSet and ImmutableMap
const rowsAdded = addRows(oldElement, deltaMsg.addRows)
const node = new Node(rowsAdded, reportId, metadata)
root.pathSet(path, node)
}
return root
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment