diff --git a/src-tauri/src/commands/mod.rs b/src-tauri/src/commands/mod.rs index eaf8423..c9c59d2 100644 --- a/src-tauri/src/commands/mod.rs +++ b/src-tauri/src/commands/mod.rs @@ -7,7 +7,7 @@ use crate::AppState; use String; #[tauri::command] -pub async fn query(query: String, state: State<'_, Mutex>) -> Result { +pub async fn query(query: String, state: State<'_, Mutex>) -> Result { let state = state.lock().unwrap(); let args = vec![ @@ -21,9 +21,9 @@ pub async fn query(query: String, state: State<'_, Mutex>) -> Result query_result .data_utf8() - .map_err(|_| ()) + .map_err(|_| "Bad encoding".to_string()) .map(|data| data.to_string()), Ok(None) => Ok(String::from("No result")), - Err(_e) => Err(()), + Err(_e) => Err(_e.to_string()), }; } diff --git a/src/lib/components/Datasets/Datasets.svelte b/src/lib/components/Datasets/Datasets.svelte new file mode 100644 index 0000000..8a46c46 --- /dev/null +++ b/src/lib/components/Datasets/Datasets.svelte @@ -0,0 +1,156 @@ + + + +
+ {#each filtered as source, i (source.slug)} +
+ + {#if source.type === 'MergeTree'} + + {:else} + + {/if} +

{source.name}

+ + {DATASOURCE_TYPE_SHORT_NAME_MAP[source.type]} + + +
    + {#each source.columns ?? [] as column} +
  • + {column.name} + {remove_nullable(column.type)} +
  • + {/each} +
+ + {/each} +
+ +
+ + + diff --git a/src/lib/components/Datasets/utils.ts b/src/lib/components/Datasets/utils.ts new file mode 100644 index 0000000..01bef0e --- /dev/null +++ b/src/lib/components/Datasets/utils.ts @@ -0,0 +1,58 @@ +import { exec, type CHResponse } from '$lib/query'; +import type { ColumnDescriptor, Dataset } from '$lib/types'; + +export function filter(sources: Dataset[], search: string) { + if (!search) return sources; + const search_ = search.toLowerCase(); + + return sources.filter( + (s) => + s.name.toLowerCase().includes(search_) || + s.slug.includes(search_) || + s.columns?.some((c) => c.name.toLowerCase().includes(search_)) + ); +} + +export const DATASOURCE_TYPE_COLOR_MAP: Record = { + CSV: 'hsl(58deg 37% 28%)', + Parquet: 'hsl(20deg 37% 28%)', + MergeTree: 'hsl(199deg 37% 28%)' +}; + +export const DATASOURCE_TYPE_SHORT_NAME_MAP: Record = { + CSV: 'CSV', + Parquet: 'PQT', + MergeTree: 'MT' +}; + +export function remove_nullable(type: string) { + return type.replace(/Nullable\((.*)\)/, '$1'); +} + +export function describe_to_column_descriptors( + response: NonNullable +): ColumnDescriptor[] { + return response.data.map((d) => { + return { + name: d.name as string, + type: d.type as string + }; + }); +} + +export async function getDefaultSource() { + const defaults: Dataset = { + name: 'Agnostic Logs', + slug: 'agnostic_logs', + path: "s3('https://data.agnostic.dev/ethereum-mainnet-pq/logs/*.parquet', 'Parquet')", + type: 'Parquet', + last_refresh: Date.now() + }; + + const response = await exec(`DESCRIBE TABLE ${defaults.path}`); + if (!response) return; + + defaults.columns = describe_to_column_descriptors(response); + + return defaults; +} diff --git a/src/lib/components/SearchBar.svelte b/src/lib/components/SearchBar.svelte new file mode 100644 index 0000000..fba6376 --- /dev/null +++ b/src/lib/components/SearchBar.svelte @@ -0,0 +1,53 @@ + + + + + diff --git a/src/lib/components/SideBar.svelte b/src/lib/components/SideBar.svelte new file mode 100644 index 0000000..f0570ab --- /dev/null +++ b/src/lib/components/SideBar.svelte @@ -0,0 +1,66 @@ + + +
+ + {#if tab === 'sources'} + + {/if} +
+ + diff --git a/src/lib/icons/Database.svelte b/src/lib/icons/Database.svelte new file mode 100644 index 0000000..2ec9b79 --- /dev/null +++ b/src/lib/icons/Database.svelte @@ -0,0 +1,16 @@ + + + + + diff --git a/src/lib/icons/Plus.svelte b/src/lib/icons/Plus.svelte new file mode 100644 index 0000000..d012955 --- /dev/null +++ b/src/lib/icons/Plus.svelte @@ -0,0 +1,16 @@ + + + + + diff --git a/src/lib/icons/Search.svelte b/src/lib/icons/Search.svelte new file mode 100644 index 0000000..b696d85 --- /dev/null +++ b/src/lib/icons/Search.svelte @@ -0,0 +1,20 @@ + + + diff --git a/src/lib/icons/Table.svelte b/src/lib/icons/Table.svelte new file mode 100644 index 0000000..04235a8 --- /dev/null +++ b/src/lib/icons/Table.svelte @@ -0,0 +1,16 @@ + + + + + diff --git a/src/lib/query.ts b/src/lib/query.ts index 6120b0a..1149723 100644 --- a/src/lib/query.ts +++ b/src/lib/query.ts @@ -5,10 +5,9 @@ export async function exec(query: string) { const r: string = await invoke('query', { query }); - return JSON.parse(r); + return JSON.parse(r) as CHResponse; } catch (e) { console.error(e); - return {}; } } diff --git a/src/lib/schema.svelte b/src/lib/schema.svelte deleted file mode 100644 index a406ca3..0000000 --- a/src/lib/schema.svelte +++ /dev/null @@ -1,58 +0,0 @@ - - -
- {#if schema} - {#each schema.data as column} -
- {column.name} - {column.type} -
- {/each} - {/if} -
- - diff --git a/src/lib/types.d.ts b/src/lib/types.d.ts new file mode 100644 index 0000000..a5b19ff --- /dev/null +++ b/src/lib/types.d.ts @@ -0,0 +1,16 @@ +export interface ColumnDescriptor { + name: string; + type: string; +} + +export interface Dataset { + name: string; + /** Must be unique */ + slug: string; + path: string; + type: 'CSV' | 'Parquet' | 'MergeTree'; + /** Describe result */ + columns?: ColumnDescriptor[]; + /** Timestamp */ + last_refresh: number; +} diff --git a/src/lib/utils.ts b/src/lib/utils.ts index 98f5b70..876d0b0 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -14,15 +14,15 @@ export function getTextWidth(text: string) { } export function getRelativeParent(node: E) { - let parent = node.parentElement + let parent = node.parentElement; - while (parent && getComputedStyle(parent).position !== 'relative') { - parent = parent.parentElement - } + while (parent && getComputedStyle(parent).position !== 'relative') { + parent = parent.parentElement; + } - return parent + return parent; } export function clamp(value: number, min: number, max: number) { - return Math.min(max, Math.max(value, min)) + return Math.min(max, Math.max(value, min)); } diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index d4eae5d..d30690d 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -3,8 +3,10 @@ import WindowTitleBar from '$lib/components/WindowTitleBar.svelte'; import { Editor } from '$lib/components/Editor'; import { exec, type CHResponse } from '$lib/query'; - import Schema from '$lib/schema.svelte'; + import SideBar from '$lib/components/SideBar.svelte'; import Result from '$lib/components/Result.svelte'; + import type { Dataset } from '$lib/types'; + import { getDefaultSource } from '$lib/components/Datasets/utils'; let response: CHResponse = $state.raw(undefined); @@ -16,6 +18,15 @@ loading = true; response = await exec(query).finally(() => (loading = false)); } + + let sources = $state([]); + $effect.pre(() => { + if (!sources.length) { + getDefaultSource().then((source) => { + if (source) sources.push(source); + }); + } + }); @@ -27,7 +38,7 @@
{#snippet a()} - + {/snippet} {#snippet b()}