@xpert-ai/plugin-sdk 3.18.6 → 3.19.0
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/CHANGELOG.md +27 -0
- package/MIDDLEWARE_APPS.md +71 -0
- package/README.md +2 -0
- package/data-workbench.cjs.js +217 -66
- package/data-workbench.esm.js +217 -66
- package/index.cjs.js +162 -46
- package/index.esm.js +148 -47
- package/package.json +2 -2
- package/runtime-capabilities.md +35 -0
- package/src/index.d.ts +3 -0
- package/src/lib/agent/index.d.ts +1 -0
- package/src/lib/agent/middleware/capabilities/assistant-task.d.ts +55 -20
- package/src/lib/agent/middleware/types.d.ts +13 -3
- package/src/lib/agent/runtime/capability.d.ts +29 -0
- package/src/lib/agent/runtime/index.d.ts +3 -0
- package/src/lib/agent/runtime/strategy.d.ts +50 -0
- package/src/lib/agent/runtime/types.d.ts +132 -0
- package/src/lib/assistant-capability/index.d.ts +42 -0
- package/src/lib/connector/runtime-capability.d.ts +2 -0
- package/src/lib/connector/strategy.interface.d.ts +8 -0
- package/src/lib/core/context/request-context.d.ts +6 -0
- package/src/lib/data/datasource/workbench-pagination.d.ts +6 -0
- package/src/lib/data/datasource/workbench-sql-lexer.d.ts +11 -0
- package/src/lib/data/datasource/workbench-sql-syntax.d.ts +3 -0
- package/src/lib/evolution/runtime-capability.d.ts +2 -1
- package/src/lib/integration/strategy.interface.d.ts +22 -0
- package/src/lib/mcp/app.d.ts +10 -0
- package/src/lib/project-task/index.d.ts +59 -0
- package/src/lib/project-type/index.d.ts +64 -0
- package/src/lib/rag/analyzer/index.d.ts +3 -0
- package/src/lib/rag/analyzer/strategy.decorator.d.ts +2 -0
- package/src/lib/rag/analyzer/strategy.interface.d.ts +11 -0
- package/src/lib/rag/analyzer/strategy.registry.d.ts +8 -0
- package/src/lib/rag/index.d.ts +1 -0
- package/src/lib/runtime/capabilities/knowledge-graph.d.ts +59 -0
- package/src/lib/runtime/capabilities/knowledgebase-documents.d.ts +21 -0
- package/src/lib/runtime/capabilities/knowledgebase.d.ts +8 -3
- package/src/lib/runtime/capabilities/project-access.d.ts +2 -1
- package/src/lib/runtime/capabilities/project-provisioning.d.ts +3 -0
- package/src/lib/runtime/runtime-scope.d.ts +7 -1
- package/src/lib/sandbox/execution-environment.d.ts +10 -0
- package/src/lib/sandbox/execution.d.ts +3 -0
- package/src/lib/sandbox/index.d.ts +1 -0
- package/src/lib/sandbox/protocol.d.ts +2 -0
- package/src/lib/tool-provider/types.d.ts +6 -0
- package/src/lib/types.d.ts +2 -1
- package/src/lib/workflow/trigger/strategy.interface.d.ts +2 -1
package/data-workbench.esm.js
CHANGED
|
@@ -6,6 +6,159 @@ const DataSourceRuntimeCapability = Object.freeze({
|
|
|
6
6
|
__type: undefined
|
|
7
7
|
});
|
|
8
8
|
|
|
9
|
+
/** Mask comments and quoted content without changing source offsets. Shared by guards and pagination. */ function lexWorkbenchSql(source) {
|
|
10
|
+
if (!source.trim() || source.length > 100000 || source.includes('\0')) throw new Error('invalid_sql');
|
|
11
|
+
const masked = source.split('');
|
|
12
|
+
const quoted = new Map();
|
|
13
|
+
const hide = (start, end, kind)=>{
|
|
14
|
+
for(let i = start; i < end; i++)if (masked[i] !== '\n') masked[i] = ' ';
|
|
15
|
+
if (kind) {
|
|
16
|
+
const marker = start + 1;
|
|
17
|
+
quoted.set(marker, kind);
|
|
18
|
+
masked[marker] = kind === 'literal' ? '?' : 'i';
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
let index = 0;
|
|
22
|
+
while(index < source.length){
|
|
23
|
+
const start = index, c = source[index], next = source[index + 1];
|
|
24
|
+
if (c === '-' && next === '-' || c === '#') {
|
|
25
|
+
while(index < source.length && source[index] !== '\n')index++;
|
|
26
|
+
hide(start, index);
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
if (c === '/' && next === '*') {
|
|
30
|
+
if (source[index + 2] === '!') throw new Error('executable_comment_not_supported');
|
|
31
|
+
const end = source.indexOf('*/', index + 2);
|
|
32
|
+
if (end < 0) throw new Error('unterminated_comment');
|
|
33
|
+
index = end + 2;
|
|
34
|
+
hide(start, index);
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
if (c === "'" || c === '"' || c === '`') {
|
|
38
|
+
let closed = false;
|
|
39
|
+
index++;
|
|
40
|
+
while(index < source.length){
|
|
41
|
+
if (source[index] === '\\') throw new Error('use_parameters_for_backslash_literals');
|
|
42
|
+
if (source[index] === c) {
|
|
43
|
+
if (source[index + 1] === c) {
|
|
44
|
+
index += 2;
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
index++;
|
|
48
|
+
closed = true;
|
|
49
|
+
break;
|
|
50
|
+
}
|
|
51
|
+
index++;
|
|
52
|
+
}
|
|
53
|
+
if (!closed) throw new Error('unterminated_literal');
|
|
54
|
+
hide(start, index, c === "'" ? 'literal' : 'identifier');
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
if (c === '$') {
|
|
58
|
+
var _source_slice_match;
|
|
59
|
+
const tag = (_source_slice_match = source.slice(index).match(/^\$(?:[A-Za-z_][A-Za-z_0-9]*)?\$/)) == null ? void 0 : _source_slice_match[0];
|
|
60
|
+
if (tag) {
|
|
61
|
+
const end = source.indexOf(tag, index + tag.length);
|
|
62
|
+
if (end < 0) throw new Error('unterminated_literal');
|
|
63
|
+
index = end + tag.length;
|
|
64
|
+
hide(start, index, 'literal');
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
index++;
|
|
69
|
+
}
|
|
70
|
+
const text = masked.join('');
|
|
71
|
+
const tokens = [
|
|
72
|
+
...text.matchAll(/[A-Z_][A-Z_0-9]*|[0-9]+|[^\s]/gi)
|
|
73
|
+
].map((match)=>{
|
|
74
|
+
var _quoted_get;
|
|
75
|
+
return {
|
|
76
|
+
text: match[0].toUpperCase(),
|
|
77
|
+
start: match.index,
|
|
78
|
+
end: match.index + match[0].length,
|
|
79
|
+
kind: (_quoted_get = quoted.get(match.index)) != null ? _quoted_get : /^[A-Z_]/i.test(match[0]) ? 'word' : /^[0-9]/.test(match[0]) ? 'number' : 'symbol'
|
|
80
|
+
};
|
|
81
|
+
});
|
|
82
|
+
return {
|
|
83
|
+
masked: text,
|
|
84
|
+
tokens
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const MODIFIED_TYPES = new Set('DECIMAL NUMERIC CHAR VARCHAR NCHAR NVARCHAR BINARY VARBINARY DATETIME TIME TIMESTAMP'.split(' '));
|
|
89
|
+
/** Positions where name(...) declares columns or a built-in type, rather than invoking a function. */ function sqlDeclarationPositions(tokens) {
|
|
90
|
+
const declarations = new Set();
|
|
91
|
+
const closing = new Map(), parents = new Map();
|
|
92
|
+
const stack = [];
|
|
93
|
+
tokens.forEach((token, index)=>{
|
|
94
|
+
if (stack.length) parents.set(index, stack[stack.length - 1]);
|
|
95
|
+
if (token.text === '(') stack.push(index);
|
|
96
|
+
if (token.text === ')') {
|
|
97
|
+
const open = stack.pop();
|
|
98
|
+
if (open !== undefined) closing.set(open, index);
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
const name = (index)=>{
|
|
102
|
+
var _tokens_index;
|
|
103
|
+
return [
|
|
104
|
+
'word',
|
|
105
|
+
'identifier'
|
|
106
|
+
].includes((_tokens_index = tokens[index]) == null ? void 0 : _tokens_index.kind);
|
|
107
|
+
};
|
|
108
|
+
const is = (index, word)=>{
|
|
109
|
+
var _tokens_index;
|
|
110
|
+
return ((_tokens_index = tokens[index]) == null ? void 0 : _tokens_index.text) === word;
|
|
111
|
+
};
|
|
112
|
+
for(let i = 0; i < tokens.length; i++){
|
|
113
|
+
if (tokens[i].kind !== 'word' || !is(i, 'WITH')) continue;
|
|
114
|
+
let cursor = i + 1;
|
|
115
|
+
if (is(cursor, 'RECURSIVE')) cursor++;
|
|
116
|
+
while(name(cursor)){
|
|
117
|
+
const declaration = cursor++;
|
|
118
|
+
let columns = false;
|
|
119
|
+
if (is(cursor, '(')) {
|
|
120
|
+
const end = closing.get(cursor);
|
|
121
|
+
if (end === undefined || end === cursor + 1) break;
|
|
122
|
+
const columnTokens = tokens.slice(cursor + 1, end);
|
|
123
|
+
if (columnTokens.length % 2 === 0 || !columnTokens.every((token, n)=>n % 2 === 0 ? [
|
|
124
|
+
'word',
|
|
125
|
+
'identifier'
|
|
126
|
+
].includes(token.kind) : token.text === ',')) break;
|
|
127
|
+
columns = true;
|
|
128
|
+
cursor = end + 1;
|
|
129
|
+
}
|
|
130
|
+
if (!is(cursor++, 'AS')) break;
|
|
131
|
+
if (is(cursor, 'NOT')) cursor++;
|
|
132
|
+
if (is(cursor, 'MATERIALIZED')) cursor++;
|
|
133
|
+
if (!is(cursor, '(')) break;
|
|
134
|
+
const end = closing.get(cursor);
|
|
135
|
+
if (end === undefined) break;
|
|
136
|
+
if (columns) declarations.add(tokens[declaration].start);
|
|
137
|
+
cursor = end + 1;
|
|
138
|
+
if (!is(cursor, ',')) break;
|
|
139
|
+
cursor++;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
tokens.forEach((token, i)=>{
|
|
143
|
+
var _tokens_;
|
|
144
|
+
if (token.kind !== 'word' || !MODIFIED_TYPES.has(token.text) || !is(i + 1, '(')) return;
|
|
145
|
+
const end = closing.get(i + 1);
|
|
146
|
+
if (end === undefined) return;
|
|
147
|
+
const args = tokens.slice(i + 2, end);
|
|
148
|
+
if (![
|
|
149
|
+
1,
|
|
150
|
+
3
|
|
151
|
+
].includes(args.length) || !args.every((arg, n)=>n % 2 ? arg.text === ',' : arg.kind === 'number')) return;
|
|
152
|
+
const parent = parents.get(i);
|
|
153
|
+
const owner = parent === undefined ? undefined : (_tokens_ = tokens[parent - 1]) == null ? void 0 : _tokens_.text;
|
|
154
|
+
const cast = owner === 'CAST' && is(i - 1, 'AS');
|
|
155
|
+
const convert = owner === 'CONVERT' && is(i - 1, ',');
|
|
156
|
+
const postgresCast = is(i - 1, ':') && is(i - 2, ':');
|
|
157
|
+
if (cast || convert || postgresCast) declarations.add(token.start);
|
|
158
|
+
});
|
|
159
|
+
return declarations;
|
|
160
|
+
}
|
|
161
|
+
|
|
9
162
|
const WRITE = new Set([
|
|
10
163
|
'INSERT',
|
|
11
164
|
'UPDATE',
|
|
@@ -40,15 +193,16 @@ const FORBIDDEN = new Set([
|
|
|
40
193
|
'DETACH'
|
|
41
194
|
]);
|
|
42
195
|
const SAFE_FUNCTIONS = new Set('ABS ACOS ASIN ATAN ATAN2 AVG CAST CEIL CEILING COALESCE CONCAT CONCAT_WS CONVERT COS COUNT CURDATE CURRENT_DATE CURRENT_TIMESTAMP DATE DATE_ADD DATE_SUB DATE_FORMAT DATEDIFF DAY DAYOFMONTH DAYOFWEEK EXTRACT FLOOR FORMAT GREATEST GROUP_CONCAT IF IFNULL JSON_EXTRACT JSON_LENGTH JSON_UNQUOTE LEAST LEFT LENGTH LN LOG LOWER LPAD LTRIM MAX MD5 MIN MOD MONTH NOW NULLIF POWER RAND REPLACE REVERSE RIGHT ROUND ROW_NUMBER RANK DENSE_RANK LAG LEAD FIRST_VALUE LAST_VALUE LPAD RPAD RTRIM SIGN SIN SQRT STDDEV STDDEV_POP STDDEV_SAMP SUBSTR SUBSTRING SUM TAN TO_CHAR TO_DATE TO_TIMESTAMP TRIM TRUNC UPPER VAR_POP VAR_SAMP VERSION WEEK YEAR DATABASE CURRENT_DATABASE CURRENT_SCHEMA ARRAY_AGG STRING_AGG JSON_AGG JSON_BUILD_OBJECT PG_GET_VIEWDEF'.split(' '));
|
|
43
|
-
|
|
196
|
+
// FROM/JOIN can introduce a parenthesized subquery, not a function call.
|
|
197
|
+
const SQL_PARENS = new Set('IN AS EXISTS OVER PARTITION VALUES SELECT WITH FROM JOIN AND OR NOT ON USING FILTER GROUPING ROLLUP CUBE DISTINCT EXPLAIN'.split(' '));
|
|
44
198
|
const UNSAFE_FUNCTIONS = /\b(pg_sleep|sleep|benchmark|dblink\w*|lo_\w+|pg_(?:read|write|ls|stat|terminate|cancel|reload|rotate|log|create|drop|promote|switch|backup|replication|advisory)\w*|get_lock|release_lock|load_file|nextval|setval|set_config|http\w*|s3|hdfs|jdbc|mysql|postgresql|file|url)\s*\(/i;
|
|
45
199
|
function splitWorkbenchSql(source) {
|
|
46
|
-
|
|
200
|
+
const { masked, tokens } = lexWorkbenchSql(source);
|
|
47
201
|
const statements = [];
|
|
48
|
-
let start = 0
|
|
202
|
+
let start = 0;
|
|
49
203
|
const finish = (end)=>{
|
|
50
|
-
const text =
|
|
51
|
-
if (text) {
|
|
204
|
+
const text = masked.slice(start, end);
|
|
205
|
+
if (text.trim()) {
|
|
52
206
|
var _text_toUpperCase_match;
|
|
53
207
|
const words = (_text_toUpperCase_match = text.toUpperCase().match(/[A-Z_][A-Z_0-9]*/g)) != null ? _text_toUpperCase_match : [];
|
|
54
208
|
const first = words[0];
|
|
@@ -59,10 +213,11 @@ function splitWorkbenchSql(source) {
|
|
|
59
213
|
if (words.some((word, index)=>WRITE.has(word) && !(first === 'SHOW' && index === 1 && word === 'CREATE') || FORBIDDEN.has(word)) || UNSAFE_FUNCTIONS.test(text) || /\bFOR\s+(UPDATE|SHARE)\b/i.test(text) || /:=|\bEXPLAIN\s+ANALYZE\b|@/i.test(text)) effect = 'unsupported';
|
|
60
214
|
// eslint-disable-next-line no-control-regex -- intentional: reject any non-ASCII/control input
|
|
61
215
|
if (/[^\x00-\x7f]/.test(text) || /\.\s*[A-Z_][A-Z_0-9]*\s*\(/i.test(text)) effect = 'unsupported';
|
|
216
|
+
const declarations = sqlDeclarationPositions(tokens.filter((token)=>token.start >= start && token.end <= end));
|
|
62
217
|
if ([
|
|
63
218
|
...text.matchAll(/([A-Z_][A-Z_0-9]*)\s*\(/gi)
|
|
64
|
-
].some((match)=>!SAFE_FUNCTIONS.has(match[1].toUpperCase()) && !SQL_PARENS.has(match[1].toUpperCase()))) effect = 'unsupported';
|
|
65
|
-
if (first === 'SHOW' && !/^(SHOW\s+(DATABASES|SCHEMAS|CATALOGS|TABLES|FULL\s+TABLES|COLUMNS|FULL\s+COLUMNS|INDEX|INDEXES|KEYS|CREATE\s+TABLE|CREATE\s+VIEW|PARTITIONS|VARIABLES|STATUS|GRANTS))\b/i.test(text)) effect = 'unsupported';
|
|
219
|
+
].some((match)=>!declarations.has(start + match.index) && !SAFE_FUNCTIONS.has(match[1].toUpperCase()) && !SQL_PARENS.has(match[1].toUpperCase()))) effect = 'unsupported';
|
|
220
|
+
if (first === 'SHOW' && !/^(SHOW\s+(DATABASES|SCHEMAS|CATALOGS|TABLES|FULL\s+TABLES|COLUMNS|FULL\s+COLUMNS|INDEX|INDEXES|KEYS|CREATE\s+TABLE|CREATE\s+VIEW|PARTITIONS|VARIABLES|STATUS|GRANTS))\b/i.test(text.trim())) effect = 'unsupported';
|
|
66
221
|
}
|
|
67
222
|
// CREATE/ALTER routines, external resources and privileged SQL are outside this app.
|
|
68
223
|
if (effect === 'write' && /\b(FUNCTION|PROCEDURE|TRIGGER|USER|ROLE|CATALOG|RESOURCE|SYSTEM|SERVER|EXTENSION|FILE|OUTFILE|DUMPFILE|EXECUTE)\b/i.test(text)) effect = 'unsupported';
|
|
@@ -72,63 +227,10 @@ function splitWorkbenchSql(source) {
|
|
|
72
227
|
effect
|
|
73
228
|
});
|
|
74
229
|
}
|
|
75
|
-
clean = '';
|
|
76
230
|
start = end + 1;
|
|
77
231
|
};
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
if (c === '-' && next === '-' || c === '#') {
|
|
81
|
-
while(index < source.length && source[index] !== '\n')index++;
|
|
82
|
-
clean += ' ';
|
|
83
|
-
continue;
|
|
84
|
-
}
|
|
85
|
-
if (c === '/' && next === '*') {
|
|
86
|
-
if (source[index + 2] === '!') throw new Error('executable_comment_not_supported');
|
|
87
|
-
const end = source.indexOf('*/', index + 2);
|
|
88
|
-
if (end < 0) throw new Error('unterminated_comment');
|
|
89
|
-
index = end + 2;
|
|
90
|
-
clean += ' ';
|
|
91
|
-
continue;
|
|
92
|
-
}
|
|
93
|
-
if (c === "'" || c === '"' || c === '`') {
|
|
94
|
-
const quote = c;
|
|
95
|
-
let closed = false;
|
|
96
|
-
index++;
|
|
97
|
-
while(index < source.length){
|
|
98
|
-
if (source[index] === '\\') throw new Error('use_parameters_for_backslash_literals');
|
|
99
|
-
if (source[index] === quote) {
|
|
100
|
-
if (source[index + 1] === quote) {
|
|
101
|
-
index += 2;
|
|
102
|
-
continue;
|
|
103
|
-
}
|
|
104
|
-
index++;
|
|
105
|
-
closed = true;
|
|
106
|
-
break;
|
|
107
|
-
}
|
|
108
|
-
index++;
|
|
109
|
-
}
|
|
110
|
-
if (!closed) throw new Error('unterminated_literal');
|
|
111
|
-
clean += quote === "'" ? ' ? ' : ' identifier ';
|
|
112
|
-
continue;
|
|
113
|
-
}
|
|
114
|
-
if (c === '$') {
|
|
115
|
-
var _source_slice_match;
|
|
116
|
-
const tag = (_source_slice_match = source.slice(index).match(/^\$(?:[A-Za-z_][A-Za-z_0-9]*)?\$/)) == null ? void 0 : _source_slice_match[0];
|
|
117
|
-
if (tag) {
|
|
118
|
-
const end = source.indexOf(tag, index + tag.length);
|
|
119
|
-
if (end < 0) throw new Error('unterminated_literal');
|
|
120
|
-
index = end + tag.length;
|
|
121
|
-
clean += ' ? ';
|
|
122
|
-
continue;
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
if (c === ';') {
|
|
126
|
-
finish(index);
|
|
127
|
-
index++;
|
|
128
|
-
continue;
|
|
129
|
-
}
|
|
130
|
-
clean += c;
|
|
131
|
-
index++;
|
|
232
|
+
for (const token of tokens){
|
|
233
|
+
if (token.kind === 'symbol' && token.text === ';') finish(token.start);
|
|
132
234
|
}
|
|
133
235
|
finish(source.length);
|
|
134
236
|
if (!statements.length || statements.length > 50) throw new Error('statement_count_exceeded');
|
|
@@ -146,6 +248,53 @@ function quoteDatabaseIdentifier(name, engine) {
|
|
|
146
248
|
return quote + name.split(quote).join(quote + quote) + quote;
|
|
147
249
|
}
|
|
148
250
|
|
|
251
|
+
/** Apply a page to a MySQL result without turning its (possibly duplicate) output names into table columns. */ function paginateMysqlQuery(sql, parameters = [], limit, offset) {
|
|
252
|
+
const { tokens } = lexWorkbenchSql(sql);
|
|
253
|
+
const top = [];
|
|
254
|
+
let depth = 0;
|
|
255
|
+
for (const token of tokens){
|
|
256
|
+
if (token.text === '(') depth++;
|
|
257
|
+
if (!depth) top.push(token);
|
|
258
|
+
if (token.text === ')') depth--;
|
|
259
|
+
if (depth < 0) throw new Error('unsupported_pagination');
|
|
260
|
+
}
|
|
261
|
+
if (depth) throw new Error('unsupported_pagination');
|
|
262
|
+
const start = top.findIndex((token)=>token.kind === 'word' && token.text === 'LIMIT');
|
|
263
|
+
if (start < 0) return {
|
|
264
|
+
sql: `${sql}\nLIMIT ${limit + 1} OFFSET ${offset}`,
|
|
265
|
+
parameters
|
|
266
|
+
};
|
|
267
|
+
const clause = top.slice(start + 1);
|
|
268
|
+
const bindings = tokens.filter((token)=>token.text === '?' && token.kind === 'symbol');
|
|
269
|
+
const consumed = new Set();
|
|
270
|
+
const integer = (token)=>{
|
|
271
|
+
if ((token == null ? void 0 : token.kind) === 'number') return BigInt(token.text);
|
|
272
|
+
if ((token == null ? void 0 : token.kind) === 'symbol' && token.text === '?') {
|
|
273
|
+
const index = bindings.indexOf(token), value = parameters[index];
|
|
274
|
+
if (typeof value === 'number' && Number.isSafeInteger(value) && value >= 0) {
|
|
275
|
+
consumed.add(index);
|
|
276
|
+
return BigInt(value);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
throw new Error('unsupported_pagination');
|
|
280
|
+
};
|
|
281
|
+
let count, skip = 0n;
|
|
282
|
+
if (clause.length === 1) count = integer(clause[0]);
|
|
283
|
+
else if (clause.length === 3 && clause[1].text === ',') {
|
|
284
|
+
skip = integer(clause[0]);
|
|
285
|
+
count = integer(clause[2]);
|
|
286
|
+
} else if (clause.length === 3 && clause[1].kind === 'word' && clause[1].text === 'OFFSET') {
|
|
287
|
+
count = integer(clause[0]);
|
|
288
|
+
skip = integer(clause[2]);
|
|
289
|
+
} else throw new Error('unsupported_pagination');
|
|
290
|
+
const remaining = count > BigInt(offset) ? count - BigInt(offset) : 0n;
|
|
291
|
+
const size = remaining < BigInt(limit + 1) ? remaining : BigInt(limit + 1);
|
|
292
|
+
return {
|
|
293
|
+
sql: `${sql.slice(0, top[start].start)}LIMIT ${size} OFFSET ${skip + BigInt(offset)}${sql.slice(clause[clause.length - 1].end)}`,
|
|
294
|
+
parameters: parameters.filter((_, index)=>!consumed.has(index))
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
|
|
149
298
|
const number = (value)=>Number(value != null ? value : 0);
|
|
150
299
|
const string = (value)=>value == null ? '' : String(value);
|
|
151
300
|
const cell = (result, row, name)=>row[result.columns.findIndex((column)=>column.name.toLowerCase() === name.toLowerCase())];
|
|
@@ -387,12 +536,14 @@ const cell = (result, row, name)=>row[result.columns.findIndex((column)=>column.
|
|
|
387
536
|
if (input.mode === 'write' && !(await this.capabilities()).writes) throw new Error('engine_version_writes_unavailable');
|
|
388
537
|
if (input.mode === 'write' && offset) throw new Error('mutation_cannot_be_paginated');
|
|
389
538
|
let sql = statements[0].sql;
|
|
390
|
-
|
|
539
|
+
let parameters = input.parameters;
|
|
391
540
|
if (input.mode === 'read' && [
|
|
392
541
|
'SELECT',
|
|
393
542
|
'WITH'
|
|
394
|
-
].includes(statements[0].words[0]))
|
|
395
|
-
|
|
543
|
+
].includes(statements[0].words[0])) {
|
|
544
|
+
if (this.engine === 'mysql') ({ sql, parameters } = paginateMysqlQuery(sql, parameters, limit, offset));
|
|
545
|
+
else sql = `SELECT * FROM (\n${sql}\n) AS ${this.quote('_db_studio_page')} LIMIT ${limit + 1} OFFSET ${offset}`;
|
|
546
|
+
} else if (offset) throw new Error('statement_cannot_be_paginated');
|
|
396
547
|
this.busy = true;
|
|
397
548
|
let readTransaction = false;
|
|
398
549
|
try {
|
|
@@ -401,7 +552,7 @@ const cell = (result, row, name)=>row[result.columns.findIndex((column)=>column.
|
|
|
401
552
|
readTransaction = true;
|
|
402
553
|
}
|
|
403
554
|
var _input_timeoutMs;
|
|
404
|
-
const result = await this.raw(sql,
|
|
555
|
+
const result = await this.raw(sql, parameters, limit + 1, signal, Math.max(1, Math.min((_input_timeoutMs = input.timeoutMs) != null ? _input_timeoutMs : 30000, 120000)));
|
|
405
556
|
const hasMore = result.rows.length > limit || result.truncated;
|
|
406
557
|
return _extends({}, result, {
|
|
407
558
|
rows: result.rows.slice(0, limit),
|