catalyst-relay 0.2.1 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -4
- package/dist/index.d.mts +3 -23
- package/dist/index.d.ts +3 -23
- package/dist/index.js +36 -247
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +36 -247
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -270,9 +270,9 @@ if (!error) {
|
|
|
270
270
|
```typescript
|
|
271
271
|
const [data, error] = await client.previewData({
|
|
272
272
|
objectName: 'T000',
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
273
|
+
objectType: 'table',
|
|
274
|
+
sqlQuery: "SELECT MANDT, MTEXT FROM T000 WHERE MANDT = '100'",
|
|
275
|
+
limit: 10
|
|
276
276
|
});
|
|
277
277
|
```
|
|
278
278
|
|
|
@@ -327,7 +327,8 @@ curl -X POST http://localhost:3000/preview/data \
|
|
|
327
327
|
-H "x-session-id: abc123" \
|
|
328
328
|
-d '{
|
|
329
329
|
"objectName": "T000",
|
|
330
|
-
"
|
|
330
|
+
"objectType": "table",
|
|
331
|
+
"sqlQuery": "SELECT MANDT, MTEXT FROM T000 WHERE MANDT = '\''100'\''",
|
|
331
332
|
"limit": 10
|
|
332
333
|
}'
|
|
333
334
|
```
|
package/dist/index.d.mts
CHANGED
|
@@ -113,30 +113,10 @@ interface PreviewQuery {
|
|
|
113
113
|
objectName: string;
|
|
114
114
|
/** Object type ('table' or 'view') */
|
|
115
115
|
objectType: 'table' | 'view';
|
|
116
|
-
/**
|
|
117
|
-
|
|
118
|
-
/** ORDER BY columns */
|
|
119
|
-
orderBy?: OrderBy[];
|
|
116
|
+
/** SQL query to execute */
|
|
117
|
+
sqlQuery: string;
|
|
120
118
|
/** Maximum rows to return (default: 100) */
|
|
121
119
|
limit?: number;
|
|
122
|
-
/** Row offset for pagination */
|
|
123
|
-
offset?: number;
|
|
124
|
-
}
|
|
125
|
-
/**
|
|
126
|
-
* Filter condition for data preview
|
|
127
|
-
*/
|
|
128
|
-
interface Filter {
|
|
129
|
-
column: string;
|
|
130
|
-
operator: FilterOperator;
|
|
131
|
-
value: string | number | boolean | null;
|
|
132
|
-
}
|
|
133
|
-
type FilterOperator = 'eq' | 'ne' | 'gt' | 'ge' | 'lt' | 'le' | 'like' | 'in';
|
|
134
|
-
/**
|
|
135
|
-
* Sort specification for data preview
|
|
136
|
-
*/
|
|
137
|
-
interface OrderBy {
|
|
138
|
-
column: string;
|
|
139
|
-
direction: 'asc' | 'desc';
|
|
140
120
|
}
|
|
141
121
|
|
|
142
122
|
/**
|
|
@@ -464,4 +444,4 @@ interface ADTClient {
|
|
|
464
444
|
}
|
|
465
445
|
declare function createClient(config: ClientConfig): Result<ADTClient, Error>;
|
|
466
446
|
|
|
467
|
-
export { type ADTClient, type ActivationMessage, type ActivationResult, type ApiResponse, type AsyncResult, type AuthConfig, type AuthType, type BasicAuthConfig, type ClientConfig, type ColumnInfo, type DataFrame, type Dependency, type DiffResult, type DistinctResult, type ErrorCode, type ErrorResponse, type
|
|
447
|
+
export { type ADTClient, type ActivationMessage, type ActivationResult, type ApiResponse, type AsyncResult, type AuthConfig, type AuthType, type BasicAuthConfig, type ClientConfig, type ColumnInfo, type DataFrame, type Dependency, type DiffResult, type DistinctResult, type ErrorCode, type ErrorResponse, type ObjectConfig, type ObjectContent, type ObjectMetadata, type ObjectRef, type ObjectWithContent, type Package, type PreviewQuery, type Result, type SamlAuthConfig, type SearchResult, type Session, type SsoAuthConfig, type SuccessResponse, type Transport, type TransportConfig, type TreeNode, type TreeQuery, type UpsertResult, createClient, err, ok };
|
package/dist/index.d.ts
CHANGED
|
@@ -113,30 +113,10 @@ interface PreviewQuery {
|
|
|
113
113
|
objectName: string;
|
|
114
114
|
/** Object type ('table' or 'view') */
|
|
115
115
|
objectType: 'table' | 'view';
|
|
116
|
-
/**
|
|
117
|
-
|
|
118
|
-
/** ORDER BY columns */
|
|
119
|
-
orderBy?: OrderBy[];
|
|
116
|
+
/** SQL query to execute */
|
|
117
|
+
sqlQuery: string;
|
|
120
118
|
/** Maximum rows to return (default: 100) */
|
|
121
119
|
limit?: number;
|
|
122
|
-
/** Row offset for pagination */
|
|
123
|
-
offset?: number;
|
|
124
|
-
}
|
|
125
|
-
/**
|
|
126
|
-
* Filter condition for data preview
|
|
127
|
-
*/
|
|
128
|
-
interface Filter {
|
|
129
|
-
column: string;
|
|
130
|
-
operator: FilterOperator;
|
|
131
|
-
value: string | number | boolean | null;
|
|
132
|
-
}
|
|
133
|
-
type FilterOperator = 'eq' | 'ne' | 'gt' | 'ge' | 'lt' | 'le' | 'like' | 'in';
|
|
134
|
-
/**
|
|
135
|
-
* Sort specification for data preview
|
|
136
|
-
*/
|
|
137
|
-
interface OrderBy {
|
|
138
|
-
column: string;
|
|
139
|
-
direction: 'asc' | 'desc';
|
|
140
120
|
}
|
|
141
121
|
|
|
142
122
|
/**
|
|
@@ -464,4 +444,4 @@ interface ADTClient {
|
|
|
464
444
|
}
|
|
465
445
|
declare function createClient(config: ClientConfig): Result<ADTClient, Error>;
|
|
466
446
|
|
|
467
|
-
export { type ADTClient, type ActivationMessage, type ActivationResult, type ApiResponse, type AsyncResult, type AuthConfig, type AuthType, type BasicAuthConfig, type ClientConfig, type ColumnInfo, type DataFrame, type Dependency, type DiffResult, type DistinctResult, type ErrorCode, type ErrorResponse, type
|
|
447
|
+
export { type ADTClient, type ActivationMessage, type ActivationResult, type ApiResponse, type AsyncResult, type AuthConfig, type AuthType, type BasicAuthConfig, type ClientConfig, type ColumnInfo, type DataFrame, type Dependency, type DiffResult, type DistinctResult, type ErrorCode, type ErrorResponse, type ObjectConfig, type ObjectContent, type ObjectMetadata, type ObjectRef, type ObjectWithContent, type Package, type PreviewQuery, type Result, type SamlAuthConfig, type SearchResult, type Session, type SsoAuthConfig, type SuccessResponse, type Transport, type TransportConfig, type TreeNode, type TreeQuery, type UpsertResult, createClient, err, ok };
|
package/dist/index.js
CHANGED
|
@@ -125,93 +125,6 @@ function dictToAbapXml(data, root = "DATA") {
|
|
|
125
125
|
</asx:abap>`;
|
|
126
126
|
}
|
|
127
127
|
|
|
128
|
-
// src/core/utils/sql.ts
|
|
129
|
-
var SqlValidationError = class extends Error {
|
|
130
|
-
constructor(message) {
|
|
131
|
-
super(message);
|
|
132
|
-
this.name = "SqlValidationError";
|
|
133
|
-
}
|
|
134
|
-
};
|
|
135
|
-
function validateSqlInput(input, maxLength = 1e4) {
|
|
136
|
-
if (typeof input !== "string") {
|
|
137
|
-
return err(new SqlValidationError("Input must be a string"));
|
|
138
|
-
}
|
|
139
|
-
if (input.length > maxLength) {
|
|
140
|
-
return err(new SqlValidationError(`Input exceeds maximum length of ${maxLength}`));
|
|
141
|
-
}
|
|
142
|
-
const dangerousPatterns = [
|
|
143
|
-
{
|
|
144
|
-
pattern: /\b(DROP|DELETE|INSERT|UPDATE|ALTER|CREATE|TRUNCATE)\s+/i,
|
|
145
|
-
description: "DDL/DML keywords (DROP, DELETE, INSERT, etc.)"
|
|
146
|
-
},
|
|
147
|
-
{
|
|
148
|
-
pattern: /;[\s]*\w/,
|
|
149
|
-
description: "Statement termination followed by another statement"
|
|
150
|
-
},
|
|
151
|
-
{
|
|
152
|
-
pattern: /--[\s]*\w/,
|
|
153
|
-
description: "SQL comments with content"
|
|
154
|
-
},
|
|
155
|
-
{
|
|
156
|
-
pattern: /\/\*.*?\*\//,
|
|
157
|
-
description: "Block comments"
|
|
158
|
-
},
|
|
159
|
-
{
|
|
160
|
-
pattern: /\bEXEC(UTE)?\s*\(/i,
|
|
161
|
-
description: "Procedure execution"
|
|
162
|
-
},
|
|
163
|
-
{
|
|
164
|
-
pattern: /\bSP_\w+/i,
|
|
165
|
-
description: "Stored procedures"
|
|
166
|
-
},
|
|
167
|
-
{
|
|
168
|
-
pattern: /\bXP_\w+/i,
|
|
169
|
-
description: "Extended stored procedures"
|
|
170
|
-
},
|
|
171
|
-
{
|
|
172
|
-
pattern: /\bUNION\s+(ALL\s+)?SELECT/i,
|
|
173
|
-
description: "Union-based injection"
|
|
174
|
-
},
|
|
175
|
-
{
|
|
176
|
-
pattern: /@@\w+/,
|
|
177
|
-
description: "System variables"
|
|
178
|
-
},
|
|
179
|
-
{
|
|
180
|
-
pattern: /\bDECLARE\s+@/i,
|
|
181
|
-
description: "Variable declarations"
|
|
182
|
-
},
|
|
183
|
-
{
|
|
184
|
-
pattern: /\bCAST\s*\(/i,
|
|
185
|
-
description: "Type casting"
|
|
186
|
-
},
|
|
187
|
-
{
|
|
188
|
-
pattern: /\bCONVERT\s*\(/i,
|
|
189
|
-
description: "Type conversion"
|
|
190
|
-
}
|
|
191
|
-
];
|
|
192
|
-
for (const { pattern, description } of dangerousPatterns) {
|
|
193
|
-
if (pattern.test(input)) {
|
|
194
|
-
return err(new SqlValidationError(
|
|
195
|
-
`Input contains potentially dangerous SQL pattern: ${description}`
|
|
196
|
-
));
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
const specialCharMatches = input.match(/[;'"\\]/g);
|
|
200
|
-
const specialCharCount = specialCharMatches ? specialCharMatches.length : 0;
|
|
201
|
-
if (specialCharCount > 5) {
|
|
202
|
-
return err(new SqlValidationError("Input contains excessive special characters"));
|
|
203
|
-
}
|
|
204
|
-
const singleQuoteCount = (input.match(/'/g) || []).length;
|
|
205
|
-
if (singleQuoteCount % 2 !== 0) {
|
|
206
|
-
return err(new SqlValidationError("Unbalanced single quotes detected"));
|
|
207
|
-
}
|
|
208
|
-
const doubleQuoteCount = (input.match(/"/g) || []).length;
|
|
209
|
-
if (doubleQuoteCount % 2 !== 0) {
|
|
210
|
-
return err(new SqlValidationError("Unbalanced double quotes detected"));
|
|
211
|
-
}
|
|
212
|
-
return ok(true);
|
|
213
|
-
}
|
|
214
|
-
|
|
215
128
|
// src/core/utils/csrf.ts
|
|
216
129
|
var FETCH_CSRF_TOKEN = "fetch";
|
|
217
130
|
var CSRF_TOKEN_HEADER = "x-csrf-token";
|
|
@@ -958,63 +871,6 @@ function extractTransports(xml) {
|
|
|
958
871
|
return ok(transports);
|
|
959
872
|
}
|
|
960
873
|
|
|
961
|
-
// src/core/adt/queryBuilder.ts
|
|
962
|
-
function buildWhereClauses(filters) {
|
|
963
|
-
if (!filters || filters.length === 0) {
|
|
964
|
-
return "";
|
|
965
|
-
}
|
|
966
|
-
const clauses = filters.map((filter) => {
|
|
967
|
-
const { column, operator, value } = filter;
|
|
968
|
-
switch (operator) {
|
|
969
|
-
case "eq":
|
|
970
|
-
return `${column} = ${formatValue(value)}`;
|
|
971
|
-
case "ne":
|
|
972
|
-
return `${column} != ${formatValue(value)}`;
|
|
973
|
-
case "gt":
|
|
974
|
-
return `${column} > ${formatValue(value)}`;
|
|
975
|
-
case "ge":
|
|
976
|
-
return `${column} >= ${formatValue(value)}`;
|
|
977
|
-
case "lt":
|
|
978
|
-
return `${column} < ${formatValue(value)}`;
|
|
979
|
-
case "le":
|
|
980
|
-
return `${column} <= ${formatValue(value)}`;
|
|
981
|
-
case "like":
|
|
982
|
-
return `${column} LIKE ${formatValue(value)}`;
|
|
983
|
-
case "in":
|
|
984
|
-
if (Array.isArray(value)) {
|
|
985
|
-
const values = value.map((v) => formatValue(v)).join(", ");
|
|
986
|
-
return `${column} IN (${values})`;
|
|
987
|
-
}
|
|
988
|
-
return `${column} IN (${formatValue(value)})`;
|
|
989
|
-
default:
|
|
990
|
-
return "";
|
|
991
|
-
}
|
|
992
|
-
}).filter((c) => c);
|
|
993
|
-
if (clauses.length === 0) {
|
|
994
|
-
return "";
|
|
995
|
-
}
|
|
996
|
-
return ` WHERE ${clauses.join(" AND ")}`;
|
|
997
|
-
}
|
|
998
|
-
function buildOrderByClauses(orderBy) {
|
|
999
|
-
if (!orderBy || orderBy.length === 0) {
|
|
1000
|
-
return "";
|
|
1001
|
-
}
|
|
1002
|
-
const clauses = orderBy.map((o) => `${o.column} ${o.direction.toUpperCase()}`);
|
|
1003
|
-
return ` ORDER BY ${clauses.join(", ")}`;
|
|
1004
|
-
}
|
|
1005
|
-
function formatValue(value) {
|
|
1006
|
-
if (value === null) {
|
|
1007
|
-
return "NULL";
|
|
1008
|
-
}
|
|
1009
|
-
if (typeof value === "string") {
|
|
1010
|
-
return `'${value.replace(/'/g, "''")}'`;
|
|
1011
|
-
}
|
|
1012
|
-
if (typeof value === "boolean") {
|
|
1013
|
-
return value ? "1" : "0";
|
|
1014
|
-
}
|
|
1015
|
-
return String(value);
|
|
1016
|
-
}
|
|
1017
|
-
|
|
1018
874
|
// src/core/adt/previewParser.ts
|
|
1019
875
|
function parseDataPreview(xml, maxRows, isTable) {
|
|
1020
876
|
const [doc, parseErr] = safeParseXml(xml);
|
|
@@ -1033,10 +889,18 @@ function parseDataPreview(xml, maxRows, isTable) {
|
|
|
1033
889
|
if (!name || !dataType) continue;
|
|
1034
890
|
columns.push({ name, dataType });
|
|
1035
891
|
}
|
|
892
|
+
const dataSetElements = doc.getElementsByTagNameNS(namespace, "dataSet");
|
|
893
|
+
if (columns.length === 0 && dataSetElements.length > 0) {
|
|
894
|
+
for (let i = 0; i < dataSetElements.length; i++) {
|
|
895
|
+
const dataSet = dataSetElements[i];
|
|
896
|
+
if (!dataSet) continue;
|
|
897
|
+
const name = dataSet.getAttributeNS(namespace, "columnName") || dataSet.getAttribute("columnName") || `column${i}`;
|
|
898
|
+
columns.push({ name, dataType: "unknown" });
|
|
899
|
+
}
|
|
900
|
+
}
|
|
1036
901
|
if (columns.length === 0) {
|
|
1037
|
-
return
|
|
902
|
+
return ok({ columns: [], rows: [], totalRows: 0 });
|
|
1038
903
|
}
|
|
1039
|
-
const dataSetElements = doc.getElementsByTagNameNS(namespace, "dataSet");
|
|
1040
904
|
const columnData = Array.from({ length: columns.length }, () => []);
|
|
1041
905
|
for (let i = 0; i < dataSetElements.length; i++) {
|
|
1042
906
|
const dataSet = dataSetElements[i];
|
|
@@ -1066,23 +930,16 @@ function parseDataPreview(xml, maxRows, isTable) {
|
|
|
1066
930
|
return ok(dataFrame);
|
|
1067
931
|
}
|
|
1068
932
|
|
|
1069
|
-
// src/core/adt/
|
|
933
|
+
// src/core/adt/dataPreview.ts
|
|
1070
934
|
async function previewData(client, query) {
|
|
1071
935
|
const extension = query.objectType === "table" ? "astabldt" : "asddls";
|
|
1072
936
|
const config = getConfigByExtension(extension);
|
|
1073
|
-
if (!config
|
|
937
|
+
if (!config?.dpEndpoint || !config?.dpParam) {
|
|
1074
938
|
return err(new Error(`Data preview not supported for object type: ${query.objectType}`));
|
|
1075
939
|
}
|
|
1076
940
|
const limit = query.limit ?? 100;
|
|
1077
|
-
const whereClauses = buildWhereClauses(query.filters);
|
|
1078
|
-
const orderByClauses = buildOrderByClauses(query.orderBy);
|
|
1079
|
-
const sqlQuery = `select * from ${query.objectName}${whereClauses}${orderByClauses}`;
|
|
1080
|
-
const [, validationErr] = validateSqlInput(sqlQuery);
|
|
1081
|
-
if (validationErr) {
|
|
1082
|
-
return err(new Error(`SQL validation failed: ${validationErr.message}`));
|
|
1083
|
-
}
|
|
1084
941
|
debug(`Data preview: endpoint=${config.dpEndpoint}, param=${config.dpParam}=${query.objectName}`);
|
|
1085
|
-
debug(`SQL: ${sqlQuery}`);
|
|
942
|
+
debug(`SQL: ${query.sqlQuery}`);
|
|
1086
943
|
const [response, requestErr] = await client.request({
|
|
1087
944
|
method: "POST",
|
|
1088
945
|
path: `/sap/bc/adt/datapreview/${config.dpEndpoint}`,
|
|
@@ -1094,7 +951,7 @@ async function previewData(client, query) {
|
|
|
1094
951
|
"Accept": "application/vnd.sap.adt.datapreview.table.v1+xml",
|
|
1095
952
|
"Content-Type": "text/plain"
|
|
1096
953
|
},
|
|
1097
|
-
body: sqlQuery
|
|
954
|
+
body: query.sqlQuery
|
|
1098
955
|
});
|
|
1099
956
|
if (requestErr) {
|
|
1100
957
|
return err(requestErr);
|
|
@@ -1116,109 +973,41 @@ async function previewData(client, query) {
|
|
|
1116
973
|
// src/core/adt/distinct.ts
|
|
1117
974
|
var MAX_ROW_COUNT = 5e4;
|
|
1118
975
|
async function getDistinctValues(client, objectName, column, objectType = "view") {
|
|
1119
|
-
const extension = objectType === "table" ? "astabldt" : "asddls";
|
|
1120
|
-
const config = getConfigByExtension(extension);
|
|
1121
|
-
if (!config || !config.dpEndpoint || !config.dpParam) {
|
|
1122
|
-
return err(new Error(`Data preview not supported for object type: ${objectType}`));
|
|
1123
|
-
}
|
|
1124
976
|
const columnName = column.toUpperCase();
|
|
1125
977
|
const sqlQuery = `SELECT ${columnName} AS value, COUNT(*) AS count FROM ${objectName} GROUP BY ${columnName}`;
|
|
1126
|
-
const [,
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
method: "POST",
|
|
1132
|
-
path: `/sap/bc/adt/datapreview/${config.dpEndpoint}`,
|
|
1133
|
-
params: {
|
|
1134
|
-
"rowNumber": MAX_ROW_COUNT,
|
|
1135
|
-
[config.dpParam]: objectName
|
|
1136
|
-
},
|
|
1137
|
-
headers: {
|
|
1138
|
-
"Accept": "application/vnd.sap.adt.datapreview.table.v1+xml"
|
|
1139
|
-
},
|
|
1140
|
-
body: sqlQuery
|
|
978
|
+
const [dataFrame, error] = await previewData(client, {
|
|
979
|
+
objectName,
|
|
980
|
+
objectType,
|
|
981
|
+
sqlQuery,
|
|
982
|
+
limit: MAX_ROW_COUNT
|
|
1141
983
|
});
|
|
1142
|
-
if (
|
|
1143
|
-
return err(
|
|
984
|
+
if (error) {
|
|
985
|
+
return err(new Error(`Distinct values query failed: ${error.message}`));
|
|
1144
986
|
}
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
}
|
|
1150
|
-
const text = await response.text();
|
|
1151
|
-
const [doc, parseErr] = safeParseXml(text);
|
|
1152
|
-
if (parseErr) {
|
|
1153
|
-
return err(parseErr);
|
|
1154
|
-
}
|
|
1155
|
-
const dataSets = doc.getElementsByTagNameNS("http://www.sap.com/adt/dataPreview", "dataSet");
|
|
1156
|
-
const values = [];
|
|
1157
|
-
for (let i = 0; i < dataSets.length; i++) {
|
|
1158
|
-
const dataSet = dataSets[i];
|
|
1159
|
-
if (!dataSet) continue;
|
|
1160
|
-
const dataElements = dataSet.getElementsByTagNameNS("http://www.sap.com/adt/dataPreview", "data");
|
|
1161
|
-
if (dataElements.length < 2) continue;
|
|
1162
|
-
const value = dataElements[0]?.textContent ?? "";
|
|
1163
|
-
const countText = dataElements[1]?.textContent?.trim() ?? "0";
|
|
1164
|
-
values.push({
|
|
1165
|
-
value,
|
|
1166
|
-
count: parseInt(countText, 10)
|
|
1167
|
-
});
|
|
1168
|
-
}
|
|
1169
|
-
const result = {
|
|
1170
|
-
column,
|
|
1171
|
-
values
|
|
1172
|
-
};
|
|
1173
|
-
return ok(result);
|
|
987
|
+
const values = dataFrame.rows.map((row) => ({
|
|
988
|
+
value: row[0],
|
|
989
|
+
count: parseInt(String(row[1]), 10)
|
|
990
|
+
}));
|
|
991
|
+
return ok({ column, values });
|
|
1174
992
|
}
|
|
1175
993
|
|
|
1176
994
|
// src/core/adt/count.ts
|
|
1177
995
|
async function countRows(client, objectName, objectType) {
|
|
1178
|
-
const extension = objectType === "table" ? "astabldt" : "asddls";
|
|
1179
|
-
const config = getConfigByExtension(extension);
|
|
1180
|
-
if (!config || !config.dpEndpoint || !config.dpParam) {
|
|
1181
|
-
return err(new Error(`Data preview not supported for object type: ${objectType}`));
|
|
1182
|
-
}
|
|
1183
996
|
const sqlQuery = `SELECT COUNT(*) AS count FROM ${objectName}`;
|
|
1184
|
-
const [,
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
method: "POST",
|
|
1190
|
-
path: `/sap/bc/adt/datapreview/${config.dpEndpoint}`,
|
|
1191
|
-
params: {
|
|
1192
|
-
"rowNumber": 1,
|
|
1193
|
-
[config.dpParam]: objectName
|
|
1194
|
-
},
|
|
1195
|
-
headers: {
|
|
1196
|
-
"Accept": "application/vnd.sap.adt.datapreview.table.v1+xml"
|
|
1197
|
-
},
|
|
1198
|
-
body: sqlQuery
|
|
997
|
+
const [dataFrame, error] = await previewData(client, {
|
|
998
|
+
objectName,
|
|
999
|
+
objectType,
|
|
1000
|
+
sqlQuery,
|
|
1001
|
+
limit: 1
|
|
1199
1002
|
});
|
|
1200
|
-
if (
|
|
1201
|
-
return err(
|
|
1202
|
-
}
|
|
1203
|
-
if (!response.ok) {
|
|
1204
|
-
const text2 = await response.text();
|
|
1205
|
-
const errorMsg = extractError(text2);
|
|
1206
|
-
return err(new Error(`Row count query failed: ${errorMsg}`));
|
|
1003
|
+
if (error) {
|
|
1004
|
+
return err(new Error(`Row count query failed: ${error.message}`));
|
|
1207
1005
|
}
|
|
1208
|
-
const
|
|
1209
|
-
|
|
1210
|
-
if (parseErr) {
|
|
1211
|
-
return err(parseErr);
|
|
1212
|
-
}
|
|
1213
|
-
const dataElements = doc.getElementsByTagNameNS("http://www.sap.com/adt/dataPreview", "data");
|
|
1214
|
-
if (dataElements.length === 0) {
|
|
1006
|
+
const countValue = dataFrame.rows[0]?.[0];
|
|
1007
|
+
if (countValue === void 0) {
|
|
1215
1008
|
return err(new Error("No count value returned"));
|
|
1216
1009
|
}
|
|
1217
|
-
const
|
|
1218
|
-
if (!countText) {
|
|
1219
|
-
return err(new Error("Empty count value returned"));
|
|
1220
|
-
}
|
|
1221
|
-
const count = parseInt(countText, 10);
|
|
1010
|
+
const count = parseInt(String(countValue), 10);
|
|
1222
1011
|
if (isNaN(count)) {
|
|
1223
1012
|
return err(new Error("Invalid count value returned"));
|
|
1224
1013
|
}
|