Skip to content

Commit 8df50db

Browse files
authored
Merge pull request #185 from sebjulliand/fix/exampleLoadLoop
Examples browser cleanup
2 parents d279656 + c775947 commit 8df50db

File tree

4 files changed

+80
-70
lines changed

4 files changed

+80
-70
lines changed

package.json

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,11 @@
7575
"type": "string",
7676
"description": "SQL formatting options: Lowercase or uppercase SQL identifiers",
7777
"default": "preserve",
78-
"enum": ["lower", "upper", "preserve"],
78+
"enum": [
79+
"lower",
80+
"upper",
81+
"preserve"
82+
],
7983
"enumDescriptions": [
8084
"Format SQL identifiers in lowercase",
8185
"Format SQL identifiers in uppercase",
@@ -86,7 +90,10 @@
8690
"type": "string",
8791
"description": "SQL formatting options: Lowercase or uppercase SQL keywords",
8892
"default": "lower",
89-
"enum": ["lower", "upper"],
93+
"enum": [
94+
"lower",
95+
"upper"
96+
],
9097
"enumDescriptions": [
9198
"Format reserved SQL keywords in lowercase",
9299
"Format reserved SQL keywords in uppercase"
@@ -291,6 +298,12 @@
291298
"category": "Db2 for i (Examples)",
292299
"icon": "$(clear-all)"
293300
},
301+
{
302+
"command": "vscode-db2i.examples.reload",
303+
"title": "Reload examples",
304+
"category": "Db2 for i",
305+
"icon": "$(sync)"
306+
},
294307
{
295308
"command": "vscode-db2i.jobManager.newJob",
296309
"title": "New SQL Job",
@@ -420,6 +433,10 @@
420433
{
421434
"command": "vscode-db2i.jobManager.deleteConfig",
422435
"when": "never"
436+
},
437+
{
438+
"command": "vscode-db2i.examples.reload",
439+
"when": "never"
423440
}
424441
],
425442
"editor/context": [
@@ -466,7 +483,12 @@
466483
"command": "vscode-db2i.examples.clearFilter",
467484
"group": "navigation",
468485
"when": "view == exampleBrowser"
469-
},
486+
},
487+
{
488+
"command": "vscode-db2i.examples.reload",
489+
"group": "navigation@99",
490+
"when": "view == exampleBrowser"
491+
},
470492
{
471493
"command": "vscode-db2i.openSqlDocument",
472494
"group": "navigation",
@@ -645,4 +667,4 @@
645667
"sql-formatter": "^14.0.0",
646668
"lru-cache": "^6.0.0"
647669
}
648-
}
670+
}

src/database/serviceInfo.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
1-
import { SQLExample } from "../views/examples";
21
import { JobManager } from "../config";
2+
import { SQLExample } from "../views/examples";
33
import Statement from "./statement";
44

5-
export async function getServiceInfo(): Promise<SQLExample[]|undefined> {
5+
export async function getServiceInfo(): Promise<SQLExample[]> {
66
// The reason we check for a selection is because we don't want it to prompt the user to start one here
77
if (JobManager.getSelection()) {
8-
const resultSet = await JobManager.runSQL<{SERVICE_NAME: string, EXAMPLE: string}>(`select SERVICE_NAME, EXAMPLE from qsys2.services_info`);
8+
const resultSet = await JobManager.runSQL<{ SERVICE_NAME: string, EXAMPLE: string }>(`select SERVICE_NAME, EXAMPLE from qsys2.services_info`);
99

1010
return resultSet.map(r => ({
1111
name: Statement.prettyName(r.SERVICE_NAME),
1212
content: [r.EXAMPLE],
1313
}))
1414
} else {
15-
return undefined;
15+
return [{ name: "Please start an SQL job to load the examples", content: [""] }];
1616
}
1717
}

src/views/examples/exampleBrowser.ts

Lines changed: 47 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,16 @@
1-
import { EventEmitter, MarkdownString, workspace } from "vscode";
2-
import { window } from "vscode";
3-
import { CancellationToken, Event, ExtensionContext, ProviderResult, ThemeIcon, TreeDataProvider, TreeItem, TreeItemCollapsibleState, commands } from "vscode";
4-
import { SQLExample, Examples, ServiceInfoLabel } from ".";
5-
import { OSData, fetchSystemInfo } from "../../config";
1+
import { Event, EventEmitter, ExtensionContext, MarkdownString, ThemeIcon, TreeDataProvider, TreeItem, TreeItemCollapsibleState, Uri, commands, window, workspace } from "vscode";
2+
import { Examples, SQLExample, ServiceInfoLabel } from ".";
63
import { getInstance } from "../../base";
4+
import { OSData, fetchSystemInfo } from "../../config";
75
import { getServiceInfo } from "../../database/serviceInfo";
86

97
const openExampleCommand = `vscode-db2i.examples.open`;
108

119
export class ExampleBrowser implements TreeDataProvider<any> {
1210
private _onDidChangeTreeData: EventEmitter<TreeItem | undefined | null | void> = new EventEmitter<TreeItem | undefined | null | void>();
1311
readonly onDidChangeTreeData: Event<TreeItem | undefined | null | void> = this._onDidChangeTreeData.event;
14-
15-
private currentFilter: string|undefined;
12+
13+
private currentFilter: string | undefined;
1614

1715
constructor(context: ExtensionContext) {
1816
context.subscriptions.push(
@@ -40,6 +38,11 @@ export class ExampleBrowser implements TreeDataProvider<any> {
4038
commands.registerCommand(`vscode-db2i.examples.clearFilter`, async () => {
4139
this.currentFilter = undefined;
4240
this.refresh();
41+
}),
42+
43+
commands.registerCommand("vscode-db2i.examples.reload", () => {
44+
delete Examples[ServiceInfoLabel];
45+
this.refresh();
4346
})
4447
);
4548

@@ -49,9 +52,9 @@ export class ExampleBrowser implements TreeDataProvider<any> {
4952
// Refresh the examples when we have it, so we only display certain examples
5053
this.refresh();
5154
})
52-
})
55+
})
5356
}
54-
57+
5558
refresh() {
5659
this._onDidChangeTreeData.fire();
5760
}
@@ -60,74 +63,53 @@ export class ExampleBrowser implements TreeDataProvider<any> {
6063
return element;
6164
}
6265

63-
async getChildren(element?: ExampleGroupItem): Promise<any[]> {
64-
// Unlike the bulk of the examples which are defined in views/examples/index.ts, the services examples are retrieved dynamically
65-
if (!Examples[ServiceInfoLabel]) {
66-
getServiceInfo().then(serviceExamples => {
67-
Examples[ServiceInfoLabel] = serviceExamples;
68-
this.refresh();
69-
})
66+
async getChildren(element?: ExampleGroupItem): Promise<SQLExampleItem[]> {
67+
if (element) {
68+
return element.getChildren();
7069
}
71-
72-
if (this.currentFilter) {
73-
// If there is a filter, then show all examples that include this criteria
74-
let items: SQLExampleItem[] = [];
75-
76-
const upperFilter = this.currentFilter.toUpperCase();
77-
78-
for (const exampleName in Examples) {
79-
items.push(
80-
...Examples[exampleName]
81-
.filter(example => exampleWorksForOnOS(example))
82-
.filter(example => example.name.toUpperCase().includes(upperFilter) || example.content.some(line => line.toUpperCase().includes(upperFilter)))
83-
.map(example => new SQLExampleItem(example))
84-
)
70+
else {
71+
// Unlike the bulk of the examples which are defined in views/examples/index.ts, the services examples are retrieved dynamically
72+
if (!Examples[ServiceInfoLabel]) {
73+
Examples[ServiceInfoLabel] = await getServiceInfo();
8574
}
8675

87-
return items;
88-
89-
} else {
90-
if (element) {
91-
return element.getChildren();
92-
} else {
93-
let items: ExampleGroupItem[] = [];
94-
95-
for (const exampleName in Examples) {
96-
items.push(
97-
new ExampleGroupItem(exampleName, Examples[exampleName])
98-
)
99-
}
100-
101-
return items;
76+
if (this.currentFilter) {
77+
// If there is a filter, then show all examples that include this criteria
78+
const upperFilter = this.currentFilter.toUpperCase();
79+
return Object.values(Examples)
80+
.flatMap(examples => examples.filter(exampleWorksForOnOS))
81+
.filter(example => example.name.toUpperCase().includes(upperFilter) || example.content.some(line => line.toUpperCase().includes(upperFilter)))
82+
.sort(sort)
83+
.map(example => new SQLExampleItem(example));
84+
}
85+
else {
86+
return Object.entries(Examples)
87+
.sort(([name1], [name2]) => sort(name1, name2))
88+
.map(([name, examples]) => new ExampleGroupItem(name, examples));
10289
}
10390
}
10491
}
105-
106-
getParent?(element: any) {
107-
throw new Error("Method not implemented.");
108-
}
10992
}
11093

11194
class ExampleGroupItem extends TreeItem {
11295
constructor(name: string, private group: SQLExample[]) {
11396
super(name, TreeItemCollapsibleState.Collapsed);
114-
115-
this.iconPath = new ThemeIcon(`folder`);
97+
this.iconPath = ThemeIcon.Folder;
11698
}
11799

118100
getChildren(): SQLExampleItem[] {
119101
return this.group
120102
.filter(example => exampleWorksForOnOS(example))
103+
.sort(sort)
121104
.map(example => new SQLExampleItem(example));
122105
}
123106
}
124107

125108
class SQLExampleItem extends TreeItem {
126109
constructor(example: SQLExample) {
127110
super(example.name, TreeItemCollapsibleState.None);
128-
129-
this.iconPath = new ThemeIcon(`file`);
130-
111+
this.iconPath = ThemeIcon.File;
112+
this.resourceUri = Uri.parse('_.sql');
131113
this.tooltip = new MarkdownString(['```sql', example.content.join(`\n`), '```'].join(`\n`));
132114

133115
this.command = {
@@ -142,13 +124,19 @@ function exampleWorksForOnOS(example: SQLExample): boolean {
142124
if (OSData) {
143125
const myOsVersion = OSData.version;
144126

145-
// If this example has specific system requirements defined..
146-
if (example.requirements && example.requirements[myOsVersion]) {
147-
if (OSData.db2Level < example.requirements[myOsVersion]) {
148-
return false;
149-
}
127+
// If this example has specific system requirements defined
128+
if (example.requirements &&
129+
example.requirements[myOsVersion] &&
130+
OSData.db2Level < example.requirements[myOsVersion]) {
131+
return false;
150132
}
151133
}
152134

153135
return true;
136+
}
137+
138+
function sort(string1: string | SQLExample, string2: string | SQLExample) {
139+
string1 = typeof string1 === "string" ? string1 : string1.name;
140+
string2 = typeof string2 === "string" ? string2 : string2.name;
141+
return string1.localeCompare(string2);
154142
}

src/views/examples/index.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@ export interface SQLExample {
1313
requirements?: ExampleSystemRequirements;
1414
};
1515

16-
// Unlike the bulk of the examples defined below, the services examples are retrieved dynamically
17-
export const ServiceInfoLabel = `IBM i (SQL) Services`;
16+
// Unlike the bulk of the examples defined below, the services examples are retrieved dynamically
17+
export const ServiceInfoLabel = `IBM i (SQL) Services`;
1818

19-
export let Examples: SQLExamplesList = {
19+
export const Examples: SQLExamplesList = {
2020
"Data Definition Language (DDL)": [
2121
{
2222
"name": "Create Schema",

0 commit comments

Comments
 (0)