mirror of
https://github.com/sasjs/adapter.git
synced 2025-12-11 01:14:36 +00:00
feat: created a minified version of adapter for executing web jobs on sas9
This commit is contained in:
@@ -1,6 +0,0 @@
|
|||||||
import SASjs from './SASjs-sas9-min'
|
|
||||||
export * from './types'
|
|
||||||
export * from './types/errors'
|
|
||||||
export * from './SAS9ApiClient'
|
|
||||||
export * from './request/Sas9RequestClient'
|
|
||||||
export default SASjs
|
|
||||||
@@ -1,16 +1,16 @@
|
|||||||
import { validateInput, compareTimestamps } from './utils'
|
import { validateInput, compareTimestamps } from '../../utils'
|
||||||
import { SASjsConfig, UploadFile, LoginMechanism } from './types'
|
import { SASjsConfig, UploadFile, LoginMechanism } from '../../types'
|
||||||
import { SAS9ApiClient } from './SAS9ApiClient'
|
import { AuthManager } from '../../auth'
|
||||||
import { AuthManager } from './auth/AuthManager-sas9-min'
|
|
||||||
import {
|
import {
|
||||||
ServerType,
|
ServerType,
|
||||||
AuthConfig,
|
AuthConfig,
|
||||||
ExtraResponseAttributes
|
ExtraResponseAttributes
|
||||||
} from '@sasjs/utils/types'
|
} from '@sasjs/utils/types'
|
||||||
import { RequestClient } from './request/RequestClient'
|
import { RequestClient } from '../../request/RequestClient'
|
||||||
import { JobExecutor, Sas9JobExecutor, FileUploader } from './job-execution'
|
import { FileUploader } from '../../job-execution/FileUploader'
|
||||||
import { ErrorResponse } from './types/errors'
|
import { WebJobExecutor } from './WebJobExecutor'
|
||||||
import { LoginOptions, LoginResult } from './types/Login'
|
import { ErrorResponse } from '../../types/errors/ErrorResponse'
|
||||||
|
import { LoginOptions, LoginResult } from '../../types/Login'
|
||||||
|
|
||||||
const defaultConfig: SASjsConfig = {
|
const defaultConfig: SASjsConfig = {
|
||||||
serverUrl: '',
|
serverUrl: '',
|
||||||
@@ -32,12 +32,10 @@ const defaultConfig: SASjsConfig = {
|
|||||||
export default class SASjs {
|
export default class SASjs {
|
||||||
private sasjsConfig: SASjsConfig = new SASjsConfig()
|
private sasjsConfig: SASjsConfig = new SASjsConfig()
|
||||||
private jobsPath: string = ''
|
private jobsPath: string = ''
|
||||||
private sas9ApiClient: SAS9ApiClient | null = null
|
|
||||||
private fileUploader: FileUploader | null = null
|
private fileUploader: FileUploader | null = null
|
||||||
private authManager: AuthManager | null = null
|
private authManager: AuthManager | null = null
|
||||||
private requestClient: RequestClient | null = null
|
private requestClient: RequestClient | null = null
|
||||||
private webJobExecutor: JobExecutor | null = null
|
private webJobExecutor: WebJobExecutor | null = null
|
||||||
private sas9JobExecutor: JobExecutor | null = null
|
|
||||||
|
|
||||||
constructor(config?: Partial<SASjsConfig>) {
|
constructor(config?: Partial<SASjsConfig>) {
|
||||||
this.sasjsConfig = {
|
this.sasjsConfig = {
|
||||||
@@ -190,23 +188,14 @@ export default class SASjs {
|
|||||||
|
|
||||||
// status is true if the data passes validation checks above
|
// status is true if the data passes validation checks above
|
||||||
if (validationResult.status) {
|
if (validationResult.status) {
|
||||||
if (
|
return await this.webJobExecutor!.execute(
|
||||||
config.serverType === ServerType.Sas9 &&
|
sasJob,
|
||||||
config.username &&
|
data,
|
||||||
config.password
|
config,
|
||||||
) {
|
loginRequiredCallback,
|
||||||
console.log(`🤖[198]🤖`, 198)
|
authConfig,
|
||||||
return await this.sas9JobExecutor!.execute(sasJob, data, config)
|
extraResponseAttributes
|
||||||
} else {
|
)
|
||||||
return await this.webJobExecutor!.execute(
|
|
||||||
sasJob,
|
|
||||||
data,
|
|
||||||
config,
|
|
||||||
loginRequiredCallback,
|
|
||||||
authConfig,
|
|
||||||
extraResponseAttributes
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
return Promise.reject(new ErrorResponse(validationResult.msg))
|
return Promise.reject(new ErrorResponse(validationResult.msg))
|
||||||
}
|
}
|
||||||
@@ -241,8 +230,7 @@ export default class SASjs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!this.requestClient) {
|
if (!this.requestClient) {
|
||||||
const RequestClientClass = RequestClient
|
this.requestClient = new RequestClient(
|
||||||
this.requestClient = new RequestClientClass(
|
|
||||||
this.sasjsConfig.serverUrl,
|
this.sasjsConfig.serverUrl,
|
||||||
this.sasjsConfig.httpsAgentOptions,
|
this.sasjsConfig.httpsAgentOptions,
|
||||||
this.sasjsConfig.requestHistoryLimit
|
this.sasjsConfig.requestHistoryLimit
|
||||||
@@ -263,18 +251,6 @@ export default class SASjs {
|
|||||||
this.resendWaitingRequests
|
this.resendWaitingRequests
|
||||||
)
|
)
|
||||||
|
|
||||||
if (this.sasjsConfig.serverType === ServerType.Sas9) {
|
|
||||||
if (this.sas9ApiClient) {
|
|
||||||
this.sas9ApiClient!.setConfig(this.sasjsConfig.serverUrl)
|
|
||||||
} else {
|
|
||||||
this.sas9ApiClient = new SAS9ApiClient(
|
|
||||||
this.sasjsConfig.serverUrl,
|
|
||||||
this.jobsPath,
|
|
||||||
this.sasjsConfig.httpsAgentOptions
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.fileUploader = new FileUploader(
|
this.fileUploader = new FileUploader(
|
||||||
this.sasjsConfig.serverUrl,
|
this.sasjsConfig.serverUrl,
|
||||||
this.sasjsConfig.serverType!,
|
this.sasjsConfig.serverType!,
|
||||||
@@ -282,17 +258,11 @@ export default class SASjs {
|
|||||||
this.requestClient
|
this.requestClient
|
||||||
)
|
)
|
||||||
|
|
||||||
this.sas9JobExecutor = new Sas9JobExecutor(
|
this.webJobExecutor = new WebJobExecutor(
|
||||||
this.sasjsConfig.serverUrl,
|
this.sasjsConfig.serverUrl,
|
||||||
this.sasjsConfig.serverType!,
|
this.sasjsConfig.serverType!,
|
||||||
this.jobsPath,
|
this.jobsPath,
|
||||||
this.requestClient,
|
this.requestClient
|
||||||
this.sasjsConfig.httpsAgentOptions
|
|
||||||
)
|
|
||||||
|
|
||||||
console.log(
|
|
||||||
`🤖[setupConfiguration this.sas9JobExecutor]🤖`,
|
|
||||||
this.sas9JobExecutor
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
157
src/minified/sas9/WebJobExecutor.ts
Normal file
157
src/minified/sas9/WebJobExecutor.ts
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
import {
|
||||||
|
AuthConfig,
|
||||||
|
ExtraResponseAttributes,
|
||||||
|
ServerType
|
||||||
|
} from '@sasjs/utils/types'
|
||||||
|
import {
|
||||||
|
ErrorResponse,
|
||||||
|
JobExecutionError,
|
||||||
|
LoginRequiredError
|
||||||
|
} from '../../types/errors'
|
||||||
|
import { RequestClient } from '../../request/RequestClient'
|
||||||
|
import {
|
||||||
|
isRelativePath,
|
||||||
|
parseSasViyaDebugResponse,
|
||||||
|
appendExtraResponseAttributes,
|
||||||
|
convertToCSV
|
||||||
|
} from '../../utils'
|
||||||
|
import { BaseJobExecutor } from '../../job-execution/JobExecutor'
|
||||||
|
import { parseWeboutResponse } from '../../utils/parseWeboutResponse'
|
||||||
|
|
||||||
|
export interface WaitingRequstPromise {
|
||||||
|
promise: Promise<any> | null
|
||||||
|
resolve: any
|
||||||
|
reject: any
|
||||||
|
}
|
||||||
|
export class WebJobExecutor extends BaseJobExecutor {
|
||||||
|
constructor(
|
||||||
|
serverUrl: string,
|
||||||
|
serverType: ServerType,
|
||||||
|
private jobsPath: string,
|
||||||
|
private requestClient: RequestClient
|
||||||
|
) {
|
||||||
|
super(serverUrl, serverType)
|
||||||
|
}
|
||||||
|
|
||||||
|
async execute(
|
||||||
|
sasJob: string,
|
||||||
|
data: any,
|
||||||
|
config: any,
|
||||||
|
loginRequiredCallback?: any,
|
||||||
|
authConfig?: AuthConfig,
|
||||||
|
extraResponseAttributes: ExtraResponseAttributes[] = []
|
||||||
|
) {
|
||||||
|
const loginCallback = loginRequiredCallback
|
||||||
|
const program = isRelativePath(sasJob)
|
||||||
|
? config.appLoc
|
||||||
|
? config.appLoc.replace(/\/?$/, '/') + sasJob.replace(/^\//, '')
|
||||||
|
: sasJob
|
||||||
|
: sasJob
|
||||||
|
let apiUrl = `${config.serverUrl}${this.jobsPath}/?${'_program=' + program}`
|
||||||
|
|
||||||
|
let requestParams = {
|
||||||
|
...this.getRequestParams(config)
|
||||||
|
}
|
||||||
|
|
||||||
|
let formData = new FormData()
|
||||||
|
|
||||||
|
if (data) {
|
||||||
|
try {
|
||||||
|
formData = generateFileUploadForm(formData, data)
|
||||||
|
} catch (e: any) {
|
||||||
|
return Promise.reject(new ErrorResponse(e?.message, e))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const key in requestParams) {
|
||||||
|
if (requestParams.hasOwnProperty(key)) {
|
||||||
|
formData.append(key, requestParams[key])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const requestPromise = new Promise((resolve, reject) => {
|
||||||
|
this.requestClient!.post(apiUrl, formData, authConfig?.access_token)
|
||||||
|
.then(async (res: any) => {
|
||||||
|
this.requestClient!.appendRequest(res, sasJob, config.debug)
|
||||||
|
|
||||||
|
const jsonResponse =
|
||||||
|
config.debug && typeof res.result === 'string'
|
||||||
|
? parseWeboutResponse(res.result, apiUrl)
|
||||||
|
: res.result
|
||||||
|
|
||||||
|
const responseObject = appendExtraResponseAttributes(
|
||||||
|
{ result: jsonResponse, log: res.log },
|
||||||
|
extraResponseAttributes
|
||||||
|
)
|
||||||
|
resolve(responseObject)
|
||||||
|
})
|
||||||
|
.catch(async (e: Error) => {
|
||||||
|
if (e instanceof JobExecutionError) {
|
||||||
|
this.requestClient!.appendRequest(e, sasJob, config.debug)
|
||||||
|
reject(new ErrorResponse(e?.message, e))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e instanceof LoginRequiredError) {
|
||||||
|
if (!loginRequiredCallback) {
|
||||||
|
reject(
|
||||||
|
new ErrorResponse(
|
||||||
|
'Request is not authenticated. Make sure .env file exists with valid credentials.',
|
||||||
|
e
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.appendWaitingRequest(() => {
|
||||||
|
return this.execute(
|
||||||
|
sasJob,
|
||||||
|
data,
|
||||||
|
config,
|
||||||
|
loginRequiredCallback,
|
||||||
|
authConfig,
|
||||||
|
extraResponseAttributes
|
||||||
|
).then(
|
||||||
|
(res: any) => {
|
||||||
|
resolve(res)
|
||||||
|
},
|
||||||
|
(err: any) => {
|
||||||
|
reject(err)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
if (loginCallback) await loginCallback()
|
||||||
|
} else reject(new ErrorResponse(e?.message, e))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
return requestPromise
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* One of the approaches SASjs takes to send tables-formatted JSON (see README)
|
||||||
|
* to SAS is as multipart form data, where each table is provided as a specially
|
||||||
|
* formatted CSV file.
|
||||||
|
*/
|
||||||
|
const generateFileUploadForm = (formData: FormData, data: any): FormData => {
|
||||||
|
for (const tableName in data) {
|
||||||
|
if (!Array.isArray(data[tableName])) continue
|
||||||
|
|
||||||
|
const name = tableName
|
||||||
|
const csv = convertToCSV(data, tableName)
|
||||||
|
|
||||||
|
if (csv === 'ERROR: LARGE STRING LENGTH') {
|
||||||
|
throw new Error(
|
||||||
|
'The max length of a string value in SASjs is 32765 characters.'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const file = new Blob([csv], {
|
||||||
|
type: 'application/csv'
|
||||||
|
})
|
||||||
|
|
||||||
|
formData.append(name, file, `${name}.csv`)
|
||||||
|
}
|
||||||
|
|
||||||
|
return formData
|
||||||
|
}
|
||||||
3
src/minified/sas9/index.ts
Normal file
3
src/minified/sas9/index.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
import SASjs from './SASjs'
|
||||||
|
export * from '../../types'
|
||||||
|
export default SASjs
|
||||||
@@ -23,8 +23,16 @@ const optimization = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const browserConfig = {
|
const browserConfig = {
|
||||||
entry: './src/index-sas9-min.ts',
|
entry: {
|
||||||
devtool: 'inline-source-map',
|
index: './src/index.ts',
|
||||||
|
minified_sas9: './src/minified/sas9/index.ts'
|
||||||
|
},
|
||||||
|
output: {
|
||||||
|
filename: '[name].js',
|
||||||
|
path: path.resolve(__dirname, 'build'),
|
||||||
|
libraryTarget: 'umd',
|
||||||
|
library: 'SASjs'
|
||||||
|
},
|
||||||
mode: 'production',
|
mode: 'production',
|
||||||
optimization: optimization,
|
optimization: optimization,
|
||||||
module: {
|
module: {
|
||||||
@@ -40,12 +48,6 @@ const browserConfig = {
|
|||||||
extensions: ['.ts', '.js'],
|
extensions: ['.ts', '.js'],
|
||||||
fallback: { https: false, fs: false, readline: false }
|
fallback: { https: false, fs: false, readline: false }
|
||||||
},
|
},
|
||||||
output: {
|
|
||||||
filename: 'index-sas9-min.js',
|
|
||||||
path: path.resolve(__dirname, 'build'),
|
|
||||||
libraryTarget: 'umd',
|
|
||||||
library: 'SASjs'
|
|
||||||
},
|
|
||||||
plugins: [
|
plugins: [
|
||||||
...defaultPlugins,
|
...defaultPlugins,
|
||||||
new webpack.ProvidePlugin({
|
new webpack.ProvidePlugin({
|
||||||
@@ -55,6 +57,18 @@ const browserConfig = {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const browserConfigWithDevTool = {
|
||||||
|
...browserConfig,
|
||||||
|
entry: './src/index.ts',
|
||||||
|
output: {
|
||||||
|
filename: 'index-dev.js',
|
||||||
|
path: path.resolve(__dirname, 'build'),
|
||||||
|
libraryTarget: 'umd',
|
||||||
|
library: 'SASjs'
|
||||||
|
},
|
||||||
|
devtool: 'inline-source-map'
|
||||||
|
}
|
||||||
|
|
||||||
const browserConfigWithoutProcessPlugin = {
|
const browserConfigWithoutProcessPlugin = {
|
||||||
entry: browserConfig.entry,
|
entry: browserConfig.entry,
|
||||||
devtool: browserConfig.devtool,
|
devtool: browserConfig.devtool,
|
||||||
@@ -76,4 +90,4 @@ const nodeConfig = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = [browserConfig, nodeConfig]
|
module.exports = [browserConfig, browserConfigWithDevTool, nodeConfig]
|
||||||
|
|||||||
Reference in New Issue
Block a user