toolkit/components/places/PlacesSemanticHistoryDatabase.sys.mjs (91 lines of code) (raw):
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
const lazy = {};
ChromeUtils.defineESModuleGetters(lazy, {
Sqlite: "resource://gre/modules/Sqlite.sys.mjs",
});
export class PlacesSemanticHistoryDatabase {
#conn;
dbDirPath;
#placesDbPath;
#semanticDbPath;
#embeddingSize;
constructor(embeddingSize, semanticDbFullPath) {
this.#embeddingSize = embeddingSize;
this.#semanticDbPath = semanticDbFullPath;
this.dbDirPath = PathUtils.parent(semanticDbFullPath);
}
/**
* Creates the necessary virtual tables in the semantic.sqlite database.
*/
async #createVirtualVecTables(conn, embeddingSize) {
await conn.executeTransaction(async () => {
await conn.execute(`
CREATE VIRTUAL TABLE vec_history USING vec0(
embedding FLOAT[${embeddingSize}],
embedding_coarse bit[${embeddingSize}]
);`);
await conn.execute(`
CREATE TABLE vec_history_mapping (
rowid INTEGER PRIMARY KEY,
url_hash INTEGER NOT NULL UNIQUE
);`);
});
}
/**
* Connects to the semantic.sqlite database and attaches the Places DB.
*
* @returns {Promise<object>}
* A promise resolving to the database connection.
*/
async getConnection() {
// Connect to the database
this.#conn = await lazy.Sqlite.openConnection({
path: this.#semanticDbPath,
extensions: ["vec"],
});
this.#placesDbPath = PathUtils.join(this.dbDirPath, "places.sqlite");
await this.attachPlacesDb();
// Add shutdown blocker to close connection gracefully
lazy.Sqlite.shutdown.addBlocker(
"PlacesSemanticHistoryDatabase: Shutdown",
() => this.#conn.close()
);
return this.#conn;
}
/**
* Attaches the Places database to the semantic.sqlite connection.
*/
async attachPlacesDb() {
await this.#conn.execute(
`ATTACH DATABASE '${this.#placesDbPath}' AS places`
);
}
/**
* Initializes the semantic database, creating virtual tables if needed.
*/
async initVectorDatabase() {
// Connect to the database
let version = await this.#conn.getSchemaVersion();
if (version == 0) {
await this.#createVirtualVecTables(this.#conn, this.#embeddingSize);
version = 1;
await this.#conn.setSchemaVersion(version);
}
}
// util method to get the path to semanticDB
getDatabasePath() {
return this.#semanticDbPath;
}
/**
* Drops the history vector tables and resets schema version
*/
async dropSchema() {
await this.#conn.executeTransaction(async () => {
await this.#conn.execute(`DROP TABLE IF EXISTS vec_history;`);
await this.#conn.execute(`DROP TABLE IF EXISTS vec_history_mapping;`);
});
await this.#conn.setSchemaVersion(0);
}
}