@rawsql-ts/testkit-sqlite 1.0.1
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/README.md +67 -0
- package/dist/cli/generateSchema.d.ts +1 -0
- package/dist/cli/generateSchema.js +244 -0
- package/dist/cli/generateSchema.js.map +1 -0
- package/dist/driver/SqliteSelectTestDriver.d.ts +46 -0
- package/dist/driver/SqliteSelectTestDriver.js +130 -0
- package/dist/driver/SqliteSelectTestDriver.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/dist/proxy/wrapSqliteDriver.d.ts +23 -0
- package/dist/proxy/wrapSqliteDriver.js +141 -0
- package/dist/proxy/wrapSqliteDriver.js.map +1 -0
- package/dist/types/index.d.ts +40 -0
- package/dist/types/index.js +3 -0
- package/dist/types/index.js.map +1 -0
- package/package.json +51 -0
package/README.md
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# @rawsql-ts/testkit-sqlite
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+

|
|
5
|
+
|
|
6
|
+
SQLite driver adapter for running repository tests entirely in-memory by shadowing tables with fixture-backed CTEs. Built on `@rawsql-ts/testkit-core` for schema validation and SQL rewrites.
|
|
7
|
+
|
|
8
|
+
## Features
|
|
9
|
+
|
|
10
|
+
- In-memory testing with `better-sqlite3`
|
|
11
|
+
- Transparent query interception via `wrapSqliteDriver`
|
|
12
|
+
- Scenario-specific fixture overrides with `withFixtures`
|
|
13
|
+
- Schema registry support for consistent large test suites
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install @rawsql-ts/testkit-sqlite
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Quick Start
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
import Database from 'better-sqlite3';
|
|
25
|
+
import { createSqliteSelectTestDriver } from '@rawsql-ts/testkit-sqlite';
|
|
26
|
+
|
|
27
|
+
const driver = createSqliteSelectTestDriver({
|
|
28
|
+
connectionFactory: () => new Database(':memory:'),
|
|
29
|
+
fixtures: [
|
|
30
|
+
{
|
|
31
|
+
tableName: 'users',
|
|
32
|
+
rows: [{ id: 1, name: 'Alice', role: 'admin' }],
|
|
33
|
+
schema: { columns: { id: 'INTEGER', name: 'TEXT', role: 'TEXT' } },
|
|
34
|
+
},
|
|
35
|
+
],
|
|
36
|
+
missingFixtureStrategy: 'error',
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
const rows = await driver.query('SELECT * FROM users');
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Use `driver.withFixtures([...])` to derive a scoped driver with scenario-specific overrides, and `driver.close()` to dispose the connection when done.
|
|
43
|
+
|
|
44
|
+
## Wrapping an Existing Connection
|
|
45
|
+
|
|
46
|
+
`wrapSqliteDriver` turns any `better-sqlite3` connection into a transparent proxy that intercepts `prepare`, `exec`, `all`, `get`, and `run` — rewriting SELECT statements into fixture-backed CTEs while passing through everything else.
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
import Database from 'better-sqlite3';
|
|
50
|
+
import { wrapSqliteDriver } from '@rawsql-ts/testkit-sqlite';
|
|
51
|
+
|
|
52
|
+
const raw = new Database(':memory:');
|
|
53
|
+
const intercepted = wrapSqliteDriver(raw, {
|
|
54
|
+
fixtures: [
|
|
55
|
+
{ tableName: 'orders', rows: [{ id: 1 }], schema: { columns: { id: 'INTEGER' } } },
|
|
56
|
+
],
|
|
57
|
+
missingFixtureStrategy: 'warn',
|
|
58
|
+
recordQueries: true,
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
intercepted.prepare('SELECT * FROM orders').all();
|
|
62
|
+
console.log(intercepted.queries); // inspect emitted SQL
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## License
|
|
66
|
+
|
|
67
|
+
MIT
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
const node_fs_1 = require("node:fs");
|
|
37
|
+
const node_path_1 = require("node:path");
|
|
38
|
+
const rawsql_ts_1 = require("rawsql-ts");
|
|
39
|
+
const DEFAULT_OUTPUT = 'schema.json';
|
|
40
|
+
/**
|
|
41
|
+
* Entry point that parses CLI arguments, builds the SQLite schema map, and writes the output.
|
|
42
|
+
*/
|
|
43
|
+
async function main() {
|
|
44
|
+
var _a, _b;
|
|
45
|
+
// Normalize CLI paths to keep behavior consistent regardless of the caller's location.
|
|
46
|
+
const options = parseArgs(process.argv.slice(2));
|
|
47
|
+
const resolvedDatabase = (0, node_path_1.resolve)(process.cwd(), options.database);
|
|
48
|
+
const schema = await buildSchema(resolvedDatabase, options.tables);
|
|
49
|
+
if (options.perTable) {
|
|
50
|
+
const outputDir = (0, node_path_1.resolve)(process.cwd(), (_a = options.output) !== null && _a !== void 0 ? _a : 'schema');
|
|
51
|
+
writeSchemaPerTable(outputDir, schema);
|
|
52
|
+
console.log(`Saved ${Object.keys(schema).length} tables as individual JSON files in ${outputDir}`);
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
const resolvedOutput = (0, node_path_1.resolve)(process.cwd(), (_b = options.output) !== null && _b !== void 0 ? _b : DEFAULT_OUTPUT);
|
|
56
|
+
writeSchema(resolvedOutput, schema);
|
|
57
|
+
console.log(`Saved schema for ${Object.keys(schema).length} tables to ${resolvedOutput}`);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Parses the CLI arguments consumed by `pnpm schema:generate`.
|
|
61
|
+
* @param rawArgs - Raw argument tokens provided by the caller.
|
|
62
|
+
* @returns The normalized CLI options object.
|
|
63
|
+
*/
|
|
64
|
+
function parseArgs(rawArgs) {
|
|
65
|
+
const options = {};
|
|
66
|
+
// Walk through the raw arguments and stash values for recognized flags.
|
|
67
|
+
for (let i = 0; i < rawArgs.length; i += 1) {
|
|
68
|
+
const arg = rawArgs[i];
|
|
69
|
+
if (arg === '--help' || arg === '-h') {
|
|
70
|
+
printUsage();
|
|
71
|
+
process.exit(0);
|
|
72
|
+
}
|
|
73
|
+
if (arg === '--database' || arg === '-d') {
|
|
74
|
+
options.database = rawArgs[++i];
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
if (arg === '--per-table') {
|
|
78
|
+
options.perTable = true;
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
if (arg === '--output' || arg === '-o') {
|
|
82
|
+
options.output = rawArgs[++i];
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
if (arg === '--tables' || arg === '-t') {
|
|
86
|
+
const value = rawArgs[++i];
|
|
87
|
+
options.tables = value
|
|
88
|
+
.split(',')
|
|
89
|
+
.map((segment) => segment.trim())
|
|
90
|
+
.filter((segment) => segment.length > 0);
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
throw new Error(`Unknown option "${arg}". Run with --help for usage.`);
|
|
94
|
+
}
|
|
95
|
+
if (!options.database) {
|
|
96
|
+
throw new Error('Missing --database argument.');
|
|
97
|
+
}
|
|
98
|
+
return {
|
|
99
|
+
database: options.database,
|
|
100
|
+
output: options.output,
|
|
101
|
+
tables: options.tables,
|
|
102
|
+
perTable: options.perTable,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Reads CREATE TABLE definitions from the SQLite master table and accumulates parsed column metadata.
|
|
107
|
+
* @param databasePath - Absolute path to the SQLite database file.
|
|
108
|
+
* @param filters - Optional list of lower-cased table names to include.
|
|
109
|
+
* @returns A mapping from normalized table names to schema definitions.
|
|
110
|
+
*/
|
|
111
|
+
async function buildSchema(databasePath, filters) {
|
|
112
|
+
var _a;
|
|
113
|
+
// Dynamically import better-sqlite3 so we can surface a clear error when it is missing.
|
|
114
|
+
const betterSqliteModule = await Promise.resolve().then(() => __importStar(require('better-sqlite3')));
|
|
115
|
+
const BetterSqlite = ((_a = betterSqliteModule.default) !== null && _a !== void 0 ? _a : betterSqliteModule);
|
|
116
|
+
const connection = new BetterSqlite(databasePath, { readonly: true, fileMustExist: true });
|
|
117
|
+
const whitelist = filters ? new Set(filters.map((name) => name.toLowerCase())) : null;
|
|
118
|
+
const schema = {};
|
|
119
|
+
try {
|
|
120
|
+
const rows = connection
|
|
121
|
+
.prepare("SELECT name, sql FROM sqlite_master WHERE type = 'table' AND name NOT LIKE 'sqlite_%' ORDER BY name")
|
|
122
|
+
.all();
|
|
123
|
+
// Iterate through every table definition exposed by sqlite_master.
|
|
124
|
+
for (const row of rows) {
|
|
125
|
+
const normalizedName = row.name.toLowerCase();
|
|
126
|
+
if (whitelist && !whitelist.has(normalizedName)) {
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
if (!row.sql) {
|
|
130
|
+
// SQLite may omit the CREATE text for virtual or internal structures, so skip those entries.
|
|
131
|
+
console.warn(`Skipping table "${row.name}" because no CREATE statement could be read.`);
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
try {
|
|
135
|
+
const parsed = rawsql_ts_1.SqlParser.parse(row.sql);
|
|
136
|
+
// Guard against other statements so the schema generator stays focused on CREATE TABLE definitions.
|
|
137
|
+
if (!isCreateTableStatement(parsed)) {
|
|
138
|
+
console.warn(`Skipping "${row.name}" because the parser emitted a non-CREATE TABLE statement.`);
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
const createTable = parsed;
|
|
142
|
+
if (createTable.columns.length === 0) {
|
|
143
|
+
console.warn(`Skipping "${row.name}" because the CREATE TABLE statement does not expose columns.`);
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
schema[normalizedName] = {
|
|
147
|
+
columns: Object.fromEntries(createTable.columns.map((column) => [
|
|
148
|
+
column.name.name,
|
|
149
|
+
getDeclaredType(column.dataType),
|
|
150
|
+
])),
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
catch (error) {
|
|
154
|
+
console.warn(`Failed to parse table "${row.name}": ${error.message}`);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
finally {
|
|
159
|
+
connection.close();
|
|
160
|
+
}
|
|
161
|
+
if (Object.keys(schema).length === 0) {
|
|
162
|
+
throw new Error('No tables were included in the generated schema.');
|
|
163
|
+
}
|
|
164
|
+
return schema;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Serializes the schema map to the specified JSON file, sorting the tables for deterministic output.
|
|
168
|
+
* @param outputPath - Destination path for the schema JSON document.
|
|
169
|
+
* @param schema - Table schema definitions to persist.
|
|
170
|
+
*/
|
|
171
|
+
function writeSchema(outputPath, schema) {
|
|
172
|
+
// Sort table entries to keep the generated JSON deterministic.
|
|
173
|
+
const ordered = {};
|
|
174
|
+
Object.keys(schema)
|
|
175
|
+
.sort()
|
|
176
|
+
.forEach((name) => {
|
|
177
|
+
ordered[name] = schema[name];
|
|
178
|
+
});
|
|
179
|
+
const directory = (0, node_path_1.dirname)(outputPath);
|
|
180
|
+
// Ensure the destination folder exists before writing.
|
|
181
|
+
(0, node_fs_1.mkdirSync)(directory, { recursive: true });
|
|
182
|
+
(0, node_fs_1.writeFileSync)(outputPath, `${JSON.stringify(ordered, null, 2)}\n`, 'utf8');
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Emits one JSON file per table schema so downstream diffs can focus on individual tables.
|
|
186
|
+
* @param directory - Directory to persist the per-table JSON artifacts.
|
|
187
|
+
* @param schema - Table schema definitions to emit individually.
|
|
188
|
+
*/
|
|
189
|
+
function writeSchemaPerTable(directory, schema) {
|
|
190
|
+
(0, node_fs_1.mkdirSync)(directory, { recursive: true });
|
|
191
|
+
// Persist each table schema inside its own JSON file for easier diffs.
|
|
192
|
+
for (const [tableName, definition] of Object.entries(schema)) {
|
|
193
|
+
const fileName = `${encodeURIComponent(tableName)}.json`;
|
|
194
|
+
const filePath = (0, node_path_1.resolve)(directory, fileName);
|
|
195
|
+
(0, node_fs_1.writeFileSync)(filePath, `${JSON.stringify({ [tableName]: definition }, null, 2)}\n`, 'utf8');
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Guards on CREATE TABLE statements and filters out any other parsed SQL nodes.
|
|
200
|
+
* @param statement - The AST node emitted by the parser.
|
|
201
|
+
*/
|
|
202
|
+
function isCreateTableStatement(statement) {
|
|
203
|
+
return statement.getKind() === rawsql_ts_1.CreateTableQuery.kind;
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Retrieves the declared type name from the parser metadata, falling back to literal tokens when necessary.
|
|
207
|
+
* @param dataType - AST node describing the column's declared type.
|
|
208
|
+
* @returns The original type text or an empty string when unavailable.
|
|
209
|
+
*/
|
|
210
|
+
function getDeclaredType(dataType) {
|
|
211
|
+
if (!dataType) {
|
|
212
|
+
return '';
|
|
213
|
+
}
|
|
214
|
+
// Prefer the parser's helper when it exposes the declarative type text.
|
|
215
|
+
if ('getTypeName' in dataType && typeof dataType.getTypeName === 'function') {
|
|
216
|
+
return dataType.getTypeName().trim();
|
|
217
|
+
}
|
|
218
|
+
// Fall back to direct literal values for simple AST nodes.
|
|
219
|
+
if ('value' in dataType && typeof dataType.value === 'string') {
|
|
220
|
+
return dataType.value.trim();
|
|
221
|
+
}
|
|
222
|
+
return '';
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Prints the human-friendly CLI usage instructions and exits the process.
|
|
226
|
+
*/
|
|
227
|
+
function printUsage() {
|
|
228
|
+
console.log(`
|
|
229
|
+
Usage:
|
|
230
|
+
pnpm --filter @rawsql-ts/testkit-sqlite run schema:generate -- --database <path> [--output <path>] [--tables <names>]
|
|
231
|
+
|
|
232
|
+
Options:
|
|
233
|
+
--per-table Emit per-table JSON files instead of a single schema.json (output path becomes a directory).
|
|
234
|
+
--database, -d <path> SQLite database file that hosts the CREATE TABLE statements.
|
|
235
|
+
--output, -o <path> Path to write schema.json (defaults to schema.json in the current directory).
|
|
236
|
+
--tables, -t <names> Comma-separated list of table names to include (case-insensitive).
|
|
237
|
+
--help, -h Show this message.
|
|
238
|
+
`);
|
|
239
|
+
}
|
|
240
|
+
void main().catch((error) => {
|
|
241
|
+
console.error('Schema generation failed:', error.message);
|
|
242
|
+
process.exitCode = 1;
|
|
243
|
+
});
|
|
244
|
+
//# sourceMappingURL=generateSchema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generateSchema.js","sourceRoot":"","sources":["../../src/cli/generateSchema.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,qCAAmD;AACnD,yCAA6C;AAE7C,yCAOmB;AAEnB,MAAM,cAAc,GAAG,aAAa,CAAC;AA0BrC;;GAEG;AACH,KAAK,UAAU,IAAI;;IACjB,uFAAuF;IACvF,MAAM,OAAO,GAAG,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IACjD,MAAM,gBAAgB,GAAG,IAAA,mBAAO,EAAC,OAAO,CAAC,GAAG,EAAE,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;IAClE,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,gBAAgB,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;IAEnE,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;QACrB,MAAM,SAAS,GAAG,IAAA,mBAAO,EAAC,OAAO,CAAC,GAAG,EAAE,EAAE,MAAA,OAAO,CAAC,MAAM,mCAAI,QAAQ,CAAC,CAAC;QACrE,mBAAmB,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;QACvC,OAAO,CAAC,GAAG,CAAC,SAAS,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,uCAAuC,SAAS,EAAE,CAAC,CAAC;QACnG,OAAO;IACT,CAAC;IAED,MAAM,cAAc,GAAG,IAAA,mBAAO,EAAC,OAAO,CAAC,GAAG,EAAE,EAAE,MAAA,OAAO,CAAC,MAAM,mCAAI,cAAc,CAAC,CAAC;IAChF,WAAW,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC;IACpC,OAAO,CAAC,GAAG,CAAC,oBAAoB,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,cAAc,cAAc,EAAE,CAAC,CAAC;AAC5F,CAAC;AAED;;;;GAIG;AACH,SAAS,SAAS,CAAC,OAAiB;IAClC,MAAM,OAAO,GAAwB,EAAE,CAAC;IACxC,wEAAwE;IACxE,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QAC3C,MAAM,GAAG,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;QACvB,IAAI,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;YACrC,UAAU,EAAE,CAAC;YACb,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QACD,IAAI,GAAG,KAAK,YAAY,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;YACzC,OAAO,CAAC,QAAQ,GAAG,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;YAChC,SAAS;QACX,CAAC;QACD,IAAI,GAAG,KAAK,aAAa,EAAE,CAAC;YAC1B,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;YACxB,SAAS;QACX,CAAC;QACD,IAAI,GAAG,KAAK,UAAU,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;YACvC,OAAO,CAAC,MAAM,GAAG,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;YAC9B,SAAS;QACX,CAAC;QACD,IAAI,GAAG,KAAK,UAAU,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;YACvC,MAAM,KAAK,GAAG,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;YAC3B,OAAO,CAAC,MAAM,GAAG,KAAK;iBACnB,KAAK,CAAC,GAAG,CAAC;iBACV,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;iBAChC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;YAC3C,SAAS;QACX,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,mBAAmB,GAAG,+BAA+B,CAAC,CAAC;IACzE,CAAC;IAED,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;IAClD,CAAC;IAED,OAAO;QACL,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,QAAQ,EAAE,OAAO,CAAC,QAAQ;KAC3B,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,KAAK,UAAU,WAAW,CAAC,YAAoB,EAAE,OAAkB;;IACjE,wFAAwF;IACxF,MAAM,kBAAkB,GAAG,wDAAa,gBAAgB,GAAC,CAAC;IAC1D,MAAM,YAAY,GAAG,CAAC,MAAA,kBAAkB,CAAC,OAAO,mCAAI,kBAAkB,CAA4B,CAAC;IACnG,MAAM,UAAU,GAAG,IAAI,YAAY,CAAC,YAAY,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3F,MAAM,SAAS,GAAG,OAAO,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACtF,MAAM,MAAM,GAA0C,EAAE,CAAC;IAEzD,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,UAAU;aACpB,OAAO,CAAC,qGAAqG,CAAC;aAC9G,GAAG,EAAuB,CAAC;QAE9B,mEAAmE;QACnE,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,MAAM,cAAc,GAAG,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;YAC9C,IAAI,SAAS,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,cAAc,CAAC,EAAE,CAAC;gBAChD,SAAS;YACX,CAAC;YAED,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC;gBACb,6FAA6F;gBAC7F,OAAO,CAAC,IAAI,CAAC,mBAAmB,GAAG,CAAC,IAAI,8CAA8C,CAAC,CAAC;gBACxF,SAAS;YACX,CAAC;YAED,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,qBAAS,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;gBACxC,oGAAoG;gBACpG,IAAI,CAAC,sBAAsB,CAAC,MAAM,CAAC,EAAE,CAAC;oBACpC,OAAO,CAAC,IAAI,CAAC,aAAa,GAAG,CAAC,IAAI,4DAA4D,CAAC,CAAC;oBAChG,SAAS;gBACX,CAAC;gBAED,MAAM,WAAW,GAAG,MAAM,CAAC;gBAC3B,IAAI,WAAW,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;oBACrC,OAAO,CAAC,IAAI,CAAC,aAAa,GAAG,CAAC,IAAI,+DAA+D,CAAC,CAAC;oBACnG,SAAS;gBACX,CAAC;gBAED,MAAM,CAAC,cAAc,CAAC,GAAG;oBACvB,OAAO,EAAE,MAAM,CAAC,WAAW,CACzB,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAA6B,EAAE,EAAE,CAAC;wBACzD,MAAM,CAAC,IAAI,CAAC,IAAI;wBAChB,eAAe,CAAC,MAAM,CAAC,QAAQ,CAAC;qBACjC,CAAC,CACH;iBACF,CAAC;YACJ,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,OAAO,CAAC,IAAI,CAAC,0BAA0B,GAAG,CAAC,IAAI,MAAO,KAAe,CAAC,OAAO,EAAE,CAAC,CAAC;YACnF,CAAC;QACH,CAAC;IACH,CAAC;YAAS,CAAC;QACT,UAAU,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC;IAED,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACrC,MAAM,IAAI,KAAK,CAAC,kDAAkD,CAAC,CAAC;IACtE,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;GAIG;AACH,SAAS,WAAW,CAAC,UAAkB,EAAE,MAA6C;IACpF,+DAA+D;IAC/D,MAAM,OAAO,GAA0C,EAAE,CAAC;IAC1D,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC;SAChB,IAAI,EAAE;SACN,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;QAChB,OAAO,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;IAC/B,CAAC,CAAC,CAAC;IAEL,MAAM,SAAS,GAAG,IAAA,mBAAO,EAAC,UAAU,CAAC,CAAC;IACtC,uDAAuD;IACvD,IAAA,mBAAS,EAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1C,IAAA,uBAAa,EAAC,UAAU,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;AAC7E,CAAC;AAED;;;;GAIG;AACH,SAAS,mBAAmB,CAAC,SAAiB,EAAE,MAA6C;IAC3F,IAAA,mBAAS,EAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1C,uEAAuE;IACvE,KAAK,MAAM,CAAC,SAAS,EAAE,UAAU,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAC7D,MAAM,QAAQ,GAAG,GAAG,kBAAkB,CAAC,SAAS,CAAC,OAAO,CAAC;QACzD,MAAM,QAAQ,GAAG,IAAA,mBAAO,EAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;QAC9C,IAAA,uBAAa,EAAC,QAAQ,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,UAAU,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAC/F,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,SAAS,sBAAsB,CAAC,SAA0B;IACxD,OAAO,SAAS,CAAC,OAAO,EAAE,KAAK,4BAAgB,CAAC,IAAI,CAAC;AACvD,CAAC;AAED;;;;GAIG;AACH,SAAS,eAAe,CAAC,QAAuC;IAC9D,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,wEAAwE;IACxE,IAAI,aAAa,IAAI,QAAQ,IAAI,OAAO,QAAQ,CAAC,WAAW,KAAK,UAAU,EAAE,CAAC;QAC5E,OAAO,QAAQ,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC;IACvC,CAAC;IAED,2DAA2D;IAC3D,IAAI,OAAO,IAAI,QAAQ,IAAI,OAAO,QAAQ,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9D,OAAO,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;IAC/B,CAAC;IAED,OAAO,EAAE,CAAC;AACZ,CAAC;AAED;;GAEG;AACH,SAAS,UAAU;IACjB,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;GAUX,CAAC,CAAC;AACL,CAAC;AAED,KAAK,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IAC1B,OAAO,CAAC,KAAK,CAAC,2BAA2B,EAAG,KAAe,CAAC,OAAO,CAAC,CAAC;IACrE,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;AACvB,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { TableFixture } from '@rawsql-ts/testkit-core';
|
|
2
|
+
import type { CreateSqliteSelectTestDriverOptions, SqliteConnectionLike, SqliteSelectTestDriver } from '../types';
|
|
3
|
+
export type QueryParams = unknown[] | Record<string, unknown> | undefined;
|
|
4
|
+
/**
|
|
5
|
+
* Concrete {@link SqliteSelectTestDriver} implementation that rewrites fixtures
|
|
6
|
+
* before delegating to the underlying SQLite connection.
|
|
7
|
+
*/
|
|
8
|
+
export declare class SqliteSelectTestDriverImpl implements SqliteSelectTestDriver {
|
|
9
|
+
private readonly options;
|
|
10
|
+
private readonly scopedFixtures?;
|
|
11
|
+
private connection?;
|
|
12
|
+
private readonly rewriter;
|
|
13
|
+
constructor(options: CreateSqliteSelectTestDriverOptions, scopedFixtures?: TableFixture[] | undefined, seedConnection?: SqliteConnectionLike);
|
|
14
|
+
query<T = unknown>(sql: string, params?: QueryParams): Promise<T[]>;
|
|
15
|
+
withFixtures(fixtures: TableFixture[]): SqliteSelectTestDriver;
|
|
16
|
+
close(): void;
|
|
17
|
+
private getConnection;
|
|
18
|
+
private execute;
|
|
19
|
+
private runStatement;
|
|
20
|
+
private invokeConnectionMethod;
|
|
21
|
+
private normalizeParams;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Creates a lightweight SQLite test driver that injects fixture-backed CTEs before delegating to the real driver.
|
|
25
|
+
* @param options Driver options that provide the connection factory plus rewrite behavior inherited from testkit-core.
|
|
26
|
+
* @returns An implementation that exposes `query`, `withFixtures`, and `close` helpers for SELECT-first tests.
|
|
27
|
+
* @example
|
|
28
|
+
* ```ts
|
|
29
|
+
* import Database from 'better-sqlite3';
|
|
30
|
+
* import { createSqliteSelectTestDriver } from '@rawsql-ts/testkit-sqlite';
|
|
31
|
+
*
|
|
32
|
+
* const driver = createSqliteSelectTestDriver({
|
|
33
|
+
* connectionFactory: () => new Database(':memory:'),
|
|
34
|
+
* fixtures: [
|
|
35
|
+
* {
|
|
36
|
+
* tableName: 'users',
|
|
37
|
+
* rows: [{ id: 1, email: 'demo@example.com' }],
|
|
38
|
+
* },
|
|
39
|
+
* ],
|
|
40
|
+
* });
|
|
41
|
+
*
|
|
42
|
+
* const rows = await driver.query('SELECT id, email FROM users');
|
|
43
|
+
* console.log(rows);
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export declare const createSqliteSelectTestDriver: (options: CreateSqliteSelectTestDriverOptions) => SqliteSelectTestDriver;
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createSqliteSelectTestDriver = exports.SqliteSelectTestDriverImpl = void 0;
|
|
4
|
+
const testkit_core_1 = require("@rawsql-ts/testkit-core");
|
|
5
|
+
/**
|
|
6
|
+
* Concrete {@link SqliteSelectTestDriver} implementation that rewrites fixtures
|
|
7
|
+
* before delegating to the underlying SQLite connection.
|
|
8
|
+
*/
|
|
9
|
+
class SqliteSelectTestDriverImpl {
|
|
10
|
+
constructor(options, scopedFixtures, seedConnection) {
|
|
11
|
+
this.options = options;
|
|
12
|
+
this.scopedFixtures = scopedFixtures;
|
|
13
|
+
this.rewriter = new testkit_core_1.SelectFixtureRewriter(options);
|
|
14
|
+
this.connection = seedConnection;
|
|
15
|
+
}
|
|
16
|
+
async query(sql, params) {
|
|
17
|
+
// Rewrite the incoming SQL so fixture-backed CTEs shadow physical tables.
|
|
18
|
+
const context = this.scopedFixtures ? { fixtures: this.scopedFixtures } : undefined;
|
|
19
|
+
const rewritten = this.rewriter.rewrite(sql, context);
|
|
20
|
+
// Execute the rewritten SQL via the configured driver surface.
|
|
21
|
+
const rows = this.execute(rewritten.sql, params);
|
|
22
|
+
return Promise.resolve(rows);
|
|
23
|
+
}
|
|
24
|
+
withFixtures(fixtures) {
|
|
25
|
+
// Pass along the current connection so scoped drivers reuse the same DB handle.
|
|
26
|
+
const next = new SqliteSelectTestDriverImpl(this.options, fixtures, this.connection);
|
|
27
|
+
return next;
|
|
28
|
+
}
|
|
29
|
+
close() {
|
|
30
|
+
if (this.connection && typeof this.connection.close === 'function') {
|
|
31
|
+
// Allow upstream driver to dispose any native handles.
|
|
32
|
+
this.connection.close();
|
|
33
|
+
this.connection = undefined;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
getConnection() {
|
|
37
|
+
if (!this.connection) {
|
|
38
|
+
// Lazily hydrate the driver so tests can swap factories per suite.
|
|
39
|
+
this.connection = this.options.connectionFactory();
|
|
40
|
+
}
|
|
41
|
+
return this.connection;
|
|
42
|
+
}
|
|
43
|
+
execute(sql, params) {
|
|
44
|
+
const connection = this.getConnection();
|
|
45
|
+
// Prefer prepared statements when the driver exposes them.
|
|
46
|
+
if (typeof connection.prepare === 'function') {
|
|
47
|
+
const statement = connection.prepare(sql);
|
|
48
|
+
if (statement) {
|
|
49
|
+
return this.runStatement(statement, params);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
// Fall back to high-level helpers such as db.all(sql, params).
|
|
53
|
+
if (typeof connection.all === 'function') {
|
|
54
|
+
const rows = this.invokeConnectionMethod(connection.all, connection, sql, params);
|
|
55
|
+
return rows !== null && rows !== void 0 ? rows : [];
|
|
56
|
+
}
|
|
57
|
+
if (typeof connection.get === 'function') {
|
|
58
|
+
const record = this.invokeConnectionMethod(connection.get, connection, sql, params);
|
|
59
|
+
return record ? [record] : [];
|
|
60
|
+
}
|
|
61
|
+
if (typeof connection.run === 'function') {
|
|
62
|
+
this.invokeConnectionMethod(connection.run, connection, sql, params);
|
|
63
|
+
return [];
|
|
64
|
+
}
|
|
65
|
+
throw new Error('SQLite connection does not expose prepare/all/get/run methods.');
|
|
66
|
+
}
|
|
67
|
+
runStatement(statement, params) {
|
|
68
|
+
const args = this.normalizeParams(params);
|
|
69
|
+
// Leverage the strongest method the statement exposes.
|
|
70
|
+
if (typeof statement.all === 'function') {
|
|
71
|
+
const rows = statement.all(...args);
|
|
72
|
+
return rows !== null && rows !== void 0 ? rows : [];
|
|
73
|
+
}
|
|
74
|
+
if (typeof statement.get === 'function') {
|
|
75
|
+
const record = statement.get(...args);
|
|
76
|
+
return record ? [record] : [];
|
|
77
|
+
}
|
|
78
|
+
if (typeof statement.run === 'function') {
|
|
79
|
+
statement.run(...args);
|
|
80
|
+
return [];
|
|
81
|
+
}
|
|
82
|
+
throw new Error('Prepared statement does not expose all/get/run helpers.');
|
|
83
|
+
}
|
|
84
|
+
invokeConnectionMethod(method, connection, sql, params) {
|
|
85
|
+
// Normalize params once so every driver helper sees the same calling convention.
|
|
86
|
+
const args = this.normalizeParams(params);
|
|
87
|
+
if (args.length === 0) {
|
|
88
|
+
return method.call(connection, sql);
|
|
89
|
+
}
|
|
90
|
+
return method.call(connection, sql, ...args);
|
|
91
|
+
}
|
|
92
|
+
normalizeParams(params) {
|
|
93
|
+
if (!params) {
|
|
94
|
+
return [];
|
|
95
|
+
}
|
|
96
|
+
if (Array.isArray(params)) {
|
|
97
|
+
return params;
|
|
98
|
+
}
|
|
99
|
+
return [params];
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
exports.SqliteSelectTestDriverImpl = SqliteSelectTestDriverImpl;
|
|
103
|
+
/**
|
|
104
|
+
* Creates a lightweight SQLite test driver that injects fixture-backed CTEs before delegating to the real driver.
|
|
105
|
+
* @param options Driver options that provide the connection factory plus rewrite behavior inherited from testkit-core.
|
|
106
|
+
* @returns An implementation that exposes `query`, `withFixtures`, and `close` helpers for SELECT-first tests.
|
|
107
|
+
* @example
|
|
108
|
+
* ```ts
|
|
109
|
+
* import Database from 'better-sqlite3';
|
|
110
|
+
* import { createSqliteSelectTestDriver } from '@rawsql-ts/testkit-sqlite';
|
|
111
|
+
*
|
|
112
|
+
* const driver = createSqliteSelectTestDriver({
|
|
113
|
+
* connectionFactory: () => new Database(':memory:'),
|
|
114
|
+
* fixtures: [
|
|
115
|
+
* {
|
|
116
|
+
* tableName: 'users',
|
|
117
|
+
* rows: [{ id: 1, email: 'demo@example.com' }],
|
|
118
|
+
* },
|
|
119
|
+
* ],
|
|
120
|
+
* });
|
|
121
|
+
*
|
|
122
|
+
* const rows = await driver.query('SELECT id, email FROM users');
|
|
123
|
+
* console.log(rows);
|
|
124
|
+
* ```
|
|
125
|
+
*/
|
|
126
|
+
const createSqliteSelectTestDriver = (options) => {
|
|
127
|
+
return new SqliteSelectTestDriverImpl(options);
|
|
128
|
+
};
|
|
129
|
+
exports.createSqliteSelectTestDriver = createSqliteSelectTestDriver;
|
|
130
|
+
//# sourceMappingURL=SqliteSelectTestDriver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SqliteSelectTestDriver.js","sourceRoot":"","sources":["../../src/driver/SqliteSelectTestDriver.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.wrapSqliteDriver = exports.createSqliteSelectTestDriver = void 0;
|
|
18
|
+
__exportStar(require("./types"), exports);
|
|
19
|
+
var SqliteSelectTestDriver_1 = require("./driver/SqliteSelectTestDriver");
|
|
20
|
+
Object.defineProperty(exports, "createSqliteSelectTestDriver", { enumerable: true, get: function () { return SqliteSelectTestDriver_1.createSqliteSelectTestDriver; } });
|
|
21
|
+
var wrapSqliteDriver_1 = require("./proxy/wrapSqliteDriver");
|
|
22
|
+
Object.defineProperty(exports, "wrapSqliteDriver", { enumerable: true, get: function () { return wrapSqliteDriver_1.wrapSqliteDriver; } });
|
|
23
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,0CAAwB;AACxB,0EAA+E;AAAtE,sIAAA,4BAA4B,OAAA;AACrC,6DAA4D;AAAnD,oHAAA,gBAAgB,OAAA"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { SqliteConnectionLike, WrapSqliteDriverOptions, WrappedSqliteDriver } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Wraps a SQLite connection so every SELECT/CTE statement is rewritten with fixture-backed CTEs before execution.
|
|
4
|
+
* @param driver Native connection (e.g. better-sqlite3, sqlite3) whose SELECT queries should honor rewrites.
|
|
5
|
+
* @param options Configuration that controls fixtures, rewrite strategy, execution hooks, and optional query logging.
|
|
6
|
+
* @returns A proxied driver that transparently rewrites queries, surfaces an optional `queries` log, and supports `withFixtures`.
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* import Database from 'better-sqlite3';
|
|
10
|
+
* import { wrapSqliteDriver } from '@rawsql-ts/testkit-sqlite';
|
|
11
|
+
*
|
|
12
|
+
* const db = wrapSqliteDriver(new Database(':memory:'), {
|
|
13
|
+
* fixtures: [
|
|
14
|
+
* { tableName: 'accounts', rows: [{ id: 42, tier: 'pro' }] },
|
|
15
|
+
* ],
|
|
16
|
+
* recordQueries: true,
|
|
17
|
+
* });
|
|
18
|
+
*
|
|
19
|
+
* const rows = db.all('SELECT id, tier FROM accounts');
|
|
20
|
+
* console.log(rows, db.queries);
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export declare const wrapSqliteDriver: <T extends SqliteConnectionLike>(driver: T, options: WrapSqliteDriverOptions) => WrappedSqliteDriver<T>;
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.wrapSqliteDriver = void 0;
|
|
4
|
+
const testkit_core_1 = require("@rawsql-ts/testkit-core");
|
|
5
|
+
const normalizeParams = (args) => {
|
|
6
|
+
if (args.length === 0) {
|
|
7
|
+
return undefined;
|
|
8
|
+
}
|
|
9
|
+
if (args.length === 1) {
|
|
10
|
+
return args[0];
|
|
11
|
+
}
|
|
12
|
+
return args;
|
|
13
|
+
};
|
|
14
|
+
const isSelectableQuery = (sql) => {
|
|
15
|
+
const trimmed = sql.trimStart();
|
|
16
|
+
if (trimmed.length === 0) {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
const upper = trimmed.toUpperCase();
|
|
20
|
+
if (upper.startsWith('SELECT') || upper.startsWith('WITH')) {
|
|
21
|
+
return true;
|
|
22
|
+
}
|
|
23
|
+
if (upper.startsWith('EXPLAIN')) {
|
|
24
|
+
return /\bSELECT\b/i.test(upper);
|
|
25
|
+
}
|
|
26
|
+
return false;
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Wraps a SQLite connection so every SELECT/CTE statement is rewritten with fixture-backed CTEs before execution.
|
|
30
|
+
* @param driver Native connection (e.g. better-sqlite3, sqlite3) whose SELECT queries should honor rewrites.
|
|
31
|
+
* @param options Configuration that controls fixtures, rewrite strategy, execution hooks, and optional query logging.
|
|
32
|
+
* @returns A proxied driver that transparently rewrites queries, surfaces an optional `queries` log, and supports `withFixtures`.
|
|
33
|
+
* @example
|
|
34
|
+
* ```ts
|
|
35
|
+
* import Database from 'better-sqlite3';
|
|
36
|
+
* import { wrapSqliteDriver } from '@rawsql-ts/testkit-sqlite';
|
|
37
|
+
*
|
|
38
|
+
* const db = wrapSqliteDriver(new Database(':memory:'), {
|
|
39
|
+
* fixtures: [
|
|
40
|
+
* { tableName: 'accounts', rows: [{ id: 42, tier: 'pro' }] },
|
|
41
|
+
* ],
|
|
42
|
+
* recordQueries: true,
|
|
43
|
+
* });
|
|
44
|
+
*
|
|
45
|
+
* const rows = db.all('SELECT id, tier FROM accounts');
|
|
46
|
+
* console.log(rows, db.queries);
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
const wrapSqliteDriver = (driver, options) => {
|
|
50
|
+
const rewriter = new testkit_core_1.SelectFixtureRewriter(options);
|
|
51
|
+
const buildProxy = (scopedFixtures) => {
|
|
52
|
+
const queryLog = options.recordQueries ? [] : undefined;
|
|
53
|
+
const shouldObserve = Boolean(options.onExecute || queryLog);
|
|
54
|
+
// Fan out execution details to the configured hook and optional in-memory log.
|
|
55
|
+
const handleExecution = (method, sql, args, fixtures) => {
|
|
56
|
+
var _a;
|
|
57
|
+
if (!shouldObserve) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
const params = normalizeParams(args);
|
|
61
|
+
(_a = options.onExecute) === null || _a === void 0 ? void 0 : _a.call(options, sql, params);
|
|
62
|
+
queryLog === null || queryLog === void 0 ? void 0 : queryLog.push({
|
|
63
|
+
method: typeof method === 'string' ? method : String(method),
|
|
64
|
+
sql,
|
|
65
|
+
params,
|
|
66
|
+
fixtures,
|
|
67
|
+
});
|
|
68
|
+
};
|
|
69
|
+
const wrapStatement = (statement, sql, fixtures) => {
|
|
70
|
+
if (!shouldObserve || !statement) {
|
|
71
|
+
return statement;
|
|
72
|
+
}
|
|
73
|
+
return new Proxy(statement, {
|
|
74
|
+
get(stmtTarget, stmtProp, stmtReceiver) {
|
|
75
|
+
const stmtValue = Reflect.get(stmtTarget, stmtProp, stmtReceiver);
|
|
76
|
+
if (typeof stmtValue !== 'function') {
|
|
77
|
+
return stmtValue;
|
|
78
|
+
}
|
|
79
|
+
if (stmtProp === 'all' || stmtProp === 'get' || stmtProp === 'run') {
|
|
80
|
+
return (...stmtArgs) => {
|
|
81
|
+
handleExecution(stmtProp, sql, stmtArgs, fixtures);
|
|
82
|
+
return stmtValue.apply(stmtTarget, stmtArgs);
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
return stmtValue.bind(stmtTarget);
|
|
86
|
+
},
|
|
87
|
+
});
|
|
88
|
+
};
|
|
89
|
+
return new Proxy(driver, {
|
|
90
|
+
get(target, prop, receiver) {
|
|
91
|
+
if (prop === 'withFixtures') {
|
|
92
|
+
return (fixtures) => buildProxy(fixtures);
|
|
93
|
+
}
|
|
94
|
+
if (prop === 'queries') {
|
|
95
|
+
return queryLog;
|
|
96
|
+
}
|
|
97
|
+
const value = Reflect.get(target, prop, receiver);
|
|
98
|
+
if (typeof value !== 'function') {
|
|
99
|
+
return value;
|
|
100
|
+
}
|
|
101
|
+
if (prop === 'prepare') {
|
|
102
|
+
return (sql, ...rest) => {
|
|
103
|
+
if (typeof sql !== 'string' || !isSelectableQuery(sql)) {
|
|
104
|
+
return value.apply(target, [sql, ...rest]);
|
|
105
|
+
}
|
|
106
|
+
const context = scopedFixtures ? { fixtures: scopedFixtures } : undefined;
|
|
107
|
+
const rewritten = rewriter.rewrite(sql, context);
|
|
108
|
+
const statement = value.apply(target, [rewritten.sql, ...rest]);
|
|
109
|
+
return wrapStatement(statement, rewritten.sql, rewritten.fixturesApplied);
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
if (prop === 'exec') {
|
|
113
|
+
return (sql, ...rest) => {
|
|
114
|
+
if (typeof sql !== 'string' || !isSelectableQuery(sql)) {
|
|
115
|
+
return value.apply(target, [sql, ...rest]);
|
|
116
|
+
}
|
|
117
|
+
const context = scopedFixtures ? { fixtures: scopedFixtures } : undefined;
|
|
118
|
+
const rewritten = rewriter.rewrite(sql, context);
|
|
119
|
+
handleExecution(prop, rewritten.sql, rest, rewritten.fixturesApplied);
|
|
120
|
+
return value.apply(target, [rewritten.sql, ...rest]);
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
if (prop === 'all' || prop === 'get' || prop === 'run') {
|
|
124
|
+
return (sql, ...rest) => {
|
|
125
|
+
if (typeof sql !== 'string' || !isSelectableQuery(sql)) {
|
|
126
|
+
return value.apply(target, [sql, ...rest]);
|
|
127
|
+
}
|
|
128
|
+
const context = scopedFixtures ? { fixtures: scopedFixtures } : undefined;
|
|
129
|
+
const rewritten = rewriter.rewrite(sql, context);
|
|
130
|
+
handleExecution(prop, rewritten.sql, rest, rewritten.fixturesApplied);
|
|
131
|
+
return value.apply(target, [rewritten.sql, ...rest]);
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
return value.bind(target);
|
|
135
|
+
},
|
|
136
|
+
});
|
|
137
|
+
};
|
|
138
|
+
return buildProxy();
|
|
139
|
+
};
|
|
140
|
+
exports.wrapSqliteDriver = wrapSqliteDriver;
|
|
141
|
+
//# sourceMappingURL=wrapSqliteDriver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wrapSqliteDriver.js","sourceRoot":"","sources":["../../src/proxy/wrapSqliteDriver.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { SelectRewriterOptions } from '@rawsql-ts/testkit-core';
|
|
2
|
+
import type { TableFixture } from '@rawsql-ts/testkit-core';
|
|
3
|
+
export interface SqliteStatementLike {
|
|
4
|
+
all?(...params: unknown[]): unknown[] | undefined;
|
|
5
|
+
get?(...params: unknown[]): unknown;
|
|
6
|
+
run?(...params: unknown[]): unknown;
|
|
7
|
+
}
|
|
8
|
+
export interface SqliteConnectionLike {
|
|
9
|
+
prepare?(sql: string, ...params: unknown[]): SqliteStatementLike;
|
|
10
|
+
all?(sql: string, ...params: unknown[]): unknown[] | undefined;
|
|
11
|
+
get?(sql: string, ...params: unknown[]): unknown;
|
|
12
|
+
run?(sql: string, ...params: unknown[]): unknown;
|
|
13
|
+
exec?(sql: string, ...params: unknown[]): unknown;
|
|
14
|
+
pragma?(statement: string, ...params: unknown[]): unknown;
|
|
15
|
+
close?(): void;
|
|
16
|
+
}
|
|
17
|
+
export interface SelectDriver<T = unknown> {
|
|
18
|
+
query<U = T>(sql: string, params?: unknown[]): Promise<U[]>;
|
|
19
|
+
}
|
|
20
|
+
export interface CreateSqliteSelectTestDriverOptions extends SelectRewriterOptions {
|
|
21
|
+
connectionFactory: () => SqliteConnectionLike;
|
|
22
|
+
}
|
|
23
|
+
export interface SqliteSelectTestDriver extends SelectDriver {
|
|
24
|
+
withFixtures(fixtures: TableFixture[]): SqliteSelectTestDriver;
|
|
25
|
+
close(): void;
|
|
26
|
+
}
|
|
27
|
+
export interface WrappedSqlQueryLogEntry {
|
|
28
|
+
method: string;
|
|
29
|
+
sql: string;
|
|
30
|
+
params?: unknown;
|
|
31
|
+
fixtures?: string[];
|
|
32
|
+
}
|
|
33
|
+
export interface WrapSqliteDriverOptions extends SelectRewriterOptions {
|
|
34
|
+
onExecute?(sql: string, params?: unknown): void;
|
|
35
|
+
recordQueries?: boolean;
|
|
36
|
+
}
|
|
37
|
+
export type WrappedSqliteDriver<T> = T & {
|
|
38
|
+
withFixtures(fixtures: TableFixture[]): WrappedSqliteDriver<T>;
|
|
39
|
+
queries?: WrappedSqlQueryLogEntry[];
|
|
40
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@rawsql-ts/testkit-sqlite",
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"description": "SQLite driver adapters for the rawsql-ts select query test harness.",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"prepack": "node -e \"const fs=require('fs');const cp=require('child_process');const npm=process.platform==='win32'?'npm.cmd':'npm';if(!fs.existsSync('dist/index.js')){process.exit(cp.spawnSync(npm,['run','build'],{stdio:'inherit'}).status??1)}\"",
|
|
9
|
+
"build": "tsc -p tsconfig.build.json",
|
|
10
|
+
"test": "vitest run",
|
|
11
|
+
"test:watch": "vitest",
|
|
12
|
+
"lint": "eslint src tests --ext .ts",
|
|
13
|
+
"schema:generate": "ts-node --project tsconfig.json src/cli/generateSchema.ts",
|
|
14
|
+
"postinstall": "node ./scripts/install-better-sqlite3.cjs",
|
|
15
|
+
"release": "npm run lint && npm run test && npm run build && node -e \"require('fs').mkdirSync('../../tmp', { recursive: true })\" && pnpm pack --out ../../tmp/rawsql-ts-testkit-sqlite.tgz && pnpm publish --access public"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"sqlite",
|
|
19
|
+
"testing",
|
|
20
|
+
"fixtures",
|
|
21
|
+
"rawsql"
|
|
22
|
+
],
|
|
23
|
+
"license": "MIT",
|
|
24
|
+
"author": "msugiura",
|
|
25
|
+
"repository": {
|
|
26
|
+
"type": "git",
|
|
27
|
+
"url": "git+https://github.com/mk3008/rawsql-ts.git",
|
|
28
|
+
"directory": "packages/testkit-sqlite"
|
|
29
|
+
},
|
|
30
|
+
"publishConfig": {
|
|
31
|
+
"access": "public"
|
|
32
|
+
},
|
|
33
|
+
"engines": {
|
|
34
|
+
"node": ">=20"
|
|
35
|
+
},
|
|
36
|
+
"dependencies": {
|
|
37
|
+
"@rawsql-ts/testkit-core": "workspace:^",
|
|
38
|
+
"rawsql-ts": "workspace:^"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"@types/better-sqlite3": "^7.6.13",
|
|
42
|
+
"better-sqlite3": "^12.4.1",
|
|
43
|
+
"dotenv": "^16.4.7",
|
|
44
|
+
"typescript": "^5.8.2",
|
|
45
|
+
"vitest": "^4.0.7",
|
|
46
|
+
"ts-node": "^10.9.2"
|
|
47
|
+
},
|
|
48
|
+
"files": [
|
|
49
|
+
"dist"
|
|
50
|
+
]
|
|
51
|
+
}
|