mirror of
https://github.com/enso-org/enso.git
synced 2024-12-23 10:21:41 +03:00
Update Runtime Notifications API (#1055)
Co-authored-by: Ara Adkins <iamrecursion@users.noreply.github.com>
This commit is contained in:
parent
d72de5f306
commit
467d13a9e7
@ -28,6 +28,8 @@ transport formats, please look [here](./protocol-architecture).
|
||||
- [`SuggestionEntryArgument`](#suggestionentryargument)
|
||||
- [`SuggestionEntry`](#suggestionentry)
|
||||
- [`SuggestionEntryType`](#suggestionentrytype)
|
||||
- [`SuggestionId`](#suggestionid)
|
||||
- [`SuggestionsDatabaseEntry`](#suggestionsdatabaseentry)
|
||||
- [`SuggestionsDatabaseUpdate`](#suggestionsdatabaseupdate)
|
||||
- [`File`](#file)
|
||||
- [`DirectoryTree`](#directorytree)
|
||||
@ -203,8 +205,13 @@ Points to a method definition.
|
||||
|
||||
```typescript
|
||||
interface MethodPointer {
|
||||
file: Path;
|
||||
/** The fully qualified module name. */
|
||||
module: String;
|
||||
|
||||
/** The type on which the method is defined. */
|
||||
definedOnType: String;
|
||||
|
||||
/** The method name. */
|
||||
name: String;
|
||||
}
|
||||
```
|
||||
@ -216,8 +223,11 @@ interface ExpressionValueUpdate {
|
||||
/** The id of updated expression */
|
||||
expressionId: ExpressionId;
|
||||
|
||||
/** The updated suggestion id */
|
||||
suggestionId: number;
|
||||
/** The updated type of the expression */
|
||||
type?: String;
|
||||
|
||||
/** The updated pointer to the method call */
|
||||
methodPointer?: SuggestionId;
|
||||
}
|
||||
```
|
||||
|
||||
@ -335,6 +345,16 @@ The suggestion entry type that is used as a filter in search requests.
|
||||
type SuggestionEntryType = Atom | Method | Function | Local;
|
||||
```
|
||||
|
||||
### `SuggestionId`
|
||||
|
||||
The suggestion entry id of the suggestions database.
|
||||
|
||||
#### Format
|
||||
|
||||
```typescript
|
||||
type SuggestionId = number;
|
||||
```
|
||||
|
||||
### `SuggestionsDatabaseEntry`
|
||||
|
||||
#### Format
|
||||
@ -344,7 +364,7 @@ The entry in the suggestions database.
|
||||
```typescript
|
||||
interface SuggestionsDatabaseEntry {
|
||||
// suggestion entry id
|
||||
id: number;
|
||||
id: SuggestionId;
|
||||
// suggestion entry
|
||||
suggestion: SuggestionEntry;
|
||||
}
|
||||
@ -362,19 +382,19 @@ type SuggestionsDatabaseUpdate = Add | Remove | Modify;
|
||||
|
||||
interface Add {
|
||||
// suggestion entry id
|
||||
id: number;
|
||||
id: SuggestionId;
|
||||
// suggestion entry
|
||||
suggestion: SuggestionEntry;
|
||||
}
|
||||
|
||||
interface Remove {
|
||||
// suggestion entry id
|
||||
id: number;
|
||||
id: SuggestionId;
|
||||
}
|
||||
|
||||
interface Modify {
|
||||
// suggestion entry id
|
||||
id: number;
|
||||
id: SuggestionId;
|
||||
// new return type
|
||||
returnType: String;
|
||||
}
|
||||
|
@ -89,16 +89,41 @@ final class ContextEventsListener(
|
||||
sessionRouter ! DeliverToBinaryController(rpcSession.clientId, payload)
|
||||
|
||||
case RunExpressionUpdates if expressionUpdates.nonEmpty =>
|
||||
val updatedExpressionIds = expressionUpdates.map(_.expressionId)
|
||||
def toMethodPointer(call: Api.MethodPointer): (String, String, String) =
|
||||
(call.module, call.definedOnType, call.name)
|
||||
val methodPointerToExpression = expressionUpdates
|
||||
.flatMap(update =>
|
||||
update.methodCall.map(call =>
|
||||
toMethodPointer(call) -> update.expressionId
|
||||
)
|
||||
)
|
||||
.toMap
|
||||
val methodPointers = methodPointerToExpression.keys.toSeq
|
||||
repo
|
||||
.getAllByExternalIds(updatedExpressionIds)
|
||||
.getAllMethods(methodPointers)
|
||||
.map { suggestionIds =>
|
||||
val valueUpdates = updatedExpressionIds.zip(suggestionIds).flatMap {
|
||||
case (expressionId, Some(suggestionId)) =>
|
||||
Some(ExpressionValueUpdate(expressionId, suggestionId))
|
||||
case (id, None) =>
|
||||
log.error("Unable to find suggestion with expression id: {}", id)
|
||||
None
|
||||
val methodPointerToSuggestion =
|
||||
methodPointers
|
||||
.zip(suggestionIds)
|
||||
.collect {
|
||||
case (ptr, Some(suggestionId)) =>
|
||||
ptr -> suggestionId
|
||||
}
|
||||
.toMap
|
||||
val valueUpdates = expressionUpdates.map { update =>
|
||||
ExpressionValueUpdate(
|
||||
update.expressionId,
|
||||
update.expressionType,
|
||||
update.methodCall.flatMap { call =>
|
||||
val pointer = toMethodPointer(call)
|
||||
methodPointerToSuggestion.get(pointer) match {
|
||||
case suggestionId @ Some(_) => suggestionId
|
||||
case None =>
|
||||
log.error(s"Unable to find suggestion for $pointer")
|
||||
None
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
val payload =
|
||||
ContextRegistryProtocol.ExpressionValuesComputedNotification(
|
||||
|
@ -8,7 +8,6 @@ import org.enso.languageserver.event.{
|
||||
ExecutionContextCreated,
|
||||
ExecutionContextDestroyed
|
||||
}
|
||||
import org.enso.languageserver.filemanager.FileSystemFailure
|
||||
import org.enso.languageserver.monitoring.MonitoringProtocol.{Ping, Pong}
|
||||
import org.enso.languageserver.runtime.handler._
|
||||
import org.enso.languageserver.util.UnhandledLogging
|
||||
@ -134,14 +133,11 @@ final class ContextRegistry(
|
||||
|
||||
case PushContextRequest(client, contextId, stackItem) =>
|
||||
if (store.hasContext(client.clientId, contextId)) {
|
||||
getRuntimeStackItem(stackItem) match {
|
||||
case Right(stackItem) =>
|
||||
val handler =
|
||||
context.actorOf(PushContextHandler.props(timeout, runtime))
|
||||
handler.forward(Api.PushContextRequest(contextId, stackItem))
|
||||
case Left(error) =>
|
||||
sender() ! FileSystemError(error)
|
||||
}
|
||||
val item = getRuntimeStackItem(stackItem)
|
||||
val handler =
|
||||
context.actorOf(PushContextHandler.props(timeout, runtime))
|
||||
handler.forward(Api.PushContextRequest(contextId, item))
|
||||
|
||||
} else {
|
||||
sender() ! AccessDenied
|
||||
}
|
||||
@ -224,27 +220,24 @@ final class ContextRegistry(
|
||||
|
||||
private def getRuntimeStackItem(
|
||||
stackItem: StackItem
|
||||
): Either[FileSystemFailure, Api.StackItem] =
|
||||
): Api.StackItem =
|
||||
stackItem match {
|
||||
case StackItem.ExplicitCall(pointer, argument, arguments) =>
|
||||
getRuntimeMethodPointer(pointer).map { methodPointer =>
|
||||
Api.StackItem.ExplicitCall(methodPointer, argument, arguments)
|
||||
}
|
||||
val methodPointer = getRuntimeMethodPointer(pointer)
|
||||
Api.StackItem.ExplicitCall(methodPointer, argument, arguments)
|
||||
|
||||
case StackItem.LocalCall(expressionId) =>
|
||||
Right(Api.StackItem.LocalCall(expressionId))
|
||||
Api.StackItem.LocalCall(expressionId)
|
||||
}
|
||||
|
||||
private def getRuntimeMethodPointer(
|
||||
pointer: MethodPointer
|
||||
): Either[FileSystemFailure, Api.MethodPointer] =
|
||||
config.findContentRoot(pointer.file.rootId).map { rootPath =>
|
||||
Api.MethodPointer(
|
||||
file = pointer.file.toFile(rootPath),
|
||||
definedOnType = pointer.definedOnType,
|
||||
name = pointer.name
|
||||
)
|
||||
}
|
||||
): Api.MethodPointer =
|
||||
Api.MethodPointer(
|
||||
module = pointer.module,
|
||||
definedOnType = pointer.definedOnType,
|
||||
name = pointer.name
|
||||
)
|
||||
|
||||
private def toRuntimeInvalidatedExpressions(
|
||||
expressions: InvalidatedExpressions
|
||||
|
@ -6,6 +6,11 @@ import org.enso.languageserver.runtime.ExecutionApi.ExpressionId
|
||||
* An update containing information about expression.
|
||||
*
|
||||
* @param expressionId the id of updated expression
|
||||
* @param suggestionId the updated suggestion id
|
||||
* @param `type` the updated type of expression
|
||||
* @param methodPointer the suggestion id of the updated method pointer
|
||||
*/
|
||||
case class ExpressionValueUpdate(expressionId: ExpressionId, suggestionId: Long)
|
||||
case class ExpressionValueUpdate(
|
||||
expressionId: ExpressionId,
|
||||
`type`: Option[String],
|
||||
methodPointer: Option[Long]
|
||||
)
|
||||
|
@ -1,12 +1,10 @@
|
||||
package org.enso.languageserver.runtime
|
||||
|
||||
import org.enso.languageserver.filemanager.Path
|
||||
|
||||
/**
|
||||
* An object pointing to a method definition.
|
||||
*
|
||||
* @param file path to the method file
|
||||
* @param module the module of the method file
|
||||
* @param definedOnType method type
|
||||
* @param name method name
|
||||
*/
|
||||
case class MethodPointer(file: Path, definedOnType: String, name: String)
|
||||
case class MethodPointer(module: String, definedOnType: String, name: String)
|
||||
|
@ -74,8 +74,14 @@ class ContextEventsListenerSpec
|
||||
Vector(
|
||||
Api.ExpressionValueUpdate(
|
||||
Suggestions.method.externalId.get,
|
||||
None,
|
||||
None
|
||||
Some(Suggestions.method.returnType),
|
||||
Some(
|
||||
Api.MethodPointer(
|
||||
Suggestions.method.module,
|
||||
Suggestions.method.selfType,
|
||||
Suggestions.method.name
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
@ -88,7 +94,8 @@ class ContextEventsListenerSpec
|
||||
Vector(
|
||||
ExpressionValueUpdate(
|
||||
Suggestions.method.externalId.get,
|
||||
suggestionIds(1).get
|
||||
Some(Suggestions.method.returnType),
|
||||
Some(suggestionIds(1).get)
|
||||
)
|
||||
)
|
||||
)
|
||||
@ -98,7 +105,7 @@ class ContextEventsListenerSpec
|
||||
|
||||
"send expression updates grouped" taggedAs Retry in withDb(0.seconds) {
|
||||
(clientId, contextId, repo, router, listener) =>
|
||||
val (_, suggestionIds) = Await.result(
|
||||
Await.result(
|
||||
repo.insertAll(
|
||||
Seq(
|
||||
Suggestions.atom,
|
||||
@ -142,11 +149,13 @@ class ContextEventsListenerSpec
|
||||
Vector(
|
||||
ExpressionValueUpdate(
|
||||
Suggestions.method.externalId.get,
|
||||
suggestionIds(1).get
|
||||
None,
|
||||
None
|
||||
),
|
||||
ExpressionValueUpdate(
|
||||
Suggestions.local.externalId.get,
|
||||
suggestionIds(3).get
|
||||
None,
|
||||
None
|
||||
)
|
||||
)
|
||||
)
|
||||
|
@ -198,7 +198,11 @@ object Runtime {
|
||||
/**
|
||||
* A representation of a pointer to a method definition.
|
||||
*/
|
||||
case class MethodPointer(file: File, definedOnType: String, name: String)
|
||||
case class MethodPointer(
|
||||
module: String,
|
||||
definedOnType: String,
|
||||
name: String
|
||||
)
|
||||
|
||||
/**
|
||||
* A representation of an executable position in code.
|
||||
|
@ -119,7 +119,7 @@ public class ExecutionService {
|
||||
* Executes a method described by its name, constructor it's defined on and the module it's
|
||||
* defined in.
|
||||
*
|
||||
* @param modulePath the path to the module where the method is defined.
|
||||
* @param moduleName the module where the method is defined.
|
||||
* @param consName the name of the constructor the method is defined on.
|
||||
* @param methodName the method name.
|
||||
* @param cache the precomputed expression values.
|
||||
@ -129,7 +129,7 @@ public class ExecutionService {
|
||||
* @param funCallCallback the consumer for function call events.
|
||||
*/
|
||||
public void execute(
|
||||
File modulePath,
|
||||
String moduleName,
|
||||
String consName,
|
||||
String methodName,
|
||||
RuntimeCache cache,
|
||||
@ -140,7 +140,7 @@ public class ExecutionService {
|
||||
throws UnsupportedMessageException, ArityException, UnsupportedTypeException {
|
||||
Optional<FunctionCallInstrumentationNode.FunctionCall> callMay =
|
||||
context
|
||||
.getModuleForFile(modulePath)
|
||||
.findModule(moduleName)
|
||||
.flatMap(module -> prepareFunctionCall(module, consName, methodName));
|
||||
if (!callMay.isPresent()) {
|
||||
return;
|
||||
|
@ -21,7 +21,7 @@ import scala.jdk.OptionConverters._
|
||||
*
|
||||
* @param files a files to compile
|
||||
*/
|
||||
class EnsureCompiledJob(protected val files: List[File])
|
||||
class EnsureCompiledJob(protected val files: Iterable[File])
|
||||
extends Job[Unit](List.empty, true, false) {
|
||||
|
||||
/**
|
||||
|
@ -14,8 +14,9 @@ import scala.jdk.OptionConverters._
|
||||
*
|
||||
* @param stack a call stack
|
||||
*/
|
||||
class EnsureCompiledStackJob(stack: Iterable[InstrumentFrame])
|
||||
extends EnsureCompiledJob(EnsureCompiledStackJob.extractFiles(stack)) {
|
||||
class EnsureCompiledStackJob(stack: Iterable[InstrumentFrame])(implicit
|
||||
ctx: RuntimeContext
|
||||
) extends EnsureCompiledJob(EnsureCompiledStackJob.extractFiles(stack)) {
|
||||
|
||||
/** @inheritdoc */
|
||||
override def ensureCompiled(
|
||||
@ -38,7 +39,7 @@ class EnsureCompiledStackJob(stack: Iterable[InstrumentFrame])
|
||||
)(implicit ctx: RuntimeContext): Option[CachePreferenceAnalysis.Metadata] =
|
||||
stack.lastOption flatMap {
|
||||
case InstrumentFrame(Api.StackItem.ExplicitCall(ptr, _, _), _) =>
|
||||
ctx.executionService.getContext.getModuleForFile(ptr.file).toScala.map {
|
||||
ctx.executionService.getContext.findModule(ptr.module).toScala.map {
|
||||
module =>
|
||||
module.getIr
|
||||
.unsafeGetMetadata(
|
||||
@ -58,12 +59,19 @@ object EnsureCompiledStackJob {
|
||||
* @param stack a call stack
|
||||
* @return a list of files to compile
|
||||
*/
|
||||
private def extractFiles(stack: Iterable[InstrumentFrame]): List[File] =
|
||||
private def extractFiles(stack: Iterable[InstrumentFrame])(implicit
|
||||
ctx: RuntimeContext
|
||||
): Iterable[File] =
|
||||
stack
|
||||
.map(_.item)
|
||||
.collect {
|
||||
.flatMap {
|
||||
case Api.StackItem.ExplicitCall(methodPointer, _, _) =>
|
||||
methodPointer.file
|
||||
ctx.executionService.getContext
|
||||
.findModule(methodPointer.module)
|
||||
.flatMap(module => java.util.Optional.ofNullable(module.getPath))
|
||||
.map(path => new File(path))
|
||||
.toScala
|
||||
case _ =>
|
||||
None
|
||||
}
|
||||
.toList
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
package org.enso.interpreter.instrument.job
|
||||
|
||||
import java.io.File
|
||||
import java.util.{Objects, UUID}
|
||||
import java.util.function.Consumer
|
||||
import java.util.logging.Level
|
||||
@ -25,8 +24,6 @@ import org.enso.interpreter.node.callable.FunctionCallInstrumentationNode.Functi
|
||||
import org.enso.polyglot.runtime.Runtime.Api
|
||||
import org.enso.polyglot.runtime.Runtime.Api.ContextId
|
||||
|
||||
import scala.jdk.javaapi.OptionConverters
|
||||
|
||||
/**
|
||||
* Provides support for executing Enso code. Adds convenient methods to
|
||||
* run Enso programs in a Truffle context.
|
||||
@ -56,9 +53,12 @@ trait ProgramExecutionSupport {
|
||||
enterables += fun.getExpressionId -> fun.getCall
|
||||
}
|
||||
executionFrame match {
|
||||
case ExecutionFrame(ExecutionItem.Method(file, cons, function), cache) =>
|
||||
case ExecutionFrame(
|
||||
ExecutionItem.Method(module, cons, function),
|
||||
cache
|
||||
) =>
|
||||
ctx.executionService.execute(
|
||||
file,
|
||||
module,
|
||||
cons,
|
||||
function,
|
||||
cache,
|
||||
@ -250,21 +250,15 @@ trait ProgramExecutionSupport {
|
||||
|
||||
private def toMethodPointer(
|
||||
value: ExpressionValue
|
||||
)(implicit ctx: RuntimeContext): Option[Api.MethodPointer] =
|
||||
): Option[Api.MethodPointer] =
|
||||
for {
|
||||
call <- Option(value.getCallInfo)
|
||||
moduleName <- Option(call.getModuleName)
|
||||
functionName = call.getFunctionName
|
||||
typeName <- Option(call.getTypeName).map(_.item)
|
||||
module <- OptionConverters.toScala(
|
||||
ctx.executionService.getContext.getTopScope
|
||||
.getModule(moduleName.toString)
|
||||
)
|
||||
modulePath <- Option(module.getPath)
|
||||
typeName <- Option(call.getTypeName).map(_.item)
|
||||
} yield Api.MethodPointer(
|
||||
new File(modulePath),
|
||||
moduleName.toString,
|
||||
typeName,
|
||||
functionName
|
||||
call.getFunctionName
|
||||
)
|
||||
}
|
||||
|
||||
@ -296,11 +290,11 @@ object ProgramExecutionSupport {
|
||||
|
||||
/** The explicit method call.
|
||||
*
|
||||
* @param file the file containing the method
|
||||
* @param module the module containing the method
|
||||
* @param constructor the type on which the method is defined
|
||||
* @param function the method name
|
||||
*/
|
||||
case class Method(file: File, constructor: String, function: String)
|
||||
case class Method(module: String, constructor: String, function: String)
|
||||
extends ExecutionItem
|
||||
|
||||
object Method {
|
||||
@ -312,7 +306,7 @@ object ProgramExecutionSupport {
|
||||
*/
|
||||
def apply(call: Api.StackItem.ExplicitCall): Method =
|
||||
Method(
|
||||
call.methodPointer.file,
|
||||
call.methodPointer.module,
|
||||
call.methodPointer.definedOnType,
|
||||
call.methodPointer.name
|
||||
)
|
||||
|
@ -144,7 +144,7 @@ class RuntimeServerTest
|
||||
Api.ExpressionValueUpdate(
|
||||
Main.idMainY,
|
||||
Some("Number"),
|
||||
Some(Api.MethodPointer(pkg.mainFile, "Number", "foo"))
|
||||
Some(Api.MethodPointer("Test.Main", "Number", "foo"))
|
||||
)
|
||||
)
|
||||
)
|
||||
@ -228,7 +228,7 @@ class RuntimeServerTest
|
||||
Api.ExpressionValueUpdate(
|
||||
idMainY,
|
||||
Some("Number"),
|
||||
Some(Api.MethodPointer(pkg.mainFile, "Main", "foo"))
|
||||
Some(Api.MethodPointer("Test.Main", "Main", "foo"))
|
||||
)
|
||||
)
|
||||
)
|
||||
@ -242,7 +242,7 @@ class RuntimeServerTest
|
||||
Api.ExpressionValueUpdate(
|
||||
idMainZ,
|
||||
Some("Number"),
|
||||
Some(Api.MethodPointer(pkg.mainFile, "Main", "bar"))
|
||||
Some(Api.MethodPointer("Test.Main", "Main", "bar"))
|
||||
)
|
||||
)
|
||||
)
|
||||
@ -284,7 +284,7 @@ class RuntimeServerTest
|
||||
}
|
||||
|
||||
"RuntimeServer" should "push and pop functions on the stack" in {
|
||||
val mainFile = context.writeMain(context.Main.code)
|
||||
context.writeMain(context.Main.code)
|
||||
val contextId = UUID.randomUUID()
|
||||
val requestId = UUID.randomUUID()
|
||||
|
||||
@ -306,7 +306,7 @@ class RuntimeServerTest
|
||||
|
||||
// push main
|
||||
val item1 = Api.StackItem.ExplicitCall(
|
||||
Api.MethodPointer(mainFile, "Main", "main"),
|
||||
Api.MethodPointer("Test.Main", "Main", "main"),
|
||||
None,
|
||||
Vector()
|
||||
)
|
||||
@ -333,7 +333,7 @@ class RuntimeServerTest
|
||||
|
||||
// push method pointer on top of the non-empty stack
|
||||
val invalidExplicitCall = Api.StackItem.ExplicitCall(
|
||||
Api.MethodPointer(mainFile, "Main", "main"),
|
||||
Api.MethodPointer("Test.Main", "Main", "main"),
|
||||
None,
|
||||
Vector()
|
||||
)
|
||||
@ -402,7 +402,7 @@ class RuntimeServerTest
|
||||
Api.PushContextRequest(
|
||||
contextId,
|
||||
Api.StackItem.ExplicitCall(
|
||||
Api.MethodPointer(mainFile, "Main", "main"),
|
||||
Api.MethodPointer(moduleName, "Main", "main"),
|
||||
None,
|
||||
Vector()
|
||||
)
|
||||
@ -521,7 +521,7 @@ class RuntimeServerTest
|
||||
Api.PushContextRequest(
|
||||
contextId,
|
||||
Api.StackItem.ExplicitCall(
|
||||
Api.MethodPointer(mainFile, "Main", "main"),
|
||||
Api.MethodPointer(moduleName, "Main", "main"),
|
||||
None,
|
||||
Vector()
|
||||
)
|
||||
@ -689,7 +689,7 @@ class RuntimeServerTest
|
||||
Api.PushContextRequest(
|
||||
contextId,
|
||||
Api.StackItem.ExplicitCall(
|
||||
Api.MethodPointer(mainFile, "Main", "main"),
|
||||
Api.MethodPointer(moduleName, "Main", "main"),
|
||||
None,
|
||||
Vector()
|
||||
)
|
||||
@ -818,7 +818,7 @@ class RuntimeServerTest
|
||||
Api.ExpressionValueUpdate(
|
||||
idMainA,
|
||||
Some("Number"),
|
||||
Some(Api.MethodPointer(mainFile, "Number", "x"))
|
||||
Some(Api.MethodPointer(moduleName, "Number", "x"))
|
||||
)
|
||||
)
|
||||
)
|
||||
@ -865,7 +865,7 @@ class RuntimeServerTest
|
||||
Api.ExpressionValueUpdate(
|
||||
idMainA,
|
||||
Some("Number"),
|
||||
Some(Api.MethodPointer(mainFile, "Main", "pie"))
|
||||
Some(Api.MethodPointer(moduleName, "Main", "pie"))
|
||||
)
|
||||
)
|
||||
)
|
||||
@ -895,7 +895,7 @@ class RuntimeServerTest
|
||||
Api.ExpressionValueUpdate(
|
||||
idMainA,
|
||||
Some("Number"),
|
||||
Some(Api.MethodPointer(mainFile, "Main", "uwu"))
|
||||
Some(Api.MethodPointer(moduleName, "Main", "uwu"))
|
||||
)
|
||||
)
|
||||
)
|
||||
@ -925,7 +925,7 @@ class RuntimeServerTest
|
||||
Api.ExpressionValueUpdate(
|
||||
idMainA,
|
||||
Some("Text"),
|
||||
Some(Api.MethodPointer(mainFile, "Main", "hie"))
|
||||
Some(Api.MethodPointer(moduleName, "Main", "hie"))
|
||||
)
|
||||
)
|
||||
)
|
||||
@ -992,7 +992,7 @@ class RuntimeServerTest
|
||||
contextId,
|
||||
Api.StackItem
|
||||
.ExplicitCall(
|
||||
Api.MethodPointer(fooFile, "Foo", "main"),
|
||||
Api.MethodPointer("Test.Foo", "Foo", "main"),
|
||||
None,
|
||||
Vector()
|
||||
)
|
||||
@ -1080,7 +1080,7 @@ class RuntimeServerTest
|
||||
contextId,
|
||||
Api.StackItem
|
||||
.ExplicitCall(
|
||||
Api.MethodPointer(fooFile, "Foo", "main"),
|
||||
Api.MethodPointer("Test.Foo", "Foo", "main"),
|
||||
None,
|
||||
Vector()
|
||||
)
|
||||
@ -1168,7 +1168,7 @@ class RuntimeServerTest
|
||||
|
||||
// push main
|
||||
val item1 = Api.StackItem.ExplicitCall(
|
||||
Api.MethodPointer(mainFile, "Main", "main"),
|
||||
Api.MethodPointer("Test.Main", "Main", "main"),
|
||||
None,
|
||||
Vector()
|
||||
)
|
||||
@ -1329,7 +1329,7 @@ class RuntimeServerTest
|
||||
contextId,
|
||||
Api.StackItem
|
||||
.ExplicitCall(
|
||||
Api.MethodPointer(fooFile, "Foo", "main"),
|
||||
Api.MethodPointer("Test.Foo", "Foo", "main"),
|
||||
None,
|
||||
Vector()
|
||||
)
|
||||
@ -1405,7 +1405,7 @@ class RuntimeServerTest
|
||||
}
|
||||
|
||||
it should "recompute expressions without invalidation" in {
|
||||
val mainFile = context.writeMain(context.Main.code)
|
||||
context.writeMain(context.Main.code)
|
||||
val contextId = UUID.randomUUID()
|
||||
val requestId = UUID.randomUUID()
|
||||
|
||||
@ -1417,7 +1417,7 @@ class RuntimeServerTest
|
||||
|
||||
// push main
|
||||
val item1 = Api.StackItem.ExplicitCall(
|
||||
Api.MethodPointer(mainFile, "Main", "main"),
|
||||
Api.MethodPointer("Test.Main", "Main", "main"),
|
||||
None,
|
||||
Vector()
|
||||
)
|
||||
@ -1441,7 +1441,7 @@ class RuntimeServerTest
|
||||
}
|
||||
|
||||
it should "recompute expressions invalidating all" in {
|
||||
val mainFile = context.writeMain(context.Main.code)
|
||||
context.writeMain(context.Main.code)
|
||||
val contextId = UUID.randomUUID()
|
||||
val requestId = UUID.randomUUID()
|
||||
|
||||
@ -1453,7 +1453,7 @@ class RuntimeServerTest
|
||||
|
||||
// push main
|
||||
val item1 = Api.StackItem.ExplicitCall(
|
||||
Api.MethodPointer(mainFile, "Main", "main"),
|
||||
Api.MethodPointer("Test.Main", "Main", "main"),
|
||||
None,
|
||||
Vector()
|
||||
)
|
||||
@ -1483,7 +1483,7 @@ class RuntimeServerTest
|
||||
}
|
||||
|
||||
it should "recompute expressions invalidating some" in {
|
||||
val mainFile = context.writeMain(context.Main.code)
|
||||
context.writeMain(context.Main.code)
|
||||
val contextId = UUID.randomUUID()
|
||||
val requestId = UUID.randomUUID()
|
||||
|
||||
@ -1495,7 +1495,7 @@ class RuntimeServerTest
|
||||
|
||||
// push main
|
||||
val item1 = Api.StackItem.ExplicitCall(
|
||||
Api.MethodPointer(mainFile, "Main", "main"),
|
||||
Api.MethodPointer("Test.Main", "Main", "main"),
|
||||
None,
|
||||
Vector()
|
||||
)
|
||||
@ -1527,7 +1527,7 @@ class RuntimeServerTest
|
||||
}
|
||||
|
||||
it should "return error when computing erroneous code" in {
|
||||
val mainFile = context.writeMain(context.MainWithError.code)
|
||||
context.writeMain(context.MainWithError.code)
|
||||
val contextId = UUID.randomUUID()
|
||||
val requestId = UUID.randomUUID()
|
||||
|
||||
@ -1539,7 +1539,7 @@ class RuntimeServerTest
|
||||
|
||||
// push main
|
||||
val item1 = Api.StackItem.ExplicitCall(
|
||||
Api.MethodPointer(mainFile, "Main", "main"),
|
||||
Api.MethodPointer("Test.Main", "Main", "main"),
|
||||
None,
|
||||
Vector()
|
||||
)
|
||||
@ -1562,7 +1562,7 @@ class RuntimeServerTest
|
||||
}
|
||||
|
||||
it should "skip side effects when evaluating cached expression" in {
|
||||
val file = context.writeMain(context.Main2.code)
|
||||
context.writeMain(context.Main2.code)
|
||||
val contextId = UUID.randomUUID()
|
||||
val requestId = UUID.randomUUID()
|
||||
|
||||
@ -1574,7 +1574,7 @@ class RuntimeServerTest
|
||||
|
||||
// push main
|
||||
val item1 = Api.StackItem.ExplicitCall(
|
||||
Api.MethodPointer(file, "Main", "main"),
|
||||
Api.MethodPointer("Test.Main", "Main", "main"),
|
||||
None,
|
||||
Vector()
|
||||
)
|
||||
@ -1601,7 +1601,7 @@ class RuntimeServerTest
|
||||
}
|
||||
|
||||
it should "emit visualisation update when expression is evaluated" in {
|
||||
val mainFile = context.writeMain(context.Main.code)
|
||||
context.writeMain(context.Main.code)
|
||||
val visualisationFile =
|
||||
context.writeInSrcDir("Visualisation", context.Visualisation.code)
|
||||
|
||||
@ -1627,7 +1627,7 @@ class RuntimeServerTest
|
||||
|
||||
// push main
|
||||
val item1 = Api.StackItem.ExplicitCall(
|
||||
Api.MethodPointer(mainFile, "Main", "main"),
|
||||
Api.MethodPointer("Test.Main", "Main", "main"),
|
||||
None,
|
||||
Vector()
|
||||
)
|
||||
@ -1752,7 +1752,7 @@ class RuntimeServerTest
|
||||
|
||||
// push main
|
||||
val item1 = Api.StackItem.ExplicitCall(
|
||||
Api.MethodPointer(mainFile, "Main", "main"),
|
||||
Api.MethodPointer(moduleName, "Main", "main"),
|
||||
None,
|
||||
Vector()
|
||||
)
|
||||
@ -1918,7 +1918,7 @@ class RuntimeServerTest
|
||||
}
|
||||
|
||||
it should "be able to modify visualisations" in {
|
||||
val mainFile = context.writeMain(context.Main.code)
|
||||
context.writeMain(context.Main.code)
|
||||
val visualisationFile =
|
||||
context.writeInSrcDir("Visualisation", context.Visualisation.code)
|
||||
|
||||
@ -1944,7 +1944,7 @@ class RuntimeServerTest
|
||||
|
||||
// push main
|
||||
val item1 = Api.StackItem.ExplicitCall(
|
||||
Api.MethodPointer(mainFile, "Main", "main"),
|
||||
Api.MethodPointer("Test.Main", "Main", "main"),
|
||||
None,
|
||||
Vector()
|
||||
)
|
||||
@ -2031,7 +2031,7 @@ class RuntimeServerTest
|
||||
}
|
||||
|
||||
it should "not emit visualisation updates when visualisation is detached" in {
|
||||
val mainFile = context.writeMain(context.Main.code)
|
||||
context.writeMain(context.Main.code)
|
||||
val visualisationFile =
|
||||
context.writeInSrcDir("Visualisation", context.Visualisation.code)
|
||||
|
||||
@ -2075,7 +2075,7 @@ class RuntimeServerTest
|
||||
)
|
||||
// push main
|
||||
val item1 = Api.StackItem.ExplicitCall(
|
||||
Api.MethodPointer(mainFile, "Main", "main"),
|
||||
Api.MethodPointer("Test.Main", "Main", "main"),
|
||||
None,
|
||||
Vector()
|
||||
)
|
||||
@ -2130,7 +2130,7 @@ class RuntimeServerTest
|
||||
}
|
||||
|
||||
it should "rename a project" in {
|
||||
val mainFile = context.writeMain(context.Main.code)
|
||||
context.writeMain(context.Main.code)
|
||||
val contextId = UUID.randomUUID()
|
||||
val requestId = UUID.randomUUID()
|
||||
|
||||
@ -2142,7 +2142,7 @@ class RuntimeServerTest
|
||||
|
||||
// push main
|
||||
val item1 = Api.StackItem.ExplicitCall(
|
||||
Api.MethodPointer(mainFile, "Main", "main"),
|
||||
Api.MethodPointer("Test.Main", "Main", "main"),
|
||||
None,
|
||||
Vector()
|
||||
)
|
||||
|
@ -32,7 +32,8 @@ public class SuggestionsRepoBenchmark {
|
||||
final Path dbfile = Path.of(System.getProperty("java.io.tmpdir"), "bench-suggestions.db");
|
||||
final Seq<Suggestion.Kind> kinds = SuggestionRandom.nextKinds();
|
||||
final Seq<scala.Tuple2<UUID, String>> updateInput = SuggestionRandom.nextUpdateAllInput();
|
||||
final Seq<UUID> getAllByExternalIdsInput = SuggestionRandom.nextGetByExternalIdsInput();
|
||||
final Seq<scala.Tuple3<String, String, String>> getAllMethodsInput =
|
||||
SuggestionRandom.nextGetAllMethodsInput();
|
||||
|
||||
SqlSuggestionsRepo repo;
|
||||
|
||||
@ -104,8 +105,8 @@ public class SuggestionsRepoBenchmark {
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public Object searchByExternalIds() throws TimeoutException, InterruptedException {
|
||||
return Await.result(repo.getAllByExternalIds(getAllByExternalIdsInput), TIMEOUT);
|
||||
public Object getAllMethods() throws TimeoutException, InterruptedException {
|
||||
return Await.result(repo.getAllMethods(getAllMethodsInput), TIMEOUT);
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
|
@ -11,8 +11,11 @@ object SuggestionRandom {
|
||||
def nextUpdateAllInput(): Seq[(UUID, String)] =
|
||||
Seq(UUID.randomUUID() -> nextString())
|
||||
|
||||
def nextGetByExternalIdsInput(): Seq[UUID] =
|
||||
Seq(UUID.randomUUID(), UUID.randomUUID(), UUID.randomUUID())
|
||||
def nextGetAllMethodsInput(): Seq[(String, String, String)] =
|
||||
Seq(
|
||||
(nextString(), nextString(), nextString()),
|
||||
(nextString(), nextString(), nextString())
|
||||
)
|
||||
|
||||
def nextKinds(): Seq[Suggestion.Kind] =
|
||||
Set.fill(1)(nextKind()).toSeq
|
||||
|
@ -14,12 +14,12 @@ trait SuggestionsRepo[F[_]] {
|
||||
*/
|
||||
def getAll: F[(Long, Seq[SuggestionEntry])]
|
||||
|
||||
/** Get suggestions by external ids.
|
||||
/** Get suggestions by the method call info.
|
||||
*
|
||||
* @param ids the list of external ids
|
||||
* @param calls the list of triples: module, self type and method name
|
||||
* @return the list of found suggestion ids
|
||||
*/
|
||||
def getAllByExternalIds(ids: Seq[Suggestion.ExternalId]): F[Seq[Option[Long]]]
|
||||
def getAllMethods(calls: Seq[(String, String, String)]): F[Seq[Option[Long]]]
|
||||
|
||||
/** Search suggestion by various parameters.
|
||||
*
|
||||
|
@ -40,10 +40,10 @@ final class SqlSuggestionsRepo(db: SqlDatabase)(implicit ec: ExecutionContext)
|
||||
db.run(getAllQuery)
|
||||
|
||||
/** @inheritdoc */
|
||||
override def getAllByExternalIds(
|
||||
ids: Seq[Suggestion.ExternalId]
|
||||
override def getAllMethods(
|
||||
calls: Seq[(String, String, String)]
|
||||
): Future[Seq[Option[Long]]] =
|
||||
db.run(getAllByExternalIdsQuery(ids))
|
||||
db.run(getAllMethodsQuery(calls))
|
||||
|
||||
/** @inheritdoc */
|
||||
override def search(
|
||||
@ -140,34 +140,32 @@ final class SqlSuggestionsRepo(db: SqlDatabase)(implicit ec: ExecutionContext)
|
||||
query.transactionally
|
||||
}
|
||||
|
||||
/** The query to get suggestions by external ids.
|
||||
/** The query to get the suggestions by the method call info.
|
||||
*
|
||||
* @param ids the list of external ids
|
||||
* @param calls the triples containing module name, self type, method name
|
||||
* @return the list of found suggestion ids
|
||||
*/
|
||||
private def getAllByExternalIdsQuery(
|
||||
ids: Seq[Suggestion.ExternalId]
|
||||
def getAllMethodsQuery(
|
||||
calls: Seq[(String, String, String)]
|
||||
): DBIO[Seq[Option[Long]]] =
|
||||
if (ids.isEmpty) {
|
||||
if (calls.isEmpty) {
|
||||
DBIO.successful(Seq())
|
||||
} else {
|
||||
val bits =
|
||||
ids.map(id => (id.getLeastSignificantBits, id.getMostSignificantBits))
|
||||
val query = Suggestions
|
||||
.filter { row =>
|
||||
bits
|
||||
calls
|
||||
.map {
|
||||
case (least, most) =>
|
||||
row.externalIdLeast === least && row.externalIdMost === most
|
||||
case (module, selfType, name) =>
|
||||
row.module === module && row.selfType === selfType && row.name === name
|
||||
}
|
||||
.reduce(_ || _)
|
||||
}
|
||||
.map(row => (row.id, row.externalIdLeast, row.externalIdMost))
|
||||
query.result.map { triples =>
|
||||
val result = triples.flatMap {
|
||||
case (id, least, most) => toUUID(least, most).map(_ -> id)
|
||||
.map(row => (row.id, row.module, row.selfType, row.name))
|
||||
query.result.map { tuples =>
|
||||
val result = tuples.map {
|
||||
case (id, module, selfType, name) => (module, selfType, name) -> id
|
||||
}.toMap
|
||||
ids.map(result.get)
|
||||
calls.map(result.get)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -63,7 +63,7 @@ class SuggestionsRepoTest extends AnyWordSpec with Matchers with RetrySpec {
|
||||
)
|
||||
}
|
||||
|
||||
"get suggestions by external ids" taggedAs Retry in withRepo { repo =>
|
||||
"get suggestions by method call info" taggedAs Retry in withRepo { repo =>
|
||||
val action = for {
|
||||
(_, ids) <- repo.insertAll(
|
||||
Seq(
|
||||
@ -73,30 +73,31 @@ class SuggestionsRepoTest extends AnyWordSpec with Matchers with RetrySpec {
|
||||
suggestion.local
|
||||
)
|
||||
)
|
||||
results <- repo.getAllByExternalIds(
|
||||
Seq(suggestion.method.externalId.get, suggestion.local.externalId.get)
|
||||
results <- repo.getAllMethods(
|
||||
Seq(("Test.Main", "Main", "main"), ("Test.Main", "Main", "foo"))
|
||||
)
|
||||
} yield (ids, results)
|
||||
|
||||
val (ids, results) = Await.result(action, Timeout)
|
||||
results should contain theSameElementsAs Seq(ids(1), ids(3))
|
||||
results should contain theSameElementsInOrderAs Seq(ids(1), None)
|
||||
}
|
||||
|
||||
"get suggestions by empty external ids" taggedAs Retry in withRepo { repo =>
|
||||
val action = for {
|
||||
_ <- repo.insertAll(
|
||||
Seq(
|
||||
suggestion.atom,
|
||||
suggestion.method,
|
||||
suggestion.function,
|
||||
suggestion.local
|
||||
"get suggestions by empty method call info" taggedAs Retry in withRepo {
|
||||
repo =>
|
||||
val action = for {
|
||||
_ <- repo.insertAll(
|
||||
Seq(
|
||||
suggestion.atom,
|
||||
suggestion.method,
|
||||
suggestion.function,
|
||||
suggestion.local
|
||||
)
|
||||
)
|
||||
)
|
||||
results <- repo.getAllByExternalIds(Seq())
|
||||
} yield results
|
||||
results <- repo.getAllMethods(Seq())
|
||||
} yield results
|
||||
|
||||
val results = Await.result(action, Timeout)
|
||||
results.isEmpty shouldEqual true
|
||||
val results = Await.result(action, Timeout)
|
||||
results.isEmpty shouldEqual true
|
||||
}
|
||||
|
||||
"fail to insert duplicate suggestion" taggedAs Retry in withRepo { repo =>
|
||||
|
Loading…
Reference in New Issue
Block a user