1
0
mirror of https://github.com/sasjs/adapter.git synced 2026-01-16 16:40:06 +00:00

feat(job-execution): support absolute paths to SAS jobs

This commit is contained in:
Krishna Acondy
2020-09-16 08:49:18 +01:00
parent e7e238e20b
commit 5f5d84da87
5 changed files with 76 additions and 27 deletions

View File

@@ -3,6 +3,7 @@ import {
parseAndSubmitAuthorizeForm, parseAndSubmitAuthorizeForm,
convertToCSV, convertToCSV,
makeRequest, makeRequest,
isRelativePath,
isUri, isUri,
isUrl isUrl
} from './utils' } from './utils'
@@ -32,10 +33,6 @@ export class SASViyaApiClient {
private setCsrfToken: (csrfToken: CsrfToken) => void, private setCsrfToken: (csrfToken: CsrfToken) => void,
private rootFolderMap = new Map<string, Job[]>() private rootFolderMap = new Map<string, Job[]>()
) { ) {
if (!rootFolderName) {
throw new Error('Root folder must be provided.')
}
if (serverUrl) isUrl(serverUrl) if (serverUrl) isUrl(serverUrl)
} }
@@ -47,6 +44,7 @@ export class SASViyaApiClient {
this.setCsrfToken this.setCsrfToken
) )
private isForceDeploy: boolean = false private isForceDeploy: boolean = false
private folderMap = new Map<string, Job[]>()
/** /**
* Returns a map containing the directory structure in the currently set root folder. * Returns a map containing the directory structure in the currently set root folder.
@@ -192,7 +190,7 @@ export class SASViyaApiClient {
} }
const { result: contexts } = await this.request<{ items: Context[] }>( const { result: contexts } = await this.request<{ items: Context[] }>(
`${this.serverUrl}/compute/contexts`, `${this.serverUrl}/compute/contexts?limit=10000`,
{ headers } { headers }
) )
const executionContext = const executionContext =
@@ -892,32 +890,56 @@ export class SASViyaApiClient {
data?: any, data?: any,
accessToken?: string accessToken?: string
) { ) {
if (!this.rootFolder) { if (isRelativePath(sasJob) && !this.rootFolderName) {
await this.populateRootFolder(accessToken)
}
if (!this.rootFolder) {
console.error('Root folder was not found')
throw new Error('Root folder was not found')
}
if (!this.rootFolderMap.size) {
await this.populateRootFolderMap(accessToken)
}
if (!this.rootFolderMap.size) {
console.error(`The job ${sasJob} was not found in ${this.rootFolderName}`)
throw new Error( throw new Error(
`The job ${sasJob} was not found in ${this.rootFolderName}` 'Relative paths cannot be used without specifying a root folder name'
) )
} }
if (isRelativePath(sasJob)) {
if (!this.rootFolder) {
await this.populateRootFolder(accessToken)
}
if (!this.rootFolder) {
console.error('Root folder was not found')
throw new Error('Root folder was not found')
}
if (!this.rootFolderMap.size) {
await this.populateRootFolderMap(accessToken)
}
if (!this.rootFolderMap.size) {
console.error(
`The job ${sasJob} was not found in ${this.rootFolderName}`
)
throw new Error(
`The job ${sasJob} was not found in ${this.rootFolderName}`
)
}
} else {
const folderPathParts = sasJob.split('/')
folderPathParts.pop()
const folderPath = folderPathParts.join('/')
await this.populateFolderMap(folderPath, accessToken)
}
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}`
} }
const folderName = sasJob.split('/')[0] let jobToExecute
const jobName = sasJob.split('/')[1] if (isRelativePath(sasJob)) {
const jobFolder = this.rootFolderMap.get(folderName) const folderName = sasJob.split('/')[0]
const jobToExecute = jobFolder?.find((item) => item.name === jobName) const jobName = sasJob.split('/')[1]
const jobFolder = this.rootFolderMap.get(folderName)
jobToExecute = jobFolder?.find((item) => item.name === jobName)
} else {
const folderPathParts = sasJob.split('/')
const jobName = folderPathParts.pop()
const folderPath = folderPathParts.join('/')
const jobFolder = this.folderMap.get(folderPath)
jobToExecute = jobFolder?.find((item) => item.name === jobName)
}
if (!jobToExecute) { if (!jobToExecute) {
throw new Error('Job was not found.') throw new Error('Job was not found.')
@@ -1100,6 +1122,32 @@ export class SASViyaApiClient {
} }
} }
private async populateFolderMap(folderPath: string, accessToken?: string) {
const url = '/folders/folders/@item?path=' + folderPath
const requestInfo: any = {
method: 'GET'
}
if (accessToken) {
requestInfo.headers = { Authorization: `Bearer ${accessToken}` }
}
const { result: folder } = await this.request<Folder>(
`${this.serverUrl}${url}`,
requestInfo
)
if (!folder) {
throw new Error(
`The path ${folderPath} does not exist on ${this.serverUrl}`
)
}
const { result: members } = await this.request<{ items: any[] }>(
`${this.serverUrl}/folders/folders/${folder.id}/members`,
requestInfo
)
const itemsAtRoot = members.items
this.folderMap.set(folderPath, itemsAtRoot)
}
private async populateRootFolderMap(accessToken?: string) { private async populateRootFolderMap(accessToken?: string) {
const allItems = new Map<string, Job[]>() const allItems = new Map<string, Job[]>()
const url = '/folders/folders/@item?path=' + this.rootFolderName const url = '/folders/folders/@item?path=' + this.rootFolderName

View File

@@ -515,8 +515,6 @@ export default class SASjs {
...config ...config
} }
sasJob = sasJob.startsWith('/') ? sasJob.replace('/', '') : sasJob
if (config.serverType === ServerType.SASViya && config.contextName) { if (config.serverType === ServerType.SASViya && config.contextName) {
if (config.useComputeApi) { if (config.useComputeApi) {
requestResponse = await this.executeJobViaComputeApi( requestResponse = await this.executeJobViaComputeApi(

View File

@@ -78,7 +78,7 @@ export class SessionManager {
if (!this.currentContext) { if (!this.currentContext) {
const { result: contexts } = await this.request<{ const { result: contexts } = await this.request<{
items: Context[] items: Context[]
}>(`${this.serverUrl}/compute/contexts`, { }>(`${this.serverUrl}/compute/contexts?limit=10000`, {
headers: this.getHeaders(accessToken) headers: this.getHeaders(accessToken)
}) })

View File

@@ -4,6 +4,9 @@ export * from './convertToCsv'
export * from './isAuthorizeFormRequired' export * from './isAuthorizeFormRequired'
export * from './isLoginRequired' export * from './isLoginRequired'
export * from './isLoginSuccess' export * from './isLoginSuccess'
export * from './isRelativePath'
export * from './isUri'
export * from './isUrl'
export * from './makeRequest' export * from './makeRequest'
export * from './needsRetry' export * from './needsRetry'
export * from './parseAndSubmitAuthorizeForm' export * from './parseAndSubmitAuthorizeForm'
@@ -13,5 +16,3 @@ export * from './parseSasViyaLog'
export * from './serialize' export * from './serialize'
export * from './splitChunks' export * from './splitChunks'
export * from './parseWeboutResponse' export * from './parseWeboutResponse'
export * from './isUri'
export * from './isUrl'

View File

@@ -0,0 +1,2 @@
export const isRelativePath = (uri: string): boolean =>
!!uri && !uri.startsWith('/')