1
0
mirror of https://github.com/sasjs/adapter.git synced 2026-01-05 03:30:05 +00:00

Compare commits

...

22 Commits

Author SHA1 Message Date
Allan Bowe
982c4c329c Merge pull request #734 from sasjs/issue-733
fix: special missing double dot issue
2022-07-07 19:23:02 +01:00
8617e2dc57 fix: special missing double dot issue 2022-07-07 17:58:27 +02:00
Allan Bowe
d3d62f6888 Merge pull request #731 from sasjs/issue-730
fix: do not throw job execution error if response contains >>weboutBEGIN<<
2022-06-29 16:33:03 +02:00
Allan Bowe
bf35e52962 Merge pull request #713 from sasjs/critical-deps-issues
Fixed critical dependencies issues
2022-06-29 14:24:29 +02:00
22eca50e3f fix: do not throw job execution error if response contains >>weboutBEGIN<< 2022-06-29 16:59:03 +05:00
Yury Shkoda
eb83101dbf fix(sasjs-test): addede appLoc to useEffect deps 2022-06-29 08:46:52 +03:00
Yury Shkoda
56d84e1940 fix(sasjs-tests): used appLoc from config 2022-06-29 08:37:59 +03:00
Yury Shkoda
283800dfa6 fix(special-missings): fixed formats table sent as part of sasjs_tables 2022-06-28 10:17:22 +03:00
Yury Shkoda
c073d72dd4 chore(deps): regenerated package-locks 2022-06-24 16:16:36 +03:00
Yury Shkoda
f5d40eaaf7 chore: Merge branch 'deps-fix' into critical-deps-issues 2022-06-24 16:13:43 +03:00
Allan Bowe
79ba044dea Update README.md 2022-06-24 11:49:48 +01:00
Allan Bowe
9329dc848a Update README.md 2022-06-24 11:46:09 +01:00
Allan Bowe
98c492e85e Merge pull request #729 from sasjs/update-AuthManager
fix: update logout url
2022-06-21 22:10:26 +02:00
d1fcc2ca0a fix: update logout url 2022-06-22 00:53:49 +05:00
Yury Shkoda
122f302bae Merge pull request #728 from sasjs/deps-fix
fix(workflow): added actions/setup-node@v2
2022-06-20 20:44:57 +03:00
Yury Shkoda
a28b48f815 Merge pull request #726 from sasjs/deps-fix
fix(workflows): fixed npmpublish workflow
2022-06-20 20:36:13 +03:00
Allan Bowe
db60962c1e Merge pull request #725 from sasjs/allanbowe-patch-1
fix: bumping with README updates
2022-06-20 19:29:15 +02:00
Allan Bowe
1eae59ad3b fix: bumping with README updates 2022-06-20 18:28:47 +01:00
Allan Bowe
d485023d65 Update dependabot.yml 2022-06-20 18:09:07 +01:00
Allan Bowe
c2f21babb4 Merge pull request #723 from sasjs/deps-fix
Regenerated package-lock and fixed linting issues
2022-06-20 19:03:17 +02:00
Yury Shkoda
f602d5baf0 chore(deps): added prettier 2022-06-01 10:08:50 +03:00
Yury Shkoda
4744dbf196 fix(deps): fixed critical vulnerabilities 2022-06-01 09:53:22 +03:00
14 changed files with 1036 additions and 921 deletions

View File

@@ -1,7 +1,7 @@
version: 2 version: 2
updates: updates:
- package-ecosystem: npm - package-ecosystem: "npm"
directory: '/' directory: "/"
schedule: schedule:
interval: monthly interval: "monthly"
open-pull-requests-limit: 2 open-pull-requests-limit: 2

View File

@@ -2,7 +2,6 @@
[![npm package][npm-image]][npm-url] [![npm package][npm-image]][npm-url]
[![Github Workflow][githubworkflow-image]][githubworkflow-url] [![Github Workflow][githubworkflow-image]][githubworkflow-url]
[![Dependency Status][dependency-image]][dependency-url]
[![npm](https://img.shields.io/npm/dt/@sasjs/adapter)]() [![npm](https://img.shields.io/npm/dt/@sasjs/adapter)]()
![Snyk Vulnerabilities for npm package](https://img.shields.io/snyk/vulnerabilities/npm/@sasjs/adapter) ![Snyk Vulnerabilities for npm package](https://img.shields.io/snyk/vulnerabilities/npm/@sasjs/adapter)
[![License](https://img.shields.io/apm/l/atomic-design-ui.svg)](/LICENSE) [![License](https://img.shields.io/apm/l/atomic-design-ui.svg)](/LICENSE)
@@ -16,7 +15,6 @@
[githubworkflow-image]:https://github.com/sasjs/adapter/actions/workflows/build.yml/badge.svg [githubworkflow-image]:https://github.com/sasjs/adapter/actions/workflows/build.yml/badge.svg
[githubworkflow-url]:https://github.com/sasjs/adapter/blob/main/.github/workflows/build.yml [githubworkflow-url]:https://github.com/sasjs/adapter/blob/main/.github/workflows/build.yml
[dependency-image]:https://david-dm.org/sasjs/adapter.svg [dependency-image]:https://david-dm.org/sasjs/adapter.svg
[dependency-url]:https://github.com/sasjs/adapter/blob/main/package.json
SASjs is a open-source framework for building Web Apps on SAS® platforms. You can use as much or as little of it as you like. This repository contains the JS adapter, the part that handles the to/from SAS communication on the client side. There are 3 ways to install it: SASjs is a open-source framework for building Web Apps on SAS® platforms. You can use as much or as little of it as you like. This repository contains the JS adapter, the part that handles the to/from SAS communication on the client side. There are 3 ways to install it:
@@ -32,7 +30,7 @@ For more information on building web apps with SAS, check out [sasjs.io](https:/
## None of this makes sense. How do I build an app with it? ## None of this makes sense. How do I build an app with it?
Ok ok. Deploy this [example.html](https://raw.githubusercontent.com/sasjs/adapter/master/example.html) file to your web server, and update `servertype` to `SAS9` or `SASVIYA` depending on your backend. Ok ok. Deploy this [example.html](https://raw.githubusercontent.com/sasjs/adapter/master/example.html) file to your web server, and update `servertype` to `SAS9`, `SASVIYA`, or `SASJS` depending on your backend.
The backend part can be deployed as follows: The backend part can be deployed as follows:
@@ -52,7 +50,7 @@ parmcards4;
%webout(OBJ,areas) %webout(OBJ,areas)
%webout(CLOSE) %webout(CLOSE)
;;;; ;;;;
%mp_createwebservice(path=&appLoc/common,name=getdata) %mx_createwebservice(path=&appLoc/common,name=getdata)
``` ```
You now have a simple web app with a backend service! You now have a simple web app with a backend service!
@@ -96,10 +94,10 @@ const sasJs = new SASjs({your config})
More on the config later. More on the config later.
### SAS Logon ### SAS Logon
All authentication from the adapter is done against SASLogon. There are two approaches that can be taken, which are configured using the `LoginMechanism` attribute of the sasJs config object (above): All authentication from the adapter is done against SASLogon. There are two approaches that can be taken, which are configured using the `loginMechanism` attribute of the sasJs config object (above):
* `LoginMechanism:'Redirected'` - this approach enables authentication through a SASLogon window, supporting complex authentication flows (such as 2FA) and avoids the need to handle passwords in the application itself. The styling of the window can be modified using CSS. * `loginMechanism:'Redirected'` - this approach enables authentication through a SASLogon window, supporting complex authentication flows (such as 2FA) and avoids the need to handle passwords in the application itself. The styling of the window can be modified using CSS.
* `LoginMechanism:'Default'` - this approach requires that the username and password are captured, and used within the `.login()` method. This can be helpful for development, or automated testing. * `loginMechanism:'Default'` - this approach requires that the username and password are captured, and used within the `.login()` method. This can be helpful for development, or automated testing.
Sample code for logging in with the `Default` approach: Sample code for logging in with the `Default` approach:
@@ -127,7 +125,11 @@ sasJs.request("/path/to/my/service", dataObject)
}) })
``` ```
We supply the path to the SAS service, and a data object. The data object can be null (for services with no input), or can contain one or more tables in the following format: We supply the path to the SAS service, and a data object.
If the path starts with a `/` then it should be a full path to the service. If there is no leading `/` then it is relative to the `appLoc`.
The data object can be null (for services with no input), or can contain one or more "tables" in the following format:
```javascript ```javascript
let dataObject={ let dataObject={
@@ -143,7 +145,9 @@ let dataObject={
}; };
``` ```
There are optional parameters such as a config object and a callback login function. These tables (`tablewith2cols1row` and `tablewith1col2rows`) will be created in SAS WORK after running `%webout(FETCH)` in your SAS service.
The `request()` method also has optional parameters such as a config object and a callback login function.
The response object will contain returned tables and columns. Table names are always lowercase, and column names uppercase. The response object will contain returned tables and columns. Table names are always lowercase, and column names uppercase.
@@ -221,7 +225,7 @@ The SAS side is handled by a number of macros in the [macro core](https://github
The following snippet shows the process of SAS tables arriving / leaving: The following snippet shows the process of SAS tables arriving / leaving:
```sas ```sas
/* fetch all input tables sent from frontend - they arrive as work tables */ /* convert frontend input tables from into SASWORK datasets */
%webout(FETCH) %webout(FETCH)
/* some sas code */ /* some sas code */
@@ -250,6 +254,8 @@ Where an entire column is made up of special missing numerics, there would be no
%webout(OBJ,a,missing=STRING,showmeta=YES) %webout(OBJ,a,missing=STRING,showmeta=YES)
``` ```
The `%webout()` macro itself is just a wrapper for the [mp_jsonout](https://core.sasjs.io/mp__jsonout_8sas.html) macro.
## Configuration ## Configuration
Configuration on the client side involves passing an object on startup, which can also be passed with each request. Technical documentation on the SASjsConfig class is available [here](https://adapter.sasjs.io/classes/types.sasjsconfig.html). The main config items are: Configuration on the client side involves passing an object on startup, which can also be passed with each request. Technical documentation on the SASjsConfig class is available [here](https://adapter.sasjs.io/classes/types.sasjsconfig.html). The main config items are:
@@ -258,7 +264,7 @@ Configuration on the client side involves passing an object on startup, which ca
* `serverType` - either `SAS9`, `SASVIYA` or `SASJS`. The `SASJS` server type is for use with [sasjs/server](https://github.com/sasjs/server). * `serverType` - either `SAS9`, `SASVIYA` or `SASJS`. The `SASJS` server type is for use with [sasjs/server](https://github.com/sasjs/server).
* `serverUrl` - the location (including http protocol and port) of the SAS Server. Can be omitted, eg if serving directly from the SAS Web Server, or in streaming mode. * `serverUrl` - the location (including http protocol and port) of the SAS Server. Can be omitted, eg if serving directly from the SAS Web Server, or in streaming mode.
* `debug` - if `true` then SAS Logs and extra debug information is returned. * `debug` - if `true` then SAS Logs and extra debug information is returned.
* `LoginMechanism` - either `Default` or `Redirected`. See [SAS Logon](#sas-logon) section. * `loginMechanism` - either `Default` or `Redirected`. See [SAS Logon](#sas-logon) section.
* `useComputeApi` - Only relevant when the serverType is `SASVIYA`. If `true` the [Compute API](#using-the-compute-api) is used. If `false` the [JES API](#using-the-jes-api) is used. If `null` or `undefined` the [Web](#using-jes-web-app) approach is used. * `useComputeApi` - Only relevant when the serverType is `SASVIYA`. If `true` the [Compute API](#using-the-compute-api) is used. If `false` the [JES API](#using-the-jes-api) is used. If `null` or `undefined` the [Web](#using-jes-web-app) approach is used.
* `contextName` - Compute context on which the requests will be called. If missing or not provided, defaults to `Job Execution Compute context`. * `contextName` - Compute context on which the requests will be called. If missing or not provided, defaults to `Job Execution Compute context`.
* `requestHistoryLimit` - Request history limit. Increasing this limit may affect browser performance, especially with debug (logs) enabled. Default is 10. * `requestHistoryLimit` - Request history limit. Increasing this limit may affect browser performance, especially with debug (logs) enabled. Default is 10.
@@ -314,7 +320,7 @@ For more information and examples specific to this adapter you can check out the
For more information on building web apps in general, check out these [resources](https://sasjs.io/training/resources/) or contact the [author](https://www.linkedin.com/in/allanbowe/) directly. For more information on building web apps in general, check out these [resources](https://sasjs.io/training/resources/) or contact the [author](https://www.linkedin.com/in/allanbowe/) directly.
If you are a SAS 9 or SAS Viya customer you can also request a copy of [Data Controller](https://datacontroller.io) - free for up to 5 users, this tool makes use of all parts of the SASjs framework. As a SAS customer you can also request a copy of [Data Controller](https://datacontroller.io) - free for up to 5 users, this tool makes use of all parts of the SASjs framework.
## Star Gazing ## Star Gazing

12
package-lock.json generated
View File

@@ -12973,7 +12973,7 @@
}, },
"node_modules/npm/node_modules/rimraf/node_modules/brace-expansion": { "node_modules/npm/node_modules/rimraf/node_modules/brace-expansion": {
"version": "1.1.11", "version": "1.1.11",
"dev": true, "extraneous": true,
"inBundle": true, "inBundle": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -12983,7 +12983,7 @@
}, },
"node_modules/npm/node_modules/rimraf/node_modules/glob": { "node_modules/npm/node_modules/rimraf/node_modules/glob": {
"version": "7.2.3", "version": "7.2.3",
"dev": true, "extraneous": true,
"inBundle": true, "inBundle": true,
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
@@ -13003,7 +13003,7 @@
}, },
"node_modules/npm/node_modules/rimraf/node_modules/minimatch": { "node_modules/npm/node_modules/rimraf/node_modules/minimatch": {
"version": "3.1.2", "version": "3.1.2",
"dev": true, "extraneous": true,
"inBundle": true, "inBundle": true,
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
@@ -26856,7 +26856,7 @@
"brace-expansion": { "brace-expansion": {
"version": "1.1.11", "version": "1.1.11",
"bundled": true, "bundled": true,
"dev": true, "extraneous": true,
"requires": { "requires": {
"balanced-match": "^1.0.0", "balanced-match": "^1.0.0",
"concat-map": "0.0.1" "concat-map": "0.0.1"
@@ -26865,7 +26865,7 @@
"glob": { "glob": {
"version": "7.2.3", "version": "7.2.3",
"bundled": true, "bundled": true,
"dev": true, "extraneous": true,
"requires": { "requires": {
"fs.realpath": "^1.0.0", "fs.realpath": "^1.0.0",
"inflight": "^1.0.4", "inflight": "^1.0.4",
@@ -26878,7 +26878,7 @@
"minimatch": { "minimatch": {
"version": "3.1.2", "version": "3.1.2",
"bundled": true, "bundled": true,
"dev": true, "extraneous": true,
"requires": { "requires": {
"brace-expansion": "^1.1.7" "brace-expansion": "^1.1.7"
} }

File diff suppressed because it is too large Load Diff

View File

@@ -11,12 +11,13 @@ import { fileUploadTests } from './testSuites/FileUpload'
const App = (): ReactElement<{}> => { const App = (): ReactElement<{}> => {
const { adapter, config } = useContext(AppContext) const { adapter, config } = useContext(AppContext)
const [testSuites, setTestSuites] = useState<TestSuite[]>([]) const [testSuites, setTestSuites] = useState<TestSuite[]>([])
const appLoc = config.sasJsConfig.appLoc
useEffect(() => { useEffect(() => {
if (adapter) { if (adapter) {
const testSuites = [ const testSuites = [
basicTests(adapter, config.userName, config.password), basicTests(adapter, config.userName, config.password),
sendArrTests(adapter), sendArrTests(adapter, appLoc),
sendObjTests(adapter), sendObjTests(adapter),
specialCaseTests(adapter), specialCaseTests(adapter),
sasjsRequestTests(adapter), sasjsRequestTests(adapter),
@@ -24,12 +25,12 @@ const App = (): ReactElement<{}> => {
] ]
if (adapter.getSasjsConfig().serverType === 'SASVIYA') { if (adapter.getSasjsConfig().serverType === 'SASVIYA') {
testSuites.push(computeTests(adapter)) testSuites.push(computeTests(adapter, appLoc))
} }
setTestSuites(testSuites) setTestSuites(testSuites)
} }
}, [adapter, config]) }, [adapter, config, appLoc])
return ( return (
<div className="app"> <div className="app">

View File

@@ -3,7 +3,7 @@ import { TestSuite } from '@sasjs/test-framework'
const stringData: any = { table1: [{ col1: 'first col value' }] } const stringData: any = { table1: [{ col1: 'first col value' }] }
export const computeTests = (adapter: SASjs): TestSuite => ({ export const computeTests = (adapter: SASjs, appLoc: string): TestSuite => ({
name: 'Compute', name: 'Compute',
tests: [ tests: [
{ {
@@ -35,7 +35,7 @@ export const computeTests = (adapter: SASjs): TestSuite => ({
description: 'Should start a compute job and return the session', description: 'Should start a compute job and return the session',
test: () => { test: () => {
const data: any = { table1: [{ col1: 'first col value' }] } const data: any = { table1: [{ col1: 'first col value' }] }
return adapter.startComputeJob('/Public/app/common/sendArr', data) return adapter.startComputeJob(`${appLoc}/common/sendArr`, data)
}, },
assertion: (res: any) => { assertion: (res: any) => {
const expectedProperties = ['id', 'applicationName', 'attributes'] const expectedProperties = ['id', 'applicationName', 'attributes']

View File

@@ -45,14 +45,14 @@ const getLargeObjectData = () => {
return data return data
} }
export const sendArrTests = (adapter: SASjs): TestSuite => ({ export const sendArrTests = (adapter: SASjs, appLoc: string): TestSuite => ({
name: 'sendArr', name: 'sendArr',
tests: [ tests: [
{ {
title: 'Absolute paths', title: 'Absolute paths',
description: 'Should work with absolute paths to SAS jobs', description: 'Should work with absolute paths to SAS jobs',
test: () => { test: () => {
return adapter.request('/Public/app/common/sendArr', stringData) return adapter.request(`${appLoc}/common/sendArr`, stringData)
}, },
assertion: (res: any) => { assertion: (res: any) => {
return res.table1[0][0] === stringData.table1[0].col1 return res.table1[0][0] === stringData.table1[0].col1

View File

@@ -23,7 +23,7 @@ export class AuthManager {
? '/SASLogon/logout?' ? '/SASLogon/logout?'
: this.serverType === ServerType.SasViya : this.serverType === ServerType.SasViya
? '/SASLogon/logout.do?' ? '/SASLogon/logout.do?'
: '/SASjsApi/auth/logout' : '/SASLogon/logout'
} }
/** /**
@@ -334,19 +334,9 @@ export class AuthManager {
/** /**
* Logs out of the configured SAS server. * Logs out of the configured SAS server.
* @param accessToken - an optional access token is required for SASjs server type. *
*/ */
public async logOut() { public async logOut() {
if (this.serverType === ServerType.Sasjs) {
return this.requestClient
.delete(this.logoutUrl)
.catch(() => true)
.finally(() => {
this.requestClient.clearLocalStorageTokens()
return true
})
}
this.requestClient.clearCsrfTokens() this.requestClient.clearCsrfTokens()
return this.requestClient.get(this.logoutUrl, undefined).then(() => true) return this.requestClient.get(this.logoutUrl, undefined).then(() => true)

View File

@@ -1,5 +1,5 @@
import * as NodeFormData from 'form-data' import * as NodeFormData from 'form-data'
import { convertToCSV } from '../utils/convertToCsv' import { convertToCSV, isFormatsTable } from '../utils/convertToCsv'
import { splitChunks } from '../utils/splitChunks' import { splitChunks } from '../utils/splitChunks'
export const generateTableUploadForm = ( export const generateTableUploadForm = (
@@ -13,7 +13,8 @@ export const generateTableUploadForm = (
for (const tableName in data) { for (const tableName in data) {
tableCounter++ tableCounter++
sasjsTables.push(tableName) // Formats table should not be sent as part of 'sasjs_tables'
if (!isFormatsTable(tableName)) sasjsTables.push(tableName)
const csv = convertToCSV(data, tableName) const csv = convertToCSV(data, tableName)

View File

@@ -703,7 +703,14 @@ const parseError = (data: string) => {
} catch (_) {} } catch (_) {}
try { try {
// There are some edge cases in which the SAS mp_abort macro
// (https://core.sasjs.io/mp__abort_8sas.html) is unable to
// provide a clean exit. In this case the JSON response will
// be wrapped in >>weboutBEGIN<< and >>weboutEND<< strings.
// Therefore, if the first string exists, we won't throw an
// error just yet (the parser may yet throw one instead)
const hasError = const hasError =
!data?.match(/>>weboutBEGIN<</) &&
!!data?.match(/Stored Process Error/i) && !!data?.match(/Stored Process Error/i) &&
!!data?.match(/This request completed with errors./i) !!data?.match(/This request completed with errors./i)
if (hasError) { if (hasError) {

View File

@@ -11,13 +11,16 @@ describe('formatDataForRequest', () => {
{ var1: 'string', var2: 232, nullvar: '_' }, { var1: 'string', var2: 232, nullvar: '_' },
{ var1: 'string', var2: 232, nullvar: 0 }, { var1: 'string', var2: 232, nullvar: 0 },
{ var1: 'string', var2: 232, nullvar: 'z' }, { var1: 'string', var2: 232, nullvar: 'z' },
{ var1: 'string', var2: 232, nullvar: null } { var1: 'string', var2: 232, nullvar: null },
{ var1: 'string', var2: 232, nullvar: '.A' },
{ var1: 'string', var2: 232, nullvar: '._' },
{ var1: 'string', var2: 232, nullvar: '.' }
], ],
[`$${testTable}`]: { formats: { var1: '$char12.', nullvar: 'best.' } } [`$${testTable}`]: { formats: { var1: '$char12.', nullvar: 'best.' } }
} }
const expectedOutput = { const expectedOutput = {
sasjs1data: `var1:$char12. var2:best. nullvar:best.\r\nstring,232,.a\r\nstring,232,.b\r\nstring,232,._\r\nstring,232,0\r\nstring,232,.z\r\nstring,232,.`, sasjs1data: `var1:$char12. var2:best. nullvar:best.\r\nstring,232,.a\r\nstring,232,.b\r\nstring,232,._\r\nstring,232,0\r\nstring,232,.z\r\nstring,232,.\r\nstring,232,.a\r\nstring,232,._\r\nstring,232,.`,
sasjs_tables: testTable sasjs_tables: testTable
} }

View File

@@ -1,4 +1,4 @@
import { convertToCSV } from './convertToCsv' import { convertToCSV, isFormatsTable } from './convertToCsv'
describe('convertToCsv', () => { describe('convertToCsv', () => {
const tableName = 'testTable' const tableName = 'testTable'
@@ -216,7 +216,9 @@ describe('convertToCsv', () => {
const data = { [tableName]: [{ var1: 'string' }] } const data = { [tableName]: [{ var1: 'string' }] }
expect(() => convertToCSV(data, 'wrongTableName')).toThrow( expect(() => convertToCSV(data, 'wrongTableName')).toThrow(
new Error('No table provided to be converted to CSV') new Error(
'Error while converting to CSV. No table provided to be converted to CSV.'
)
) )
}) })
@@ -226,3 +228,15 @@ describe('convertToCsv', () => {
expect(convertToCSV(data, tableName)).toEqual('') expect(convertToCSV(data, tableName)).toEqual('')
}) })
}) })
describe('isFormatsTable', () => {
const tableName = 'sometable'
it('should return true if table name match pattern of formats table', () => {
expect(isFormatsTable(`$${tableName}`)).toEqual(true)
})
it('should return false if table name does not match pattern of formats table', () => {
expect(isFormatsTable(tableName)).toEqual(false)
})
})

View File

@@ -1,4 +1,5 @@
import { isSpecialMissing } from '@sasjs/utils/input/validators' import { isSpecialMissing } from '@sasjs/utils/input/validators'
import { prefixMessage } from '@sasjs/utils/error'
/** /**
* Converts the given JSON object array to a CSV string. * Converts the given JSON object array to a CSV string.
@@ -9,7 +10,10 @@ export const convertToCSV = (
tableName: string tableName: string
) => { ) => {
if (!data[tableName]) { if (!data[tableName]) {
throw new Error('No table provided to be converted to CSV') throw prefixMessage(
'No table provided to be converted to CSV.',
'Error while converting to CSV. '
)
} }
const table = data[tableName] const table = data[tableName]
@@ -137,7 +141,9 @@ export const convertToCSV = (
) )
} }
return `.${value.toLowerCase()}` const dot = value.includes('.') ? '' : '.'
return `${dot}${value.toLowerCase()}`
} }
// if there any present, it should have preceding (") for escaping // if there any present, it should have preceding (") for escaping
@@ -170,6 +176,12 @@ export const convertToCSV = (
return finalCSV return finalCSV
} }
/**
* Checks if table is table of formats (table name should start from '$' character).
* @param tableName - table name.
*/
export const isFormatsTable = (tableName: string) => /^\$.*/.test(tableName)
const getByteSize = (str: string) => { const getByteSize = (str: string) => {
let byteSize = str.length let byteSize = str.length
for (let i = str.length - 1; i >= 0; i--) { for (let i = str.length - 1; i >= 0; i--) {

View File

@@ -1,4 +1,4 @@
import { convertToCSV } from './convertToCsv' import { convertToCSV, isFormatsTable } from './convertToCsv'
import { splitChunks } from './splitChunks' import { splitChunks } from './splitChunks'
export const formatDataForRequest = (data: any) => { export const formatDataForRequest = (data: any) => {
@@ -8,7 +8,7 @@ export const formatDataForRequest = (data: any) => {
for (const tableName in data) { for (const tableName in data) {
if ( if (
tableName.match(/^\$.*/) && isFormatsTable(tableName) &&
Object.keys(data).includes(tableName.replace(/^\$/, '')) Object.keys(data).includes(tableName.replace(/^\$/, ''))
) { ) {
continue continue
@@ -16,7 +16,8 @@ export const formatDataForRequest = (data: any) => {
tableCounter++ tableCounter++
sasjsTables.push(tableName) // Formats table should not be sent as part of 'sasjs_tables'
if (!isFormatsTable(tableName)) sasjsTables.push(tableName)
const csv = convertToCSV(data, tableName) const csv = convertToCSV(data, tableName)