mirror of
https://github.com/sasjs/adapter.git
synced 2026-01-07 12:30:06 +00:00
Compare commits
32 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f679b17cbe | ||
|
|
36a0f0e743 | ||
|
|
ad563b9bc8 | ||
|
|
893cce7f21 | ||
|
|
bf7e8fd0e6 | ||
|
|
50be3acc78 | ||
|
|
66c12a69bb | ||
|
|
e2058f0c71 | ||
|
|
75a74152a5 | ||
|
|
9344c4fd35 | ||
|
|
be0fe00076 | ||
|
|
a2069ee48b | ||
|
|
907885cf85 | ||
|
|
f10ed3236e | ||
|
|
a852a0af7c | ||
|
|
03f3550774 | ||
|
|
2e8d06f9e1 | ||
|
|
7a6e6e8333 | ||
|
|
cc594eca52 | ||
|
|
3fbca2835e | ||
|
|
61ed5c4fa7 | ||
|
|
9b6ba3548f | ||
|
|
efa4c71b8a | ||
|
|
ecfc1a4bf8 | ||
|
|
246b855c76 | ||
|
|
80aa848617 | ||
|
|
acf045965e | ||
|
|
5a7f64dc35 | ||
|
|
de447b0727 | ||
|
|
ace16efd93 | ||
|
|
13ae5ae756 | ||
|
|
f1b035032f |
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
328
docs/classes/auth.authmanager.html
Normal file
328
docs/classes/auth.authmanager.html
Normal file
File diff suppressed because one or more lines are too long
432
docs/classes/job_execution.basejobexecutor.html
Normal file
432
docs/classes/job_execution.basejobexecutor.html
Normal file
File diff suppressed because one or more lines are too long
435
docs/classes/job_execution.computejobexecutor.html
Normal file
435
docs/classes/job_execution.computejobexecutor.html
Normal file
File diff suppressed because one or more lines are too long
435
docs/classes/job_execution.jesjobexecutor.html
Normal file
435
docs/classes/job_execution.jesjobexecutor.html
Normal file
File diff suppressed because one or more lines are too long
441
docs/classes/job_execution.webjobexecutor.html
Normal file
441
docs/classes/job_execution.webjobexecutor.html
Normal file
File diff suppressed because one or more lines are too long
231
docs/classes/reflection-817.reflection-220.fileuploader.html
Normal file
231
docs/classes/reflection-817.reflection-220.fileuploader.html
Normal file
File diff suppressed because one or more lines are too long
312
docs/classes/reflection-817.reflection-220.sas9apiclient.html
Normal file
312
docs/classes/reflection-817.reflection-220.sas9apiclient.html
Normal file
File diff suppressed because one or more lines are too long
1715
docs/classes/reflection-817.reflection-220.sasjs.html
Normal file
1715
docs/classes/reflection-817.reflection-220.sasjs.html
Normal file
File diff suppressed because one or more lines are too long
1516
docs/classes/reflection-817.reflection-220.sasviyaapiclient.html
Normal file
1516
docs/classes/reflection-817.reflection-220.sasviyaapiclient.html
Normal file
File diff suppressed because one or more lines are too long
323
docs/classes/reflection-817.reflection-220.sessionmanager.html
Normal file
323
docs/classes/reflection-817.reflection-220.sessionmanager.html
Normal file
File diff suppressed because one or more lines are too long
231
docs/classes/reflection-830.reflection-222.fileuploader.html
Normal file
231
docs/classes/reflection-830.reflection-222.fileuploader.html
Normal file
File diff suppressed because one or more lines are too long
312
docs/classes/reflection-830.reflection-222.sas9apiclient.html
Normal file
312
docs/classes/reflection-830.reflection-222.sas9apiclient.html
Normal file
File diff suppressed because one or more lines are too long
1721
docs/classes/reflection-830.reflection-222.sasjs.html
Normal file
1721
docs/classes/reflection-830.reflection-222.sasjs.html
Normal file
File diff suppressed because one or more lines are too long
1528
docs/classes/reflection-830.reflection-222.sasviyaapiclient.html
Normal file
1528
docs/classes/reflection-830.reflection-222.sasviyaapiclient.html
Normal file
File diff suppressed because one or more lines are too long
360
docs/classes/reflection-830.reflection-222.sessionmanager.html
Normal file
360
docs/classes/reflection-830.reflection-222.sessionmanager.html
Normal file
File diff suppressed because one or more lines are too long
548
docs/classes/request.requestclient.html
Normal file
548
docs/classes/request.requestclient.html
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
328
docs/classes/types.authorizeerror.html
Normal file
328
docs/classes/types.authorizeerror.html
Normal file
File diff suppressed because one or more lines are too long
346
docs/classes/types.computejobexecutionerror.html
Normal file
346
docs/classes/types.computejobexecutionerror.html
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
367
docs/classes/types.jobexecutionerror.html
Normal file
367
docs/classes/types.jobexecutionerror.html
Normal file
File diff suppressed because one or more lines are too long
301
docs/classes/types.loginrequirederror.html
Normal file
301
docs/classes/types.loginrequirederror.html
Normal file
File diff suppressed because one or more lines are too long
325
docs/classes/types.notfounderror.html
Normal file
325
docs/classes/types.notfounderror.html
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
302
docs/interfaces/job_execution.jobexecutor.html
Normal file
302
docs/interfaces/job_execution.jobexecutor.html
Normal file
File diff suppressed because one or more lines are too long
392
docs/interfaces/request.httpclient.html
Normal file
392
docs/interfaces/request.httpclient.html
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
94
docs/modules/__mocks__.html
Normal file
94
docs/modules/__mocks__.html
Normal file
File diff suppressed because one or more lines are too long
179
docs/modules/auth.html
Normal file
179
docs/modules/auth.html
Normal file
File diff suppressed because one or more lines are too long
144
docs/modules/auth_spec.html
Normal file
144
docs/modules/auth_spec.html
Normal file
File diff suppressed because one or more lines are too long
184
docs/modules/file.html
Normal file
184
docs/modules/file.html
Normal file
File diff suppressed because one or more lines are too long
171
docs/modules/job_execution.html
Normal file
171
docs/modules/job_execution.html
Normal file
File diff suppressed because one or more lines are too long
106
docs/modules/reflection-817.html
Normal file
106
docs/modules/reflection-817.html
Normal file
File diff suppressed because one or more lines are too long
128
docs/modules/reflection-817.reflection-220.html
Normal file
128
docs/modules/reflection-817.reflection-220.html
Normal file
File diff suppressed because one or more lines are too long
106
docs/modules/reflection-830.html
Normal file
106
docs/modules/reflection-830.html
Normal file
File diff suppressed because one or more lines are too long
128
docs/modules/reflection-830.reflection-222.html
Normal file
128
docs/modules/reflection-830.reflection-222.html
Normal file
File diff suppressed because one or more lines are too long
118
docs/modules/request.html
Normal file
118
docs/modules/request.html
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -21,6 +21,7 @@ import { isAuthorizeFormRequired } from './auth/isAuthorizeFormRequired'
|
|||||||
import { RequestClient } from './request/RequestClient'
|
import { RequestClient } from './request/RequestClient'
|
||||||
import { NotFoundError } from './types/NotFoundError'
|
import { NotFoundError } from './types/NotFoundError'
|
||||||
import { SasAuthResponse } from '@sasjs/utils/types'
|
import { SasAuthResponse } from '@sasjs/utils/types'
|
||||||
|
import { prefixMessage } from '@sasjs/utils/error'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A client for interfacing with the SAS Viya REST API.
|
* A client for interfacing with the SAS Viya REST API.
|
||||||
@@ -280,25 +281,24 @@ export class SASViyaApiClient {
|
|||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
}
|
}
|
||||||
|
|
||||||
if (accessToken) {
|
if (accessToken) headers.Authorization = `Bearer ${accessToken}`
|
||||||
headers.Authorization = `Bearer ${accessToken}`
|
|
||||||
}
|
|
||||||
|
|
||||||
let executionSessionId: string
|
let executionSessionId: string
|
||||||
|
|
||||||
const session = await this.sessionManager
|
const session = await this.sessionManager
|
||||||
.getSession(accessToken)
|
.getSession(accessToken)
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
throw err
|
throw prefixMessage(err, 'Error while getting session. ')
|
||||||
})
|
})
|
||||||
|
|
||||||
executionSessionId = session!.id
|
executionSessionId = session!.id
|
||||||
|
|
||||||
if (printPid) {
|
if (printPid) {
|
||||||
const { result: jobIdVariable } = await this.sessionManager.getVariable(
|
const { result: jobIdVariable } = await this.sessionManager
|
||||||
executionSessionId,
|
.getVariable(executionSessionId, 'SYSJOBID', accessToken)
|
||||||
'SYSJOBID',
|
.catch((err) => {
|
||||||
accessToken
|
throw prefixMessage(err, 'Error while getting session variable. ')
|
||||||
)
|
})
|
||||||
|
|
||||||
if (jobIdVariable && jobIdVariable.value) {
|
if (jobIdVariable && jobIdVariable.value) {
|
||||||
const relativeJobPath = this.rootFolderName
|
const relativeJobPath = this.rootFolderName
|
||||||
@@ -331,6 +331,7 @@ export class SASViyaApiClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let fileName
|
let fileName
|
||||||
|
|
||||||
if (isRelativePath(jobPath)) {
|
if (isRelativePath(jobPath)) {
|
||||||
fileName = `exec-${
|
fileName = `exec-${
|
||||||
jobPath.includes('/') ? jobPath.split('/')[1] : jobPath
|
jobPath.includes('/') ? jobPath.split('/')[1] : jobPath
|
||||||
@@ -352,7 +353,7 @@ export class SASViyaApiClient {
|
|||||||
if (data) {
|
if (data) {
|
||||||
if (JSON.stringify(data).includes(';')) {
|
if (JSON.stringify(data).includes(';')) {
|
||||||
files = await this.uploadTables(data, accessToken).catch((err) => {
|
files = await this.uploadTables(data, accessToken).catch((err) => {
|
||||||
throw err
|
throw prefixMessage(err, 'Error while uploading tables. ')
|
||||||
})
|
})
|
||||||
|
|
||||||
jobVariables['_webin_file_count'] = files.length
|
jobVariables['_webin_file_count'] = files.length
|
||||||
@@ -376,19 +377,18 @@ export class SASViyaApiClient {
|
|||||||
variables: jobVariables,
|
variables: jobVariables,
|
||||||
arguments: jobArguments
|
arguments: jobArguments
|
||||||
}
|
}
|
||||||
|
|
||||||
const { result: postedJob, etag } = await this.requestClient
|
const { result: postedJob, etag } = await this.requestClient
|
||||||
.post<Job>(
|
.post<Job>(
|
||||||
`/compute/sessions/${executionSessionId}/jobs`,
|
`/compute/sessions/${executionSessionId}/jobs`,
|
||||||
jobRequestBody,
|
jobRequestBody,
|
||||||
accessToken
|
accessToken
|
||||||
)
|
)
|
||||||
.catch((err: any) => {
|
.catch((err) => {
|
||||||
throw err
|
throw prefixMessage(err, 'Error while posting job. ')
|
||||||
})
|
})
|
||||||
|
|
||||||
if (!waitForResult) {
|
if (!waitForResult) return session
|
||||||
return session
|
|
||||||
}
|
|
||||||
|
|
||||||
if (debug) {
|
if (debug) {
|
||||||
console.log(`Job has been submitted for '${fileName}'.`)
|
console.log(`Job has been submitted for '${fileName}'.`)
|
||||||
@@ -404,7 +404,9 @@ export class SASViyaApiClient {
|
|||||||
etag,
|
etag,
|
||||||
accessToken,
|
accessToken,
|
||||||
pollOptions
|
pollOptions
|
||||||
)
|
).catch((err) => {
|
||||||
|
throw prefixMessage(err, 'Error while polling job status. ')
|
||||||
|
})
|
||||||
|
|
||||||
const { result: currentJob } = await this.requestClient
|
const { result: currentJob } = await this.requestClient
|
||||||
.get<Job>(
|
.get<Job>(
|
||||||
@@ -412,7 +414,7 @@ export class SASViyaApiClient {
|
|||||||
accessToken
|
accessToken
|
||||||
)
|
)
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
throw err
|
throw prefixMessage(err, 'Error while getting job. ')
|
||||||
})
|
})
|
||||||
|
|
||||||
let jobResult
|
let jobResult
|
||||||
@@ -427,7 +429,7 @@ export class SASViyaApiClient {
|
|||||||
res.result.items.map((i: any) => i.line).join('\n')
|
res.result.items.map((i: any) => i.line).join('\n')
|
||||||
)
|
)
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
throw err
|
throw prefixMessage(err, 'Error while getting log. ')
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -455,7 +457,7 @@ export class SASViyaApiClient {
|
|||||||
res.result.items.map((i: any) => i.line).join('\n')
|
res.result.items.map((i: any) => i.line).join('\n')
|
||||||
)
|
)
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
throw err
|
throw prefixMessage(err, 'Error while getting log. ')
|
||||||
})
|
})
|
||||||
|
|
||||||
return Promise.reject({
|
return Promise.reject({
|
||||||
@@ -464,6 +466,7 @@ export class SASViyaApiClient {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
result: JSON.stringify(e)
|
result: JSON.stringify(e)
|
||||||
}
|
}
|
||||||
@@ -473,7 +476,7 @@ export class SASViyaApiClient {
|
|||||||
await this.sessionManager
|
await this.sessionManager
|
||||||
.clearSession(executionSessionId, accessToken)
|
.clearSession(executionSessionId, accessToken)
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
throw err
|
throw prefixMessage(err, 'Error while clearing session. ')
|
||||||
})
|
})
|
||||||
|
|
||||||
return { result: jobResult?.result, log }
|
return { result: jobResult?.result, log }
|
||||||
@@ -490,7 +493,7 @@ export class SASViyaApiClient {
|
|||||||
true
|
true
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
throw e
|
throw prefixMessage(e, 'Error while executing script. ')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -814,9 +817,12 @@ export class SASViyaApiClient {
|
|||||||
? `${this.rootFolderName}/${folderPath}`
|
? `${this.rootFolderName}/${folderPath}`
|
||||||
: folderPath
|
: folderPath
|
||||||
|
|
||||||
await this.populateFolderMap(fullFolderPath, accessToken)
|
await this.populateFolderMap(fullFolderPath, accessToken).catch((err) => {
|
||||||
|
throw prefixMessage(err, 'Error while populating folder map. ')
|
||||||
|
})
|
||||||
|
|
||||||
const jobFolder = this.folderMap.get(fullFolderPath)
|
const jobFolder = this.folderMap.get(fullFolderPath)
|
||||||
|
|
||||||
if (!jobFolder) {
|
if (!jobFolder) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`The folder '${fullFolderPath}' was not found on '${this.serverUrl}'`
|
`The folder '${fullFolderPath}' was not found on '${this.serverUrl}'`
|
||||||
@@ -824,6 +830,7 @@ export class SASViyaApiClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const headers: any = { 'Content-Type': 'application/json' }
|
const headers: any = { 'Content-Type': 'application/json' }
|
||||||
|
|
||||||
if (!!accessToken) {
|
if (!!accessToken) {
|
||||||
headers.Authorization = `Bearer ${accessToken}`
|
headers.Authorization = `Bearer ${accessToken}`
|
||||||
}
|
}
|
||||||
@@ -847,10 +854,14 @@ export class SASViyaApiClient {
|
|||||||
|
|
||||||
const {
|
const {
|
||||||
result: jobDefinition
|
result: jobDefinition
|
||||||
} = await this.requestClient.get<JobDefinition>(
|
} = await this.requestClient
|
||||||
|
.get<JobDefinition>(
|
||||||
`${this.serverUrl}${jobDefinitionLink.href}`,
|
`${this.serverUrl}${jobDefinitionLink.href}`,
|
||||||
accessToken
|
accessToken
|
||||||
)
|
)
|
||||||
|
.catch((err) => {
|
||||||
|
throw prefixMessage(err, 'Error while getting job definition. ')
|
||||||
|
})
|
||||||
|
|
||||||
code = jobDefinition.code
|
code = jobDefinition.code
|
||||||
|
|
||||||
@@ -861,6 +872,7 @@ export class SASViyaApiClient {
|
|||||||
if (!code) code = ''
|
if (!code) code = ''
|
||||||
|
|
||||||
const linesToExecute = code.replace(/\r\n/g, '\n').split('\n')
|
const linesToExecute = code.replace(/\r\n/g, '\n').split('\n')
|
||||||
|
|
||||||
return await this.executeScript(
|
return await this.executeScript(
|
||||||
sasJob,
|
sasJob,
|
||||||
linesToExecute,
|
linesToExecute,
|
||||||
@@ -872,7 +884,9 @@ export class SASViyaApiClient {
|
|||||||
waitForResult,
|
waitForResult,
|
||||||
pollOptions,
|
pollOptions,
|
||||||
printPid
|
printPid
|
||||||
)
|
).catch((err) => {
|
||||||
|
throw prefixMessage(err, 'Error while executing script. ')
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1007,19 +1021,27 @@ export class SASViyaApiClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const url = '/folders/folders/@item?path=' + path
|
const url = '/folders/folders/@item?path=' + path
|
||||||
const { result: folder } = await this.requestClient.get<Folder>(
|
const { result: folder } = await this.requestClient
|
||||||
`${url}`,
|
.get<Folder>(`${url}`, accessToken)
|
||||||
accessToken
|
.catch((err) => {
|
||||||
)
|
throw prefixMessage(err, 'Error while getting folder. ')
|
||||||
|
})
|
||||||
|
|
||||||
if (!folder) {
|
if (!folder) {
|
||||||
throw new Error(`The path ${path} does not exist on ${this.serverUrl}`)
|
throw new Error(`The path ${path} does not exist on ${this.serverUrl}`)
|
||||||
}
|
}
|
||||||
const { result: members } = await this.requestClient.get<{ items: any[] }>(
|
|
||||||
|
const { result: members } = await this.requestClient
|
||||||
|
.get<{ items: any[] }>(
|
||||||
`/folders/folders/${folder.id}/members?limit=${folder.memberCount}`,
|
`/folders/folders/${folder.id}/members?limit=${folder.memberCount}`,
|
||||||
accessToken
|
accessToken
|
||||||
)
|
)
|
||||||
|
.catch((err) => {
|
||||||
|
throw prefixMessage(err, 'Error while getting members. ')
|
||||||
|
})
|
||||||
|
|
||||||
const itemsAtRoot = members.items
|
const itemsAtRoot = members.items
|
||||||
|
|
||||||
this.folderMap.set(path, itemsAtRoot)
|
this.folderMap.set(path, itemsAtRoot)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1052,11 +1074,15 @@ export class SASViyaApiClient {
|
|||||||
Promise.reject(`Job state link was not found.`)
|
Promise.reject(`Job state link was not found.`)
|
||||||
}
|
}
|
||||||
|
|
||||||
const { result: state } = await this.requestClient.get<string>(
|
const { result: state } = await this.requestClient
|
||||||
|
.get<string>(
|
||||||
`${this.serverUrl}${stateLink.href}?_action=wait&wait=30`,
|
`${this.serverUrl}${stateLink.href}?_action=wait&wait=30`,
|
||||||
accessToken,
|
accessToken,
|
||||||
'text/plain'
|
'text/plain'
|
||||||
)
|
)
|
||||||
|
.catch((err) => {
|
||||||
|
throw prefixMessage(err, 'Error while getting job state. ')
|
||||||
|
})
|
||||||
|
|
||||||
const currentState = state.trim()
|
const currentState = state.trim()
|
||||||
if (currentState === 'completed') {
|
if (currentState === 'completed') {
|
||||||
@@ -1073,11 +1099,15 @@ export class SASViyaApiClient {
|
|||||||
postedJobState === 'pending'
|
postedJobState === 'pending'
|
||||||
) {
|
) {
|
||||||
if (stateLink) {
|
if (stateLink) {
|
||||||
const { result: jobState } = await this.requestClient.get<string>(
|
const { result: jobState } = await this.requestClient
|
||||||
|
.get<string>(
|
||||||
`${this.serverUrl}${stateLink.href}?_action=wait&wait=30`,
|
`${this.serverUrl}${stateLink.href}?_action=wait&wait=30`,
|
||||||
accessToken,
|
accessToken,
|
||||||
'text/plain'
|
'text/plain'
|
||||||
)
|
)
|
||||||
|
.catch((err) => {
|
||||||
|
throw prefixMessage(err, 'Error while getting job state. ')
|
||||||
|
})
|
||||||
|
|
||||||
postedJobState = jobState.trim()
|
postedJobState = jobState.trim()
|
||||||
|
|
||||||
@@ -1119,19 +1149,25 @@ export class SASViyaApiClient {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const uploadResponse = await this.requestClient.uploadFile(
|
const uploadResponse = await this.requestClient
|
||||||
`${this.serverUrl}/files/files#rawUpload`,
|
.uploadFile(`${this.serverUrl}/files/files#rawUpload`, csv, accessToken)
|
||||||
csv,
|
.catch((err) => {
|
||||||
accessToken
|
throw prefixMessage(err, 'Error while uploading file. ')
|
||||||
)
|
})
|
||||||
|
|
||||||
uploadedFiles.push({ tableName, file: uploadResponse.result })
|
uploadedFiles.push({ tableName, file: uploadResponse.result })
|
||||||
}
|
}
|
||||||
return uploadedFiles
|
return uploadedFiles
|
||||||
}
|
}
|
||||||
|
|
||||||
private async getFolderUri(folderPath: string, accessToken?: string) {
|
private async getFolderDetails(
|
||||||
const url = '/folders/folders/@item?path=' + folderPath
|
folderPath: string,
|
||||||
|
accessToken?: string
|
||||||
|
): Promise<Folder | undefined> {
|
||||||
|
const url = isUri(folderPath)
|
||||||
|
? folderPath
|
||||||
|
: `/folders/folders/@item?path=${folderPath}`
|
||||||
|
|
||||||
const { result: folder } = await this.requestClient
|
const { result: folder } = await this.requestClient
|
||||||
.get<Folder>(`${this.serverUrl}${url}`, accessToken)
|
.get<Folder>(`${this.serverUrl}${url}`, accessToken)
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
@@ -1139,7 +1175,15 @@ export class SASViyaApiClient {
|
|||||||
})
|
})
|
||||||
|
|
||||||
if (!folder) return undefined
|
if (!folder) return undefined
|
||||||
return `/folders/folders/${folder.id}`
|
return folder
|
||||||
|
}
|
||||||
|
|
||||||
|
private async getFolderUri(folderPath: string, accessToken?: string) {
|
||||||
|
const folderDetails = await this.getFolderDetails(folderPath, accessToken)
|
||||||
|
|
||||||
|
if (!folderDetails) return undefined
|
||||||
|
|
||||||
|
return `/folders/folders/${folderDetails.id}`
|
||||||
}
|
}
|
||||||
|
|
||||||
private async getRecycleBinUri(accessToken: string) {
|
private async getRecycleBinUri(accessToken: string) {
|
||||||
@@ -1188,9 +1232,44 @@ export class SASViyaApiClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Moves a Viya folder to a new location. The folder may be renamed at the same time.
|
* Lists children folders for given Viya folder.
|
||||||
|
* @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.
|
||||||
|
* @param accessToken - an access token for authorizing the request.
|
||||||
|
*/
|
||||||
|
public async listFolder(
|
||||||
|
sourceFolder: string,
|
||||||
|
accessToken?: string,
|
||||||
|
limit: number = 20
|
||||||
|
) {
|
||||||
|
// checks if 'sourceFolder' is already a URI
|
||||||
|
const sourceFolderUri = isUri(sourceFolder)
|
||||||
|
? sourceFolder
|
||||||
|
: await this.getFolderUri(sourceFolder, accessToken)
|
||||||
|
|
||||||
|
const requestInfo = {
|
||||||
|
method: 'GET',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
Authorization: 'Bearer ' + accessToken
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const { result: members } = await this.requestClient.get<{ items: any[] }>(
|
||||||
|
`${this.serverUrl}${sourceFolderUri}/members?limit=${limit}`,
|
||||||
|
accessToken
|
||||||
|
)
|
||||||
|
|
||||||
|
if (members && members.items) {
|
||||||
|
return members.items.map((item: any) => item.name)
|
||||||
|
} else {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Moves Viya folder to a new location. The folder may be renamed at the same time.
|
||||||
* @param sourceFolder - the full path (eg `/Public/example/myFolder`) or URI of the source folder to be moved. Providing URI instead of path will save one extra request.
|
* @param sourceFolder - the full path (eg `/Public/example/myFolder`) or URI of the source folder to be moved. Providing URI instead of path will save one extra request.
|
||||||
* @param targetParentFolder - the full path or URI of the _parent_ folder to which the `sourceFolder` will be moved (eg `/Public/newDestination`). To move a folder, a user has to have write permissions in targetParentFolder. Providing URI instead of path will save one extra request.
|
* @param targetParentFolder - the full path or URI of the _parent_ folder to which the `sourceFolder` will be moved (eg `/Public/newDestination`). To move a folder, a user has to have write permissions in targetParentFolder. Providing URI instead of the path will save one extra request.
|
||||||
* @param targetFolderName - the name of the "moved" folder. If left blank, the original folder name will be used (eg `myFolder` in `/Public/newDestination/myFolder` for the example above). Optional field.
|
* @param targetFolderName - the name of the "moved" folder. If left blank, the original folder name will be used (eg `myFolder` in `/Public/newDestination/myFolder` for the example above). Optional field.
|
||||||
* @param accessToken - an access token for authorizing the request.
|
* @param accessToken - an access token for authorizing the request.
|
||||||
*/
|
*/
|
||||||
@@ -1200,22 +1279,35 @@ export class SASViyaApiClient {
|
|||||||
targetFolderName: string,
|
targetFolderName: string,
|
||||||
accessToken: string
|
accessToken: string
|
||||||
) {
|
) {
|
||||||
// checks if 'sourceFolder' is already a URI
|
// If target path is an existing folder, than keep source folder name, othervise rename it with given target folder name
|
||||||
const sourceFolderUri = isUri(sourceFolder)
|
const sourceFolderName = sourceFolder.split('/').pop() as string
|
||||||
? sourceFolder
|
const targetFolderDetails = await this.getFolderDetails(
|
||||||
: await this.getFolderUri(sourceFolder, accessToken)
|
targetParentFolder,
|
||||||
|
accessToken
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!targetFolderDetails) {
|
||||||
|
let targetParentFolderArr = targetParentFolder.split('/')
|
||||||
|
targetParentFolderArr.splice(targetParentFolderArr.length - 1, 1)
|
||||||
|
targetParentFolder = targetParentFolderArr.join('/')
|
||||||
|
} else {
|
||||||
|
targetFolderName = sourceFolderName
|
||||||
|
}
|
||||||
|
|
||||||
|
// checks if 'sourceFolder' is already an URI
|
||||||
|
const sourceFolderUri = await this.getFolderUri(sourceFolder, accessToken)
|
||||||
|
|
||||||
// checks if 'targetParentFolder' is already a URI
|
// checks if 'targetParentFolder' is already a URI
|
||||||
const targetParentFolderUri = isUri(targetParentFolder)
|
const targetParentFolderUri = await this.getFolderUri(
|
||||||
? targetParentFolder
|
targetParentFolder,
|
||||||
: await this.getFolderUri(targetParentFolder, accessToken)
|
accessToken
|
||||||
|
)
|
||||||
|
|
||||||
const sourceFolderId = sourceFolderUri?.split('/').pop()
|
const sourceFolderId = sourceFolderUri?.split('/').pop()
|
||||||
const url = sourceFolderUri
|
|
||||||
|
|
||||||
const { result: folder } = await this.requestClient
|
const { result: folder } = await this.requestClient
|
||||||
.patch<Folder>(
|
.patch<Folder>(
|
||||||
`${this.serverUrl}${url}`,
|
`${this.serverUrl}${sourceFolderUri}`,
|
||||||
{
|
{
|
||||||
id: sourceFolderId,
|
id: sourceFolderId,
|
||||||
name: targetFolderName,
|
name: targetFolderName,
|
||||||
|
|||||||
19
src/SASjs.ts
19
src/SASjs.ts
@@ -317,6 +317,25 @@ export default class SASjs {
|
|||||||
return await this.sasViyaApiClient?.deleteFolder(folderPath, accessToken)
|
return await this.sasViyaApiClient?.deleteFolder(folderPath, accessToken)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lists children folders for given Viya folder.
|
||||||
|
* @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.
|
||||||
|
* @param accessToken - an access token for authorizing the request.
|
||||||
|
*/
|
||||||
|
public async listFolder(
|
||||||
|
sourceFolder: string,
|
||||||
|
accessToken?: string,
|
||||||
|
limit?: number
|
||||||
|
) {
|
||||||
|
this.isMethodSupported('listFolder', ServerType.SasViya)
|
||||||
|
|
||||||
|
return await this.sasViyaApiClient?.listFolder(
|
||||||
|
sourceFolder,
|
||||||
|
accessToken,
|
||||||
|
limit
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Moves folder to a new location. The folder may be renamed at the same time.
|
* Moves folder to a new location. The folder may be renamed at the same time.
|
||||||
* @param sourceFolder - the full path (eg `/Public/example/myFolder`) or URI of the source folder to be moved. Providing URI instead of path will save one extra request.
|
* @param sourceFolder - the full path (eg `/Public/example/myFolder`) or URI of the source folder to be moved. Providing URI instead of path will save one extra request.
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ export class SessionManager {
|
|||||||
this.sessions = this.sessions.filter((s) => s.id !== id)
|
this.sessions = this.sessions.filter((s) => s.id !== id)
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
throw err
|
throw prefixMessage(err, 'Error while deleting session. ')
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
83
src/test/FolderOperations.spec.ts
Normal file
83
src/test/FolderOperations.spec.ts
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
import { RequestClient } from '../request/RequestClient'
|
||||||
|
import { SASViyaApiClient } from '../SASViyaApiClient'
|
||||||
|
import axios from 'axios'
|
||||||
|
jest.mock('axios')
|
||||||
|
const mockedAxios = axios as jest.Mocked<typeof axios>
|
||||||
|
|
||||||
|
describe('FolderOperations', () => {
|
||||||
|
const sasViyaApiClient = new SASViyaApiClient(
|
||||||
|
'https://sample.server.com',
|
||||||
|
'/Public',
|
||||||
|
'Context',
|
||||||
|
new RequestClient('https://sample.server.com')
|
||||||
|
)
|
||||||
|
|
||||||
|
beforeEach(() => {})
|
||||||
|
|
||||||
|
it('should move and rename folder', async (done) => {
|
||||||
|
mockFetchResponse(false)
|
||||||
|
|
||||||
|
let res: any = await sasViyaApiClient.moveFolder(
|
||||||
|
'/Test/fromFolder/oldName',
|
||||||
|
'/Test/toFolder/newName',
|
||||||
|
'newName',
|
||||||
|
'token'
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(res.folder.name).toEqual('newName')
|
||||||
|
expect(res.folder.parentFolderUri.split('=')[1]).toEqual('/Test/toFolder')
|
||||||
|
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should move and keep the name of folder', async (done) => {
|
||||||
|
mockFetchResponse(true)
|
||||||
|
|
||||||
|
let res: any = await sasViyaApiClient.moveFolder(
|
||||||
|
'/Test/fromFolder/oldName',
|
||||||
|
'/Test/toFolder',
|
||||||
|
'toFolder',
|
||||||
|
'token'
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(res.folder.name).toEqual('oldName')
|
||||||
|
expect(res.folder.parentFolderUri.split('=')[1]).toEqual('/Test/toFolder')
|
||||||
|
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should only rename folder', async (done) => {
|
||||||
|
mockFetchResponse(false)
|
||||||
|
|
||||||
|
let res: any = await sasViyaApiClient.moveFolder(
|
||||||
|
'/Test/toFolder/oldName',
|
||||||
|
'/Test/toFolder/newName',
|
||||||
|
'newName',
|
||||||
|
'token'
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(res.folder.name).toEqual('newName')
|
||||||
|
expect(res.folder.parentFolderUri.split('=')[1]).toEqual('/Test/toFolder')
|
||||||
|
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
const mockFetchResponse = (targetFolderExists: boolean) => {
|
||||||
|
mockedAxios.patch.mockImplementation((url: any, request: any) => {
|
||||||
|
return Promise.resolve({ status: 200, data: { folder: request } })
|
||||||
|
})
|
||||||
|
|
||||||
|
mockedAxios.get.mockImplementation((url: any, request: any) => {
|
||||||
|
if (!targetFolderExists && url.includes('newName')) {
|
||||||
|
return Promise.resolve(undefined)
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.resolve({
|
||||||
|
status: 200,
|
||||||
|
data: {
|
||||||
|
id: url
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user