Skip to content

Commit 2a6d581

Browse files
authored
Added logic to clean expanded state when it's updated (github#1938)
1 parent b3fcd47 commit 2a6d581

File tree

5 files changed

+269
-3
lines changed

5 files changed

+269
-3
lines changed

extensions/ql-vscode/src/databases/db-item-expansion.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { DbItem, DbItemKind } from "./db-item";
1+
import { DbItem, DbItemKind, flattenDbItems } from "./db-item";
22

33
export type ExpandedDbItem =
44
| RootLocalExpandedDbItem
@@ -68,6 +68,16 @@ export function replaceExpandedItem(
6868
return newExpandedItems;
6969
}
7070

71+
export function cleanNonExistentExpandedItems(
72+
currentExpandedItems: ExpandedDbItem[],
73+
dbItems: DbItem[],
74+
): ExpandedDbItem[] {
75+
const flattenedDbItems = flattenDbItems(dbItems);
76+
return currentExpandedItems.filter((i) =>
77+
flattenedDbItems.some((dbItem) => isDbItemEqualToExpandedDbItem(dbItem, i)),
78+
);
79+
}
80+
7181
function mapDbItemToExpandedDbItem(dbItem: DbItem): ExpandedDbItem {
7282
switch (dbItem.kind) {
7383
case DbItemKind.RootLocal:

extensions/ql-vscode/src/databases/db-item.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,3 +149,32 @@ const SelectableDbItemKinds = [
149149
DbItemKind.RemoteOwner,
150150
DbItemKind.RemoteRepo,
151151
];
152+
153+
export function flattenDbItems(dbItems: DbItem[]): DbItem[] {
154+
const allItems: DbItem[] = [];
155+
156+
for (const dbItem of dbItems) {
157+
allItems.push(dbItem);
158+
switch (dbItem.kind) {
159+
case DbItemKind.RootLocal:
160+
allItems.push(...flattenDbItems(dbItem.children));
161+
break;
162+
case DbItemKind.LocalList:
163+
allItems.push(...flattenDbItems(dbItem.databases));
164+
break;
165+
case DbItemKind.RootRemote:
166+
allItems.push(...flattenDbItems(dbItem.children));
167+
break;
168+
case DbItemKind.RemoteUserDefinedList:
169+
allItems.push(...dbItem.repos);
170+
break;
171+
case DbItemKind.LocalDatabase:
172+
case DbItemKind.RemoteSystemDefinedList:
173+
case DbItemKind.RemoteOwner:
174+
case DbItemKind.RemoteRepo:
175+
break;
176+
}
177+
}
178+
179+
return allItems;
180+
}

extensions/ql-vscode/src/databases/db-manager.ts

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
updateExpandedItem,
1515
replaceExpandedItem,
1616
ExpandedDbItem,
17+
cleanNonExistentExpandedItems,
1718
} from "./db-item-expansion";
1819
import {
1920
getSelectedDbItem,
@@ -86,7 +87,7 @@ export class DbManager {
8687
itemExpanded,
8788
);
8889

89-
await this.setExpandedItems(newExpandedItems);
90+
await this.updateExpandedItems(newExpandedItems);
9091
}
9192

9293
public async addNewRemoteRepo(
@@ -133,7 +134,7 @@ export class DbManager {
133134
newDbItem,
134135
);
135136

136-
await this.setExpandedItems(newExpandedItems);
137+
await this.updateExpandedItems(newExpandedItems);
137138
}
138139

139140
public async renameLocalDb(
@@ -184,4 +185,25 @@ export class DbManager {
184185
items,
185186
);
186187
}
188+
189+
private async updateExpandedItems(items: ExpandedDbItem[]): Promise<void> {
190+
let itemsToStore;
191+
192+
const dbItemsResult = this.getDbItems();
193+
194+
if (dbItemsResult.isFailure) {
195+
// Log an error but don't throw an exception since if the db items are failing
196+
// to be read, then there is a bigger problem than the expanded state.
197+
void this.app.logger.log(
198+
`Could not read db items when calculating expanded state: ${JSON.stringify(
199+
dbItemsResult.errors,
200+
)}`,
201+
);
202+
itemsToStore = items;
203+
} else {
204+
itemsToStore = cleanNonExistentExpandedItems(items, dbItemsResult.value);
205+
}
206+
207+
await this.setExpandedItems(itemsToStore);
208+
}
187209
}

extensions/ql-vscode/test/unit-tests/databases/db-item-expansion.test.ts

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,12 @@ import {
33
ExpandedDbItem,
44
ExpandedDbItemKind,
55
replaceExpandedItem,
6+
cleanNonExistentExpandedItems,
67
} from "../../../src/databases/db-item-expansion";
78
import {
9+
createLocalListDbItem,
810
createRemoteUserDefinedListDbItem,
11+
createRootLocalDbItem,
912
createRootRemoteDbItem,
1013
} from "../../factories/db-item-factories";
1114

@@ -157,4 +160,62 @@ describe("db item expansion", () => {
157160
]);
158161
});
159162
});
163+
164+
describe("cleanNonExistentExpandedItems", () => {
165+
it("should remove non-existent items", () => {
166+
const currentExpandedItems: ExpandedDbItem[] = [
167+
{
168+
kind: ExpandedDbItemKind.RootRemote,
169+
},
170+
{
171+
kind: ExpandedDbItemKind.RemoteUserDefinedList,
172+
listName: "list1",
173+
},
174+
{
175+
kind: ExpandedDbItemKind.RemoteUserDefinedList,
176+
listName: "list2",
177+
},
178+
{
179+
kind: ExpandedDbItemKind.LocalUserDefinedList,
180+
listName: "list1",
181+
},
182+
];
183+
184+
const dbItems = [
185+
createRootRemoteDbItem({
186+
children: [
187+
createRemoteUserDefinedListDbItem({
188+
listName: "list2",
189+
}),
190+
],
191+
}),
192+
createRootLocalDbItem({
193+
children: [
194+
createLocalListDbItem({
195+
listName: "list1",
196+
}),
197+
],
198+
}),
199+
];
200+
201+
const newExpandedItems = cleanNonExistentExpandedItems(
202+
currentExpandedItems,
203+
dbItems,
204+
);
205+
206+
expect(newExpandedItems).toEqual([
207+
{
208+
kind: ExpandedDbItemKind.RootRemote,
209+
},
210+
{
211+
kind: ExpandedDbItemKind.RemoteUserDefinedList,
212+
listName: "list2",
213+
},
214+
{
215+
kind: ExpandedDbItemKind.LocalUserDefinedList,
216+
listName: "list1",
217+
},
218+
]);
219+
});
220+
});
160221
});
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
import {
2+
DbItem,
3+
DbItemKind,
4+
flattenDbItems,
5+
} from "../../../src/databases/db-item";
6+
import {
7+
createLocalDatabaseDbItem,
8+
createLocalListDbItem,
9+
createRemoteOwnerDbItem,
10+
createRemoteRepoDbItem,
11+
createRemoteSystemDefinedListDbItem,
12+
createRemoteUserDefinedListDbItem,
13+
createRootLocalDbItem,
14+
createRootRemoteDbItem,
15+
} from "../../factories/db-item-factories";
16+
17+
describe("DbItem", () => {
18+
describe("flattenDbItems", () => {
19+
it("should flatten a list of DbItems", () => {
20+
const dbItems = [
21+
createRootRemoteDbItem({
22+
children: [
23+
createRemoteSystemDefinedListDbItem({ listName: "top10" }),
24+
createRemoteSystemDefinedListDbItem({ listName: "top100" }),
25+
createRemoteUserDefinedListDbItem({
26+
listName: "remote-list1",
27+
repos: [
28+
createRemoteRepoDbItem({ repoFullName: "owner1/repo1" }),
29+
createRemoteRepoDbItem({ repoFullName: "owner1/repo2" }),
30+
],
31+
}),
32+
createRemoteUserDefinedListDbItem({
33+
listName: "remote-list2",
34+
repos: [
35+
createRemoteRepoDbItem({ repoFullName: "owner2/repo1" }),
36+
createRemoteRepoDbItem({ repoFullName: "owner2/repo2" }),
37+
],
38+
}),
39+
createRemoteOwnerDbItem({ ownerName: "owner1" }),
40+
createRemoteRepoDbItem({ repoFullName: "owner3/repo3" }),
41+
],
42+
}),
43+
createRootLocalDbItem({
44+
children: [
45+
createLocalListDbItem({
46+
listName: "local-list1",
47+
databases: [
48+
createLocalDatabaseDbItem({ databaseName: "local-db1" }),
49+
],
50+
}),
51+
createLocalDatabaseDbItem({ databaseName: "local-db2" }),
52+
],
53+
}),
54+
];
55+
56+
const flattenedItems = flattenDbItems(dbItems);
57+
58+
expect(flattenedItems.length).toEqual(15);
59+
checkRootRemoteExists(flattenedItems);
60+
checkSystemDefinedListExists(flattenedItems, "top10");
61+
checkSystemDefinedListExists(flattenedItems, "top100");
62+
checkUserDefinedListExists(flattenedItems, "remote-list1");
63+
checkRemoteRepoExists(flattenedItems, "owner1/repo1");
64+
checkRemoteRepoExists(flattenedItems, "owner1/repo2");
65+
checkRemoteRepoExists(flattenedItems, "owner2/repo1");
66+
checkRemoteRepoExists(flattenedItems, "owner2/repo2");
67+
checkRemoteOwnerExists(flattenedItems, "owner1");
68+
checkRemoteRepoExists(flattenedItems, "owner3/repo3");
69+
checkRootLocalExists(flattenedItems);
70+
checkLocalListExists(flattenedItems, "local-list1");
71+
checkLocalDbExists(flattenedItems, "local-db1");
72+
checkLocalDbExists(flattenedItems, "local-db2");
73+
});
74+
75+
function checkRootRemoteExists(items: DbItem[]): void {
76+
expect(
77+
items.find((item) => item.kind === DbItemKind.RootRemote),
78+
).toBeDefined();
79+
}
80+
81+
function checkUserDefinedListExists(items: DbItem[], name: string): void {
82+
expect(
83+
items.find(
84+
(item) =>
85+
item.kind === DbItemKind.RemoteUserDefinedList &&
86+
item.listName === name,
87+
),
88+
).toBeDefined();
89+
}
90+
91+
function checkSystemDefinedListExists(items: DbItem[], name: string): void {
92+
expect(
93+
items.find(
94+
(item) =>
95+
item.kind === DbItemKind.RemoteSystemDefinedList &&
96+
item.listName === name,
97+
),
98+
).toBeDefined();
99+
}
100+
101+
function checkRemoteOwnerExists(items: DbItem[], name: string): void {
102+
expect(
103+
items.find(
104+
(item) =>
105+
item.kind === DbItemKind.RemoteOwner && item.ownerName === name,
106+
),
107+
).toBeDefined();
108+
}
109+
110+
function checkRemoteRepoExists(items: DbItem[], name: string): void {
111+
expect(
112+
items.find(
113+
(item) =>
114+
item.kind === DbItemKind.RemoteRepo && item.repoFullName === name,
115+
),
116+
).toBeDefined();
117+
}
118+
119+
function checkRootLocalExists(items: DbItem[]): void {
120+
expect(
121+
items.find((item) => item.kind === DbItemKind.RootLocal),
122+
).toBeDefined();
123+
}
124+
125+
function checkLocalListExists(items: DbItem[], name: string): void {
126+
expect(
127+
items.find(
128+
(item) =>
129+
item.kind === DbItemKind.LocalList && item.listName === name,
130+
),
131+
).toBeDefined();
132+
}
133+
134+
function checkLocalDbExists(items: DbItem[], name: string): void {
135+
expect(
136+
items.find(
137+
(item) =>
138+
item.kind === DbItemKind.LocalDatabase &&
139+
item.databaseName === name,
140+
),
141+
).toBeDefined();
142+
}
143+
});
144+
});

0 commit comments

Comments
 (0)