sqlstack 1.0.13 → 1.0.15
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/cjs/binders/sqlBinder.d.ts +2 -1
- package/dist/cjs/binders/sqlBinder.d.ts.map +1 -1
- package/dist/cjs/binders/sqlBinder.js +3 -1
- package/dist/cjs/binders/sqlBinder.js.map +1 -1
- package/dist/cjs/core/errors.d.ts +4 -0
- package/dist/cjs/core/errors.d.ts.map +1 -1
- package/dist/cjs/core/errors.js +9 -1
- package/dist/cjs/core/errors.js.map +1 -1
- package/dist/cjs/core/metadata.d.ts +3 -0
- package/dist/cjs/core/metadata.d.ts.map +1 -1
- package/dist/cjs/core/metadata.js.map +1 -1
- package/dist/cjs/core/sqlParams.d.ts +6 -0
- package/dist/cjs/core/sqlParams.d.ts.map +1 -0
- package/dist/cjs/core/sqlParams.js +120 -0
- package/dist/cjs/core/sqlParams.js.map +1 -0
- package/dist/cjs/core/validator.d.ts +0 -5
- package/dist/cjs/core/validator.d.ts.map +1 -1
- package/dist/cjs/core/validator.js +2 -11
- package/dist/cjs/core/validator.js.map +1 -1
- package/dist/cjs/decorators/missingAsNull.d.ts +34 -0
- package/dist/cjs/decorators/missingAsNull.d.ts.map +1 -0
- package/dist/cjs/decorators/missingAsNull.js +40 -0
- package/dist/cjs/decorators/missingAsNull.js.map +1 -0
- package/dist/cjs/decorators/query.d.ts.map +1 -1
- package/dist/cjs/decorators/query.js +23 -0
- package/dist/cjs/decorators/query.js.map +1 -1
- package/dist/cjs/index.d.ts +5 -4
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +10 -5
- package/dist/cjs/index.js.map +1 -1
- package/dist/esm/adapters/index.js +3 -3
- package/dist/esm/binders/sqlBinder.js +3 -0
- package/dist/esm/binders/sqlBinder.js.map +1 -1
- package/dist/esm/core/errors.js +7 -0
- package/dist/esm/core/errors.js.map +1 -1
- package/dist/esm/core/metadata.js.map +1 -1
- package/dist/esm/core/sqlParams.js +117 -0
- package/dist/esm/core/sqlParams.js.map +1 -0
- package/dist/esm/core/validator.js +1 -8
- package/dist/esm/core/validator.js.map +1 -1
- package/dist/esm/decorators/defaults.js +1 -1
- package/dist/esm/decorators/missingAsNull.js +37 -0
- package/dist/esm/decorators/missingAsNull.js.map +1 -0
- package/dist/esm/decorators/page.js +1 -1
- package/dist/esm/decorators/query.js +29 -6
- package/dist/esm/decorators/query.js.map +1 -1
- package/dist/esm/decorators/queryBinder.js +1 -1
- package/dist/esm/decorators/resultShape.js +1 -1
- package/dist/esm/decorators/transform.js +1 -1
- package/dist/esm/decorators/validateResult.js +1 -1
- package/dist/esm/index.js +19 -14
- package/dist/esm/index.js.map +1 -1
- package/package.json +2 -2
- package/readme.md +458 -230
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { extractNamedParams } from '../core/sqlParams';
|
|
1
2
|
export type BindResult = {
|
|
2
3
|
sql: string;
|
|
3
4
|
params: unknown[];
|
|
@@ -10,5 +11,5 @@ export declare function createBinder(dialect: Dialect): SqlBinder;
|
|
|
10
11
|
export declare const createMysqlBinder: () => SqlBinder;
|
|
11
12
|
export declare const createSqliteBinder: () => SqlBinder;
|
|
12
13
|
export declare const createPostgresBinder: () => SqlBinder;
|
|
13
|
-
export {};
|
|
14
|
+
export { extractNamedParams };
|
|
14
15
|
//# sourceMappingURL=sqlBinder.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sqlBinder.d.ts","sourceRoot":"","sources":["../../../src/binders/sqlBinder.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,UAAU,GAAG;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,OAAO,EAAE,CAAC;CACnB,CAAC;AAEF,MAAM,WAAW,SAAS;IACxB,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,EAAE,GAAG,UAAU,CAAC;CAC1E;AAED,KAAK,OAAO,GAAG,OAAO,GAAG,QAAQ,GAAG,UAAU,CAAC;AAE/C,wBAAgB,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,SAAS,CAiLxD;AAED,eAAO,MAAM,iBAAiB,iBAA8B,CAAC;AAC7D,eAAO,MAAM,kBAAkB,iBAA+B,CAAC;AAC/D,eAAO,MAAM,oBAAoB,iBAAiC,CAAC"}
|
|
1
|
+
{"version":3,"file":"sqlBinder.d.ts","sourceRoot":"","sources":["../../../src/binders/sqlBinder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAEvD,MAAM,MAAM,UAAU,GAAG;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,OAAO,EAAE,CAAC;CACnB,CAAC;AAEF,MAAM,WAAW,SAAS;IACxB,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,EAAE,GAAG,UAAU,CAAC;CAC1E;AAED,KAAK,OAAO,GAAG,OAAO,GAAG,QAAQ,GAAG,UAAU,CAAC;AAE/C,wBAAgB,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,SAAS,CAiLxD;AAED,eAAO,MAAM,iBAAiB,iBAA8B,CAAC;AAC7D,eAAO,MAAM,kBAAkB,iBAA+B,CAAC;AAC/D,eAAO,MAAM,oBAAoB,iBAAiC,CAAC;AAGnE,OAAO,EAAE,kBAAkB,EAAE,CAAC"}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.createPostgresBinder = exports.createSqliteBinder = exports.createMysqlBinder = void 0;
|
|
3
|
+
exports.extractNamedParams = exports.createPostgresBinder = exports.createSqliteBinder = exports.createMysqlBinder = void 0;
|
|
4
4
|
exports.createBinder = createBinder;
|
|
5
|
+
const sqlParams_1 = require("../core/sqlParams");
|
|
6
|
+
Object.defineProperty(exports, "extractNamedParams", { enumerable: true, get: function () { return sqlParams_1.extractNamedParams; } });
|
|
5
7
|
function createBinder(dialect) {
|
|
6
8
|
const placeholder = (indexRef) => {
|
|
7
9
|
if (dialect === 'postgres')
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sqlBinder.js","sourceRoot":"","sources":["../../../src/binders/sqlBinder.ts"],"names":[],"mappings":"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","sourcesContent":["export type BindResult = {\n sql: string;\n params: unknown[];\n};\n\nexport interface SqlBinder {\n bind(sql: string, args: Record<string, unknown> | unknown[]): BindResult;\n}\n\ntype Dialect = 'mysql' | 'sqlite' | 'postgres';\n\nexport function createBinder(dialect: Dialect): SqlBinder {\n const placeholder = (indexRef: { i: number }) => {\n if (dialect === 'postgres') return `$${indexRef.i++}`;\n return '?'; // mysql + sqlite\n };\n\n return {\n bind(sql: string, args: Record<string, unknown> | unknown[]): BindResult {\n const isArrayArgs = Array.isArray(args);\n const params: unknown[] = [];\n const out: string[] = [];\n\n let i = 0;\n let inSQ = false; // single quote string\n let inDQ = false; // double quote identifier\n let inLC = false; // line comment -- ...\\n\n let inBC = false; // block comment /* ... */\n const pgIndex = { i: 1 };\n\n let sawNamed = false;\n let sawPositional = false;\n\n const len = sql.length;\n while (i < len) {\n const ch = sql[i];\n const next = i + 1 < len ? sql[i + 1] : '';\n\n // Handle exiting comments/strings first\n if (inLC) {\n out.push(ch);\n i++;\n if (ch === '\\n') inLC = false;\n continue;\n }\n if (inBC) {\n out.push(ch);\n i++;\n if (ch === '*' && next === '/') {\n out.push(next);\n i++;\n inBC = false;\n }\n continue;\n }\n if (inSQ) {\n out.push(ch);\n i++;\n // escape '' inside string\n if (ch === \"'\" && next === \"'\") {\n out.push(next);\n i++;\n } else if (ch === \"'\") {\n inSQ = false;\n }\n continue;\n }\n if (inDQ) {\n out.push(ch);\n i++;\n // escape \"\" inside identifier\n if (ch === '\"' && next === '\"') {\n out.push(next);\n i++;\n } else if (ch === '\"') {\n inDQ = false;\n }\n continue;\n }\n\n // Not inside string/comment\n if (ch === '-' && next === '-') {\n out.push(ch, next);\n i += 2;\n inLC = true;\n continue;\n }\n if (ch === '/' && next === '*') {\n out.push(ch, next);\n i += 2;\n inBC = true;\n continue;\n }\n if (ch === \"'\") {\n out.push(ch);\n i++;\n inSQ = true;\n continue;\n }\n if (ch === '\"') {\n out.push(ch);\n i++;\n inDQ = true;\n continue;\n }\n\n // Postgres cast :: — skip as literal\n if (ch === ':' && next === ':') {\n out.push('::');\n i += 2;\n continue;\n }\n\n if (ch === ':') {\n // Attempt to parse a parameter token\n let j = i + 1;\n const start = j;\n while (j < len) {\n const c = sql[j];\n if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c === '_') {\n j++;\n } else {\n break;\n }\n }\n const name = sql.slice(start, j);\n if (!name) {\n // not a parameter — keep literal ':'\n out.push(':');\n i++;\n continue;\n }\n\n // Decide positional vs named\n const m = /^arg([1-9][0-9]*)$/.exec(name);\n const isPos = !!m;\n if (isPos) sawPositional = true; else sawNamed = true;\n if (sawNamed && sawPositional) {\n throw new Error('Cannot mix named and positional parameters in a single query');\n }\n\n let value: unknown;\n if (isPos) {\n if (!isArrayArgs) throw new Error('Positional placeholders require array arguments');\n const index = parseInt(m![1], 10) - 1; // 1-based in SQL\n const arr = args as unknown[];\n if (index < 0 || index >= arr.length) throw new Error(`Missing positional argument :${name}`);\n value = arr[index];\n } else {\n if (isArrayArgs) throw new Error('Named placeholders require a parameter object');\n const obj = args as Record<string, unknown>;\n if (!Object.prototype.hasOwnProperty.call(obj, name)) {\n throw new Error(`Missing named parameter :${name}`);\n }\n value = obj[name];\n }\n\n if (value === undefined) {\n throw new Error(`Parameter :${name} is undefined`);\n }\n\n // Expand placeholder(s)\n if (Array.isArray(value)) {\n if (value.length === 0) throw new Error(`Array parameter :${name} must not be empty`);\n const placeholders: string[] = [];\n for (const v of value) {\n if (v === undefined) throw new Error(`Array parameter :${name} contains undefined`);\n placeholders.push(placeholder(pgIndex));\n params.push(v === undefined ? null : v);\n }\n out.push(placeholders.join(', '));\n } else {\n out.push(placeholder(pgIndex));\n params.push(value === undefined ? null : value);\n }\n\n i = j;\n continue;\n }\n\n // default: copy char\n out.push(ch);\n i++;\n }\n\n return { sql: out.join(''), params };\n },\n };\n}\n\nexport const createMysqlBinder = () => createBinder('mysql');\nexport const createSqliteBinder = () => createBinder('sqlite');\nexport const createPostgresBinder = () => createBinder('postgres');\n"]}
|
|
1
|
+
{"version":3,"file":"sqlBinder.js","sourceRoot":"","sources":["../../../src/binders/sqlBinder.ts"],"names":[],"mappings":"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","sourcesContent":["import { extractNamedParams } from '../core/sqlParams';\n\nexport type BindResult = {\n sql: string;\n params: unknown[];\n};\n\nexport interface SqlBinder {\n bind(sql: string, args: Record<string, unknown> | unknown[]): BindResult;\n}\n\ntype Dialect = 'mysql' | 'sqlite' | 'postgres';\n\nexport function createBinder(dialect: Dialect): SqlBinder {\n const placeholder = (indexRef: { i: number }) => {\n if (dialect === 'postgres') return `$${indexRef.i++}`;\n return '?'; // mysql + sqlite\n };\n\n return {\n bind(sql: string, args: Record<string, unknown> | unknown[]): BindResult {\n const isArrayArgs = Array.isArray(args);\n const params: unknown[] = [];\n const out: string[] = [];\n\n let i = 0;\n let inSQ = false; // single quote string\n let inDQ = false; // double quote identifier\n let inLC = false; // line comment -- ...\\n\n let inBC = false; // block comment /* ... */\n const pgIndex = { i: 1 };\n\n let sawNamed = false;\n let sawPositional = false;\n\n const len = sql.length;\n while (i < len) {\n const ch = sql[i];\n const next = i + 1 < len ? sql[i + 1] : '';\n\n // Handle exiting comments/strings first\n if (inLC) {\n out.push(ch);\n i++;\n if (ch === '\\n') inLC = false;\n continue;\n }\n if (inBC) {\n out.push(ch);\n i++;\n if (ch === '*' && next === '/') {\n out.push(next);\n i++;\n inBC = false;\n }\n continue;\n }\n if (inSQ) {\n out.push(ch);\n i++;\n // escape '' inside string\n if (ch === \"'\" && next === \"'\") {\n out.push(next);\n i++;\n } else if (ch === \"'\") {\n inSQ = false;\n }\n continue;\n }\n if (inDQ) {\n out.push(ch);\n i++;\n // escape \"\" inside identifier\n if (ch === '\"' && next === '\"') {\n out.push(next);\n i++;\n } else if (ch === '\"') {\n inDQ = false;\n }\n continue;\n }\n\n // Not inside string/comment\n if (ch === '-' && next === '-') {\n out.push(ch, next);\n i += 2;\n inLC = true;\n continue;\n }\n if (ch === '/' && next === '*') {\n out.push(ch, next);\n i += 2;\n inBC = true;\n continue;\n }\n if (ch === \"'\") {\n out.push(ch);\n i++;\n inSQ = true;\n continue;\n }\n if (ch === '\"') {\n out.push(ch);\n i++;\n inDQ = true;\n continue;\n }\n\n // Postgres cast :: — skip as literal\n if (ch === ':' && next === ':') {\n out.push('::');\n i += 2;\n continue;\n }\n\n if (ch === ':') {\n // Attempt to parse a parameter token\n let j = i + 1;\n const start = j;\n while (j < len) {\n const c = sql[j];\n if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c === '_') {\n j++;\n } else {\n break;\n }\n }\n const name = sql.slice(start, j);\n if (!name) {\n // not a parameter — keep literal ':'\n out.push(':');\n i++;\n continue;\n }\n\n // Decide positional vs named\n const m = /^arg([1-9][0-9]*)$/.exec(name);\n const isPos = !!m;\n if (isPos) sawPositional = true; else sawNamed = true;\n if (sawNamed && sawPositional) {\n throw new Error('Cannot mix named and positional parameters in a single query');\n }\n\n let value: unknown;\n if (isPos) {\n if (!isArrayArgs) throw new Error('Positional placeholders require array arguments');\n const index = parseInt(m![1], 10) - 1; // 1-based in SQL\n const arr = args as unknown[];\n if (index < 0 || index >= arr.length) throw new Error(`Missing positional argument :${name}`);\n value = arr[index];\n } else {\n if (isArrayArgs) throw new Error('Named placeholders require a parameter object');\n const obj = args as Record<string, unknown>;\n if (!Object.prototype.hasOwnProperty.call(obj, name)) {\n throw new Error(`Missing named parameter :${name}`);\n }\n value = obj[name];\n }\n\n if (value === undefined) {\n throw new Error(`Parameter :${name} is undefined`);\n }\n\n // Expand placeholder(s)\n if (Array.isArray(value)) {\n if (value.length === 0) throw new Error(`Array parameter :${name} must not be empty`);\n const placeholders: string[] = [];\n for (const v of value) {\n if (v === undefined) throw new Error(`Array parameter :${name} contains undefined`);\n placeholders.push(placeholder(pgIndex));\n params.push(v === undefined ? null : v);\n }\n out.push(placeholders.join(', '));\n } else {\n out.push(placeholder(pgIndex));\n params.push(value === undefined ? null : value);\n }\n\n i = j;\n continue;\n }\n\n // default: copy char\n out.push(ch);\n i++;\n }\n\n return { sql: out.join(''), params };\n },\n };\n}\n\nexport const createMysqlBinder = () => createBinder('mysql');\nexport const createSqliteBinder = () => createBinder('sqlite');\nexport const createPostgresBinder = () => createBinder('postgres');\n\n// Re-export the shared helper for use in decorators\nexport { extractNamedParams };\n"]}
|
|
@@ -10,4 +10,8 @@ export declare class NoRowsError extends SqlStackError {
|
|
|
10
10
|
export declare class RowsExistError extends SqlStackError {
|
|
11
11
|
constructor(actualCount: number);
|
|
12
12
|
}
|
|
13
|
+
export declare class ValidationError extends SqlStackError {
|
|
14
|
+
constructor(details: string);
|
|
15
|
+
details: string;
|
|
16
|
+
}
|
|
13
17
|
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../src/core/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,aAAc,SAAQ,KAAK;gBAC1B,OAAO,CAAC,EAAE,MAAM;CAI7B;AAED,qBAAa,kBAAmB,SAAQ,aAAa;gBACvC,WAAW,EAAE,MAAM;CAIhC;AAED,qBAAa,WAAY,SAAQ,aAAa;;CAK7C;AAED,qBAAa,cAAe,SAAQ,aAAa;gBACnC,WAAW,EAAE,MAAM;CAIhC"}
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../src/core/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,aAAc,SAAQ,KAAK;gBAC1B,OAAO,CAAC,EAAE,MAAM;CAI7B;AAED,qBAAa,kBAAmB,SAAQ,aAAa;gBACvC,WAAW,EAAE,MAAM;CAIhC;AAED,qBAAa,WAAY,SAAQ,aAAa;;CAK7C;AAED,qBAAa,cAAe,SAAQ,aAAa;gBACnC,WAAW,EAAE,MAAM;CAIhC;AAED,qBAAa,eAAgB,SAAQ,aAAa;gBACpC,OAAO,EAAE,MAAM;IAK3B,OAAO,EAAE,MAAM,CAAC;CACjB"}
|
package/dist/cjs/core/errors.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.RowsExistError = exports.NoRowsError = exports.ExactlyOneRowError = exports.SqlStackError = void 0;
|
|
3
|
+
exports.ValidationError = exports.RowsExistError = exports.NoRowsError = exports.ExactlyOneRowError = exports.SqlStackError = void 0;
|
|
4
4
|
class SqlStackError extends Error {
|
|
5
5
|
constructor(message) {
|
|
6
6
|
super(message);
|
|
@@ -29,4 +29,12 @@ class RowsExistError extends SqlStackError {
|
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
31
|
exports.RowsExistError = RowsExistError;
|
|
32
|
+
class ValidationError extends SqlStackError {
|
|
33
|
+
constructor(details) {
|
|
34
|
+
super(`Validation failed: ${details}`);
|
|
35
|
+
this.details = details;
|
|
36
|
+
this.name = 'ValidationError';
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
exports.ValidationError = ValidationError;
|
|
32
40
|
//# sourceMappingURL=errors.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../../src/core/errors.ts"],"names":[],"mappings":";;;AAAA,MAAa,aAAc,SAAQ,KAAK;IACtC,YAAY,OAAgB;QAC1B,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;IAC9B,CAAC;CACF;AALD,sCAKC;AAED,MAAa,kBAAmB,SAAQ,aAAa;IACnD,YAAY,WAAmB;QAC7B,KAAK,CAAC,iCAAiC,WAAW,EAAE,CAAC,CAAC;QACtD,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC;IACnC,CAAC;CACF;AALD,gDAKC;AAED,MAAa,WAAY,SAAQ,aAAa;IAC5C;QACE,KAAK,CAAC,kCAAkC,CAAC,CAAC;QAC1C,IAAI,CAAC,IAAI,GAAG,aAAa,CAAC;IAC5B,CAAC;CACF;AALD,kCAKC;AAED,MAAa,cAAe,SAAQ,aAAa;IAC/C,YAAY,WAAmB;QAC7B,KAAK,CAAC,yBAAyB,WAAW,EAAE,CAAC,CAAC;QAC9C,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;IAC/B,CAAC;CACF;AALD,wCAKC","sourcesContent":["export class SqlStackError extends Error {\n constructor(message?: string) {\n super(message);\n this.name = 'SqlStackError';\n }\n}\n\nexport class ExactlyOneRowError extends SqlStackError {\n constructor(actualCount: number) {\n super(`Expected exactly one row, got ${actualCount}`);\n this.name = 'ExactlyOneRowError';\n }\n}\n\nexport class NoRowsError extends SqlStackError {\n constructor() {\n super('Expected at least one row, got 0');\n this.name = 'NoRowsError';\n }\n}\n\nexport class RowsExistError extends SqlStackError {\n constructor(actualCount: number) {\n super(`Expected no rows, got ${actualCount}`);\n this.name = 'RowsExistError';\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../../src/core/errors.ts"],"names":[],"mappings":";;;AAAA,MAAa,aAAc,SAAQ,KAAK;IACtC,YAAY,OAAgB;QAC1B,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;IAC9B,CAAC;CACF;AALD,sCAKC;AAED,MAAa,kBAAmB,SAAQ,aAAa;IACnD,YAAY,WAAmB;QAC7B,KAAK,CAAC,iCAAiC,WAAW,EAAE,CAAC,CAAC;QACtD,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC;IACnC,CAAC;CACF;AALD,gDAKC;AAED,MAAa,WAAY,SAAQ,aAAa;IAC5C;QACE,KAAK,CAAC,kCAAkC,CAAC,CAAC;QAC1C,IAAI,CAAC,IAAI,GAAG,aAAa,CAAC;IAC5B,CAAC;CACF;AALD,kCAKC;AAED,MAAa,cAAe,SAAQ,aAAa;IAC/C,YAAY,WAAmB;QAC7B,KAAK,CAAC,yBAAyB,WAAW,EAAE,CAAC,CAAC;QAC9C,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;IAC/B,CAAC;CACF;AALD,wCAKC;AAED,MAAa,eAAgB,SAAQ,aAAa;IAChD,YAAY,OAAe;QACzB,KAAK,CAAC,sBAAsB,OAAO,EAAE,CAAC,CAAC;QACvC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAC;IAChC,CAAC;CAEF;AAPD,0CAOC","sourcesContent":["export class SqlStackError extends Error {\n constructor(message?: string) {\n super(message);\n this.name = 'SqlStackError';\n }\n}\n\nexport class ExactlyOneRowError extends SqlStackError {\n constructor(actualCount: number) {\n super(`Expected exactly one row, got ${actualCount}`);\n this.name = 'ExactlyOneRowError';\n }\n}\n\nexport class NoRowsError extends SqlStackError {\n constructor() {\n super('Expected at least one row, got 0');\n this.name = 'NoRowsError';\n }\n}\n\nexport class RowsExistError extends SqlStackError {\n constructor(actualCount: number) {\n super(`Expected no rows, got ${actualCount}`);\n this.name = 'RowsExistError';\n }\n}\n\nexport class ValidationError extends SqlStackError {\n constructor(details: string) {\n super(`Validation failed: ${details}`);\n this.details = details;\n this.name = 'ValidationError';\n }\n details: string;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metadata.d.ts","sourceRoot":"","sources":["../../../src/core/metadata.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,YAAY,GAAG;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,KAAK,CAAC,EAAE,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;IAC7C,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,MAAM,CAAC,EAAE;QAAE,IAAI,EAAE,QAAQ,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,GAAG;QAAE,IAAI,EAAE,IAAI,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3E,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,GAAG,CAAC;IAC9B,IAAI,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"metadata.d.ts","sourceRoot":"","sources":["../../../src/core/metadata.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,YAAY,GAAG;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,KAAK,CAAC,EAAE,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;IAC7C,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,MAAM,CAAC,EAAE;QAAE,IAAI,EAAE,QAAQ,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,GAAG;QAAE,IAAI,EAAE,IAAI,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3E,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,GAAG,CAAC;IAC9B,IAAI,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;IAC5C,aAAa,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;CACxC,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,EAAE,CAAC,EAAE,MAAM,CAAC;CACb,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG;IACtB,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC,MAAM,GAAG,MAAM,EAAE,YAAY,CAAC,CAAC;CAChD,CAAC;AAEF,wBAAgB,OAAO,CAAC,MAAM,EAAE,GAAG,GAAG,SAAS,CAK9C;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,YAAY,CAAC,QAG/F;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,YAAY,CAGlF;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,OAAO,CAAC,WAAW,CAAC,QAGpE;AAED,wBAAgB,cAAc,CAAC,QAAQ,EAAE,GAAG,GAAG,WAAW,GAAG,SAAS,CAGrE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metadata.js","sourceRoot":"","sources":["../../../src/core/metadata.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"metadata.js","sourceRoot":"","sources":["../../../src/core/metadata.ts"],"names":[],"mappings":";;AAsBA,0BAKC;AAED,0CAGC;AAED,0CAGC;AAED,wCAGC;AAED,wCAGC;AA/CD,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;AAsBzC,SAAgB,OAAO,CAAC,MAAW;IACjC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;QAClB,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE,EAAe,CAAC;IAC9C,CAAC;IACD,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC;AACtB,CAAC;AAED,SAAgB,eAAe,CAAC,MAAW,EAAE,IAAqB,EAAE,KAA4B;IAC9F,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC7B,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,GAAG,KAAK,EAAE,CAAC;AACnE,CAAC;AAED,SAAgB,eAAe,CAAC,QAAa,EAAE,IAAqB;IAClE,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC,CAAC;IACtD,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;AAClC,CAAC;AAED,SAAgB,cAAc,CAAC,IAAS,EAAE,KAA2B;IACnE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACrC,IAAI,CAAC,KAAK,GAAG,EAAE,GAAG,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC,EAAE,GAAG,KAAK,EAAE,CAAC;AACnD,CAAC;AAED,SAAgB,cAAc,CAAC,QAAa;IAC1C,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC,CAAC;IACtD,OAAO,IAAI,CAAC,KAAK,CAAC;AACpB,CAAC","sourcesContent":["const META = Symbol.for('sqlstack:meta');\n\nexport type MethodLabels = {\n defaults?: Record<string, unknown>;\n shape?: 'single' | 'only' | 'exist' | 'none';\n validateSchema?: unknown;\n source?: { kind: 'inline'; sql: string } | { kind: 'fs'; rootDir: string };\n db?: string;\n transform?: (row: any) => any;\n page?: { size: number; zeroBase?: boolean };\n missingAsNull?: { require?: string[] };\n};\n\nexport type ClassLabels = {\n db?: string;\n};\n\nexport type MetaShape = {\n class?: ClassLabels;\n methods: Record<string | symbol, MethodLabels>;\n};\n\nexport function getMeta(target: any): MetaShape {\n if (!target[META]) {\n target[META] = { methods: {} } as MetaShape;\n }\n return target[META];\n}\n\nexport function setMethodLabels(target: any, prop: string | symbol, patch: Partial<MethodLabels>) {\n const meta = getMeta(target);\n meta.methods[prop] = { ...(meta.methods[prop] || {}), ...patch };\n}\n\nexport function getMethodLabels(instance: any, prop: string | symbol): MethodLabels {\n const meta = getMeta(Object.getPrototypeOf(instance));\n return meta.methods[prop] || {};\n}\n\nexport function setClassLabels(ctor: any, patch: Partial<ClassLabels>) {\n const meta = getMeta(ctor.prototype);\n meta.class = { ...(meta.class || {}), ...patch };\n}\n\nexport function getClassLabels(instance: any): ClassLabels | undefined {\n const meta = getMeta(Object.getPrototypeOf(instance));\n return meta.class;\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sqlParams.d.ts","sourceRoot":"","sources":["../../../src/core/sqlParams.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAsHxD"}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.extractNamedParams = extractNamedParams;
|
|
4
|
+
/**
|
|
5
|
+
* Extracts named parameter names from SQL.
|
|
6
|
+
* Ignores parameters in string literals and comments.
|
|
7
|
+
*/
|
|
8
|
+
function extractNamedParams(sql) {
|
|
9
|
+
const names = new Set();
|
|
10
|
+
let i = 0;
|
|
11
|
+
let inSQ = false; // single quote string
|
|
12
|
+
let inDQ = false; // double quote identifier
|
|
13
|
+
let inLC = false; // line comment -- ...\n
|
|
14
|
+
let inBC = false; // block comment /* ... */
|
|
15
|
+
const len = sql.length;
|
|
16
|
+
while (i < len) {
|
|
17
|
+
const ch = sql[i];
|
|
18
|
+
const next = i + 1 < len ? sql[i + 1] : '';
|
|
19
|
+
// Handle exiting comments/strings first
|
|
20
|
+
if (inLC) {
|
|
21
|
+
i++;
|
|
22
|
+
if (ch === '\n')
|
|
23
|
+
inLC = false;
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
if (inBC) {
|
|
27
|
+
i++;
|
|
28
|
+
if (ch === '*' && next === '/') {
|
|
29
|
+
i++;
|
|
30
|
+
inBC = false;
|
|
31
|
+
}
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
if (inSQ) {
|
|
35
|
+
i++;
|
|
36
|
+
// escape '' inside string
|
|
37
|
+
if (ch === "'" && next === "'") {
|
|
38
|
+
i++;
|
|
39
|
+
}
|
|
40
|
+
else if (ch === "'") {
|
|
41
|
+
inSQ = false;
|
|
42
|
+
}
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
if (inDQ) {
|
|
46
|
+
i++;
|
|
47
|
+
// escape "" inside identifier
|
|
48
|
+
if (ch === '"' && next === '"') {
|
|
49
|
+
i++;
|
|
50
|
+
}
|
|
51
|
+
else if (ch === '"') {
|
|
52
|
+
inDQ = false;
|
|
53
|
+
}
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
// Not inside string/comment
|
|
57
|
+
if (ch === '-' && next === '-') {
|
|
58
|
+
i += 2;
|
|
59
|
+
inLC = true;
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
if (ch === '/' && next === '*') {
|
|
63
|
+
i += 2;
|
|
64
|
+
inBC = true;
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
if (ch === "'") {
|
|
68
|
+
i++;
|
|
69
|
+
inSQ = true;
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
if (ch === '"') {
|
|
73
|
+
i++;
|
|
74
|
+
inDQ = true;
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
// Postgres cast :: — skip as literal
|
|
78
|
+
if (ch === ':' && next === ':') {
|
|
79
|
+
i += 2;
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
if (ch === ':') {
|
|
83
|
+
// Attempt to parse a parameter token
|
|
84
|
+
let j = i + 1;
|
|
85
|
+
const start = j;
|
|
86
|
+
// Parameter name must start with letter or underscore
|
|
87
|
+
if (j < len) {
|
|
88
|
+
const c = sql[j];
|
|
89
|
+
if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c === '_') {
|
|
90
|
+
j++;
|
|
91
|
+
// Continue with alphanumeric and underscore
|
|
92
|
+
while (j < len) {
|
|
93
|
+
const ch = sql[j];
|
|
94
|
+
if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9') || ch === '_') {
|
|
95
|
+
j++;
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
const name = sql.slice(start, j);
|
|
102
|
+
// Don't add positional parameters (argN)
|
|
103
|
+
const isPos = /^arg([1-9][0-9]*)$/.test(name);
|
|
104
|
+
if (!isPos) {
|
|
105
|
+
names.add(name);
|
|
106
|
+
}
|
|
107
|
+
i = j;
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
// Not a valid parameter name, keep the colon
|
|
112
|
+
i++;
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
// default: skip char
|
|
116
|
+
i++;
|
|
117
|
+
}
|
|
118
|
+
return Array.from(names);
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=sqlParams.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sqlParams.js","sourceRoot":"","sources":["../../../src/core/sqlParams.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Extracts named parameter names from SQL.\n * Ignores parameters in string literals and comments.\n */\nexport function extractNamedParams(sql: string): string[] {\n const names = new Set<string>();\n\n let i = 0;\n let inSQ = false; // single quote string\n let inDQ = false; // double quote identifier\n let inLC = false; // line comment -- ...\\n\n let inBC = false; // block comment /* ... */\n\n const len = sql.length;\n while (i < len) {\n const ch = sql[i];\n const next = i + 1 < len ? sql[i + 1] : '';\n\n // Handle exiting comments/strings first\n if (inLC) {\n i++;\n if (ch === '\\n') inLC = false;\n continue;\n }\n if (inBC) {\n i++;\n if (ch === '*' && next === '/') {\n i++;\n inBC = false;\n }\n continue;\n }\n if (inSQ) {\n i++;\n // escape '' inside string\n if (ch === \"'\" && next === \"'\") {\n i++;\n } else if (ch === \"'\") {\n inSQ = false;\n }\n continue;\n }\n if (inDQ) {\n i++;\n // escape \"\" inside identifier\n if (ch === '\"' && next === '\"') {\n i++;\n } else if (ch === '\"') {\n inDQ = false;\n }\n continue;\n }\n\n // Not inside string/comment\n if (ch === '-' && next === '-') {\n i += 2;\n inLC = true;\n continue;\n }\n if (ch === '/' && next === '*') {\n i += 2;\n inBC = true;\n continue;\n }\n if (ch === \"'\") {\n i++;\n inSQ = true;\n continue;\n }\n if (ch === '\"') {\n i++;\n inDQ = true;\n continue;\n }\n\n // Postgres cast :: — skip as literal\n if (ch === ':' && next === ':') {\n i += 2;\n continue;\n }\n\n if (ch === ':') {\n // Attempt to parse a parameter token\n let j = i + 1;\n const start = j;\n\n // Parameter name must start with letter or underscore\n if (j < len) {\n const c = sql[j];\n if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c === '_') {\n j++;\n // Continue with alphanumeric and underscore\n while (j < len) {\n const ch = sql[j];\n if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9') || ch === '_') {\n j++;\n } else {\n break;\n }\n }\n\n const name = sql.slice(start, j);\n // Don't add positional parameters (argN)\n const isPos = /^arg([1-9][0-9]*)$/.test(name);\n if (!isPos) {\n names.add(name);\n }\n i = j;\n continue;\n }\n }\n\n // Not a valid parameter name, keep the colon\n i++;\n continue;\n }\n\n // default: skip char\n i++;\n }\n\n return Array.from(names);\n}\n"]}
|
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
import { SqlStackError } from './errors';
|
|
2
|
-
export declare class ValidationError extends SqlStackError {
|
|
3
|
-
details: string;
|
|
4
|
-
constructor(details: string);
|
|
5
|
-
}
|
|
6
1
|
export declare function validateOutput(schema: any, data: any): void;
|
|
7
2
|
export declare function isValidationDisabled(): boolean;
|
|
8
3
|
//# sourceMappingURL=validator.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../../../src/core/validator.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../../../src/core/validator.ts"],"names":[],"mappings":"AAoBA,wBAAgB,cAAc,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,QAOpD;AAgBD,wBAAgB,oBAAoB,IAAI,OAAO,CAO9C"}
|
|
@@ -3,20 +3,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.ValidationError = void 0;
|
|
7
6
|
exports.validateOutput = validateOutput;
|
|
8
7
|
exports.isValidationDisabled = isValidationDisabled;
|
|
9
8
|
const ajv_1 = __importDefault(require("ajv"));
|
|
10
9
|
const ajv_formats_1 = __importDefault(require("ajv-formats"));
|
|
11
10
|
const errors_1 = require("./errors");
|
|
12
|
-
class ValidationError extends errors_1.SqlStackError {
|
|
13
|
-
constructor(details) {
|
|
14
|
-
super(`Validation failed: ${details}`);
|
|
15
|
-
this.details = details;
|
|
16
|
-
this.name = 'ValidationError';
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
exports.ValidationError = ValidationError;
|
|
20
11
|
const ajv = new ajv_1.default({ allErrors: true, strict: false });
|
|
21
12
|
(0, ajv_formats_1.default)(ajv);
|
|
22
13
|
const cache = new WeakMap();
|
|
@@ -29,14 +20,14 @@ function getValidator(schema) {
|
|
|
29
20
|
cache.set(schema, compiled);
|
|
30
21
|
return compiled;
|
|
31
22
|
}
|
|
32
|
-
throw new ValidationError('Invalid schema');
|
|
23
|
+
throw new errors_1.ValidationError('Invalid schema');
|
|
33
24
|
}
|
|
34
25
|
function validateOutput(schema, data) {
|
|
35
26
|
const validate = getValidator(schema);
|
|
36
27
|
const ok = validate(data);
|
|
37
28
|
if (!ok) {
|
|
38
29
|
const msg = ajv.errorsText(validate.errors, { dataVar: 'result' });
|
|
39
|
-
throw new ValidationError(msg);
|
|
30
|
+
throw new errors_1.ValidationError(msg);
|
|
40
31
|
}
|
|
41
32
|
}
|
|
42
33
|
function isTruthyEnv(value) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validator.js","sourceRoot":"","sources":["../../../src/core/validator.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"validator.js","sourceRoot":"","sources":["../../../src/core/validator.ts"],"names":[],"mappings":";;;;;AAoBA,wCAOC;AAgBD,oDAOC;AAlDD,8CAAwC;AACxC,8DAAqC;AACrC,qCAA2C;AAE3C,MAAM,GAAG,GAAG,IAAI,aAAG,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;AACxD,IAAA,qBAAU,EAAC,GAAG,CAAC,CAAC;AAEhB,MAAM,KAAK,GAAG,IAAI,OAAO,EAAsC,CAAC;AAEhE,SAAS,YAAY,CAAC,MAAW;IAC/B,IAAI,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;QACzC,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,MAAgB,CAAC,CAAC;QAC7C,IAAI,QAAQ;YAAE,OAAO,QAAQ,CAAC;QAC9B,MAAM,QAAQ,GAAG,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QACrC,KAAK,CAAC,GAAG,CAAC,MAAgB,EAAE,QAAQ,CAAC,CAAC;QACtC,OAAO,QAAQ,CAAC;IAClB,CAAC;IACD,MAAM,IAAI,wBAAe,CAAC,gBAAgB,CAAC,CAAC;AAC9C,CAAC;AAED,SAAgB,cAAc,CAAC,MAAW,EAAE,IAAS;IACnD,MAAM,QAAQ,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;IACtC,MAAM,EAAE,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC1B,IAAI,CAAC,EAAE,EAAE,CAAC;QACR,MAAM,GAAG,GAAG,GAAG,CAAC,UAAU,CAAC,QAAQ,CAAC,MAA+B,EAAE,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAC;QAC5F,MAAM,IAAI,wBAAe,CAAC,GAAG,CAAC,CAAC;IACjC,CAAC;AACH,CAAC;AAED,SAAS,WAAW,CAAC,KAAyB;IAC5C,IAAI,CAAC,KAAK;QAAE,OAAO,KAAK,CAAC;IACzB,QAAQ,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;QAC5B,KAAK,GAAG,CAAC;QACT,KAAK,MAAM,CAAC;QACZ,KAAK,KAAK,CAAC;QACX,KAAK,IAAI;YACP,OAAO,IAAI,CAAC;QACd;YACE,OAAO,KAAK,CAAC;IACjB,CAAC;AACH,CAAC;AAED,mEAAmE;AACnE,SAAgB,oBAAoB;IAClC,8DAA8D;IAC9D,IAAI,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,0BAA0B,CAAC;QAAE,OAAO,KAAK,CAAC;IACtE,yBAAyB;IACzB,IAAI,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,2BAA2B,CAAC;QAAE,OAAO,IAAI,CAAC;IACtE,uCAAuC;IACvC,OAAO,KAAK,CAAC;AACf,CAAC","sourcesContent":["import Ajv, { DefinedError } from 'ajv';\nimport addFormats from 'ajv-formats';\nimport { ValidationError } from './errors';\n\nconst ajv = new Ajv({ allErrors: true, strict: false });\naddFormats(ajv);\n\nconst cache = new WeakMap<object, ReturnType<Ajv['compile']>>();\n\nfunction getValidator(schema: any) {\n if (schema && typeof schema === 'object') {\n const existing = cache.get(schema as object);\n if (existing) return existing;\n const compiled = ajv.compile(schema);\n cache.set(schema as object, compiled);\n return compiled;\n }\n throw new ValidationError('Invalid schema');\n}\n\nexport function validateOutput(schema: any, data: any) {\n const validate = getValidator(schema);\n const ok = validate(data);\n if (!ok) {\n const msg = ajv.errorsText(validate.errors as DefinedError[] | null, { dataVar: 'result' });\n throw new ValidationError(msg);\n }\n}\n\nfunction isTruthyEnv(value: string | undefined): boolean {\n if (!value) return false;\n switch (value.toLowerCase()) {\n case '1':\n case 'true':\n case 'yes':\n case 'on':\n return true;\n default:\n return false;\n }\n}\n\n// SQLSTACK_DISABLE_VALIDATION: when truthy, validation is skipped.\nexport function isValidationDisabled(): boolean {\n // Highest priority: explicit enable wins (even in production)\n if (isTruthyEnv(process.env.SQLSTACK_ENABLE_VALIDATION)) return false;\n // Next: explicit disable\n if (isTruthyEnv(process.env.SQLSTACK_DISABLE_VALIDATION)) return true;\n // Default: enabled in all environments\n return false;\n}\n"]}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export interface MissingAsNullOptions {
|
|
2
|
+
/**
|
|
3
|
+
* Array of parameter names that must not be null.
|
|
4
|
+
* If a required parameter is missing or undefined, an error will be thrown.
|
|
5
|
+
*/
|
|
6
|
+
require?: string[];
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Decorator that enables automatic binding of missing or undefined named SQL parameters as NULL.
|
|
10
|
+
*
|
|
11
|
+
* By default (without this decorator), missing/undefined parameters throw an error.
|
|
12
|
+
* With @MissingAsNull, they are bound as NULL instead, allowing SQL functions like
|
|
13
|
+
* COALESCE/IFNULL to provide fallback values for partial updates.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```
|
|
17
|
+
* @MissingAsNull()
|
|
18
|
+
* async updateUser(args: { id: string; name?: string; email?: string }) {
|
|
19
|
+
* // Parameters not provided are bound as NULL
|
|
20
|
+
* // SQL can use COALESCE: COALESCE(:name, name) keeps old name if :name is NULL
|
|
21
|
+
* }
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```
|
|
26
|
+
* @MissingAsNull({ require: ['id'] })
|
|
27
|
+
* async updateUser(args: { id: string; name?: string }) {
|
|
28
|
+
* // 'id' is required; missing it throws
|
|
29
|
+
* // 'name' is optional; if missing, bound as NULL
|
|
30
|
+
* }
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export declare function MissingAsNull(options?: MissingAsNullOptions): (target: any, propertyKey: string | symbol, descriptor: PropertyDescriptor) => PropertyDescriptor;
|
|
34
|
+
//# sourceMappingURL=missingAsNull.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"missingAsNull.d.ts","sourceRoot":"","sources":["../../../src/decorators/missingAsNull.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,oBAAoB;IACnC;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,aAAa,CAAC,OAAO,CAAC,EAAE,oBAAoB,IACzC,QAAQ,GAAG,EAAE,aAAa,MAAM,GAAG,MAAM,EAAE,YAAY,kBAAkB,wBAQ3F"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MissingAsNull = MissingAsNull;
|
|
4
|
+
const metadata_1 = require("../core/metadata");
|
|
5
|
+
/**
|
|
6
|
+
* Decorator that enables automatic binding of missing or undefined named SQL parameters as NULL.
|
|
7
|
+
*
|
|
8
|
+
* By default (without this decorator), missing/undefined parameters throw an error.
|
|
9
|
+
* With @MissingAsNull, they are bound as NULL instead, allowing SQL functions like
|
|
10
|
+
* COALESCE/IFNULL to provide fallback values for partial updates.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```
|
|
14
|
+
* @MissingAsNull()
|
|
15
|
+
* async updateUser(args: { id: string; name?: string; email?: string }) {
|
|
16
|
+
* // Parameters not provided are bound as NULL
|
|
17
|
+
* // SQL can use COALESCE: COALESCE(:name, name) keeps old name if :name is NULL
|
|
18
|
+
* }
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```
|
|
23
|
+
* @MissingAsNull({ require: ['id'] })
|
|
24
|
+
* async updateUser(args: { id: string; name?: string }) {
|
|
25
|
+
* // 'id' is required; missing it throws
|
|
26
|
+
* // 'name' is optional; if missing, bound as NULL
|
|
27
|
+
* }
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
function MissingAsNull(options) {
|
|
31
|
+
return function (target, propertyKey, descriptor) {
|
|
32
|
+
(0, metadata_1.setMethodLabels)(target, propertyKey, {
|
|
33
|
+
missingAsNull: {
|
|
34
|
+
require: options?.require,
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
return descriptor;
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=missingAsNull.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"missingAsNull.js","sourceRoot":"","sources":["../../../src/decorators/missingAsNull.ts"],"names":[],"mappings":";;AAmCA,sCASC;AA5CD,+CAAmD;AAUnD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,SAAgB,aAAa,CAAC,OAA8B;IAC1D,OAAO,UAAU,MAAW,EAAE,WAA4B,EAAE,UAA8B;QACxF,IAAA,0BAAe,EAAC,MAAM,EAAE,WAAW,EAAE;YACnC,aAAa,EAAE;gBACb,OAAO,EAAE,OAAO,EAAE,OAAO;aAC1B;SACF,CAAC,CAAC;QACH,OAAO,UAAU,CAAC;IACpB,CAAC,CAAC;AACJ,CAAC","sourcesContent":["import { setMethodLabels } from '../core/metadata';\n\nexport interface MissingAsNullOptions {\n /**\n * Array of parameter names that must not be null.\n * If a required parameter is missing or undefined, an error will be thrown.\n */\n require?: string[];\n}\n\n/**\n * Decorator that enables automatic binding of missing or undefined named SQL parameters as NULL.\n *\n * By default (without this decorator), missing/undefined parameters throw an error.\n * With @MissingAsNull, they are bound as NULL instead, allowing SQL functions like\n * COALESCE/IFNULL to provide fallback values for partial updates.\n *\n * @example\n * ```\n * @MissingAsNull()\n * async updateUser(args: { id: string; name?: string; email?: string }) {\n * // Parameters not provided are bound as NULL\n * // SQL can use COALESCE: COALESCE(:name, name) keeps old name if :name is NULL\n * }\n * ```\n *\n * @example\n * ```\n * @MissingAsNull({ require: ['id'] })\n * async updateUser(args: { id: string; name?: string }) {\n * // 'id' is required; missing it throws\n * // 'name' is optional; if missing, bound as NULL\n * }\n * ```\n */\nexport function MissingAsNull(options?: MissingAsNullOptions) {\n return function (target: any, propertyKey: string | symbol, descriptor: PropertyDescriptor) {\n setMethodLabels(target, propertyKey, {\n missingAsNull: {\n require: options?.require,\n },\n });\n return descriptor;\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,wBAmO/E"}
|
|
@@ -59,6 +59,29 @@ function Query(arg) {
|
|
|
59
59
|
const namedBase = callArgs.length > 0 ? callArgs[0] : undefined;
|
|
60
60
|
args = applyDefaults(labels.defaults, namedBase ?? {});
|
|
61
61
|
}
|
|
62
|
+
// Handle @MissingAsNull before pagination
|
|
63
|
+
const missingAsNullCfg = labels.missingAsNull;
|
|
64
|
+
if (missingAsNullCfg && !hasPositional) {
|
|
65
|
+
// Only for named parameters
|
|
66
|
+
const namedParams = (0, sqlBinder_1.extractNamedParams)(workingSql);
|
|
67
|
+
const namedArgs = args;
|
|
68
|
+
const required = new Set(missingAsNullCfg.require || []);
|
|
69
|
+
// Check required parameters (missing or undefined)
|
|
70
|
+
for (const param of required) {
|
|
71
|
+
if (!(param in namedArgs) || namedArgs[param] === undefined) {
|
|
72
|
+
throw new errors_1.SqlStackError(`Missing required parameter :${param}`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
// Bind missing/undefined parameters as NULL
|
|
76
|
+
for (const param of namedParams) {
|
|
77
|
+
if (!(param in namedArgs)) {
|
|
78
|
+
namedArgs[param] = null;
|
|
79
|
+
}
|
|
80
|
+
else if (namedArgs[param] === undefined) {
|
|
81
|
+
namedArgs[param] = null;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
62
85
|
// Compute paging and inject :offset/:limit (named mode) or rewrite to positional
|
|
63
86
|
const pageCfg = labels.page;
|
|
64
87
|
if (pageCfg) {
|