README.md78 lines · main
1# SQL Editor Overview
2
3Quick run-through of the different building blocks that make up the SQL Editor, to help navigating the codebase a little easier 🙂🙏
4
5## UI structure
6
7- Folders and snippets (in the product menu) are rendered via `SQLEditorMenu` and `SQLEditorNav`, in which the data are all loaded from the API via React Query directly. (Refer to point 3 under "Data Structure" below)
8 - [`SQLEditorMenu`](https://github.com/briven/briven/blob/master/apps/studio/components/layouts/SQLEditorLayout/SQLEditorMenu.tsx): Wraps around `SQLEditorNav` + renders search input + View running queries button
9 - [`SQLEditorNav`](https://github.com/briven/briven/blob/master/apps/studio/components/layouts/SQLEditorLayout/SQLEditorNavV2/SQLEditorNav.tsx): Renders the 3 collapsible snippet sections
10
11- The Tabs interface is powered by a separate state [`tabs.ts`](https://github.com/briven/briven/blob/master/apps/studio/state/tabs.ts). (Also used by the Table Editor)
12
13- Route validation to check for snippet validity + last visited snippet lies in the page level on [`[id].tsx`](https://github.com/briven/briven/blob/master/apps/studio/pages/project/%5Bref%5D/sql/%5Bid%5D.tsx)
14
15- When searching for snippets, we're deliberately opting to render the results as a flat list in [`SearchList`](https://github.com/briven/briven/blob/master/apps/studio/components/layouts/SQLEditorLayout/SQLEditorNavV2/SearchList.tsx) for ease of finding (rather than keeping the 3 separate sections / having folders)
16
17## Data structure
18
19- SQL Editor is mainly powered by a Valtio store in [`sql-editor-v2.ts`](https://github.com/briven/briven/blob/master/apps/studio/state/sql-editor-v2.ts), in which most of the data is being managed on the client side for optimistic rendering to keep the editor feeling snappy. (unlike other parts of the dashboard where the data is always invalidated whenever a mutation happens).
20
21- The Valtio store here stores snippets across multiple projects as we aren't using a context provider, though this was a legacy decision (refer to [`ProjectContext`](https://github.com/briven/briven/blob/master/apps/studio/components/layouts/ProjectLayout/ProjectContext.tsx) for more context on using providers with stores)
22
23- While [`SQLEditorNav`](https://github.com/briven/briven/blob/master/apps/studio/components/layouts/SQLEditorLayout/SQLEditorNavV2/SQLEditorNav.tsx) renders the folders + snippets directly from the API endpoints via React Query, we still store them in the Valtio store to store some properties used on the client side like `splitSizes` and `projectRef` for snippets, and `status` for folders (although it's possible that we can simplify the Valtio store).
24
25## Data fetching
26
27- The endpoint to fetch snippets and folders are via [`useSQLSnippetFoldersQuery`](https://github.com/briven/briven/blob/master/apps/studio/data/content/sql-folders-query.ts) and [`useSqlSnippetsQuery`](https://github.com/briven/briven/blob/master/apps/studio/data/content/sql-snippets-query.ts), both of which are paginated (limit set at 100)
28 - [`useSQLSnippetFoldersQuery`](https://github.com/briven/briven/blob/master/apps/studio/data/content/sql-folders-query.ts): Specifically for fetching private snippets and folders
29 - [`useSqlSnippetsQuery`](https://github.com/briven/briven/blob/master/apps/studio/data/content/sql-snippets-query.ts): For fetching shared and favorite snippets
30
31- Page fetching is done on demand for the snippets via a "Load more" button due to the complexity of a tree view (we've deliberate avoided an infinite loading UX which we commonly do across other parts of the dashboard)
32
33## Data flow
34
35### Landing on the SQL Editor
36
37- Snippets and folders are all initially loaded via React Query in [`SQLEditorNav`](https://github.com/briven/briven/blob/master/apps/studio/components/layouts/SQLEditorLayout/SQLEditorNavV2/SQLEditorNav.tsx), which are then initialized into the Valtio store via [`snapV2.addSnippet`](https://github.com/briven/briven/blob/master/apps/studio/components/layouts/SQLEditorLayout/SQLEditorNavV2/SQLEditorNav.tsx#L415) calls in the `useEffects`
38
39- On `/editor/sql`
40 - We'll redirect users to the last visited snippet if there's one (`/editor/sql/[id]`), otherwise will redirect to `/editor/sql/new` (within [`[id].tsx`](https://github.com/briven/briven/blob/master/apps/studio/pages/project/%5Bref%5D/sql/%5Bid%5D.tsx) )
41
42- On `/editor/sql/[id]`
43 - We'll load the content of the snippet via `useContentQuery` and update the Valtio store via [`snapV2.setSnippet`](https://github.com/briven/briven/blob/master/apps/studio/pages/project/%5Bref%5D/sql/%5Bid%5D.tsx#L69)
44
45### Writing a snippet
46
47- On `/editor/sql/new`:
48 - The first character input will [update the Valtio store](https://github.com/briven/briven/blob/master/apps/studio/components/interfaces/SQLEditor/MonacoEditor.tsx#L192) with a snippet skeleton via `snapV2.addSnippet` and user will be redirected to `/editor/sql/[id]`, using the `id` from the skeleton
49 - Note that `snapV2.addSnippet` only handles adding snippets to the store and does not queue the snippet for saving
50 - Subsequent character inputs will follow below as per `/editor/sql/[id]`
51
52- On `/editor/sql/[id]`:
53 - [`snapV2.setSql`](https://github.com/briven/briven/blob/master/apps/studio/components/interfaces/SQLEditor/MonacoEditor.tsx#L207) will be called based on the debounced value of the code editor, in which we'll then queue the snippet for [saving](https://github.com/briven/briven/blob/master/apps/studio/state/sql-editor-v2.ts#L477) via `upsertSnippet`.
54 - Note that we do invalidate some React Queries (snippet count, snippets, and folders) after saving via [`upsertSnippet`](https://github.com/briven/briven/blob/master/apps/studio/state/sql-editor-v2.ts#L412), but the invalidation is only [triggered](https://github.com/briven/briven/blob/master/apps/studio/components/interfaces/SQLEditor/MonacoEditor.tsx#L209) if it's a new snippet that's not saved in the DB yet
55
56### Running a snippet
57
58- There's several safeguards in place before we run the query
59 - [Check for destructive operations](https://github.com/briven/briven/blob/master/apps/studio/components/interfaces/SQLEditor/SQLEditor.tsx#L293): Will open a confirmation modal before running the query
60 - [Check for update statements without where clause](https://github.com/briven/briven/blob/master/apps/studio/components/interfaces/SQLEditor/SQLEditor.tsx#L300): Will open a confirmation modal before running the query
61 - [Append a preset limit to the query if it's a select](https://github.com/briven/briven/blob/master/apps/studio/components/interfaces/SQLEditor/SQLEditor.tsx#L333): To prevent accidentally running an expensive query on the database. Users can explicitly opt out of this to set "No limit"
62
63- If the snippet's name is "Untitled query", we'll also trigger a non-blocking request to [rename the snippet via AI](https://github.com/briven/briven/blob/master/apps/studio/components/interfaces/SQLEditor/SQLEditor.tsx#L317). Snippet name will be updated whenever the request completes.
64
65### Renaming, Moving, Deleting, Sharing snippets
66
67- These functionalities all call `upsertContent` via React Query directly without going through the Valtio store
68- We thereafter update the Valtio stores for the SQL Editor and Tabs as required if the upsert is successful
69
70## Possible areas to simplify, refactor, or improve
71
72- `updateSnippet` and `setSql` could be consolidated in `sql-editor-v2.ts`
73
74- Refactor renaming a query to have optimistic rendering for consistency on how we update snippets in the `sql-editor-v2.ts`
75
76- Implement drag and drop functionality for snippets into folders
77
78- `RenameQueryModal` and `MoveQueryModal`, could call `updateSnippet` instead of `removeSnippet` + `addSnippet`?
Preview

SQL Editor Overview

Quick run-through of the different building blocks that make up the SQL Editor, to help navigating the codebase a little easier 🙂🙏

UI structure

  • Folders and snippets (in the product menu) are rendered via SQLEditorMenu and SQLEditorNav, in which the data are all loaded from the API via React Query directly. (Refer to point 3 under "Data Structure" below)

    • SQLEditorMenu: Wraps around SQLEditorNav + renders search input + View running queries button
    • SQLEditorNav: Renders the 3 collapsible snippet sections
  • The Tabs interface is powered by a separate state tabs.ts. (Also used by the Table Editor)

  • Route validation to check for snippet validity + last visited snippet lies in the page level on [id].tsx

  • When searching for snippets, we're deliberately opting to render the results as a flat list in SearchList for ease of finding (rather than keeping the 3 separate sections / having folders)

Data structure

  • SQL Editor is mainly powered by a Valtio store in sql-editor-v2.ts, in which most of the data is being managed on the client side for optimistic rendering to keep the editor feeling snappy. (unlike other parts of the dashboard where the data is always invalidated whenever a mutation happens).

  • The Valtio store here stores snippets across multiple projects as we aren't using a context provider, though this was a legacy decision (refer to ProjectContext for more context on using providers with stores)

  • While SQLEditorNav renders the folders + snippets directly from the API endpoints via React Query, we still store them in the Valtio store to store some properties used on the client side like splitSizes and projectRef for snippets, and status for folders (although it's possible that we can simplify the Valtio store).

Data fetching

  • The endpoint to fetch snippets and folders are via useSQLSnippetFoldersQuery and useSqlSnippetsQuery, both of which are paginated (limit set at 100)

  • Page fetching is done on demand for the snippets via a "Load more" button due to the complexity of a tree view (we've deliberate avoided an infinite loading UX which we commonly do across other parts of the dashboard)

Data flow

Landing on the SQL Editor

  • Snippets and folders are all initially loaded via React Query in SQLEditorNav, which are then initialized into the Valtio store via snapV2.addSnippet calls in the useEffects

  • On /editor/sql

    • We'll redirect users to the last visited snippet if there's one (/editor/sql/[id]), otherwise will redirect to /editor/sql/new (within [id].tsx )
  • On /editor/sql/[id]

    • We'll load the content of the snippet via useContentQuery and update the Valtio store via snapV2.setSnippet

Writing a snippet

  • On /editor/sql/new:

    • The first character input will update the Valtio store with a snippet skeleton via snapV2.addSnippet and user will be redirected to /editor/sql/[id], using the id from the skeleton
    • Note that snapV2.addSnippet only handles adding snippets to the store and does not queue the snippet for saving
    • Subsequent character inputs will follow below as per /editor/sql/[id]
  • On /editor/sql/[id]:

    • snapV2.setSql will be called based on the debounced value of the code editor, in which we'll then queue the snippet for saving via upsertSnippet.
    • Note that we do invalidate some React Queries (snippet count, snippets, and folders) after saving via upsertSnippet, but the invalidation is only triggered if it's a new snippet that's not saved in the DB yet

Running a snippet

Renaming, Moving, Deleting, Sharing snippets

  • These functionalities all call upsertContent via React Query directly without going through the Valtio store
  • We thereafter update the Valtio stores for the SQL Editor and Tabs as required if the upsert is successful

Possible areas to simplify, refactor, or improve

  • updateSnippet and setSql could be consolidated in sql-editor-v2.ts

  • Refactor renaming a query to have optimistic rendering for consistency on how we update snippets in the sql-editor-v2.ts

  • Implement drag and drop functionality for snippets into folders

  • RenameQueryModal and MoveQueryModal, could call updateSnippet instead of removeSnippet + addSnippet?