Skip to content

Library Viewer optimization in ITC #1508

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 32 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
176ab4b
Add changes from file explorer feature.
DanilaGrobovSEB Apr 13, 2025
c12016f
Use data connection instead of code execution.
DanilaGrobovSEB May 1, 2025
9d1aff6
Improve columns loading time.
DanilaGrobovSEB May 3, 2025
328b22d
Add column type mapping to the format.
DanilaGrobovSEB May 3, 2025
70069a6
Merge branch 'main' into table_viewer_optimization
danila-grobov May 3, 2025
179fcb7
DCO Remediation Commit for Danila Grobov (s4642g) <danila.grobov@seb.se>
DanilaGrobovSEB May 3, 2025
16eedec
Support empty arrays in json
DanilaGrobovSEB May 3, 2025
2ab7999
Fix incorrect label.
DanilaGrobovSEB May 6, 2025
e78ff54
Remove unnecessary parameters in data connection
DanilaGrobovSEB May 6, 2025
5383d38
Merge branch 'main' into table_viewer_optimization
danila-grobov May 6, 2025
ed6a9ed
Merge branch 'main' into table_viewer_optimization
danila-grobov May 8, 2025
cd0ef99
Fix tests
DanilaGrobovSEB May 11, 2025
019bd3d
Use proxyquire for mocking uuid.
danila-grobov May 12, 2025
d39ce5d
Merge remote-tracking branch 'upstream/main' into table_viewer_optimi…
danila-grobov May 12, 2025
bbcc56d
Merge branch 'main' into table_viewer_optimization
danila-grobov May 13, 2025
192c22f
Fix linting problems.
danila-grobov May 13, 2025
7ec2b55
Merge remote-tracking branch 'upstream/main' into table_viewer_optimi…
DanilaGrobovSEB May 25, 2025
7e4d8a2
Fix package-lock
danila-grobov May 25, 2025
b5785aa
Bring the file explorer changes back.
DanilaGrobovSEB May 25, 2025
207d325
DCO Remediation Commit for Danila Grobov <danila.grob@gmail.com>
danila-grobov May 25, 2025
674c87e
DCO Remediation Commit for Danila Grobov (s4642g) <danila.grobov@seb.se>
DanilaGrobovSEB May 25, 2025
a23005e
Merge branch 'main' into table_viewer_optimization
danila-grobov May 28, 2025
9cfb1f6
Fix formatting issues.
danila-grobov May 28, 2025
ce94b23
Refactor getColumnIconType.
danila-grobov May 30, 2025
3e92c0d
Merge branch 'main' into table_viewer_optimization
danila-grobov May 30, 2025
f341dd8
Updating getLibraries/getTables to use ADO DB connector
Jun 3, 2025
8845e58
Updating tests
DmitryMK Jun 4, 2025
0e4e742
Merge branch 'main' into library_viewer_optimization
DmitryMK Jun 4, 2025
8d805a8
Merge branch 'main' into library_viewer_optimization
DmitryMK Jun 10, 2025
2cc7de0
Fixing duplicated code in scripts
DmitryMK Jun 10, 2025
165f24e
Merge remote-tracking branch 'sas/main' into library_viewer_optimization
DmitryMK Jun 11, 2025
72aad6a
Removing trailing spaces in script.ts
DmitryMK Jun 11, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 12 additions & 30 deletions client/src/connection/itc/ItcLibraryAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,27 +59,19 @@ class ItcLibraryAdapter implements LibraryAdapter {
count: -1,
};
}

public async getLibraries(): Promise<{
items: LibraryItem[];
count: number;
}> {
const sql = `
%let OUTPUT;
proc sql;
select catx(',', libname, readonly) as libname_target into: OUTPUT separated by '~'
from sashelp.vlibnam order by libname asc;
quit;
%put <LIBOUTPUT> &OUTPUT; %put </LIBOUTPUT>;
const code = `
$runner.GetLibraries()
`;

const libNames = processQueryRows(
await this.runCode(sql, "<LIBOUTPUT>", "</LIBOUTPUT>"),
);

const libraries = libNames.map((lineText): LibraryItem => {
const [libName, readOnlyValue] = lineText.split(",");
const output = await executeRawCode(code);
const rawLibraries = JSON.parse(output).libraries;

const libraries = rawLibraries.map((row: string[]) => {
const [libName, readOnlyValue] = row;
return {
type: "library",
uid: libName,
Expand Down Expand Up @@ -161,24 +153,14 @@ class ItcLibraryAdapter implements LibraryAdapter {
items: LibraryItem[];
count: number;
}> {
const sql = `
%let OUTPUT;
proc sql;
select memname into: OUTPUT separated by '~'
from sashelp.vtable
where libname='${item.name!}'
order by memname asc;
quit;
%put <TABLEOUTPUT> &OUTPUT; %put </TABLEOUTPUT>;
`;

const tableNames = processQueryRows(
await this.runCode(sql, "<TABLEOUTPUT>", "</TABLEOUTPUT>"),
);

const tables = tableNames.map((lineText): LibraryItem => {
const [table] = lineText.split(",");
const code = `
$runner.GetTables("${item.name}")
`;

const output = await executeRawCode(code);
const rawTables = JSON.parse(output).tables;
const tables = rawTables.map((table: string): LibraryItem => {
return {
type: "table",
uid: `${item.name!}.${table}`,
Expand Down
77 changes: 71 additions & 6 deletions client/src/connection/itc/script.ts
Original file line number Diff line number Diff line change
Expand Up @@ -243,14 +243,14 @@ class SASRunner{

Write-Host "${LineCodes.ResultsFetchedCode}"
}

[void]GetDatasetRecords([string]$tableName, [int]$start = 0, [int]$limit = 100) {
$objRecordSet = New-Object -comobject ADODB.Recordset
$objRecordSet.ActiveConnection = $this.dataConnection # This is needed to set the properties for sas formats.
$objRecordSet.Properties.Item("SAS Formats").Value = "_ALL_"

$objRecordSet.Open(
$tableName,
$tableName,
[System.Reflection.Missing]::Value, # Use the active connection
2, # adOpenDynamic
1, # adLockReadOnly
Expand Down Expand Up @@ -278,7 +278,7 @@ class SASRunner{
$objRecordSet.Close()

$objRecordSet.Open(
"SELECT COUNT(1) FROM $tableName",
"SELECT COUNT(1) FROM $tableName",
$this.dataConnection, 3, 1, 1
) # adOpenStatic, adLockReadOnly, adCmdText
$count = $objRecordSet.Fields.Item(0).Value
Expand All @@ -295,8 +295,8 @@ class SASRunner{
$objRecordSet = New-Object -comobject ADODB.Recordset
$objRecordSet.ActiveConnection = $this.dataConnection
$query = @"
select name, type, format
from sashelp.vcolumn
select name, type, format
from sashelp.vcolumn
where libname='$libname' and memname='$memname';
"@
$objRecordSet.Open(
Expand All @@ -306,7 +306,7 @@ class SASRunner{
1, # adLockReadOnly
1 # adCmdText
)

$rows = $objRecordSet.GetRows()

$objRecordSet.Close()
Expand Down Expand Up @@ -533,5 +533,70 @@ class SASRunner{
Write-Host (@{success=$false; message=$Error[0].Exception.Message} | ConvertTo-Json)
}
}

[void]GetLibraries() {
$objRecordSet = New-Object -comobject ADODB.Recordset
$objRecordSet.ActiveConnection = $this.dataConnection
$query = @"
select distinct libname, readonly
from sashelp.vlibnam
order by libname asc
"@
$objRecordSet.Open(
$query,
[System.Reflection.Missing]::Value, # Use the active connection
2, # adOpenDynamic
1, # adLockReadOnly
1 # adCmdText
)

$records = [System.Collections.Generic.List[object[]]]::new()
while (-not $objRecordSet.EOF) {
$row = @()
for ($i = 0; $i -lt $objRecordSet.Fields.Count; $i++) {
$row += $objRecordSet.Fields.Item($i).Value
}
$records.Add($row)
$objRecordSet.MoveNext()
}
$objRecordSet.Close()

$result = New-Object psobject
$result | Add-Member -MemberType NoteProperty -Name "libraries" -Value $records
$result | Add-Member -MemberType NoteProperty -Name "count" -Value $records.Count

Write-Host $(ConvertTo-Json -Depth 10 -InputObject $result -Compress)
}

[void]GetTables([string]$libname) {
$objRecordSet = New-Object -comobject ADODB.Recordset
$objRecordSet.ActiveConnection = $this.dataConnection
$query = @"
select memname
from sashelp.vtable
where libname='$libname'
order by memname asc
"@
$objRecordSet.Open(
$query,
[System.Reflection.Missing]::Value, # Use the active connection
2, # adOpenDynamic
1, # adLockReadOnly
1 # adCmdText
)

$records = @()
while (-not $objRecordSet.EOF) {
$records += $objRecordSet.Fields.Item(0).Value
$objRecordSet.MoveNext()
}
$objRecordSet.Close()

$result = New-Object psobject
$result | Add-Member -MemberType NoteProperty -Name "tables" -Value $records
$result | Add-Member -MemberType NoteProperty -Name "count" -Value $records.Count

Write-Host $(ConvertTo-Json -Depth 10 -InputObject $result -Compress)
}
}
`;
31 changes: 20 additions & 11 deletions client/test/connection/itc/ItcLibraryAdapter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,7 @@ import * as connection from "../../../src/connection";
import { MockSession } from "./Coderunner.test";

const mockOutput = () => ({
LIBOUTPUT: `
<LIBOUTPUT>
test1,yes~test2,no
</LIBOUTPUT>
`,
"SELECT COUNT(1)": `<Count>1234</Count>`,
TABLEOUTPUT: `
<TABLEOUTPUT>
test1~test2
</TABLEOUTPUT>`,
});

class DatasetMockSession extends MockSession {
Expand Down Expand Up @@ -107,7 +98,6 @@ describe("ItcLibraryAdapter tests", () => {
});

it("loads libraries", async () => {
const libraryAdapter = new ItcLibraryAdapter();
const expectedLibraries: LibraryItem[] = [
{
uid: "test1",
Expand All @@ -125,6 +115,17 @@ describe("ItcLibraryAdapter tests", () => {
},
];

const mockOutput = JSON.stringify({
libraries: [
["test1", "yes"],
["test2", "no"],
],
count: 2,
});

sessionStub.returns(new DatasetMockSession([mockOutput]));

const libraryAdapter = new ItcLibraryAdapter();
const response = await libraryAdapter.getLibraries();

expect(response.items).to.eql(expectedLibraries);
Expand Down Expand Up @@ -227,7 +228,14 @@ describe("ItcLibraryAdapter tests", () => {
type: "library",
readOnly: true,
};
const libraryAdapter = new ItcLibraryAdapter();

const mockOutput = JSON.stringify({
tables: ["test1", "test2"],
count: 2,
});

sessionStub.returns(new DatasetMockSession([mockOutput]));

const expectedTables: LibraryItem[] = [
{
library: "lib",
Expand All @@ -247,6 +255,7 @@ describe("ItcLibraryAdapter tests", () => {
},
];

const libraryAdapter = new ItcLibraryAdapter();
const response = await libraryAdapter.getTables(library);

expect(response.items).to.eql(expectedTables);
Expand Down