@sasjs/adapter 3.7.0 → 3.7.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/SASjs.d.ts +7 -5
- package/file/generateFileUploadForm.d.ts +11 -1
- package/file/generateTableUploadForm.d.ts +3 -2
- package/index.js +2 -2
- package/job-execution/index.d.ts +0 -1
- package/node/SASjs.d.ts +7 -5
- package/node/file/generateFileUploadForm.d.ts +11 -1
- package/node/file/generateTableUploadForm.d.ts +3 -2
- package/node/index.js +2 -2
- package/node/job-execution/index.d.ts +0 -1
- package/node/request/RequestClient.d.ts +2 -0
- package/package.json +1 -1
- package/request/RequestClient.d.ts +2 -0
- package/src/SASjs.ts +10 -15
- package/src/SASjsApiClient.ts +4 -1
- package/src/file/generateFileUploadForm.ts +12 -2
- package/src/file/generateTableUploadForm.ts +5 -1
- package/src/job-execution/WebJobExecutor.ts +31 -5
- package/src/job-execution/index.ts +0 -1
- package/src/request/RequestClient.ts +7 -2
- package/job-execution/SasJsJobExecutor.d.ts +0 -10
- package/node/job-execution/SasJsJobExecutor.d.ts +0 -10
- package/src/job-execution/SasJsJobExecutor.ts +0 -123
|
@@ -71,6 +71,8 @@ export declare class RequestClient implements HttpClient {
|
|
|
71
71
|
}>;
|
|
72
72
|
post<T>(url: string, data: any, accessToken: string | undefined, contentType?: string, overrideHeaders?: {
|
|
73
73
|
[key: string]: string | number;
|
|
74
|
+
}, additionalSettings?: {
|
|
75
|
+
[key: string]: string | number;
|
|
74
76
|
}): Promise<{
|
|
75
77
|
result: T;
|
|
76
78
|
etag: string;
|
package/package.json
CHANGED
|
@@ -71,6 +71,8 @@ export declare class RequestClient implements HttpClient {
|
|
|
71
71
|
}>;
|
|
72
72
|
post<T>(url: string, data: any, accessToken: string | undefined, contentType?: string, overrideHeaders?: {
|
|
73
73
|
[key: string]: string | number;
|
|
74
|
+
}, additionalSettings?: {
|
|
75
|
+
[key: string]: string | number;
|
|
74
76
|
}): Promise<{
|
|
75
77
|
result: T;
|
|
76
78
|
etag: string;
|
package/src/SASjs.ts
CHANGED
|
@@ -27,7 +27,6 @@ import {
|
|
|
27
27
|
ComputeJobExecutor,
|
|
28
28
|
JesJobExecutor,
|
|
29
29
|
Sas9JobExecutor,
|
|
30
|
-
SasJsJobExecutor,
|
|
31
30
|
FileUploader
|
|
32
31
|
} from './job-execution'
|
|
33
32
|
import { ErrorResponse } from './types/errors'
|
|
@@ -63,7 +62,6 @@ export default class SASjs {
|
|
|
63
62
|
private computeJobExecutor: JobExecutor | null = null
|
|
64
63
|
private jesJobExecutor: JobExecutor | null = null
|
|
65
64
|
private sas9JobExecutor: JobExecutor | null = null
|
|
66
|
-
private sasJsJobExecutor: JobExecutor | null = null
|
|
67
65
|
|
|
68
66
|
constructor(config?: Partial<SASjsConfig>) {
|
|
69
67
|
this.sasjsConfig = {
|
|
@@ -79,7 +77,8 @@ export default class SASjs {
|
|
|
79
77
|
}
|
|
80
78
|
|
|
81
79
|
/**
|
|
82
|
-
* Executes
|
|
80
|
+
* Executes code against a SAS 9 server. Requires a runner to be present in
|
|
81
|
+
* the users home directory in metadata.
|
|
83
82
|
* @param linesOfCode - lines of sas code from the file to run.
|
|
84
83
|
* @param username - a string representing the username.
|
|
85
84
|
* @param password - a string representing the password.
|
|
@@ -99,7 +98,7 @@ export default class SASjs {
|
|
|
99
98
|
}
|
|
100
99
|
|
|
101
100
|
/**
|
|
102
|
-
* Executes
|
|
101
|
+
* Executes sas code in a SAS Viya compute session.
|
|
103
102
|
* @param fileName - name of the file to run. It will be converted to path to the file being submitted for execution.
|
|
104
103
|
* @param linesOfCode - lines of sas code from the file to run.
|
|
105
104
|
* @param contextName - context name on which code will be run on the server.
|
|
@@ -643,7 +642,8 @@ export default class SASjs {
|
|
|
643
642
|
}
|
|
644
643
|
|
|
645
644
|
/**
|
|
646
|
-
* Makes a request to
|
|
645
|
+
* Makes a request to program specified in `SASjob` (could be a Viya Job, a
|
|
646
|
+
* SAS 9 Stored Process, or a SASjs Server Stored Program). The response
|
|
647
647
|
* object will always contain table names in lowercase, and column names in
|
|
648
648
|
* uppercase. Values are returned formatted by default, unformatted
|
|
649
649
|
* values can be configured as an option in the `%webout` macro.
|
|
@@ -652,7 +652,8 @@ export default class SASjs {
|
|
|
652
652
|
* the SAS `_program` parameter to run a Job Definition or SAS 9 Stored
|
|
653
653
|
* Process). Is prepended at runtime with the value of `appLoc`.
|
|
654
654
|
* @param data - a JSON object containing one or more tables to be sent to
|
|
655
|
-
* SAS.
|
|
655
|
+
* SAS. For an example of the table structure, see the project README. This
|
|
656
|
+
* value can be `null` if no inputs are required.
|
|
656
657
|
* @param config - provide any changes to the config here, for instance to
|
|
657
658
|
* enable/disable `debug`. Any change provided will override the global config,
|
|
658
659
|
* for that particular function call.
|
|
@@ -682,9 +683,10 @@ export default class SASjs {
|
|
|
682
683
|
|
|
683
684
|
const validationResult = this.validateInput(data)
|
|
684
685
|
|
|
686
|
+
// status is true if the data passes validation checks above
|
|
685
687
|
if (validationResult.status) {
|
|
686
688
|
if (config.serverType === ServerType.Sasjs) {
|
|
687
|
-
return await this.
|
|
689
|
+
return await this.webJobExecutor!.execute(
|
|
688
690
|
sasJob,
|
|
689
691
|
data,
|
|
690
692
|
config,
|
|
@@ -693,7 +695,7 @@ export default class SASjs {
|
|
|
693
695
|
extraResponseAttributes
|
|
694
696
|
)
|
|
695
697
|
} else if (
|
|
696
|
-
config.serverType
|
|
698
|
+
config.serverType === ServerType.SasViya &&
|
|
697
699
|
config.useComputeApi !== undefined &&
|
|
698
700
|
config.useComputeApi !== null
|
|
699
701
|
) {
|
|
@@ -1114,13 +1116,6 @@ export default class SASjs {
|
|
|
1114
1116
|
this.sasViyaApiClient!
|
|
1115
1117
|
)
|
|
1116
1118
|
|
|
1117
|
-
this.sasJsJobExecutor = new SasJsJobExecutor(
|
|
1118
|
-
this.sasjsConfig.serverUrl,
|
|
1119
|
-
this.sasjsConfig.serverType!,
|
|
1120
|
-
this.jobsPath,
|
|
1121
|
-
this.requestClient
|
|
1122
|
-
)
|
|
1123
|
-
|
|
1124
1119
|
this.sas9JobExecutor = new Sas9JobExecutor(
|
|
1125
1120
|
this.sasjsConfig.serverUrl,
|
|
1126
1121
|
this.sasjsConfig.serverType!,
|
package/src/SASjsApiClient.ts
CHANGED
|
@@ -37,7 +37,10 @@ export class SASjsApiClient {
|
|
|
37
37
|
}>(
|
|
38
38
|
'SASjsApi/drive/deploy',
|
|
39
39
|
{ fileTree: members, appLoc: appLoc },
|
|
40
|
-
access_token
|
|
40
|
+
access_token,
|
|
41
|
+
undefined,
|
|
42
|
+
{},
|
|
43
|
+
{ maxContentLength: Infinity, maxBodyLength: Infinity }
|
|
41
44
|
)
|
|
42
45
|
|
|
43
46
|
return Promise.resolve(result)
|
|
@@ -1,9 +1,19 @@
|
|
|
1
|
+
import * as NodeFormData from 'form-data'
|
|
1
2
|
import { convertToCSV } from '../utils/convertToCsv'
|
|
2
3
|
|
|
4
|
+
/**
|
|
5
|
+
* One of the approaches SASjs takes to send tables-formatted JSON (see README)
|
|
6
|
+
* to SAS is as multipart form data, where each table is provided as a specially
|
|
7
|
+
* formatted CSV file.
|
|
8
|
+
* @param formData Different objects are used depending on whether the adapter is
|
|
9
|
+
* running in the browser, or in the CLI
|
|
10
|
+
* @param data Special, tables-formatted JSON (see README)
|
|
11
|
+
* @returns Populated formData
|
|
12
|
+
*/
|
|
3
13
|
export const generateFileUploadForm = (
|
|
4
|
-
formData: FormData,
|
|
14
|
+
formData: FormData | NodeFormData,
|
|
5
15
|
data: any
|
|
6
|
-
): FormData => {
|
|
16
|
+
): FormData | NodeFormData => {
|
|
7
17
|
for (const tableName in data) {
|
|
8
18
|
if (!Array.isArray(data[tableName])) continue
|
|
9
19
|
|
|
@@ -1,7 +1,11 @@
|
|
|
1
|
+
import * as NodeFormData from 'form-data'
|
|
1
2
|
import { convertToCSV } from '../utils/convertToCsv'
|
|
2
3
|
import { splitChunks } from '../utils/splitChunks'
|
|
3
4
|
|
|
4
|
-
export const generateTableUploadForm = (
|
|
5
|
+
export const generateTableUploadForm = (
|
|
6
|
+
formData: FormData | NodeFormData,
|
|
7
|
+
data: any
|
|
8
|
+
) => {
|
|
5
9
|
const sasjsTables = []
|
|
6
10
|
const requestParams: any = {}
|
|
7
11
|
let tableCounter = 0
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import * as NodeFormData from 'form-data'
|
|
1
2
|
import {
|
|
2
3
|
AuthConfig,
|
|
3
4
|
ExtraResponseAttributes,
|
|
@@ -108,7 +109,12 @@ export class WebJobExecutor extends BaseJobExecutor {
|
|
|
108
109
|
...this.getRequestParams(config)
|
|
109
110
|
}
|
|
110
111
|
|
|
111
|
-
|
|
112
|
+
/**
|
|
113
|
+
* Use the available form data object (FormData in Browser, NodeFormData in
|
|
114
|
+
* Node)
|
|
115
|
+
*/
|
|
116
|
+
let formData =
|
|
117
|
+
typeof FormData === 'undefined' ? new NodeFormData() : new FormData()
|
|
112
118
|
|
|
113
119
|
if (data) {
|
|
114
120
|
const stringifiedData = JSON.stringify(data)
|
|
@@ -143,14 +149,30 @@ export class WebJobExecutor extends BaseJobExecutor {
|
|
|
143
149
|
}
|
|
144
150
|
}
|
|
145
151
|
|
|
152
|
+
/* The NodeFormData object does not set the request header - so, set it */
|
|
153
|
+
const contentType =
|
|
154
|
+
formData instanceof NodeFormData
|
|
155
|
+
? `multipart/form-data; boundary=${formData.getBoundary()}`
|
|
156
|
+
: undefined
|
|
157
|
+
|
|
146
158
|
const requestPromise = new Promise((resolve, reject) => {
|
|
147
|
-
this.requestClient!.post(
|
|
159
|
+
this.requestClient!.post(
|
|
160
|
+
apiUrl,
|
|
161
|
+
formData,
|
|
162
|
+
authConfig?.access_token,
|
|
163
|
+
contentType
|
|
164
|
+
)
|
|
148
165
|
.then(async (res: any) => {
|
|
166
|
+
const parsedSasjsServerLog =
|
|
167
|
+
this.serverType === ServerType.Sasjs
|
|
168
|
+
? res.result.log.map((logLine: any) => logLine.line).join('\n')
|
|
169
|
+
: res.result.log
|
|
170
|
+
|
|
149
171
|
const resObj =
|
|
150
172
|
this.serverType === ServerType.Sasjs
|
|
151
173
|
? {
|
|
152
174
|
result: res.result._webout,
|
|
153
|
-
log:
|
|
175
|
+
log: parsedSasjsServerLog
|
|
154
176
|
}
|
|
155
177
|
: res
|
|
156
178
|
this.requestClient!.appendRequest(resObj, sasJob, config.debug)
|
|
@@ -173,8 +195,12 @@ export class WebJobExecutor extends BaseJobExecutor {
|
|
|
173
195
|
: res.result
|
|
174
196
|
break
|
|
175
197
|
case ServerType.Sasjs:
|
|
176
|
-
|
|
177
|
-
|
|
198
|
+
if (typeof res.result._webout === 'object') {
|
|
199
|
+
jsonResponse = res.result._webout
|
|
200
|
+
} else {
|
|
201
|
+
const webout = parseWeboutResponse(res.result._webout, apiUrl)
|
|
202
|
+
jsonResponse = getValidJson(webout)
|
|
203
|
+
}
|
|
178
204
|
break
|
|
179
205
|
}
|
|
180
206
|
} else if (this.serverType === ServerType.Sasjs) {
|
|
@@ -207,7 +207,8 @@ export class RequestClient implements HttpClient {
|
|
|
207
207
|
data: any,
|
|
208
208
|
accessToken: string | undefined,
|
|
209
209
|
contentType = 'application/json',
|
|
210
|
-
overrideHeaders: { [key: string]: string | number } = {}
|
|
210
|
+
overrideHeaders: { [key: string]: string | number } = {},
|
|
211
|
+
additionalSettings: { [key: string]: string | number } = {}
|
|
211
212
|
): Promise<{ result: T; etag: string }> {
|
|
212
213
|
const headers = {
|
|
213
214
|
...this.getHeaders(accessToken, contentType),
|
|
@@ -215,7 +216,11 @@ export class RequestClient implements HttpClient {
|
|
|
215
216
|
}
|
|
216
217
|
|
|
217
218
|
return this.httpClient
|
|
218
|
-
.post<T>(url, data, {
|
|
219
|
+
.post<T>(url, data, {
|
|
220
|
+
headers,
|
|
221
|
+
withCredentials: true,
|
|
222
|
+
...additionalSettings
|
|
223
|
+
})
|
|
219
224
|
.then((response) => {
|
|
220
225
|
throwIfError(response)
|
|
221
226
|
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { AuthConfig, ExtraResponseAttributes, ServerType } from '@sasjs/utils/types';
|
|
2
|
-
import { RequestClient } from '../request/RequestClient';
|
|
3
|
-
import { BaseJobExecutor } from './JobExecutor';
|
|
4
|
-
export declare class SasJsJobExecutor extends BaseJobExecutor {
|
|
5
|
-
private jobsPath;
|
|
6
|
-
private requestClient;
|
|
7
|
-
constructor(serverUrl: string, serverType: ServerType, jobsPath: string, requestClient: RequestClient);
|
|
8
|
-
execute(sasJob: string, data: any, config: any, loginRequiredCallback?: any, authConfig?: AuthConfig, extraResponseAttributes?: ExtraResponseAttributes[]): Promise<unknown>;
|
|
9
|
-
private getRequestParams;
|
|
10
|
-
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { AuthConfig, ExtraResponseAttributes, ServerType } from '@sasjs/utils/types';
|
|
2
|
-
import { RequestClient } from '../request/RequestClient';
|
|
3
|
-
import { BaseJobExecutor } from './JobExecutor';
|
|
4
|
-
export declare class SasJsJobExecutor extends BaseJobExecutor {
|
|
5
|
-
private jobsPath;
|
|
6
|
-
private requestClient;
|
|
7
|
-
constructor(serverUrl: string, serverType: ServerType, jobsPath: string, requestClient: RequestClient);
|
|
8
|
-
execute(sasJob: string, data: any, config: any, loginRequiredCallback?: any, authConfig?: AuthConfig, extraResponseAttributes?: ExtraResponseAttributes[]): Promise<unknown>;
|
|
9
|
-
private getRequestParams;
|
|
10
|
-
}
|
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
AuthConfig,
|
|
3
|
-
ExtraResponseAttributes,
|
|
4
|
-
ServerType
|
|
5
|
-
} from '@sasjs/utils/types'
|
|
6
|
-
import {
|
|
7
|
-
ErrorResponse,
|
|
8
|
-
JobExecutionError,
|
|
9
|
-
LoginRequiredError
|
|
10
|
-
} from '../types/errors'
|
|
11
|
-
import { RequestClient } from '../request/RequestClient'
|
|
12
|
-
import {
|
|
13
|
-
isRelativePath,
|
|
14
|
-
appendExtraResponseAttributes,
|
|
15
|
-
getValidJson
|
|
16
|
-
} from '../utils'
|
|
17
|
-
import { BaseJobExecutor } from './JobExecutor'
|
|
18
|
-
import { parseWeboutResponse } from '../utils/parseWeboutResponse'
|
|
19
|
-
|
|
20
|
-
export class SasJsJobExecutor extends BaseJobExecutor {
|
|
21
|
-
constructor(
|
|
22
|
-
serverUrl: string,
|
|
23
|
-
serverType: ServerType,
|
|
24
|
-
private jobsPath: string,
|
|
25
|
-
private requestClient: RequestClient
|
|
26
|
-
) {
|
|
27
|
-
super(serverUrl, serverType)
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
async execute(
|
|
31
|
-
sasJob: string,
|
|
32
|
-
data: any,
|
|
33
|
-
config: any,
|
|
34
|
-
loginRequiredCallback?: any,
|
|
35
|
-
authConfig?: AuthConfig,
|
|
36
|
-
extraResponseAttributes: ExtraResponseAttributes[] = []
|
|
37
|
-
) {
|
|
38
|
-
const loginCallback = loginRequiredCallback || (() => Promise.resolve())
|
|
39
|
-
const program = isRelativePath(sasJob)
|
|
40
|
-
? config.appLoc
|
|
41
|
-
? config.appLoc.replace(/\/?$/, '/') + sasJob.replace(/^\//, '')
|
|
42
|
-
: sasJob
|
|
43
|
-
: sasJob
|
|
44
|
-
let apiUrl = `${config.serverUrl}${this.jobsPath}/?${'_program=' + program}`
|
|
45
|
-
|
|
46
|
-
const requestParams = this.getRequestParams(config)
|
|
47
|
-
|
|
48
|
-
const requestPromise = new Promise((resolve, reject) => {
|
|
49
|
-
this.requestClient!.post(
|
|
50
|
-
apiUrl,
|
|
51
|
-
{ ...requestParams, ...data },
|
|
52
|
-
authConfig?.access_token
|
|
53
|
-
)
|
|
54
|
-
.then(async (res: any) => {
|
|
55
|
-
const resObj = {
|
|
56
|
-
result: res.result._webout,
|
|
57
|
-
log: res.result.log
|
|
58
|
-
}
|
|
59
|
-
this.requestClient!.appendRequest(resObj, sasJob, config.debug)
|
|
60
|
-
|
|
61
|
-
let jsonResponse = res.result
|
|
62
|
-
|
|
63
|
-
if (config.debug) {
|
|
64
|
-
const webout = parseWeboutResponse(res.result._webout, apiUrl)
|
|
65
|
-
jsonResponse = getValidJson(webout)
|
|
66
|
-
} else {
|
|
67
|
-
jsonResponse = getValidJson(res.result._webout)
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
const responseObject = appendExtraResponseAttributes(
|
|
71
|
-
{ result: jsonResponse },
|
|
72
|
-
extraResponseAttributes
|
|
73
|
-
)
|
|
74
|
-
resolve(responseObject)
|
|
75
|
-
})
|
|
76
|
-
.catch(async (e: Error) => {
|
|
77
|
-
if (e instanceof JobExecutionError) {
|
|
78
|
-
this.requestClient!.appendRequest(e, sasJob, config.debug)
|
|
79
|
-
reject(new ErrorResponse(e?.message, e))
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
if (e instanceof LoginRequiredError) {
|
|
83
|
-
this.appendWaitingRequest(() => {
|
|
84
|
-
return this.execute(
|
|
85
|
-
sasJob,
|
|
86
|
-
data,
|
|
87
|
-
config,
|
|
88
|
-
loginRequiredCallback,
|
|
89
|
-
authConfig,
|
|
90
|
-
extraResponseAttributes
|
|
91
|
-
).then(
|
|
92
|
-
(res: any) => {
|
|
93
|
-
resolve(res)
|
|
94
|
-
},
|
|
95
|
-
(err: any) => {
|
|
96
|
-
reject(err)
|
|
97
|
-
}
|
|
98
|
-
)
|
|
99
|
-
})
|
|
100
|
-
|
|
101
|
-
await loginCallback()
|
|
102
|
-
} else {
|
|
103
|
-
reject(new ErrorResponse(e?.message, e))
|
|
104
|
-
}
|
|
105
|
-
})
|
|
106
|
-
})
|
|
107
|
-
|
|
108
|
-
return requestPromise
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
private getRequestParams(config: any): any {
|
|
112
|
-
const requestParams: any = {}
|
|
113
|
-
|
|
114
|
-
if (config.debug) {
|
|
115
|
-
requestParams['_omittextlog'] = 'false'
|
|
116
|
-
requestParams['_omitsessionresults'] = 'false'
|
|
117
|
-
|
|
118
|
-
requestParams['_debug'] = 131
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
return requestParams
|
|
122
|
-
}
|
|
123
|
-
}
|