Add column presets
This commit is contained in:
parent
6479d09196
commit
1bfc20673d
6 changed files with 50 additions and 34 deletions
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@endeavorance/prequel",
|
||||
"version": "1.4.0",
|
||||
"version": "2.0.0",
|
||||
"exports": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
"scripts": {
|
||||
|
|
|
@ -23,6 +23,11 @@ export const ColumnOf = {
|
|||
nullable: false,
|
||||
},
|
||||
|
||||
Blob: {
|
||||
type: "BLOB",
|
||||
nullable: false,
|
||||
},
|
||||
|
||||
ForeignKey(otherTable: Table<unknown>, cascade = false): ColumnShorthand {
|
||||
return {
|
||||
type: otherTable.primaryColumnType(),
|
||||
|
@ -48,6 +53,11 @@ export const ColumnOf = {
|
|||
nullable: true,
|
||||
},
|
||||
|
||||
Blob: {
|
||||
type: "BLOB",
|
||||
nullable: true,
|
||||
},
|
||||
|
||||
ForeignKey(otherTable: Table<unknown>, cascade = false): ColumnShorthand {
|
||||
return {
|
||||
type: otherTable.primaryColumnType(),
|
||||
|
@ -77,6 +87,12 @@ export const ColumnOf = {
|
|||
unique: true,
|
||||
},
|
||||
|
||||
Blob: {
|
||||
type: "BLOB",
|
||||
nullable: false,
|
||||
unique: true,
|
||||
},
|
||||
|
||||
ForeignKey(otherTable: Table<unknown>, cascade = false): ColumnShorthand {
|
||||
return {
|
||||
type: otherTable.primaryColumnType(),
|
||||
|
@ -109,5 +125,12 @@ export const ColumnOf = {
|
|||
default: defaultValue,
|
||||
} as const;
|
||||
},
|
||||
|
||||
Blob(defaultValue: string): ColumnShorthand {
|
||||
return {
|
||||
type: "BLOB",
|
||||
default: defaultValue,
|
||||
} as const;
|
||||
},
|
||||
},
|
||||
} as const;
|
|
@ -1,4 +1,4 @@
|
|||
import { ColumnOf } from "./column-types";
|
||||
import { ColumnOf } from "./column-presets";
|
||||
import type { Column, ColumnShorthand, DataType } from "./columns";
|
||||
import { Prequel } from "./prequel";
|
||||
import { Table } from "./table";
|
||||
|
|
|
@ -106,7 +106,7 @@ export class Prequel {
|
|||
public kv: PrequelKVStore;
|
||||
public tables: Record<string, Table<unknown>> = {};
|
||||
public query: typeof Database.prototype.query;
|
||||
public uncachedQuery: typeof Database.prototype.prepare;
|
||||
public prepare: typeof Database.prototype.prepare;
|
||||
|
||||
/**
|
||||
* Creates a new Prequel database instance.
|
||||
|
@ -115,7 +115,7 @@ export class Prequel {
|
|||
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.prepare = this.db.prepare.bind(this.db);
|
||||
this.db.exec("PRAGMA foreign_keys=ON");
|
||||
this.kv = new PrequelKVStore(this, "PrequelManagedKVStore");
|
||||
}
|
||||
|
|
37
src/table.ts
37
src/table.ts
|
@ -12,7 +12,17 @@ import { Prequel } from "./prequel";
|
|||
export type ExtractRowShape<T> = T extends Table<infer R> ? R : never;
|
||||
|
||||
/** Types that may appear in a row */
|
||||
type ColumnValue = string | number | null;
|
||||
type ColumnValue = string | number | boolean | bigint | null;
|
||||
|
||||
function isColumnValue(val: unknown): val is ColumnValue {
|
||||
return (
|
||||
typeof val === "string" ||
|
||||
typeof val === "number" ||
|
||||
typeof val === "boolean" ||
|
||||
typeof val === "bigint" ||
|
||||
val === null
|
||||
);
|
||||
}
|
||||
|
||||
export class PrequelIDNotFoundError extends Error {
|
||||
constructor(tableName: string, id: ColumnValue) {
|
||||
|
@ -37,13 +47,7 @@ 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" &&
|
||||
typeof val === "boolean" &&
|
||||
typeof val === "bigint" &&
|
||||
val !== null
|
||||
) {
|
||||
if (val !== undefined && !isColumnValue(val)) {
|
||||
throw new SchemaError(
|
||||
`Invalid value in query: ${key} -> ${val} (type: ${typeof val})`,
|
||||
);
|
||||
|
@ -68,6 +72,7 @@ export class Table<RowShape> {
|
|||
private _columnNames: string[];
|
||||
private _createTableSQL: string;
|
||||
private _primaryColumnName = "ROWID";
|
||||
private _primaryColumnType: DataType | null = null;
|
||||
private _insertQuery: Statement<RowShape, [ArbitraryRow]>;
|
||||
private _updateQuery: Statement<RowShape, [ArbitraryRow]>;
|
||||
private _findQuery: Statement<RowShape, [string]>;
|
||||
|
@ -109,6 +114,7 @@ export class Table<RowShape> {
|
|||
// Identify a primary column besides ROWID if specified
|
||||
if (columnDefinition.primary && this._primaryColumnName === "ROWID") {
|
||||
this._primaryColumnName = columnName;
|
||||
this._primaryColumnType = columnDefinition.type;
|
||||
}
|
||||
|
||||
// Add non-primary columns to the generic update query
|
||||
|
@ -166,9 +172,7 @@ export class Table<RowShape> {
|
|||
}
|
||||
|
||||
public primaryColumnType(): DataType {
|
||||
const primary = this
|
||||
._primaryColumnName as keyof typeof this._columnDefinitions;
|
||||
return this._columnDefinitions[primary].type;
|
||||
return this._primaryColumnType ?? "INTEGER";
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -488,17 +492,6 @@ export class Table<RowShape> {
|
|||
this._truncateQuery.run();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the size of the table.
|
||||
*
|
||||
* @deprecated Use `count()` instead.
|
||||
* @returns {number} The number of rows in the table.
|
||||
* @throws {Error} If the row count query fails.
|
||||
*/
|
||||
public size(): number {
|
||||
return this.count();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the size of the table.
|
||||
*
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { Database } from "bun:sqlite";
|
||||
import { expect, test } from "bun:test";
|
||||
import { Prequel, Table } from "../src/index";
|
||||
import { ColumnOf, Prequel, Table } from "../src/index";
|
||||
|
||||
interface UserWithID {
|
||||
user_id: number;
|
||||
|
@ -263,11 +263,11 @@ test(".delete() deletes a full record", () => {
|
|||
table.insertPartial({ name: "Kate" });
|
||||
table.insertPartial({ name: "Sayid" });
|
||||
|
||||
expect(table.size()).toBe(3);
|
||||
expect(table.count()).toBe(3);
|
||||
|
||||
table.delete(table.findOneByIdOrFail(2));
|
||||
|
||||
expect(table.size()).toBe(2);
|
||||
expect(table.count()).toBe(2);
|
||||
|
||||
expect(table.findAll()).toEqual([
|
||||
{ user_id: 1, name: "Jack" },
|
||||
|
@ -281,11 +281,11 @@ test(".deleteById() deletes the element with the given primary value", () => {
|
|||
table.insertPartial({ name: "Kate" });
|
||||
table.insertPartial({ name: "Sayid" });
|
||||
|
||||
expect(table.size()).toBe(3);
|
||||
expect(table.count()).toBe(3);
|
||||
|
||||
table.deleteById(2);
|
||||
|
||||
expect(table.size()).toBe(2);
|
||||
expect(table.count()).toBe(2);
|
||||
|
||||
expect(table.findAll()).toEqual([
|
||||
{ user_id: 1, name: "Jack" },
|
||||
|
@ -299,11 +299,11 @@ test(".deleteWhere() deletes all rows that match", () => {
|
|||
table.insertPartial({ name: "Jack" });
|
||||
table.insertPartial({ name: "Sayid" });
|
||||
|
||||
expect(table.size()).toBe(3);
|
||||
expect(table.count()).toBe(3);
|
||||
|
||||
table.deleteWhere({ name: "Jack" });
|
||||
|
||||
expect(table.size()).toBe(1);
|
||||
expect(table.count()).toBe(1);
|
||||
|
||||
expect(table.findAll()).toEqual([{ user_id: 3, name: "Sayid" }]);
|
||||
});
|
||||
|
@ -336,7 +336,7 @@ test(".deleteById() respects when references are set to cascade", () => {
|
|||
});
|
||||
|
||||
users.deleteById(user.user_id);
|
||||
expect(posts.size()).toBe(0);
|
||||
expect(posts.count()).toBe(0);
|
||||
});
|
||||
|
||||
test(".deleteAll() deletes all rows in the table", () => {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue