diff --git a/src/lib/editor/index.ts b/src/lib/editor/index.ts index 69afc6e..c563bf8 100644 --- a/src/lib/editor/index.ts +++ b/src/lib/editor/index.ts @@ -1,2 +1,2 @@ export { ClickHouseDialect } from './SQLDialect'; -export { tablesToSQLNamespace } from './utils'; +export { extendsDialect, tablesToSQLNamespace } from './utils'; diff --git a/src/lib/editor/utils.ts b/src/lib/editor/utils.ts index 3f7bfca..ebc8ac8 100644 --- a/src/lib/editor/utils.ts +++ b/src/lib/editor/utils.ts @@ -1,5 +1,6 @@ import type { ColumnDescriptor, Table } from '$lib/olap-engine'; import type { Completion } from '@codemirror/autocomplete'; +import { SQLDialect } from '@codemirror/lang-sql'; export function tablesToSQLNamespace(tables: Table[]) { return tables.reduce((acc, table) => { @@ -12,3 +13,12 @@ export function tablesToSQLNamespace(tables: Table[]) { function columnDescriptorToCompletion(cd: ColumnDescriptor): Completion { return { label: cd.name, detail: cd.type, type: 'property' }; } + +export function extendsDialect(dialect: SQLDialect, keywords: string[]) { + if (!keywords.length) return dialect; + + return SQLDialect.define({ + ...dialect.spec, + keywords: dialect.spec.keywords + ' ' + keywords.join(' ') + }); +} diff --git a/src/lib/olap-engine/engine-chdb.ts b/src/lib/olap-engine/engine-chdb.ts index 198ee3d..a246cc0 100644 --- a/src/lib/olap-engine/engine-chdb.ts +++ b/src/lib/olap-engine/engine-chdb.ts @@ -1,8 +1,9 @@ import { invoke } from '@tauri-apps/api/core'; import type { OLAPEngine, OLAPResponse, Table } from './index'; - import { Logger } from './Logger'; + import CLICKHOUSE_GET_SCHEMA from './queries/clickhouse_get_schema.sql?raw'; +import CLICKHOUSE_GET_UDFS from './queries/clickhouse_get_udfs.sql?raw'; import CLICKHOUSE_INIT_DB from './queries/clickhouse_init_db.sql?raw'; export class CHDBEngine extends Logger implements OLAPEngine { @@ -28,4 +29,11 @@ export class CHDBEngine extends Logger implements OLAPEngine { if (!response) return []; return response.data as Table[]; } + + async getUDFs() { + const response = await this.exec(CLICKHOUSE_GET_UDFS); + if (!response) return []; + + return response.data.map((row) => row.name as string); + } } diff --git a/src/lib/olap-engine/engine-remote.ts b/src/lib/olap-engine/engine-remote.ts index d70fc48..77b88dd 100644 --- a/src/lib/olap-engine/engine-remote.ts +++ b/src/lib/olap-engine/engine-remote.ts @@ -2,6 +2,7 @@ import type { OLAPEngine, OLAPResponse, Table } from './index'; import { Logger } from './Logger'; import CLICKHOUSE_GET_SCHEMA from './queries/clickhouse_get_schema.sql?raw'; +import CLICKHOUSE_GET_UDFS from './queries/clickhouse_get_udfs.sql?raw'; export class RemoteEngine extends Logger implements OLAPEngine { async init() {} @@ -33,6 +34,13 @@ export class RemoteEngine extends Logger implements OLAPEngine { if (!response) return []; return response.data as Table[]; } + + async getUDFs() { + const response = await this.exec(CLICKHOUSE_GET_UDFS); + if (!response) return []; + + return response.data.map((row) => row.name as string); + } } interface RemoteEngineException { diff --git a/src/lib/olap-engine/index.ts b/src/lib/olap-engine/index.ts index 8540334..fe1f6ac 100644 --- a/src/lib/olap-engine/index.ts +++ b/src/lib/olap-engine/index.ts @@ -28,6 +28,7 @@ export interface OLAPEngine extends ILogger { init(): Promise; exec(query: string): Promise; getSchema(): Promise; + getUDFs(): Promise; } export const engine: OLAPEngine = PLATFORM === 'WEB' ? new RemoteEngine() : new CHDBEngine(); diff --git a/src/lib/olap-engine/queries/clickhouse_get_udfs.sql b/src/lib/olap-engine/queries/clickhouse_get_udfs.sql new file mode 100644 index 0000000..6641376 --- /dev/null +++ b/src/lib/olap-engine/queries/clickhouse_get_udfs.sql @@ -0,0 +1,6 @@ +select + name +from + system.functions +where + origin != 'System' diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index f635548..82a618d 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -9,7 +9,7 @@ import TabComponent from '$lib/components/Tab.svelte'; import TimeCounter from '$lib/components/TimeCounter.svelte'; import { setAppContext } from '$lib/context'; - import { ClickHouseDialect, tablesToSQLNamespace } from '$lib/editor'; + import { ClickHouseDialect, extendsDialect, tablesToSQLNamespace } from '$lib/editor'; import Bars3 from '$lib/icons/Bars3.svelte'; import PanelBottom from '$lib/icons/PanelBottom.svelte'; import PanelLeft from '$lib/icons/PanelLeft.svelte'; @@ -26,11 +26,14 @@ import { SplitPane } from '@rich_harris/svelte-split-pane'; import debounce from 'p-debounce'; import { tick, type ComponentProps } from 'svelte'; + import type { PageData } from './$types'; let response = $state.raw(); let loading = $state(false); let counter = $state>(); + let { data }: { data: PageData } = $props(); + async function handleExec() { const query = currentTab.contents; if (loading || !query) { @@ -311,7 +314,7 @@ diff --git a/src/routes/+page.ts b/src/routes/+page.ts index cdaa54a..d6e52ce 100644 --- a/src/routes/+page.ts +++ b/src/routes/+page.ts @@ -3,6 +3,7 @@ import type { PageLoad } from './$types'; export const load = (async () => { await engine.init(); + const udfs = await engine.getUDFs(); - return {}; + return { udfs }; }) satisfies PageLoad;