feat: 🎸 Add sqlite handler and parser (#2933)
* feat: 🎸 Add sqlite handler and parser ✅ Closes: https://hashicorp.atlassian.net/browse/ICU-17410
This commit is contained in:
1 parent
8abed1a809
commit
e0982da744
33 files changed
+1692
-111
No files matched your search
@@ -0,0 +1,123 @@
|
||||
/**
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import Service from '@ember/service';
|
||||
import { PWBHost } from 'promise-worker-bi';
|
||||
|
||||
// A mapping of columns to their expected model attributes for supported models
|
||||
// The JSON data column is not included here but is assumed to always be last.
|
||||
export const modelMapping = {
|
||||
target: {
|
||||
id: 'id',
|
||||
type: 'type',
|
||||
name: 'name',
|
||||
description: 'description',
|
||||
address: 'address',
|
||||
scope_id: 'scope.scope_id',
|
||||
created_time: 'created_time',
|
||||
},
|
||||
};
|
||||
|
||||
// A list of tables that we support searching using FTS5 in SQLite.
|
||||
export const searchTables = new Set(['target']);
|
||||
|
||||
export default class SqliteDbService extends Service {
|
||||
// =attributes
|
||||
|
||||
// We need a handle on the original web worker to properly clean it up.
|
||||
webWorker;
|
||||
// This will be the worker we interact with that is wrapped by PWBHost.
|
||||
worker;
|
||||
|
||||
setup(dbName) {
|
||||
if (this.worker) {
|
||||
// If the worker already exists, we don't need to do anything.
|
||||
return;
|
||||
}
|
||||
|
||||
// In production, our JS files will be fingerprinted with an MD5 hash
|
||||
// so we need a way to map the worker file name to be able to find it.
|
||||
//
|
||||
// Ember is automagically replacing any URL path with the fingerprinted
|
||||
// asset, and this is done by broccoli-asset-rev.
|
||||
//
|
||||
// The problem is it's a bit finicky as seen in this issue
|
||||
// https://github.com/ember-cli/broccoli-asset-rewrite/issues/66
|
||||
// and will not work properly if it's part of a template string or interpolated.
|
||||
// Therefore, we need the URL path in a string somewhere to be replaced properly.
|
||||
this.webWorker = new Worker('/workers/sqlite-worker.js', {
|
||||
type: 'module',
|
||||
});
|
||||
|
||||
// We use PWBHost to simplify communication so we can just send and receive
|
||||
// messages with promises rather than having to manually set up event listeners
|
||||
this.worker = new PWBHost(this.webWorker);
|
||||
this.worker.register(async ({ method }) => {
|
||||
if (method === 'getDatabaseName') {
|
||||
return dbName;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fetchResource({ sql, parameters }) {
|
||||
return this.worker.postMessage({
|
||||
method: 'fetchResource',
|
||||
payload: { sql, parameters },
|
||||
});
|
||||
}
|
||||
|
||||
insertResource(resource, items) {
|
||||
return this.worker.postMessage({
|
||||
method: 'insertResource',
|
||||
payload: { resource, items, modelMapping },
|
||||
});
|
||||
}
|
||||
|
||||
deleteResource(resource, ids) {
|
||||
return this.worker.postMessage({
|
||||
method: 'deleteResource',
|
||||
payload: { resource, ids },
|
||||
});
|
||||
}
|
||||
|
||||
analyzeDatabase() {
|
||||
return this.worker.postMessage({ method: 'analyzeDatabase' });
|
||||
}
|
||||
|
||||
async downloadDatabase() {
|
||||
const byteArray = await this.worker.postMessage({
|
||||
method: 'downloadDatabase',
|
||||
});
|
||||
|
||||
const blob = new Blob([byteArray.buffer], {
|
||||
type: 'application/x-sqlite3',
|
||||
});
|
||||
|
||||
// Create temporary elements to initialize the download
|
||||
const a = window.document.createElement('a');
|
||||
window.document.body.appendChild(a);
|
||||
a.href = window.URL.createObjectURL(blob);
|
||||
a.download = 'boundary.db';
|
||||
a.addEventListener('click', function () {
|
||||
setTimeout(function () {
|
||||
window.URL.revokeObjectURL(a.href);
|
||||
a.remove();
|
||||
}, 500);
|
||||
});
|
||||
a.click();
|
||||
}
|
||||
|
||||
async clearDatabase() {
|
||||
await this.worker.postMessage({ method: 'clearDatabase' });
|
||||
}
|
||||
|
||||
async deleteDatabase() {
|
||||
await this.worker.postMessage({ method: 'deleteDatabase' });
|
||||
}
|
||||
|
||||
willDestroy() {
|
||||
this.webWorker?.terminate();
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user