Put all reexports of given entry in Suggestion Database (#9454)

close #9351

Changelog:
- update: deprecate the `reexport` suggestion field
- add: `reexports` suggestion field containing the list of modules re-exporting this symbol
- update: exports logic to gather all the symbols exported from a given module
This commit is contained in:
Dmitry Bushev 2024-03-26 16:33:25 +00:00 committed by GitHub
parent 09a6ab7bd6
commit fb0559e7ab
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 326 additions and 354 deletions

View File

@ -500,8 +500,14 @@ interface Module {
/** The documentation string. */
documentation?: string;
/** The fully qualified module name re-exporting this module. */
/** The fully qualified module name re-exporting this module.
*
* @deprecated use reexports field instead
*/
reexport?: string;
/** The list of fully qualified module names re-exporting this module. */
reexports: string[];
}
interface Type {
@ -520,9 +526,15 @@ interface Type {
/** Qualified name of the parent type. */
parentType?: string;
/** The fully qualified module name re-exporting this type. */
/** The fully qualified module name re-exporting this type.
*
* @deprecated use reexports field instead
*/
reexport?: string;
/** The list of fully qualified module names re-exporting this type. */
reexports: string[];
/** The documentation string. */
documentation?: string;
}
@ -543,9 +555,15 @@ interface Constructor {
/** The type of the constructor. */
returnType: string;
/** The fully qualified module name re-exporting this constructor. */
/** The fully qualified module name re-exporting this constructor.
*
* @deprecated use reexports field instead
*/
reexport?: string;
/** The list of fully qualified module names re-exporting this constructor. */
reexports: string[];
/** The documentation string. */
documentation?: string;
@ -575,9 +593,15 @@ interface Method {
/** The flag indicating whether this method is static or instance. */
isStatic: boolean;
/** The fully qualified module name re-exporting this method. */
/** The fully qualified module name re-exporting this method.
*
* @deprecated use reexports field instead
*/
reexport?: string;
/** The list of fully qualified module names re-exporting this method. */
reexports: string[];
/** The documentation string. */
documentation?: string;

View File

@ -33,6 +33,8 @@ object SearchProtocol {
val Documentation = "documentation"
val Reexport = "reexport"
val Reexports = "reexports"
}
private object CodecType {
@ -64,7 +66,12 @@ object SearchProtocol {
case module: Suggestion.Module =>
Encoder[Suggestion.Module]
.apply(module)
.deepMerge(Json.obj(CodecField.Type -> SuggestionType.Module.asJson))
.deepMerge(
Json.obj(
CodecField.Type -> SuggestionType.Module.asJson,
CodecField.Reexport -> module.reexports.headOption.asJson
)
)
case tpe: Suggestion.Type =>
Encoder[Suggestion.Type]
@ -72,7 +79,8 @@ object SearchProtocol {
.deepMerge(
Json.obj(
CodecField.Type -> SuggestionType.Type.asJson,
CodecField.ReturnType -> Json.Null
CodecField.ReturnType -> Json.Null,
CodecField.Reexport -> tpe.reexports.headOption.asJson
)
)
.dropNullValues
@ -81,7 +89,10 @@ object SearchProtocol {
Encoder[Suggestion.Constructor]
.apply(constructor)
.deepMerge(
Json.obj(CodecField.Type -> SuggestionType.Constructor.asJson)
Json.obj(
CodecField.Type -> SuggestionType.Constructor.asJson,
CodecField.Reexport -> constructor.reexports.headOption.asJson
)
)
.dropNullValues
@ -89,7 +100,10 @@ object SearchProtocol {
Encoder[Suggestion.DefinedMethod]
.apply(conversionToMethod(conversion))
.deepMerge(
Json.obj(CodecField.Type -> SuggestionType.Method.asJson)
Json.obj(
CodecField.Type -> SuggestionType.Method.asJson,
CodecField.Reexport -> conversion.reexports.headOption.asJson
)
)
.dropNullValues
@ -97,7 +111,10 @@ object SearchProtocol {
Encoder[Suggestion.DefinedMethod]
.apply(getterToMethod(getter))
.deepMerge(
Json.obj(CodecField.Type -> SuggestionType.Method.asJson)
Json.obj(
CodecField.Type -> SuggestionType.Method.asJson,
CodecField.Reexport -> getter.reexports.headOption.asJson
)
)
.dropNullValues
@ -105,7 +122,10 @@ object SearchProtocol {
Encoder[Suggestion.DefinedMethod]
.apply(method)
.deepMerge(
Json.obj(CodecField.Type -> SuggestionType.Method.asJson)
Json.obj(
CodecField.Type -> SuggestionType.Method.asJson,
CodecField.Reexport -> method.reexports.headOption.asJson
)
)
.dropNullValues
@ -137,7 +157,7 @@ object SearchProtocol {
conversion.isStatic,
conversion.documentation,
conversion.annotations,
conversion.reexport
conversion.reexports
)
private def getterToMethod(
@ -153,7 +173,7 @@ object SearchProtocol {
getter.isStatic,
getter.documentation,
getter.annotations,
getter.reexport
getter.reexports
)
private val suggestionTypeDecoder: Decoder[Suggestion.Type] =
@ -171,7 +191,7 @@ object SearchProtocol {
documentation <- cursor
.downField(CodecField.Documentation)
.as[Option[String]]
reexport <- cursor.downField(CodecField.Reexport).as[Option[String]]
reexports <- cursor.downField(CodecField.Reexports).as[Set[String]]
} yield {
val returnType =
QualifiedName.fromString(module).createChild(name).toString
@ -183,7 +203,7 @@ object SearchProtocol {
returnType,
parentType,
documentation,
reexport
reexports
)
}
}

View File

@ -550,7 +550,7 @@ final class SuggestionsHandler(
for {
actionResults <- suggestionsRepo.applyActions(msg.actions)
treeResults <- suggestionsRepo.applyTree(msg.updates.toVector)
exportResults <- suggestionsRepo.applyExports(msg.exports)
exportResults <- suggestionsRepo.getExportedSymbols(msg.exports)
version <- suggestionsRepo.currentVersion
} yield {
val actionUpdates = actionResults.flatMap {

View File

@ -642,7 +642,7 @@ class SuggestionsHandlerSpec
DeliverToJsonController(
clientId,
SearchProtocol.SuggestionsDatabaseUpdateNotification(
updates1.size.toLong + 1,
updates1.size.toLong,
updates2
)
)
@ -690,7 +690,7 @@ class SuggestionsHandlerSpec
DeliverToJsonController(
clientId,
SearchProtocol.SuggestionsDatabaseUpdateNotification(
updates1.size.toLong + 2,
updates1.size.toLong,
updates3
)
)

View File

@ -65,7 +65,8 @@ class SuggestionsHandlerEventsTest
"tagValues" : null
}
],
"parentType" : "Any"
"parentType" : "Any",
"reexports" : []
}
}
],
@ -117,7 +118,8 @@ class SuggestionsHandlerEventsTest
],
"returnType" : "MyAtom",
"documentation" : " PRIVATE\n\n A key-value store. This type assumes all keys are pairwise comparable,\n using the `<`, `>` and `==` operators.\n\n Arguments:\n - one: The first.\n - two_three: The *second*.\n\n ? Info\n Here is a thing.",
"annotations" : ["a"]
"annotations" : ["a"],
"reexports" : []
}
}
],
@ -161,7 +163,8 @@ class SuggestionsHandlerEventsTest
"selfType" : "MyType",
"returnType" : "Any",
"isStatic" : false,
"annotations" : [ ]
"annotations" : [ ],
"reexports" : [ ]
}
}
],
@ -232,7 +235,8 @@ class SuggestionsHandlerEventsTest
"returnType" : "Number",
"isStatic" : false,
"documentation" : "Lovely",
"annotations" : ["foo"]
"annotations" : ["foo"],
"reexports" : []
}
}
],
@ -578,7 +582,7 @@ class SuggestionsHandlerEventsTest
}
}
],
"currentVersion" : 9
"currentVersion" : 8
}
}
""")
@ -625,7 +629,7 @@ class SuggestionsHandlerEventsTest
"id" : 6
}
],
"currentVersion" : 9
"currentVersion" : 8
}
}
""")

View File

@ -5,6 +5,8 @@ import org.enso.logger.masking.ToLogString
import java.util.UUID
import scala.collection.immutable.ListSet
/** A search suggestion. */
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
@JsonSubTypes(
@ -51,8 +53,7 @@ sealed trait Suggestion extends ToLogString {
def returnType: String
def documentation: Option[String]
/** Set the reexport field of the suggestion. */
def withReexport(reexport: Option[String]): Suggestion
def withReexports(reexports: Set[String]): Suggestion
}
object Suggestion {
@ -223,12 +224,12 @@ object Suggestion {
*
* @param module the fully qualified module name
* @param documentation the documentation string
* @param reexport the module re-exporting this module
* @param reexports modules re-exporting this module
*/
case class Module(
module: String,
documentation: Option[String],
reexport: Option[String] = None
reexports: Set[String] = ListSet()
) extends Suggestion
with ToLogString {
@ -242,14 +243,14 @@ object Suggestion {
module
/** @inheritdoc */
override def withReexport(reexport: Option[String]): Module =
copy(reexport = reexport)
override def withReexports(reexports: Set[String]): Suggestion =
copy(reexports = reexports)
/** @inheritdoc */
override def toLogString(shouldMask: Boolean): String =
s"Module(module=$module,name=$name,documentation=" +
(if (shouldMask) documentation.map(_ => STUB) else documentation) +
s",reexport=$reexport)"
s",reexports=$reexports)"
}
/** A type definition.
@ -261,7 +262,7 @@ object Suggestion {
* @param returnType the type of an atom
* @param parentType qualified name of the parent type
* @param documentation the documentation string
* @param reexport the module re-exporting this atom
* @param reexports modules re-exporting this atom
*/
case class Type(
externalId: Option[ExternalID],
@ -271,13 +272,13 @@ object Suggestion {
returnType: String,
parentType: Option[String],
documentation: Option[String],
reexport: Option[String] = None
reexports: Set[String] = ListSet()
) extends Suggestion
with ToLogString {
/** @inheritdoc */
override def withReexport(reexport: Option[String]): Type =
copy(reexport = reexport)
override def withReexports(reexports: Set[String]): Suggestion =
copy(reexports = reexports)
/** @inheritdoc */
override def toLogString(shouldMask: Boolean): String =
@ -290,7 +291,7 @@ object Suggestion {
s"parentType=$parentType" +
s",documentation=" + (if (shouldMask) documentation.map(_ => STUB)
else documentation) +
s",reexport=$reexport)"
s",reexports=$reexports)"
}
/** A value constructor.
@ -302,7 +303,7 @@ object Suggestion {
* @param returnType the type of an atom
* @param documentation the documentation string
* @param annotations the list of annotations
* @param reexport the module re-exporting this atom
* @param reexports modules re-exporting this atom
*/
case class Constructor(
externalId: Option[ExternalID],
@ -312,13 +313,13 @@ object Suggestion {
returnType: String,
documentation: Option[String],
annotations: Seq[String],
reexport: Option[String] = None
reexports: Set[String] = ListSet()
) extends Suggestion
with ToLogString {
/** @inheritdoc */
override def withReexport(reexport: Option[String]): Constructor =
copy(reexport = reexport)
override def withReexports(reexports: Set[String]): Suggestion =
copy(reexports = reexports)
/** @inheritdoc */
override def toLogString(shouldMask: Boolean): String =
@ -330,7 +331,7 @@ object Suggestion {
s"returnType=$returnType" +
s",documentation=" + (if (shouldMask) documentation.map(_ => STUB)
else documentation) +
s",reexport=$reexport)"
s",reexports=$reexports)"
}
/** Base trait for method suggestions. */
@ -356,7 +357,7 @@ object Suggestion {
def selfType: String
def isStatic: Boolean
def annotations: Seq[String]
def reexport: Option[String]
def reexports: Set[String]
}
/** A method generated to access constructor field.
@ -369,7 +370,7 @@ object Suggestion {
* @param returnType the return type of a method
* @param documentation the documentation string
* @param annotations the list of annotations
* @param reexport the module re-exporting this method
* @param reexports modules re-exporting this method
*/
case class Getter(
externalId: Option[ExternalID],
@ -380,7 +381,7 @@ object Suggestion {
returnType: String,
documentation: Option[String],
annotations: Seq[String],
reexport: Option[String] = None
reexports: Set[String] = ListSet()
) extends Method
with ToLogString {
@ -389,8 +390,8 @@ object Suggestion {
override def isStatic: Boolean = false
/** @inheritdoc */
override def withReexport(reexport: Option[String]): Method =
copy(reexport = reexport)
override def withReexports(reexports: Set[String]): Suggestion =
copy(reexports = reexports)
/** @inheritdoc */
override def toLogString(shouldMask: Boolean): String =
@ -402,7 +403,7 @@ object Suggestion {
s"returnType=$returnType," +
s"documentation=" + (if (shouldMask) documentation.map(_ => STUB)
else documentation) +
s",reexport=$reexport)"
s",reexports=$reexports)"
}
/** A function defined on a type or a module.
@ -416,7 +417,7 @@ object Suggestion {
* @param isStatic the flag indicating whether a method is static or instance
* @param documentation the documentation string
* @param annotations the list of annotations
* @param reexport the module re-exporting this method
* @param reexports modules re-exporting this method
*/
case class DefinedMethod(
externalId: Option[ExternalID],
@ -428,13 +429,13 @@ object Suggestion {
isStatic: Boolean,
documentation: Option[String],
annotations: Seq[String],
reexport: Option[String] = None
reexports: Set[String] = ListSet()
) extends Method
with ToLogString {
/** @inheritdoc */
override def withReexport(reexport: Option[String]): Method =
copy(reexport = reexport)
override def withReexports(reexports: Set[String]): Suggestion =
copy(reexports = reexports)
/** @inheritdoc */
override def toLogString(shouldMask: Boolean): String =
@ -447,7 +448,7 @@ object Suggestion {
s"isStatic=$isStatic," +
s"documentation=" + (if (shouldMask) documentation.map(_ => STUB)
else documentation) +
s",reexport=$reexport)"
s",reexports=$reexports)"
}
/** A conversion function.
@ -458,7 +459,7 @@ object Suggestion {
* @param selfType the source type of a conversion
* @param returnType the return type of a conversion
* @param documentation the documentation string
* @param reexport the module re-exporting this conversion
* @param reexports modules re-exporting this conversion
*/
case class Conversion(
externalId: Option[ExternalID],
@ -467,7 +468,7 @@ object Suggestion {
selfType: String,
returnType: String,
documentation: Option[String],
reexport: Option[String] = None
reexports: Set[String] = ListSet()
) extends Method {
/** @inheritdoc */
@ -478,15 +479,15 @@ object Suggestion {
@JsonIgnore
override def annotations: Seq[String] = Seq()
/** @inheritdoc */
override def withReexport(reexport: Option[String]): Conversion =
copy(reexport = reexport)
/** @inheritdoc */
@JsonIgnore
override def name: String =
Kind.Conversion.From
/** @inheritdoc */
override def withReexports(reexports: Set[String]): Suggestion =
copy(reexports = reexports)
/** @inheritdoc */
override def toLogString(shouldMask: Boolean): String =
"Conversion(" +
@ -496,7 +497,7 @@ object Suggestion {
s"returnType=$returnType," +
s"documentation=" + (if (shouldMask) documentation.map(_ => STUB)
else documentation) +
s",reexport=$reexport)"
s",reexports=$reexports)"
}
/** A local function definition.
@ -521,7 +522,7 @@ object Suggestion {
with ToLogString {
/** @inheritdoc */
override def withReexport(reexport: Option[String]): Function =
override def withReexports(reexports: Set[String]): Suggestion =
this
/** @inheritdoc */
@ -556,7 +557,7 @@ object Suggestion {
) extends Suggestion {
/** @inheritdoc */
override def withReexport(reexport: Option[String]): Local =
override def withReexports(reexports: Set[String]): Suggestion =
this
/** @inheritdoc */

View File

@ -1,12 +1,14 @@
package org.enso.compiler.context;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.SortedSet;
import java.util.TreeSet;
import org.enso.pkg.QualifiedName;
import org.enso.polyglot.ExportedSymbol;
import org.enso.polyglot.ModuleExports;
import org.enso.polyglot.Suggestion;
import scala.Option;
import scala.runtime.BoxedUnit;
public final class ExportsMap {
@ -14,18 +16,27 @@ public final class ExportsMap {
private static final String MODULE_MAIN = "Main";
private static final String TYPE_SUFFIX = "type";
private final Map<ExportedSymbol, QualifiedName> exportsMap;
private static final Comparator<QualifiedName> EXPORTS_COMPARATOR =
Comparator.comparingInt(ExportsMap::length);
private final Map<ExportedSymbol, SortedSet<QualifiedName>> exportsMap;
public ExportsMap() {
this.exportsMap = new HashMap<>();
}
public ExportsMap(Map<ExportedSymbol, QualifiedName> exportsMap) {
public ExportsMap(Map<ExportedSymbol, SortedSet<QualifiedName>> exportsMap) {
this.exportsMap = exportsMap;
}
public void add(ExportedSymbol symbol, QualifiedName moduleName) {
exportsMap.merge(symbol, moduleName, ExportsMap::getShortest);
exportsMap.compute(
symbol,
(k, v) -> {
var set = v == null ? new TreeSet<>(EXPORTS_COMPARATOR) : v;
set.add(moduleName);
return set;
});
}
public void addAll(QualifiedName moduleName, ModuleExports moduleExports) {
@ -38,13 +49,10 @@ public final class ExportsMap {
});
}
public Option<QualifiedName> get(Suggestion suggestion) {
public SortedSet<QualifiedName> get(Suggestion suggestion) {
return ExportedSymbol.fromSuggestion(suggestion)
.flatMap(symbol -> Option.apply(exportsMap.get(symbol)));
}
private static QualifiedName getShortest(QualifiedName name1, QualifiedName name2) {
return length(name1) <= length(name2) ? name1 : name2;
.map(symbol -> exportsMap.getOrDefault(symbol, new TreeSet<>(EXPORTS_COMPARATOR)))
.getOrElse(() -> new TreeSet<>(EXPORTS_COMPARATOR));
}
private static int length(QualifiedName qualifiedName) {

View File

@ -16,7 +16,6 @@ final class ExportsBuilder {
*/
def build(moduleName: QualifiedName, ir: IR): ModuleExports = {
val symbols = getBindings(ir).exportedSymbols.values.flatten
.filter(_.module.getName != moduleName)
.collect {
case BindingsMap.ResolvedMethod(module, method) =>
ExportedSymbol.Method(module.getName.toString, method.name)

View File

@ -13,6 +13,7 @@ import org.enso.editions.LibraryName;
import org.enso.interpreter.runtime.EnsoContext;
import org.enso.interpreter.runtime.util.TruffleFileSystem;
import org.enso.interpreter.test.InterpreterContext;
import org.enso.interpreter.util.ScalaConversions;
import org.enso.pkg.Package;
import org.enso.pkg.PackageManager;
import org.enso.polyglot.LanguageInfo;
@ -112,7 +113,9 @@ public class SerializationManagerTest {
.filter(constructor -> constructor.name().equals("True"))
.findFirst()
.get();
Assert.assertEquals(scala.Some.apply("Standard.Base.Main"), booleanTrueSuggestion.reexport());
Assert.assertEquals(
ScalaConversions.set("Standard.Base.Main", "Standard.Base.Data.Boolean").toList(),
booleanTrueSuggestion.reexports().toList());
Suggestion.Constructor runtimeContextInputSuggestion =
cachedConstructorSuggestions
@ -120,7 +123,8 @@ public class SerializationManagerTest {
.filter(constructor -> constructor.name().equals("Input"))
.findFirst()
.get();
Assert.assertEquals(scala.None$.MODULE$, runtimeContextInputSuggestion.reexport());
Assert.assertEquals(
ScalaConversions.set().toList(), runtimeContextInputSuggestion.reexports().toList());
clearLibraryCache(standardBaseLibrary);
}

View File

@ -7,6 +7,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.module.scala.DefaultScalaModule;
import java.util.List;
import org.enso.interpreter.util.ScalaConversions;
import org.enso.polyglot.Suggestion;
import org.junit.Test;
import scala.Option;
@ -15,7 +16,8 @@ public class JacksonTest {
@Test
public void testSerdeOfSuggestion() throws Exception {
Object shape = new Suggestion.Module("SampleModule", Option.apply("doc"), Option.empty());
Object shape =
new Suggestion.Module("SampleModule", Option.apply("doc"), ScalaConversions.set());
final ObjectMapper m = new ObjectMapper().registerModule(new DefaultScalaModule());
String result = m.writerWithDefaultPrettyPrinter().writeValueAsString(shape);
@ -29,7 +31,7 @@ public class JacksonTest {
public void testArraySerdeOfSuggestion() throws Exception {
Object shape =
new Suggestion[] {
new Suggestion.Module("SampleModule", Option.apply("doc"), Option.empty())
new Suggestion.Module("SampleModule", Option.apply("doc"), ScalaConversions.set())
};
final ObjectMapper m = new ObjectMapper().registerModule(new DefaultScalaModule());
String result = m.writerWithDefaultPrettyPrinter().writeValueAsString(shape);
@ -50,7 +52,9 @@ public class JacksonTest {
Object shape =
new SuggestionCache(
11,
List.of(new Suggestion.Module("SampleModule", Option.apply("doc"), Option.empty())));
List.of(
new Suggestion.Module(
"SampleModule", Option.apply("doc"), ScalaConversions.set())));
final ObjectMapper m = new ObjectMapper().registerModule(new DefaultScalaModule());
String result = m.writerWithDefaultPrettyPrinter().writeValueAsString(shape);

View File

@ -16,6 +16,8 @@ import java.nio.file.{Files, Paths}
import java.util.UUID
import java.util.logging.Level
import scala.collection.immutable.ListSet
@scala.annotation.nowarn("msg=multiarg infix syntax")
class RuntimeSuggestionUpdatesTest
extends AnyFlatSpec
@ -148,7 +150,15 @@ class RuntimeSuggestionUpdatesTest
Api.SuggestionsDatabaseModuleUpdateNotification(
module = moduleName,
actions = Vector(Api.SuggestionsDatabaseAction.Clean(moduleName)),
exports = Vector(),
exports = Vector(
Api.ExportsUpdate(
ModuleExports(
moduleName,
ListSet(ExportedSymbol.Method(moduleName, "main"))
),
Api.ExportsAction.Add()
)
),
updates = Tree.Root(
Vector(
Tree.Node(
@ -472,7 +482,15 @@ class RuntimeSuggestionUpdatesTest
Api.SuggestionsDatabaseModuleUpdateNotification(
module = moduleName,
actions = Vector(),
exports = Vector(),
exports = Vector(
Api.ExportsUpdate(
ModuleExports(
moduleName,
ListSet(ExportedSymbol.Method(moduleName, "foo"))
),
Api.ExportsAction.Add()
)
),
updates = Tree.Root(
Vector(
Tree.Node(
@ -687,7 +705,15 @@ class RuntimeSuggestionUpdatesTest
Api.SuggestionsDatabaseModuleUpdateNotification(
module = moduleName,
actions = Vector(Api.SuggestionsDatabaseAction.Clean(moduleName)),
exports = Vector(),
exports = Vector(
Api.ExportsUpdate(
ModuleExports(
moduleName,
ListSet(ExportedSymbol.Method(moduleName, "main"))
),
Api.ExportsAction.Add()
)
),
updates = Tree.Root(
Vector(
Tree.Node(
@ -745,7 +771,15 @@ class RuntimeSuggestionUpdatesTest
module = "Enso_Test.Foo.Main",
actions =
Vector(Api.SuggestionsDatabaseAction.Clean("Enso_Test.Foo.Main")),
exports = Vector(),
exports = Vector(
Api.ExportsUpdate(
ModuleExports(
"Enso_Test.Foo.Main",
ListSet(ExportedSymbol.Method("Enso_Test.Foo.Main", "main"))
),
Api.ExportsAction.Add()
)
),
updates = Tree.Root(
Vector(
Tree.Node(
@ -844,7 +878,15 @@ class RuntimeSuggestionUpdatesTest
Api.SuggestionsDatabaseModuleUpdateNotification(
module = moduleName,
actions = Vector(Api.SuggestionsDatabaseAction.Clean(moduleName)),
exports = Vector(),
exports = Vector(
Api.ExportsUpdate(
ModuleExports(
moduleName,
ListSet(ExportedSymbol.Method(moduleName, "main"))
),
Api.ExportsAction.Add()
)
),
updates = Tree.Root(
Vector(
Tree.Node(
@ -1026,7 +1068,18 @@ class RuntimeSuggestionUpdatesTest
module = "Enso_Test.Test.A",
actions =
Vector(Api.SuggestionsDatabaseAction.Clean("Enso_Test.Test.A")),
exports = Vector(),
exports = Vector(
Api.ExportsUpdate(
ModuleExports(
"Enso_Test.Test.A",
ListSet(
ExportedSymbol.Type("Enso_Test.Test.A", "MyType"),
ExportedSymbol.Method("Enso_Test.Test.A", "hello")
)
),
Api.ExportsAction.Add()
)
),
updates = Tree.Root(
Vector(
Tree.Node(
@ -1148,9 +1201,10 @@ class RuntimeSuggestionUpdatesTest
Api.ExportsUpdate(
ModuleExports(
"Enso_Test.Test.Main",
Set(
ListSet(
ExportedSymbol.Type("Enso_Test.Test.A", "MyType"),
ExportedSymbol.Constructor("Enso_Test.Test.A", "MkA"),
ExportedSymbol.Method(moduleName, "main"),
ExportedSymbol.Method("Enso_Test.Test.A", "hello")
)
),

View File

@ -2,7 +2,9 @@ package org.enso.interpreter.test.instrument
import org.enso.interpreter.runtime.`type`.ConstantsGen
import org.enso.polyglot.{
ExportedSymbol,
LanguageInfo,
ModuleExports,
RuntimeOptions,
RuntimeServerInfo,
Suggestion
@ -21,6 +23,8 @@ import java.nio.file.{Files, Paths}
import java.util.UUID
import java.util.logging.Level
import scala.collection.immutable.ListSet
@scala.annotation.nowarn("msg=multiarg infix syntax")
class RuntimeTextEditsTest
extends AnyFlatSpec
@ -160,7 +164,15 @@ class RuntimeTextEditsTest
Api.SuggestionsDatabaseModuleUpdateNotification(
module = moduleName,
actions = Vector(Api.SuggestionsDatabaseAction.Clean(moduleName)),
exports = Vector(),
exports = Vector(
Api.ExportsUpdate(
ModuleExports(
moduleName,
ListSet(ExportedSymbol.Method(moduleName, "main"))
),
Api.ExportsAction.Add()
)
),
updates = Tree.Root(
Vector(
Tree.Node(
@ -180,7 +192,7 @@ class RuntimeTextEditsTest
moduleName,
"main",
List(),
"Enso_Test.Test.Main",
moduleName,
ConstantsGen.ANY,
true,
None,

View File

@ -45,6 +45,8 @@ import org.enso.polyglot.CompilationStage;
import org.enso.polyglot.LanguageInfo;
import org.enso.polyglot.Suggestion;
import org.enso.polyglot.data.TypeGraph;
import scala.collection.immutable.ListSet;
import scala.collection.immutable.SetOps;
final class TruffleCompilerContext implements CompilerContext {
@ -557,8 +559,12 @@ final class TruffleCompilerContext implements CompilerContext {
})
.map(
suggestion -> {
var reexport = exportsMap.get(suggestion).map(s -> s.toString());
return suggestion.withReexport(reexport);
scala.collection.immutable.Set<String> identity = new ListSet<>();
var reexports =
exportsMap.get(suggestion).stream()
.map(QualifiedName::toString)
.reduce(identity, SetOps::incl, SetOps::union);
return suggestion.withReexports(reexports);
})
.foreach(suggestions::add);
@ -569,7 +575,7 @@ final class TruffleCompilerContext implements CompilerContext {
context
.getPackageRepository()
.getPackageForLibraryJava(libraryName)
.map(p -> p.listSourcesJava()));
.map(Package::listSourcesJava));
var cache = SuggestionsCache.create(libraryName);
var file = saveCache(cache, cachedSuggestions, useGlobalCacheLocations);
return file != null;

View File

@ -9,6 +9,9 @@ import scala.jdk.javaapi.OptionConverters;
/** Utility class for converting between Scala and Java basic classes. */
public class ScalaConversions {
private ScalaConversions() {}
/**
* Converts a Scala {@link Option} to a Java {@link Optional}.
*
@ -38,4 +41,18 @@ public class ScalaConversions {
T head, scala.collection.immutable.List<T> tail) {
return scala.collection.immutable.$colon$colon$.MODULE$.apply(head, tail);
}
/**
* Create a Scala set from the provided elements.
*
* @param elems the set elements.
* @return the immutable Scala set.
*/
@SafeVarargs
public static <T> scala.collection.immutable.Set<T> set(T... elems) {
var s = new scala.collection.mutable.LinkedHashSet<T>();
for (T elem : elems) s.add(elem);
return s.toSet();
}
}

View File

@ -83,13 +83,13 @@ trait SuggestionsRepo[F[_]] {
actions: Seq[SuggestionsDatabaseAction]
): F[Seq[QueryResult[SuggestionsDatabaseAction]]]
/** Apply the sequence of export updates on the database.
/** Get the suggestions related to the export updates.
*
* @param updates the list of export updates
* @return the result of applying the updates
* @param actions the list of updates
* @return the suggestions ids associated with the export updates
*/
def applyExports(
updates: Seq[ExportsUpdate]
def getExportedSymbols(
actions: Seq[ExportsUpdate]
): F[Seq[QueryResult[ExportsUpdate]]]
/** Remove the suggestion.
@ -119,8 +119,7 @@ trait SuggestionsRepo[F[_]] {
externalId: Option[Option[Suggestion.ExternalID]],
returnType: Option[String],
documentation: Option[Option[String]],
scope: Option[Suggestion.Scope],
reexport: Option[Option[String]]
scope: Option[Suggestion.Scope]
): F[(Long, Option[Long])]
/** Update a list of suggestions by external id.

View File

@ -1,7 +1,7 @@
package org.enso.searcher.sql
import org.enso.polyglot.runtime.Runtime.Api._
import org.enso.polyglot.{ExportedSymbol, Suggestion}
import org.enso.polyglot.Suggestion
import org.enso.searcher.data.QueryResult
import org.enso.searcher.{SuggestionEntry, SuggestionsRepo}
import slick.jdbc.SQLiteProfile.api._
@ -70,10 +70,10 @@ final class SqlSuggestionsRepo(val db: SqlDatabase)(implicit
db.run(applyActionsQuery(actions).transactionally)
/** @inheritdoc */
override def applyExports(
updates: Seq[ExportsUpdate]
def getExportedSymbols(
actions: Seq[ExportsUpdate]
): Future[Seq[QueryResult[ExportsUpdate]]] =
db.run(applyExportsQuery(updates).transactionally)
db.run(getExportedSymbolsQuery(actions).transactionally)
/** @inheritdoc */
override def remove(suggestion: Suggestion): Future[Option[Long]] =
@ -89,8 +89,7 @@ final class SqlSuggestionsRepo(val db: SqlDatabase)(implicit
externalId: Option[Option[Suggestion.ExternalID]],
returnType: Option[String],
documentation: Option[Option[String]],
scope: Option[Suggestion.Scope],
reexport: Option[Option[String]]
scope: Option[Suggestion.Scope]
): Future[(Long, Option[Long])] =
db.run(
updateQuery(
@ -98,8 +97,7 @@ final class SqlSuggestionsRepo(val db: SqlDatabase)(implicit
externalId,
returnType,
documentation,
scope,
reexport
scope
)
)
@ -310,8 +308,7 @@ final class SqlSuggestionsRepo(val db: SqlDatabase)(implicit
extId,
returnType,
doc,
scope,
reexport
scope
)
} else {
DBIO.successful(None)
@ -339,70 +336,49 @@ final class SqlSuggestionsRepo(val db: SqlDatabase)(implicit
DBIO.sequence(removeActions)
}
/** The query that applies the sequence of export updates.
/** The query to get the suggestions related to the export updates.
*
* @param updates the list of export updates
* @return the result of applying actions
* @param actions the list of updates
* @return the suggestions ids associated with the export updates
*/
private def applyExportsQuery(
updates: Seq[ExportsUpdate]
private def getExportedSymbolsQuery(
actions: Seq[ExportsUpdate]
): DBIO[Seq[QueryResult[ExportsUpdate]]] = {
def depth(module: String): Int =
module.count(_ == '.')
def updateSuggestionReexport(module: String, symbol: ExportedSymbol) = {
val moduleDepth = depth(module)
sql"""
update suggestions
set reexport = $module
where module = ${symbol.module}
and name = ${symbol.name}
and kind = ${SuggestionKind(symbol.kind)}
and (
reexport is null or
length(reexport) - length(replace(reexport, '.', '')) > $moduleDepth
)
returning id
""".as[Long]
}
def unsetSuggestionReexport(module: String, symbol: ExportedSymbol) =
sql"""
update suggestions
set reexport = null
where module = ${symbol.module}
and name = ${symbol.name}
and kind = ${SuggestionKind(symbol.kind)}
and reexport = $module
returning id
""".as[Long]
val actions = updates.flatMap { update =>
val symbols = update.exports.symbols.toSeq
update.action match {
case ExportsAction.Add() =>
symbols.map { symbol =>
for {
ids <- updateSuggestionReexport(update.exports.module, symbol)
} yield QueryResult(ids, update)
}
case ExportsAction.Remove() =>
symbols.map { symbol =>
for {
ids <- unsetSuggestionReexport(update.exports.module, symbol)
} yield QueryResult(ids, update)
}
val qs = actions.map { action =>
val actionIdQueries = action.exports.symbols.toSeq.map { symbol =>
selectExportedSymbolQuery(
symbol.module,
symbol.name,
symbol.kind
).result
}
for {
ids <- DBIO.sequence(actionIdQueries)
} yield QueryResult(ids.flatten, action)
}
for {
rs <- DBIO.sequence(actions)
_ <-
if (rs.flatMap(_.ids).nonEmpty) incrementVersionQuery
else DBIO.successful(())
} yield rs
DBIO.sequence(qs)
}
/** The query to select the exported symbol.
*
* @param module the module name of the exported symbol
* @param name the name of the exported symbol
* @param kind the kind of the exported symbol
* @return the database query returning the list of ids corresponding to the
* exported symbol
*/
private def selectExportedSymbolQuery(
module: String,
name: String,
kind: Suggestion.Kind
): Query[Rep[Long], Long, Seq] =
Suggestions
.filter(_.module === module)
.filter(_.kind === SuggestionKind(kind))
.filter(_.name === name)
.take(1)
.map(_.id)
/** The query to select the suggestion.
*
* @param raw the suggestion converted to the row form
@ -503,8 +479,7 @@ final class SqlSuggestionsRepo(val db: SqlDatabase)(implicit
externalId: Option[Option[Suggestion.ExternalID]],
returnType: Option[String],
documentation: Option[Option[String]],
scope: Option[Suggestion.Scope],
reexport: Option[Option[String]]
scope: Option[Suggestion.Scope]
): DBIO[(Long, Option[Long])] =
for {
idOpt <- updateSuggestionQuery(
@ -512,8 +487,7 @@ final class SqlSuggestionsRepo(val db: SqlDatabase)(implicit
externalId,
returnType,
documentation,
scope,
reexport
scope
)
version <- currentVersionQuery
} yield (version, idOpt)
@ -531,8 +505,7 @@ final class SqlSuggestionsRepo(val db: SqlDatabase)(implicit
externalId: Option[Option[Suggestion.ExternalID]],
returnType: Option[String],
documentation: Option[Option[String]],
scope: Option[Suggestion.Scope],
reexport: Option[Option[String]]
scope: Option[Suggestion.Scope]
): DBIO[Option[Long]] = {
val raw = toSuggestionRow(suggestion)
val query = selectSuggestionQuery(raw)
@ -572,12 +545,7 @@ final class SqlSuggestionsRepo(val db: SqlDatabase)(implicit
)
}
}
r5 <- DBIO.sequenceOption {
reexport.map { reexportOpt =>
query.map(_.reexport).update(reexportOpt)
}
}
} yield (r1 ++ r2 ++ r3 ++ r4 ++ r5).sum
} yield (r1 ++ r2 ++ r3 ++ r4).sum
for {
id <- query.map(_.id).result.headOption
n <- updateQ
@ -770,7 +738,7 @@ final class SqlSuggestionsRepo(val db: SqlDatabase)(implicit
/** Convert the suggestion to a row in the suggestions table. */
private def toSuggestionRow(suggestion: Suggestion): SuggestionRow =
suggestion match {
case Suggestion.Module(module, doc, reexport) =>
case Suggestion.Module(module, doc, _) =>
SuggestionRow(
id = None,
externalIdLeast = None,
@ -786,8 +754,7 @@ final class SqlSuggestionsRepo(val db: SqlDatabase)(implicit
scopeStartOffset = ScopeColumn.EMPTY,
scopeEndLine = ScopeColumn.EMPTY,
scopeEndOffset = ScopeColumn.EMPTY,
documentation = doc,
reexport = reexport
documentation = doc
)
case Suggestion.Type(
expr,
@ -797,7 +764,7 @@ final class SqlSuggestionsRepo(val db: SqlDatabase)(implicit
returnType,
parentType,
doc,
reexport
_
) =>
SuggestionRow(
id = None,
@ -814,8 +781,7 @@ final class SqlSuggestionsRepo(val db: SqlDatabase)(implicit
scopeStartLine = ScopeColumn.EMPTY,
scopeStartOffset = ScopeColumn.EMPTY,
scopeEndLine = ScopeColumn.EMPTY,
scopeEndOffset = ScopeColumn.EMPTY,
reexport = reexport
scopeEndOffset = ScopeColumn.EMPTY
)
case Suggestion.Constructor(
expr,
@ -825,7 +791,7 @@ final class SqlSuggestionsRepo(val db: SqlDatabase)(implicit
returnType,
doc,
_,
reexport
_
) =>
SuggestionRow(
id = None,
@ -842,8 +808,7 @@ final class SqlSuggestionsRepo(val db: SqlDatabase)(implicit
scopeStartLine = ScopeColumn.EMPTY,
scopeStartOffset = ScopeColumn.EMPTY,
scopeEndLine = ScopeColumn.EMPTY,
scopeEndOffset = ScopeColumn.EMPTY,
reexport = reexport
scopeEndOffset = ScopeColumn.EMPTY
)
case Suggestion.Getter(
expr,
@ -854,7 +819,7 @@ final class SqlSuggestionsRepo(val db: SqlDatabase)(implicit
returnType,
doc,
_,
reexport
_
) =>
SuggestionRow(
id = None,
@ -871,8 +836,7 @@ final class SqlSuggestionsRepo(val db: SqlDatabase)(implicit
scopeStartLine = ScopeColumn.EMPTY,
scopeStartOffset = ScopeColumn.EMPTY,
scopeEndLine = ScopeColumn.EMPTY,
scopeEndOffset = ScopeColumn.EMPTY,
reexport = reexport
scopeEndOffset = ScopeColumn.EMPTY
)
case Suggestion.DefinedMethod(
expr,
@ -884,7 +848,7 @@ final class SqlSuggestionsRepo(val db: SqlDatabase)(implicit
isStatic,
doc,
_,
reexport
_
) =>
SuggestionRow(
id = None,
@ -901,8 +865,7 @@ final class SqlSuggestionsRepo(val db: SqlDatabase)(implicit
scopeStartLine = ScopeColumn.EMPTY,
scopeStartOffset = ScopeColumn.EMPTY,
scopeEndLine = ScopeColumn.EMPTY,
scopeEndOffset = ScopeColumn.EMPTY,
reexport = reexport
scopeEndOffset = ScopeColumn.EMPTY
)
case Suggestion.Conversion(
expr,
@ -911,7 +874,7 @@ final class SqlSuggestionsRepo(val db: SqlDatabase)(implicit
sourceType,
returnType,
doc,
reexport
_
) =>
SuggestionRow(
id = None,
@ -928,8 +891,7 @@ final class SqlSuggestionsRepo(val db: SqlDatabase)(implicit
scopeStartLine = ScopeColumn.EMPTY,
scopeStartOffset = ScopeColumn.EMPTY,
scopeEndLine = ScopeColumn.EMPTY,
scopeEndOffset = ScopeColumn.EMPTY,
reexport = reexport
scopeEndOffset = ScopeColumn.EMPTY
)
case Suggestion.Function(
expr,
@ -955,8 +917,7 @@ final class SqlSuggestionsRepo(val db: SqlDatabase)(implicit
scopeStartLine = scope.start.line,
scopeStartOffset = scope.start.character,
scopeEndLine = scope.end.line,
scopeEndOffset = scope.end.character,
reexport = None
scopeEndOffset = scope.end.character
)
case Suggestion.Local(expr, module, name, returnType, scope, doc) =>
SuggestionRow(
@ -974,8 +935,7 @@ final class SqlSuggestionsRepo(val db: SqlDatabase)(implicit
scopeStartLine = scope.start.line,
scopeStartOffset = scope.start.character,
scopeEndLine = scope.end.line,
scopeEndOffset = scope.end.character,
reexport = None
scopeEndOffset = scope.end.character
)
}
@ -989,8 +949,7 @@ final class SqlSuggestionsRepo(val db: SqlDatabase)(implicit
case SuggestionKind.MODULE =>
Suggestion.Module(
module = suggestion.module,
documentation = suggestion.documentation,
reexport = suggestion.reexport
documentation = suggestion.documentation
)
case SuggestionKind.TYPE =>
Suggestion.Type(
@ -1001,8 +960,7 @@ final class SqlSuggestionsRepo(val db: SqlDatabase)(implicit
params = Seq(),
returnType = suggestion.returnType,
parentType = suggestion.parentType,
documentation = suggestion.documentation,
reexport = suggestion.reexport
documentation = suggestion.documentation
)
case SuggestionKind.CONSTRUCTOR =>
Suggestion.Constructor(
@ -1013,8 +971,7 @@ final class SqlSuggestionsRepo(val db: SqlDatabase)(implicit
arguments = Seq(),
returnType = suggestion.returnType,
documentation = suggestion.documentation,
annotations = Seq(),
reexport = suggestion.reexport
annotations = Seq()
)
case SuggestionKind.GETTER =>
Suggestion.Getter(
@ -1026,8 +983,7 @@ final class SqlSuggestionsRepo(val db: SqlDatabase)(implicit
selfType = suggestion.selfType,
returnType = suggestion.returnType,
documentation = suggestion.documentation,
annotations = Seq(),
reexport = suggestion.reexport
annotations = Seq()
)
case SuggestionKind.METHOD =>
Suggestion.DefinedMethod(
@ -1040,8 +996,7 @@ final class SqlSuggestionsRepo(val db: SqlDatabase)(implicit
returnType = suggestion.returnType,
isStatic = suggestion.isStatic,
documentation = suggestion.documentation,
annotations = Seq(),
reexport = suggestion.reexport
annotations = Seq()
)
case SuggestionKind.CONVERSION =>
Suggestion.Conversion(
@ -1051,8 +1006,7 @@ final class SqlSuggestionsRepo(val db: SqlDatabase)(implicit
arguments = Seq(),
selfType = suggestion.selfType,
returnType = suggestion.returnType,
documentation = suggestion.documentation,
reexport = suggestion.reexport
documentation = suggestion.documentation
)
case SuggestionKind.FUNCTION =>
Suggestion.Function(

View File

@ -38,8 +38,7 @@ case class SuggestionRow(
scopeStartOffset: Int,
scopeEndLine: Int,
scopeEndOffset: Int,
documentation: Option[String],
reexport: Option[String]
documentation: Option[String]
)
/** A row in the suggestions_version table.
@ -143,7 +142,6 @@ final class SuggestionsTable(tag: Tag)
def scopeEndOffset =
column[Int]("scope_end_offset", O.Default(ScopeColumn.EMPTY))
def documentation = column[Option[String]]("documentation")
def reexport = column[Option[String]]("reexport")
def * =
(
@ -161,8 +159,7 @@ final class SuggestionsTable(tag: Tag)
scopeStartOffset,
scopeEndLine,
scopeEndOffset,
documentation,
reexport
documentation
) <>
(SuggestionRow.tupled, SuggestionRow.unapply)
@ -172,7 +169,7 @@ final class SuggestionsTable(tag: Tag)
def returnTypeIdx = index("suggestions_return_type_idx", returnType)
def externalIdIdx =
index("suggestions_external_id_idx", (externalIdLeast, externalIdMost))
def reexportIdx = index("suggestions_reexport_idx", reexport)
// NOTE: unique index should not contain nullable columns because SQLite
// teats NULLs as distinct values.
def uniqueIdx =
@ -288,5 +285,5 @@ object SuggestionsVersion extends TableQuery(new SuggestionsVersionTable(_))
object SchemaVersion extends TableQuery(new SchemaVersionTable(_)) {
/** The current schema version. */
val CurrentVersion: Long = 11
val CurrentVersion: Long = 12
}

View File

@ -1,7 +1,5 @@
package org.enso.searcher.sql
import java.nio.file.{Files, Path}
import java.util.UUID
import org.enso.polyglot.{ExportedSymbol, ModuleExports, Suggestion}
import org.enso.polyglot.runtime.Runtime.Api
import org.enso.searcher.SuggestionEntry
@ -13,6 +11,9 @@ import org.scalactic.TripleEqualsSupport
import org.scalatest.matchers.should.Matchers
import org.scalatest.wordspec.AnyWordSpec
import java.nio.file.{Files, Path}
import java.util.UUID
import scala.concurrent.Await
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._
@ -69,7 +70,7 @@ class SuggestionsRepoTest
thrown.version shouldEqual wrongSchemaVersion
}
"insert all suggestions111" taggedAs Retry in withRepo { repo =>
"insert all suggestions" taggedAs Retry in withRepo { repo =>
val action =
for {
v1 <- repo.currentVersion
@ -284,7 +285,6 @@ class SuggestionsRepoTest
Some(Some(newUuid)),
None,
None,
None,
None
)
s <- repo.select(id1)
@ -314,7 +314,6 @@ class SuggestionsRepoTest
Some(None),
None,
None,
None,
None
)
s <- repo.select(id1)
@ -344,7 +343,6 @@ class SuggestionsRepoTest
None,
Some(newReturnType),
None,
None,
None
)
s <- repo.select(id1)
@ -374,7 +372,6 @@ class SuggestionsRepoTest
None,
None,
Some(Some(newDoc)),
None,
None
)
s <- repo.select(id1)
@ -407,7 +404,6 @@ class SuggestionsRepoTest
None,
None,
Some(Some(newDoc)),
None,
None
)
s <- repo.select(id1)
@ -440,7 +436,6 @@ class SuggestionsRepoTest
None,
None,
Some(Some(newDoc)),
None,
None
)
s <- repo.select(id1)
@ -471,7 +466,6 @@ class SuggestionsRepoTest
None,
None,
Some(Some(newDoc)),
None,
None
)
s <- repo.select(id1)
@ -504,7 +498,6 @@ class SuggestionsRepoTest
None,
None,
Some(Some(newDoc)),
None,
None
)
s <- repo.select(id1)
@ -536,7 +529,6 @@ class SuggestionsRepoTest
None,
None,
Some(Some(newDoc)),
None,
None
)
s <- repo.select(id1)
@ -568,7 +560,6 @@ class SuggestionsRepoTest
None,
None,
Some(None),
None,
None
)
s <- repo.select(id1)
@ -601,8 +592,7 @@ class SuggestionsRepoTest
None,
None,
None,
Some(newScope),
None
Some(newScope)
)
s <- repo.select(id1)
} yield (v1, id1, v2, id2, s)
@ -630,7 +620,6 @@ class SuggestionsRepoTest
None,
None,
None,
None,
None
)
} yield (v1, v2, id1, id2)
@ -679,9 +668,9 @@ class SuggestionsRepoTest
v1 shouldEqual v2
}
"apply export updates" taggedAs Retry in withRepo { repo =>
"get exported symbols" taggedAs Retry in withRepo { repo =>
val reexport = "Foo.Bar"
val method = suggestion.method.copy(reexport = Some(reexport))
val method = suggestion.method.copy(reexports = Set(reexport))
val updates = Seq(
Api.ExportsUpdate(
ModuleExports(
@ -710,7 +699,7 @@ class SuggestionsRepoTest
suggestion.local
)
)
results <- repo.applyExports(updates)
results <- repo.getExportedSymbols(updates)
} yield (ids, results)
val (ids, results) = Await.result(action, Timeout)
@ -720,126 +709,6 @@ class SuggestionsRepoTest
)
}
"not apply exports with bigger module name" taggedAs Retry in withRepo {
repo =>
val reexport = "Foo.Bar.Baz"
val method = suggestion.method.copy(reexport = Some("Foo.Bar"))
val updates = Seq(
Api.ExportsUpdate(
ModuleExports(
reexport,
Set(ExportedSymbol.Module(suggestion.module.module))
),
Api.ExportsAction.Add()
),
Api.ExportsUpdate(
ModuleExports(
reexport,
Set(ExportedSymbol.Method(method.module, method.name))
),
Api.ExportsAction.Remove()
)
)
val action = for {
(_, ids) <- repo.insertAll(
Seq(
suggestion.module,
suggestion.tpe,
suggestion.constructor,
method,
suggestion.conversion,
suggestion.function,
suggestion.local
)
)
results <- repo.applyExports(updates)
} yield (ids, results)
val (ids, results) = Await.result(action, Timeout)
results should contain theSameElementsAs Seq(
QueryResult(Seq(ids(0)), updates(0)),
QueryResult(Seq(), updates(1))
)
}
"change version after applying exports" taggedAs Retry in withRepo { repo =>
val reexport = "Foo.Bar"
val method = suggestion.method.copy(reexport = Some(reexport))
val updates = Seq(
Api.ExportsUpdate(
ModuleExports(
reexport,
Set(ExportedSymbol.Module(suggestion.module.module))
),
Api.ExportsAction.Add()
),
Api.ExportsUpdate(
ModuleExports(
reexport,
Set(ExportedSymbol.Method(method.module, method.name))
),
Api.ExportsAction.Remove()
)
)
val action = for {
_ <- repo.insertAll(
Seq(
suggestion.module,
suggestion.tpe,
suggestion.constructor,
method,
suggestion.conversion,
suggestion.function,
suggestion.local
)
)
v1 <- repo.currentVersion
results <- repo.applyExports(updates)
v2 <- repo.currentVersion
} yield (results, v1, v2)
val (results, v1, v2) = Await.result(action, Timeout)
results.flatMap(_.ids).isEmpty shouldBe false
v1 should not equal v2
}
"not change version when exports not applied" taggedAs Retry in withRepo {
repo =>
val reexport = "Foo.Bar"
val updates = Seq(
Api.ExportsUpdate(
ModuleExports(
reexport,
Set(
ExportedSymbol
.Method(suggestion.method.module, suggestion.method.name)
)
),
Api.ExportsAction.Remove()
)
)
val action = for {
_ <- repo.insertAll(
Seq(
suggestion.module,
suggestion.tpe,
suggestion.constructor,
suggestion.method,
suggestion.conversion,
suggestion.function,
suggestion.local
)
)
v1 <- repo.currentVersion
results <- repo.applyExports(updates)
v2 <- repo.currentVersion
} yield (results, v1, v2)
val (results, v1, v2) = Await.result(action, Timeout)
results.flatMap(_.ids).isEmpty shouldBe true
v1 shouldEqual v2
}
"search suggestion by empty query" taggedAs Retry in withRepo { repo =>
val action = for {
_ <- repo.insert(suggestion.module)