Skip to content

Commit 6dfc573

Browse files
feat: system variables and fields completion VSCODE-377, VSCODE-393 (#500)
* feat: system variables and fields completion VSCODE-377, VSCODE-393 * test: wrap aggregation input into array
1 parent d50581b commit 6dfc573

File tree

5 files changed

+96
-32
lines changed

5 files changed

+96
-32
lines changed

package-lock.json

Lines changed: 14 additions & 14 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -968,7 +968,7 @@
968968
"@iconify/react": "^1.1.4",
969969
"@leafygreen-ui/logo": "^6.3.0",
970970
"@leafygreen-ui/toggle": "^7.0.5",
971-
"@mongodb-js/mongodb-constants": "^0.3.0",
971+
"@mongodb-js/mongodb-constants": "^0.4.0",
972972
"@mongosh/browser-runtime-electron": "^1.8.0",
973973
"@mongosh/i18n": "^1.8.0",
974974
"@mongosh/service-provider-server": "^1.8.0",
@@ -1057,7 +1057,7 @@
10571057
"ora": "^5.4.1",
10581058
"postcss-loader": "^3.0.0",
10591059
"pre-commit": "^1.2.2",
1060-
"prettier": "^2.8.6",
1060+
"prettier": "^2.8.7",
10611061
"process": "^0.11.10",
10621062
"semver": "^7.3.8",
10631063
"sinon": "^9.2.4",

src/language/mongoDBService.ts

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -587,7 +587,7 @@ export default class MongoDBService {
587587
/**
588588
* If the current node is 'db.collection.find({ _id: <trigger>});'.
589589
*/
590-
_provideBSONCompletionItems(state: CompletionState) {
590+
_provideIdentifierObjectValueCompletionItems(state: CompletionState) {
591591
if (state.isIdentifierObjectValue) {
592592
this._connection.console.log('VISITOR found bson completions');
593593
return getFilteredCompletions({ meta: ['bson'] }).map((item) => {
@@ -611,24 +611,28 @@ export default class MongoDBService {
611611
}
612612

613613
/**
614-
* If the current node is 'db.collection.find({ $expr: { $gt: [{ $getField: { $literal: '<trigger>' } }, 200] } });'.
614+
* If the current node is 'db.collection.find({ field: "<trigger>" });'.
615615
*/
616-
_provideFieldReferenceCompletionItems(state: CompletionState) {
616+
_provideTextObjectValueCompletionItems(state: CompletionState) {
617617
if (state.isTextObjectValue) {
618618
const fields =
619619
this._fields[`${state.databaseName}.${state.collectionName}`];
620620
this._connection.console.log('VISITOR found field reference completions');
621621

622-
return getFilteredCompletions({ fields, meta: ['field:reference'] }).map(
623-
(item) => {
624-
return {
625-
label: item.value,
626-
kind: CompletionItemKind.Reference,
627-
preselect: true,
628-
detail: item.description,
629-
};
630-
}
631-
);
622+
return getFilteredCompletions({
623+
fields,
624+
meta: ['field:reference', 'variable:*'],
625+
}).map((item) => {
626+
return {
627+
label: item.value,
628+
kind:
629+
item.meta === 'field:reference'
630+
? CompletionItemKind.Reference
631+
: CompletionItemKind.Variable,
632+
preselect: true,
633+
detail: item.description,
634+
};
635+
});
632636
}
633637
}
634638

@@ -750,8 +754,8 @@ export default class MongoDBService {
750754
this._provideStageCompletionItems.bind(this, state),
751755
this._provideQueryOperatorCompletionItems.bind(this, state),
752756
this._provideAggregationOperatorCompletionItems.bind(this, state),
753-
this._provideBSONCompletionItems.bind(this, state),
754-
this._provideFieldReferenceCompletionItems.bind(this, state),
757+
this._provideIdentifierObjectValueCompletionItems.bind(this, state),
758+
this._provideTextObjectValueCompletionItems.bind(this, state),
755759
this._provideCollectionSymbolCompletionItems.bind(this, state),
756760
this._provideFindCursorCompletionItems.bind(this, state),
757761
this._provideAggregationCursorCompletionItems.bind(this, state),

src/language/visitor.ts

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -561,7 +561,9 @@ export class Visitor {
561561
}
562562
}
563563

564-
_checkHasCollectionName(node: babel.types.MemberExpression): void {
564+
_checkHasCollectionNameMemberExpression(
565+
node: babel.types.MemberExpression
566+
): void {
565567
if (
566568
node.object.type === 'MemberExpression' &&
567569
node.object.object.type === 'Identifier' &&
@@ -575,6 +577,26 @@ export class Visitor {
575577
}
576578
}
577579

580+
_checkHasCollectionNameCallExpression(node: babel.types.MemberExpression) {
581+
if (
582+
node.object.type === 'CallExpression' &&
583+
node.object.callee.type === 'MemberExpression' &&
584+
node.object.callee.object.type === 'Identifier' &&
585+
node.object.callee.object.name === 'db' &&
586+
node.object.callee.property.type === 'Identifier' &&
587+
node.object.callee.property.name === 'getCollection' &&
588+
node.object.arguments.length === 1 &&
589+
node.object.arguments[0].type === 'StringLiteral'
590+
) {
591+
this._state.collectionName = node.object.arguments[0].value;
592+
}
593+
}
594+
595+
_checkHasCollectionName(node: babel.types.MemberExpression): void {
596+
this._checkHasCollectionNameMemberExpression(node);
597+
this._checkHasCollectionNameCallExpression(node);
598+
}
599+
578600
_checkIsCollectionMemberExpression(node: babel.types.MemberExpression): void {
579601
if (
580602
node.object.type === 'MemberExpression' &&

src/test/suite/language/mongoDBService.test.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -590,6 +590,30 @@ suite('MongoDBService Test Suite', () => {
590590
expect(completion).to.have.property('detail');
591591
});
592592

593+
test('provide system variable completion in find', async () => {
594+
const result = await testMongoDBService.provideCompletionItems(
595+
'db.collection.find({ _id: "$$N" });',
596+
{ line: 0, character: 30 }
597+
);
598+
const completion = result.find(
599+
(item: CompletionItem) => item.label === '$$NOW'
600+
);
601+
602+
expect(completion).to.have.property('kind', CompletionItemKind.Variable);
603+
});
604+
605+
test('provide system variable completion in aggregate', async () => {
606+
const result = await testMongoDBService.provideCompletionItems(
607+
'db.collection.aggregate([{ $match: { _id: "$$R" }}]);',
608+
{ line: 0, character: 46 }
609+
);
610+
const completion = result.find(
611+
(item: CompletionItem) => item.label === '$$ROOT'
612+
);
613+
614+
expect(completion).to.have.property('kind', CompletionItemKind.Variable);
615+
});
616+
593617
test('provide field reference completion in find when has db', async () => {
594618
testMongoDBService._cacheFields('test.collection', ['price']);
595619

@@ -630,6 +654,20 @@ suite('MongoDBService Test Suite', () => {
630654
expect(completion).to.have.property('kind', CompletionItemKind.Reference);
631655
});
632656

657+
test('provide field reference completion in aggregate when collection is specified via getCollection', async () => {
658+
testMongoDBService._cacheFields('test.collection', ['price']);
659+
660+
const result = await testMongoDBService.provideCompletionItems(
661+
"use('test'); db.getCollection('collection').aggregate([{ $match: '$p' }]);",
662+
{ line: 0, character: 68 }
663+
);
664+
const completion = result.find(
665+
(item: CompletionItem) => item.label === '$price'
666+
);
667+
668+
expect(completion).to.have.property('kind', CompletionItemKind.Reference);
669+
});
670+
633671
test('provide aggregation expression completion for other than $match stages', async () => {
634672
const result = await testMongoDBService.provideCompletionItems(
635673
'db.collection.aggregate([{ $project: { yearMonthDayUTC: { $d } } }]);',

0 commit comments

Comments
 (0)