Skip to content

Commit 616d5e6

Browse files
authored
fix: Library Viewer optimization in ITC (#1520)
* Similar to the approach used in PR #1466, updating getLibraries and getTables to use ADO DB connector instead of execution of a SAS code. That speeds up library and table refresh for ITC connection. Signed-off-by: dmitrymk [email protected] * DCO Remediation Commit for dmitrymk <[email protected]> I, dmitrymk <[email protected]>, hereby add my Signed-off-by to this commit: 326bd17 Signed-off-by: dmitrymk <[email protected]> --------- Signed-off-by: dmitrymk [email protected] Signed-off-by: dmitrymk <[email protected]>
1 parent 6d095ec commit 616d5e6

File tree

3 files changed

+102
-58
lines changed

3 files changed

+102
-58
lines changed

client/src/connection/itc/ItcLibraryAdapter.ts

Lines changed: 11 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -59,27 +59,19 @@ class ItcLibraryAdapter implements LibraryAdapter {
5959
count: -1,
6060
};
6161
}
62-
6362
public async getLibraries(): Promise<{
6463
items: LibraryItem[];
6564
count: number;
6665
}> {
67-
const sql = `
68-
%let OUTPUT;
69-
proc sql;
70-
select catx(',', libname, readonly) as libname_target into: OUTPUT separated by '~'
71-
from sashelp.vlibnam order by libname asc;
72-
quit;
73-
%put <LIBOUTPUT> &OUTPUT; %put </LIBOUTPUT>;
66+
const code = `
67+
$runner.GetLibraries()
7468
`;
7569

76-
const libNames = processQueryRows(
77-
await this.runCode(sql, "<LIBOUTPUT>", "</LIBOUTPUT>"),
78-
);
79-
80-
const libraries = libNames.map((lineText): LibraryItem => {
81-
const [libName, readOnlyValue] = lineText.split(",");
70+
const output = await executeRawCode(code);
71+
const rawLibraries = JSON.parse(output).libraries;
8272

73+
const libraries = rawLibraries.map((row: string[]) => {
74+
const [libName, readOnlyValue] = row;
8375
return {
8476
type: "library",
8577
uid: libName,
@@ -161,24 +153,13 @@ class ItcLibraryAdapter implements LibraryAdapter {
161153
items: LibraryItem[];
162154
count: number;
163155
}> {
164-
const sql = `
165-
%let OUTPUT;
166-
proc sql;
167-
select memname into: OUTPUT separated by '~'
168-
from sashelp.vtable
169-
where libname='${item.name!}'
170-
order by memname asc;
171-
quit;
172-
%put <TABLEOUTPUT> &OUTPUT; %put </TABLEOUTPUT>;
156+
const code = `
157+
$runner.GetTables("${item.name}")
173158
`;
174159

175-
const tableNames = processQueryRows(
176-
await this.runCode(sql, "<TABLEOUTPUT>", "</TABLEOUTPUT>"),
177-
);
178-
179-
const tables = tableNames.map((lineText): LibraryItem => {
180-
const [table] = lineText.split(",");
181-
160+
const output = await executeRawCode(code);
161+
const rawTables = JSON.parse(output).tables;
162+
const tables = rawTables.map((table: string): LibraryItem => {
182163
return {
183164
type: "table",
184165
uid: `${item.name!}.${table}`,
@@ -239,15 +220,4 @@ class ItcLibraryAdapter implements LibraryAdapter {
239220
}
240221
}
241222

242-
const processQueryRows = (response: string): string[] => {
243-
const processedResponse = response.trim().replace(/\n|\t/gm, "");
244-
if (!processedResponse) {
245-
return [];
246-
}
247-
248-
return processedResponse
249-
.split("~")
250-
.filter((value, index, array) => array.indexOf(value) === index);
251-
};
252-
253223
export default ItcLibraryAdapter;

client/src/connection/itc/script.ts

Lines changed: 71 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -243,14 +243,14 @@ class SASRunner{
243243
244244
Write-Host "${LineCodes.ResultsFetchedCode}"
245245
}
246-
246+
247247
[void]GetDatasetRecords([string]$tableName, [int]$start = 0, [int]$limit = 100) {
248248
$objRecordSet = New-Object -comobject ADODB.Recordset
249249
$objRecordSet.ActiveConnection = $this.dataConnection # This is needed to set the properties for sas formats.
250250
$objRecordSet.Properties.Item("SAS Formats").Value = "_ALL_"
251251
252252
$objRecordSet.Open(
253-
$tableName,
253+
$tableName,
254254
[System.Reflection.Missing]::Value, # Use the active connection
255255
2, # adOpenDynamic
256256
1, # adLockReadOnly
@@ -278,7 +278,7 @@ class SASRunner{
278278
$objRecordSet.Close()
279279
280280
$objRecordSet.Open(
281-
"SELECT COUNT(1) FROM $tableName",
281+
"SELECT COUNT(1) FROM $tableName",
282282
$this.dataConnection, 3, 1, 1
283283
) # adOpenStatic, adLockReadOnly, adCmdText
284284
$count = $objRecordSet.Fields.Item(0).Value
@@ -295,8 +295,8 @@ class SASRunner{
295295
$objRecordSet = New-Object -comobject ADODB.Recordset
296296
$objRecordSet.ActiveConnection = $this.dataConnection
297297
$query = @"
298-
select name, type, format
299-
from sashelp.vcolumn
298+
select name, type, format
299+
from sashelp.vcolumn
300300
where libname='$libname' and memname='$memname';
301301
"@
302302
$objRecordSet.Open(
@@ -306,7 +306,7 @@ class SASRunner{
306306
1, # adLockReadOnly
307307
1 # adCmdText
308308
)
309-
309+
310310
$rows = $objRecordSet.GetRows()
311311
312312
$objRecordSet.Close()
@@ -533,5 +533,70 @@ class SASRunner{
533533
Write-Host (@{success=$false; message=$Error[0].Exception.Message} | ConvertTo-Json)
534534
}
535535
}
536+
537+
[void]GetLibraries() {
538+
$objRecordSet = New-Object -comobject ADODB.Recordset
539+
$objRecordSet.ActiveConnection = $this.dataConnection
540+
$query = @"
541+
select distinct libname, readonly
542+
from sashelp.vlibnam
543+
order by libname asc;
544+
"@
545+
$objRecordSet.Open(
546+
$query,
547+
[System.Reflection.Missing]::Value, # Use the active connection
548+
2, # adOpenDynamic
549+
1, # adLockReadOnly
550+
1 # adCmdText
551+
)
552+
553+
$records = [System.Collections.Generic.List[object[]]]::new()
554+
while (-not $objRecordSet.EOF) {
555+
$row = @()
556+
for ($i = 0; $i -lt $objRecordSet.Fields.Count; $i++) {
557+
$row += $objRecordSet.Fields.Item($i).Value
558+
}
559+
$records.Add($row)
560+
$objRecordSet.MoveNext()
561+
}
562+
$objRecordSet.Close()
563+
564+
$result = New-Object psobject
565+
$result | Add-Member -MemberType NoteProperty -Name "libraries" -Value $records
566+
$result | Add-Member -MemberType NoteProperty -Name "count" -Value $records.Count
567+
568+
Write-Host $(ConvertTo-Json -Depth 10 -InputObject $result -Compress)
569+
}
570+
571+
[void]GetTables([string]$libname) {
572+
$objRecordSet = New-Object -comobject ADODB.Recordset
573+
$objRecordSet.ActiveConnection = $this.dataConnection
574+
$query = @"
575+
select memname
576+
from sashelp.vtable
577+
where libname='$libname'
578+
order by memname asc;
579+
"@
580+
$objRecordSet.Open(
581+
$query,
582+
[System.Reflection.Missing]::Value, # Use the active connection
583+
2, # adOpenDynamic
584+
1, # adLockReadOnly
585+
1 # adCmdText
586+
)
587+
588+
$records = @()
589+
while (-not $objRecordSet.EOF) {
590+
$records += $objRecordSet.Fields.Item(0).Value
591+
$objRecordSet.MoveNext()
592+
}
593+
$objRecordSet.Close()
594+
595+
$result = New-Object psobject
596+
$result | Add-Member -MemberType NoteProperty -Name "tables" -Value $records
597+
$result | Add-Member -MemberType NoteProperty -Name "count" -Value $records.Count
598+
599+
Write-Host $(ConvertTo-Json -Depth 10 -InputObject $result -Compress)
600+
}
536601
}
537602
`;

client/test/connection/itc/ItcLibraryAdapter.test.ts

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,7 @@ import * as connection from "../../../src/connection";
1111
import { MockSession } from "./Coderunner.test";
1212

1313
const mockOutput = () => ({
14-
LIBOUTPUT: `
15-
<LIBOUTPUT>
16-
test1,yes~test2,no
17-
</LIBOUTPUT>
18-
`,
1914
"SELECT COUNT(1)": `<Count>1234</Count>`,
20-
TABLEOUTPUT: `
21-
<TABLEOUTPUT>
22-
test1~test2
23-
</TABLEOUTPUT>`,
2415
});
2516

2617
class DatasetMockSession extends MockSession {
@@ -107,7 +98,6 @@ describe("ItcLibraryAdapter tests", () => {
10798
});
10899

109100
it("loads libraries", async () => {
110-
const libraryAdapter = new ItcLibraryAdapter();
111101
const expectedLibraries: LibraryItem[] = [
112102
{
113103
uid: "test1",
@@ -125,6 +115,17 @@ describe("ItcLibraryAdapter tests", () => {
125115
},
126116
];
127117

118+
const mockOutput = JSON.stringify({
119+
libraries: [
120+
["test1", "yes"],
121+
["test2", "no"],
122+
],
123+
count: 2,
124+
});
125+
126+
sessionStub.returns(new DatasetMockSession([mockOutput]));
127+
128+
const libraryAdapter = new ItcLibraryAdapter();
128129
const response = await libraryAdapter.getLibraries();
129130

130131
expect(response.items).to.eql(expectedLibraries);
@@ -227,7 +228,14 @@ describe("ItcLibraryAdapter tests", () => {
227228
type: "library",
228229
readOnly: true,
229230
};
230-
const libraryAdapter = new ItcLibraryAdapter();
231+
232+
const mockOutput = JSON.stringify({
233+
tables: ["test1", "test2"],
234+
count: 2,
235+
});
236+
237+
sessionStub.returns(new DatasetMockSession([mockOutput]));
238+
231239
const expectedTables: LibraryItem[] = [
232240
{
233241
library: "lib",
@@ -247,6 +255,7 @@ describe("ItcLibraryAdapter tests", () => {
247255
},
248256
];
249257

258+
const libraryAdapter = new ItcLibraryAdapter();
250259
const response = await libraryAdapter.getTables(library);
251260

252261
expect(response.items).to.eql(expectedTables);

0 commit comments

Comments
 (0)