diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/autocomplete/SpringCriteriaCompletionContributorTest.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/autocomplete/SpringCriteriaCompletionContributorTest.kt index b7f3c38b..302f6e64 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/autocomplete/SpringCriteriaCompletionContributorTest.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/autocomplete/SpringCriteriaCompletionContributorTest.kt @@ -392,4 +392,522 @@ class Repository { }, ) } + + @ParsingTest( + fileName = "Repository.java", + value = """ +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.aggregation.Aggregation; +import org.springframework.data.mongodb.core.mapping.Document; +import org.springframework.data.mongodb.core.query.Criteria; + +import java.util.List; + +import static org.springframework.data.mongodb.core.query.Criteria.where; + +@Document +record Book() {} + +class Repository { + private final MongoTemplate template; + + public Repository(MongoTemplate template) { + this.template = template; + } + + public List allReleasedBooks() { + return template.aggregate( + Aggregation.newAggregation( + Aggregation.project("") + ), + Book.class, + Book.class + ).getMappedResults(); + } +} + """, + ) + fun `should autocomplete fields from the current namespace in a Aggregation#project call`( + fixture: CodeInsightTestFixture, + ) { + val (dataSource, readModelProvider) = fixture.setupConnection() + fixture.specifyDatabase("myDatabase") + fixture.specifyDialect(SpringCriteriaDialect) + + val namespace = Namespace("myDatabase", "book") + + `when`( + readModelProvider.slice(eq(dataSource), eq(GetCollectionSchema.Slice(namespace))) + ).thenReturn( + GetCollectionSchema( + CollectionSchema( + namespace, + BsonObject( + mapOf( + "myField" to BsonString, + "myField2" to BsonString, + ), + ), + ), + ), + ) + + val elements = fixture.completeBasic() + + assertTrue( + elements.containsElements { + it.lookupString == "myField" + }, + ) + + assertTrue( + elements.containsElements { + it.lookupString == "myField2" + }, + ) + } + + @ParsingTest( + fileName = "Repository.java", + value = """ +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.aggregation.Aggregation; +import org.springframework.data.mongodb.core.aggregation.Fields;import org.springframework.data.mongodb.core.mapping.Document; +import org.springframework.data.mongodb.core.query.Criteria; + +import java.util.List; + +import static org.springframework.data.mongodb.core.query.Criteria.where; + +@Document +record Book() {} + +class Repository { + private final MongoTemplate template; + + public Repository(MongoTemplate template) { + this.template = template; + } + + public List allReleasedBooks() { + return template.aggregate( + Aggregation.newAggregation( + Aggregation.project(Fields.fields("")) + ), + Book.class, + Book.class + ).getMappedResults(); + } +} + """, + ) + fun `should autocomplete fields from the current namespace in fields helper passed to Aggregation#project call`( + fixture: CodeInsightTestFixture, + ) { + val (dataSource, readModelProvider) = fixture.setupConnection() + fixture.specifyDatabase("myDatabase") + fixture.specifyDialect(SpringCriteriaDialect) + + val namespace = Namespace("myDatabase", "book") + + `when`( + readModelProvider.slice(eq(dataSource), eq(GetCollectionSchema.Slice(namespace))) + ).thenReturn( + GetCollectionSchema( + CollectionSchema( + namespace, + BsonObject( + mapOf( + "myField" to BsonString, + "myField2" to BsonString, + ), + ), + ), + ), + ) + + val elements = fixture.completeBasic() + + assertTrue( + elements.containsElements { + it.lookupString == "myField" + }, + ) + + assertTrue( + elements.containsElements { + it.lookupString == "myField2" + }, + ) + } + + @ParsingTest( + fileName = "Repository.java", + value = """ +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.aggregation.Aggregation; +import org.springframework.data.mongodb.core.aggregation.Fields;import org.springframework.data.mongodb.core.mapping.Document; +import org.springframework.data.mongodb.core.query.Criteria; + +import java.util.List; + +import static org.springframework.data.mongodb.core.query.Criteria.where; + +@Document +record Book() {} + +class Repository { + private final MongoTemplate template; + + public Repository(MongoTemplate template) { + this.template = template; + } + + public List allReleasedBooks() { + return template.aggregate( + Aggregation.newAggregation( + Aggregation.project(Fields.from(Fields.field(""))) + ), + Book.class, + Book.class + ).getMappedResults(); + } +} + """, + ) + fun `should autocomplete fields from the current namespace in field helper passed to Aggregation#project call`( + fixture: CodeInsightTestFixture, + ) { + val (dataSource, readModelProvider) = fixture.setupConnection() + fixture.specifyDatabase("myDatabase") + fixture.specifyDialect(SpringCriteriaDialect) + + val namespace = Namespace("myDatabase", "book") + + `when`( + readModelProvider.slice(eq(dataSource), eq(GetCollectionSchema.Slice(namespace))) + ).thenReturn( + GetCollectionSchema( + CollectionSchema( + namespace, + BsonObject( + mapOf( + "myField" to BsonString, + "myField2" to BsonString, + ), + ), + ), + ), + ) + + val elements = fixture.completeBasic() + + assertTrue( + elements.containsElements { + it.lookupString == "myField" + }, + ) + + assertTrue( + elements.containsElements { + it.lookupString == "myField2" + }, + ) + } + + @ParsingTest( + fileName = "Repository.java", + value = """ +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.aggregation.Aggregation; +import org.springframework.data.mongodb.core.mapping.Document; +import org.springframework.data.mongodb.core.query.Criteria; + +import java.util.List; + +import static org.springframework.data.mongodb.core.query.Criteria.where; + +@Document +record Book() {} + +class Repository { + private final MongoTemplate template; + + public Repository(MongoTemplate template) { + this.template = template; + } + + public List allReleasedBooks() { + return template.aggregate( + Aggregation.newAggregation( + Aggregation.project().andInclude("") + ), + Book.class, + Book.class + ).getMappedResults(); + } +} + """, + ) + fun `should autocomplete fields from the current namespace in andInclude call chained to Aggregation#project call`( + fixture: CodeInsightTestFixture, + ) { + val (dataSource, readModelProvider) = fixture.setupConnection() + fixture.specifyDatabase("myDatabase") + fixture.specifyDialect(SpringCriteriaDialect) + + val namespace = Namespace("myDatabase", "book") + + `when`( + readModelProvider.slice(eq(dataSource), eq(GetCollectionSchema.Slice(namespace))) + ).thenReturn( + GetCollectionSchema( + CollectionSchema( + namespace, + BsonObject( + mapOf( + "myField" to BsonString, + "myField2" to BsonString, + ), + ), + ), + ), + ) + + val elements = fixture.completeBasic() + + assertTrue( + elements.containsElements { + it.lookupString == "myField" + }, + ) + + assertTrue( + elements.containsElements { + it.lookupString == "myField2" + }, + ) + } + + @ParsingTest( + fileName = "Repository.java", + value = """ +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.aggregation.Aggregation; +import org.springframework.data.mongodb.core.aggregation.Fields;import org.springframework.data.mongodb.core.mapping.Document; +import org.springframework.data.mongodb.core.query.Criteria; + +import java.util.List; + +import static org.springframework.data.mongodb.core.query.Criteria.where; + +@Document +record Book() {} + +class Repository { + private final MongoTemplate template; + + public Repository(MongoTemplate template) { + this.template = template; + } + + public List allReleasedBooks() { + return template.aggregate( + Aggregation.newAggregation( + Aggregation.project().andInclude(Fields.fields("")) + ), + Book.class, + Book.class + ).getMappedResults(); + } +} + """, + ) + fun `should autocomplete fields from the current namespace in fields helper passed to andInclude call chained to Aggregation#project call`( + fixture: CodeInsightTestFixture, + ) { + val (dataSource, readModelProvider) = fixture.setupConnection() + fixture.specifyDatabase("myDatabase") + fixture.specifyDialect(SpringCriteriaDialect) + + val namespace = Namespace("myDatabase", "book") + + `when`( + readModelProvider.slice(eq(dataSource), eq(GetCollectionSchema.Slice(namespace))) + ).thenReturn( + GetCollectionSchema( + CollectionSchema( + namespace, + BsonObject( + mapOf( + "myField" to BsonString, + "myField2" to BsonString, + ), + ), + ), + ), + ) + + val elements = fixture.completeBasic() + + assertTrue( + elements.containsElements { + it.lookupString == "myField" + }, + ) + + assertTrue( + elements.containsElements { + it.lookupString == "myField2" + }, + ) + } + + @ParsingTest( + fileName = "Repository.java", + value = """ +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.aggregation.Aggregation; +import org.springframework.data.mongodb.core.aggregation.Fields;import org.springframework.data.mongodb.core.mapping.Document; +import org.springframework.data.mongodb.core.query.Criteria; + +import java.util.List; + +import static org.springframework.data.mongodb.core.query.Criteria.where; + +@Document +record Book() {} + +class Repository { + private final MongoTemplate template; + + public Repository(MongoTemplate template) { + this.template = template; + } + + public List allReleasedBooks() { + return template.aggregate( + Aggregation.newAggregation( + Aggregation.project().andInclude(Fields.from(Fields.field(""))) + ), + Book.class, + Book.class + ).getMappedResults(); + } +} + """, + ) + fun `should autocomplete fields from the current namespace in field helper passed to andInclude call chained to Aggregation#project call`( + fixture: CodeInsightTestFixture, + ) { + val (dataSource, readModelProvider) = fixture.setupConnection() + fixture.specifyDatabase("myDatabase") + fixture.specifyDialect(SpringCriteriaDialect) + + val namespace = Namespace("myDatabase", "book") + + `when`( + readModelProvider.slice(eq(dataSource), eq(GetCollectionSchema.Slice(namespace))) + ).thenReturn( + GetCollectionSchema( + CollectionSchema( + namespace, + BsonObject( + mapOf( + "myField" to BsonString, + "myField2" to BsonString, + ), + ), + ), + ), + ) + + val elements = fixture.completeBasic() + + assertTrue( + elements.containsElements { + it.lookupString == "myField" + }, + ) + + assertTrue( + elements.containsElements { + it.lookupString == "myField2" + }, + ) + } + + @ParsingTest( + fileName = "Repository.java", + value = """ +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.aggregation.Aggregation; +import org.springframework.data.mongodb.core.mapping.Document; +import org.springframework.data.mongodb.core.query.Criteria; + +import java.util.List; + +import static org.springframework.data.mongodb.core.query.Criteria.where; + +@Document +record Book() {} + +class Repository { + private final MongoTemplate template; + + public Repository(MongoTemplate template) { + this.template = template; + } + + public List allReleasedBooks() { + return template.aggregate( + Aggregation.newAggregation( + Aggregation.project().andExclude("") + ), + Book.class, + Book.class + ).getMappedResults(); + } +} + """, + ) + fun `should autocomplete fields from the current namespace in andExclude call chained to Aggregation#project call`( + fixture: CodeInsightTestFixture, + ) { + val (dataSource, readModelProvider) = fixture.setupConnection() + fixture.specifyDatabase("myDatabase") + fixture.specifyDialect(SpringCriteriaDialect) + + val namespace = Namespace("myDatabase", "book") + + `when`( + readModelProvider.slice(eq(dataSource), eq(GetCollectionSchema.Slice(namespace))) + ).thenReturn( + GetCollectionSchema( + CollectionSchema( + namespace, + BsonObject( + mapOf( + "myField" to BsonString, + "myField2" to BsonString, + ), + ), + ), + ), + ) + + val elements = fixture.completeBasic() + + assertTrue( + elements.containsElements { + it.lookupString == "myField" + }, + ) + + assertTrue( + elements.containsElements { + it.lookupString == "myField2" + }, + ) + } } diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/autocomplete/SpringCriteriaMongoDbAutocompletionPopupHandlerTest.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/autocomplete/SpringCriteriaMongoDbAutocompletionPopupHandlerTest.kt index 7e5a9e1f..f03e366e 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/autocomplete/SpringCriteriaMongoDbAutocompletionPopupHandlerTest.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/autocomplete/SpringCriteriaMongoDbAutocompletionPopupHandlerTest.kt @@ -399,4 +399,529 @@ class Repository { }, ) } + + @ParsingTest( + fileName = "Repository.java", + value = """ +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.aggregation.Aggregation; +import org.springframework.data.mongodb.core.mapping.Document; +import org.springframework.data.mongodb.core.query.Criteria; + +import java.util.List; + +import static org.springframework.data.mongodb.core.query.Criteria.where; + +@Document +record Book() {} + +class Repository { + private final MongoTemplate template; + + public Repository(MongoTemplate template) { + this.template = template; + } + + public List allReleasedBooks() { + return template.aggregate( + Aggregation.newAggregation( + Aggregation.project() + ), + Book.class, + Book.class + ).getMappedResults(); + } +} + """, + ) + fun `should autocomplete fields from the current namespace in a Aggregation#project call`( + fixture: CodeInsightTestFixture, + ) { + val (dataSource, readModelProvider) = fixture.setupConnection() + fixture.specifyDatabase("myDatabase") + fixture.specifyDialect(SpringCriteriaDialect) + + val namespace = Namespace("myDatabase", "book") + + `when`( + readModelProvider.slice(eq(dataSource), eq(GetCollectionSchema.Slice(namespace))) + ).thenReturn( + GetCollectionSchema( + CollectionSchema( + namespace, + BsonObject( + mapOf( + "myField" to BsonString, + "myField2" to BsonString, + ), + ), + ), + ), + ) + + fixture.type('"') + val elements = fixture.completeBasic() + + assertTrue( + elements.containsElements { + it.lookupString == "myField" + }, + ) + + assertTrue( + elements.containsElements { + it.lookupString == "myField2" + }, + ) + } + + @ParsingTest( + fileName = "Repository.java", + value = """ +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.aggregation.Aggregation; +import org.springframework.data.mongodb.core.aggregation.Fields;import org.springframework.data.mongodb.core.mapping.Document; +import org.springframework.data.mongodb.core.query.Criteria; + +import java.util.List; + +import static org.springframework.data.mongodb.core.query.Criteria.where; + +@Document +record Book() {} + +class Repository { + private final MongoTemplate template; + + public Repository(MongoTemplate template) { + this.template = template; + } + + public List allReleasedBooks() { + return template.aggregate( + Aggregation.newAggregation( + Aggregation.project(Fields.fields()) + ), + Book.class, + Book.class + ).getMappedResults(); + } +} + """, + ) + fun `should autocomplete fields from the current namespace in fields helper passed to Aggregation#project call`( + fixture: CodeInsightTestFixture, + ) { + val (dataSource, readModelProvider) = fixture.setupConnection() + fixture.specifyDatabase("myDatabase") + fixture.specifyDialect(SpringCriteriaDialect) + + val namespace = Namespace("myDatabase", "book") + + `when`( + readModelProvider.slice(eq(dataSource), eq(GetCollectionSchema.Slice(namespace))) + ).thenReturn( + GetCollectionSchema( + CollectionSchema( + namespace, + BsonObject( + mapOf( + "myField" to BsonString, + "myField2" to BsonString, + ), + ), + ), + ), + ) + + fixture.type('"') + val elements = fixture.completeBasic() + + assertTrue( + elements.containsElements { + it.lookupString == "myField" + }, + ) + + assertTrue( + elements.containsElements { + it.lookupString == "myField2" + }, + ) + } + + @ParsingTest( + fileName = "Repository.java", + value = """ +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.aggregation.Aggregation; +import org.springframework.data.mongodb.core.aggregation.Fields;import org.springframework.data.mongodb.core.mapping.Document; +import org.springframework.data.mongodb.core.query.Criteria; + +import java.util.List; + +import static org.springframework.data.mongodb.core.query.Criteria.where; + +@Document +record Book() {} + +class Repository { + private final MongoTemplate template; + + public Repository(MongoTemplate template) { + this.template = template; + } + + public List allReleasedBooks() { + return template.aggregate( + Aggregation.newAggregation( + Aggregation.project(Fields.from(Fields.field())) + ), + Book.class, + Book.class + ).getMappedResults(); + } +} + """, + ) + fun `should autocomplete fields from the current namespace in field helper passed to Aggregation#project call`( + fixture: CodeInsightTestFixture, + ) { + val (dataSource, readModelProvider) = fixture.setupConnection() + fixture.specifyDatabase("myDatabase") + fixture.specifyDialect(SpringCriteriaDialect) + + val namespace = Namespace("myDatabase", "book") + + `when`( + readModelProvider.slice(eq(dataSource), eq(GetCollectionSchema.Slice(namespace))) + ).thenReturn( + GetCollectionSchema( + CollectionSchema( + namespace, + BsonObject( + mapOf( + "myField" to BsonString, + "myField2" to BsonString, + ), + ), + ), + ), + ) + + fixture.type('"') + val elements = fixture.completeBasic() + + assertTrue( + elements.containsElements { + it.lookupString == "myField" + }, + ) + + assertTrue( + elements.containsElements { + it.lookupString == "myField2" + }, + ) + } + + @ParsingTest( + fileName = "Repository.java", + value = """ +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.aggregation.Aggregation; +import org.springframework.data.mongodb.core.mapping.Document; +import org.springframework.data.mongodb.core.query.Criteria; + +import java.util.List; + +import static org.springframework.data.mongodb.core.query.Criteria.where; + +@Document +record Book() {} + +class Repository { + private final MongoTemplate template; + + public Repository(MongoTemplate template) { + this.template = template; + } + + public List allReleasedBooks() { + return template.aggregate( + Aggregation.newAggregation( + Aggregation.project().andInclude() + ), + Book.class, + Book.class + ).getMappedResults(); + } +} + """, + ) + fun `should autocomplete fields from the current namespace in andInclude call chained to Aggregation#project call`( + fixture: CodeInsightTestFixture, + ) { + val (dataSource, readModelProvider) = fixture.setupConnection() + fixture.specifyDatabase("myDatabase") + fixture.specifyDialect(SpringCriteriaDialect) + + val namespace = Namespace("myDatabase", "book") + + `when`( + readModelProvider.slice(eq(dataSource), eq(GetCollectionSchema.Slice(namespace))) + ).thenReturn( + GetCollectionSchema( + CollectionSchema( + namespace, + BsonObject( + mapOf( + "myField" to BsonString, + "myField2" to BsonString, + ), + ), + ), + ), + ) + + fixture.type('"') + val elements = fixture.completeBasic() + + assertTrue( + elements.containsElements { + it.lookupString == "myField" + }, + ) + + assertTrue( + elements.containsElements { + it.lookupString == "myField2" + }, + ) + } + + @ParsingTest( + fileName = "Repository.java", + value = """ +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.aggregation.Aggregation; +import org.springframework.data.mongodb.core.aggregation.Fields;import org.springframework.data.mongodb.core.mapping.Document; +import org.springframework.data.mongodb.core.query.Criteria; + +import java.util.List; + +import static org.springframework.data.mongodb.core.query.Criteria.where; + +@Document +record Book() {} + +class Repository { + private final MongoTemplate template; + + public Repository(MongoTemplate template) { + this.template = template; + } + + public List allReleasedBooks() { + return template.aggregate( + Aggregation.newAggregation( + Aggregation.project().andInclude(Fields.fields()) + ), + Book.class, + Book.class + ).getMappedResults(); + } +} + """, + ) + fun `should autocomplete fields from the current namespace in fields helper passed to andInclude call chained to Aggregation#project call`( + fixture: CodeInsightTestFixture, + ) { + val (dataSource, readModelProvider) = fixture.setupConnection() + fixture.specifyDatabase("myDatabase") + fixture.specifyDialect(SpringCriteriaDialect) + + val namespace = Namespace("myDatabase", "book") + + `when`( + readModelProvider.slice(eq(dataSource), eq(GetCollectionSchema.Slice(namespace))) + ).thenReturn( + GetCollectionSchema( + CollectionSchema( + namespace, + BsonObject( + mapOf( + "myField" to BsonString, + "myField2" to BsonString, + ), + ), + ), + ), + ) + + fixture.type('"') + val elements = fixture.completeBasic() + + assertTrue( + elements.containsElements { + it.lookupString == "myField" + }, + ) + + assertTrue( + elements.containsElements { + it.lookupString == "myField2" + }, + ) + } + + @ParsingTest( + fileName = "Repository.java", + value = """ +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.aggregation.Aggregation; +import org.springframework.data.mongodb.core.aggregation.Fields;import org.springframework.data.mongodb.core.mapping.Document; +import org.springframework.data.mongodb.core.query.Criteria; + +import java.util.List; + +import static org.springframework.data.mongodb.core.query.Criteria.where; + +@Document +record Book() {} + +class Repository { + private final MongoTemplate template; + + public Repository(MongoTemplate template) { + this.template = template; + } + + public List allReleasedBooks() { + return template.aggregate( + Aggregation.newAggregation( + Aggregation.project().andInclude(Fields.from(Fields.field())) + ), + Book.class, + Book.class + ).getMappedResults(); + } +} + """, + ) + fun `should autocomplete fields from the current namespace in field helper passed to andInclude call chained to Aggregation#project call`( + fixture: CodeInsightTestFixture, + ) { + val (dataSource, readModelProvider) = fixture.setupConnection() + fixture.specifyDatabase("myDatabase") + fixture.specifyDialect(SpringCriteriaDialect) + + val namespace = Namespace("myDatabase", "book") + + `when`( + readModelProvider.slice(eq(dataSource), eq(GetCollectionSchema.Slice(namespace))) + ).thenReturn( + GetCollectionSchema( + CollectionSchema( + namespace, + BsonObject( + mapOf( + "myField" to BsonString, + "myField2" to BsonString, + ), + ), + ), + ), + ) + + fixture.type('"') + val elements = fixture.completeBasic() + + assertTrue( + elements.containsElements { + it.lookupString == "myField" + }, + ) + + assertTrue( + elements.containsElements { + it.lookupString == "myField2" + }, + ) + } + + @ParsingTest( + fileName = "Repository.java", + value = """ +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.aggregation.Aggregation; +import org.springframework.data.mongodb.core.mapping.Document; +import org.springframework.data.mongodb.core.query.Criteria; + +import java.util.List; + +import static org.springframework.data.mongodb.core.query.Criteria.where; + +@Document +record Book() {} + +class Repository { + private final MongoTemplate template; + + public Repository(MongoTemplate template) { + this.template = template; + } + + public List allReleasedBooks() { + return template.aggregate( + Aggregation.newAggregation( + Aggregation.project().andExclude() + ), + Book.class, + Book.class + ).getMappedResults(); + } +} + """, + ) + fun `should autocomplete fields from the current namespace in andExclude call chained to Aggregation#project call`( + fixture: CodeInsightTestFixture, + ) { + val (dataSource, readModelProvider) = fixture.setupConnection() + fixture.specifyDatabase("myDatabase") + fixture.specifyDialect(SpringCriteriaDialect) + + val namespace = Namespace("myDatabase", "book") + + `when`( + readModelProvider.slice(eq(dataSource), eq(GetCollectionSchema.Slice(namespace))) + ).thenReturn( + GetCollectionSchema( + CollectionSchema( + namespace, + BsonObject( + mapOf( + "myField" to BsonString, + "myField2" to BsonString, + ), + ), + ), + ), + ) + + fixture.type('"') + val elements = fixture.completeBasic() + + assertTrue( + elements.containsElements { + it.lookupString == "myField" + }, + ) + + assertTrue( + elements.containsElements { + it.lookupString == "myField2" + }, + ) + } } diff --git a/packages/mongodb-dialects/spring-criteria/src/main/kotlin/com/mongodb/jbplugin/dialects/springcriteria/SpringCriteriaDialectParser.kt b/packages/mongodb-dialects/spring-criteria/src/main/kotlin/com/mongodb/jbplugin/dialects/springcriteria/SpringCriteriaDialectParser.kt index cdf96d11..e5a41b99 100644 --- a/packages/mongodb-dialects/spring-criteria/src/main/kotlin/com/mongodb/jbplugin/dialects/springcriteria/SpringCriteriaDialectParser.kt +++ b/packages/mongodb-dialects/spring-criteria/src/main/kotlin/com/mongodb/jbplugin/dialects/springcriteria/SpringCriteriaDialectParser.kt @@ -12,6 +12,7 @@ import com.mongodb.jbplugin.dialects.springcriteria.QueryTargetCollectionExtract import com.mongodb.jbplugin.dialects.springcriteria.QueryTargetCollectionExtractor.or import com.mongodb.jbplugin.dialects.springcriteria.aggregationstageparsers.MatchStageParser import com.mongodb.jbplugin.dialects.springcriteria.aggregationstageparsers.ProjectStageParser +import com.mongodb.jbplugin.dialects.springcriteria.aggregationstageparsers.StageParser import com.mongodb.jbplugin.mql.BsonAny import com.mongodb.jbplugin.mql.BsonArray import com.mongodb.jbplugin.mql.Node @@ -26,6 +27,11 @@ const val PROJECTION_OPERATION_FQN = "org.springframework.data.mongodb.core.aggr const val FIELDS_FQN = "org.springframework.data.mongodb.core.aggregation.Fields" object SpringCriteriaDialectParser : DialectParser { + private val aggregationStageParsers: List = listOf( + MatchStageParser(::parseFilterRecursively), + ProjectStageParser() + ) + override fun isCandidateForQuery(source: PsiElement) = inferCommandFromMethod((source as? PsiMethodCallExpression)?.fuzzyResolveMethod()).type != IsCommand.CommandType.UNKNOWN @@ -236,10 +242,7 @@ object SpringCriteriaDialectParser : DialectParser { ), HasAggregation( children = AggregationStagesParser( - stageParsers = listOf( - MatchStageParser(::parseFilterRecursively), - ProjectStageParser() - ) + stageParsers = aggregationStageParsers ).parse(mongoOpCall) ) ) @@ -295,7 +298,11 @@ object SpringCriteriaDialectParser : DialectParser { } } - return isString && methodCall.isCriteriaExpression() + return isString && + ( + methodCall.isCriteriaExpression() || + methodCall.isSuitableForFieldAutoCompleteInAggregation(aggregationStageParsers) + ) } private fun isInsideDocAnnotations(source: PsiElement): Boolean { @@ -602,6 +609,13 @@ fun PsiMethodCallExpression.isCriteriaExpression(): Boolean { return method.containingClass?.qualifiedName == CRITERIA_CLASS_FQN } +fun PsiMethodCallExpression.isSuitableForFieldAutoCompleteInAggregation( + parsers: List +): Boolean { + val method = fuzzyResolveMethod() ?: return false + return parsers.any { it.isSuitableForFieldAutoComplete(this, method) } +} + private fun PsiMethodCallExpression.findSpringMongoDbExpression(): PsiMethodCallExpression? { val method = fuzzyResolveMethod() ?: return null if (INTERFACES_WITH_QUERY_METHODS.any { diff --git a/packages/mongodb-dialects/spring-criteria/src/main/kotlin/com/mongodb/jbplugin/dialects/springcriteria/aggregationstageparsers/MatchStageParser.kt b/packages/mongodb-dialects/spring-criteria/src/main/kotlin/com/mongodb/jbplugin/dialects/springcriteria/aggregationstageparsers/MatchStageParser.kt index f81b1e36..86c33366 100644 --- a/packages/mongodb-dialects/spring-criteria/src/main/kotlin/com/mongodb/jbplugin/dialects/springcriteria/aggregationstageparsers/MatchStageParser.kt +++ b/packages/mongodb-dialects/spring-criteria/src/main/kotlin/com/mongodb/jbplugin/dialects/springcriteria/aggregationstageparsers/MatchStageParser.kt @@ -4,6 +4,7 @@ import com.intellij.psi.PsiElement import com.intellij.psi.PsiMethod import com.intellij.psi.PsiMethodCallExpression import com.mongodb.jbplugin.dialects.springcriteria.AGGREGATE_FQN +import com.mongodb.jbplugin.dialects.springcriteria.isCriteriaExpression import com.mongodb.jbplugin.mql.Node import com.mongodb.jbplugin.mql.components.HasFilter import com.mongodb.jbplugin.mql.components.Name @@ -23,6 +24,13 @@ class MatchStageParser( ) ) + override fun isSuitableForFieldAutoComplete( + methodCall: PsiMethodCallExpression, + method: PsiMethod + ): Boolean { + return methodCall.isCriteriaExpression() + } + override fun canParse(stageCallMethod: PsiMethod): Boolean { return stageCallMethod.containingClass?.qualifiedName == AGGREGATE_FQN && stageCallMethod.name == "match" diff --git a/packages/mongodb-dialects/spring-criteria/src/main/kotlin/com/mongodb/jbplugin/dialects/springcriteria/aggregationstageparsers/ProjectStageParser.kt b/packages/mongodb-dialects/spring-criteria/src/main/kotlin/com/mongodb/jbplugin/dialects/springcriteria/aggregationstageparsers/ProjectStageParser.kt index 7d913641..81e56478 100644 --- a/packages/mongodb-dialects/spring-criteria/src/main/kotlin/com/mongodb/jbplugin/dialects/springcriteria/aggregationstageparsers/ProjectStageParser.kt +++ b/packages/mongodb-dialects/spring-criteria/src/main/kotlin/com/mongodb/jbplugin/dialects/springcriteria/aggregationstageparsers/ProjectStageParser.kt @@ -175,6 +175,23 @@ class ProjectStageParser : StageParser { return parseMethodCallWithStringVarArgsAndFields(methodCall, Name.INCLUDE) } + override fun isSuitableForFieldAutoComplete( + methodCall: PsiMethodCallExpression, + method: PsiMethod + ): Boolean { + val methodFqn = method.containingClass?.qualifiedName + // Autocomplete for Aggregation.project("") + return methodFqn == AGGREGATE_FQN && + method.name == "project" || + // Autocomplete for Aggregation.project().andInclude("") + methodFqn == PROJECTION_OPERATION_FQN && + (method.name == "andInclude" || method.name == "andExclude") || + // Autocomplete for Aggregation.project(Fields.fields("")) or, + // Aggregation.project(Fields.from(Fields.field(""))) + methodFqn == FIELDS_FQN && + (method.name == "fields" || method.name == "field") + } + override fun canParse(stageCallMethod: PsiMethod): Boolean { val methodFqn = stageCallMethod.containingClass?.qualifiedName ?: return false // Project stage call might contain chained operations which might result diff --git a/packages/mongodb-dialects/spring-criteria/src/main/kotlin/com/mongodb/jbplugin/dialects/springcriteria/aggregationstageparsers/StageParser.kt b/packages/mongodb-dialects/spring-criteria/src/main/kotlin/com/mongodb/jbplugin/dialects/springcriteria/aggregationstageparsers/StageParser.kt index e0f504cc..b349a31d 100644 --- a/packages/mongodb-dialects/spring-criteria/src/main/kotlin/com/mongodb/jbplugin/dialects/springcriteria/aggregationstageparsers/StageParser.kt +++ b/packages/mongodb-dialects/spring-criteria/src/main/kotlin/com/mongodb/jbplugin/dialects/springcriteria/aggregationstageparsers/StageParser.kt @@ -6,6 +6,10 @@ import com.intellij.psi.PsiMethodCallExpression import com.mongodb.jbplugin.mql.Node interface StageParser { + fun isSuitableForFieldAutoComplete( + methodCall: PsiMethodCallExpression, + method: PsiMethod + ): Boolean fun canParse(stageCallMethod: PsiMethod): Boolean fun parse(stageCall: PsiMethodCallExpression): Node }