Add biome
This commit is contained in:
parent
09d25c926c
commit
6479d09196
9 changed files with 586 additions and 538 deletions
|
@ -28,7 +28,7 @@ export const ColumnOf = {
|
|||
type: otherTable.primaryColumnType(),
|
||||
references: otherTable.reference(),
|
||||
nullable: false,
|
||||
cascade
|
||||
cascade,
|
||||
};
|
||||
},
|
||||
|
||||
|
@ -36,7 +36,6 @@ export const ColumnOf = {
|
|||
Text: {
|
||||
type: "TEXT",
|
||||
nullable: true,
|
||||
|
||||
},
|
||||
|
||||
Int: {
|
||||
|
@ -94,7 +93,7 @@ export const ColumnOf = {
|
|||
return {
|
||||
type: "TEXT",
|
||||
default: defaultValue,
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
Int(defaultValue: number): ColumnShorthand {
|
||||
|
@ -109,7 +108,6 @@ export const ColumnOf = {
|
|||
type: "REAL",
|
||||
default: defaultValue,
|
||||
} as const;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
} as const;
|
||||
|
|
11
src/index.ts
11
src/index.ts
|
@ -1,6 +1,13 @@
|
|||
import { ColumnOf } from "./column-types";
|
||||
import type { Column, ColumnShorthand, DataType } from "./columns";
|
||||
import { Prequel } from "./prequel";
|
||||
import { Table } from "./table";
|
||||
import { ColumnOf } from "./column-types";
|
||||
|
||||
export { Prequel, Table, ColumnOf, type DataType, type Column, type ColumnShorthand };
|
||||
export {
|
||||
Prequel,
|
||||
Table,
|
||||
ColumnOf,
|
||||
type DataType,
|
||||
type Column,
|
||||
type ColumnShorthand,
|
||||
};
|
||||
|
|
322
src/prequel.ts
322
src/prequel.ts
|
@ -4,194 +4,194 @@ import { SchemaError } from "./error";
|
|||
import { Table } from "./table";
|
||||
|
||||
interface KVRow {
|
||||
kv_id: number;
|
||||
key: string;
|
||||
value: string;
|
||||
kv_id: number;
|
||||
key: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a key-value store using Prequel.
|
||||
*/
|
||||
export class PrequelKVStore {
|
||||
private table: Table<KVRow>;
|
||||
private table: Table<KVRow>;
|
||||
|
||||
/**
|
||||
* Creates a new instance of the PrequelKVStore class.
|
||||
* @param pq The Prequel instance.
|
||||
* @param tableName The name of the table.
|
||||
*/
|
||||
constructor(pq: Prequel, tableName: string) {
|
||||
this.table = pq.table<KVRow>(tableName, {
|
||||
kv_id: {
|
||||
type: "INTEGER",
|
||||
primary: true,
|
||||
autoincrement: true,
|
||||
},
|
||||
key: "TEXT",
|
||||
value: "TEXT",
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Creates a new instance of the PrequelKVStore class.
|
||||
* @param pq The Prequel instance.
|
||||
* @param tableName The name of the table.
|
||||
*/
|
||||
constructor(pq: Prequel, tableName: string) {
|
||||
this.table = pq.table<KVRow>(tableName, {
|
||||
kv_id: {
|
||||
type: "INTEGER",
|
||||
primary: true,
|
||||
autoincrement: true,
|
||||
},
|
||||
key: "TEXT",
|
||||
value: "TEXT",
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts or updates a key-value pair in the store.
|
||||
* @param key The key.
|
||||
* @param value The value.
|
||||
*/
|
||||
put<T>(key: string, value: T): void {
|
||||
const lookup = this.table.findOneWhere({
|
||||
key,
|
||||
});
|
||||
/**
|
||||
* Inserts or updates a key-value pair in the store.
|
||||
* @param key The key.
|
||||
* @param value The value.
|
||||
*/
|
||||
put<T>(key: string, value: T): void {
|
||||
const lookup = this.table.findOneWhere({
|
||||
key,
|
||||
});
|
||||
|
||||
if (lookup === null) {
|
||||
this.table.insertPartial({
|
||||
key,
|
||||
value: JSON.stringify(value),
|
||||
});
|
||||
} else {
|
||||
lookup.value = JSON.stringify(value);
|
||||
this.table.update(lookup);
|
||||
}
|
||||
}
|
||||
if (lookup === null) {
|
||||
this.table.insertPartial({
|
||||
key,
|
||||
value: JSON.stringify(value),
|
||||
});
|
||||
} else {
|
||||
lookup.value = JSON.stringify(value);
|
||||
this.table.update(lookup);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the value associated with the specified key from the store.
|
||||
* @param key The key.
|
||||
* @returns The value associated with the key, or null if the key is not found.
|
||||
*/
|
||||
get<T>(key: string): T | null {
|
||||
const lookup = this.table.findOneWhere({ key });
|
||||
/**
|
||||
* Retrieves the value associated with the specified key from the store.
|
||||
* @param key The key.
|
||||
* @returns The value associated with the key, or null if the key is not found.
|
||||
*/
|
||||
get<T>(key: string): T | null {
|
||||
const lookup = this.table.findOneWhere({ key });
|
||||
|
||||
if (lookup === null) {
|
||||
return null;
|
||||
}
|
||||
if (lookup === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return JSON.parse(lookup.value) as T;
|
||||
}
|
||||
return JSON.parse(lookup.value) as T;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a key exists in the table.
|
||||
* @param key - The key to check.
|
||||
* @returns `true` if the key exists, `false` otherwise.
|
||||
*/
|
||||
has(key: string): boolean {
|
||||
return (
|
||||
this.table.findOneWhere({
|
||||
key,
|
||||
}) !== null
|
||||
);
|
||||
}
|
||||
/**
|
||||
* Checks if a key exists in the table.
|
||||
* @param key - The key to check.
|
||||
* @returns `true` if the key exists, `false` otherwise.
|
||||
*/
|
||||
has(key: string): boolean {
|
||||
return (
|
||||
this.table.findOneWhere({
|
||||
key,
|
||||
}) !== null
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an array of all of the keys in the KV store
|
||||
* @returns The keys in the store.
|
||||
*/
|
||||
keys(): string[] {
|
||||
return this.table.findAll().map((row) => row.key);
|
||||
}
|
||||
/**
|
||||
* Get an array of all of the keys in the KV store
|
||||
* @returns The keys in the store.
|
||||
*/
|
||||
keys(): string[] {
|
||||
return this.table.findAll().map((row) => row.key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an array of all of the values in the KV store
|
||||
* @returns The values in the store.
|
||||
*/
|
||||
values(): unknown[] {
|
||||
return this.table.findAll().map((row) => JSON.parse(row.value));
|
||||
}
|
||||
/**
|
||||
* Get an array of all of the values in the KV store
|
||||
* @returns The values in the store.
|
||||
*/
|
||||
values(): unknown[] {
|
||||
return this.table.findAll().map((row) => JSON.parse(row.value));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a Prequel database instance.
|
||||
*/
|
||||
export class Prequel {
|
||||
public db: Database;
|
||||
public kv: PrequelKVStore;
|
||||
public tables: Record<string, Table<unknown>> = {};
|
||||
public query: typeof Database.prototype.query;
|
||||
public uncachedQuery: typeof Database.prototype.prepare;
|
||||
public db: Database;
|
||||
public kv: PrequelKVStore;
|
||||
public tables: Record<string, Table<unknown>> = {};
|
||||
public query: typeof Database.prototype.query;
|
||||
public uncachedQuery: typeof Database.prototype.prepare;
|
||||
|
||||
/**
|
||||
* Creates a new Prequel database instance.
|
||||
* @param filename The filename of the database. Defaults to ":memory:" if not provided.
|
||||
*/
|
||||
constructor(filename = ":memory:") {
|
||||
this.db = new Database(filename);
|
||||
this.query = this.db.query.bind(this.db);
|
||||
this.uncachedQuery = this.db.prepare.bind(this.db);
|
||||
this.db.exec("PRAGMA foreign_keys=ON");
|
||||
this.kv = new PrequelKVStore(this, "PrequelManagedKVStore");
|
||||
}
|
||||
/**
|
||||
* Creates a new Prequel database instance.
|
||||
* @param filename The filename of the database. Defaults to ":memory:" if not provided.
|
||||
*/
|
||||
constructor(filename = ":memory:") {
|
||||
this.db = new Database(filename);
|
||||
this.query = this.db.query.bind(this.db);
|
||||
this.uncachedQuery = this.db.prepare.bind(this.db);
|
||||
this.db.exec("PRAGMA foreign_keys=ON");
|
||||
this.kv = new PrequelKVStore(this, "PrequelManagedKVStore");
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables Write-Ahead Logging (WAL) mode for the database.
|
||||
*/
|
||||
enableWAL() {
|
||||
this.db.exec("PRAGMA journal_mode=WAL;");
|
||||
}
|
||||
/**
|
||||
* Enables Write-Ahead Logging (WAL) mode for the database.
|
||||
*/
|
||||
enableWAL() {
|
||||
this.db.exec("PRAGMA journal_mode=WAL;");
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the database connection.
|
||||
*/
|
||||
close() {
|
||||
this.db.close();
|
||||
}
|
||||
/**
|
||||
* Closes the database connection.
|
||||
*/
|
||||
close() {
|
||||
this.db.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a table with the given name exists in the database.
|
||||
* @param name The name of the table.
|
||||
* @returns `true` if the table exists, `false` otherwise.
|
||||
*/
|
||||
hasTable(name: string): boolean {
|
||||
return Object.keys(this.tables).includes(name);
|
||||
}
|
||||
/**
|
||||
* Checks if a table with the given name exists in the database.
|
||||
* @param name The name of the table.
|
||||
* @returns `true` if the table exists, `false` otherwise.
|
||||
*/
|
||||
hasTable(name: string): boolean {
|
||||
return Object.keys(this.tables).includes(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new table in the database.
|
||||
* @param name The name of the table.
|
||||
* @param cols The column definitions of the table.
|
||||
* @returns The created table.
|
||||
* @throws {SchemaError} If a table with the same name already exists.
|
||||
*/
|
||||
table<RowShape>(
|
||||
name: string,
|
||||
cols: ColumnShorthandMap<RowShape>,
|
||||
): Table<RowShape> {
|
||||
if (this.hasTable(name)) {
|
||||
throw new SchemaError("Duplicate table name", name);
|
||||
}
|
||||
/**
|
||||
* Creates a new table in the database.
|
||||
* @param name The name of the table.
|
||||
* @param cols The column definitions of the table.
|
||||
* @returns The created table.
|
||||
* @throws {SchemaError} If a table with the same name already exists.
|
||||
*/
|
||||
table<RowShape>(
|
||||
name: string,
|
||||
cols: ColumnShorthandMap<RowShape>,
|
||||
): Table<RowShape> {
|
||||
if (this.hasTable(name)) {
|
||||
throw new SchemaError("Duplicate table name", name);
|
||||
}
|
||||
|
||||
const newTable = new Table(this, name, cols);
|
||||
this.tables[name] = newTable;
|
||||
return newTable;
|
||||
}
|
||||
const newTable = new Table(this, name, cols);
|
||||
this.tables[name] = newTable;
|
||||
return newTable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attaches an existing table to the database.
|
||||
* @param table The table to attach.
|
||||
* @throws {SchemaError} If a table with the same name already exists.
|
||||
*/
|
||||
attachTable(table: Table<unknown>) {
|
||||
if (this.hasTable(table.name)) {
|
||||
throw new SchemaError("Duplicate table name", table.name);
|
||||
}
|
||||
/**
|
||||
* Attaches an existing table to the database.
|
||||
* @param table The table to attach.
|
||||
* @throws {SchemaError} If a table with the same name already exists.
|
||||
*/
|
||||
attachTable(table: Table<unknown>) {
|
||||
if (this.hasTable(table.name)) {
|
||||
throw new SchemaError("Duplicate table name", table.name);
|
||||
}
|
||||
|
||||
this.tables[table.name] = table;
|
||||
}
|
||||
/**
|
||||
* Executes a function within a database transaction.
|
||||
* If the function throws an error, the transaction is rolled back.
|
||||
* Otherwise, the transaction is committed.
|
||||
* @param transactionFn The function to execute within the transaction.
|
||||
* @returns `true` if the transaction was committed successfully, otherwise `false`.
|
||||
* @throws The error thrown by the transaction function if the transaction fails.
|
||||
*/
|
||||
transaction<T>(transactionFn: () => T): T {
|
||||
try {
|
||||
this.db.exec("BEGIN TRANSACTION;");
|
||||
const result: T = transactionFn();
|
||||
this.db.exec("COMMIT;");
|
||||
return result;
|
||||
} catch (error) {
|
||||
this.db.exec("ROLLBACK;");
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
this.tables[table.name] = table;
|
||||
}
|
||||
/**
|
||||
* Executes a function within a database transaction.
|
||||
* If the function throws an error, the transaction is rolled back.
|
||||
* Otherwise, the transaction is committed.
|
||||
* @param transactionFn The function to execute within the transaction.
|
||||
* @returns `true` if the transaction was committed successfully, otherwise `false`.
|
||||
* @throws The error thrown by the transaction function if the transaction fails.
|
||||
*/
|
||||
transaction<T>(transactionFn: () => T): T {
|
||||
try {
|
||||
this.db.exec("BEGIN TRANSACTION;");
|
||||
const result: T = transactionFn();
|
||||
this.db.exec("COMMIT;");
|
||||
return result;
|
||||
} catch (error) {
|
||||
this.db.exec("ROLLBACK;");
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
15
src/table.ts
15
src/table.ts
|
@ -37,9 +37,15 @@ function shapeForQuery<T>(obj: Partial<T>): ArbitraryRow {
|
|||
for (const key of keys) {
|
||||
const val = obj[key as keyof T];
|
||||
|
||||
if (typeof val !== "string" && typeof val !== "number" && val !== null) {
|
||||
if (
|
||||
typeof val === "string" &&
|
||||
typeof val === "number" &&
|
||||
typeof val === "boolean" &&
|
||||
typeof val === "bigint" &&
|
||||
val !== null
|
||||
) {
|
||||
throw new SchemaError(
|
||||
`Invalid value in query: ${key}: ${val} (type: ${typeof val})`,
|
||||
`Invalid value in query: ${key} -> ${val} (type: ${typeof val})`,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -97,7 +103,7 @@ export class Table<RowShape> {
|
|||
for (const columnName of this._columnNames) {
|
||||
const columnDefinition =
|
||||
this._columnDefinitions[
|
||||
columnName as keyof typeof this._columnDefinitions
|
||||
columnName as keyof typeof this._columnDefinitions
|
||||
];
|
||||
|
||||
// Identify a primary column besides ROWID if specified
|
||||
|
@ -160,7 +166,8 @@ export class Table<RowShape> {
|
|||
}
|
||||
|
||||
public primaryColumnType(): DataType {
|
||||
const primary = this._primaryColumnName as keyof typeof this._columnDefinitions;
|
||||
const primary = this
|
||||
._primaryColumnName as keyof typeof this._columnDefinitions;
|
||||
return this._columnDefinitions[primary].type;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue