Skip to content

Commit 93761a5

Browse files
committed
feat: Auto-reload if file changes on disk
1 parent 8508352 commit 93761a5

2 files changed

Lines changed: 45 additions & 15 deletions

File tree

media/flatFileExplorer.ts

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,11 @@ interface ConfigMessage {
116116
autoQuery?: boolean;
117117
}
118118

119-
type IncomingMessage = QueryMessage | MoreMessage | ConfigMessage;
119+
interface ReloadBaseViewMessage {
120+
type: "reloadBaseView";
121+
}
122+
123+
type IncomingMessage = QueryMessage | MoreMessage | ConfigMessage | ReloadBaseViewMessage;
120124

121125
interface CodeInputElement extends HTMLElement {
122126
value: string;
@@ -139,6 +143,7 @@ interface CodeInputElement extends HTMLElement {
139143

140144
let table: any = null;
141145
let lastSql: string | undefined;
146+
let lastQueryTimestampMs: Nullable<number> = null;
142147

143148
// Whether the spinner is currently showing.
144149
let loadingQuery = false;
@@ -250,6 +255,10 @@ interface CodeInputElement extends HTMLElement {
250255
table.addData(message.results);
251256
}
252257
break;
258+
259+
case "reloadBaseView":
260+
runQuery();
261+
break;
253262
}
254263
});
255264

@@ -289,12 +298,16 @@ interface CodeInputElement extends HTMLElement {
289298
const runQuery = () => {
290299
const sql = readSqlQueryFromBox();
291300

292-
updateQueryHint();
293-
294301
// Ctrl/Cmd + Enter causes onChange to be called twice.
295-
if (sql === lastSql) return;
302+
// if (sql === lastSql) return; - Don't do this because we must re-query on file changes!
303+
// This also has a debouncing effect, in case a CSV writer writes incrementally.
304+
if (lastQueryTimestampMs && ((Date.now() - lastQueryTimestampMs) < 250)) return;
305+
306+
lastQueryTimestampMs = Date.now();
296307
lastSql = sql;
297308

309+
updateQueryHint();
310+
298311
loadingQuery = true;
299312
loadingMore = false;
300313

src/parquetDocument.ts

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ type IMessage = {
1313
message?: string;
1414
results?: duckdb.TableData;
1515
describe?: duckdb.TableData;
16-
} | { type: 'config', autoQuery: boolean };
16+
} | { type: 'config', autoQuery: boolean } | { type: 'reloadBaseView' };
1717

1818
/**
1919
* Define the document (the data model) used for table files.
@@ -46,9 +46,9 @@ class ParquetDocument extends Disposable implements vscode.CustomDocument {
4646
const fileExtension = extname(uri.fsPath).toLowerCase();
4747

4848
if (CSV_EXTENSIONS.includes(fileExtension)) {
49-
this._createViewSql = `CREATE VIEW ${tableName} AS SELECT * FROM read_csv('${uri.fsPath}');`;
49+
this._createViewSql = `CREATE OR REPLACE VIEW ${tableName} AS SELECT * FROM read_csv('${uri.fsPath}');`;
5050
} else if (PARQUET_EXTENSIONS.includes(fileExtension)) {
51-
this._createViewSql = `CREATE VIEW ${tableName} AS SELECT * FROM read_parquet('${uri.fsPath}');`;
51+
this._createViewSql = `CREATE OR REPLACE VIEW ${tableName} AS SELECT * FROM read_parquet('${uri.fsPath}');`;
5252
} else {
5353
// If this error occurs, check that the trigger types in `package.json` are in sync
5454
// with the extension definition arrays at the top of this file.
@@ -143,6 +143,10 @@ class ParquetDocument extends Disposable implements vscode.CustomDocument {
143143
}
144144
);
145145
}
146+
147+
reloadBaseView(): void {
148+
this.db.exec(this._createViewSql);
149+
}
146150
}
147151

148152

@@ -177,14 +181,31 @@ export class ParquetDocumentProvider implements vscode.CustomReadonlyEditorProvi
177181
_token: vscode.CancellationToken
178182
): Promise<void> {
179183
// Setup initial content for the webview.
180-
webviewPanel.webview.options = {
181-
enableScripts: true,
182-
};
184+
webviewPanel.webview.options = { enableScripts: true };
183185

184186
webviewPanel.webview.html = this.getHtmlForWebview(webviewPanel.webview, document.uri);
185187

186188
webviewPanel.webview.onDidReceiveMessage(e => this.onMessage(document, webviewPanel, e));
187189

190+
// Monitor the open file for changes so we can re-query if it changes.
191+
const watcher = vscode.workspace.createFileSystemWatcher(
192+
new vscode.RelativePattern(
193+
vscode.Uri.file(document.uri.fsPath).with({ path: document.uri.fsPath }).fsPath,
194+
'*'
195+
)
196+
);
197+
198+
const reload = () => {
199+
document.reloadBaseView();
200+
this.postMessage(webviewPanel, { type: 'reloadBaseView' });
201+
};
202+
203+
watcher.onDidChange(reload);
204+
watcher.onDidCreate(reload);
205+
watcher.onDidDelete(reload);
206+
207+
webviewPanel.onDidDispose(() => watcher.dispose());
208+
188209
// Send the autoQuery configuration to the webview.
189210
const config = vscode.workspace.getConfiguration('flat-file-explorer')
190211
this.postMessage(webviewPanel, {
@@ -286,11 +307,7 @@ export class ParquetDocumentProvider implements vscode.CustomReadonlyEditorProvi
286307
<body>
287308
<div id="controls">
288309
<div class="query-toolbar">
289-
<code-input
290-
nonce="${nonce}"
291-
lang="SQL"
292-
value="${defaultQuery}">
293-
</code-input>
310+
<code-input nonce="${nonce}" lang="SQL" value="${defaultQuery}"></code-input>
294311
295312
<div class="query-actions">
296313
<button id="executeQueryButton" class="action-button primary">

0 commit comments

Comments
 (0)