@sasjs/adapter 4.11.3 → 4.12.1

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.
@@ -0,0 +1,32 @@
1
+ export interface FileResource {
2
+ creationTimeStamp: string;
3
+ modifiedTimeStamp: string;
4
+ createdBy: string;
5
+ modifiedBy: string;
6
+ id: string;
7
+ properties: Properties;
8
+ contentDisposition: string;
9
+ contentType: string;
10
+ encoding: string;
11
+ links: Link[];
12
+ name: string;
13
+ size: number;
14
+ searchable: boolean;
15
+ fileStatus: string;
16
+ fileVersion: number;
17
+ typeDefName: string;
18
+ version: number;
19
+ virusDetected: boolean;
20
+ urlDetected: boolean;
21
+ quarantine: boolean;
22
+ }
23
+ export interface Link {
24
+ method: string;
25
+ rel: string;
26
+ href: string;
27
+ uri: string;
28
+ type?: string;
29
+ responseType?: string;
30
+ }
31
+ export interface Properties {
32
+ }
package/package.json CHANGED
@@ -86,5 +86,5 @@
86
86
  "https": "1.0.0",
87
87
  "tough-cookie": "4.1.3"
88
88
  },
89
- "version": "4.11.3"
89
+ "version": "4.12.1"
90
90
  }
@@ -28,6 +28,7 @@ import { uploadTables } from './api/viya/uploadTables'
28
28
  import { executeOnComputeApi } from './api/viya/executeOnComputeApi'
29
29
  import { getAccessTokenForViya } from './auth/getAccessTokenForViya'
30
30
  import { refreshTokensForViya } from './auth/refreshTokensForViya'
31
+ import { FileResource } from './types/FileResource'
31
32
 
32
33
  interface JobExecutionResult {
33
34
  result?: { result: object }
@@ -311,6 +312,84 @@ export class SASViyaApiClient {
311
312
  )
312
313
  }
313
314
 
315
+ /**
316
+ * Fetches the file content for a file in the specified folder.
317
+ *
318
+ * @param folderPath - the full path to the folder containing the file. eg: /Public/folder1/folder2
319
+ * @param fileName - the name of the file in the `folderPath`
320
+ * @param accessToken - an access token for authorizing the request
321
+ */
322
+ public async getFileContent(
323
+ folderPath: string,
324
+ fileName: string,
325
+ accessToken?: string
326
+ ) {
327
+ const fileUri = await this.getFileUri(
328
+ folderPath,
329
+ fileName,
330
+ accessToken
331
+ ).catch((err) => {
332
+ throw prefixMessage(
333
+ err,
334
+ `Error while getting file URI for: ${fileName} in folder: ${folderPath}. `
335
+ )
336
+ })
337
+
338
+ return await this.requestClient
339
+ .get<string>(`${this.serverUrl}${fileUri}/content`, accessToken)
340
+ .then((res) => res.result)
341
+ }
342
+
343
+ /**
344
+ * Updates the file content for a file in the specified folder.
345
+ *
346
+ * @param folderPath - the full path to the folder containing the file. eg: /Public/folder1/folder2
347
+ * @param fileName - the name of the file in the `folderPath`
348
+ * @param content - the new content to be written to the file
349
+ * @param accessToken - an access token for authorizing the request
350
+ */
351
+ public async updateFileContent(
352
+ folderPath: string,
353
+ fileName: string,
354
+ content: string,
355
+ accessToken?: string
356
+ ) {
357
+ const fileUri = await this.getFileUri(
358
+ folderPath,
359
+ fileName,
360
+ accessToken
361
+ ).catch((err) => {
362
+ throw prefixMessage(
363
+ err,
364
+ `Error while getting file URI for: ${fileName} in folder: ${folderPath}. `
365
+ )
366
+ })
367
+
368
+ // Fetch the file resource details to get the Etag and content type
369
+ const { result: originalFileResource, etag } =
370
+ await this.requestClient.get<FileResource>(
371
+ `${this.serverUrl}${fileUri}`,
372
+ accessToken
373
+ )
374
+
375
+ if (!originalFileResource || !etag)
376
+ throw new Error(
377
+ `File ${fileName} does not have an ETag, or request failed.`
378
+ )
379
+
380
+ return await this.requestClient
381
+ .put<FileResource>(
382
+ `${this.serverUrl}${fileUri}/content`,
383
+ content,
384
+ accessToken,
385
+ {
386
+ 'If-Match': etag,
387
+ 'Content-Type': originalFileResource.contentType
388
+ }
389
+ )
390
+ .then((res) => res.result)
391
+ }
392
+
314
393
  /**
315
394
  * Fetches a folder. Path to the folder is required.
316
395
  * @param folderPath - the absolute path to the folder.
@@ -791,14 +870,14 @@ export class SASViyaApiClient {
791
870
  _webin_file_count: files.length,
792
871
  _OMITJSONLISTING: true,
793
872
  _OMITJSONLOG: true,
794
- _OMITSESSIONRESULTS: true,
873
+ _omitSessionResults: false,
795
874
  _OMITTEXTLISTING: true,
796
875
  _OMITTEXTLOG: true
797
876
  }
798
877
 
799
878
  if (debug) {
800
879
  jobArguments['_OMITTEXTLOG'] = 'false'
801
- jobArguments['_OMITSESSIONRESULTS'] = 'false'
880
+ jobArguments['_omitSessionResults'] = 'false'
802
881
  jobArguments['_DEBUG'] = 131
803
882
  }
804
883
 
@@ -941,6 +1020,7 @@ export class SASViyaApiClient {
941
1020
  })
942
1021
 
943
1022
  if (!folder) return undefined
1023
+
944
1024
  return folder
945
1025
  }
946
1026
 
@@ -952,6 +1032,30 @@ export class SASViyaApiClient {
952
1032
  return `/folders/folders/${folderDetails.id}`
953
1033
  }
954
1034
 
1035
+ private async getFileUri(
1036
+ folderPath: string,
1037
+ fileName: string,
1038
+ accessToken?: string
1039
+ ): Promise<string> {
1040
+ const folderMembers = await this.listFolder(folderPath, accessToken, 1000, {
1041
+ returnDetails: true
1042
+ }).catch((err) => {
1043
+ throw prefixMessage(err, `Error while listing folder: ${folderPath}. `)
1044
+ })
1045
+
1046
+ if (!folderMembers || !folderMembers.length)
1047
+ throw new Error(`No members found in folder: ${folderPath}`)
1048
+
1049
+ const fileUri = folderMembers.find(
1050
+ (member) => member.name === fileName
1051
+ )?.uri
1052
+
1053
+ if (!fileUri)
1054
+ throw new Error(`File ${fileName} not found in folder: ${folderPath}`)
1055
+
1056
+ return fileUri
1057
+ }
1058
+
955
1059
  private async getRecycleBinUri(accessToken?: string) {
956
1060
  const url = '/folders/folders/@myRecycleBin'
957
1061
 
@@ -999,14 +1103,19 @@ export class SASViyaApiClient {
999
1103
  }
1000
1104
 
1001
1105
  /**
1002
- * Lists children folders for given Viya folder.
1106
+ * Lists children folders/files for given Viya folder.
1003
1107
  * @param sourceFolder - the full path (eg `/Public/example/myFolder`) or URI of the source folder listed. Providing URI instead of path will save one extra request.
1004
1108
  * @param accessToken - an access token for authorizing the request.
1109
+ * @param {Object} [options] - Additional options.
1110
+ * @param {boolean} [options.returnDetails=false] - when set to true, the function will return an array of objects with member details, otherwise it will return an array of member names.
1005
1111
  */
1006
1112
  public async listFolder(
1007
1113
  sourceFolder: string,
1008
1114
  accessToken?: string,
1009
- limit: number = 20
1115
+ limit: number = 20,
1116
+ options?: {
1117
+ returnDetails?: boolean
1118
+ }
1010
1119
  ) {
1011
1120
  // checks if 'sourceFolder' is already a URI
1012
1121
  const sourceFolderUri = isUri(sourceFolder)
@@ -1018,11 +1127,20 @@ export class SASViyaApiClient {
1018
1127
  accessToken
1019
1128
  )
1020
1129
 
1130
+ let membersToReturn = []
1131
+
1021
1132
  if (members && members.items) {
1022
- return members.items.map((item: any) => item.name)
1023
- } else {
1024
- return []
1133
+ // If returnDetails is true, return full member details
1134
+ if (options?.returnDetails) {
1135
+ membersToReturn = members.items
1136
+ } else {
1137
+ // If returnDetails is false, return only member names
1138
+ membersToReturn = members.items.map((item: any) => item.name)
1139
+ }
1025
1140
  }
1141
+
1142
+ // Return members without Etag
1143
+ return membersToReturn
1026
1144
  }
1027
1145
 
1028
1146
  /**
package/src/SASjs.ts CHANGED
@@ -411,6 +411,51 @@ export default class SASjs {
411
411
  )
412
412
  }
413
413
 
414
+ /**
415
+ * Fetches the file content for a file in the specified folder.
416
+ *
417
+ * @param folderPath - the full path to the folder containing the file. eg: /Public/folder1/folder2
418
+ * @param fileName - the name of the file in the `folderPath`
419
+ * @param accessToken - an access token for authorizing the request
420
+ */
421
+ public async getFileContent(
422
+ folderPath: string,
423
+ fileName: string,
424
+ accessToken?: string
425
+ ) {
426
+ this.isMethodSupported('getFileContent', [ServerType.SasViya])
427
+
428
+ return await this.sasViyaApiClient!.getFileContent(
429
+ folderPath,
430
+ fileName,
431
+ accessToken
432
+ )
433
+ }
434
+
435
+ /**
436
+ * Updates the file content for a file in the specified folder.
437
+ *
438
+ * @param folderPath - the full path to the folder containing the file. eg: /Public/folder1/folder2
439
+ * @param fileName - the name of the file in the `folderPath`
440
+ * @param content - the new content to be written to the file
441
+ * @param accessToken - an access token for authorizing the request
442
+ */
443
+ public async updateFileContent(
444
+ folderPath: string,
445
+ fileName: string,
446
+ content: string,
447
+ accessToken?: string
448
+ ) {
449
+ this.isMethodSupported('updateFileContent', [ServerType.SasViya])
450
+
451
+ return await this.sasViyaApiClient!.updateFileContent(
452
+ folderPath,
453
+ fileName,
454
+ content,
455
+ accessToken
456
+ )
457
+ }
458
+
414
459
  /**
415
460
  * Fetches a folder from the SAS file system.
416
461
  * @param folderPath - path of the folder to be fetched.
@@ -436,18 +481,23 @@ export default class SASjs {
436
481
  * Lists children folders for given Viya folder.
437
482
  * @param sourceFolder - the full path (eg `/Public/example/myFolder`) or URI of the source folder listed. Providing URI instead of path will save one extra request.
438
483
  * @param accessToken - an access token for authorizing the request.
484
+ * @param returnDetails - when set to true, the function will return an array of objects with member details, otherwise it will return an array of member names.
439
485
  */
440
486
  public async listFolder(
441
487
  sourceFolder: string,
442
488
  accessToken?: string,
443
- limit?: number
489
+ limit?: number,
490
+ returnDetails = false
444
491
  ) {
445
492
  this.isMethodSupported('listFolder', [ServerType.SasViya])
446
493
 
447
494
  return await this.sasViyaApiClient?.listFolder(
448
495
  sourceFolder,
449
496
  accessToken,
450
- limit
497
+ limit,
498
+ {
499
+ returnDetails
500
+ }
451
501
  )
452
502
  }
453
503
 
@@ -51,7 +51,7 @@ export abstract class BaseJobExecutor implements JobExecutor {
51
51
 
52
52
  if (config.debug) {
53
53
  requestParams['_omittextlog'] = 'false'
54
- requestParams['_omitsessionresults'] = 'false'
54
+ requestParams['_omitSessionResults'] = 'false'
55
55
 
56
56
  requestParams['_debug'] = 131
57
57
  }
@@ -0,0 +1,33 @@
1
+ export interface FileResource {
2
+ creationTimeStamp: string
3
+ modifiedTimeStamp: string
4
+ createdBy: string
5
+ modifiedBy: string
6
+ id: string
7
+ properties: Properties
8
+ contentDisposition: string
9
+ contentType: string
10
+ encoding: string
11
+ links: Link[]
12
+ name: string
13
+ size: number
14
+ searchable: boolean
15
+ fileStatus: string
16
+ fileVersion: number
17
+ typeDefName: string
18
+ version: number
19
+ virusDetected: boolean
20
+ urlDetected: boolean
21
+ quarantine: boolean
22
+ }
23
+
24
+ export interface Link {
25
+ method: string
26
+ rel: string
27
+ href: string
28
+ uri: string
29
+ type?: string
30
+ responseType?: string
31
+ }
32
+
33
+ export interface Properties {}
@@ -0,0 +1,32 @@
1
+ export interface FileResource {
2
+ creationTimeStamp: string;
3
+ modifiedTimeStamp: string;
4
+ createdBy: string;
5
+ modifiedBy: string;
6
+ id: string;
7
+ properties: Properties;
8
+ contentDisposition: string;
9
+ contentType: string;
10
+ encoding: string;
11
+ links: Link[];
12
+ name: string;
13
+ size: number;
14
+ searchable: boolean;
15
+ fileStatus: string;
16
+ fileVersion: number;
17
+ typeDefName: string;
18
+ version: number;
19
+ virusDetected: boolean;
20
+ urlDetected: boolean;
21
+ quarantine: boolean;
22
+ }
23
+ export interface Link {
24
+ method: string;
25
+ rel: string;
26
+ href: string;
27
+ uri: string;
28
+ type?: string;
29
+ responseType?: string;
30
+ }
31
+ export interface Properties {
32
+ }