@tmlmobilidade/sqlite 20251202.1817.5
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/dist/index.d.ts +4 -0
- package/dist/index.js +4 -0
- package/dist/sqlite-db.d.ts +65 -0
- package/dist/sqlite-db.js +195 -0
- package/dist/sqlite-map.d.ts +57 -0
- package/dist/sqlite-map.js +121 -0
- package/dist/sqlite-writer.d.ts +11 -0
- package/dist/sqlite-writer.js +41 -0
- package/dist/types.d.ts +49 -0
- package/dist/types.js +2 -0
- package/package.json +50 -0
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { SQLiteDatabaseConfig, SQLiteTable } from './types.js';
|
|
2
|
+
import BSQLite3, { type Database } from 'better-sqlite3';
|
|
3
|
+
import { Readable } from 'node:stream';
|
|
4
|
+
export declare class SQLiteDatabase {
|
|
5
|
+
databaseInstance: Database;
|
|
6
|
+
private tables;
|
|
7
|
+
constructor(config?: SQLiteDatabaseConfig);
|
|
8
|
+
/**
|
|
9
|
+
* Registers a new table and returns an object with methods for that table.
|
|
10
|
+
*/
|
|
11
|
+
registerTable<T>(tableName: string, params: SQLiteTable<T>): SQLiteTableInstance<T>;
|
|
12
|
+
}
|
|
13
|
+
export declare class SQLiteTableInstance<T> {
|
|
14
|
+
/**
|
|
15
|
+
* Get the number of rows in the table.
|
|
16
|
+
* @returns The number of rows.
|
|
17
|
+
*/
|
|
18
|
+
get size(): number;
|
|
19
|
+
private batch;
|
|
20
|
+
private batchSize;
|
|
21
|
+
private columns;
|
|
22
|
+
private databaseInstance;
|
|
23
|
+
private insertStatement;
|
|
24
|
+
private tableName;
|
|
25
|
+
constructor(databaseInstance: Database, tableName: string, params: SQLiteTable<T>);
|
|
26
|
+
/**
|
|
27
|
+
* Get all rows, optionally filtered by a WHERE clause.
|
|
28
|
+
* @param whereClause Optional SQL WHERE clause (e.g., "WHERE id = ?").
|
|
29
|
+
* @param params Parameters for the WHERE clause.
|
|
30
|
+
* @returns An array of matching rows.
|
|
31
|
+
*/
|
|
32
|
+
all(whereClause?: string, params?: (boolean | number | string)[]): T[];
|
|
33
|
+
/**
|
|
34
|
+
* Clears all entries from the map.
|
|
35
|
+
*/
|
|
36
|
+
clear(): void;
|
|
37
|
+
/**
|
|
38
|
+
* Flush current buffer into DB synchronously.
|
|
39
|
+
*/
|
|
40
|
+
flush(): void;
|
|
41
|
+
/**
|
|
42
|
+
* Get a single row by column value.
|
|
43
|
+
* @param col The column to filter by.
|
|
44
|
+
* @param value The value to match.
|
|
45
|
+
* @returns The matching row, or undefined if not found.
|
|
46
|
+
*/
|
|
47
|
+
get<K extends keyof T>(col: K, value: T[K]): T | undefined;
|
|
48
|
+
/**
|
|
49
|
+
* Check if a row exists by column value.
|
|
50
|
+
* @param col The column to filter by.
|
|
51
|
+
* @param value The value to match.
|
|
52
|
+
* @returns True if the row exists, false otherwise.
|
|
53
|
+
*/
|
|
54
|
+
has<K extends keyof T>(col: K, value: T[K]): boolean;
|
|
55
|
+
query(sqlQuery?: string, params?: (boolean | number | string)[]): BSQLite3.RunResult;
|
|
56
|
+
/**
|
|
57
|
+
* Iterator to go through all rows in the table.
|
|
58
|
+
*/
|
|
59
|
+
stream(whereClause?: string, params?: (boolean | number | string)[]): Readable;
|
|
60
|
+
update(whereClause: string, newData: Partial<T>, params?: (boolean | number | string)[]): T[];
|
|
61
|
+
/**
|
|
62
|
+
* Add one item to buffer, flush automatically when batchSize reached.
|
|
63
|
+
*/
|
|
64
|
+
write(item: T): void;
|
|
65
|
+
}
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
/* * */
|
|
2
|
+
import { generateRandomString } from '@tmlmobilidade/strings';
|
|
3
|
+
import BSQLite3 from 'better-sqlite3';
|
|
4
|
+
import fs from 'node:fs';
|
|
5
|
+
import { Readable } from 'node:stream';
|
|
6
|
+
/* * */
|
|
7
|
+
export class SQLiteDatabase {
|
|
8
|
+
//
|
|
9
|
+
//
|
|
10
|
+
// Properties
|
|
11
|
+
databaseInstance;
|
|
12
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
13
|
+
tables = new Map();
|
|
14
|
+
//
|
|
15
|
+
// Constructor
|
|
16
|
+
constructor(config = {}) {
|
|
17
|
+
//
|
|
18
|
+
//
|
|
19
|
+
// If not provided, generate random values
|
|
20
|
+
// and create a new database instance.
|
|
21
|
+
if (!config.instanceName && !config.memory) {
|
|
22
|
+
config.instanceName = generateRandomString();
|
|
23
|
+
}
|
|
24
|
+
if (!config.instancePath && !config.memory) {
|
|
25
|
+
config.instancePath = `/tmp/${config.instanceName}/${config.instanceName}.db`;
|
|
26
|
+
fs.mkdirSync(`/tmp/${config.instanceName}`, { recursive: true });
|
|
27
|
+
}
|
|
28
|
+
if (!config.databaseInstance) {
|
|
29
|
+
config.databaseInstance = new BSQLite3(config.memory ? ':memory:' : config.instancePath);
|
|
30
|
+
}
|
|
31
|
+
//
|
|
32
|
+
// Initialize the database instance
|
|
33
|
+
this.databaseInstance = config.databaseInstance;
|
|
34
|
+
this.databaseInstance.pragma('journal_mode = WAL');
|
|
35
|
+
this.databaseInstance.pragma('synchronous = ON');
|
|
36
|
+
this.databaseInstance.pragma('temp_store = MEMORY');
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Registers a new table and returns an object with methods for that table.
|
|
40
|
+
*/
|
|
41
|
+
registerTable(tableName, params) {
|
|
42
|
+
if (this.tables.has(tableName)) {
|
|
43
|
+
throw new Error(`Table "${tableName}" already registered`);
|
|
44
|
+
}
|
|
45
|
+
const tableInstance = new SQLiteTableInstance(this.databaseInstance, tableName, params);
|
|
46
|
+
this.tables.set(tableName, tableInstance);
|
|
47
|
+
return tableInstance;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/* * */
|
|
51
|
+
export class SQLiteTableInstance {
|
|
52
|
+
//
|
|
53
|
+
/**
|
|
54
|
+
* Get the number of rows in the table.
|
|
55
|
+
* @returns The number of rows.
|
|
56
|
+
*/
|
|
57
|
+
get size() {
|
|
58
|
+
const sql = `SELECT COUNT(*) as count FROM ${this.tableName}`;
|
|
59
|
+
const row = this.databaseInstance.prepare(sql).get();
|
|
60
|
+
return row.count;
|
|
61
|
+
}
|
|
62
|
+
//
|
|
63
|
+
// Constructor
|
|
64
|
+
batch = [];
|
|
65
|
+
batchSize = 3000;
|
|
66
|
+
columns;
|
|
67
|
+
databaseInstance;
|
|
68
|
+
insertStatement;
|
|
69
|
+
tableName;
|
|
70
|
+
constructor(databaseInstance, tableName, params) {
|
|
71
|
+
//
|
|
72
|
+
//
|
|
73
|
+
// Set up properties
|
|
74
|
+
this.databaseInstance = databaseInstance;
|
|
75
|
+
this.batchSize = params.batch_size ?? 3000;
|
|
76
|
+
this.columns = params.columns;
|
|
77
|
+
this.tableName = tableName;
|
|
78
|
+
// Create table
|
|
79
|
+
this.databaseInstance
|
|
80
|
+
.prepare(`CREATE TABLE IF NOT EXISTS ${this.tableName} (${params.columns.map(c => `"${c.name}" ${c.type}`).join(', ')})`)
|
|
81
|
+
.run();
|
|
82
|
+
// Create indexes
|
|
83
|
+
params.columns.forEach((c) => {
|
|
84
|
+
if (c.indexed) {
|
|
85
|
+
this.databaseInstance.exec(`CREATE INDEX IF NOT EXISTS idx_${this.tableName}_${c.name} ON ${this.tableName}("${c.name}")`);
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
//
|
|
89
|
+
// Prepare insert statement
|
|
90
|
+
const placeholders = this.columns.map(() => '?').join(', ');
|
|
91
|
+
const insertSQL = `INSERT INTO ${this.tableName} (${this.columns.map(c => `"${c.name}"`).join(', ')}) VALUES (${placeholders})`;
|
|
92
|
+
this.insertStatement = this.databaseInstance.prepare(insertSQL);
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Get all rows, optionally filtered by a WHERE clause.
|
|
96
|
+
* @param whereClause Optional SQL WHERE clause (e.g., "WHERE id = ?").
|
|
97
|
+
* @param params Parameters for the WHERE clause.
|
|
98
|
+
* @returns An array of matching rows.
|
|
99
|
+
*/
|
|
100
|
+
all(whereClause = '', params = []) {
|
|
101
|
+
const sql = `SELECT * FROM ${this.tableName} ${whereClause}`;
|
|
102
|
+
return this.databaseInstance.prepare(sql).all(...params);
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Clears all entries from the map.
|
|
106
|
+
*/
|
|
107
|
+
clear() {
|
|
108
|
+
this.databaseInstance
|
|
109
|
+
.prepare(`DELETE FROM ${this.tableName}`)
|
|
110
|
+
.run();
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Flush current buffer into DB synchronously.
|
|
114
|
+
*/
|
|
115
|
+
flush() {
|
|
116
|
+
// Skip if batch is empty
|
|
117
|
+
if (this.batch.length === 0)
|
|
118
|
+
return;
|
|
119
|
+
// Prepare the operation
|
|
120
|
+
const insertManyOperation = this.databaseInstance.transaction((rows) => {
|
|
121
|
+
rows.forEach((row) => {
|
|
122
|
+
// Populate the columns with the row values
|
|
123
|
+
// to ensure the order of placeholders is preserved
|
|
124
|
+
const rowValues = this.columns.map((col) => {
|
|
125
|
+
const value = row[col.name];
|
|
126
|
+
// Convert boolean to 0 or 1
|
|
127
|
+
if (typeof value === 'boolean') {
|
|
128
|
+
return value ? 1 : 0;
|
|
129
|
+
}
|
|
130
|
+
return value;
|
|
131
|
+
});
|
|
132
|
+
this.insertStatement.run(rowValues);
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
// Run the operation
|
|
136
|
+
insertManyOperation(this.batch);
|
|
137
|
+
// Empty batch
|
|
138
|
+
this.batch = [];
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Get a single row by column value.
|
|
142
|
+
* @param col The column to filter by.
|
|
143
|
+
* @param value The value to match.
|
|
144
|
+
* @returns The matching row, or undefined if not found.
|
|
145
|
+
*/
|
|
146
|
+
get(col, value) {
|
|
147
|
+
const sql = `SELECT * FROM ${this.tableName} WHERE ${String(col)} = ? LIMIT 1`;
|
|
148
|
+
return this.databaseInstance.prepare(sql).get(value);
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Check if a row exists by column value.
|
|
152
|
+
* @param col The column to filter by.
|
|
153
|
+
* @param value The value to match.
|
|
154
|
+
* @returns True if the row exists, false otherwise.
|
|
155
|
+
*/
|
|
156
|
+
has(col, value) {
|
|
157
|
+
const sql = `SELECT 1 FROM ${this.tableName} WHERE ${String(col)} = ? LIMIT 1`;
|
|
158
|
+
return !!this.databaseInstance.prepare(sql).get(value);
|
|
159
|
+
}
|
|
160
|
+
query(sqlQuery = '', params = []) {
|
|
161
|
+
return this.databaseInstance.prepare(sqlQuery).run(...params);
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Iterator to go through all rows in the table.
|
|
165
|
+
*/
|
|
166
|
+
stream(whereClause = '', params = []) {
|
|
167
|
+
// Create an iterator for the query
|
|
168
|
+
const iterator = this.databaseInstance
|
|
169
|
+
.prepare(`SELECT * FROM ${this.tableName} ${whereClause}`)
|
|
170
|
+
.iterate(...params);
|
|
171
|
+
// Return a Readable stream in object mode
|
|
172
|
+
return new Readable({
|
|
173
|
+
objectMode: true,
|
|
174
|
+
read() {
|
|
175
|
+
const next = iterator.next();
|
|
176
|
+
if (next.done)
|
|
177
|
+
this.push(null); // end of stream
|
|
178
|
+
else
|
|
179
|
+
this.push(next.value);
|
|
180
|
+
},
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
update(whereClause = '', newData, params = []) {
|
|
184
|
+
const sql = `UPDATE ${this.tableName} SET ${Object.keys(newData).map(key => `${key} = ?`).join(', ')} WHERE ${whereClause}`;
|
|
185
|
+
return this.databaseInstance.prepare(sql).all(...params);
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Add one item to buffer, flush automatically when batchSize reached.
|
|
189
|
+
*/
|
|
190
|
+
write(item) {
|
|
191
|
+
this.batch.push(item);
|
|
192
|
+
if (this.batch.length >= this.batchSize)
|
|
193
|
+
this.flush();
|
|
194
|
+
}
|
|
195
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A map-like structure backed by SQLite for persistent key-value storage.
|
|
3
|
+
* Use it to store and retrieve data across sessions without memory constraints.
|
|
4
|
+
* The API is similar to the native javascript Map object.
|
|
5
|
+
*/
|
|
6
|
+
export declare class SQLiteMap<K extends string, V> {
|
|
7
|
+
/**
|
|
8
|
+
* Returns the number of entries in the map.
|
|
9
|
+
*/
|
|
10
|
+
get size(): number;
|
|
11
|
+
private databaseInstance;
|
|
12
|
+
constructor();
|
|
13
|
+
/**
|
|
14
|
+
* Clears all entries from the map.
|
|
15
|
+
*/
|
|
16
|
+
clear(): void;
|
|
17
|
+
/**
|
|
18
|
+
* Deletes a key-value pair from the map.
|
|
19
|
+
* @param key The key of the entry to delete.
|
|
20
|
+
* @returns True if the entry was deleted, false if it didn't exist.
|
|
21
|
+
*/
|
|
22
|
+
delete(key: K): boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Returns an iterator over the entries in the map.
|
|
25
|
+
*/
|
|
26
|
+
entries(): IterableIterator<[K, V]>;
|
|
27
|
+
/**
|
|
28
|
+
* Retrieves the value associated with the given key.
|
|
29
|
+
* @param key The key of the entry to retrieve.
|
|
30
|
+
* @returns The value associated with the key, or undefined if it doesn't exist.
|
|
31
|
+
*/
|
|
32
|
+
get(key: K): undefined | V;
|
|
33
|
+
/**
|
|
34
|
+
* Checks if the map contains a value for the given key.
|
|
35
|
+
* @param key The key to check.
|
|
36
|
+
* @returns True if the key exists, false otherwise.
|
|
37
|
+
*/
|
|
38
|
+
has(key: K): boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Returns an iterator over the keys in the map.
|
|
41
|
+
*/
|
|
42
|
+
keys(): IterableIterator<K>;
|
|
43
|
+
/**
|
|
44
|
+
* Sets the value for the given key.
|
|
45
|
+
* @param key The key of the entry to set.
|
|
46
|
+
* @param value The value to associate with the key.
|
|
47
|
+
*/
|
|
48
|
+
set(key: K, value: V): void;
|
|
49
|
+
/**
|
|
50
|
+
* Returns an iterator over the entries in the map.
|
|
51
|
+
*/
|
|
52
|
+
[Symbol.iterator](): IterableIterator<[K, V]>;
|
|
53
|
+
/**
|
|
54
|
+
* Returns an iterator over the values in the map.
|
|
55
|
+
*/
|
|
56
|
+
values(): IterableIterator<V>;
|
|
57
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/* * */
|
|
2
|
+
import { generateRandomString } from '@tmlmobilidade/strings';
|
|
3
|
+
import BSQLite3 from 'better-sqlite3';
|
|
4
|
+
/* * */
|
|
5
|
+
/**
|
|
6
|
+
* A map-like structure backed by SQLite for persistent key-value storage.
|
|
7
|
+
* Use it to store and retrieve data across sessions without memory constraints.
|
|
8
|
+
* The API is similar to the native javascript Map object.
|
|
9
|
+
*/
|
|
10
|
+
export class SQLiteMap {
|
|
11
|
+
//
|
|
12
|
+
/**
|
|
13
|
+
* Returns the number of entries in the map.
|
|
14
|
+
*/
|
|
15
|
+
get size() {
|
|
16
|
+
const row = this.databaseInstance
|
|
17
|
+
.prepare(`SELECT COUNT(*) as count FROM map`)
|
|
18
|
+
.get();
|
|
19
|
+
return row.count;
|
|
20
|
+
}
|
|
21
|
+
databaseInstance;
|
|
22
|
+
constructor() {
|
|
23
|
+
//
|
|
24
|
+
//
|
|
25
|
+
// Set up a new database instance
|
|
26
|
+
const databaseFileName = generateRandomString();
|
|
27
|
+
this.databaseInstance = new BSQLite3(`/tmp/${databaseFileName}.db`);
|
|
28
|
+
//
|
|
29
|
+
// Create a new table if it doesn't exist
|
|
30
|
+
this.databaseInstance.pragma('journal_mode = WAL');
|
|
31
|
+
this.databaseInstance.pragma('synchronous = NORMAL');
|
|
32
|
+
this.databaseInstance
|
|
33
|
+
.prepare(`CREATE TABLE IF NOT EXISTS map (key TEXT PRIMARY KEY, value TEXT NOT NULL)`)
|
|
34
|
+
.run();
|
|
35
|
+
//
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Clears all entries from the map.
|
|
39
|
+
*/
|
|
40
|
+
clear() {
|
|
41
|
+
this.databaseInstance
|
|
42
|
+
.prepare(`DELETE FROM map`)
|
|
43
|
+
.run();
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Deletes a key-value pair from the map.
|
|
47
|
+
* @param key The key of the entry to delete.
|
|
48
|
+
* @returns True if the entry was deleted, false if it didn't exist.
|
|
49
|
+
*/
|
|
50
|
+
delete(key) {
|
|
51
|
+
const result = this.databaseInstance
|
|
52
|
+
.prepare(`DELETE FROM map WHERE key = ?`)
|
|
53
|
+
.run(key);
|
|
54
|
+
return result.changes > 0;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Returns an iterator over the entries in the map.
|
|
58
|
+
*/
|
|
59
|
+
*entries() {
|
|
60
|
+
const statement = this.databaseInstance.prepare(`SELECT key, value FROM map`);
|
|
61
|
+
for (const row of statement.iterate()) {
|
|
62
|
+
yield [JSON.parse(row.key), JSON.parse(row.value)];
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Retrieves the value associated with the given key.
|
|
67
|
+
* @param key The key of the entry to retrieve.
|
|
68
|
+
* @returns The value associated with the key, or undefined if it doesn't exist.
|
|
69
|
+
*/
|
|
70
|
+
get(key) {
|
|
71
|
+
const row = this.databaseInstance
|
|
72
|
+
.prepare(`SELECT value FROM map WHERE key = ?`)
|
|
73
|
+
.get(key);
|
|
74
|
+
return row ? JSON.parse(row.value) : undefined;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Checks if the map contains a value for the given key.
|
|
78
|
+
* @param key The key to check.
|
|
79
|
+
* @returns True if the key exists, false otherwise.
|
|
80
|
+
*/
|
|
81
|
+
has(key) {
|
|
82
|
+
const row = this.databaseInstance
|
|
83
|
+
.prepare(`SELECT 1 FROM map WHERE key = ?`)
|
|
84
|
+
.get(key);
|
|
85
|
+
return !!row;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Returns an iterator over the keys in the map.
|
|
89
|
+
*/
|
|
90
|
+
*keys() {
|
|
91
|
+
const statement = this.databaseInstance.prepare(`SELECT key FROM map`);
|
|
92
|
+
for (const row of statement.iterate()) {
|
|
93
|
+
yield JSON.parse(row.key);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Sets the value for the given key.
|
|
98
|
+
* @param key The key of the entry to set.
|
|
99
|
+
* @param value The value to associate with the key.
|
|
100
|
+
*/
|
|
101
|
+
set(key, value) {
|
|
102
|
+
this.databaseInstance
|
|
103
|
+
.prepare(`INSERT OR REPLACE INTO map (key, value) VALUES (?, ?)`)
|
|
104
|
+
.run(key, JSON.stringify(value));
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Returns an iterator over the entries in the map.
|
|
108
|
+
*/
|
|
109
|
+
[Symbol.iterator]() {
|
|
110
|
+
return this.entries();
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Returns an iterator over the values in the map.
|
|
114
|
+
*/
|
|
115
|
+
*values() {
|
|
116
|
+
const statement = this.databaseInstance.prepare(`SELECT value FROM map`);
|
|
117
|
+
for (const row of statement.iterate()) {
|
|
118
|
+
yield JSON.parse(row.value);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { SQLiteTableInstance } from './sqlite-db.js';
|
|
2
|
+
import { type SQLiteTable } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* @deprecated Use `SQLiteDatabase` instead.
|
|
5
|
+
*/
|
|
6
|
+
export declare class SQLiteWriter<T> extends SQLiteTableInstance<T> {
|
|
7
|
+
readonly instanceName: string;
|
|
8
|
+
readonly instancePath: string;
|
|
9
|
+
constructor(params: SQLiteTable<T>);
|
|
10
|
+
private static createDatabase;
|
|
11
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/* * */
|
|
2
|
+
import { SQLiteTableInstance } from './sqlite-db.js';
|
|
3
|
+
import { generateRandomString } from '@tmlmobilidade/strings';
|
|
4
|
+
import BSQLite3 from 'better-sqlite3';
|
|
5
|
+
/**
|
|
6
|
+
* @deprecated Use `SQLiteDatabase` instead.
|
|
7
|
+
*/
|
|
8
|
+
export class SQLiteWriter extends SQLiteTableInstance {
|
|
9
|
+
//
|
|
10
|
+
//
|
|
11
|
+
// Properties
|
|
12
|
+
instanceName;
|
|
13
|
+
instancePath;
|
|
14
|
+
//
|
|
15
|
+
// Constructor
|
|
16
|
+
constructor(params) {
|
|
17
|
+
//
|
|
18
|
+
//
|
|
19
|
+
// Otherwise, generate a random instance name and path
|
|
20
|
+
// and create a new database instance
|
|
21
|
+
const instanceName = generateRandomString({ type: 'alphabetic' });
|
|
22
|
+
const instancePath = `/tmp/${instanceName}.db`;
|
|
23
|
+
const db = SQLiteWriter.createDatabase(instancePath);
|
|
24
|
+
super(db, instanceName, params);
|
|
25
|
+
this.instanceName = instanceName;
|
|
26
|
+
this.instancePath = instancePath;
|
|
27
|
+
}
|
|
28
|
+
//
|
|
29
|
+
// Methods
|
|
30
|
+
static createDatabase(path) {
|
|
31
|
+
//
|
|
32
|
+
// Set up the database
|
|
33
|
+
const db = new BSQLite3(path);
|
|
34
|
+
db.pragma('journal_mode = WAL');
|
|
35
|
+
db.pragma('synchronous = OFF');
|
|
36
|
+
db.pragma('temp_store = MEMORY');
|
|
37
|
+
//
|
|
38
|
+
// Return the database
|
|
39
|
+
return db;
|
|
40
|
+
}
|
|
41
|
+
}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { type Database } from 'better-sqlite3';
|
|
2
|
+
export interface SQLiteDatabaseConfig {
|
|
3
|
+
/**
|
|
4
|
+
* The BetterSQLite3 database instance to use.
|
|
5
|
+
* If not provided, a temporary database will be created.
|
|
6
|
+
*/
|
|
7
|
+
databaseInstance?: Database;
|
|
8
|
+
/**
|
|
9
|
+
* Optional custom instance name.
|
|
10
|
+
* If not provided, a random name will be generated.
|
|
11
|
+
*/
|
|
12
|
+
instanceName?: string;
|
|
13
|
+
/**
|
|
14
|
+
* Optional custom database file path.
|
|
15
|
+
* If not provided, a temporary file path will be generated.
|
|
16
|
+
*/
|
|
17
|
+
instancePath?: string;
|
|
18
|
+
/**
|
|
19
|
+
* If true, the database will be created in memory.
|
|
20
|
+
* Defaults to false.
|
|
21
|
+
* Note: If using in-memory, data will be lost when the process exits.
|
|
22
|
+
* Also, multiple instances will not share the same data.
|
|
23
|
+
* Use only for testing or ephemeral data storage.
|
|
24
|
+
* If true, instancePath is ignored.
|
|
25
|
+
* @default false
|
|
26
|
+
*/
|
|
27
|
+
memory?: boolean;
|
|
28
|
+
}
|
|
29
|
+
export interface SQLiteColumn<T> {
|
|
30
|
+
indexed?: boolean;
|
|
31
|
+
name: Extract<keyof T, string>;
|
|
32
|
+
not_null?: boolean;
|
|
33
|
+
primary_key?: boolean;
|
|
34
|
+
type: 'BLOB' | 'BOOLEAN' | 'INTEGER' | 'REAL' | 'TEXT';
|
|
35
|
+
}
|
|
36
|
+
export interface SQLiteTable<T> {
|
|
37
|
+
/**
|
|
38
|
+
* The maximum number of items to hold in memory
|
|
39
|
+
* before flushing to the database.
|
|
40
|
+
* @default 3000
|
|
41
|
+
*/
|
|
42
|
+
batch_size?: number;
|
|
43
|
+
/**
|
|
44
|
+
* Columns in the table.
|
|
45
|
+
* Order matters for INSERT.
|
|
46
|
+
* Must be keys of T or custom names.
|
|
47
|
+
*/
|
|
48
|
+
columns: SQLiteColumn<T>[];
|
|
49
|
+
}
|
package/dist/types.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@tmlmobilidade/sqlite",
|
|
3
|
+
"version": "20251202.1817.5",
|
|
4
|
+
"author": {
|
|
5
|
+
"email": "iso@tmlmobilidade.pt",
|
|
6
|
+
"name": "TML-ISO"
|
|
7
|
+
},
|
|
8
|
+
"license": "AGPL-3.0-or-later",
|
|
9
|
+
"homepage": "https://github.com/tmlmobilidade/go#readme",
|
|
10
|
+
"bugs": {
|
|
11
|
+
"url": "https://github.com/tmlmobilidade/go/issues"
|
|
12
|
+
},
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "git+https://github.com/tmlmobilidade/go.git"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"public transit",
|
|
19
|
+
"tml",
|
|
20
|
+
"transportes metropolitanos de lisboa",
|
|
21
|
+
"go"
|
|
22
|
+
],
|
|
23
|
+
"publishConfig": {
|
|
24
|
+
"access": "public"
|
|
25
|
+
},
|
|
26
|
+
"type": "module",
|
|
27
|
+
"files": [
|
|
28
|
+
"dist"
|
|
29
|
+
],
|
|
30
|
+
"main": "./dist/index.js",
|
|
31
|
+
"types": "./dist/index.d.ts",
|
|
32
|
+
"scripts": {
|
|
33
|
+
"build": "tsc && resolve-tspaths",
|
|
34
|
+
"lint": "eslint ./src/ && tsc --noEmit",
|
|
35
|
+
"lint:fix": "eslint ./src/ --fix",
|
|
36
|
+
"watch": "tsc-watch --onSuccess 'resolve-tspaths'"
|
|
37
|
+
},
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"@tmlmobilidade/strings": "*",
|
|
40
|
+
"better-sqlite3": "12.5.0"
|
|
41
|
+
},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"@tmlmobilidade/tsconfig": "*",
|
|
44
|
+
"@types/better-sqlite3": "7.6.13",
|
|
45
|
+
"@types/node": "24.10.1",
|
|
46
|
+
"resolve-tspaths": "0.8.23",
|
|
47
|
+
"tsc-watch": "7.2.0",
|
|
48
|
+
"typescript": "5.9.3"
|
|
49
|
+
}
|
|
50
|
+
}
|