catalyst-relay 0.2.2 → 0.2.4

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/index.d.mts CHANGED
@@ -108,7 +108,7 @@ interface TreeQuery {
108
108
  /**
109
109
  * Data preview query
110
110
  */
111
- interface PreviewQuery {
111
+ interface PreviewSQL {
112
112
  /** Object name (table or CDS view) */
113
113
  objectName: string;
114
114
  /** Object type ('table' or 'view') */
@@ -311,6 +311,53 @@ interface ColumnInfo {
311
311
  label?: string;
312
312
  }
313
313
 
314
+ /**
315
+ * Query Builder — Optional helper for building SQL queries for data preview
316
+ */
317
+
318
+ type BasicFilter = {
319
+ type: "basic";
320
+ field: string;
321
+ value: string | number;
322
+ operator: "=" | "<>" | "<" | "<=" | ">" | ">=" | "like" | "not like";
323
+ };
324
+ type BetweenFilter = {
325
+ type: "between";
326
+ field: string;
327
+ minimum: string | number;
328
+ maximum: string | number;
329
+ };
330
+ type ListFilter = {
331
+ type: "list";
332
+ field: string;
333
+ values: (string | number)[];
334
+ include: boolean;
335
+ };
336
+ type QueryFilter = BasicFilter | BetweenFilter | ListFilter;
337
+ type Sorting = {
338
+ field: string;
339
+ direction: "ascending" | "descending";
340
+ };
341
+ type Aggregation = {
342
+ field: string;
343
+ function: "count" | "sum" | "avg" | "min" | "max";
344
+ };
345
+ type Parameter = {
346
+ name: string;
347
+ value: string | number;
348
+ };
349
+ type DataPreviewQuery = {
350
+ objectName: string;
351
+ objectType: 'table' | 'view';
352
+ limit?: number;
353
+ fields: string[];
354
+ parameters?: Parameter[];
355
+ filters?: QueryFilter[];
356
+ sortings?: Sorting[];
357
+ aggregations?: Aggregation[];
358
+ };
359
+ declare function buildSQLQuery(query: DataPreviewQuery): Result<PreviewSQL>;
360
+
314
361
  /**
315
362
  * Distinct Values — Get distinct column values with counts
316
363
  */
@@ -433,8 +480,8 @@ interface ADTClient {
433
480
  getPackages(): AsyncResult<Package[]>;
434
481
  getTree(query: TreeQuery): AsyncResult<TreeNode[]>;
435
482
  getTransports(packageName: string): AsyncResult<Transport[]>;
436
- previewData(query: PreviewQuery): AsyncResult<DataFrame>;
437
- getDistinctValues(objectName: string, column: string, objectType?: 'table' | 'view'): AsyncResult<DistinctResult>;
483
+ previewData(query: PreviewSQL): AsyncResult<DataFrame>;
484
+ getDistinctValues(objectName: string, parameters: Parameter[], column: string, objectType?: 'table' | 'view'): AsyncResult<DistinctResult>;
438
485
  countRows(objectName: string, objectType: 'table' | 'view'): AsyncResult<number>;
439
486
  search(query: string, types?: string[]): AsyncResult<SearchResult[]>;
440
487
  whereUsed(object: ObjectRef): AsyncResult<Dependency[]>;
@@ -444,4 +491,4 @@ interface ADTClient {
444
491
  }
445
492
  declare function createClient(config: ClientConfig): Result<ADTClient, Error>;
446
493
 
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 };
494
+ export { type ADTClient, type ActivationMessage, type ActivationResult, type Aggregation, type ApiResponse, type AsyncResult, type AuthConfig, type AuthType, type BasicAuthConfig, type BasicFilter, type BetweenFilter, type ClientConfig, type ColumnInfo, type DataFrame, type DataPreviewQuery, type Dependency, type DiffResult, type DistinctResult, type ErrorCode, type ErrorResponse, type ListFilter, type ObjectConfig, type ObjectContent, type ObjectMetadata, type ObjectRef, type ObjectWithContent, type Package, type Parameter, type PreviewSQL, type QueryFilter, type Result, type SamlAuthConfig, type SearchResult, type Session, type Sorting, type SsoAuthConfig, type SuccessResponse, type Transport, type TransportConfig, type TreeNode, type TreeQuery, type UpsertResult, buildSQLQuery, createClient, err, ok };
package/dist/index.d.ts CHANGED
@@ -108,7 +108,7 @@ interface TreeQuery {
108
108
  /**
109
109
  * Data preview query
110
110
  */
111
- interface PreviewQuery {
111
+ interface PreviewSQL {
112
112
  /** Object name (table or CDS view) */
113
113
  objectName: string;
114
114
  /** Object type ('table' or 'view') */
@@ -311,6 +311,53 @@ interface ColumnInfo {
311
311
  label?: string;
312
312
  }
313
313
 
314
+ /**
315
+ * Query Builder — Optional helper for building SQL queries for data preview
316
+ */
317
+
318
+ type BasicFilter = {
319
+ type: "basic";
320
+ field: string;
321
+ value: string | number;
322
+ operator: "=" | "<>" | "<" | "<=" | ">" | ">=" | "like" | "not like";
323
+ };
324
+ type BetweenFilter = {
325
+ type: "between";
326
+ field: string;
327
+ minimum: string | number;
328
+ maximum: string | number;
329
+ };
330
+ type ListFilter = {
331
+ type: "list";
332
+ field: string;
333
+ values: (string | number)[];
334
+ include: boolean;
335
+ };
336
+ type QueryFilter = BasicFilter | BetweenFilter | ListFilter;
337
+ type Sorting = {
338
+ field: string;
339
+ direction: "ascending" | "descending";
340
+ };
341
+ type Aggregation = {
342
+ field: string;
343
+ function: "count" | "sum" | "avg" | "min" | "max";
344
+ };
345
+ type Parameter = {
346
+ name: string;
347
+ value: string | number;
348
+ };
349
+ type DataPreviewQuery = {
350
+ objectName: string;
351
+ objectType: 'table' | 'view';
352
+ limit?: number;
353
+ fields: string[];
354
+ parameters?: Parameter[];
355
+ filters?: QueryFilter[];
356
+ sortings?: Sorting[];
357
+ aggregations?: Aggregation[];
358
+ };
359
+ declare function buildSQLQuery(query: DataPreviewQuery): Result<PreviewSQL>;
360
+
314
361
  /**
315
362
  * Distinct Values — Get distinct column values with counts
316
363
  */
@@ -433,8 +480,8 @@ interface ADTClient {
433
480
  getPackages(): AsyncResult<Package[]>;
434
481
  getTree(query: TreeQuery): AsyncResult<TreeNode[]>;
435
482
  getTransports(packageName: string): AsyncResult<Transport[]>;
436
- previewData(query: PreviewQuery): AsyncResult<DataFrame>;
437
- getDistinctValues(objectName: string, column: string, objectType?: 'table' | 'view'): AsyncResult<DistinctResult>;
483
+ previewData(query: PreviewSQL): AsyncResult<DataFrame>;
484
+ getDistinctValues(objectName: string, parameters: Parameter[], column: string, objectType?: 'table' | 'view'): AsyncResult<DistinctResult>;
438
485
  countRows(objectName: string, objectType: 'table' | 'view'): AsyncResult<number>;
439
486
  search(query: string, types?: string[]): AsyncResult<SearchResult[]>;
440
487
  whereUsed(object: ObjectRef): AsyncResult<Dependency[]>;
@@ -444,4 +491,4 @@ interface ADTClient {
444
491
  }
445
492
  declare function createClient(config: ClientConfig): Result<ADTClient, Error>;
446
493
 
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 };
494
+ export { type ADTClient, type ActivationMessage, type ActivationResult, type Aggregation, type ApiResponse, type AsyncResult, type AuthConfig, type AuthType, type BasicAuthConfig, type BasicFilter, type BetweenFilter, type ClientConfig, type ColumnInfo, type DataFrame, type DataPreviewQuery, type Dependency, type DiffResult, type DistinctResult, type ErrorCode, type ErrorResponse, type ListFilter, type ObjectConfig, type ObjectContent, type ObjectMetadata, type ObjectRef, type ObjectWithContent, type Package, type Parameter, type PreviewSQL, type QueryFilter, type Result, type SamlAuthConfig, type SearchResult, type Session, type Sorting, type SsoAuthConfig, type SuccessResponse, type Transport, type TransportConfig, type TreeNode, type TreeQuery, type UpsertResult, buildSQLQuery, createClient, err, ok };
package/dist/index.js CHANGED
@@ -30,6 +30,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.ts
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
+ buildSQLQuery: () => buildSQLQuery,
33
34
  createClient: () => createClient,
34
35
  err: () => err,
35
36
  ok: () => ok
@@ -404,7 +405,7 @@ function requireConfig(extension) {
404
405
  return [config, null];
405
406
  }
406
407
 
407
- // src/core/adt/read.ts
408
+ // src/core/adt/craud/read.ts
408
409
  async function readObject(client, object) {
409
410
  const [config, configErr] = requireConfig(object.extension);
410
411
  if (configErr) return err(configErr);
@@ -428,7 +429,7 @@ async function readObject(client, object) {
428
429
  return ok(result);
429
430
  }
430
431
 
431
- // src/core/adt/lock.ts
432
+ // src/core/adt/craud/lock.ts
432
433
  async function lockObject(client, object) {
433
434
  const [config, configErr] = requireConfig(object.extension);
434
435
  if (configErr) return err(configErr);
@@ -476,7 +477,7 @@ async function unlockObject(client, object, lockHandle) {
476
477
  return ok(void 0);
477
478
  }
478
479
 
479
- // src/core/adt/create.ts
480
+ // src/core/adt/craud/create.ts
480
481
  async function createObject(client, object, packageName, transport, username) {
481
482
  const [config, configErr] = requireConfig(object.extension);
482
483
  if (configErr) return err(configErr);
@@ -513,7 +514,7 @@ async function createObject(client, object, packageName, transport, username) {
513
514
  return ok(void 0);
514
515
  }
515
516
 
516
- // src/core/adt/update.ts
517
+ // src/core/adt/craud/update.ts
517
518
  async function updateObject(client, object, lockHandle, transport) {
518
519
  const [config, configErr] = requireConfig(object.extension);
519
520
  if (configErr) return err(configErr);
@@ -541,7 +542,7 @@ async function updateObject(client, object, lockHandle, transport) {
541
542
  return ok(void 0);
542
543
  }
543
544
 
544
- // src/core/adt/delete.ts
545
+ // src/core/adt/craud/delete.ts
545
546
  async function deleteObject(client, object, lockHandle, transport) {
546
547
  const [config, configErr] = requireConfig(object.extension);
547
548
  if (configErr) return err(configErr);
@@ -566,7 +567,7 @@ async function deleteObject(client, object, lockHandle, transport) {
566
567
  return ok(void 0);
567
568
  }
568
569
 
569
- // src/core/adt/activation.ts
570
+ // src/core/adt/craud/activation.ts
570
571
  async function activateObjects(client, objects) {
571
572
  if (objects.length === 0) {
572
573
  return ok([]);
@@ -676,7 +677,7 @@ function extractActivationErrors(objects, xml, _extension) {
676
677
  return ok(results);
677
678
  }
678
679
 
679
- // src/core/adt/tree.ts
680
+ // src/core/adt/discovery/tree.ts
680
681
  async function getTree(client, query) {
681
682
  const internalQuery = {};
682
683
  if (query.package) {
@@ -793,7 +794,7 @@ function parseTreeResponse(xml) {
793
794
  return ok({ nodes, packages });
794
795
  }
795
796
 
796
- // src/core/adt/packages.ts
797
+ // src/core/adt/discovery/packages.ts
797
798
  async function getPackages(client) {
798
799
  const [treeResult, treeErr] = await getTreeInternal(client, {}, "*");
799
800
  if (treeErr) {
@@ -802,7 +803,7 @@ async function getPackages(client) {
802
803
  return ok(treeResult.packages);
803
804
  }
804
805
 
805
- // src/core/adt/transports.ts
806
+ // src/core/adt/transports/transports.ts
806
807
  async function getTransports(client, packageName) {
807
808
  const contentType = "application/vnd.sap.as+xml; charset=UTF-8; dataname=com.sap.adt.transport.service.checkData";
808
809
  const body = `<?xml version="1.0" encoding="UTF-8"?>
@@ -871,7 +872,7 @@ function extractTransports(xml) {
871
872
  return ok(transports);
872
873
  }
873
874
 
874
- // src/core/adt/previewParser.ts
875
+ // src/core/adt/data_extraction/previewParser.ts
875
876
  function parseDataPreview(xml, maxRows, isTable) {
876
877
  const [doc, parseErr] = safeParseXml(xml);
877
878
  if (parseErr) {
@@ -930,7 +931,7 @@ function parseDataPreview(xml, maxRows, isTable) {
930
931
  return ok(dataFrame);
931
932
  }
932
933
 
933
- // src/core/adt/dataPreview.ts
934
+ // src/core/adt/data_extraction/dataPreview.ts
934
935
  async function previewData(client, query) {
935
936
  const extension = query.objectType === "table" ? "astabldt" : "asddls";
936
937
  const config = getConfigByExtension(extension);
@@ -970,11 +971,83 @@ async function previewData(client, query) {
970
971
  return ok(dataFrame);
971
972
  }
972
973
 
973
- // src/core/adt/distinct.ts
974
+ // src/core/adt/data_extraction/queryBuilder.ts
975
+ function quoteString(value) {
976
+ return typeof value == "string" ? "'" + value + "'" : "" + value;
977
+ }
978
+ function basicFilterToWhere(filter) {
979
+ return `${filter.field} ${filter.operator} ${quoteString(filter.value)}`;
980
+ }
981
+ function betweenFilterToWhere(filter) {
982
+ return `${filter.field} between ${quoteString(filter.minimum)} and ${quoteString(filter.maximum)}`;
983
+ }
984
+ function listFilterToWhere(filter) {
985
+ return `${filter.field} ${filter.include ? "" : "not "}in ( ${filter.values.map(quoteString).join(", ")} )`;
986
+ }
987
+ function queryFilterToWhere(filter) {
988
+ if (filter.type === "list") return listFilterToWhere(filter);
989
+ if (filter.type === "between") return betweenFilterToWhere(filter);
990
+ return basicFilterToWhere(filter);
991
+ }
992
+ function queryFiltersToWhere(filters) {
993
+ if (filters.length === 0) return "";
994
+ return `
995
+ where ${filters.map(queryFilterToWhere).join(" and ")}`;
996
+ }
997
+ function sortingsToOrderBy(sortings) {
998
+ if (sortings.length === 0) return "";
999
+ return `
1000
+ order by ${sortings.map((s) => `${s.field} ${s.direction}`).join(", ")}`;
1001
+ }
1002
+ function fieldsToGroupbyClause(fields) {
1003
+ if (fields.length === 0) return "";
1004
+ return `
1005
+ group by ${fields.join(", ")}`;
1006
+ }
1007
+ function aggregationToFieldDefinition(aggregation) {
1008
+ if (aggregation.function === "count") {
1009
+ return `count( distinct main~${aggregation.field} ) as ${aggregation.field}`;
1010
+ }
1011
+ return `${aggregation.function}( main~${aggregation.field} ) as ${aggregation.field}`;
1012
+ }
1013
+ function parametersToSQLParams(params) {
1014
+ if (params.length === 0) return "";
1015
+ return `( ${params.map((p) => `${p.name} = ${quoteString(p.value)}`).join(", ")})`;
1016
+ }
1017
+ function buildSQLQuery(query) {
1018
+ const [parameters, filters, sortings, aggregations] = [query.parameters ?? [], query.filters ?? [], query.sortings ?? [], query.aggregations ?? []];
1019
+ const groupingFields = query.fields.filter((f) => !aggregations.find((a) => a.field === f));
1020
+ if (sortings.filter((s) => !query.fields.includes(s.field)).length > 0) {
1021
+ return err(new Error("Sorting fields must be included in the selected fields."));
1022
+ }
1023
+ let selectClause = "select\n";
1024
+ const fieldSelections = [];
1025
+ for (const field of query.fields) {
1026
+ const aggregation = aggregations.find((a) => a.field === field);
1027
+ if (aggregation) {
1028
+ fieldSelections.push(` ${aggregationToFieldDefinition(aggregation)}`);
1029
+ continue;
1030
+ }
1031
+ fieldSelections.push(` main~${field}`);
1032
+ }
1033
+ selectClause += fieldSelections.join(",\n") + `
1034
+ from ${query.objectName}${parametersToSQLParams(parameters)} as main
1035
+ `;
1036
+ const [whereClause, groupbyClause, orderbyClause] = [queryFiltersToWhere(filters), aggregations.length ? fieldsToGroupbyClause(groupingFields) : "", sortingsToOrderBy(sortings)];
1037
+ const result = {
1038
+ objectName: query.objectName,
1039
+ objectType: query.objectType,
1040
+ sqlQuery: `${selectClause}${whereClause}${groupbyClause}${orderbyClause}`
1041
+ };
1042
+ if (query.limit !== void 0) result.limit = query.limit;
1043
+ return ok(result);
1044
+ }
1045
+
1046
+ // src/core/adt/data_extraction/distinct.ts
974
1047
  var MAX_ROW_COUNT = 5e4;
975
- async function getDistinctValues(client, objectName, column, objectType = "view") {
1048
+ async function getDistinctValues(client, objectName, parameters, column, objectType = "view") {
976
1049
  const columnName = column.toUpperCase();
977
- const sqlQuery = `SELECT ${columnName} AS value, COUNT(*) AS count FROM ${objectName} GROUP BY ${columnName}`;
1050
+ const sqlQuery = `SELECT ${columnName} AS value, COUNT(*) AS ValueCount FROM ${objectName}${parametersToSQLParams(parameters)} GROUP BY ${columnName} ORDER BY ValueCount DESCENDING`;
978
1051
  const [dataFrame, error] = await previewData(client, {
979
1052
  objectName,
980
1053
  objectType,
@@ -991,7 +1064,7 @@ async function getDistinctValues(client, objectName, column, objectType = "view"
991
1064
  return ok({ column, values });
992
1065
  }
993
1066
 
994
- // src/core/adt/count.ts
1067
+ // src/core/adt/data_extraction/count.ts
995
1068
  async function countRows(client, objectName, objectType) {
996
1069
  const sqlQuery = `SELECT COUNT(*) AS count FROM ${objectName}`;
997
1070
  const [dataFrame, error] = await previewData(client, {
@@ -1014,7 +1087,7 @@ async function countRows(client, objectName, objectType) {
1014
1087
  return ok(count);
1015
1088
  }
1016
1089
 
1017
- // src/core/adt/searchObjects.ts
1090
+ // src/core/adt/discovery/searchObjects.ts
1018
1091
  async function searchObjects(client, query, types) {
1019
1092
  const searchPattern = query || "*";
1020
1093
  const objectTypes = types && types.length > 0 ? types : getAllTypes();
@@ -1081,7 +1154,7 @@ function parseSearchResults(xml) {
1081
1154
  return ok(results);
1082
1155
  }
1083
1156
 
1084
- // src/core/adt/whereUsed.ts
1157
+ // src/core/adt/discovery/whereUsed.ts
1085
1158
  async function findWhereUsed(client, object) {
1086
1159
  const config = getConfigByExtension(object.extension);
1087
1160
  if (!config) {
@@ -1155,7 +1228,7 @@ function parseWhereUsed(xml) {
1155
1228
  return ok(dependencies);
1156
1229
  }
1157
1230
 
1158
- // src/core/adt/createTransport.ts
1231
+ // src/core/adt/transports/createTransport.ts
1159
1232
  async function createTransport(client, config) {
1160
1233
  const body = dictToAbapXml({
1161
1234
  DEVCLASS: config.package,
@@ -1186,7 +1259,7 @@ async function createTransport(client, config) {
1186
1259
  return ok(transportId);
1187
1260
  }
1188
1261
 
1189
- // src/core/adt/gitDiff.ts
1262
+ // src/core/adt/craud/gitDiff.ts
1190
1263
  var import_diff = require("diff");
1191
1264
  function computeDiff(serverLines, localLines) {
1192
1265
  const changes = (0, import_diff.diffArrays)(serverLines, localLines);
@@ -2134,9 +2207,9 @@ var ADTClientImpl = class {
2134
2207
  if (!this.state.session) return err(new Error("Not logged in"));
2135
2208
  return previewData(this.requestor, query);
2136
2209
  }
2137
- async getDistinctValues(objectName, column, objectType = "view") {
2210
+ async getDistinctValues(objectName, parameters, column, objectType = "view") {
2138
2211
  if (!this.state.session) return err(new Error("Not logged in"));
2139
- return getDistinctValues(this.requestor, objectName, column, objectType);
2212
+ return getDistinctValues(this.requestor, objectName, parameters, column, objectType);
2140
2213
  }
2141
2214
  async countRows(objectName, objectType) {
2142
2215
  if (!this.state.session) return err(new Error("Not logged in"));
@@ -2181,20 +2254,9 @@ function createClient(config) {
2181
2254
  }
2182
2255
  return ok(new ADTClientImpl(config));
2183
2256
  }
2184
-
2185
- // src/core/config.ts
2186
- var import_node_fs = require("fs");
2187
- var import_zod2 = require("zod");
2188
- var systemConfigSchema = import_zod2.z.record(
2189
- import_zod2.z.string(),
2190
- import_zod2.z.object({
2191
- adt: import_zod2.z.string().url().optional(),
2192
- odata: import_zod2.z.string().url().optional(),
2193
- instance_num: import_zod2.z.string().optional()
2194
- })
2195
- );
2196
2257
  // Annotate the CommonJS export names for ESM import in node:
2197
2258
  0 && (module.exports = {
2259
+ buildSQLQuery,
2198
2260
  createClient,
2199
2261
  err,
2200
2262
  ok