Skip to content

Commit

Permalink
Parse Error || Result Error (#3065)
Browse files Browse the repository at this point in the history
  • Loading branch information
jameskerr authored May 7, 2024
1 parent bd89e0b commit f7727f3
Show file tree
Hide file tree
Showing 18 changed files with 203 additions and 112 deletions.
15 changes: 15 additions & 0 deletions apps/zui/src/core/state-object.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import {useState} from "react"

export function useStateObject<T>(init: T) {
const [state, setState] = useState<T>(init)

return {
...state,
set: setState,
setItem: (key: string, value: any) => {
setState((prev) => ({...prev, [key]: value}))
},
}
}

export type StateObject<S> = S & ReturnType<typeof useStateObject>
27 changes: 27 additions & 0 deletions apps/zui/src/core/view-handler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import {Dispatch, State, Store} from "src/js/state/types"
import {ipc} from "src/modules/bullet/view"
import {invoke} from "./invoke"

type Selector = (state: State, ...args: any) => any

export class ViewHandler {
static store: Store
static invoke = invoke
protected invoke = invoke

protected get store() {
return ViewHandler.store
}

protected dispatch(action: Parameters<Dispatch>[0]) {
return this.store.dispatch(action)
}

protected select<T extends Selector>(selector: T): ReturnType<T> {
return selector(this.store.getState())
}

protected request(path: string, params?: object) {
return ipc.request(path, params)
}
}
8 changes: 6 additions & 2 deletions apps/zui/src/domain/editor/operations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ import {createOperation} from "src/core/operations"
import {lake} from "src/zui"

export const parse = createOperation("editor.parse", async (ctx, string) => {
const resp = await lake.client.compile(string)
return resp.toJS()
try {
const resp = await lake.client.compile(string)
return resp.toJS()
} catch (error) {
return {error: error.toString()}
}
})
7 changes: 3 additions & 4 deletions apps/zui/src/domain/editor/parse.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@ test("editor.parse", async () => {
})

test("editor.parse error", async () => {
await expect(parse("from source | ;;;(")).rejects.toHaveProperty(
"error",
expect.stringContaining("error parsing Zed at column 15")
)
await expect(parse("from source | ;;;(")).resolves.toEqual({
error: expect.stringContaining("error parsing Zed at column 15"),
})
})
14 changes: 2 additions & 12 deletions apps/zui/src/domain/session/handlers/queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,18 +32,8 @@ export const resetQuery = createHandler("session.resetQuery", () => {
session.navigate(session.snapshot)
})

const fetchAst = createHandler(async ({invoke}, string) => {
let tree
try {
tree = await invoke("editor.parse", string)
} catch (error) {
tree = {error}
}
return tree
})

export const fetchQueryInfo = createHandler(async (_, query: string) => {
const tree = await fetchAst(query)
export const fetchQueryInfo = createHandler(async ({invoke}, query: string) => {
const tree = await invoke("editor.parse", query)
const ast = new ZedAst(tree, tree.error)
return {
isSummarized: ast.isSummarized,
Expand Down
2 changes: 2 additions & 0 deletions apps/zui/src/js/initializers/initialize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {createWaitForSelector} from "src/app/core/state/create-wait-for-selector
import {initAsyncTasks} from "./init-async-tasks"
import {Renderer} from "src/core/renderer"
import {initDomainModels} from "./init-domain-models"
import {ViewHandler} from "src/core/view-handler"

const getWindowId = () => {
const params = new URLSearchParams(window.location.search)
Expand Down Expand Up @@ -62,6 +63,7 @@ export default async function initialize(
initDomainModels({
store,
})
ViewHandler.store = store
setMenuContext({select: (fn) => fn(store.getState()), api})
initDebugGlobals(store, api)
initAutosave(store)
Expand Down
1 change: 1 addition & 0 deletions apps/zui/src/js/state/QueryInfo/selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ export const get = activeTabSelect((tab) => {
return tab.queryInfo
})

export const getParseError = createSelector(get, (info) => info.error)
export const getIsParsed = createSelector(get, (info) => info.isParsed)
export const getIsSummarized = createSelector(get, (info) => info.isSummarized)
15 changes: 15 additions & 0 deletions apps/zui/src/modules/bullet/main/application.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import {ipc} from "./ipc"

class Application {
controllers: any[] = []

config(fn) {
return fn(this)
}

boot() {
ipc.listen()
}
}

export const BulletApplication = new Application()
1 change: 1 addition & 0 deletions apps/zui/src/modules/bullet/main/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./application"
20 changes: 20 additions & 0 deletions apps/zui/src/modules/bullet/main/ipc.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import {ipcMain} from "electron"
import {camelCase, capitalize} from "lodash"
import {BulletApplication} from "./application"

class MainIpc {
listen() {
ipcMain.handle("bullet:view-request", (e, controllerAction, params) => {
const [shortName, action] = controllerAction.split("#")
const name = capitalize(camelCase(shortName)) + "Controller"
const Controller = BulletApplication.controllers[name]
if (!Controller) {
throw new Error("ControllerNotFound: " + controllerAction)
}
const instance = new Controller()
return instance[action](params)
})
}
}

export const ipc = new MainIpc()
1 change: 1 addition & 0 deletions apps/zui/src/modules/bullet/view/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./ipc"
7 changes: 7 additions & 0 deletions apps/zui/src/modules/bullet/view/ipc.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export class ViewIpc {
request(path: string, params: any) {
return global.zui.invoke("bullet:view-request", path, params)
}
}

export const ipc = new ViewIpc()
4 changes: 2 additions & 2 deletions apps/zui/src/views/application/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ import {useAppMenu} from "./use-app-menu"
import {WelcomePage} from "src/views/welcome-page"
import {useReleaseNotes} from "./use-release-notes"
import {InitPool, Show} from "src/views/pool-page"
import {SessionRoute} from "src/views/session-page/route"
import Head from "next/head"
import {useTabId} from "src/app/core/hooks/use-tab-id"
import {NoTabsPane} from "src/views/no-tabs-pane"
import {SessionPage} from "../session-page"

function AppRoutes() {
return (
Expand All @@ -27,7 +27,7 @@ function AppRoutes() {
</InitPool>
</Route>
<Route path={routes.query.path}>
<SessionRoute />
<SessionPage />
</Route>
<Route path={routes.welcome.path}>
<WelcomePage />
Expand Down
5 changes: 3 additions & 2 deletions apps/zui/src/views/results-pane/context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import Results from "src/js/state/Results"
import {RESULTS_QUERY} from "src/views/results-pane/run-results-query"
import {useDataTransition} from "src/util/hooks/use-data-transition"
import useResizeObserver from "use-resize-observer"
import QueryInfo from "src/js/state/QueryInfo"

function useContextValue(parentRef: React.RefObject<HTMLDivElement>) {
const rect = useResizeObserver({ref: parentRef})
Expand All @@ -15,12 +16,12 @@ function useContextValue(parentRef: React.RefObject<HTMLDivElement>) {
const r = useResults(RESULTS_QUERY)
const results = useDataTransition(r, r.data.length === 0 && fetching)
const shapes = useMemo(() => Object.values(results.shapes), [results.shapes])

const parseError = useSelector(QueryInfo.getParseError)
return {
width: rect.width ?? 1000,
height: rect.height ?? 1000,
view: useSelector(Layout.getResultsView),
error: results.error,
error: parseError || results.error,
values: results.data,
shapes,
isSingleShape: shapes.length === 1,
Expand Down
83 changes: 83 additions & 0 deletions apps/zui/src/views/session-page/handler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import {ViewHandler} from "src/core/view-handler"
import {Active} from "src/models/active"
import QueryInfo from "src/js/state/QueryInfo"
import Tabs from "src/js/state/Tabs"
import Notice from "src/js/state/Notice"
import Editor from "src/js/state/Editor"
import {startTransition} from "react"
import {
runResultsCount,
runResultsMain,
} from "../results-pane/run-results-query"
import Layout from "src/js/state/Layout"
import {runHistogramQuery} from "../histogram-pane/run-query"
import {fetchQueryInfo} from "src/domain/session/handlers"
import Current from "src/js/state/Current"
import Pools from "src/js/state/Pools"
import {syncPool} from "src/app/core/pools/sync-pool"

type Props = {
locationKey: string
}

export class SessionPageHandler extends ViewHandler {
constructor(public props: Props) {
super()
}

load() {
this.reset()
this.setEditorValues()
this.fetchResults()
this.parseQueryText()
}

private reset() {
this.dispatch(QueryInfo.reset())
this.dispatch(Tabs.loaded(this.props.locationKey))
this.dispatch(Notice.dismiss()) // This may not be needed any more
}

private setEditorValues() {
const snapshot = Active.session.snapshot
// Give editor a chance to update by scheduling this update
setTimeout(() => {
this.dispatch(Editor.setValue(snapshot.attrs.value ?? ""))
this.dispatch(Editor.setPins(snapshot.attrs.pins || []))
})
}

private fetchResults() {
startTransition(() => {
runResultsMain()
runResultsCount()
if (this.histogramVisible) runHistogramQuery()
})
}

private get histogramVisible() {
return this.select(Layout.getShowHistogram)
}

private async parseQueryText() {
const {session} = Active
const lakeId = this.select(Current.getLakeId)
const program = this.select(Current.getQueryText)
const history = this.select(Current.getHistory)

fetchQueryInfo(program).then((info) => {
const {poolName, error} = info
const pool = this.select(Pools.getByName(lakeId, poolName))

this.dispatch(QueryInfo.set({isParsed: true, ...info}))
this.invoke("updatePluginSessionOp", {poolName, program})
if (pool && !pool.hasSpan()) {
this.dispatch(syncPool(pool.id, lakeId))
}

if (!error && history.action === "PUSH") {
session.pushHistory()
}
})
}
}
15 changes: 15 additions & 0 deletions apps/zui/src/views/session-page/index.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,26 @@
import {useLayoutEffect} from "react"
import {Editor} from "./editor"
import {Footer} from "./footer"
import {Grid} from "./grid"
import {Pins} from "./pins"
import {Results} from "./results"
import {Toolbar} from "./toolbar"
import {useSelector} from "react-redux"
import Current from "src/js/state/Current"
import Tab from "src/js/state/Tab"
import {SessionPageHandler} from "./handler"

export function SessionPage() {
const locationKey = useSelector(Current.getLocation).key
const tabKey = useSelector(Tab.getLastLocationKey)
const handler = new SessionPageHandler({locationKey})

useLayoutEffect(() => {
// When you switch tabs, the location key changes, but you don't want to reload
const tabHasLoaded = tabKey === locationKey
if (!tabHasLoaded) handler.load()
}, [locationKey, tabKey])

return (
<Grid>
<Toolbar />
Expand Down
68 changes: 0 additions & 68 deletions apps/zui/src/views/session-page/loader.ts

This file was deleted.

Loading

0 comments on commit f7727f3

Please sign in to comment.