Skip to content

Commit 5ab24c0

Browse files
Merge pull request #2330 from github/yer-a-sorted-database-query
Select latest database when creating skeleton query
2 parents cf78dbb + 02e1751 commit 5ab24c0

File tree

2 files changed

+193
-99
lines changed

2 files changed

+193
-99
lines changed

extensions/ql-vscode/src/skeleton-query-wizard.ts

Lines changed: 49 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -253,11 +253,19 @@ export class SkeletonQueryWizard {
253253
}
254254

255255
private async selectOrDownloadDatabase() {
256+
if (this.language === undefined) {
257+
throw new Error("Language is undefined");
258+
}
259+
256260
if (this.qlPackStoragePath === undefined) {
257261
throw new Error("QL Pack storage path is undefined");
258262
}
259263

260-
const existingDatabaseItem = await this.findExistingDatabaseItem();
264+
const existingDatabaseItem =
265+
await SkeletonQueryWizard.findExistingDatabaseItem(
266+
this.language,
267+
this.databaseManager.databaseItems,
268+
);
261269

262270
if (existingDatabaseItem) {
263271
// select the found database
@@ -268,59 +276,68 @@ export class SkeletonQueryWizard {
268276
}
269277
}
270278

271-
public async findDatabaseItemByNwo(
279+
public static async findDatabaseItemByNwo(
272280
language: string,
273281
databaseNwo: string,
274282
databaseItems: readonly DatabaseItem[],
275283
): Promise<DatabaseItem | undefined> {
276-
const dbItems = databaseItems || [];
277-
const dbs = dbItems.filter(
278-
(db) =>
279-
db.language === language &&
280-
db.name === databaseNwo &&
281-
db.error === undefined,
284+
const dbs = databaseItems.filter(
285+
(db) => db.language === language && db.name === databaseNwo,
282286
);
283287

284-
if (dbs.length === 0) {
285-
return undefined;
286-
}
287-
return dbs[0];
288+
return dbs.pop();
288289
}
289290

290-
public async findDatabaseItemByLanguage(
291+
public static async findDatabaseItemByLanguage(
291292
language: string,
292293
databaseItems: readonly DatabaseItem[],
293294
): Promise<DatabaseItem | undefined> {
294-
const dbItems = databaseItems || [];
295-
const dbs = dbItems.filter(
296-
(db) => db.language === language && db.error === undefined,
297-
);
298-
if (dbs.length === 0) {
299-
return undefined;
300-
}
301-
return dbs[0];
295+
const dbs = databaseItems.filter((db) => db.language === language);
296+
297+
return dbs.pop();
302298
}
303299

304-
private async findExistingDatabaseItem() {
305-
if (this.language === undefined) {
306-
throw new Error("Language is undefined");
307-
}
300+
public static async findExistingDatabaseItem(
301+
language: string,
302+
databaseItems: readonly DatabaseItem[],
303+
): Promise<DatabaseItem | undefined> {
304+
const defaultDatabaseNwo = QUERY_LANGUAGE_TO_DATABASE_REPO[language];
308305

309-
const defaultDatabaseNwo = QUERY_LANGUAGE_TO_DATABASE_REPO[this.language];
306+
const dbItems = await SkeletonQueryWizard.sortDatabaseItemsByDateAdded(
307+
databaseItems,
308+
);
310309

311-
const defaultDatabaseItem = await this.findDatabaseItemByNwo(
312-
this.language,
310+
const defaultDatabaseItem = await SkeletonQueryWizard.findDatabaseItemByNwo(
311+
language,
313312
defaultDatabaseNwo,
314-
this.databaseManager.databaseItems,
313+
dbItems,
315314
);
316315

317316
if (defaultDatabaseItem !== undefined) {
318317
return defaultDatabaseItem;
319318
}
320319

321-
return await this.findDatabaseItemByLanguage(
322-
this.language,
323-
this.databaseManager.databaseItems,
320+
return await SkeletonQueryWizard.findDatabaseItemByLanguage(
321+
language,
322+
dbItems,
324323
);
325324
}
325+
326+
public static async sortDatabaseItemsByDateAdded(
327+
databaseItems: readonly DatabaseItem[],
328+
) {
329+
const validDbItems = databaseItems.filter((db) => db.error === undefined);
330+
331+
return validDbItems.sort((a, b) => {
332+
if (a.dateAdded === undefined) {
333+
return -1;
334+
}
335+
336+
if (b.dateAdded === undefined) {
337+
return 1;
338+
}
339+
340+
return a.dateAdded - b.dateAdded;
341+
});
342+
}
326343
}

extensions/ql-vscode/test/vscode-tests/cli-integration/skeleton-query-wizard.test.ts

Lines changed: 144 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,7 @@ describe("SkeletonQueryWizard", () => {
320320

321321
jest.spyOn(mockDbItem, "name", "get").mockReturnValue("mock-name");
322322

323-
const databaseItem = await wizard.findDatabaseItemByNwo(
323+
const databaseItem = await SkeletonQueryWizard.findDatabaseItemByNwo(
324324
mockDbItem.language,
325325
mockDbItem.name,
326326
[mockDbItem, mockDbItem2],
@@ -330,45 +330,14 @@ describe("SkeletonQueryWizard", () => {
330330
JSON.stringify(mockDbItem),
331331
);
332332
});
333-
334-
it("should ignore databases with errors", async () => {
335-
const mockDbItem = createMockDB(dir, {
336-
language: "ruby",
337-
dateAdded: 123,
338-
} as FullDatabaseOptions);
339-
const mockDbItem2 = createMockDB(dir, {
340-
language: "javascript",
341-
} as FullDatabaseOptions);
342-
const mockDbItem3 = createMockDB(dir, {
343-
language: "ruby",
344-
dateAdded: 345,
345-
} as FullDatabaseOptions);
346-
347-
jest.spyOn(mockDbItem, "name", "get").mockReturnValue("mock-name");
348-
jest.spyOn(mockDbItem3, "name", "get").mockReturnValue(mockDbItem.name);
349-
350-
jest
351-
.spyOn(mockDbItem, "error", "get")
352-
.mockReturnValue(asError("database go boom!"));
353-
354-
const databaseItem = await wizard.findDatabaseItemByNwo(
355-
mockDbItem.language,
356-
mockDbItem.name,
357-
[mockDbItem, mockDbItem2, mockDbItem3],
358-
);
359-
360-
expect(JSON.stringify(databaseItem)).toEqual(
361-
JSON.stringify(mockDbItem3),
362-
);
363-
});
364333
});
365334

366335
describe("when the item doesn't exist", () => {
367336
it("should return nothing", async () => {
368337
const mockDbItem = createMockDB(dir);
369338
const mockDbItem2 = createMockDB(dir);
370339

371-
const databaseItem = await wizard.findDatabaseItemByNwo(
340+
const databaseItem = await SkeletonQueryWizard.findDatabaseItemByNwo(
372341
"ruby",
373342
"mock-nwo",
374343
[mockDbItem, mockDbItem2],
@@ -389,50 +358,26 @@ describe("SkeletonQueryWizard", () => {
389358
language: "javascript",
390359
} as FullDatabaseOptions);
391360

392-
const databaseItem = await wizard.findDatabaseItemByLanguage("ruby", [
393-
mockDbItem,
394-
mockDbItem2,
395-
]);
361+
const databaseItem =
362+
await SkeletonQueryWizard.findDatabaseItemByLanguage("ruby", [
363+
mockDbItem,
364+
mockDbItem2,
365+
]);
396366

397367
expect(databaseItem).toEqual(mockDbItem);
398368
});
399-
400-
it("should ignore databases with errors", async () => {
401-
const mockDbItem = createMockDB(dir, {
402-
language: "ruby",
403-
} as FullDatabaseOptions);
404-
const mockDbItem2 = createMockDB(dir, {
405-
language: "javascript",
406-
} as FullDatabaseOptions);
407-
const mockDbItem3 = createMockDB(dir, {
408-
language: "ruby",
409-
} as FullDatabaseOptions);
410-
411-
jest
412-
.spyOn(mockDbItem, "error", "get")
413-
.mockReturnValue(asError("database go boom!"));
414-
415-
const databaseItem = await wizard.findDatabaseItemByLanguage("ruby", [
416-
mockDbItem,
417-
mockDbItem2,
418-
mockDbItem3,
419-
]);
420-
421-
expect(JSON.stringify(databaseItem)).toEqual(
422-
JSON.stringify(mockDbItem3),
423-
);
424-
});
425369
});
426370

427371
describe("when the item doesn't exist", () => {
428372
it("should return nothing", async () => {
429373
const mockDbItem = createMockDB(dir);
430374
const mockDbItem2 = createMockDB(dir);
431375

432-
const databaseItem = await wizard.findDatabaseItemByLanguage("ruby", [
433-
mockDbItem,
434-
mockDbItem2,
435-
]);
376+
const databaseItem =
377+
await SkeletonQueryWizard.findDatabaseItemByLanguage("ruby", [
378+
mockDbItem,
379+
mockDbItem2,
380+
]);
436381

437382
expect(databaseItem).toBeUndefined();
438383
});
@@ -550,4 +495,136 @@ describe("SkeletonQueryWizard", () => {
550495
});
551496
});
552497
});
498+
499+
describe("sortDatabaseItemsByDateAdded", () => {
500+
describe("should return a sorted list", () => {
501+
it("should sort the items by dateAdded", async () => {
502+
const mockDbItem = createMockDB(dir, {
503+
dateAdded: 678,
504+
} as FullDatabaseOptions);
505+
const mockDbItem2 = createMockDB(dir, {
506+
dateAdded: 123,
507+
} as FullDatabaseOptions);
508+
const mockDbItem3 = createMockDB(dir, {
509+
dateAdded: undefined,
510+
} as FullDatabaseOptions);
511+
const mockDbItem4 = createMockDB(dir, {
512+
dateAdded: 345,
513+
} as FullDatabaseOptions);
514+
515+
const sortedList =
516+
await SkeletonQueryWizard.sortDatabaseItemsByDateAdded([
517+
mockDbItem,
518+
mockDbItem2,
519+
mockDbItem3,
520+
mockDbItem4,
521+
]);
522+
523+
expect(sortedList).toEqual([
524+
mockDbItem3,
525+
mockDbItem2,
526+
mockDbItem4,
527+
mockDbItem,
528+
]);
529+
});
530+
531+
it("should ignore databases with errors", async () => {
532+
const mockDbItem = createMockDB(dir, {
533+
dateAdded: 678,
534+
} as FullDatabaseOptions);
535+
const mockDbItem2 = createMockDB(dir, {
536+
dateAdded: undefined,
537+
} as FullDatabaseOptions);
538+
const mockDbItem3 = createMockDB(dir, {
539+
dateAdded: 345,
540+
} as FullDatabaseOptions);
541+
const mockDbItem4 = createMockDB(dir, {
542+
dateAdded: 123,
543+
} as FullDatabaseOptions);
544+
545+
jest
546+
.spyOn(mockDbItem, "error", "get")
547+
.mockReturnValue(asError("database go boom!"));
548+
549+
const sortedList =
550+
await SkeletonQueryWizard.sortDatabaseItemsByDateAdded([
551+
mockDbItem,
552+
mockDbItem2,
553+
mockDbItem3,
554+
mockDbItem4,
555+
]);
556+
557+
expect(sortedList).toEqual([mockDbItem2, mockDbItem4, mockDbItem3]);
558+
});
559+
});
560+
});
561+
562+
describe("findExistingDatabaseItem", () => {
563+
describe("when there are multiple items with the same name", () => {
564+
it("should choose the latest one", async () => {
565+
const mockDbItem = createMockDB(dir, {
566+
language: "javascript",
567+
dateAdded: 456,
568+
} as FullDatabaseOptions);
569+
const mockDbItem2 = createMockDB(dir, {
570+
language: "ruby",
571+
dateAdded: 789,
572+
} as FullDatabaseOptions);
573+
const mockDbItem3 = createMockDB(dir, {
574+
language: "javascript",
575+
dateAdded: 123,
576+
} as FullDatabaseOptions);
577+
const mockDbItem4 = createMockDB(dir, {
578+
language: "javascript",
579+
dateAdded: undefined,
580+
} as FullDatabaseOptions);
581+
582+
jest
583+
.spyOn(mockDbItem, "name", "get")
584+
.mockReturnValue(QUERY_LANGUAGE_TO_DATABASE_REPO["javascript"]);
585+
jest
586+
.spyOn(mockDbItem2, "name", "get")
587+
.mockReturnValue(QUERY_LANGUAGE_TO_DATABASE_REPO["javascript"]);
588+
589+
const databaseItem = await SkeletonQueryWizard.findExistingDatabaseItem(
590+
"javascript",
591+
[mockDbItem, mockDbItem2, mockDbItem3, mockDbItem4],
592+
);
593+
594+
expect(JSON.stringify(databaseItem)).toEqual(
595+
JSON.stringify(mockDbItem),
596+
);
597+
});
598+
});
599+
600+
describe("when there are multiple items with the same language", () => {
601+
it("should choose the latest one", async () => {
602+
const mockDbItem = createMockDB(dir, {
603+
language: "ruby",
604+
dateAdded: 789,
605+
} as FullDatabaseOptions);
606+
const mockDbItem2 = createMockDB(dir, {
607+
language: "javascript",
608+
dateAdded: 456,
609+
} as FullDatabaseOptions);
610+
const mockDbItem3 = createMockDB(dir, {
611+
language: "ruby",
612+
dateAdded: 123,
613+
} as FullDatabaseOptions);
614+
const mockDbItem4 = createMockDB(dir, {
615+
language: "javascript",
616+
dateAdded: undefined,
617+
} as FullDatabaseOptions);
618+
619+
const databaseItem = await SkeletonQueryWizard.findExistingDatabaseItem(
620+
"javascript",
621+
[mockDbItem, mockDbItem2, mockDbItem3, mockDbItem4],
622+
);
623+
624+
expect(JSON.stringify(databaseItem)).toEqual(
625+
JSON.stringify(mockDbItem2),
626+
);
627+
});
628+
});
629+
});
553630
});

0 commit comments

Comments
 (0)