sqlstack 1.0.6 → 1.0.7

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.
@@ -11,6 +11,10 @@ export type MethodLabels = {
11
11
  };
12
12
  db?: string;
13
13
  transform?: (row: any) => any;
14
+ page?: {
15
+ size: number;
16
+ zeroBase?: boolean;
17
+ };
14
18
  };
15
19
  export type ClassLabels = {
16
20
  db?: string;
@@ -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;CAC/B,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
+ {"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;CAC7C,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":";;AAoBA,0BAKC;AAED,0CAGC;AAED,0CAGC;AAED,wCAGC;AAED,wCAGC;AA7CD,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;AAoBzC,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};\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"]}
1
+ {"version":3,"file":"metadata.js","sourceRoot":"","sources":["../../src/core/metadata.ts"],"names":[],"mappings":";;AAqBA,0BAKC;AAED,0CAGC;AAED,0CAGC;AAED,wCAGC;AAED,wCAGC;AA9CD,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;AAqBzC,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};\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,8 @@
1
+ export type PageOptions = {
2
+ zeroBase?: boolean;
3
+ };
4
+ export declare function Page(size: number, options?: PageOptions): (_target: any, prop: string | symbol) => void;
5
+ export interface PageOption {
6
+ page?: number;
7
+ }
8
+ //# sourceMappingURL=page.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"page.d.ts","sourceRoot":"","sources":["../../src/decorators/page.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,WAAW,GAAG;IACxB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,CAAC;AAEF,wBAAgB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,IACrC,SAAS,GAAG,EAAE,MAAM,MAAM,GAAG,MAAM,UAIrD;AAID,MAAM,WAAW,UAAU;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf"}
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Page = Page;
4
+ const metadata_1 = require("../core/metadata");
5
+ function Page(size, options) {
6
+ return function (_target, prop) {
7
+ const zeroBase = options?.zeroBase === true;
8
+ (0, metadata_1.setMethodLabels)(_target, prop, { page: { size, zeroBase } });
9
+ };
10
+ }
11
+ //# sourceMappingURL=page.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"page.js","sourceRoot":"","sources":["../../src/decorators/page.ts"],"names":[],"mappings":";;AAMA,oBAKC;AAXD,+CAAmD;AAMnD,SAAgB,IAAI,CAAC,IAAY,EAAE,OAAqB;IACtD,OAAO,UAAU,OAAY,EAAE,IAAqB;QAClD,MAAM,QAAQ,GAAG,OAAO,EAAE,QAAQ,KAAK,IAAI,CAAC;QAC5C,IAAA,0BAAe,EAAC,OAAO,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC;IAC/D,CAAC,CAAC;AACJ,CAAC","sourcesContent":["import { setMethodLabels } from '../core/metadata';\n\nexport type PageOptions = {\n zeroBase?: boolean; // default false → pages are 1-based\n};\n\nexport function Page(size: number, options?: PageOptions) {\n return function (_target: any, prop: string | symbol) {\n const zeroBase = options?.zeroBase === true;\n setMethodLabels(_target, prop, { page: { size, zeroBase } });\n };\n}\n\n// Runtime options object users can pass as the final argument\n// e.g. repo.list(userId, { page: 2 }) or repo.list({ user_id: 'u1' }, { page: 2 })\nexport interface PageOption {\n page?: number;\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,wBA2E/E"}
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,wBA0M/E"}
@@ -48,10 +48,185 @@ function Query(arg) {
48
48
  }
49
49
  // 4) bind placeholders
50
50
  // Decide argument mode: positional if SQL contains :argN
51
- const hasPositional = /:arg[1-9][0-9]*/.test(sql);
52
- const args = hasPositional ? callArgs : applyDefaults(labels.defaults, rawInput);
51
+ let workingSql = sql;
52
+ const hasPositional = /:arg[1-9][0-9]*/.test(workingSql);
53
+ // Prepare args for binder
54
+ let args;
55
+ if (hasPositional) {
56
+ args = callArgs;
57
+ }
58
+ else {
59
+ const namedBase = callArgs.length > 0 ? callArgs[0] : undefined;
60
+ args = applyDefaults(labels.defaults, namedBase ?? {});
61
+ }
62
+ // Compute paging and inject :offset/:limit (named mode) or rewrite to positional
63
+ const pageCfg = labels.page;
64
+ if (pageCfg) {
65
+ const { size, zeroBase } = pageCfg;
66
+ const base = zeroBase ? 0 : 1;
67
+ // Extract page number from input (object) or a trailing options object in positional mode
68
+ const pageFromObject = (val) => {
69
+ if (val && typeof val === 'object' && !Array.isArray(val) && typeof val.page !== 'undefined') {
70
+ const p = val.page;
71
+ if (typeof p === 'number' && isFinite(p))
72
+ return p;
73
+ }
74
+ return undefined;
75
+ };
76
+ let pageNum;
77
+ if (hasPositional) {
78
+ // Variadic-style: only the LAST argument may carry `{ page }`
79
+ if (callArgs.length > 0) {
80
+ const last = callArgs[callArgs.length - 1];
81
+ pageNum = pageFromObject(last);
82
+ }
83
+ }
84
+ else {
85
+ // Prefer last-arg options if provided; otherwise read from named object
86
+ if (callArgs.length > 1) {
87
+ const last = callArgs[callArgs.length - 1];
88
+ pageNum = pageFromObject(last);
89
+ }
90
+ if (pageNum === undefined) {
91
+ pageNum = pageFromObject(args);
92
+ }
93
+ }
94
+ const effectivePage = typeof pageNum === 'number' ? pageNum : base;
95
+ const offset = (effectivePage - base) * size;
96
+ const limit = size;
97
+ if (hasPositional) {
98
+ // Replace occurrences of :offset and :limit with new :argN tokens appended to args
99
+ const baseIndex = callArgs.length; // start numbering after user args
100
+ let nextIndex = baseIndex + 1;
101
+ const additions = [];
102
+ const rewrite = (sqlText) => {
103
+ const out = [];
104
+ let i = 0;
105
+ let inSQ = false, inDQ = false, inLC = false, inBC = false;
106
+ const len = sqlText.length;
107
+ while (i < len) {
108
+ const ch = sqlText[i];
109
+ const next = i + 1 < len ? sqlText[i + 1] : '';
110
+ if (inLC) {
111
+ out.push(ch);
112
+ if (ch === '\n')
113
+ inLC = false;
114
+ i++;
115
+ continue;
116
+ }
117
+ if (inBC) {
118
+ out.push(ch);
119
+ if (ch === '*' && next === '/') {
120
+ out.push(next);
121
+ i++;
122
+ inBC = false;
123
+ }
124
+ i++;
125
+ continue;
126
+ }
127
+ if (inSQ) {
128
+ out.push(ch);
129
+ if (ch === "'" && next === "'") {
130
+ out.push(next);
131
+ i += 2;
132
+ continue;
133
+ }
134
+ if (ch === "'")
135
+ inSQ = false;
136
+ i++;
137
+ continue;
138
+ }
139
+ if (inDQ) {
140
+ out.push(ch);
141
+ if (ch === '"' && next === '"') {
142
+ out.push(next);
143
+ i += 2;
144
+ continue;
145
+ }
146
+ if (ch === '"')
147
+ inDQ = false;
148
+ i++;
149
+ continue;
150
+ }
151
+ if (ch === '-' && next === '-') {
152
+ out.push(ch, next);
153
+ i += 2;
154
+ inLC = true;
155
+ continue;
156
+ }
157
+ if (ch === '/' && next === '*') {
158
+ out.push(ch, next);
159
+ i += 2;
160
+ inBC = true;
161
+ continue;
162
+ }
163
+ if (ch === '"') {
164
+ out.push(ch);
165
+ inDQ = true;
166
+ i++;
167
+ continue;
168
+ }
169
+ if (ch === "'") {
170
+ out.push(ch);
171
+ inSQ = true;
172
+ i++;
173
+ continue;
174
+ }
175
+ if (ch === ':' && next === ':') {
176
+ out.push('::');
177
+ i += 2;
178
+ continue;
179
+ }
180
+ if (ch === ':') {
181
+ // parse token
182
+ let j = i + 1;
183
+ const start = j;
184
+ while (j < len) {
185
+ const c = sqlText[j];
186
+ if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c === '_')
187
+ j++;
188
+ else
189
+ break;
190
+ }
191
+ const name = sqlText.slice(start, j);
192
+ if (name === 'offset') {
193
+ const token = `:arg${nextIndex++}`;
194
+ out.push(token);
195
+ additions.push(offset);
196
+ i = j;
197
+ continue;
198
+ }
199
+ if (name === 'limit') {
200
+ const token = `:arg${nextIndex++}`;
201
+ out.push(token);
202
+ additions.push(limit);
203
+ i = j;
204
+ continue;
205
+ }
206
+ // otherwise leave untouched
207
+ out.push(':');
208
+ i++;
209
+ continue;
210
+ }
211
+ out.push(ch);
212
+ i++;
213
+ }
214
+ return out.join('');
215
+ };
216
+ const rewritten = rewrite(workingSql);
217
+ if (rewritten !== workingSql) {
218
+ workingSql = rewritten;
219
+ // append values so :argK map correctly
220
+ args.push(...additions);
221
+ }
222
+ }
223
+ else {
224
+ // Named-mode: attach computed values (override any provided)
225
+ args = { ...args, offset, limit };
226
+ }
227
+ }
53
228
  const binder = dialect === 'postgres' ? (0, sqlBinder_1.createPostgresBinder)() : dialect === 'mysql' ? (0, sqlBinder_1.createMysqlBinder)() : (0, sqlBinder_1.createSqliteBinder)();
54
- const { sql: boundSql, params } = binder.bind(sql, args);
229
+ const { sql: boundSql, params } = binder.bind(workingSql, args);
55
230
  // 5) execute query via registry DB
56
231
  const out = await db.query(boundSql, params);
57
232
  // 6) If rows were returned (SELECT/CTE), shape + transform + validate
@@ -1 +1 @@
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 + transform + validate\n if (Array.isArray(out)) {\n const shaped = applyShape(out, labels.shape);\n const transformed = labels.transform ? labels.transform(shaped) : shaped;\n\n // 7) validate result via JSON Schema, if provided\n if (labels.validateSchema && !isValidationDisabled()) {\n if (Array.isArray(transformed)) {\n for (const row of transformed) validateOutput(labels.validateSchema, row);\n } else if (transformed !== null && transformed !== undefined) {\n validateOutput(labels.validateSchema, transformed);\n }\n }\n return transformed;\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"]}
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 let workingSql = sql;\n const hasPositional = /:arg[1-9][0-9]*/.test(workingSql);\n\n // Prepare args for binder\n let args: any;\n if (hasPositional) {\n args = callArgs;\n } else {\n const namedBase = callArgs.length > 0 ? callArgs[0] : undefined;\n args = applyDefaults(labels.defaults, namedBase ?? {});\n }\n\n // Compute paging and inject :offset/:limit (named mode) or rewrite to positional\n const pageCfg = labels.page;\n if (pageCfg) {\n const { size, zeroBase } = pageCfg;\n const base = zeroBase ? 0 : 1;\n\n // Extract page number from input (object) or a trailing options object in positional mode\n const pageFromObject = (val: any): number | undefined => {\n if (val && typeof val === 'object' && !Array.isArray(val) && typeof (val as any).page !== 'undefined') {\n const p = (val as any).page;\n if (typeof p === 'number' && isFinite(p)) return p;\n }\n return undefined;\n };\n\n let pageNum: number | undefined;\n if (hasPositional) {\n // Variadic-style: only the LAST argument may carry `{ page }`\n if (callArgs.length > 0) {\n const last = callArgs[callArgs.length - 1];\n pageNum = pageFromObject(last);\n }\n } else {\n // Prefer last-arg options if provided; otherwise read from named object\n if (callArgs.length > 1) {\n const last = callArgs[callArgs.length - 1];\n pageNum = pageFromObject(last);\n }\n if (pageNum === undefined) {\n pageNum = pageFromObject(args);\n }\n }\n\n const effectivePage = typeof pageNum === 'number' ? pageNum : base;\n const offset = (effectivePage - base) * size;\n const limit = size;\n\n if (hasPositional) {\n // Replace occurrences of :offset and :limit with new :argN tokens appended to args\n const baseIndex = callArgs.length; // start numbering after user args\n let nextIndex = baseIndex + 1;\n const additions: unknown[] = [];\n\n const rewrite = (sqlText: string) => {\n const out: string[] = [];\n let i = 0;\n let inSQ = false, inDQ = false, inLC = false, inBC = false;\n const len = sqlText.length;\n while (i < len) {\n const ch = sqlText[i];\n const next = i + 1 < len ? sqlText[i + 1] : '';\n if (inLC) { out.push(ch); if (ch === '\\n') inLC = false; i++; continue; }\n if (inBC) { out.push(ch); if (ch === '*' && next === '/') { out.push(next); i++; inBC = false; } i++; continue; }\n if (inSQ) {\n out.push(ch);\n if (ch === \"'\" && next === \"'\") { out.push(next); i += 2; continue; }\n if (ch === \"'\") inSQ = false;\n i++;\n continue;\n }\n if (inDQ) {\n out.push(ch);\n if (ch === '\"' && next === '\"') { out.push(next); i += 2; continue; }\n if (ch === '\"') inDQ = false;\n i++;\n continue;\n }\n if (ch === '-' && next === '-') { out.push(ch, next); i += 2; inLC = true; continue; }\n if (ch === '/' && next === '*') { out.push(ch, next); i += 2; inBC = true; continue; }\n if (ch === '\"') { out.push(ch); inDQ = true; i++; continue; }\n if (ch === \"'\") { out.push(ch); inSQ = true; i++; continue; }\n if (ch === ':' && next === ':') { out.push('::'); i += 2; continue; }\n if (ch === ':') {\n // parse token\n let j = i + 1;\n const start = j;\n while (j < len) {\n const c = sqlText[j];\n if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c === '_') j++; else break;\n }\n const name = sqlText.slice(start, j);\n if (name === 'offset') {\n const token = `:arg${nextIndex++}`;\n out.push(token);\n additions.push(offset);\n i = j;\n continue;\n }\n if (name === 'limit') {\n const token = `:arg${nextIndex++}`;\n out.push(token);\n additions.push(limit);\n i = j;\n continue;\n }\n // otherwise leave untouched\n out.push(':');\n i++;\n continue;\n }\n out.push(ch);\n i++;\n }\n return out.join('');\n };\n\n const rewritten = rewrite(workingSql);\n if (rewritten !== workingSql) {\n workingSql = rewritten;\n // append values so :argK map correctly\n (args as unknown[]).push(...additions);\n }\n } else {\n // Named-mode: attach computed values (override any provided)\n args = { ...(args as Record<string, unknown>), offset, limit };\n }\n }\n const binder =\n dialect === 'postgres' ? createPostgresBinder() : dialect === 'mysql' ? createMysqlBinder() : createSqliteBinder();\n const { sql: boundSql, params } = binder.bind(workingSql, 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 + transform + validate\n if (Array.isArray(out)) {\n const shaped = applyShape(out, labels.shape);\n const transformed = labels.transform ? labels.transform(shaped) : shaped;\n\n // 7) validate result via JSON Schema, if provided\n if (labels.validateSchema && !isValidationDisabled()) {\n if (Array.isArray(transformed)) {\n for (const row of transformed) validateOutput(labels.validateSchema, row);\n } else if (transformed !== null && transformed !== undefined) {\n validateOutput(labels.validateSchema, transformed);\n }\n }\n return transformed;\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/index.d.ts CHANGED
@@ -9,5 +9,6 @@ export * from './decorators/defaults';
9
9
  export * from './decorators/resultShape';
10
10
  export * from './decorators/validateResult';
11
11
  export * from './decorators/transform';
12
+ export * from './decorators/page';
12
13
  export * from './utils/dto';
13
14
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,0BAA0B,CAAC;AACzC,cAAc,oBAAoB,CAAC;AACnC,cAAc,uBAAuB,CAAC;AACtC,cAAc,0BAA0B,CAAC;AACzC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,wBAAwB,CAAC;AACvC,cAAc,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,0BAA0B,CAAC;AACzC,cAAc,oBAAoB,CAAC;AACnC,cAAc,uBAAuB,CAAC;AACtC,cAAc,0BAA0B,CAAC;AACzC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,wBAAwB,CAAC;AACvC,cAAc,mBAAmB,CAAC;AAClC,cAAc,aAAa,CAAC"}
package/dist/index.js CHANGED
@@ -25,5 +25,6 @@ __exportStar(require("./decorators/defaults"), exports);
25
25
  __exportStar(require("./decorators/resultShape"), exports);
26
26
  __exportStar(require("./decorators/validateResult"), exports);
27
27
  __exportStar(require("./decorators/transform"), exports);
28
+ __exportStar(require("./decorators/page"), exports);
28
29
  __exportStar(require("./utils/dto"), exports);
29
30
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,sDAAoC;AACpC,gDAA8B;AAC9B,mDAAiC;AACjC,6CAA2B;AAC3B,6CAA2B;AAC3B,2DAAyC;AACzC,qDAAmC;AACnC,wDAAsC;AACtC,2DAAyC;AACzC,8DAA4C;AAC5C,yDAAuC;AACvC,8CAA4B","sourcesContent":["export * from './binders/sqlBinder';\nexport * from './core/errors';\nexport * from './core/validator';\nexport * from './registry';\nexport * from './adapters';\nexport * from './decorators/queryBinder';\nexport * from './decorators/query';\nexport * from './decorators/defaults';\nexport * from './decorators/resultShape';\nexport * from './decorators/validateResult';\nexport * from './decorators/transform';\nexport * from './utils/dto';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,sDAAoC;AACpC,gDAA8B;AAC9B,mDAAiC;AACjC,6CAA2B;AAC3B,6CAA2B;AAC3B,2DAAyC;AACzC,qDAAmC;AACnC,wDAAsC;AACtC,2DAAyC;AACzC,8DAA4C;AAC5C,yDAAuC;AACvC,oDAAkC;AAClC,8CAA4B","sourcesContent":["export * from './binders/sqlBinder';\nexport * from './core/errors';\nexport * from './core/validator';\nexport * from './registry';\nexport * from './adapters';\nexport * from './decorators/queryBinder';\nexport * from './decorators/query';\nexport * from './decorators/defaults';\nexport * from './decorators/resultShape';\nexport * from './decorators/validateResult';\nexport * from './decorators/transform';\nexport * from './decorators/page';\nexport * from './utils/dto';\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sqlstack",
3
- "version": "1.0.6",
3
+ "version": "1.0.7",
4
4
  "description": "",
5
5
  "license": "ISC",
6
6
  "author": "",
@@ -42,6 +42,8 @@
42
42
  "db:pg:down": "docker compose -f docker/docker-compose.pg.yml down -v",
43
43
  "db:mysql:up": "docker compose -f docker/docker-compose.mysql.yml up -d",
44
44
  "db:mysql:down": "docker compose -f docker/docker-compose.mysql.yml down -v",
45
+ "db:up": "npm-run-all db:pg:up db:mysql:up",
46
+ "db:down": "npm-run-all db:pg:down db:mysql:down",
45
47
  "db:ps": "docker ps --filter name=sqlstack-",
46
48
  "db:logs:pg": "docker logs -f sqlstack-postgres",
47
49
  "db:logs:mysql": "docker logs -f sqlstack-mysql"
@@ -49,6 +51,7 @@
49
51
  "devDependencies": {
50
52
  "@types/jest": "^29.5.13",
51
53
  "jest": "^29.7.0",
54
+ "npm-run-all": "^4.1.5",
52
55
  "rimraf": "^5.0.5",
53
56
  "ts-jest": "^29.2.5",
54
57
  "ts-node": "^10.9.2",
package/readme.md CHANGED
@@ -232,6 +232,31 @@ class UsersRepo {
232
232
 
233
233
  - Calling `repo.listUsers({})` fills `{ status: "active", limit: 10 }`.
234
234
 
235
+ ### `@Page`
236
+
237
+ Add pagination parameters `:offset` and `:limit` derived from a page size and a page number. Pages are 1-based by default.
238
+
239
+ ```ts
240
+ import { QueryBinder, Page, Query, SqlStackError } from "sqlstack";
241
+
242
+ @QueryBinder()
243
+ class UsersRepo {
244
+ @Page(10) // limit = 10, pages are 1-based
245
+ @Query()
246
+ async listUsers(_a: { page?: number; status?: string }): Promise<User[]> {
247
+ throw new SqlStackError();
248
+ }
249
+ }
250
+ ```
251
+
252
+ - Use `:offset` and `:limit` in your SQL files.
253
+ - The current page is read from `page` when passing a named object, or from a trailing options object as the last argument. This works for both named and positional styles:
254
+ - Named style: `list({ user_id: 1 })` or `list({ user_id: 1 }, { page: 2 })`.
255
+ - Positional style: `list(userId)` or `list(userId, { page: 2 })`.
256
+ Only the last argument is checked for `{ page }`.
257
+ If no page is provided, page defaults to 1 (or 0 when `zeroBase: true`).
258
+ - Zero-based pages are supported with `@Page(10, { zeroBase: true })`.
259
+
235
260
  ### Result shape decorators
236
261
 
237
262
  Choose a decorator to shape row results without parameters.