sqlstack 1.0.0 → 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/dist/adapters/mysql.d.ts +1 -1
- package/dist/adapters/mysql.d.ts.map +1 -1
- package/dist/adapters/mysql.js +26 -8
- package/dist/adapters/mysql.js.map +1 -1
- package/dist/adapters/pg.d.ts +1 -1
- package/dist/adapters/pg.d.ts.map +1 -1
- package/dist/adapters/pg.js +57 -7
- package/dist/adapters/pg.js.map +1 -1
- package/dist/adapters/sqlite.d.ts +1 -1
- package/dist/adapters/sqlite.d.ts.map +1 -1
- package/dist/adapters/sqlite.js +87 -7
- package/dist/adapters/sqlite.js.map +1 -1
- package/dist/adapters/test.d.ts.map +1 -1
- package/dist/adapters/test.js +5 -2
- package/dist/adapters/test.js.map +1 -1
- package/dist/decorators/query.d.ts.map +1 -1
- package/dist/decorators/query.js +16 -12
- package/dist/decorators/query.js.map +1 -1
- package/dist/registry.d.ts +11 -2
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js.map +1 -1
- package/package.json +1 -1
- package/readme.md +70 -0
package/dist/adapters/mysql.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mysql.d.ts","sourceRoot":"","sources":["../../src/adapters/mysql.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE5C,wBAAgB,aAAa,CAAC,
|
|
1
|
+
{"version":3,"file":"mysql.d.ts","sourceRoot":"","sources":["../../src/adapters/mysql.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE5C,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,GAAG,GAAG,QAAQ,CAmC/D"}
|
package/dist/adapters/mysql.js
CHANGED
|
@@ -1,20 +1,38 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.createMysqlDb = createMysqlDb;
|
|
4
|
-
function createMysqlDb(
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
function createMysqlDb(urlOrPool) {
|
|
5
|
+
let pool;
|
|
6
|
+
let own = false;
|
|
7
|
+
if (typeof urlOrPool === 'string') {
|
|
8
|
+
// Lazy import to keep driver optional
|
|
9
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
10
|
+
const mysql = require('mysql2/promise');
|
|
11
|
+
pool = mysql.createPool({ uri: urlOrPool, connectionLimit: 4 });
|
|
12
|
+
own = true;
|
|
13
|
+
}
|
|
14
|
+
else {
|
|
15
|
+
pool = urlOrPool;
|
|
16
|
+
}
|
|
9
17
|
return {
|
|
10
18
|
dialect: 'mysql',
|
|
11
19
|
async query(sql, params) {
|
|
12
20
|
const [rows] = await pool.query(sql, params);
|
|
13
|
-
|
|
14
|
-
|
|
21
|
+
if (Array.isArray(rows)) {
|
|
22
|
+
// SELECT/CTE result
|
|
23
|
+
return rows.map((r) => ({ ...r }));
|
|
24
|
+
}
|
|
25
|
+
// Non-SELECT result header
|
|
26
|
+
const hdr = rows || {};
|
|
27
|
+
const rowsAffected = Number(hdr.affectedRows ?? hdr.changedRows ?? 0);
|
|
28
|
+
const lastInsertId = hdr.insertId;
|
|
29
|
+
return { rowsAffected, lastInsertId };
|
|
15
30
|
},
|
|
31
|
+
conn: pool,
|
|
16
32
|
async close() {
|
|
17
|
-
|
|
33
|
+
if (own && typeof pool?.end === 'function') {
|
|
34
|
+
await pool.end();
|
|
35
|
+
}
|
|
18
36
|
},
|
|
19
37
|
};
|
|
20
38
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mysql.js","sourceRoot":"","sources":["../../src/adapters/mysql.ts"],"names":[],"mappings":";;AAEA,
|
|
1
|
+
{"version":3,"file":"mysql.js","sourceRoot":"","sources":["../../src/adapters/mysql.ts"],"names":[],"mappings":";;AAEA,sCAmCC;AAnCD,SAAgB,aAAa,CAAC,SAAuB;IACnD,IAAI,IAAS,CAAC;IACd,IAAI,GAAG,GAAG,KAAK,CAAC;IAEhB,IAAI,OAAO,SAAS,KAAK,QAAQ,EAAE,CAAC;QAClC,sCAAsC;QACtC,8DAA8D;QAC9D,MAAM,KAAK,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC;QACxC,IAAI,GAAG,KAAK,CAAC,UAAU,CAAC,EAAE,GAAG,EAAE,SAAS,EAAE,eAAe,EAAE,CAAC,EAAE,CAAC,CAAC;QAChE,GAAG,GAAG,IAAI,CAAC;IACb,CAAC;SAAM,CAAC;QACN,IAAI,GAAG,SAAS,CAAC;IACnB,CAAC;IAED,OAAO;QACL,OAAO,EAAE,OAAO;QAChB,KAAK,CAAC,KAAK,CAAC,GAAW,EAAE,MAAiB;YACxC,MAAM,CAAC,IAAI,CAAC,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;YAC7C,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;gBACxB,oBAAoB;gBACpB,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;YAC1C,CAAC;YACD,2BAA2B;YAC3B,MAAM,GAAG,GAAQ,IAAI,IAAI,EAAE,CAAC;YAC5B,MAAM,YAAY,GAAG,MAAM,CAAC,GAAG,CAAC,YAAY,IAAI,GAAG,CAAC,WAAW,IAAI,CAAC,CAAC,CAAC;YACtE,MAAM,YAAY,GAAG,GAAG,CAAC,QAAQ,CAAC;YAClC,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,CAAC;QACxC,CAAC;QACD,IAAI,EAAE,IAAI;QACV,KAAK,CAAC,KAAK;YACT,IAAI,GAAG,IAAI,OAAO,IAAI,EAAE,GAAG,KAAK,UAAU,EAAE,CAAC;gBAC3C,MAAM,IAAI,CAAC,GAAG,EAAE,CAAC;YACnB,CAAC;QACH,CAAC;KACU,CAAC;AAChB,CAAC","sourcesContent":["import type { Database } from '../registry';\n\nexport function createMysqlDb(urlOrPool: string | any): Database {\n let pool: any;\n let own = false;\n\n if (typeof urlOrPool === 'string') {\n // Lazy import to keep driver optional\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n const mysql = require('mysql2/promise');\n pool = mysql.createPool({ uri: urlOrPool, connectionLimit: 4 });\n own = true;\n } else {\n pool = urlOrPool;\n }\n\n return {\n dialect: 'mysql',\n async query(sql: string, params: unknown[]) {\n const [rows] = await pool.query(sql, params);\n if (Array.isArray(rows)) {\n // SELECT/CTE result\n return rows.map((r: any) => ({ ...r }));\n }\n // Non-SELECT result header\n const hdr: any = rows || {};\n const rowsAffected = Number(hdr.affectedRows ?? hdr.changedRows ?? 0);\n const lastInsertId = hdr.insertId;\n return { rowsAffected, lastInsertId };\n },\n conn: pool,\n async close() {\n if (own && typeof pool?.end === 'function') {\n await pool.end();\n }\n },\n } as Database;\n}\n"]}
|
package/dist/adapters/pg.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pg.d.ts","sourceRoot":"","sources":["../../src/adapters/pg.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"pg.d.ts","sourceRoot":"","sources":["../../src/adapters/pg.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AA6B5C,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,GAAG,GAAG,QAAQ,CAoC5D"}
|
package/dist/adapters/pg.js
CHANGED
|
@@ -1,19 +1,69 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.createPgDb = createPgDb;
|
|
4
|
-
function
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
function stripLeadingComments(sql) {
|
|
5
|
+
let i = 0;
|
|
6
|
+
const n = sql.length;
|
|
7
|
+
// Strip BOM
|
|
8
|
+
if (sql.charCodeAt(0) === 0xfeff)
|
|
9
|
+
i = 1;
|
|
10
|
+
while (i < n) {
|
|
11
|
+
// Skip whitespace
|
|
12
|
+
while (i < n && /\s/.test(sql[i]))
|
|
13
|
+
i++;
|
|
14
|
+
if (i + 1 < n && sql[i] === '-' && sql[i + 1] === '-') {
|
|
15
|
+
// Line comment -- ...\n
|
|
16
|
+
i += 2;
|
|
17
|
+
while (i < n && sql[i] !== '\n')
|
|
18
|
+
i++;
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
if (i + 1 < n && sql[i] === '/' && sql[i + 1] === '*') {
|
|
22
|
+
// Block comment /* ... */
|
|
23
|
+
i += 2;
|
|
24
|
+
let end = sql.indexOf('*/', i);
|
|
25
|
+
if (end === -1)
|
|
26
|
+
return '';
|
|
27
|
+
i = end + 2;
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
break;
|
|
31
|
+
}
|
|
32
|
+
return sql.slice(i);
|
|
33
|
+
}
|
|
34
|
+
function createPgDb(urlOrPool) {
|
|
35
|
+
let pool;
|
|
36
|
+
let own = false;
|
|
37
|
+
if (typeof urlOrPool === 'string') {
|
|
38
|
+
// Lazy import to keep driver optional
|
|
39
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
40
|
+
const { Pool } = require('pg');
|
|
41
|
+
pool = new Pool({ connectionString: urlOrPool, max: 4 });
|
|
42
|
+
own = true;
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
pool = urlOrPool;
|
|
46
|
+
}
|
|
9
47
|
return {
|
|
10
48
|
dialect: 'postgres',
|
|
11
49
|
async query(sql, params) {
|
|
12
50
|
const res = await pool.query(sql, params);
|
|
13
|
-
|
|
51
|
+
const text = stripLeadingComments(String(sql)).trimStart().toUpperCase();
|
|
52
|
+
if (text.startsWith('SELECT') || text.startsWith('WITH')) {
|
|
53
|
+
return res.rows;
|
|
54
|
+
}
|
|
55
|
+
// Non-SELECT: include rowCount and optional returning
|
|
56
|
+
const base = { rowsAffected: Number(res.rowCount ?? 0) };
|
|
57
|
+
if (Array.isArray(res.rows) && res.rows.length > 0) {
|
|
58
|
+
base.returning = res.rows;
|
|
59
|
+
}
|
|
60
|
+
return base;
|
|
14
61
|
},
|
|
62
|
+
conn: pool,
|
|
15
63
|
async close() {
|
|
16
|
-
|
|
64
|
+
if (own && typeof pool?.end === 'function') {
|
|
65
|
+
await pool.end();
|
|
66
|
+
}
|
|
17
67
|
},
|
|
18
68
|
};
|
|
19
69
|
}
|
package/dist/adapters/pg.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pg.js","sourceRoot":"","sources":["../../src/adapters/pg.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"pg.js","sourceRoot":"","sources":["../../src/adapters/pg.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Database } from '../registry';\n\nfunction stripLeadingComments(sql: string): string {\n let i = 0;\n const n = sql.length;\n // Strip BOM\n if (sql.charCodeAt(0) === 0xfeff) i = 1;\n while (i < n) {\n // Skip whitespace\n while (i < n && /\\s/.test(sql[i]!)) i++;\n if (i + 1 < n && sql[i] === '-' && sql[i + 1] === '-') {\n // Line comment -- ...\\n\n i += 2;\n while (i < n && sql[i] !== '\\n') i++;\n continue;\n }\n if (i + 1 < n && sql[i] === '/' && sql[i + 1] === '*') {\n // Block comment /* ... */\n i += 2;\n let end = sql.indexOf('*/', i);\n if (end === -1) return '';\n i = end + 2;\n continue;\n }\n break;\n }\n return sql.slice(i);\n}\n\nexport function createPgDb(urlOrPool: string | any): Database {\n let pool: any;\n let own = false;\n\n if (typeof urlOrPool === 'string') {\n // Lazy import to keep driver optional\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n const { Pool } = require('pg');\n pool = new Pool({ connectionString: urlOrPool, max: 4 });\n own = true;\n } else {\n pool = urlOrPool;\n }\n\n return {\n dialect: 'postgres',\n async query(sql: string, params: unknown[]) {\n const res = await pool.query(sql, params);\n const text = stripLeadingComments(String(sql)).trimStart().toUpperCase();\n if (text.startsWith('SELECT') || text.startsWith('WITH')) {\n return res.rows;\n }\n // Non-SELECT: include rowCount and optional returning\n const base: any = { rowsAffected: Number(res.rowCount ?? 0) };\n if (Array.isArray(res.rows) && res.rows.length > 0) {\n base.returning = res.rows;\n }\n return base;\n },\n conn: pool,\n async close() {\n if (own && typeof pool?.end === 'function') {\n await pool.end();\n }\n },\n } as Database;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sqlite.d.ts","sourceRoot":"","sources":["../../src/adapters/sqlite.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"sqlite.d.ts","sourceRoot":"","sources":["../../src/adapters/sqlite.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AA2B5C,wBAAgB,cAAc,CAAC,YAAY,EAAE,MAAM,GAAG,GAAG,GAAG,QAAQ,CA+GnE"}
|
package/dist/adapters/sqlite.js
CHANGED
|
@@ -1,7 +1,85 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.createSqliteDb = createSqliteDb;
|
|
4
|
-
function
|
|
4
|
+
function stripLeadingComments(sql) {
|
|
5
|
+
let i = 0;
|
|
6
|
+
const n = sql.length;
|
|
7
|
+
if (sql.charCodeAt(0) === 0xfeff)
|
|
8
|
+
i = 1; // BOM
|
|
9
|
+
while (i < n) {
|
|
10
|
+
while (i < n && /\s/.test(sql[i]))
|
|
11
|
+
i++;
|
|
12
|
+
if (i + 1 < n && sql[i] === '-' && sql[i + 1] === '-') {
|
|
13
|
+
// -- line comment
|
|
14
|
+
i += 2;
|
|
15
|
+
while (i < n && sql[i] !== '\n')
|
|
16
|
+
i++;
|
|
17
|
+
continue;
|
|
18
|
+
}
|
|
19
|
+
if (i + 1 < n && sql[i] === '/' && sql[i + 1] === '*') {
|
|
20
|
+
// /* block comment */
|
|
21
|
+
i += 2;
|
|
22
|
+
const end = sql.indexOf('*/', i);
|
|
23
|
+
if (end === -1)
|
|
24
|
+
return '';
|
|
25
|
+
i = end + 2;
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
28
|
+
break;
|
|
29
|
+
}
|
|
30
|
+
return sql.slice(i);
|
|
31
|
+
}
|
|
32
|
+
function createSqliteDb(filenameOrDb) {
|
|
33
|
+
// If a pre-created connection is provided
|
|
34
|
+
if (typeof filenameOrDb !== 'string' && filenameOrDb) {
|
|
35
|
+
const db = filenameOrDb;
|
|
36
|
+
// better-sqlite3 shape
|
|
37
|
+
if (typeof db.prepare === 'function') {
|
|
38
|
+
return {
|
|
39
|
+
dialect: 'sqlite',
|
|
40
|
+
async query(sql, params) {
|
|
41
|
+
const stmt = db.prepare(sql);
|
|
42
|
+
const text = stripLeadingComments(String(sql)).trimStart().toUpperCase();
|
|
43
|
+
if (text.startsWith('SELECT') || text.startsWith('WITH')) {
|
|
44
|
+
return stmt.all(...params);
|
|
45
|
+
}
|
|
46
|
+
const info = stmt.run(...params);
|
|
47
|
+
return { rowsAffected: Number(info?.changes ?? 0), lastInsertId: info?.lastInsertRowid };
|
|
48
|
+
},
|
|
49
|
+
conn: db,
|
|
50
|
+
// Do not close externally provided connection
|
|
51
|
+
close() { },
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
// sqlite3 shape
|
|
55
|
+
return {
|
|
56
|
+
dialect: 'sqlite',
|
|
57
|
+
async query(sql, params) {
|
|
58
|
+
const text = stripLeadingComments(String(sql)).trimStart().toUpperCase();
|
|
59
|
+
if (text.startsWith('SELECT') || text.startsWith('WITH')) {
|
|
60
|
+
return new Promise((resolve, reject) => {
|
|
61
|
+
db.all(sql, params, (err, rows) => {
|
|
62
|
+
if (err)
|
|
63
|
+
return reject(err);
|
|
64
|
+
resolve(rows || []);
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
return new Promise((resolve, reject) => {
|
|
69
|
+
// Use function callback to access `this` for metadata
|
|
70
|
+
db.run(sql, params, function (err) {
|
|
71
|
+
if (err)
|
|
72
|
+
return reject(err);
|
|
73
|
+
resolve({ rowsAffected: Number(this?.changes ?? 0), lastInsertId: this?.lastID });
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
},
|
|
77
|
+
conn: db,
|
|
78
|
+
// Do not close externally provided connection
|
|
79
|
+
close() { },
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
const filename = filenameOrDb;
|
|
5
83
|
// Prefer better-sqlite3
|
|
6
84
|
try {
|
|
7
85
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
@@ -11,13 +89,14 @@ function createSqliteDb(filename) {
|
|
|
11
89
|
dialect: 'sqlite',
|
|
12
90
|
async query(sql, params) {
|
|
13
91
|
const stmt = db.prepare(sql);
|
|
14
|
-
const text = String(sql).
|
|
92
|
+
const text = stripLeadingComments(String(sql)).trimStart().toUpperCase();
|
|
15
93
|
if (text.startsWith('SELECT') || text.startsWith('WITH')) {
|
|
16
94
|
return stmt.all(...params);
|
|
17
95
|
}
|
|
18
|
-
stmt.run(...params);
|
|
19
|
-
return
|
|
96
|
+
const info = stmt.run(...params);
|
|
97
|
+
return { rowsAffected: Number(info?.changes ?? 0), lastInsertId: info?.lastInsertRowid };
|
|
20
98
|
},
|
|
99
|
+
conn: db,
|
|
21
100
|
close() {
|
|
22
101
|
db.close();
|
|
23
102
|
},
|
|
@@ -32,7 +111,7 @@ function createSqliteDb(filename) {
|
|
|
32
111
|
return {
|
|
33
112
|
dialect: 'sqlite',
|
|
34
113
|
async query(sql, params) {
|
|
35
|
-
const text = String(sql).
|
|
114
|
+
const text = stripLeadingComments(String(sql)).trimStart().toUpperCase();
|
|
36
115
|
if (text.startsWith('SELECT') || text.startsWith('WITH')) {
|
|
37
116
|
return new Promise((resolve, reject) => {
|
|
38
117
|
db.all(sql, params, (err, rows) => {
|
|
@@ -44,13 +123,14 @@ function createSqliteDb(filename) {
|
|
|
44
123
|
}
|
|
45
124
|
// Non-SELECT statements
|
|
46
125
|
return new Promise((resolve, reject) => {
|
|
47
|
-
db.run(sql, params, (err)
|
|
126
|
+
db.run(sql, params, function (err) {
|
|
48
127
|
if (err)
|
|
49
128
|
return reject(err);
|
|
50
|
-
resolve(
|
|
129
|
+
resolve({ rowsAffected: Number(this?.changes ?? 0), lastInsertId: this?.lastID });
|
|
51
130
|
});
|
|
52
131
|
});
|
|
53
132
|
},
|
|
133
|
+
conn: db,
|
|
54
134
|
close() {
|
|
55
135
|
return new Promise((resolve, reject) => {
|
|
56
136
|
db.close((err) => (err ? reject(err) : resolve()));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sqlite.js","sourceRoot":"","sources":["../../src/adapters/sqlite.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"sqlite.js","sourceRoot":"","sources":["../../src/adapters/sqlite.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Database } from '../registry';\n\nfunction stripLeadingComments(sql: string): string {\n let i = 0;\n const n = sql.length;\n if (sql.charCodeAt(0) === 0xfeff) i = 1; // BOM\n while (i < n) {\n while (i < n && /\\s/.test(sql[i]!)) i++;\n if (i + 1 < n && sql[i] === '-' && sql[i + 1] === '-') {\n // -- line comment\n i += 2;\n while (i < n && sql[i] !== '\\n') i++;\n continue;\n }\n if (i + 1 < n && sql[i] === '/' && sql[i + 1] === '*') {\n // /* block comment */\n i += 2;\n const end = sql.indexOf('*/', i);\n if (end === -1) return '';\n i = end + 2;\n continue;\n }\n break;\n }\n return sql.slice(i);\n}\n\nexport function createSqliteDb(filenameOrDb: string | any): Database {\n // If a pre-created connection is provided\n if (typeof filenameOrDb !== 'string' && filenameOrDb) {\n const db = filenameOrDb;\n\n // better-sqlite3 shape\n if (typeof db.prepare === 'function') {\n return {\n dialect: 'sqlite',\n async query(sql: string, params: unknown[]) {\n const stmt = db.prepare(sql);\n const text = stripLeadingComments(String(sql)).trimStart().toUpperCase();\n if (text.startsWith('SELECT') || text.startsWith('WITH')) {\n return stmt.all(...params);\n }\n const info = stmt.run(...params);\n return { rowsAffected: Number(info?.changes ?? 0), lastInsertId: info?.lastInsertRowid };\n },\n conn: db,\n // Do not close externally provided connection\n close() {},\n } as Database;\n }\n\n // sqlite3 shape\n return {\n dialect: 'sqlite',\n async query(sql: string, params: unknown[]) {\n const text = stripLeadingComments(String(sql)).trimStart().toUpperCase();\n if (text.startsWith('SELECT') || text.startsWith('WITH')) {\n return new Promise<any[]>((resolve, reject) => {\n db.all(sql, params, (err: Error | null, rows: any[]) => {\n if (err) return reject(err);\n resolve(rows || []);\n });\n });\n }\n return new Promise((resolve, reject) => {\n // Use function callback to access `this` for metadata\n db.run(sql, params, function (this: any, err: Error | null) {\n if (err) return reject(err);\n resolve({ rowsAffected: Number(this?.changes ?? 0), lastInsertId: this?.lastID });\n });\n });\n },\n conn: db,\n // Do not close externally provided connection\n close() {},\n } as Database;\n }\n\n const filename = filenameOrDb as string;\n\n // Prefer better-sqlite3\n try {\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n const BetterSqlite3 = require('better-sqlite3');\n const db = new BetterSqlite3(filename);\n return {\n dialect: 'sqlite',\n async query(sql: string, params: unknown[]) {\n const stmt = db.prepare(sql);\n const text = stripLeadingComments(String(sql)).trimStart().toUpperCase();\n if (text.startsWith('SELECT') || text.startsWith('WITH')) {\n return stmt.all(...params);\n }\n const info = stmt.run(...params);\n return { rowsAffected: Number(info?.changes ?? 0), lastInsertId: info?.lastInsertRowid };\n },\n conn: db,\n close() {\n db.close();\n },\n } as Database;\n } catch {}\n\n // Fallback to sqlite3\n try {\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n const sqlite3 = require('sqlite3');\n const db = new sqlite3.Database(filename);\n return {\n dialect: 'sqlite',\n async query(sql: string, params: unknown[]) {\n const text = stripLeadingComments(String(sql)).trimStart().toUpperCase();\n if (text.startsWith('SELECT') || text.startsWith('WITH')) {\n return new Promise<any[]>((resolve, reject) => {\n db.all(sql, params, (err: Error | null, rows: any[]) => {\n if (err) return reject(err);\n resolve(rows || []);\n });\n });\n }\n // Non-SELECT statements\n return new Promise((resolve, reject) => {\n db.run(sql, params, function (this: any, err: Error | null) {\n if (err) return reject(err);\n resolve({ rowsAffected: Number(this?.changes ?? 0), lastInsertId: this?.lastID });\n });\n });\n },\n conn: db,\n close() {\n return new Promise<void>((resolve, reject) => {\n db.close((err: Error | null) => (err ? reject(err) : resolve()));\n });\n },\n } as Database;\n } catch {}\n\n throw new Error('No SQLite driver available. Install either better-sqlite3 or sqlite3.');\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"test.d.ts","sourceRoot":"","sources":["../../src/adapters/test.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAI5C,wBAAgB,YAAY,IAAI,QAAQ,
|
|
1
|
+
{"version":3,"file":"test.d.ts","sourceRoot":"","sources":["../../src/adapters/test.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAI5C,wBAAgB,YAAY,IAAI,QAAQ,CAoDvC"}
|
package/dist/adapters/test.js
CHANGED
|
@@ -11,7 +11,7 @@ function createTestDb() {
|
|
|
11
11
|
// Very small subset for tests: CREATE TABLE users
|
|
12
12
|
if (s.startsWith('CREATE TABLE USERS')) {
|
|
13
13
|
ensure('users');
|
|
14
|
-
return
|
|
14
|
+
return { rowsAffected: 0 };
|
|
15
15
|
}
|
|
16
16
|
// INSERT INTO users (id, email, status, ...)
|
|
17
17
|
if (s.startsWith('INSERT INTO USERS')) {
|
|
@@ -19,7 +19,7 @@ function createTestDb() {
|
|
|
19
19
|
// naive: params order must match tests
|
|
20
20
|
const [id, email, status, created_at] = params;
|
|
21
21
|
users.push({ id, email, status, created_at });
|
|
22
|
-
return
|
|
22
|
+
return { rowsAffected: 1, lastInsertId: id };
|
|
23
23
|
}
|
|
24
24
|
// SELECT id, email, status FROM users WHERE email = ? AND status = ?
|
|
25
25
|
if (/FROM\s+users/i.test(sql) && /WHERE\s+email\s*=/.test(sql) && /status\s*=/.test(sql)) {
|
|
@@ -42,6 +42,9 @@ function createTestDb() {
|
|
|
42
42
|
// Fallback: return empty
|
|
43
43
|
return [];
|
|
44
44
|
},
|
|
45
|
+
conn: null,
|
|
46
|
+
// Ensure close exists; no-op for in-memory test adapter
|
|
47
|
+
close() { },
|
|
45
48
|
};
|
|
46
49
|
}
|
|
47
50
|
//# sourceMappingURL=test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"test.js","sourceRoot":"","sources":["../../src/adapters/test.ts"],"names":[],"mappings":";;AAIA,
|
|
1
|
+
{"version":3,"file":"test.js","sourceRoot":"","sources":["../../src/adapters/test.ts"],"names":[],"mappings":";;AAIA,oCAoDC;AApDD,SAAgB,YAAY;IAC1B,MAAM,MAAM,GAA0B,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAC1D,MAAM,MAAM,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,IAAI,MAAX,MAAM,CAAC,IAAI,IAAM,EAAE,EAAC,CAAC;IAEvD,OAAO;QACL,OAAO,EAAE,QAAQ;QACjB,KAAK,CAAC,KAAK,CAAC,GAAW,EAAE,MAAiB;YACxC,MAAM,CAAC,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;YAEnC,kDAAkD;YAClD,IAAI,CAAC,CAAC,UAAU,CAAC,oBAAoB,CAAC,EAAE,CAAC;gBACvC,MAAM,CAAC,OAAO,CAAC,CAAC;gBAChB,OAAO,EAAE,YAAY,EAAE,CAAC,EAAE,CAAC;YAC7B,CAAC;YAED,6CAA6C;YAC7C,IAAI,CAAC,CAAC,UAAU,CAAC,mBAAmB,CAAC,EAAE,CAAC;gBACtC,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;gBAC9B,uCAAuC;gBACvC,MAAM,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,CAAC,GAAG,MAAe,CAAC;gBACxD,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,CAAC;gBAC9C,OAAO,EAAE,YAAY,EAAE,CAAC,EAAE,YAAY,EAAE,EAAE,EAAE,CAAC;YAC/C,CAAC;YAED,qEAAqE;YACrE,IAAI,eAAe,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,mBAAmB,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;gBACzF,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,GAAG,MAAe,CAAC;gBACxC,OAAO,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,KAAK,IAAI,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC;YACjF,CAAC;YAED,mDAAmD;YACnD,IAAI,eAAe,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,gBAAgB,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC5D,MAAM,CAAC,EAAE,CAAC,GAAG,MAAe,CAAC;gBAC7B,OAAO,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;YACjH,CAAC;YAED,oDAAoD;YACpD,IAAI,eAAe,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,oBAAoB,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;gBAChE,MAAM,CAAC,MAAM,CAAC,GAAG,MAAe,CAAC;gBACjC,OAAO,MAAM,CAAC,OAAO,CAAC;qBACnB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC;qBAClC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;qBACxD,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;YAChC,CAAC;YAED,yBAAyB;YACzB,OAAO,EAAE,CAAC;QACZ,CAAC;QACD,IAAI,EAAE,IAAI;QACV,wDAAwD;QACxD,KAAK,KAAI,CAAC;KACX,CAAC;AACJ,CAAC","sourcesContent":["import type { Database } from '../registry';\n\ntype Row = Record<string, any>;\n\nexport function createTestDb(): Database {\n const tables: Record<string, Row[]> = Object.create(null);\n const ensure = (name: string) => (tables[name] ||= []);\n\n return {\n dialect: 'sqlite',\n async query(sql: string, params: unknown[]) {\n const s = sql.trim().toUpperCase();\n\n // Very small subset for tests: CREATE TABLE users\n if (s.startsWith('CREATE TABLE USERS')) {\n ensure('users');\n return { rowsAffected: 0 };\n }\n\n // INSERT INTO users (id, email, status, ...)\n if (s.startsWith('INSERT INTO USERS')) {\n const users = ensure('users');\n // naive: params order must match tests\n const [id, email, status, created_at] = params as any[];\n users.push({ id, email, status, created_at });\n return { rowsAffected: 1, lastInsertId: id };\n }\n\n // SELECT id, email, status FROM users WHERE email = ? AND status = ?\n if (/FROM\\s+users/i.test(sql) && /WHERE\\s+email\\s*=/.test(sql) && /status\\s*=/.test(sql)) {\n const [email, status] = params as any[];\n return ensure('users').filter((r) => r.email === email && r.status === status);\n }\n\n // SELECT id, email, status FROM users WHERE id = ?\n if (/FROM\\s+users/i.test(sql) && /WHERE\\s+id\\s*=/.test(sql)) {\n const [id] = params as any[];\n return ensure('users').filter((r) => r.id === id).map((r) => ({ id: r.id, email: r.email, status: r.status }));\n }\n\n // SELECT id FROM users WHERE status = ? ORDER BY id\n if (/FROM\\s+users/i.test(sql) && /WHERE\\s+status\\s*=/.test(sql)) {\n const [status] = params as any[];\n return ensure('users')\n .filter((r) => r.status === status)\n .sort((a, b) => String(a.id).localeCompare(String(b.id)))\n .map((r) => ({ id: r.id }));\n }\n\n // Fallback: return empty\n return [];\n },\n conn: null,\n // Ensure close exists; no-op for in-memory test adapter\n close() {},\n };\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../../src/decorators/query.ts"],"names":[],"mappings":"AAOA,KAAK,YAAY,GAAG;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,QAAQ,GAAG,OAAO,GAAG,UAAU,CAAC;CAC3C,CAAC;AAEF,wBAAgB,KAAK,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,YAAY,IAC9B,SAAS,GAAG,EAAE,MAAM,MAAM,GAAG,MAAM,EAAE,MAAM,kBAAkB,
|
|
1
|
+
{"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../../src/decorators/query.ts"],"names":[],"mappings":"AAOA,KAAK,YAAY,GAAG;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,QAAQ,GAAG,OAAO,GAAG,UAAU,CAAC;CAC3C,CAAC;AAEF,wBAAgB,KAAK,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,YAAY,IAC9B,SAAS,GAAG,EAAE,MAAM,MAAM,GAAG,MAAM,EAAE,MAAM,kBAAkB,wBA0E/E"}
|
package/dist/decorators/query.js
CHANGED
|
@@ -53,20 +53,24 @@ function Query(arg) {
|
|
|
53
53
|
const binder = dialect === 'postgres' ? (0, sqlBinder_1.createPostgresBinder)() : dialect === 'mysql' ? (0, sqlBinder_1.createMysqlBinder)() : (0, sqlBinder_1.createSqliteBinder)();
|
|
54
54
|
const { sql: boundSql, params } = binder.bind(sql, args);
|
|
55
55
|
// 5) execute query via registry DB
|
|
56
|
-
const
|
|
57
|
-
// 6) shape
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
if (
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
56
|
+
const out = await db.query(boundSql, params);
|
|
57
|
+
// 6) If rows were returned (SELECT/CTE), shape + validate
|
|
58
|
+
if (Array.isArray(out)) {
|
|
59
|
+
const shaped = applyShape(out, labels.shape);
|
|
60
|
+
// 7) validate result via JSON Schema, if provided
|
|
61
|
+
if (labels.validateSchema && !(0, validator_1.isValidationDisabled)()) {
|
|
62
|
+
if (Array.isArray(shaped)) {
|
|
63
|
+
for (const row of shaped)
|
|
64
|
+
(0, validator_1.validateOutput)(labels.validateSchema, row);
|
|
65
|
+
}
|
|
66
|
+
else if (shaped !== null && shaped !== undefined) {
|
|
67
|
+
(0, validator_1.validateOutput)(labels.validateSchema, shaped);
|
|
68
|
+
}
|
|
67
69
|
}
|
|
70
|
+
return shaped;
|
|
68
71
|
}
|
|
69
|
-
return
|
|
72
|
+
// Non-SELECT: return the write result as-is
|
|
73
|
+
return out;
|
|
70
74
|
};
|
|
71
75
|
return desc;
|
|
72
76
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"query.js","sourceRoot":"","sources":["../../src/decorators/query.ts"],"names":[],"mappings":";;AAaA,
|
|
1
|
+
{"version":3,"file":"query.js","sourceRoot":"","sources":["../../src/decorators/query.ts"],"names":[],"mappings":"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","sourcesContent":["import { getClassLabels, getMethodLabels, setMethodLabels } from '../core/metadata';\nimport { SqlStackError, ExactlyOneRowError, NoRowsError, RowsExistError } from '../core/errors';\nimport { isValidationDisabled, validateOutput } from '../core/validator';\nimport { SqlStackDB } from '../registry';\nimport { createSqliteBinder, createMysqlBinder, createPostgresBinder } from '../binders/sqlBinder';\nimport { coerceRootPath, guessDecoratorDir, resolveSqlFromFs } from '../core/fileResolution';\n\ntype QueryOptions = {\n sql?: string; // optional inline SQL for testing; otherwise, future: load from file\n db?: string; // optional override DB name\n dialect?: 'sqlite' | 'mysql' | 'postgres';\n};\n\nexport function Query(arg?: string | QueryOptions) {\n return function (_target: any, prop: string | symbol, desc: PropertyDescriptor) {\n const options: QueryOptions | undefined = typeof arg === 'string' ? undefined : arg;\n const rootArg: string | undefined = typeof arg === 'string' ? arg : undefined;\n // Store method-level db override if provided\n if (options?.db) {\n setMethodLabels(_target, prop, { db: options.db });\n }\n // Store inline SQL if provided\n if (options?.sql) {\n setMethodLabels(_target, prop, { source: { kind: 'inline', sql: options.sql } });\n } else {\n // FS-based resolution\n const { rootDir } = coerceRootPath(rootArg);\n const dir = rootDir ?? guessDecoratorDir();\n if (dir) {\n setMethodLabels(_target, prop, { source: { kind: 'fs', rootDir: dir } });\n }\n }\n\n const original = desc.value;\n desc.value = async function (...callArgs: any[]) {\n const labels = getMethodLabels(this, prop);\n const classLabels = getClassLabels(this);\n\n // 1) prepare args with defaults\n const rawInput = callArgs.length === 1 ? callArgs[0] : callArgs; // object or positional array\n\n // 2) choose database and dialect\n const dbName = labels.db ?? options?.db ?? classLabels?.db;\n const db = SqlStackDB.get(dbName);\n const dialect = options?.dialect ?? db.dialect ?? 'sqlite';\n\n // 3) load SQL source (inline or fs)\n const sql = labels?.source?.kind === 'inline'\n ? labels.source.sql\n : labels?.source?.kind === 'fs'\n ? resolveSqlFromFs(labels.source.rootDir, String(prop), dialect).sql\n : undefined;\n if (!sql) {\n throw new SqlStackError(`No SQL source provided for method ${String(prop)}. Use @Query() with a file/folder path or inline sql.`);\n }\n\n // 4) bind placeholders\n // Decide argument mode: positional if SQL contains :argN\n const hasPositional = /:arg[1-9][0-9]*/.test(sql);\n const args = hasPositional ? callArgs : applyDefaults(labels.defaults, rawInput);\n const binder =\n dialect === 'postgres' ? createPostgresBinder() : dialect === 'mysql' ? createMysqlBinder() : createSqliteBinder();\n const { sql: boundSql, params } = binder.bind(sql, args as any);\n\n // 5) execute query via registry DB\n const out = await db.query(boundSql, params);\n\n // 6) If rows were returned (SELECT/CTE), shape + validate\n if (Array.isArray(out)) {\n const shaped = applyShape(out, labels.shape);\n\n // 7) validate result via JSON Schema, if provided\n if (labels.validateSchema && !isValidationDisabled()) {\n if (Array.isArray(shaped)) {\n for (const row of shaped) validateOutput(labels.validateSchema, row);\n } else if (shaped !== null && shaped !== undefined) {\n validateOutput(labels.validateSchema, shaped);\n }\n }\n return shaped;\n }\n\n // Non-SELECT: return the write result as-is\n return out;\n };\n\n return desc;\n };\n}\n\nfunction applyDefaults(defaults: Record<string, unknown> | undefined, input: any) {\n if (!defaults) return input;\n if (Array.isArray(input)) return input; // defaults only apply to named-object args\n return { ...defaults, ...(input || {}) };\n}\n\nfunction applyShape<T>(rows: T[], shape?: 'single' | 'only' | 'exist' | 'none'): any {\n switch (shape) {\n case 'single':\n return rows.length > 0 ? rows[0] : null;\n case 'only':\n if (rows.length !== 1) throw new ExactlyOneRowError(rows.length);\n return rows[0];\n case 'exist':\n if (rows.length < 1) throw new NoRowsError();\n return rows[0];\n case 'none':\n if (rows.length > 0) throw new RowsExistError(rows.length);\n return null;\n default:\n return rows;\n }\n}\n"]}
|
package/dist/registry.d.ts
CHANGED
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
export type Dialect = 'sqlite' | 'mysql' | 'postgres';
|
|
2
|
+
export interface WriteResult {
|
|
3
|
+
rowsAffected: number;
|
|
4
|
+
lastInsertId?: unknown;
|
|
5
|
+
}
|
|
6
|
+
export interface PostgresWriteResult extends WriteResult {
|
|
7
|
+
returning?: any[];
|
|
8
|
+
}
|
|
9
|
+
export type QueryResult = any[] | WriteResult | PostgresWriteResult;
|
|
2
10
|
export interface Database {
|
|
3
11
|
dialect: Dialect;
|
|
4
|
-
query(sql: string, params: unknown[]): Promise<
|
|
5
|
-
|
|
12
|
+
query(sql: string, params: unknown[]): Promise<QueryResult>;
|
|
13
|
+
conn: unknown;
|
|
14
|
+
close: () => Promise<void> | void;
|
|
6
15
|
}
|
|
7
16
|
declare class Registry {
|
|
8
17
|
private map;
|
package/dist/registry.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,OAAO,GAAG,QAAQ,GAAG,OAAO,GAAG,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,OAAO,GAAG,QAAQ,GAAG,OAAO,GAAG,UAAU,CAAC;AAGtD,MAAM,WAAW,WAAW;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAGD,MAAM,WAAW,mBAAoB,SAAQ,WAAW;IAEtD,SAAS,CAAC,EAAE,GAAG,EAAE,CAAC;CACnB;AAED,MAAM,MAAM,WAAW,GAAG,GAAG,EAAE,GAAG,WAAW,GAAG,mBAAmB,CAAC;AAEpE,MAAM,WAAW,QAAQ;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IAE5D,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CACnC;AAED,cAAM,QAAQ;IACZ,OAAO,CAAC,GAAG,CAA+B;IAC1C,OAAO,CAAC,WAAW,CAAC,CAAS;IAE7B,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ;IAKnC,UAAU,CAAC,IAAI,EAAE,MAAM;IAMvB,GAAG,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,QAAQ;CAO7B;AAED,eAAO,MAAM,UAAU,UAAiB,CAAC"}
|
package/dist/registry.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":";;;AAwBA,MAAM,QAAQ;IAAd;QACU,QAAG,GAAG,IAAI,GAAG,EAAoB,CAAC;IAqB5C,CAAC;IAlBC,QAAQ,CAAC,IAAY,EAAE,EAAY;QACjC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QACvB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,UAAU,CAAC,IAAY;QACrB,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,gCAAgC,IAAI,EAAE,CAAC,CAAC;QACjF,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;QACxB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,GAAG,CAAC,IAAa;QACf,MAAM,GAAG,GAAG,IAAI,IAAI,IAAI,CAAC,WAAW,CAAC;QACrC,IAAI,CAAC,GAAG;YAAE,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;QACrD,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC7B,IAAI,CAAC,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,gCAAgC,GAAG,EAAE,CAAC,CAAC;QAChE,OAAO,EAAE,CAAC;IACZ,CAAC;CACF;AAEY,QAAA,UAAU,GAAG,IAAI,QAAQ,EAAE,CAAC","sourcesContent":["export type Dialect = 'sqlite' | 'mysql' | 'postgres';\n\n// Result for non-SELECT statements across adapters\nexport interface WriteResult {\n rowsAffected: number;\n lastInsertId?: unknown;\n}\n\n// Postgres-specific extension when using RETURNING on write statements\nexport interface PostgresWriteResult extends WriteResult {\n // Only present when the SQL includes RETURNING and rows are returned\n returning?: any[];\n}\n\nexport type QueryResult = any[] | WriteResult | PostgresWriteResult;\n\nexport interface Database {\n dialect: Dialect;\n query(sql: string, params: unknown[]): Promise<QueryResult>;\n // Underlying driver connection or pool (driver-specific)\n conn: unknown;\n close: () => Promise<void> | void;\n}\n\nclass Registry {\n private map = new Map<string, Database>();\n private defaultName?: string;\n\n register(name: string, db: Database) {\n this.map.set(name, db);\n return this;\n }\n\n setDefault(name: string) {\n if (!this.map.has(name)) throw new Error(`No database registered under ${name}`);\n this.defaultName = name;\n return this;\n }\n\n get(name?: string): Database {\n const key = name ?? this.defaultName;\n if (!key) throw new Error('No default database set');\n const db = this.map.get(key);\n if (!db) throw new Error(`No database registered under ${key}`);\n return db;\n }\n}\n\nexport const SqlStackDB = new Registry();\n"]}
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -48,6 +48,26 @@ SqlStackDB
|
|
|
48
48
|
.setDefault("primary");
|
|
49
49
|
```
|
|
50
50
|
|
|
51
|
+
Adapters can receive either a connection string or an existing driver instance (pool/connection):
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
import { Pool as PgPool } from 'pg';
|
|
55
|
+
import mysql from 'mysql2/promise';
|
|
56
|
+
import BetterSqlite3 from 'better-sqlite3';
|
|
57
|
+
|
|
58
|
+
// Postgres: pass an existing pool
|
|
59
|
+
const pgPool = new PgPool({ connectionString: process.env.PG_URL, max: 4 });
|
|
60
|
+
SqlStackDB.register('pg-existing', createPgDb(pgPool));
|
|
61
|
+
|
|
62
|
+
// MySQL: pass an existing pool
|
|
63
|
+
const mysqlPool = mysql.createPool({ uri: process.env.MYSQL_URL!, connectionLimit: 4 });
|
|
64
|
+
SqlStackDB.register('mysql-existing', createMysqlDb(mysqlPool));
|
|
65
|
+
|
|
66
|
+
// SQLite: pass an existing better-sqlite3 connection
|
|
67
|
+
const sqlite = new BetterSqlite3(':memory:');
|
|
68
|
+
SqlStackDB.register('sqlite-existing', createSqliteDb(sqlite));
|
|
69
|
+
```
|
|
70
|
+
|
|
51
71
|
Then, choose a database per repository (class-level default):
|
|
52
72
|
|
|
53
73
|
```ts
|
|
@@ -374,3 +394,53 @@ The binder placeholder style is inferred from the selected database (method →
|
|
|
374
394
|
## License
|
|
375
395
|
|
|
376
396
|
ISC
|
|
397
|
+
|
|
398
|
+
## Result Shape
|
|
399
|
+
|
|
400
|
+
- SELECT and WITH CTE queries return an array of rows and can be shaped via decorators.
|
|
401
|
+
- INSERT/UPDATE/DELETE return a common object: `{ rowsAffected: number, lastInsertId?: unknown }`.
|
|
402
|
+
- Postgres-only: if a non-SELECT query includes `RETURNING`, the result also includes an optional `returning` array: `{ rowsAffected, returning: Row[] }`.
|
|
403
|
+
|
|
404
|
+
### Examples
|
|
405
|
+
|
|
406
|
+
```ts
|
|
407
|
+
import type { WriteResult } from 'sqlstack';
|
|
408
|
+
import { SqlStackDB } from 'sqlstack/registry';
|
|
409
|
+
|
|
410
|
+
const db = SqlStackDB.get();
|
|
411
|
+
|
|
412
|
+
// A write returns WriteResult
|
|
413
|
+
const write: WriteResult = await db.query(
|
|
414
|
+
'UPDATE users SET status = ? WHERE id = ?',
|
|
415
|
+
['inactive', 'u1']
|
|
416
|
+
);
|
|
417
|
+
console.log(write.rowsAffected);
|
|
418
|
+
|
|
419
|
+
// Postgres with RETURNING returns WriteResult & { returning?: any[] }
|
|
420
|
+
// (only has `returning` when RETURNING is present)
|
|
421
|
+
const pgWrite = await db.query(
|
|
422
|
+
'INSERT INTO users(id,email) VALUES($1,$2) RETURNING id',
|
|
423
|
+
['u9', 'nine@example.com']
|
|
424
|
+
);
|
|
425
|
+
if (!Array.isArray(pgWrite) && pgWrite.returning) {
|
|
426
|
+
console.log(pgWrite.returning[0].id);
|
|
427
|
+
}
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
## Underlying Connections
|
|
431
|
+
|
|
432
|
+
Every `Database` exposes its driver via `conn` so you can drop down to the raw client when needed:
|
|
433
|
+
|
|
434
|
+
```ts
|
|
435
|
+
import { SqlStackDB } from 'sqlstack/registry';
|
|
436
|
+
|
|
437
|
+
const db = SqlStackDB.get();
|
|
438
|
+
// Driver shape depends on adapter:
|
|
439
|
+
// - Postgres: pg.Pool
|
|
440
|
+
// - MySQL: mysql2/promise Pool
|
|
441
|
+
// - SQLite: better-sqlite3 Database or sqlite3.Database
|
|
442
|
+
const raw = db.conn;
|
|
443
|
+
|
|
444
|
+
// close() only disposes connections created by the adapter itself.
|
|
445
|
+
// If you supplied an existing connection/pool, close() is a no-op.
|
|
446
|
+
```
|