mirror of
https://github.com/sasjs/adapter.git
synced 2026-01-03 10:40:06 +00:00
Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bde28046be | ||
|
|
eab61a80bf | ||
|
|
9149f932c3 | ||
|
|
fb30ff8876 | ||
|
|
afff422333 | ||
|
|
b49010cfe5 | ||
|
|
fd6fad9b07 | ||
|
|
8a10c229d6 | ||
|
|
66462fcc50 | ||
|
|
7e23b5db9d | ||
| 78f117812e | |||
|
|
55af8c3f50 | ||
| 1185c2f1bf | |||
|
|
2842636c4a | ||
| 8c7f614509 | |||
| 943f60ea11 | |||
| 3de343f135 | |||
| e11c97ec5d | |||
| 49fba07824 | |||
| b1c0e26c23 |
11
.github/workflows/build-unit-tests.yml
vendored
11
.github/workflows/build-unit-tests.yml
vendored
@@ -20,7 +20,16 @@ jobs:
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
cache: npm
|
||||
|
||||
# 2. Restore npm cache manually
|
||||
- name: Restore npm cache
|
||||
uses: actions/cache@v3
|
||||
id: npm-cache
|
||||
with:
|
||||
path: ~/.npm
|
||||
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-node-
|
||||
|
||||
- name: Check npm audit
|
||||
run: npm audit --production --audit-level=low
|
||||
|
||||
11
.github/workflows/generateDocs.yml
vendored
11
.github/workflows/generateDocs.yml
vendored
@@ -21,7 +21,16 @@ jobs:
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
cache: npm
|
||||
|
||||
# 2. Restore npm cache manually
|
||||
- name: Restore npm cache
|
||||
uses: actions/cache@v3
|
||||
id: npm-cache
|
||||
with:
|
||||
path: ~/.npm
|
||||
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-node-
|
||||
|
||||
- name: Install Dependencies
|
||||
run: npm ci
|
||||
|
||||
11
.github/workflows/npmpublish.yml
vendored
11
.github/workflows/npmpublish.yml
vendored
@@ -22,7 +22,16 @@ jobs:
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
cache: npm
|
||||
|
||||
# 2. Restore npm cache manually
|
||||
- name: Restore npm cache
|
||||
uses: actions/cache@v3
|
||||
id: npm-cache
|
||||
with:
|
||||
path: ~/.npm
|
||||
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-node-
|
||||
|
||||
- name: Install Dependencies
|
||||
run: npm ci
|
||||
|
||||
11
.github/workflows/server-tests.yml
vendored
11
.github/workflows/server-tests.yml
vendored
@@ -20,7 +20,16 @@ jobs:
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
cache: npm
|
||||
|
||||
# 2. Restore npm cache manually
|
||||
- name: Restore npm cache
|
||||
uses: actions/cache@v3
|
||||
id: npm-cache
|
||||
with:
|
||||
path: ~/.npm
|
||||
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-node-
|
||||
|
||||
- name: Install Dependencies
|
||||
run: npm ci
|
||||
|
||||
46
package-lock.json
generated
46
package-lock.json
generated
@@ -9,9 +9,9 @@
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@sasjs/utils": "3.5.2",
|
||||
"axios": "1.8.2",
|
||||
"axios": "1.12.2",
|
||||
"axios-cookiejar-support": "5.0.5",
|
||||
"form-data": "4.0.0",
|
||||
"form-data": "4.0.4",
|
||||
"https": "1.0.0",
|
||||
"tough-cookie": "4.1.3"
|
||||
},
|
||||
@@ -3510,13 +3510,13 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/axios": {
|
||||
"version": "1.8.2",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.8.2.tgz",
|
||||
"integrity": "sha512-ls4GYBm5aig9vWx8AWDSGLpnpDQRtWAfrjU+EuytuODrFBkqesN2RkOQCBzrA1RQNHw1SmRMSDDDSwzNAYQ6Rg==",
|
||||
"version": "1.12.2",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.12.2.tgz",
|
||||
"integrity": "sha512-vMJzPewAlRyOgxV2dU0Cuz2O8zzzx9VYtbJOaBgXFeLc4IV/Eg50n4LowmehOOR61S8ZMpc2K5Sa7g6A4jfkUw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.15.6",
|
||||
"form-data": "^4.0.0",
|
||||
"form-data": "^4.0.4",
|
||||
"proxy-from-env": "^1.1.0"
|
||||
}
|
||||
},
|
||||
@@ -4096,7 +4096,6 @@
|
||||
},
|
||||
"node_modules/call-bind-apply-helpers": {
|
||||
"version": "1.0.2",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"es-errors": "^1.3.0",
|
||||
@@ -5204,7 +5203,6 @@
|
||||
},
|
||||
"node_modules/dunder-proto": {
|
||||
"version": "1.0.1",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bind-apply-helpers": "^1.0.1",
|
||||
@@ -5459,7 +5457,6 @@
|
||||
},
|
||||
"node_modules/es-define-property": {
|
||||
"version": "1.0.1",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
@@ -5467,7 +5464,6 @@
|
||||
},
|
||||
"node_modules/es-errors": {
|
||||
"version": "1.3.0",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
@@ -5480,7 +5476,6 @@
|
||||
},
|
||||
"node_modules/es-object-atoms": {
|
||||
"version": "1.1.1",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"es-errors": "^1.3.0"
|
||||
@@ -5489,6 +5484,21 @@
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/es-set-tostringtag": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
|
||||
"integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"es-errors": "^1.3.0",
|
||||
"get-intrinsic": "^1.2.6",
|
||||
"has-tostringtag": "^1.0.2",
|
||||
"hasown": "^2.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/es6-promisify": {
|
||||
"version": "7.0.0",
|
||||
"dev": true,
|
||||
@@ -6046,11 +6056,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/form-data": {
|
||||
"version": "4.0.0",
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz",
|
||||
"integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.8",
|
||||
"es-set-tostringtag": "^2.1.0",
|
||||
"hasown": "^2.0.2",
|
||||
"mime-types": "^2.1.12"
|
||||
},
|
||||
"engines": {
|
||||
@@ -6147,7 +6161,6 @@
|
||||
},
|
||||
"node_modules/function-bind": {
|
||||
"version": "1.1.2",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
@@ -6171,7 +6184,6 @@
|
||||
},
|
||||
"node_modules/get-intrinsic": {
|
||||
"version": "1.3.0",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bind-apply-helpers": "^1.0.2",
|
||||
@@ -6204,7 +6216,6 @@
|
||||
},
|
||||
"node_modules/get-proto": {
|
||||
"version": "1.0.1",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"dunder-proto": "^1.0.1",
|
||||
@@ -6343,7 +6354,6 @@
|
||||
},
|
||||
"node_modules/gopd": {
|
||||
"version": "1.2.0",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
@@ -6404,7 +6414,6 @@
|
||||
},
|
||||
"node_modules/has-symbols": {
|
||||
"version": "1.1.0",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
@@ -6415,7 +6424,6 @@
|
||||
},
|
||||
"node_modules/has-tostringtag": {
|
||||
"version": "1.0.2",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"has-symbols": "^1.0.3"
|
||||
@@ -6450,7 +6458,6 @@
|
||||
},
|
||||
"node_modules/hasown": {
|
||||
"version": "2.0.2",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"function-bind": "^1.1.2"
|
||||
@@ -8639,7 +8646,6 @@
|
||||
},
|
||||
"node_modules/math-intrinsics": {
|
||||
"version": "1.1.0",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
|
||||
@@ -80,9 +80,9 @@
|
||||
"main": "index.js",
|
||||
"dependencies": {
|
||||
"@sasjs/utils": "3.5.2",
|
||||
"axios": "1.8.2",
|
||||
"axios": "1.12.2",
|
||||
"axios-cookiejar-support": "5.0.5",
|
||||
"form-data": "4.0.0",
|
||||
"form-data": "4.0.4",
|
||||
"https": "1.0.0",
|
||||
"tough-cookie": "4.1.3"
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ import { uploadTables } from './api/viya/uploadTables'
|
||||
import { executeOnComputeApi } from './api/viya/executeOnComputeApi'
|
||||
import { getAccessTokenForViya } from './auth/getAccessTokenForViya'
|
||||
import { refreshTokensForViya } from './auth/refreshTokensForViya'
|
||||
import { FileResource } from './types/FileResource'
|
||||
|
||||
interface JobExecutionResult {
|
||||
result?: { result: object }
|
||||
@@ -311,6 +312,84 @@ export class SASViyaApiClient {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the file content for a file in the specified folder.
|
||||
*
|
||||
* @param folderPath - the full path to the folder containing the file. eg: /Public/folder1/folder2
|
||||
* @param fileName - the name of the file in the `folderPath`
|
||||
* @param accessToken - an access token for authorizing the request
|
||||
*/
|
||||
public async getFileContent(
|
||||
folderPath: string,
|
||||
fileName: string,
|
||||
accessToken?: string
|
||||
) {
|
||||
const fileUri = await this.getFileUri(
|
||||
folderPath,
|
||||
fileName,
|
||||
accessToken
|
||||
).catch((err) => {
|
||||
throw prefixMessage(
|
||||
err,
|
||||
`Error while getting file URI for: ${fileName} in folder: ${folderPath}. `
|
||||
)
|
||||
})
|
||||
|
||||
return await this.requestClient
|
||||
.get<string>(`${this.serverUrl}${fileUri}/content`, accessToken)
|
||||
.then((res) => res.result)
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the file content for a file in the specified folder.
|
||||
*
|
||||
* @param folderPath - the full path to the folder containing the file. eg: /Public/folder1/folder2
|
||||
* @param fileName - the name of the file in the `folderPath`
|
||||
* @param content - the new content to be written to the file
|
||||
* @param accessToken - an access token for authorizing the request
|
||||
*/
|
||||
public async updateFileContent(
|
||||
folderPath: string,
|
||||
fileName: string,
|
||||
content: string,
|
||||
accessToken?: string
|
||||
) {
|
||||
const fileUri = await this.getFileUri(
|
||||
folderPath,
|
||||
fileName,
|
||||
accessToken
|
||||
).catch((err) => {
|
||||
throw prefixMessage(
|
||||
err,
|
||||
`Error while getting file URI for: ${fileName} in folder: ${folderPath}. `
|
||||
)
|
||||
})
|
||||
|
||||
// Fetch the file resource details to get the Etag and content type
|
||||
const { result: originalFileResource, etag } =
|
||||
await this.requestClient.get<FileResource>(
|
||||
`${this.serverUrl}${fileUri}`,
|
||||
accessToken
|
||||
)
|
||||
|
||||
if (!originalFileResource || !etag)
|
||||
throw new Error(
|
||||
`File ${fileName} does not have an ETag, or request failed.`
|
||||
)
|
||||
|
||||
return await this.requestClient
|
||||
.put<FileResource>(
|
||||
`${this.serverUrl}${fileUri}/content`,
|
||||
content,
|
||||
accessToken,
|
||||
{
|
||||
'If-Match': etag,
|
||||
'Content-Type': originalFileResource.contentType
|
||||
}
|
||||
)
|
||||
.then((res) => res.result)
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches a folder. Path to the folder is required.
|
||||
* @param folderPath - the absolute path to the folder.
|
||||
@@ -791,14 +870,14 @@ export class SASViyaApiClient {
|
||||
_webin_file_count: files.length,
|
||||
_OMITJSONLISTING: true,
|
||||
_OMITJSONLOG: true,
|
||||
_OMITSESSIONRESULTS: true,
|
||||
_omitSessionResults: false,
|
||||
_OMITTEXTLISTING: true,
|
||||
_OMITTEXTLOG: true
|
||||
}
|
||||
|
||||
if (debug) {
|
||||
jobArguments['_OMITTEXTLOG'] = 'false'
|
||||
jobArguments['_OMITSESSIONRESULTS'] = 'false'
|
||||
jobArguments['_omitSessionResults'] = 'false'
|
||||
jobArguments['_DEBUG'] = 131
|
||||
}
|
||||
|
||||
@@ -941,6 +1020,7 @@ export class SASViyaApiClient {
|
||||
})
|
||||
|
||||
if (!folder) return undefined
|
||||
|
||||
return folder
|
||||
}
|
||||
|
||||
@@ -952,6 +1032,30 @@ export class SASViyaApiClient {
|
||||
return `/folders/folders/${folderDetails.id}`
|
||||
}
|
||||
|
||||
private async getFileUri(
|
||||
folderPath: string,
|
||||
fileName: string,
|
||||
accessToken?: string
|
||||
): Promise<string> {
|
||||
const folderMembers = await this.listFolder(folderPath, accessToken, 1000, {
|
||||
returnDetails: true
|
||||
}).catch((err) => {
|
||||
throw prefixMessage(err, `Error while listing folder: ${folderPath}. `)
|
||||
})
|
||||
|
||||
if (!folderMembers || !folderMembers.length)
|
||||
throw new Error(`No members found in folder: ${folderPath}`)
|
||||
|
||||
const fileUri = folderMembers.find(
|
||||
(member) => member.name === fileName
|
||||
)?.uri
|
||||
|
||||
if (!fileUri)
|
||||
throw new Error(`File ${fileName} not found in folder: ${folderPath}`)
|
||||
|
||||
return fileUri
|
||||
}
|
||||
|
||||
private async getRecycleBinUri(accessToken?: string) {
|
||||
const url = '/folders/folders/@myRecycleBin'
|
||||
|
||||
@@ -999,14 +1103,19 @@ export class SASViyaApiClient {
|
||||
}
|
||||
|
||||
/**
|
||||
* Lists children folders for given Viya folder.
|
||||
* Lists children folders/files 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.
|
||||
* @param {Object} [options] - Additional options.
|
||||
* @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.
|
||||
*/
|
||||
public async listFolder(
|
||||
sourceFolder: string,
|
||||
accessToken?: string,
|
||||
limit: number = 20
|
||||
limit: number = 20,
|
||||
options?: {
|
||||
returnDetails?: boolean
|
||||
}
|
||||
) {
|
||||
// checks if 'sourceFolder' is already a URI
|
||||
const sourceFolderUri = isUri(sourceFolder)
|
||||
@@ -1018,11 +1127,20 @@ export class SASViyaApiClient {
|
||||
accessToken
|
||||
)
|
||||
|
||||
let membersToReturn = []
|
||||
|
||||
if (members && members.items) {
|
||||
return members.items.map((item: any) => item.name)
|
||||
} else {
|
||||
return []
|
||||
// If returnDetails is true, return full member details
|
||||
if (options?.returnDetails) {
|
||||
membersToReturn = members.items
|
||||
} else {
|
||||
// If returnDetails is false, return only member names
|
||||
membersToReturn = members.items.map((item: any) => item.name)
|
||||
}
|
||||
}
|
||||
|
||||
// Return members without Etag
|
||||
return membersToReturn
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
68
src/SASjs.ts
68
src/SASjs.ts
@@ -9,7 +9,8 @@ import {
|
||||
ErrorResponse,
|
||||
LoginOptions,
|
||||
LoginResult,
|
||||
ExecutionQuery
|
||||
ExecutionQuery,
|
||||
Tables
|
||||
} from './types'
|
||||
import { SASViyaApiClient } from './SASViyaApiClient'
|
||||
import { SAS9ApiClient } from './SAS9ApiClient'
|
||||
@@ -411,6 +412,51 @@ export default class SASjs {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the file content for a file in the specified folder.
|
||||
*
|
||||
* @param folderPath - the full path to the folder containing the file. eg: /Public/folder1/folder2
|
||||
* @param fileName - the name of the file in the `folderPath`
|
||||
* @param accessToken - an access token for authorizing the request
|
||||
*/
|
||||
public async getFileContent(
|
||||
folderPath: string,
|
||||
fileName: string,
|
||||
accessToken?: string
|
||||
) {
|
||||
this.isMethodSupported('getFileContent', [ServerType.SasViya])
|
||||
|
||||
return await this.sasViyaApiClient!.getFileContent(
|
||||
folderPath,
|
||||
fileName,
|
||||
accessToken
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the file content for a file in the specified folder.
|
||||
*
|
||||
* @param folderPath - the full path to the folder containing the file. eg: /Public/folder1/folder2
|
||||
* @param fileName - the name of the file in the `folderPath`
|
||||
* @param content - the new content to be written to the file
|
||||
* @param accessToken - an access token for authorizing the request
|
||||
*/
|
||||
public async updateFileContent(
|
||||
folderPath: string,
|
||||
fileName: string,
|
||||
content: string,
|
||||
accessToken?: string
|
||||
) {
|
||||
this.isMethodSupported('updateFileContent', [ServerType.SasViya])
|
||||
|
||||
return await this.sasViyaApiClient!.updateFileContent(
|
||||
folderPath,
|
||||
fileName,
|
||||
content,
|
||||
accessToken
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches a folder from the SAS file system.
|
||||
* @param folderPath - path of the folder to be fetched.
|
||||
@@ -436,18 +482,23 @@ export default class SASjs {
|
||||
* 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.
|
||||
* @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.
|
||||
*/
|
||||
public async listFolder(
|
||||
sourceFolder: string,
|
||||
accessToken?: string,
|
||||
limit?: number
|
||||
limit?: number,
|
||||
returnDetails = false
|
||||
) {
|
||||
this.isMethodSupported('listFolder', [ServerType.SasViya])
|
||||
|
||||
return await this.sasViyaApiClient?.listFolder(
|
||||
sourceFolder,
|
||||
accessToken,
|
||||
limit
|
||||
limit,
|
||||
{
|
||||
returnDetails
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1190,4 +1241,15 @@ export default class SASjs {
|
||||
public setVerboseMode = (verboseMode: VerboseMode) => {
|
||||
this.requestClient?.setVerboseMode(verboseMode)
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a tables class containing one or more tables to be sent to
|
||||
* SAS.
|
||||
* @param table - initial table data
|
||||
* @param macroName - macro name
|
||||
* @returns Tables class
|
||||
*/
|
||||
Tables(table: Record<string, any>, macroName: string) {
|
||||
return new Tables(table, macroName)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ export abstract class BaseJobExecutor implements JobExecutor {
|
||||
|
||||
if (config.debug) {
|
||||
requestParams['_omittextlog'] = 'false'
|
||||
requestParams['_omitsessionresults'] = 'false'
|
||||
requestParams['_omitSessionResults'] = 'false'
|
||||
|
||||
requestParams['_debug'] = 131
|
||||
}
|
||||
|
||||
@@ -104,7 +104,7 @@ Connection: close
|
||||
_contextName: 'SAS Job Execution compute context',
|
||||
_OMITJSONLISTING: true,
|
||||
_OMITJSONLOG: true,
|
||||
_OMITSESSIONRESULTS: true,
|
||||
_omitSessionResults: true,
|
||||
_OMITTEXTLISTING: true,
|
||||
_OMITTEXTLOG: true
|
||||
}
|
||||
|
||||
33
src/types/FileResource.ts
Normal file
33
src/types/FileResource.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
export interface FileResource {
|
||||
creationTimeStamp: string
|
||||
modifiedTimeStamp: string
|
||||
createdBy: string
|
||||
modifiedBy: string
|
||||
id: string
|
||||
properties: Properties
|
||||
contentDisposition: string
|
||||
contentType: string
|
||||
encoding: string
|
||||
links: Link[]
|
||||
name: string
|
||||
size: number
|
||||
searchable: boolean
|
||||
fileStatus: string
|
||||
fileVersion: number
|
||||
typeDefName: string
|
||||
version: number
|
||||
virusDetected: boolean
|
||||
urlDetected: boolean
|
||||
quarantine: boolean
|
||||
}
|
||||
|
||||
export interface Link {
|
||||
method: string
|
||||
rel: string
|
||||
href: string
|
||||
uri: string
|
||||
type?: string
|
||||
responseType?: string
|
||||
}
|
||||
|
||||
export interface Properties {}
|
||||
28
src/types/Tables.spec.ts
Normal file
28
src/types/Tables.spec.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import SASjs from '../SASjs'
|
||||
|
||||
describe('Tables - basic coverage', () => {
|
||||
const adapter = new SASjs()
|
||||
|
||||
it('should throw an error if first argument is not an array', () => {
|
||||
expect(() => adapter.Tables({}, 'test')).toThrow('First argument')
|
||||
})
|
||||
|
||||
it('should throw an error if second argument is not a string', () => {
|
||||
// @ts-expect-error
|
||||
expect(() => adapter.Tables([], 1234)).toThrow('Second argument')
|
||||
})
|
||||
|
||||
it('should throw an error if macro name ends with a number', () => {
|
||||
expect(() => adapter.Tables([], 'test1')).toThrow('number at the end')
|
||||
})
|
||||
|
||||
it('should throw an error if no arguments are passed', () => {
|
||||
// @ts-expect-error
|
||||
expect(() => adapter.Tables()).toThrow('Missing arguments')
|
||||
})
|
||||
|
||||
it('should create Tables class successfully with _tables property', () => {
|
||||
const tables = adapter.Tables([], 'test')
|
||||
expect(tables).toHaveProperty('_tables')
|
||||
})
|
||||
})
|
||||
29
src/types/Tables.ts
Normal file
29
src/types/Tables.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { ArgumentError } from './errors'
|
||||
|
||||
export class Tables {
|
||||
_tables: { [macroName: string]: Record<string, any> }
|
||||
|
||||
constructor(table: Record<string, any>, macroName: string) {
|
||||
this._tables = {}
|
||||
|
||||
this.add(table, macroName)
|
||||
}
|
||||
|
||||
add(table: Record<string, any> | null, macroName: string) {
|
||||
if (table && macroName) {
|
||||
if (!(table instanceof Array)) {
|
||||
throw new ArgumentError('First argument must be array')
|
||||
}
|
||||
if (typeof macroName !== 'string') {
|
||||
throw new ArgumentError('Second argument must be string')
|
||||
}
|
||||
if (!isNaN(Number(macroName[macroName.length - 1]))) {
|
||||
throw new ArgumentError('Macro name cannot have number at the end')
|
||||
}
|
||||
} else {
|
||||
throw new ArgumentError('Missing arguments')
|
||||
}
|
||||
|
||||
this._tables[macroName] = table
|
||||
}
|
||||
}
|
||||
7
src/types/errors/ArgumentError.ts
Normal file
7
src/types/errors/ArgumentError.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
export class ArgumentError extends Error {
|
||||
constructor(public message: string) {
|
||||
super(message)
|
||||
this.name = 'ArgumentError'
|
||||
Object.setPrototypeOf(this, ArgumentError.prototype)
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
export * from './ArgumentError'
|
||||
export * from './AuthorizeError'
|
||||
export * from './CertificateError'
|
||||
export * from './ComputeJobExecutionError'
|
||||
|
||||
@@ -15,3 +15,4 @@ export * from './PollOptions'
|
||||
export * from './WriteStream'
|
||||
export * from './ExecuteScript'
|
||||
export * from './errors'
|
||||
export * from './Tables'
|
||||
|
||||
Reference in New Issue
Block a user