@mark1russell7/docker-sqlite 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +48 -23
- package/LICENSE +21 -21
- package/README.md +1089 -1057
- package/dist/.tsbuildinfo +1 -1
- package/dist/connect.d.ts +79 -50
- package/dist/connect.d.ts.map +1 -1
- package/dist/connect.js +120 -14
- package/dist/connect.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/migrate.d.ts.map +1 -1
- package/dist/migrate.js +151 -12
- package/dist/migrate.js.map +1 -1
- package/dist/query.d.ts +51 -51
- package/dist/query.d.ts.map +1 -1
- package/dist/query.js +3 -4
- package/dist/query.js.map +1 -1
- package/package.json +80 -86
- package/schema/logs.sql +21 -21
- package/src/connect.ts +317 -194
- package/src/index.ts +61 -61
- package/src/migrate.ts +293 -159
- package/src/query.ts +146 -147
- package/src/types.ts +62 -62
package/src/query.ts
CHANGED
|
@@ -1,147 +1,146 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Query helper utilities for SQLite
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import type { Database } from "sql.js";
|
|
6
|
-
import type { QueryResult, ExecuteResult } from "./types.js";
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Execute a SELECT query and return results
|
|
10
|
-
*
|
|
11
|
-
* @example
|
|
12
|
-
* ```typescript
|
|
13
|
-
* const result = query(db, 'SELECT * FROM users WHERE age > ?', [21]);
|
|
14
|
-
* console.log(result.columns); // ['id', 'name', 'age']
|
|
15
|
-
* console.log(result.rows); // [{ id: 1, name: 'Alice', age: 25 }, ...]
|
|
16
|
-
* ```
|
|
17
|
-
*/
|
|
18
|
-
export function query<T = Record<string, unknown>>(
|
|
19
|
-
db: Database,
|
|
20
|
-
sql: string,
|
|
21
|
-
params: unknown[] = []
|
|
22
|
-
): QueryResult<T> {
|
|
23
|
-
const stmt = db.prepare(sql);
|
|
24
|
-
|
|
25
|
-
try {
|
|
26
|
-
stmt.bind(params as (string | number | Uint8Array | null)[]);
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
//
|
|
59
|
-
//
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
db
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
.replace(
|
|
86
|
-
.replace(
|
|
87
|
-
.
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
*
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
const
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
//
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
*
|
|
116
|
-
*
|
|
117
|
-
*
|
|
118
|
-
*
|
|
119
|
-
*
|
|
120
|
-
* CREATE TABLE IF NOT EXISTS
|
|
121
|
-
*
|
|
122
|
-
*
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Query helper utilities for SQLite
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { Database } from "sql.js";
|
|
6
|
+
import type { QueryResult, ExecuteResult } from "./types.js";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Execute a SELECT query and return results
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* const result = query(db, 'SELECT * FROM users WHERE age > ?', [21]);
|
|
14
|
+
* console.log(result.columns); // ['id', 'name', 'age']
|
|
15
|
+
* console.log(result.rows); // [{ id: 1, name: 'Alice', age: 25 }, ...]
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export function query<T = Record<string, unknown>>(
|
|
19
|
+
db: Database,
|
|
20
|
+
sql: string,
|
|
21
|
+
params: unknown[] = []
|
|
22
|
+
): QueryResult<T> {
|
|
23
|
+
const stmt = db.prepare(sql);
|
|
24
|
+
|
|
25
|
+
try {
|
|
26
|
+
stmt.bind(params as (string | number | Uint8Array | null)[]);
|
|
27
|
+
|
|
28
|
+
// The statement knows its columns before the first step. Before, the columns came from the
|
|
29
|
+
// first row, so a result with no rows had no columns.
|
|
30
|
+
const columns = stmt.getColumnNames();
|
|
31
|
+
const rows: T[] = [];
|
|
32
|
+
|
|
33
|
+
while (stmt.step()) {
|
|
34
|
+
rows.push(stmt.getAsObject() as T);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return { columns, rows };
|
|
38
|
+
} finally {
|
|
39
|
+
stmt.free();
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Execute an INSERT, UPDATE, DELETE, or other statement
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```typescript
|
|
48
|
+
* const result = execute(db, 'INSERT INTO users (name, age) VALUES (?, ?)', ['Bob', 30]);
|
|
49
|
+
* console.log(result.changes); // 1
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
export function execute(
|
|
53
|
+
db: Database,
|
|
54
|
+
sql: string,
|
|
55
|
+
params: unknown[] = []
|
|
56
|
+
): ExecuteResult {
|
|
57
|
+
// With parameters, sql.js runs only the first statement. Before, the other statements were
|
|
58
|
+
// ignored and the call reported success. Now several statements run with no parameters, and
|
|
59
|
+
// are an error with parameters.
|
|
60
|
+
if (hasSeveralStatements(db, sql)) {
|
|
61
|
+
if (params.length > 0) {
|
|
62
|
+
throw new Error(
|
|
63
|
+
"execute() binds parameters to one statement, and the SQL has several. Send one statement per call."
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
const before = totalChanges(db);
|
|
67
|
+
db.exec(sql);
|
|
68
|
+
return { changes: totalChanges(db) - before };
|
|
69
|
+
}
|
|
70
|
+
db.run(sql, params as (string | number | Uint8Array | null)[]);
|
|
71
|
+
const changes = db.getRowsModified();
|
|
72
|
+
return { changes };
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** The number of rows that the statements of this connection changed. */
|
|
76
|
+
function totalChanges(db: Database): number {
|
|
77
|
+
const result = db.exec("SELECT total_changes()");
|
|
78
|
+
return Number(result[0]?.values[0]?.[0] ?? 0);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** True when the text holds SQL other than spaces, ";" and comments. */
|
|
82
|
+
function holdsStatement(sql: string): boolean {
|
|
83
|
+
return sql
|
|
84
|
+
.replace(/--[^\n]*/g, "")
|
|
85
|
+
.replace(/\/\*[\s\S]*?\*\//g, "")
|
|
86
|
+
.replace(/[\s;]/g, "")
|
|
87
|
+
.length > 0;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* True when `sql` holds more than one statement. Nothing runs: the function only prepares the
|
|
92
|
+
* first statement and examines the SQL after it.
|
|
93
|
+
*/
|
|
94
|
+
export function hasSeveralStatements(db: Database, sql: string): boolean {
|
|
95
|
+
const iterator = db.iterateStatements(sql);
|
|
96
|
+
const first = iterator.next();
|
|
97
|
+
if (first.done) {
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
const rest = iterator.getRemainingSQL();
|
|
101
|
+
// Read the iterator to its end: this frees the statement and the copy of the SQL. A later
|
|
102
|
+
// statement can fail to prepare (its table does not exist yet), and that also ends it.
|
|
103
|
+
try {
|
|
104
|
+
while (!iterator.next().done) {
|
|
105
|
+
// Prepare only
|
|
106
|
+
}
|
|
107
|
+
} catch {
|
|
108
|
+
// The iterator ended
|
|
109
|
+
}
|
|
110
|
+
return holdsStatement(rest);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Execute multiple statements (for schema setup, etc.)
|
|
115
|
+
*
|
|
116
|
+
* @example
|
|
117
|
+
* ```typescript
|
|
118
|
+
* execMultiple(db, `
|
|
119
|
+
* CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT);
|
|
120
|
+
* CREATE TABLE IF NOT EXISTS posts (id INTEGER PRIMARY KEY, user_id INTEGER);
|
|
121
|
+
* `);
|
|
122
|
+
* ```
|
|
123
|
+
*/
|
|
124
|
+
export function execMultiple(db: Database, sql: string): void {
|
|
125
|
+
db.exec(sql);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Get the last inserted row ID
|
|
130
|
+
*/
|
|
131
|
+
export function lastInsertRowId(db: Database): number {
|
|
132
|
+
const result = query<{ id: number }>(db, "SELECT last_insert_rowid() as id");
|
|
133
|
+
return result.rows[0]?.id ?? 0;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Check if a table exists
|
|
138
|
+
*/
|
|
139
|
+
export function tableExists(db: Database, tableName: string): boolean {
|
|
140
|
+
const result = query<{ name: string }>(
|
|
141
|
+
db,
|
|
142
|
+
"SELECT name FROM sqlite_master WHERE type='table' AND name=?",
|
|
143
|
+
[tableName]
|
|
144
|
+
);
|
|
145
|
+
return result.rows.length > 0;
|
|
146
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -1,62 +1,62 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Type definitions for docker-sqlite
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import type { Database } from "sql.js";
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Configuration for SQLite connection
|
|
9
|
-
*/
|
|
10
|
-
export interface ConnectionConfig {
|
|
11
|
-
/** Path to the SQLite database file. Use ":memory:" for in-memory database */
|
|
12
|
-
dbPath: string;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Callback function for withConnection
|
|
17
|
-
*/
|
|
18
|
-
export type ConnectionCallback<T> = (db: Database) => T | Promise<T>;
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Result of a query operation
|
|
22
|
-
*/
|
|
23
|
-
export interface QueryResult<T = Record<string, unknown>> {
|
|
24
|
-
/** Column names */
|
|
25
|
-
columns: string[];
|
|
26
|
-
/** Row values */
|
|
27
|
-
rows: T[];
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Result of an execute operation (INSERT, UPDATE, DELETE)
|
|
32
|
-
*/
|
|
33
|
-
export interface ExecuteResult {
|
|
34
|
-
/** Number of rows affected */
|
|
35
|
-
changes: number;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Migration definition
|
|
40
|
-
*/
|
|
41
|
-
export interface Migration {
|
|
42
|
-
/** Migration version (must be unique and sequential) */
|
|
43
|
-
version: number;
|
|
44
|
-
/** Description of the migration */
|
|
45
|
-
description: string;
|
|
46
|
-
/** SQL to apply the migration */
|
|
47
|
-
up: string;
|
|
48
|
-
/** SQL to revert the migration (optional) */
|
|
49
|
-
down?: string;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Migration status
|
|
54
|
-
*/
|
|
55
|
-
export interface MigrationStatus {
|
|
56
|
-
/** Current version (0 if no migrations applied) */
|
|
57
|
-
currentVersion: number;
|
|
58
|
-
/** List of applied migrations */
|
|
59
|
-
appliedMigrations: number[];
|
|
60
|
-
/** List of pending migrations */
|
|
61
|
-
pendingMigrations: Migration[];
|
|
62
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Type definitions for docker-sqlite
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { Database } from "sql.js";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Configuration for SQLite connection
|
|
9
|
+
*/
|
|
10
|
+
export interface ConnectionConfig {
|
|
11
|
+
/** Path to the SQLite database file. Use ":memory:" for in-memory database */
|
|
12
|
+
dbPath: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Callback function for withConnection
|
|
17
|
+
*/
|
|
18
|
+
export type ConnectionCallback<T> = (db: Database) => T | Promise<T>;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Result of a query operation
|
|
22
|
+
*/
|
|
23
|
+
export interface QueryResult<T = Record<string, unknown>> {
|
|
24
|
+
/** Column names */
|
|
25
|
+
columns: string[];
|
|
26
|
+
/** Row values */
|
|
27
|
+
rows: T[];
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Result of an execute operation (INSERT, UPDATE, DELETE)
|
|
32
|
+
*/
|
|
33
|
+
export interface ExecuteResult {
|
|
34
|
+
/** Number of rows affected */
|
|
35
|
+
changes: number;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Migration definition
|
|
40
|
+
*/
|
|
41
|
+
export interface Migration {
|
|
42
|
+
/** Migration version (must be unique and sequential) */
|
|
43
|
+
version: number;
|
|
44
|
+
/** Description of the migration */
|
|
45
|
+
description: string;
|
|
46
|
+
/** SQL to apply the migration */
|
|
47
|
+
up: string;
|
|
48
|
+
/** SQL to revert the migration (optional) */
|
|
49
|
+
down?: string;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Migration status
|
|
54
|
+
*/
|
|
55
|
+
export interface MigrationStatus {
|
|
56
|
+
/** Current version (0 if no migrations applied) */
|
|
57
|
+
currentVersion: number;
|
|
58
|
+
/** List of applied migrations */
|
|
59
|
+
appliedMigrations: number[];
|
|
60
|
+
/** List of pending migrations */
|
|
61
|
+
pendingMigrations: Migration[];
|
|
62
|
+
}
|