@eclipse-lyra/extension-duckdb 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/api.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ export { duckdbService, DuckDBService, DuckDBDatabase, type DuckDBQueryResult, } from './duckdb-service';
2
+ export { duckdbExtensionManagerService, DUCKDB_AVAILABLE_EXTENSIONS } from './duckdb-extension-manager';
3
+ //# sourceMappingURL=api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,aAAa,EACb,cAAc,EACd,KAAK,iBAAiB,GACvB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,6BAA6B,EAAE,2BAA2B,EAAE,MAAM,4BAA4B,CAAC"}
package/dist/api.js ADDED
@@ -0,0 +1,9 @@
1
+ import { D, a, b, d, c } from "./duckdb-extension-manager-BlVBXxTt.js";
2
+ export {
3
+ D as DUCKDB_AVAILABLE_EXTENSIONS,
4
+ a as DuckDBDatabase,
5
+ b as DuckDBService,
6
+ d as duckdbExtensionManagerService,
7
+ c as duckdbService
8
+ };
9
+ //# sourceMappingURL=api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.js","sources":[],"sourcesContent":[],"names":[],"mappings":";"}
@@ -0,0 +1,47 @@
1
+ import { LyraPart, EditorInput, EditorContentProvider } from '@eclipse-lyra/core';
2
+ export declare class LyraDuckDBEditor extends LyraPart implements EditorContentProvider {
3
+ input?: EditorInput;
4
+ readOnly: boolean;
5
+ private initialContent;
6
+ private initialUri;
7
+ private resultTabs;
8
+ private activeResultId;
9
+ private running;
10
+ private availableDatabases;
11
+ private selectedDbName;
12
+ private widgetRef;
13
+ private tabGroupRef;
14
+ private tabIdCounter;
15
+ private db;
16
+ protected doInitUI(): Promise<void>;
17
+ private refreshDatabaseList;
18
+ private _onContentChange;
19
+ save(): void;
20
+ protected doClose(): void;
21
+ getLanguage(): string | null;
22
+ isLanguage(lang: string): boolean;
23
+ getContent(): string | null;
24
+ getSelection(): string | null;
25
+ getSnippet(lines?: number): {
26
+ snippet: string;
27
+ cursorLine: number;
28
+ } | null;
29
+ getFilePath(): string | null;
30
+ private runQuery;
31
+ private clearRunningState;
32
+ private closeTab;
33
+ private renderResultPanel;
34
+ private onDatabaseChange;
35
+ private addNewDatabase;
36
+ private deleteSelectedDatabase;
37
+ protected renderToolbar(): import('lit-html').TemplateResult<1>;
38
+ protected updated(changedProperties: Map<string, unknown>): void;
39
+ render(): import('lit-html').TemplateResult<1>;
40
+ static styles: import('lit').CSSResult;
41
+ }
42
+ declare global {
43
+ interface HTMLElementTagNameMap {
44
+ "lyra-duckdb-editor": LyraDuckDBEditor;
45
+ }
46
+ }
47
+ //# sourceMappingURL=duckdb-editor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"duckdb-editor.d.ts","sourceRoot":"","sources":["../src/duckdb-editor.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAI9C,OAAO,EAAE,WAAW,EAAE,qBAAqB,EAAwE,MAAM,oBAAoB,CAAC;AAoB9I,qBACa,gBAAiB,SAAQ,QAAS,YAAW,qBAAqB;IAEtE,KAAK,CAAC,EAAE,WAAW,CAAC;IAGpB,QAAQ,UAAS;IAGxB,OAAO,CAAC,cAAc,CAAiC;IAGvD,OAAO,CAAC,UAAU,CAAiC;IAGnD,OAAO,CAAC,UAAU,CAAmB;IAGrC,OAAO,CAAC,cAAc,CAAuB;IAG7C,OAAO,CAAC,OAAO,CAAS;IAGxB,OAAO,CAAC,kBAAkB,CAAgB;IAG1C,OAAO,CAAC,cAAc,CAAuB;IAE7C,OAAO,CAAC,SAAS,CAAiC;IAClD,OAAO,CAAC,WAAW,CAAiD;IACpE,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,EAAE,CAA+B;cAEzB,QAAQ;YAYV,mBAAmB;IAUjC,OAAO,CAAC,gBAAgB,CAEtB;IAEF,IAAI,IAAI,IAAI;IAMZ,SAAS,CAAC,OAAO;IAQV,WAAW,IAAI,MAAM,GAAG,IAAI;IAI5B,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAIjC,UAAU,IAAI,MAAM,GAAG,IAAI;IAI3B,YAAY,IAAI,MAAM,GAAG,IAAI;IAI7B,UAAU,CAAC,KAAK,GAAE,MAAU,GAAG;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IAI7E,WAAW,IAAI,MAAM,GAAG,IAAI;YAIrB,QAAQ;IAgDtB,OAAO,CAAC,iBAAiB;IAQzB,OAAO,CAAC,QAAQ;IAahB,OAAO,CAAC,iBAAiB;IAkCzB,OAAO,CAAC,gBAAgB;YAaV,cAAc;YA+Bd,sBAAsB;IAyBpC,SAAS,CAAC,aAAa;IAmEvB,SAAS,CAAC,OAAO,CAAC,iBAAiB,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC;IAWzD,MAAM;IA8DN,MAAM,CAAC,MAAM,0BA4FX;CACH;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,oBAAoB,EAAE,gBAAgB,CAAC;KACxC;CACF"}
@@ -0,0 +1,534 @@
1
+ import { LyraPart, activePartSignal, toastError, promptDialog, toastInfo, confirmDialog, rootContext, editorRegistry, File } from "@eclipse-lyra/core";
2
+ import { css, html } from "lit";
3
+ import { c as duckdbService, d as duckdbExtensionManagerService } from "./duckdb-extension-manager-BlVBXxTt.js";
4
+ import { property, state, customElement } from "lit/decorators.js";
5
+ import { createRef, ref } from "lit/directives/ref.js";
6
+ var __defProp = Object.defineProperty;
7
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
8
+ var __decorateClass = (decorators, target, key, kind) => {
9
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
10
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
11
+ if (decorator = decorators[i])
12
+ result = (kind ? decorator(target, key, result) : decorator(result)) || result;
13
+ if (kind && result) __defProp(target, key, result);
14
+ return result;
15
+ };
16
+ const MAX_TAB_LABEL = 28;
17
+ const DB_NAME_REGEX = /^[a-zA-Z0-9_.-]+$/;
18
+ function truncateLabel(sql) {
19
+ const oneLine = sql.replace(/\s+/g, " ").trim();
20
+ if (oneLine.length <= MAX_TAB_LABEL) return oneLine;
21
+ return oneLine.slice(0, MAX_TAB_LABEL) + "…";
22
+ }
23
+ let LyraDuckDBEditor = class extends LyraPart {
24
+ constructor() {
25
+ super(...arguments);
26
+ this.readOnly = false;
27
+ this.initialContent = void 0;
28
+ this.initialUri = void 0;
29
+ this.resultTabs = [];
30
+ this.activeResultId = null;
31
+ this.running = false;
32
+ this.availableDatabases = [];
33
+ this.selectedDbName = null;
34
+ this.widgetRef = createRef();
35
+ this.tabGroupRef = createRef();
36
+ this.tabIdCounter = 0;
37
+ this.db = null;
38
+ this._onContentChange = () => {
39
+ this.markDirty(true);
40
+ };
41
+ }
42
+ async doInitUI() {
43
+ const file = this.input.data;
44
+ const textContents = await file.getContents();
45
+ this.initialContent = textContents;
46
+ this.initialUri = file.getName();
47
+ this.watch(activePartSignal, () => {
48
+ if (activePartSignal.get() === this) this.refreshDatabaseList();
49
+ });
50
+ await this.refreshDatabaseList();
51
+ this.requestUpdate();
52
+ }
53
+ async refreshDatabaseList() {
54
+ try {
55
+ this.availableDatabases = await duckdbService.listDatabases();
56
+ } catch {
57
+ this.availableDatabases = [];
58
+ }
59
+ this.requestUpdate();
60
+ this.updateToolbar();
61
+ }
62
+ save() {
63
+ const value = this.widgetRef.value?.getContent() ?? "";
64
+ this.input?.data.saveContents(value);
65
+ this.markDirty(false);
66
+ }
67
+ doClose() {
68
+ this.widgetRef.value?.dispose();
69
+ if (this.db) {
70
+ void this.db.close();
71
+ this.db = null;
72
+ }
73
+ }
74
+ getLanguage() {
75
+ return "sql";
76
+ }
77
+ isLanguage(lang) {
78
+ return lang.toLowerCase() === "sql";
79
+ }
80
+ getContent() {
81
+ return this.widgetRef.value?.getContent() ?? null;
82
+ }
83
+ getSelection() {
84
+ return this.widgetRef.value?.getSelection() ?? null;
85
+ }
86
+ getSnippet(lines = 5) {
87
+ return this.widgetRef.value?.getSnippet(lines) ?? null;
88
+ }
89
+ getFilePath() {
90
+ return this.input?.data?.getWorkspacePath() ?? null;
91
+ }
92
+ async runQuery(useSelectionOnly = false) {
93
+ const sql = useSelectionOnly ? this.getSelection()?.trim() : this.getSelection()?.trim() || this.getContent()?.trim();
94
+ if (!sql) {
95
+ toastError(useSelectionOnly ? "No selection to run" : "No SQL to run");
96
+ return;
97
+ }
98
+ if (this.running) return;
99
+ this.running = true;
100
+ const id = `result-${++this.tabIdCounter}`;
101
+ const label = truncateLabel(sql);
102
+ this.resultTabs = [...this.resultTabs, { id, label, sql, result: { columns: [], rows: [] } }];
103
+ this.activeResultId = id;
104
+ this.requestUpdate();
105
+ this.updateToolbar();
106
+ const timeoutMs = 6e4;
107
+ const timeoutId = window.setTimeout(() => this.clearRunningState(), timeoutMs);
108
+ try {
109
+ const dbName = this.selectedDbName ?? void 0;
110
+ if (!this.db || this.db.name !== (dbName ?? null)) {
111
+ if (this.db) {
112
+ void this.db.close();
113
+ this.db = null;
114
+ }
115
+ this.db = await duckdbService.open(dbName);
116
+ }
117
+ const result = await this.db.runQuery(sql);
118
+ this.resultTabs = this.resultTabs.map(
119
+ (t) => t.id === id ? { ...t, result } : t
120
+ );
121
+ } catch (err) {
122
+ const error = err instanceof Error ? err.message : String(err);
123
+ this.resultTabs = this.resultTabs.map(
124
+ (t) => t.id === id ? { ...t, result: { error } } : t
125
+ );
126
+ } finally {
127
+ window.clearTimeout(timeoutId);
128
+ this.running = false;
129
+ this.activeResultId = id;
130
+ this.requestUpdate();
131
+ this.updateToolbar();
132
+ }
133
+ }
134
+ clearRunningState() {
135
+ if (this.running) {
136
+ this.running = false;
137
+ this.requestUpdate();
138
+ this.updateToolbar();
139
+ }
140
+ }
141
+ closeTab(id) {
142
+ const idx = this.resultTabs.findIndex((t) => t.id === id);
143
+ if (idx < 0) return;
144
+ const next = this.resultTabs.filter((t) => t.id !== id);
145
+ this.resultTabs = next;
146
+ if (this.activeResultId === id) {
147
+ const prevIdx = Math.min(idx, next.length - 1);
148
+ this.activeResultId = next[prevIdx]?.id ?? null;
149
+ }
150
+ this.requestUpdate();
151
+ this.updateToolbar();
152
+ }
153
+ renderResultPanel(tab) {
154
+ if ("error" in tab.result) {
155
+ return html`
156
+ <div class="result-error">
157
+ <pre>${tab.result.error}</pre>
158
+ </div>
159
+ `;
160
+ }
161
+ const { columns, rows } = tab.result;
162
+ if (columns.length === 0 && rows.length === 0) {
163
+ return html`<div class="result-empty">Query returned no rows.</div>`;
164
+ }
165
+ return html`
166
+ <div class="result-table-wrap">
167
+ <table class="result-table">
168
+ <thead>
169
+ <tr>
170
+ ${columns.map((col) => html`<th>${col}</th>`)}
171
+ </tr>
172
+ </thead>
173
+ <tbody>
174
+ ${rows.map(
175
+ (row) => html`
176
+ <tr>
177
+ ${row.map((cell) => html`<td>${String(cell ?? "")}</td>`)}
178
+ </tr>
179
+ `
180
+ )}
181
+ </tbody>
182
+ </table>
183
+ </div>
184
+ `;
185
+ }
186
+ onDatabaseChange(e) {
187
+ const select = e.target;
188
+ const value = select?.value ?? "";
189
+ const next = value === "" ? null : value;
190
+ if (this.selectedDbName === next) return;
191
+ this.selectedDbName = next;
192
+ if (this.db) {
193
+ void this.db.close();
194
+ this.db = null;
195
+ }
196
+ this.requestUpdate();
197
+ }
198
+ async addNewDatabase() {
199
+ const raw = await promptDialog("New database name", "");
200
+ if (raw == null) return;
201
+ const name = raw.trim();
202
+ if (!name) {
203
+ toastError("Name cannot be empty");
204
+ return;
205
+ }
206
+ if (!DB_NAME_REGEX.test(name)) {
207
+ toastError("Name may only contain letters, numbers, and . _ -");
208
+ return;
209
+ }
210
+ if (this.availableDatabases.includes(name)) {
211
+ toastError(`Database "${name}" already exists`);
212
+ return;
213
+ }
214
+ try {
215
+ const newDb = await duckdbService.open(name);
216
+ await newDb.close();
217
+ this.selectedDbName = name;
218
+ if (this.db) {
219
+ void this.db.close();
220
+ this.db = null;
221
+ }
222
+ await this.refreshDatabaseList();
223
+ toastInfo(`Database "${name}" created`);
224
+ } catch (err) {
225
+ toastError(err instanceof Error ? err.message : String(err));
226
+ }
227
+ }
228
+ async deleteSelectedDatabase() {
229
+ const name = this.selectedDbName;
230
+ const label = name === null ? "In-memory" : name;
231
+ const ok = await confirmDialog(`Delete database "${label}"?`);
232
+ if (!ok) return;
233
+ if (name === null) {
234
+ if (this.db) {
235
+ void this.db.close();
236
+ this.db = null;
237
+ }
238
+ } else {
239
+ try {
240
+ await duckdbService.delete(name);
241
+ if (this.db?.name === name) this.db = null;
242
+ this.selectedDbName = null;
243
+ await this.refreshDatabaseList();
244
+ } catch (err) {
245
+ toastError(err instanceof Error ? err.message : String(err));
246
+ return;
247
+ }
248
+ }
249
+ this.requestUpdate();
250
+ this.updateToolbar();
251
+ }
252
+ renderToolbar() {
253
+ const dbValue = this.selectedDbName ?? "";
254
+ return html`
255
+ <wa-select
256
+ class="db-select"
257
+ size="small"
258
+ value=${dbValue}
259
+ title="Database (OPFS)"
260
+ @change=${(e) => this.onDatabaseChange(e)}
261
+ >
262
+ <wa-option value="">In-memory</wa-option>
263
+ ${this.availableDatabases.map(
264
+ (name) => html`<wa-option value=${name}>${name}</wa-option>`
265
+ )}
266
+ </wa-select>
267
+ <wa-button
268
+ size="small"
269
+ appearance="plain"
270
+ title="New database"
271
+ @click=${() => this.addNewDatabase()}
272
+ >
273
+ <wa-icon name="plus" label="New"></wa-icon>
274
+ </wa-button>
275
+ <wa-button
276
+ size="small"
277
+ appearance="plain"
278
+ title=${this.selectedDbName === null ? "Clear in-memory database" : `Delete database "${this.selectedDbName}"`}
279
+ @click=${() => this.deleteSelectedDatabase()}
280
+ >
281
+ <wa-icon name="trash" label="Delete"></wa-icon>
282
+ </wa-button>
283
+ <wa-button
284
+ size="small"
285
+ appearance="plain"
286
+ title="Manage DuckDB extensions"
287
+ @click=${() => duckdbExtensionManagerService.showExtensionManager({
288
+ db: this.db,
289
+ databaseLabel: this.selectedDbName === null ? "In-memory" : this.selectedDbName
290
+ })}
291
+ >
292
+ <wa-icon name="puzzle-piece" label="Extensions"></wa-icon>
293
+ Extensions
294
+ </wa-button>
295
+ <wa-button
296
+ size="small"
297
+ appearance="plain"
298
+ ?disabled=${this.running}
299
+ @click=${() => this.runQuery(true)}
300
+ title="Run selection only"
301
+ >
302
+ <wa-icon name="i-cursor" label="Run selection"></wa-icon>
303
+ ${this.running ? "Running…" : "Run selection"}
304
+ </wa-button>
305
+ <wa-button
306
+ size="small"
307
+ appearance="plain"
308
+ ?disabled=${this.running}
309
+ @click=${() => this.runQuery(false)}
310
+ title="Run all SQL"
311
+ >
312
+ <wa-icon name="play" label="Run"></wa-icon>
313
+ ${this.running ? "Running…" : "Run all"}
314
+ </wa-button>
315
+ `;
316
+ }
317
+ updated(changedProperties) {
318
+ super.updated(changedProperties);
319
+ if (changedProperties.has("resultTabs") || changedProperties.has("running")) {
320
+ this.updateToolbar();
321
+ }
322
+ const activeId = this.activeResultId ?? this.resultTabs[0]?.id ?? "";
323
+ if (activeId && this.tabGroupRef.value && this.tabGroupRef.value.active !== activeId) {
324
+ this.tabGroupRef.value.active = activeId;
325
+ }
326
+ }
327
+ render() {
328
+ if (this.initialContent === void 0) {
329
+ return html`<div class="editor-placeholder"></div>`;
330
+ }
331
+ const hasResults = this.resultTabs.length > 0;
332
+ const activeId = this.activeResultId ?? this.resultTabs[0]?.id ?? "";
333
+ return html`
334
+ <wa-split-panel
335
+ class="editor-split"
336
+ orientation="vertical"
337
+ position="60"
338
+ >
339
+ <div slot="start" class="editor-area">
340
+ <lyra-monaco-widget
341
+ .value=${this.initialContent}
342
+ .uri=${this.initialUri}
343
+ .language=${"sql"}
344
+ .readOnly=${this.readOnly}
345
+ @content-change=${this._onContentChange}
346
+ ${ref(this.widgetRef)}
347
+ ></lyra-monaco-widget>
348
+ </div>
349
+ <div slot="end" class="results-area">
350
+ ${hasResults ? html`
351
+ <wa-tab-group
352
+ class="result-tabs"
353
+ .active=${activeId}
354
+ ${ref(this.tabGroupRef)}
355
+ @wa-tab-show=${(e) => {
356
+ this.activeResultId = e.detail?.name ?? null;
357
+ }}
358
+ >
359
+ ${this.resultTabs.flatMap((tab) => [
360
+ html`<wa-tab panel="${tab.id}">${tab.label}</wa-tab>`,
361
+ html`<wa-button
362
+ slot="nav"
363
+ tabindex="-1"
364
+ appearance="plain"
365
+ size="small"
366
+ class="tab-close"
367
+ title="Close tab"
368
+ @click=${() => this.closeTab(tab.id)}
369
+ >
370
+ <wa-icon name="xmark" label="Close"></wa-icon>
371
+ </wa-button>`,
372
+ html`<wa-tab-panel name="${tab.id}">${this.renderResultPanel(tab)}</wa-tab-panel>`
373
+ ])}
374
+ </wa-tab-group>
375
+ ` : html`
376
+ <div class="results-empty">
377
+ Run a query to see results in a new tab.
378
+ </div>
379
+ `}
380
+ </div>
381
+ </wa-split-panel>
382
+ `;
383
+ }
384
+ };
385
+ LyraDuckDBEditor.styles = css`
386
+ :host {
387
+ display: flex;
388
+ flex-direction: column;
389
+ position: relative;
390
+ width: 100%;
391
+ height: 100%;
392
+ }
393
+ .db-select {
394
+ max-width: 10rem;
395
+ }
396
+ .editor-split {
397
+ flex: 1;
398
+ min-height: 0;
399
+ height: 100%;
400
+ }
401
+ .editor-area,
402
+ .results-area {
403
+ height: 100%;
404
+ min-height: 0;
405
+ display: flex;
406
+ flex-direction: column;
407
+ overflow: hidden;
408
+ }
409
+ .editor-area monaco-widget {
410
+ flex: 1;
411
+ min-height: 0;
412
+ }
413
+ .editor-placeholder {
414
+ flex: 1;
415
+ min-height: 0;
416
+ }
417
+ .result-tabs {
418
+ flex: 1;
419
+ min-height: 0;
420
+ display: flex;
421
+ flex-direction: column;
422
+ }
423
+ .result-tabs::part(body) {
424
+ flex: 1;
425
+ min-height: 0;
426
+ overflow: auto;
427
+ }
428
+ .result-tabs .tab-close {
429
+ margin-left: -0.25rem;
430
+ padding: 0.2rem;
431
+ }
432
+ .results-empty {
433
+ flex: 1;
434
+ display: flex;
435
+ align-items: center;
436
+ justify-content: center;
437
+ color: var(--wa-color-neutral-500, #6b7280);
438
+ font-size: 0.875rem;
439
+ }
440
+ .result-table-wrap {
441
+ overflow: auto;
442
+ padding: 0.75rem;
443
+ }
444
+ .result-table {
445
+ width: 100%;
446
+ border-collapse: collapse;
447
+ font-size: 0.8125rem;
448
+ }
449
+ .result-table th,
450
+ .result-table td {
451
+ padding: 0.35rem 0.75rem;
452
+ text-align: left;
453
+ border-bottom: 1px solid var(--wa-color-neutral-200, #e5e7eb);
454
+ }
455
+ .result-table th {
456
+ font-weight: 600;
457
+ background: var(--wa-color-neutral-100, #f3f4f6);
458
+ }
459
+ .result-table tbody tr:hover {
460
+ background: var(--wa-color-neutral-50, #f9fafb);
461
+ }
462
+ .result-error {
463
+ padding: 0.75rem;
464
+ color: var(--wa-color-red-60, #dc2626);
465
+ font-family: ui-monospace, monospace;
466
+ font-size: 0.8125rem;
467
+ }
468
+ .result-error pre {
469
+ margin: 0;
470
+ white-space: pre-wrap;
471
+ }
472
+ .result-empty {
473
+ padding: 0.75rem;
474
+ color: var(--wa-color-neutral-500, #6b7280);
475
+ font-size: 0.875rem;
476
+ }
477
+ `;
478
+ __decorateClass([
479
+ property({ attribute: false })
480
+ ], LyraDuckDBEditor.prototype, "input", 2);
481
+ __decorateClass([
482
+ property({ type: Boolean })
483
+ ], LyraDuckDBEditor.prototype, "readOnly", 2);
484
+ __decorateClass([
485
+ state()
486
+ ], LyraDuckDBEditor.prototype, "initialContent", 2);
487
+ __decorateClass([
488
+ state()
489
+ ], LyraDuckDBEditor.prototype, "initialUri", 2);
490
+ __decorateClass([
491
+ state()
492
+ ], LyraDuckDBEditor.prototype, "resultTabs", 2);
493
+ __decorateClass([
494
+ state()
495
+ ], LyraDuckDBEditor.prototype, "activeResultId", 2);
496
+ __decorateClass([
497
+ state()
498
+ ], LyraDuckDBEditor.prototype, "running", 2);
499
+ __decorateClass([
500
+ state()
501
+ ], LyraDuckDBEditor.prototype, "availableDatabases", 2);
502
+ __decorateClass([
503
+ state()
504
+ ], LyraDuckDBEditor.prototype, "selectedDbName", 2);
505
+ LyraDuckDBEditor = __decorateClass([
506
+ customElement("lyra-duckdb-editor")
507
+ ], LyraDuckDBEditor);
508
+ function duckdbExtension() {
509
+ rootContext.put("duckdbService", duckdbService);
510
+ editorRegistry.registerEditorInputHandler({
511
+ editorId: "system.duckdb-editor",
512
+ label: "DuckDB",
513
+ icon: "database",
514
+ canHandle: (input) => input instanceof File && input.getName().toLowerCase().endsWith(".sql"),
515
+ ranking: 1e3,
516
+ handle: async (input) => {
517
+ const editorInput = {
518
+ title: input.getName(),
519
+ data: input,
520
+ key: input.getName(),
521
+ icon: "database",
522
+ noOverflow: false,
523
+ state: {},
524
+ widgetFactory: () => null
525
+ };
526
+ editorInput.widgetFactory = () => html`<lyra-duckdb-editor .input=${editorInput}></lyra-duckdb-editor>`;
527
+ return editorInput;
528
+ }
529
+ });
530
+ }
531
+ export {
532
+ duckdbExtension as default
533
+ };
534
+ //# sourceMappingURL=duckdb-extension-D0_ZZcoC.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"duckdb-extension-D0_ZZcoC.js","sources":["../src/duckdb-editor.ts","../src/duckdb-extension.ts"],"sourcesContent":["import { customElement, property, state } from \"lit/decorators.js\";\nimport { LyraPart } from \"@eclipse-lyra/core\";\nimport { css, html } from \"lit\";\nimport { createRef, ref } from \"lit/directives/ref.js\";\nimport { styleMap } from \"lit/directives/style-map.js\";\nimport { EditorInput, EditorContentProvider, toastError, toastInfo, promptDialog, confirmDialog, activePartSignal } from \"@eclipse-lyra/core\";\nimport { LyraMonacoWidget } from \"@eclipse-lyra/extension-monaco-editor\";\nimport { duckdbService, duckdbExtensionManagerService, type DuckDBDatabase, type DuckDBQueryResult } from \"./api\";\n\nconst MAX_TAB_LABEL = 28;\nconst DB_NAME_REGEX = /^[a-zA-Z0-9_.-]+$/;\n\ninterface ResultTab {\n id: string;\n label: string;\n sql: string;\n result: DuckDBQueryResult | { error: string };\n}\n\nfunction truncateLabel(sql: string): string {\n const oneLine = sql.replace(/\\s+/g, \" \").trim();\n if (oneLine.length <= MAX_TAB_LABEL) return oneLine;\n return oneLine.slice(0, MAX_TAB_LABEL) + \"…\";\n}\n\n@customElement(\"lyra-duckdb-editor\")\nexport class LyraDuckDBEditor extends LyraPart implements EditorContentProvider {\n @property({ attribute: false })\n public input?: EditorInput;\n\n @property({ type: Boolean })\n public readOnly = false;\n\n @state()\n private initialContent: string | undefined = undefined;\n\n @state()\n private initialUri: string | undefined = undefined;\n\n @state()\n private resultTabs: ResultTab[] = [];\n\n @state()\n private activeResultId: string | null = null;\n\n @state()\n private running = false;\n\n @state()\n private availableDatabases: string[] = [];\n\n @state()\n private selectedDbName: string | null = null;\n\n private widgetRef = createRef<LyraMonacoWidget>();\n private tabGroupRef = createRef<HTMLElement & { active: string }>();\n private tabIdCounter = 0;\n private db: DuckDBDatabase | null = null;\n\n protected async doInitUI() {\n const file = this.input!.data;\n const textContents = await file.getContents();\n this.initialContent = textContents;\n this.initialUri = file.getName();\n this.watch(activePartSignal, () => {\n if (activePartSignal.get() === this) this.refreshDatabaseList();\n });\n await this.refreshDatabaseList();\n this.requestUpdate();\n }\n\n private async refreshDatabaseList(): Promise<void> {\n try {\n this.availableDatabases = await duckdbService.listDatabases();\n } catch {\n this.availableDatabases = [];\n }\n this.requestUpdate();\n this.updateToolbar();\n }\n\n private _onContentChange = () => {\n this.markDirty(true);\n };\n\n save(): void {\n const value = this.widgetRef.value?.getContent() ?? \"\";\n this.input?.data.saveContents(value);\n this.markDirty(false);\n }\n\n protected doClose() {\n this.widgetRef.value?.dispose();\n if (this.db) {\n void this.db.close();\n this.db = null;\n }\n }\n\n public getLanguage(): string | null {\n return \"sql\";\n }\n\n public isLanguage(lang: string): boolean {\n return lang.toLowerCase() === \"sql\";\n }\n\n public getContent(): string | null {\n return this.widgetRef.value?.getContent() ?? null;\n }\n\n public getSelection(): string | null {\n return this.widgetRef.value?.getSelection() ?? null;\n }\n\n public getSnippet(lines: number = 5): { snippet: string; cursorLine: number } | null {\n return this.widgetRef.value?.getSnippet(lines) ?? null;\n }\n\n public getFilePath(): string | null {\n return this.input?.data?.getWorkspacePath() ?? null;\n }\n\n private async runQuery(useSelectionOnly = false): Promise<void> {\n const sql = useSelectionOnly\n ? this.getSelection()?.trim()\n : (this.getSelection()?.trim() || this.getContent()?.trim());\n if (!sql) {\n toastError(useSelectionOnly ? \"No selection to run\" : \"No SQL to run\");\n return;\n }\n if (this.running) return;\n\n this.running = true;\n const id = `result-${++this.tabIdCounter}`;\n const label = truncateLabel(sql);\n this.resultTabs = [...this.resultTabs, { id, label, sql, result: { columns: [], rows: [] } }];\n this.activeResultId = id;\n this.requestUpdate();\n this.updateToolbar();\n\n const timeoutMs = 60_000;\n const timeoutId = window.setTimeout(() => this.clearRunningState(), timeoutMs);\n\n try {\n const dbName = this.selectedDbName ?? undefined;\n if (!this.db || this.db.name !== (dbName ?? null)) {\n if (this.db) {\n void this.db.close();\n this.db = null;\n }\n this.db = await duckdbService.open(dbName);\n }\n const result = await this.db.runQuery(sql);\n this.resultTabs = this.resultTabs.map((t) =>\n t.id === id ? { ...t, result } : t\n );\n } catch (err) {\n const error = err instanceof Error ? err.message : String(err);\n this.resultTabs = this.resultTabs.map((t) =>\n t.id === id ? { ...t, result: { error } } : t\n );\n } finally {\n window.clearTimeout(timeoutId);\n this.running = false;\n this.activeResultId = id;\n this.requestUpdate();\n this.updateToolbar();\n }\n }\n\n private clearRunningState(): void {\n if (this.running) {\n this.running = false;\n this.requestUpdate();\n this.updateToolbar();\n }\n }\n\n private closeTab(id: string): void {\n const idx = this.resultTabs.findIndex((t) => t.id === id);\n if (idx < 0) return;\n const next = this.resultTabs.filter((t) => t.id !== id);\n this.resultTabs = next;\n if (this.activeResultId === id) {\n const prevIdx = Math.min(idx, next.length - 1);\n this.activeResultId = next[prevIdx]?.id ?? null;\n }\n this.requestUpdate();\n this.updateToolbar();\n }\n\n private renderResultPanel(tab: ResultTab) {\n if (\"error\" in tab.result) {\n return html`\n <div class=\"result-error\">\n <pre>${tab.result.error}</pre>\n </div>\n `;\n }\n const { columns, rows } = tab.result;\n if (columns.length === 0 && rows.length === 0) {\n return html`<div class=\"result-empty\">Query returned no rows.</div>`;\n }\n return html`\n <div class=\"result-table-wrap\">\n <table class=\"result-table\">\n <thead>\n <tr>\n ${columns.map((col) => html`<th>${col}</th>`)}\n </tr>\n </thead>\n <tbody>\n ${rows.map(\n (row) => html`\n <tr>\n ${row.map((cell) => html`<td>${String(cell ?? \"\")}</td>`)}\n </tr>\n `\n )}\n </tbody>\n </table>\n </div>\n `;\n }\n\n private onDatabaseChange(e: Event) {\n const select = e.target as { value?: string };\n const value = select?.value ?? \"\";\n const next = value === \"\" ? null : value;\n if (this.selectedDbName === next) return;\n this.selectedDbName = next;\n if (this.db) {\n void this.db.close();\n this.db = null;\n }\n this.requestUpdate();\n }\n\n private async addNewDatabase(): Promise<void> {\n const raw = await promptDialog(\"New database name\", \"\");\n if (raw == null) return;\n const name = raw.trim();\n if (!name) {\n toastError(\"Name cannot be empty\");\n return;\n }\n if (!DB_NAME_REGEX.test(name)) {\n toastError(\"Name may only contain letters, numbers, and . _ -\");\n return;\n }\n if (this.availableDatabases.includes(name)) {\n toastError(`Database \"${name}\" already exists`);\n return;\n }\n try {\n const newDb = await duckdbService.open(name);\n await newDb.close();\n this.selectedDbName = name;\n if (this.db) {\n void this.db.close();\n this.db = null;\n }\n await this.refreshDatabaseList();\n toastInfo(`Database \"${name}\" created`);\n } catch (err) {\n toastError(err instanceof Error ? err.message : String(err));\n }\n }\n\n private async deleteSelectedDatabase(): Promise<void> {\n const name = this.selectedDbName;\n const label = name === null ? \"In-memory\" : name;\n const ok = await confirmDialog(`Delete database \"${label}\"?`);\n if (!ok) return;\n if (name === null) {\n if (this.db) {\n void this.db.close();\n this.db = null;\n }\n } else {\n try {\n await duckdbService.delete(name);\n if (this.db?.name === name) this.db = null;\n this.selectedDbName = null;\n await this.refreshDatabaseList();\n } catch (err) {\n toastError(err instanceof Error ? err.message : String(err));\n return;\n }\n }\n this.requestUpdate();\n this.updateToolbar();\n }\n\n protected renderToolbar() {\n const dbValue = this.selectedDbName ?? \"\";\n return html`\n <wa-select\n class=\"db-select\"\n size=\"small\"\n value=${dbValue}\n title=\"Database (OPFS)\"\n @change=${(e: Event) => this.onDatabaseChange(e)}\n >\n <wa-option value=\"\">In-memory</wa-option>\n ${this.availableDatabases.map(\n (name) => html`<wa-option value=${name}>${name}</wa-option>`\n )}\n </wa-select>\n <wa-button\n size=\"small\"\n appearance=\"plain\"\n title=\"New database\"\n @click=${() => this.addNewDatabase()}\n >\n <wa-icon name=\"plus\" label=\"New\"></wa-icon>\n </wa-button>\n <wa-button\n size=\"small\"\n appearance=\"plain\"\n title=${this.selectedDbName === null ? \"Clear in-memory database\" : `Delete database \"${this.selectedDbName}\"`}\n @click=${() => this.deleteSelectedDatabase()}\n >\n <wa-icon name=\"trash\" label=\"Delete\"></wa-icon>\n </wa-button>\n <wa-button\n size=\"small\"\n appearance=\"plain\"\n title=\"Manage DuckDB extensions\"\n @click=${() =>\n duckdbExtensionManagerService.showExtensionManager({\n db: this.db,\n databaseLabel: this.selectedDbName === null ? \"In-memory\" : this.selectedDbName,\n })}\n >\n <wa-icon name=\"puzzle-piece\" label=\"Extensions\"></wa-icon>\n Extensions\n </wa-button>\n <wa-button\n size=\"small\"\n appearance=\"plain\"\n ?disabled=${this.running}\n @click=${() => this.runQuery(true)}\n title=\"Run selection only\"\n >\n <wa-icon name=\"i-cursor\" label=\"Run selection\"></wa-icon>\n ${this.running ? \"Running…\" : \"Run selection\"}\n </wa-button>\n <wa-button\n size=\"small\"\n appearance=\"plain\"\n ?disabled=${this.running}\n @click=${() => this.runQuery(false)}\n title=\"Run all SQL\"\n >\n <wa-icon name=\"play\" label=\"Run\"></wa-icon>\n ${this.running ? \"Running…\" : \"Run all\"}\n </wa-button>\n `;\n }\n\n protected updated(changedProperties: Map<string, unknown>) {\n super.updated(changedProperties);\n if (changedProperties.has(\"resultTabs\") || changedProperties.has(\"running\")) {\n this.updateToolbar();\n }\n const activeId = this.activeResultId ?? this.resultTabs[0]?.id ?? \"\";\n if (activeId && this.tabGroupRef.value && this.tabGroupRef.value.active !== activeId) {\n this.tabGroupRef.value.active = activeId;\n }\n }\n\n render() {\n if (this.initialContent === undefined) {\n return html`<div class=\"editor-placeholder\"></div>`;\n }\n\n const hasResults = this.resultTabs.length > 0;\n const activeId = this.activeResultId ?? this.resultTabs[0]?.id ?? \"\";\n\n return html`\n <wa-split-panel\n class=\"editor-split\"\n orientation=\"vertical\"\n position=\"60\"\n >\n <div slot=\"start\" class=\"editor-area\">\n <lyra-monaco-widget\n .value=${this.initialContent}\n .uri=${this.initialUri}\n .language=${\"sql\"}\n .readOnly=${this.readOnly}\n @content-change=${this._onContentChange}\n ${ref(this.widgetRef)}\n ></lyra-monaco-widget>\n </div>\n <div slot=\"end\" class=\"results-area\">\n ${hasResults\n ? html`\n <wa-tab-group\n class=\"result-tabs\"\n .active=${activeId}\n ${ref(this.tabGroupRef)}\n @wa-tab-show=${(e: CustomEvent<{ name: string }>) => {\n this.activeResultId = e.detail?.name ?? null;\n }}\n >\n ${this.resultTabs.flatMap((tab) => [\n html`<wa-tab panel=\"${tab.id}\">${tab.label}</wa-tab>`,\n html`<wa-button\n slot=\"nav\"\n tabindex=\"-1\"\n appearance=\"plain\"\n size=\"small\"\n class=\"tab-close\"\n title=\"Close tab\"\n @click=${() => this.closeTab(tab.id)}\n >\n <wa-icon name=\"xmark\" label=\"Close\"></wa-icon>\n </wa-button>`,\n html`<wa-tab-panel name=\"${tab.id}\">${this.renderResultPanel(tab)}</wa-tab-panel>`,\n ])}\n </wa-tab-group>\n `\n : html`\n <div class=\"results-empty\">\n Run a query to see results in a new tab.\n </div>\n `}\n </div>\n </wa-split-panel>\n `;\n }\n\n static styles = css`\n :host {\n display: flex;\n flex-direction: column;\n position: relative;\n width: 100%;\n height: 100%;\n }\n .db-select {\n max-width: 10rem;\n }\n .editor-split {\n flex: 1;\n min-height: 0;\n height: 100%;\n }\n .editor-area,\n .results-area {\n height: 100%;\n min-height: 0;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n }\n .editor-area monaco-widget {\n flex: 1;\n min-height: 0;\n }\n .editor-placeholder {\n flex: 1;\n min-height: 0;\n }\n .result-tabs {\n flex: 1;\n min-height: 0;\n display: flex;\n flex-direction: column;\n }\n .result-tabs::part(body) {\n flex: 1;\n min-height: 0;\n overflow: auto;\n }\n .result-tabs .tab-close {\n margin-left: -0.25rem;\n padding: 0.2rem;\n }\n .results-empty {\n flex: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--wa-color-neutral-500, #6b7280);\n font-size: 0.875rem;\n }\n .result-table-wrap {\n overflow: auto;\n padding: 0.75rem;\n }\n .result-table {\n width: 100%;\n border-collapse: collapse;\n font-size: 0.8125rem;\n }\n .result-table th,\n .result-table td {\n padding: 0.35rem 0.75rem;\n text-align: left;\n border-bottom: 1px solid var(--wa-color-neutral-200, #e5e7eb);\n }\n .result-table th {\n font-weight: 600;\n background: var(--wa-color-neutral-100, #f3f4f6);\n }\n .result-table tbody tr:hover {\n background: var(--wa-color-neutral-50, #f9fafb);\n }\n .result-error {\n padding: 0.75rem;\n color: var(--wa-color-red-60, #dc2626);\n font-family: ui-monospace, monospace;\n font-size: 0.8125rem;\n }\n .result-error pre {\n margin: 0;\n white-space: pre-wrap;\n }\n .result-empty {\n padding: 0.75rem;\n color: var(--wa-color-neutral-500, #6b7280);\n font-size: 0.875rem;\n }\n `;\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"lyra-duckdb-editor\": LyraDuckDBEditor;\n }\n}\n","import { rootContext, editorRegistry, File, type EditorInput } from '@eclipse-lyra/core';\nimport { html } from 'lit';\nimport { duckdbService } from './duckdb-service';\nimport './duckdb-editor';\nimport './duckdb-extension-manager';\n\nexport default function () {\n rootContext.put('duckdbService', duckdbService);\n\n editorRegistry.registerEditorInputHandler({\n editorId: 'system.duckdb-editor',\n label: 'DuckDB',\n icon: 'database',\n canHandle: (input: unknown) =>\n input instanceof File && input.getName().toLowerCase().endsWith('.sql'),\n ranking: 1000,\n handle: async (input: File) => {\n const editorInput: EditorInput = {\n title: input.getName(),\n data: input,\n key: input.getName(),\n icon: 'database',\n noOverflow: false,\n state: {},\n widgetFactory: () => null as any,\n };\n editorInput.widgetFactory = () =>\n html`<lyra-duckdb-editor .input=${editorInput}></lyra-duckdb-editor>`;\n return editorInput;\n },\n });\n}\n"],"names":[],"mappings":"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"}