mirror of
https://github.com/enso-org/enso.git
synced 2024-12-23 00:11:45 +03:00
Fix the Suggestions Database Updates Handling (#1161)
Misc updates to the Suggestions database updates handling algorithm
This commit is contained in:
parent
8e07e0347f
commit
3d65ffd3cd
@ -90,11 +90,7 @@ final class SuggestionsHandler(
|
|||||||
context.system.eventStream
|
context.system.eventStream
|
||||||
.subscribe(self, classOf[Api.ExpressionValuesComputed])
|
.subscribe(self, classOf[Api.ExpressionValuesComputed])
|
||||||
context.system.eventStream
|
context.system.eventStream
|
||||||
.subscribe(self, classOf[Api.SuggestionsDatabaseUpdateNotification])
|
.subscribe(self, classOf[Api.SuggestionsDatabaseModuleUpdateNotification])
|
||||||
context.system.eventStream
|
|
||||||
.subscribe(self, classOf[Api.SuggestionsDatabaseReIndexNotification])
|
|
||||||
context.system.eventStream
|
|
||||||
.subscribe(self, classOf[Api.SuggestionsDatabaseIndexUpdateNotification])
|
|
||||||
context.system.eventStream.subscribe(self, classOf[ProjectNameChangedEvent])
|
context.system.eventStream.subscribe(self, classOf[ProjectNameChangedEvent])
|
||||||
context.system.eventStream.subscribe(self, classOf[FileDeletedEvent])
|
context.system.eventStream.subscribe(self, classOf[FileDeletedEvent])
|
||||||
context.system.eventStream
|
context.system.eventStream
|
||||||
@ -143,24 +139,7 @@ final class SuggestionsHandler(
|
|||||||
sender() ! CapabilityReleased
|
sender() ! CapabilityReleased
|
||||||
context.become(initialized(projectName, clients - client.clientId))
|
context.become(initialized(projectName, clients - client.clientId))
|
||||||
|
|
||||||
case msg: Api.SuggestionsDatabaseIndexUpdateNotification =>
|
case msg: Api.SuggestionsDatabaseModuleUpdateNotification =>
|
||||||
applyIndexedModuleUpdates(msg.updates.toSeq)
|
|
||||||
.onComplete {
|
|
||||||
case Success(notification) =>
|
|
||||||
if (notification.updates.nonEmpty) {
|
|
||||||
clients.foreach { clientId =>
|
|
||||||
sessionRouter ! DeliverToJsonController(clientId, notification)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case Failure(ex) =>
|
|
||||||
log.error(
|
|
||||||
ex,
|
|
||||||
"Error applying suggestion database updates: {}",
|
|
||||||
msg.updates.map(_.file)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
case msg: Api.SuggestionsDatabaseUpdateNotification =>
|
|
||||||
applyDatabaseUpdates(msg)
|
applyDatabaseUpdates(msg)
|
||||||
.onComplete {
|
.onComplete {
|
||||||
case Success(notification) =>
|
case Success(notification) =>
|
||||||
@ -173,25 +152,7 @@ final class SuggestionsHandler(
|
|||||||
log.error(
|
log.error(
|
||||||
ex,
|
ex,
|
||||||
"Error applying suggestion database updates: {}",
|
"Error applying suggestion database updates: {}",
|
||||||
msg.updates
|
msg.file
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
case msg: Api.SuggestionsDatabaseReIndexNotification =>
|
|
||||||
log.debug(s"ReIndex ${msg.moduleName} ${msg.updates.map(_.suggestion)}")
|
|
||||||
applyReIndexUpdates(msg.updates)
|
|
||||||
.onComplete {
|
|
||||||
case Success(notification) =>
|
|
||||||
if (notification.updates.nonEmpty) {
|
|
||||||
clients.foreach { clientId =>
|
|
||||||
sessionRouter ! DeliverToJsonController(clientId, notification)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case Failure(ex) =>
|
|
||||||
log.error(
|
|
||||||
ex,
|
|
||||||
"Error applying suggestion re-index updates: {}",
|
|
||||||
msg.updates
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -211,6 +172,20 @@ final class SuggestionsHandler(
|
|||||||
}
|
}
|
||||||
SuggestionsDatabaseUpdateNotification(version, updates)
|
SuggestionsDatabaseUpdateNotification(version, updates)
|
||||||
}
|
}
|
||||||
|
.onComplete {
|
||||||
|
case Success(notification) =>
|
||||||
|
if (notification.updates.nonEmpty) {
|
||||||
|
clients.foreach { clientId =>
|
||||||
|
sessionRouter ! DeliverToJsonController(clientId, notification)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case Failure(ex) =>
|
||||||
|
log.error(
|
||||||
|
ex,
|
||||||
|
"Error applying changes from computed values: {}",
|
||||||
|
updates
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
case GetSuggestionsDatabaseVersion =>
|
case GetSuggestionsDatabaseVersion =>
|
||||||
suggestionsRepo.currentVersion
|
suggestionsRepo.currentVersion
|
||||||
@ -314,68 +289,6 @@ final class SuggestionsHandler(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private def applyIndexedModuleUpdates(
|
|
||||||
updates: Seq[Api.IndexedModule]
|
|
||||||
): Future[SuggestionsDatabaseUpdateNotification] = {
|
|
||||||
def createIndexedModuleUpdatesBatch(
|
|
||||||
contents: String,
|
|
||||||
file: java.io.File,
|
|
||||||
updates: Seq[Api.SuggestionsDatabaseUpdate.Add]
|
|
||||||
): Future[Seq[Api.SuggestionsDatabaseUpdate.Add]] =
|
|
||||||
fileVersionsRepo
|
|
||||||
.updateVersion(file, versionCalculator.evalDigest(contents))
|
|
||||||
.map(versionChanged => if (versionChanged) updates else Seq())
|
|
||||||
def getBatches =
|
|
||||||
Future
|
|
||||||
.traverse(updates) { indexed =>
|
|
||||||
createIndexedModuleUpdatesBatch(
|
|
||||||
indexed.contents,
|
|
||||||
indexed.file,
|
|
||||||
indexed.updates
|
|
||||||
)
|
|
||||||
}
|
|
||||||
.map(_.flatten)
|
|
||||||
for {
|
|
||||||
batch <- getBatches
|
|
||||||
update <- applyReIndexUpdates(batch)
|
|
||||||
} yield update
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle the suggestions database re-index update.
|
|
||||||
*
|
|
||||||
* Function clears existing module suggestions from the database, inserts new
|
|
||||||
* suggestions and builds the notification containing combined removed and
|
|
||||||
* added suggestions.
|
|
||||||
*
|
|
||||||
* @param updates the list of updates after the full module re-index
|
|
||||||
* @return the API suggestions database update notification
|
|
||||||
*/
|
|
||||||
private def applyReIndexUpdates(
|
|
||||||
updates: Seq[Api.SuggestionsDatabaseUpdate.Add]
|
|
||||||
): Future[SuggestionsDatabaseUpdateNotification] = {
|
|
||||||
val added = updates.map(_.suggestion)
|
|
||||||
val modules = updates.map(_.suggestion.module).distinct
|
|
||||||
log.debug(s"Applying re-index updates; modules=$modules")
|
|
||||||
for {
|
|
||||||
(_, removedIds) <- suggestionsRepo.removeAllByModule(modules)
|
|
||||||
(version, addedIds) <- suggestionsRepo.insertAll(added)
|
|
||||||
} yield {
|
|
||||||
val updatesRemoved = removedIds.map(SuggestionsDatabaseUpdate.Remove)
|
|
||||||
val updatesAdded = (addedIds zip added).flatMap {
|
|
||||||
case (Some(id), suggestion) =>
|
|
||||||
Some(SuggestionsDatabaseUpdate.Add(id, suggestion))
|
|
||||||
case (None, suggestion) =>
|
|
||||||
log.error("Failed to insert re-index suggestion: {}", suggestion)
|
|
||||||
None
|
|
||||||
}
|
|
||||||
SuggestionsDatabaseUpdateNotification(
|
|
||||||
version,
|
|
||||||
updatesRemoved :++ updatesAdded
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle the suggestions database update.
|
* Handle the suggestions database update.
|
||||||
*
|
*
|
||||||
@ -386,28 +299,42 @@ final class SuggestionsHandler(
|
|||||||
* @return the API suggestions database update notification
|
* @return the API suggestions database update notification
|
||||||
*/
|
*/
|
||||||
private def applyDatabaseUpdates(
|
private def applyDatabaseUpdates(
|
||||||
msg: Api.SuggestionsDatabaseUpdateNotification
|
msg: Api.SuggestionsDatabaseModuleUpdateNotification
|
||||||
): Future[SuggestionsDatabaseUpdateNotification] = {
|
): Future[SuggestionsDatabaseUpdateNotification] = {
|
||||||
val (added, removed) = msg.updates
|
val (addCmds, removeCmds, cleanCmds) = msg.updates
|
||||||
.foldLeft((Seq[Suggestion](), Seq[Suggestion]())) {
|
.foldLeft(
|
||||||
case ((add, remove), msg: Api.SuggestionsDatabaseUpdate.Add) =>
|
(Vector[Suggestion](), Vector[Suggestion](), Vector[String]())
|
||||||
(add :+ msg.suggestion, remove)
|
) {
|
||||||
case ((add, remove), msg: Api.SuggestionsDatabaseUpdate.Remove) =>
|
case ((add, remove, clean), m: Api.SuggestionsDatabaseUpdate.Add) =>
|
||||||
(add, remove :+ msg.suggestion)
|
(add :+ m.suggestion, remove, clean)
|
||||||
|
case ((add, remove, clean), m: Api.SuggestionsDatabaseUpdate.Remove) =>
|
||||||
|
(add, remove :+ m.suggestion, clean)
|
||||||
|
case ((add, remove, clean), m: Api.SuggestionsDatabaseUpdate.Clean) =>
|
||||||
|
(add, remove, clean :+ m.module)
|
||||||
}
|
}
|
||||||
|
val fileVersion = versionCalculator.evalDigest(msg.contents)
|
||||||
log.debug(
|
log.debug(
|
||||||
s"Applying suggestion updates; added=${added
|
s"Applying suggestion updates: Add(${addCmds.map(_.name).mkString(",")}); Remove(${removeCmds
|
||||||
.map(_.name)}; removed=${removed.map(_.name)}"
|
.map(_.name)
|
||||||
|
.mkString(",")}); Clean(${cleanCmds.mkString(",")})"
|
||||||
)
|
)
|
||||||
for {
|
for {
|
||||||
(_, removedIds) <- suggestionsRepo.removeAll(removed)
|
(_, cleanedIds) <- suggestionsRepo.removeAllByModule(cleanCmds)
|
||||||
(version, addedIds) <- suggestionsRepo.insertAll(added)
|
(_, removedIds) <- suggestionsRepo.removeAll(removeCmds)
|
||||||
|
(version, addedIds) <- suggestionsRepo.insertAll(addCmds)
|
||||||
|
_ <- fileVersionsRepo.setVersion(msg.file, fileVersion)
|
||||||
} yield {
|
} yield {
|
||||||
val updatesRemoved = removedIds.collect {
|
val updatesCleaned = cleanedIds.map(SuggestionsDatabaseUpdate.Remove)
|
||||||
case Some(id) => SuggestionsDatabaseUpdate.Remove(id)
|
val updatesRemoved =
|
||||||
|
(removedIds zip removeCmds).flatMap {
|
||||||
|
case (Some(id), _) =>
|
||||||
|
Some(SuggestionsDatabaseUpdate.Remove(id))
|
||||||
|
case (None, suggestion) =>
|
||||||
|
log.error("Failed to remove suggestion: {}", suggestion)
|
||||||
|
None
|
||||||
}
|
}
|
||||||
val updatesAdded =
|
val updatesAdded =
|
||||||
(addedIds zip added).flatMap {
|
(addedIds zip addCmds).flatMap {
|
||||||
case (Some(id), suggestion) =>
|
case (Some(id), suggestion) =>
|
||||||
Some(SuggestionsDatabaseUpdate.Add(id, suggestion))
|
Some(SuggestionsDatabaseUpdate.Add(id, suggestion))
|
||||||
case (None, suggestion) =>
|
case (None, suggestion) =>
|
||||||
@ -416,7 +343,7 @@ final class SuggestionsHandler(
|
|||||||
}
|
}
|
||||||
SuggestionsDatabaseUpdateNotification(
|
SuggestionsDatabaseUpdateNotification(
|
||||||
version,
|
version,
|
||||||
updatesRemoved :++ updatesAdded
|
updatesCleaned :++ updatesRemoved :++ updatesAdded
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -71,7 +71,9 @@ class SuggestionsHandlerSpec
|
|||||||
expectMsg(CapabilityAcquired)
|
expectMsg(CapabilityAcquired)
|
||||||
|
|
||||||
// receive updates
|
// receive updates
|
||||||
handler ! Api.SuggestionsDatabaseUpdateNotification(
|
handler ! Api.SuggestionsDatabaseModuleUpdateNotification(
|
||||||
|
new File("/tmp/foo"),
|
||||||
|
"",
|
||||||
Suggestions.all.map(Api.SuggestionsDatabaseUpdate.Add)
|
Suggestions.all.map(Api.SuggestionsDatabaseUpdate.Add)
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -105,7 +107,9 @@ class SuggestionsHandlerSpec
|
|||||||
expectMsg(CapabilityAcquired)
|
expectMsg(CapabilityAcquired)
|
||||||
|
|
||||||
// receive updates
|
// receive updates
|
||||||
handler ! Api.SuggestionsDatabaseUpdateNotification(
|
handler ! Api.SuggestionsDatabaseModuleUpdateNotification(
|
||||||
|
new File("/tmp/foo"),
|
||||||
|
"",
|
||||||
Suggestions.all.map(Api.SuggestionsDatabaseUpdate.Add) ++
|
Suggestions.all.map(Api.SuggestionsDatabaseUpdate.Add) ++
|
||||||
Suggestions.all.map(Api.SuggestionsDatabaseUpdate.Remove)
|
Suggestions.all.map(Api.SuggestionsDatabaseUpdate.Remove)
|
||||||
)
|
)
|
||||||
@ -178,7 +182,7 @@ class SuggestionsHandlerSpec
|
|||||||
|
|
||||||
"search entries by empty search query" taggedAs Retry in withDb {
|
"search entries by empty search query" taggedAs Retry in withDb {
|
||||||
(config, repo, _, _, handler) =>
|
(config, repo, _, _, handler) =>
|
||||||
Await.ready(repo.insertAll(Suggestions.all), Timeout)
|
val (_, inserted) = Await.result(repo.insertAll(Suggestions.all), Timeout)
|
||||||
handler ! SearchProtocol.Completion(
|
handler ! SearchProtocol.Completion(
|
||||||
file = mkModulePath(config, "Foo", "Main.enso"),
|
file = mkModulePath(config, "Foo", "Main.enso"),
|
||||||
position = Position(0, 0),
|
position = Position(0, 0),
|
||||||
@ -187,7 +191,12 @@ class SuggestionsHandlerSpec
|
|||||||
tags = None
|
tags = None
|
||||||
)
|
)
|
||||||
|
|
||||||
expectMsg(SearchProtocol.CompletionResult(4L, Seq()))
|
expectMsg(
|
||||||
|
SearchProtocol.CompletionResult(
|
||||||
|
4L,
|
||||||
|
Seq(inserted(0).get, inserted(1).get)
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
"search entries by self type" taggedAs Retry in withDb {
|
"search entries by self type" taggedAs Retry in withDb {
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package org.enso.languageserver.websocket.json
|
package org.enso.languageserver.websocket.json
|
||||||
|
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
import io.circe.literal._
|
import io.circe.literal._
|
||||||
import org.enso.languageserver.refactoring.ProjectNameChangedEvent
|
import org.enso.languageserver.refactoring.ProjectNameChangedEvent
|
||||||
import org.enso.languageserver.search.Suggestions
|
import org.enso.languageserver.search.Suggestions
|
||||||
@ -20,7 +22,9 @@ class SuggestionsHandlerEventsTest extends BaseServerTest with FlakySpec {
|
|||||||
|
|
||||||
// add atom
|
// add atom
|
||||||
system.eventStream.publish(
|
system.eventStream.publish(
|
||||||
Api.SuggestionsDatabaseUpdateNotification(
|
Api.SuggestionsDatabaseModuleUpdateNotification(
|
||||||
|
new File("/tmp/foo"),
|
||||||
|
"",
|
||||||
Seq(Api.SuggestionsDatabaseUpdate.Add(Suggestions.atom))
|
Seq(Api.SuggestionsDatabaseUpdate.Add(Suggestions.atom))
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -56,7 +60,9 @@ class SuggestionsHandlerEventsTest extends BaseServerTest with FlakySpec {
|
|||||||
|
|
||||||
// add method
|
// add method
|
||||||
system.eventStream.publish(
|
system.eventStream.publish(
|
||||||
Api.SuggestionsDatabaseUpdateNotification(
|
Api.SuggestionsDatabaseModuleUpdateNotification(
|
||||||
|
new File("/tmp/foo"),
|
||||||
|
"",
|
||||||
Seq(Api.SuggestionsDatabaseUpdate.Add(Suggestions.method))
|
Seq(Api.SuggestionsDatabaseUpdate.Add(Suggestions.method))
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -102,7 +108,9 @@ class SuggestionsHandlerEventsTest extends BaseServerTest with FlakySpec {
|
|||||||
|
|
||||||
// add function
|
// add function
|
||||||
system.eventStream.publish(
|
system.eventStream.publish(
|
||||||
Api.SuggestionsDatabaseUpdateNotification(
|
Api.SuggestionsDatabaseModuleUpdateNotification(
|
||||||
|
new File("/tmp/foo"),
|
||||||
|
"",
|
||||||
Seq(Api.SuggestionsDatabaseUpdate.Add(Suggestions.function))
|
Seq(Api.SuggestionsDatabaseUpdate.Add(Suggestions.function))
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -142,7 +150,9 @@ class SuggestionsHandlerEventsTest extends BaseServerTest with FlakySpec {
|
|||||||
|
|
||||||
// add local
|
// add local
|
||||||
system.eventStream.publish(
|
system.eventStream.publish(
|
||||||
Api.SuggestionsDatabaseUpdateNotification(
|
Api.SuggestionsDatabaseModuleUpdateNotification(
|
||||||
|
new File("/tmp/foo"),
|
||||||
|
"",
|
||||||
Seq(Api.SuggestionsDatabaseUpdate.Add(Suggestions.local))
|
Seq(Api.SuggestionsDatabaseUpdate.Add(Suggestions.local))
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -281,7 +291,9 @@ class SuggestionsHandlerEventsTest extends BaseServerTest with FlakySpec {
|
|||||||
|
|
||||||
// remove items
|
// remove items
|
||||||
system.eventStream.publish(
|
system.eventStream.publish(
|
||||||
Api.SuggestionsDatabaseUpdateNotification(
|
Api.SuggestionsDatabaseModuleUpdateNotification(
|
||||||
|
new File("/tmp/foo"),
|
||||||
|
"",
|
||||||
Seq(
|
Seq(
|
||||||
Api.SuggestionsDatabaseUpdate.Remove(Suggestions.method),
|
Api.SuggestionsDatabaseUpdate.Remove(Suggestions.method),
|
||||||
Api.SuggestionsDatabaseUpdate.Remove(Suggestions.function)
|
Api.SuggestionsDatabaseUpdate.Remove(Suggestions.function)
|
||||||
|
@ -28,8 +28,10 @@ import com.fasterxml.jackson.annotation.{JsonSubTypes, JsonTypeInfo}
|
|||||||
)
|
)
|
||||||
sealed trait Suggestion {
|
sealed trait Suggestion {
|
||||||
|
|
||||||
def name: String
|
def externalId: Option[Suggestion.ExternalId]
|
||||||
def module: String
|
def module: String
|
||||||
|
def name: String
|
||||||
|
def returnType: String
|
||||||
}
|
}
|
||||||
|
|
||||||
object Suggestion {
|
object Suggestion {
|
||||||
|
@ -165,12 +165,8 @@ object Runtime {
|
|||||||
name = "runtimeServerShutDown"
|
name = "runtimeServerShutDown"
|
||||||
),
|
),
|
||||||
new JsonSubTypes.Type(
|
new JsonSubTypes.Type(
|
||||||
value = classOf[Api.SuggestionsDatabaseUpdateNotification],
|
value = classOf[Api.SuggestionsDatabaseModuleUpdateNotification],
|
||||||
name = "suggestionsDatabaseUpdateNotification"
|
name = "suggestionsDatabaseModuleUpdateNotification"
|
||||||
),
|
|
||||||
new JsonSubTypes.Type(
|
|
||||||
value = classOf[Api.SuggestionsDatabaseReIndexNotification],
|
|
||||||
name = "suggestionsDatabaseReindexNotification"
|
|
||||||
),
|
),
|
||||||
new JsonSubTypes.Type(
|
new JsonSubTypes.Type(
|
||||||
value = classOf[Api.InvalidateModulesIndexRequest],
|
value = classOf[Api.InvalidateModulesIndexRequest],
|
||||||
@ -179,10 +175,6 @@ object Runtime {
|
|||||||
new JsonSubTypes.Type(
|
new JsonSubTypes.Type(
|
||||||
value = classOf[Api.InvalidateModulesIndexResponse],
|
value = classOf[Api.InvalidateModulesIndexResponse],
|
||||||
name = "invalidateModulesIndexResponse"
|
name = "invalidateModulesIndexResponse"
|
||||||
),
|
|
||||||
new JsonSubTypes.Type(
|
|
||||||
value = classOf[Api.SuggestionsDatabaseIndexUpdateNotification],
|
|
||||||
name = "suggestionsDatabaseIndexUpdateNotification"
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -343,24 +335,37 @@ object Runtime {
|
|||||||
new JsonSubTypes.Type(
|
new JsonSubTypes.Type(
|
||||||
value = classOf[SuggestionsDatabaseUpdate.Remove],
|
value = classOf[SuggestionsDatabaseUpdate.Remove],
|
||||||
name = "suggestionsDatabaseUpdateRemove"
|
name = "suggestionsDatabaseUpdateRemove"
|
||||||
|
),
|
||||||
|
new JsonSubTypes.Type(
|
||||||
|
value = classOf[SuggestionsDatabaseUpdate.Clean],
|
||||||
|
name = "suggestionsDatabaseUpdateClean"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
sealed trait SuggestionsDatabaseUpdate
|
sealed trait SuggestionsDatabaseUpdate
|
||||||
object SuggestionsDatabaseUpdate {
|
object SuggestionsDatabaseUpdate {
|
||||||
|
|
||||||
/** Create or replace the database entry.
|
/**
|
||||||
|
* Create or replace the database entry.
|
||||||
*
|
*
|
||||||
* @param suggestion the new suggestion
|
* @param suggestion the new suggestion
|
||||||
*/
|
*/
|
||||||
case class Add(suggestion: Suggestion) extends SuggestionsDatabaseUpdate
|
case class Add(suggestion: Suggestion) extends SuggestionsDatabaseUpdate
|
||||||
|
|
||||||
/** Remove the database entry.
|
/**
|
||||||
|
* Remove the database entry.
|
||||||
*
|
*
|
||||||
* @param suggestion the suggestion to remove
|
* @param suggestion the suggestion to remove
|
||||||
*/
|
*/
|
||||||
case class Remove(suggestion: Suggestion)
|
case class Remove(suggestion: Suggestion)
|
||||||
extends SuggestionsDatabaseUpdate
|
extends SuggestionsDatabaseUpdate
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove all module entries from the database.
|
||||||
|
*
|
||||||
|
* @param module the module name
|
||||||
|
*/
|
||||||
|
case class Clean(module: String) extends SuggestionsDatabaseUpdate
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -711,53 +716,24 @@ object Runtime {
|
|||||||
case class ProjectRenamed(newName: String) extends ApiResponse
|
case class ProjectRenamed(newName: String) extends ApiResponse
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A notification about the change in the suggestions database.
|
* A notification about the changes in the suggestions database.
|
||||||
*
|
*
|
||||||
* @param updates the list of database updates
|
* @param file the module file path
|
||||||
|
* @param contents the module source
|
||||||
|
* @param updates the list of suggestions extracted from module
|
||||||
*/
|
*/
|
||||||
case class SuggestionsDatabaseUpdateNotification(
|
case class SuggestionsDatabaseModuleUpdateNotification(
|
||||||
|
file: File,
|
||||||
|
contents: String,
|
||||||
updates: Seq[SuggestionsDatabaseUpdate]
|
updates: Seq[SuggestionsDatabaseUpdate]
|
||||||
) extends ApiNotification
|
) extends ApiNotification
|
||||||
|
|
||||||
/**
|
|
||||||
* A notification about the re-indexed module updates.
|
|
||||||
*
|
|
||||||
* @param moduleName the name of re-indexed module
|
|
||||||
* @param updates the list of database updates
|
|
||||||
*/
|
|
||||||
case class SuggestionsDatabaseReIndexNotification(
|
|
||||||
moduleName: String,
|
|
||||||
updates: Seq[SuggestionsDatabaseUpdate.Add]
|
|
||||||
) extends ApiNotification
|
|
||||||
|
|
||||||
/** A request to invalidate the indexed flag of the modules. */
|
/** A request to invalidate the indexed flag of the modules. */
|
||||||
case class InvalidateModulesIndexRequest() extends ApiRequest
|
case class InvalidateModulesIndexRequest() extends ApiRequest
|
||||||
|
|
||||||
/** Signals that the module indexes has been invalidated. */
|
/** Signals that the module indexes has been invalidated. */
|
||||||
case class InvalidateModulesIndexResponse() extends ApiResponse
|
case class InvalidateModulesIndexResponse() extends ApiResponse
|
||||||
|
|
||||||
/**
|
|
||||||
* An indexed module.
|
|
||||||
*
|
|
||||||
* @param file the module file path
|
|
||||||
* @param contents the module source
|
|
||||||
* @param updates the list of suggestions extracted from module
|
|
||||||
*/
|
|
||||||
case class IndexedModule(
|
|
||||||
file: File,
|
|
||||||
contents: String,
|
|
||||||
updates: Seq[SuggestionsDatabaseUpdate.Add]
|
|
||||||
) extends ApiNotification
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A notification about new indexed modules.
|
|
||||||
*
|
|
||||||
* @param updates the list of suggestions database updates
|
|
||||||
*/
|
|
||||||
case class SuggestionsDatabaseIndexUpdateNotification(
|
|
||||||
updates: Iterable[IndexedModule]
|
|
||||||
) extends ApiNotification
|
|
||||||
|
|
||||||
private lazy val mapper = {
|
private lazy val mapper = {
|
||||||
val factory = new CBORFactory()
|
val factory = new CBORFactory()
|
||||||
val mapper = new ObjectMapper(factory) with ScalaObjectMapper
|
val mapper = new ObjectMapper(factory) with ScalaObjectMapper
|
||||||
|
@ -92,33 +92,40 @@ class EnsureCompiledJob(protected val files: Iterable[File])
|
|||||||
ctx.executionService.getContext.getTopScope.getModules.asScala
|
ctx.executionService.getContext.getTopScope.getModules.asScala
|
||||||
ctx.executionService.getLogger
|
ctx.executionService.getLogger
|
||||||
.finest(s"Modules in scope: ${modulesInScope.map(_.getName)}")
|
.finest(s"Modules in scope: ${modulesInScope.map(_.getName)}")
|
||||||
val updates = modulesInScope.flatMap { module =>
|
modulesInScope.foreach { module =>
|
||||||
compile(module)
|
compile(module)
|
||||||
analyzeModuleInScope(module)
|
analyzeModuleInScope(module)
|
||||||
}
|
}
|
||||||
sendIndexUpdateNotification(
|
|
||||||
Api.SuggestionsDatabaseIndexUpdateNotification(updates)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private def analyzeImport(
|
private def analyzeImport(
|
||||||
module: Module
|
module: Module
|
||||||
)(implicit ctx: RuntimeContext): Unit = {
|
)(implicit ctx: RuntimeContext): Unit = {
|
||||||
if (!module.isIndexed && module.getLiteralSource != null) {
|
if (
|
||||||
|
!module.isIndexed &&
|
||||||
|
module.getLiteralSource != null &&
|
||||||
|
module.getPath != null
|
||||||
|
) {
|
||||||
ctx.executionService.getLogger
|
ctx.executionService.getLogger
|
||||||
.finest(s"Analyzing imported ${module.getName}")
|
.finest(s"Analyzing imported ${module.getName}")
|
||||||
val moduleName = module.getName.toString
|
val moduleName = module.getName.toString
|
||||||
val addedSuggestions = SuggestionBuilder(module.getLiteralSource)
|
val addedSuggestions = SuggestionBuilder(module.getLiteralSource)
|
||||||
.build(module.getName.toString, module.getIr)
|
.build(module.getName.toString, module.getIr)
|
||||||
.filter(isSuggestionGlobal)
|
.filter(isSuggestionGlobal)
|
||||||
sendReIndexNotification(moduleName, addedSuggestions)
|
val update = Api.SuggestionsDatabaseModuleUpdateNotification(
|
||||||
|
new File(module.getPath),
|
||||||
|
module.getLiteralSource.toString,
|
||||||
|
Api.SuggestionsDatabaseUpdate.Clean(moduleName) +:
|
||||||
|
addedSuggestions.map(Api.SuggestionsDatabaseUpdate.Add)
|
||||||
|
)
|
||||||
|
sendModuleUpdate(update)
|
||||||
module.setIndexed(true)
|
module.setIndexed(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private def analyzeModuleInScope(module: Module)(implicit
|
private def analyzeModuleInScope(module: Module)(implicit
|
||||||
ctx: RuntimeContext
|
ctx: RuntimeContext
|
||||||
): Option[Api.IndexedModule] = {
|
): Unit = {
|
||||||
try module.getSource
|
try module.getSource
|
||||||
catch {
|
catch {
|
||||||
case e: IOException =>
|
case e: IOException =>
|
||||||
@ -139,16 +146,14 @@ class EnsureCompiledJob(protected val files: Iterable[File])
|
|||||||
val addedSuggestions = SuggestionBuilder(module.getLiteralSource)
|
val addedSuggestions = SuggestionBuilder(module.getLiteralSource)
|
||||||
.build(moduleName, module.getIr)
|
.build(moduleName, module.getIr)
|
||||||
.filter(isSuggestionGlobal)
|
.filter(isSuggestionGlobal)
|
||||||
module.setIndexed(true)
|
val update = Api.SuggestionsDatabaseModuleUpdateNotification(
|
||||||
Some(
|
|
||||||
Api.IndexedModule(
|
|
||||||
new File(module.getPath),
|
new File(module.getPath),
|
||||||
module.getSource.getCharacters.toString,
|
module.getLiteralSource.toString,
|
||||||
|
Api.SuggestionsDatabaseUpdate.Clean(moduleName) +:
|
||||||
addedSuggestions.map(Api.SuggestionsDatabaseUpdate.Add)
|
addedSuggestions.map(Api.SuggestionsDatabaseUpdate.Add)
|
||||||
)
|
)
|
||||||
)
|
sendModuleUpdate(update)
|
||||||
} else {
|
module.setIndexed(true)
|
||||||
None
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -165,17 +170,30 @@ class EnsureCompiledJob(protected val files: Iterable[File])
|
|||||||
val addedSuggestions =
|
val addedSuggestions =
|
||||||
SuggestionBuilder(module.getLiteralSource)
|
SuggestionBuilder(module.getLiteralSource)
|
||||||
.build(moduleName, module.getIr)
|
.build(moduleName, module.getIr)
|
||||||
sendSuggestionsUpdateNotification(
|
val update = Api.SuggestionsDatabaseModuleUpdateNotification(
|
||||||
removedSuggestions diff addedSuggestions,
|
new File(module.getPath),
|
||||||
addedSuggestions diff removedSuggestions
|
module.getLiteralSource.toString,
|
||||||
|
removedSuggestions
|
||||||
|
.diff(addedSuggestions)
|
||||||
|
.map(Api.SuggestionsDatabaseUpdate.Remove) :++
|
||||||
|
addedSuggestions
|
||||||
|
.diff(removedSuggestions)
|
||||||
|
.map(Api.SuggestionsDatabaseUpdate.Add)
|
||||||
)
|
)
|
||||||
|
sendModuleUpdate(update)
|
||||||
} else {
|
} else {
|
||||||
ctx.executionService.getLogger
|
ctx.executionService.getLogger
|
||||||
.finest(s"Analyzing not-indexed module ${module.getName}")
|
.finest(s"Analyzing not-indexed module ${module.getName}")
|
||||||
val addedSuggestions =
|
val addedSuggestions =
|
||||||
SuggestionBuilder(module.getLiteralSource)
|
SuggestionBuilder(module.getLiteralSource)
|
||||||
.build(moduleName, module.getIr)
|
.build(moduleName, module.getIr)
|
||||||
sendReIndexNotification(moduleName, addedSuggestions)
|
val update = Api.SuggestionsDatabaseModuleUpdateNotification(
|
||||||
|
new File(module.getPath),
|
||||||
|
module.getLiteralSource.toString,
|
||||||
|
Api.SuggestionsDatabaseUpdate.Clean(moduleName) +:
|
||||||
|
addedSuggestions.map(Api.SuggestionsDatabaseUpdate.Add)
|
||||||
|
)
|
||||||
|
sendModuleUpdate(update)
|
||||||
module.setIndexed(true)
|
module.setIndexed(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -209,7 +227,7 @@ class EnsureCompiledJob(protected val files: Iterable[File])
|
|||||||
val prevStage = module.getCompilationStage
|
val prevStage = module.getCompilationStage
|
||||||
module.compileScope(ctx.executionService.getContext).getModule
|
module.compileScope(ctx.executionService.getContext).getModule
|
||||||
if (prevStage != module.getCompilationStage) {
|
if (prevStage != module.getCompilationStage) {
|
||||||
ctx.executionService.getLogger.finer(
|
ctx.executionService.getLogger.finest(
|
||||||
s"Compiled ${module.getName} $prevStage->${module.getCompilationStage}"
|
s"Compiled ${module.getName} $prevStage->${module.getCompilationStage}"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -289,56 +307,16 @@ class EnsureCompiledJob(protected val files: Iterable[File])
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send notification about the suggestions database updates.
|
* Send notification about module updates.
|
||||||
*
|
*
|
||||||
* @param removed the list of suggestions to remove
|
* @param payload the module update
|
||||||
* @param added the list of suggestions to add
|
|
||||||
* @param ctx the runtime context
|
* @param ctx the runtime context
|
||||||
*/
|
*/
|
||||||
private def sendSuggestionsUpdateNotification(
|
private def sendModuleUpdate(
|
||||||
removed: Seq[Suggestion],
|
payload: Api.SuggestionsDatabaseModuleUpdateNotification
|
||||||
added: Seq[Suggestion]
|
|
||||||
)(implicit ctx: RuntimeContext): Unit =
|
)(implicit ctx: RuntimeContext): Unit =
|
||||||
if (added.nonEmpty || removed.nonEmpty) {
|
if (payload.updates.nonEmpty) {
|
||||||
ctx.endpoint.sendToClient(
|
ctx.endpoint.sendToClient(Api.Response(payload))
|
||||||
Api.Response(
|
|
||||||
Api.SuggestionsDatabaseUpdateNotification(
|
|
||||||
removed.map(Api.SuggestionsDatabaseUpdate.Remove) :++
|
|
||||||
added.map(Api.SuggestionsDatabaseUpdate.Add)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send notification about the re-indexed module updates.
|
|
||||||
*
|
|
||||||
* @param moduleName the name of re-indexed module
|
|
||||||
* @param added the list of suggestions to add
|
|
||||||
* @param ctx the runtime context
|
|
||||||
*/
|
|
||||||
private def sendReIndexNotification(
|
|
||||||
moduleName: String,
|
|
||||||
added: Seq[Suggestion]
|
|
||||||
)(implicit ctx: RuntimeContext): Unit = {
|
|
||||||
ctx.endpoint.sendToClient(
|
|
||||||
Api.Response(
|
|
||||||
Api.SuggestionsDatabaseReIndexNotification(
|
|
||||||
moduleName,
|
|
||||||
added.map(Api.SuggestionsDatabaseUpdate.Add)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private def sendIndexUpdateNotification(
|
|
||||||
msg: Api.SuggestionsDatabaseIndexUpdateNotification
|
|
||||||
)(implicit
|
|
||||||
ctx: RuntimeContext
|
|
||||||
): Unit = {
|
|
||||||
if (msg.updates.nonEmpty) {
|
|
||||||
ctx.endpoint.sendToClient(Api.Response(msg))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private def isSuggestionGlobal(suggestion: Suggestion): Boolean =
|
private def isSuggestionGlobal(suggestion: Suggestion): Boolean =
|
||||||
|
@ -454,9 +454,11 @@ class RuntimeServerTest
|
|||||||
)
|
)
|
||||||
),
|
),
|
||||||
Api.Response(
|
Api.Response(
|
||||||
Api.SuggestionsDatabaseReIndexNotification(
|
Api.SuggestionsDatabaseModuleUpdateNotification(
|
||||||
moduleName,
|
mainFile,
|
||||||
|
contents,
|
||||||
Seq(
|
Seq(
|
||||||
|
Api.SuggestionsDatabaseUpdate.Clean(moduleName),
|
||||||
Api.SuggestionsDatabaseUpdate.Add(
|
Api.SuggestionsDatabaseUpdate.Add(
|
||||||
Suggestion.Method(
|
Suggestion.Method(
|
||||||
None,
|
None,
|
||||||
@ -557,9 +559,11 @@ class RuntimeServerTest
|
|||||||
)
|
)
|
||||||
),
|
),
|
||||||
Api.Response(
|
Api.Response(
|
||||||
Api.SuggestionsDatabaseReIndexNotification(
|
Api.SuggestionsDatabaseModuleUpdateNotification(
|
||||||
moduleName,
|
mainFile,
|
||||||
|
contents,
|
||||||
Seq(
|
Seq(
|
||||||
|
Api.SuggestionsDatabaseUpdate.Clean(moduleName),
|
||||||
Api.SuggestionsDatabaseUpdate.Add(
|
Api.SuggestionsDatabaseUpdate.Add(
|
||||||
Suggestion.Method(
|
Suggestion.Method(
|
||||||
None,
|
None,
|
||||||
@ -660,9 +664,11 @@ class RuntimeServerTest
|
|||||||
)
|
)
|
||||||
),
|
),
|
||||||
Api.Response(
|
Api.Response(
|
||||||
Api.SuggestionsDatabaseReIndexNotification(
|
Api.SuggestionsDatabaseModuleUpdateNotification(
|
||||||
moduleName,
|
mainFile,
|
||||||
|
contents,
|
||||||
Seq(
|
Seq(
|
||||||
|
Api.SuggestionsDatabaseUpdate.Clean(moduleName),
|
||||||
Api.SuggestionsDatabaseUpdate.Add(
|
Api.SuggestionsDatabaseUpdate.Add(
|
||||||
Suggestion.Method(
|
Suggestion.Method(
|
||||||
Some(idMain),
|
Some(idMain),
|
||||||
@ -761,9 +767,11 @@ class RuntimeServerTest
|
|||||||
)
|
)
|
||||||
),
|
),
|
||||||
Api.Response(
|
Api.Response(
|
||||||
Api.SuggestionsDatabaseReIndexNotification(
|
Api.SuggestionsDatabaseModuleUpdateNotification(
|
||||||
moduleName,
|
mainFile,
|
||||||
|
contents,
|
||||||
Seq(
|
Seq(
|
||||||
|
Api.SuggestionsDatabaseUpdate.Clean(moduleName),
|
||||||
Api.SuggestionsDatabaseUpdate.Add(
|
Api.SuggestionsDatabaseUpdate.Add(
|
||||||
Suggestion.Method(
|
Suggestion.Method(
|
||||||
Some(idMain),
|
Some(idMain),
|
||||||
@ -862,9 +870,11 @@ class RuntimeServerTest
|
|||||||
)
|
)
|
||||||
),
|
),
|
||||||
Api.Response(
|
Api.Response(
|
||||||
Api.SuggestionsDatabaseReIndexNotification(
|
Api.SuggestionsDatabaseModuleUpdateNotification(
|
||||||
moduleName,
|
mainFile,
|
||||||
|
contents,
|
||||||
Seq(
|
Seq(
|
||||||
|
Api.SuggestionsDatabaseUpdate.Clean(moduleName),
|
||||||
Api.SuggestionsDatabaseUpdate.Add(
|
Api.SuggestionsDatabaseUpdate.Add(
|
||||||
Suggestion.Method(
|
Suggestion.Method(
|
||||||
None,
|
None,
|
||||||
@ -946,9 +956,11 @@ class RuntimeServerTest
|
|||||||
context.Main.Update.mainZ(contextId),
|
context.Main.Update.mainZ(contextId),
|
||||||
idMainUpdate,
|
idMainUpdate,
|
||||||
Api.Response(
|
Api.Response(
|
||||||
Api.SuggestionsDatabaseReIndexNotification(
|
Api.SuggestionsDatabaseModuleUpdateNotification(
|
||||||
moduleName,
|
mainFile,
|
||||||
|
contents,
|
||||||
Seq(
|
Seq(
|
||||||
|
Api.SuggestionsDatabaseUpdate.Clean(moduleName),
|
||||||
Api.SuggestionsDatabaseUpdate.Add(
|
Api.SuggestionsDatabaseUpdate.Add(
|
||||||
Suggestion.Method(
|
Suggestion.Method(
|
||||||
Some(idMain),
|
Some(idMain),
|
||||||
@ -1136,9 +1148,11 @@ class RuntimeServerTest
|
|||||||
)
|
)
|
||||||
),
|
),
|
||||||
Api.Response(
|
Api.Response(
|
||||||
Api.SuggestionsDatabaseReIndexNotification(
|
Api.SuggestionsDatabaseModuleUpdateNotification(
|
||||||
moduleName,
|
mainFile,
|
||||||
|
contents,
|
||||||
Seq(
|
Seq(
|
||||||
|
Api.SuggestionsDatabaseUpdate.Clean(moduleName),
|
||||||
Api.SuggestionsDatabaseUpdate.Add(
|
Api.SuggestionsDatabaseUpdate.Add(
|
||||||
Suggestion.Method(
|
Suggestion.Method(
|
||||||
Some(idMain),
|
Some(idMain),
|
||||||
@ -1270,9 +1284,11 @@ class RuntimeServerTest
|
|||||||
)
|
)
|
||||||
),
|
),
|
||||||
Api.Response(
|
Api.Response(
|
||||||
Api.SuggestionsDatabaseReIndexNotification(
|
Api.SuggestionsDatabaseModuleUpdateNotification(
|
||||||
moduleName,
|
mainFile,
|
||||||
|
contents,
|
||||||
Seq(
|
Seq(
|
||||||
|
Api.SuggestionsDatabaseUpdate.Clean(moduleName),
|
||||||
Api.SuggestionsDatabaseUpdate.Add(
|
Api.SuggestionsDatabaseUpdate.Add(
|
||||||
Suggestion.Method(
|
Suggestion.Method(
|
||||||
Some(idMain),
|
Some(idMain),
|
||||||
@ -1621,9 +1637,11 @@ class RuntimeServerTest
|
|||||||
)
|
)
|
||||||
),
|
),
|
||||||
Api.Response(
|
Api.Response(
|
||||||
Api.SuggestionsDatabaseReIndexNotification(
|
Api.SuggestionsDatabaseModuleUpdateNotification(
|
||||||
moduleName,
|
mainFile,
|
||||||
|
contents,
|
||||||
Seq(
|
Seq(
|
||||||
|
Api.SuggestionsDatabaseUpdate.Clean(moduleName),
|
||||||
Api.SuggestionsDatabaseUpdate.Add(
|
Api.SuggestionsDatabaseUpdate.Add(
|
||||||
Suggestion.Method(
|
Suggestion.Method(
|
||||||
Some(idMain),
|
Some(idMain),
|
||||||
@ -1877,6 +1895,7 @@ class RuntimeServerTest
|
|||||||
Api.Response(requestId, Api.CreateContextResponse(contextId))
|
Api.Response(requestId, Api.CreateContextResponse(contextId))
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val moduleName = "Test.Main"
|
||||||
val code =
|
val code =
|
||||||
"""from Builtins import all
|
"""from Builtins import all
|
||||||
|
|
|
|
||||||
@ -1899,7 +1918,7 @@ class RuntimeServerTest
|
|||||||
contextId,
|
contextId,
|
||||||
Api.StackItem
|
Api.StackItem
|
||||||
.ExplicitCall(
|
.ExplicitCall(
|
||||||
Api.MethodPointer("Test.Main", "Main", "main"),
|
Api.MethodPointer(moduleName, "Main", "main"),
|
||||||
None,
|
None,
|
||||||
Vector()
|
Vector()
|
||||||
)
|
)
|
||||||
@ -1909,9 +1928,11 @@ class RuntimeServerTest
|
|||||||
context.receive(3) should contain theSameElementsAs Seq(
|
context.receive(3) should contain theSameElementsAs Seq(
|
||||||
Api.Response(requestId, Api.PushContextResponse(contextId)),
|
Api.Response(requestId, Api.PushContextResponse(contextId)),
|
||||||
Api.Response(
|
Api.Response(
|
||||||
Api.SuggestionsDatabaseReIndexNotification(
|
Api.SuggestionsDatabaseModuleUpdateNotification(
|
||||||
"Test.Main",
|
mainFile,
|
||||||
|
code,
|
||||||
Seq(
|
Seq(
|
||||||
|
Api.SuggestionsDatabaseUpdate.Clean(moduleName),
|
||||||
Api.SuggestionsDatabaseUpdate.Add(
|
Api.SuggestionsDatabaseUpdate.Add(
|
||||||
Suggestion.Method(
|
Suggestion.Method(
|
||||||
None,
|
None,
|
||||||
@ -1955,6 +1976,7 @@ class RuntimeServerTest
|
|||||||
it should "support file modification operations with attached ids" in {
|
it should "support file modification operations with attached ids" in {
|
||||||
val contextId = UUID.randomUUID()
|
val contextId = UUID.randomUUID()
|
||||||
val requestId = UUID.randomUUID()
|
val requestId = UUID.randomUUID()
|
||||||
|
val moduleName = "Test.Main"
|
||||||
val metadata = new Metadata
|
val metadata = new Metadata
|
||||||
val idMain = metadata.addItem(7, 2)
|
val idMain = metadata.addItem(7, 2)
|
||||||
val code = metadata.appendToCode("main = 84")
|
val code = metadata.appendToCode("main = 84")
|
||||||
@ -1987,7 +2009,7 @@ class RuntimeServerTest
|
|||||||
contextId,
|
contextId,
|
||||||
Api.StackItem
|
Api.StackItem
|
||||||
.ExplicitCall(
|
.ExplicitCall(
|
||||||
Api.MethodPointer("Test.Main", "Main", "main"),
|
Api.MethodPointer(moduleName, "Main", "main"),
|
||||||
None,
|
None,
|
||||||
Vector()
|
Vector()
|
||||||
)
|
)
|
||||||
@ -2005,9 +2027,11 @@ class RuntimeServerTest
|
|||||||
)
|
)
|
||||||
),
|
),
|
||||||
Api.Response(
|
Api.Response(
|
||||||
Api.SuggestionsDatabaseReIndexNotification(
|
Api.SuggestionsDatabaseModuleUpdateNotification(
|
||||||
"Test.Main",
|
mainFile,
|
||||||
|
code,
|
||||||
Seq(
|
Seq(
|
||||||
|
Api.SuggestionsDatabaseUpdate.Clean(moduleName),
|
||||||
Api.SuggestionsDatabaseUpdate.Add(
|
Api.SuggestionsDatabaseUpdate.Add(
|
||||||
Suggestion.Method(
|
Suggestion.Method(
|
||||||
Some(idMain),
|
Some(idMain),
|
||||||
@ -2045,6 +2069,7 @@ class RuntimeServerTest
|
|||||||
it should "send suggestion notifications when file is executed" in {
|
it should "send suggestion notifications when file is executed" in {
|
||||||
val contextId = UUID.randomUUID()
|
val contextId = UUID.randomUUID()
|
||||||
val requestId = UUID.randomUUID()
|
val requestId = UUID.randomUUID()
|
||||||
|
val moduleName = "Test.Main"
|
||||||
val idMain = context.Main.metadata.addItem(33, 47)
|
val idMain = context.Main.metadata.addItem(33, 47)
|
||||||
val idMainUpdate =
|
val idMainUpdate =
|
||||||
Api.Response(
|
Api.Response(
|
||||||
@ -2076,7 +2101,7 @@ class RuntimeServerTest
|
|||||||
|
|
||||||
// push main
|
// push main
|
||||||
val item1 = Api.StackItem.ExplicitCall(
|
val item1 = Api.StackItem.ExplicitCall(
|
||||||
Api.MethodPointer("Test.Main", "Main", "main"),
|
Api.MethodPointer(moduleName, "Main", "main"),
|
||||||
None,
|
None,
|
||||||
Vector()
|
Vector()
|
||||||
)
|
)
|
||||||
@ -2090,13 +2115,15 @@ class RuntimeServerTest
|
|||||||
context.Main.Update.mainZ(contextId),
|
context.Main.Update.mainZ(contextId),
|
||||||
idMainUpdate,
|
idMainUpdate,
|
||||||
Api.Response(
|
Api.Response(
|
||||||
Api.SuggestionsDatabaseReIndexNotification(
|
Api.SuggestionsDatabaseModuleUpdateNotification(
|
||||||
"Test.Main",
|
mainFile,
|
||||||
|
context.Main.code,
|
||||||
List(
|
List(
|
||||||
|
Api.SuggestionsDatabaseUpdate.Clean(moduleName),
|
||||||
Api.SuggestionsDatabaseUpdate.Add(
|
Api.SuggestionsDatabaseUpdate.Add(
|
||||||
Suggestion.Method(
|
Suggestion.Method(
|
||||||
Some(idMain),
|
Some(idMain),
|
||||||
"Test.Main",
|
moduleName,
|
||||||
"main",
|
"main",
|
||||||
List(Suggestion.Argument("this", "Any", false, false, None)),
|
List(Suggestion.Argument("this", "Any", false, false, None)),
|
||||||
"Main",
|
"Main",
|
||||||
@ -2107,7 +2134,7 @@ class RuntimeServerTest
|
|||||||
Api.SuggestionsDatabaseUpdate.Add(
|
Api.SuggestionsDatabaseUpdate.Add(
|
||||||
Suggestion.Method(
|
Suggestion.Method(
|
||||||
None,
|
None,
|
||||||
"Test.Main",
|
moduleName,
|
||||||
"foo",
|
"foo",
|
||||||
List(
|
List(
|
||||||
Suggestion.Argument("this", "Any", false, false, None),
|
Suggestion.Argument("this", "Any", false, false, None),
|
||||||
@ -2121,7 +2148,7 @@ class RuntimeServerTest
|
|||||||
Api.SuggestionsDatabaseUpdate.Add(
|
Api.SuggestionsDatabaseUpdate.Add(
|
||||||
Suggestion.Local(
|
Suggestion.Local(
|
||||||
Some(context.Main.idMainX),
|
Some(context.Main.idMainX),
|
||||||
"Test.Main",
|
moduleName,
|
||||||
"x",
|
"x",
|
||||||
"Any",
|
"Any",
|
||||||
Suggestion
|
Suggestion
|
||||||
@ -2131,7 +2158,7 @@ class RuntimeServerTest
|
|||||||
Api.SuggestionsDatabaseUpdate.Add(
|
Api.SuggestionsDatabaseUpdate.Add(
|
||||||
Suggestion.Local(
|
Suggestion.Local(
|
||||||
Some(context.Main.idMainY),
|
Some(context.Main.idMainY),
|
||||||
"Test.Main",
|
moduleName,
|
||||||
"y",
|
"y",
|
||||||
"Any",
|
"Any",
|
||||||
Suggestion
|
Suggestion
|
||||||
@ -2141,7 +2168,7 @@ class RuntimeServerTest
|
|||||||
Api.SuggestionsDatabaseUpdate.Add(
|
Api.SuggestionsDatabaseUpdate.Add(
|
||||||
Suggestion.Local(
|
Suggestion.Local(
|
||||||
Some(context.Main.idMainZ),
|
Some(context.Main.idMainZ),
|
||||||
"Test.Main",
|
moduleName,
|
||||||
"z",
|
"z",
|
||||||
"Any",
|
"Any",
|
||||||
Suggestion
|
Suggestion
|
||||||
@ -2151,7 +2178,7 @@ class RuntimeServerTest
|
|||||||
Api.SuggestionsDatabaseUpdate.Add(
|
Api.SuggestionsDatabaseUpdate.Add(
|
||||||
Suggestion.Local(
|
Suggestion.Local(
|
||||||
Some(context.Main.idFooY),
|
Some(context.Main.idFooY),
|
||||||
"Test.Main",
|
moduleName,
|
||||||
"y",
|
"y",
|
||||||
"Any",
|
"Any",
|
||||||
Suggestion
|
Suggestion
|
||||||
@ -2161,7 +2188,7 @@ class RuntimeServerTest
|
|||||||
Api.SuggestionsDatabaseUpdate.Add(
|
Api.SuggestionsDatabaseUpdate.Add(
|
||||||
Suggestion.Local(
|
Suggestion.Local(
|
||||||
Some(context.Main.idFooZ),
|
Some(context.Main.idFooZ),
|
||||||
"Test.Main",
|
moduleName,
|
||||||
"z",
|
"z",
|
||||||
"Any",
|
"Any",
|
||||||
Suggestion
|
Suggestion
|
||||||
@ -2221,6 +2248,8 @@ class RuntimeServerTest
|
|||||||
it should "send suggestion notifications when file is modified" in {
|
it should "send suggestion notifications when file is modified" in {
|
||||||
val contextId = UUID.randomUUID()
|
val contextId = UUID.randomUUID()
|
||||||
val requestId = UUID.randomUUID()
|
val requestId = UUID.randomUUID()
|
||||||
|
val moduleName = "Test.Main"
|
||||||
|
val newline = System.lineSeparator()
|
||||||
|
|
||||||
context.send(Api.Request(requestId, Api.CreateContextRequest(contextId)))
|
context.send(Api.Request(requestId, Api.CreateContextRequest(contextId)))
|
||||||
context.receive shouldEqual Some(
|
context.receive shouldEqual Some(
|
||||||
@ -2237,15 +2266,7 @@ class RuntimeServerTest
|
|||||||
val mainFile = context.writeMain(code)
|
val mainFile = context.writeMain(code)
|
||||||
|
|
||||||
// Open the new file
|
// Open the new file
|
||||||
context.send(
|
context.send(Api.Request(Api.OpenFileNotification(mainFile, code, false)))
|
||||||
Api.Request(
|
|
||||||
Api.OpenFileNotification(
|
|
||||||
mainFile,
|
|
||||||
code,
|
|
||||||
false
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
context.receiveNone shouldEqual None
|
context.receiveNone shouldEqual None
|
||||||
context.consumeOut shouldEqual List()
|
context.consumeOut shouldEqual List()
|
||||||
|
|
||||||
@ -2257,7 +2278,7 @@ class RuntimeServerTest
|
|||||||
contextId,
|
contextId,
|
||||||
Api.StackItem
|
Api.StackItem
|
||||||
.ExplicitCall(
|
.ExplicitCall(
|
||||||
Api.MethodPointer("Test.Main", "Main", "main"),
|
Api.MethodPointer(moduleName, "Main", "main"),
|
||||||
None,
|
None,
|
||||||
Vector()
|
Vector()
|
||||||
)
|
)
|
||||||
@ -2267,13 +2288,15 @@ class RuntimeServerTest
|
|||||||
context.receive(3) should contain theSameElementsAs Seq(
|
context.receive(3) should contain theSameElementsAs Seq(
|
||||||
Api.Response(requestId, Api.PushContextResponse(contextId)),
|
Api.Response(requestId, Api.PushContextResponse(contextId)),
|
||||||
Api.Response(
|
Api.Response(
|
||||||
Api.SuggestionsDatabaseReIndexNotification(
|
Api.SuggestionsDatabaseModuleUpdateNotification(
|
||||||
"Test.Main",
|
mainFile,
|
||||||
|
code,
|
||||||
Seq(
|
Seq(
|
||||||
|
Api.SuggestionsDatabaseUpdate.Clean(moduleName),
|
||||||
Api.SuggestionsDatabaseUpdate.Add(
|
Api.SuggestionsDatabaseUpdate.Add(
|
||||||
Suggestion.Method(
|
Suggestion.Method(
|
||||||
None,
|
None,
|
||||||
"Test.Main",
|
moduleName,
|
||||||
"main",
|
"main",
|
||||||
Seq(Suggestion.Argument("this", "Any", false, false, None)),
|
Seq(Suggestion.Argument("this", "Any", false, false, None)),
|
||||||
"Main",
|
"Main",
|
||||||
@ -2300,20 +2323,29 @@ class RuntimeServerTest
|
|||||||
),
|
),
|
||||||
TextEdit(
|
TextEdit(
|
||||||
model.Range(model.Position(2, 0), model.Position(2, 0)),
|
model.Range(model.Position(2, 0), model.Position(2, 0)),
|
||||||
"Number.lucky = 42\n\n"
|
s"Number.lucky = 42$newline$newline"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
val codeModified =
|
||||||
|
"""from Builtins import all
|
||||||
|
|
|
||||||
|
|Number.lucky = 42
|
||||||
|
|
|
||||||
|
|main = IO.println "I'm a modified!"
|
||||||
|
|""".stripMargin
|
||||||
context.receive(2) should contain theSameElementsAs Seq(
|
context.receive(2) should contain theSameElementsAs Seq(
|
||||||
Api.Response(
|
Api.Response(
|
||||||
Api.SuggestionsDatabaseUpdateNotification(
|
Api.SuggestionsDatabaseModuleUpdateNotification(
|
||||||
|
mainFile,
|
||||||
|
codeModified,
|
||||||
Seq(
|
Seq(
|
||||||
Api.SuggestionsDatabaseUpdate.Add(
|
Api.SuggestionsDatabaseUpdate.Add(
|
||||||
Suggestion.Method(
|
Suggestion.Method(
|
||||||
None,
|
None,
|
||||||
"Test.Main",
|
moduleName,
|
||||||
"lucky",
|
"lucky",
|
||||||
Seq(Suggestion.Argument("this", "Any", false, false, None)),
|
Seq(Suggestion.Argument("this", "Any", false, false, None)),
|
||||||
"Number",
|
"Number",
|
||||||
@ -2337,6 +2369,7 @@ class RuntimeServerTest
|
|||||||
it should "recompute expressions without invalidation" in {
|
it should "recompute expressions without invalidation" in {
|
||||||
val contents = context.Main.code
|
val contents = context.Main.code
|
||||||
val mainFile = context.writeMain(contents)
|
val mainFile = context.writeMain(contents)
|
||||||
|
val moduleName = "Test.Main"
|
||||||
val contextId = UUID.randomUUID()
|
val contextId = UUID.randomUUID()
|
||||||
val requestId = UUID.randomUUID()
|
val requestId = UUID.randomUUID()
|
||||||
|
|
||||||
@ -2354,7 +2387,7 @@ class RuntimeServerTest
|
|||||||
|
|
||||||
// push main
|
// push main
|
||||||
val item1 = Api.StackItem.ExplicitCall(
|
val item1 = Api.StackItem.ExplicitCall(
|
||||||
Api.MethodPointer("Test.Main", "Main", "main"),
|
Api.MethodPointer(moduleName, "Main", "main"),
|
||||||
None,
|
None,
|
||||||
Vector()
|
Vector()
|
||||||
)
|
)
|
||||||
@ -2382,6 +2415,7 @@ class RuntimeServerTest
|
|||||||
it should "recompute expressions invalidating all" in {
|
it should "recompute expressions invalidating all" in {
|
||||||
val contents = context.Main.code
|
val contents = context.Main.code
|
||||||
val mainFile = context.writeMain(contents)
|
val mainFile = context.writeMain(contents)
|
||||||
|
val moduleName = "Test.Main"
|
||||||
val contextId = UUID.randomUUID()
|
val contextId = UUID.randomUUID()
|
||||||
val requestId = UUID.randomUUID()
|
val requestId = UUID.randomUUID()
|
||||||
|
|
||||||
@ -2399,7 +2433,7 @@ class RuntimeServerTest
|
|||||||
|
|
||||||
// push main
|
// push main
|
||||||
val item1 = Api.StackItem.ExplicitCall(
|
val item1 = Api.StackItem.ExplicitCall(
|
||||||
Api.MethodPointer("Test.Main", "Main", "main"),
|
Api.MethodPointer(moduleName, "Main", "main"),
|
||||||
None,
|
None,
|
||||||
Vector()
|
Vector()
|
||||||
)
|
)
|
||||||
@ -2433,6 +2467,7 @@ class RuntimeServerTest
|
|||||||
it should "recompute expressions invalidating some" in {
|
it should "recompute expressions invalidating some" in {
|
||||||
val contents = context.Main.code
|
val contents = context.Main.code
|
||||||
val mainFile = context.writeMain(contents)
|
val mainFile = context.writeMain(contents)
|
||||||
|
val moduleName = "Test.Main"
|
||||||
val contextId = UUID.randomUUID()
|
val contextId = UUID.randomUUID()
|
||||||
val requestId = UUID.randomUUID()
|
val requestId = UUID.randomUUID()
|
||||||
|
|
||||||
@ -2450,7 +2485,7 @@ class RuntimeServerTest
|
|||||||
context.receiveNone shouldEqual None
|
context.receiveNone shouldEqual None
|
||||||
// push main
|
// push main
|
||||||
val item1 = Api.StackItem.ExplicitCall(
|
val item1 = Api.StackItem.ExplicitCall(
|
||||||
Api.MethodPointer("Test.Main", "Main", "main"),
|
Api.MethodPointer(moduleName, "Main", "main"),
|
||||||
None,
|
None,
|
||||||
Vector()
|
Vector()
|
||||||
)
|
)
|
||||||
@ -2851,6 +2886,7 @@ class RuntimeServerTest
|
|||||||
it should "emit visualisation update when expression is evaluated" in {
|
it should "emit visualisation update when expression is evaluated" in {
|
||||||
val contents = context.Main.code
|
val contents = context.Main.code
|
||||||
val mainFile = context.writeMain(context.Main.code)
|
val mainFile = context.writeMain(context.Main.code)
|
||||||
|
val moduleName = "Test.Main"
|
||||||
val visualisationFile =
|
val visualisationFile =
|
||||||
context.writeInSrcDir("Visualisation", context.Visualisation.code)
|
context.writeInSrcDir("Visualisation", context.Visualisation.code)
|
||||||
|
|
||||||
@ -2882,7 +2918,7 @@ class RuntimeServerTest
|
|||||||
|
|
||||||
// push main
|
// push main
|
||||||
val item1 = Api.StackItem.ExplicitCall(
|
val item1 = Api.StackItem.ExplicitCall(
|
||||||
Api.MethodPointer("Test.Main", "Main", "main"),
|
Api.MethodPointer(moduleName, "Main", "main"),
|
||||||
None,
|
None,
|
||||||
Vector()
|
Vector()
|
||||||
)
|
)
|
||||||
@ -2895,12 +2931,11 @@ class RuntimeServerTest
|
|||||||
context.Main.Update.mainY(contextId),
|
context.Main.Update.mainY(contextId),
|
||||||
context.Main.Update.mainZ(contextId),
|
context.Main.Update.mainZ(contextId),
|
||||||
Api.Response(
|
Api.Response(
|
||||||
Api.SuggestionsDatabaseIndexUpdateNotification(
|
Api.SuggestionsDatabaseModuleUpdateNotification(
|
||||||
Seq(
|
|
||||||
Api.IndexedModule(
|
|
||||||
visualisationFile,
|
visualisationFile,
|
||||||
context.Visualisation.code,
|
context.Visualisation.code,
|
||||||
Seq(
|
Seq(
|
||||||
|
Api.SuggestionsDatabaseUpdate.Clean("Test.Visualisation"),
|
||||||
Api.SuggestionsDatabaseUpdate.Add(
|
Api.SuggestionsDatabaseUpdate.Add(
|
||||||
Suggestion.Method(
|
Suggestion.Method(
|
||||||
None,
|
None,
|
||||||
@ -2931,8 +2966,6 @@ class RuntimeServerTest
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
|
||||||
)
|
|
||||||
),
|
),
|
||||||
context.executionSuccessful(contextId)
|
context.executionSuccessful(contextId)
|
||||||
)
|
)
|
||||||
@ -3066,12 +3099,11 @@ class RuntimeServerTest
|
|||||||
context.Main.Update.mainY(contextId),
|
context.Main.Update.mainY(contextId),
|
||||||
context.Main.Update.mainZ(contextId),
|
context.Main.Update.mainZ(contextId),
|
||||||
Api.Response(
|
Api.Response(
|
||||||
Api.SuggestionsDatabaseIndexUpdateNotification(
|
Api.SuggestionsDatabaseModuleUpdateNotification(
|
||||||
Seq(
|
|
||||||
Api.IndexedModule(
|
|
||||||
visualisationFile,
|
visualisationFile,
|
||||||
context.Visualisation.code,
|
context.Visualisation.code,
|
||||||
Seq(
|
Seq(
|
||||||
|
Api.SuggestionsDatabaseUpdate.Clean("Test.Visualisation"),
|
||||||
Api.SuggestionsDatabaseUpdate.Add(
|
Api.SuggestionsDatabaseUpdate.Add(
|
||||||
Suggestion.Method(
|
Suggestion.Method(
|
||||||
None,
|
None,
|
||||||
@ -3102,13 +3134,13 @@ class RuntimeServerTest
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
|
||||||
)
|
|
||||||
),
|
),
|
||||||
Api.Response(
|
Api.Response(
|
||||||
Api.SuggestionsDatabaseReIndexNotification(
|
Api.SuggestionsDatabaseModuleUpdateNotification(
|
||||||
moduleName,
|
mainFile,
|
||||||
|
contents,
|
||||||
Seq(
|
Seq(
|
||||||
|
Api.SuggestionsDatabaseUpdate.Clean(moduleName),
|
||||||
Api.SuggestionsDatabaseUpdate.Add(
|
Api.SuggestionsDatabaseUpdate.Add(
|
||||||
Suggestion.Method(
|
Suggestion.Method(
|
||||||
None,
|
None,
|
||||||
|
@ -112,6 +112,17 @@ class StdlibRuntimeServerTest
|
|||||||
Iterator.continually(receive(timeout)).take(n).flatten.toList
|
Iterator.continually(receive(timeout)).take(n).flatten.toList
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def receiveAllUntil(
|
||||||
|
msg: Api.Response,
|
||||||
|
timeout: Long
|
||||||
|
): List[Api.Response] = {
|
||||||
|
Iterator
|
||||||
|
.continually(receive(timeout))
|
||||||
|
.takeWhile(received => received.isDefined && received != Some(msg))
|
||||||
|
.flatten
|
||||||
|
.toList
|
||||||
|
}
|
||||||
|
|
||||||
def consumeOut: List[String] = {
|
def consumeOut: List[String] = {
|
||||||
val result = out.toString
|
val result = out.toString
|
||||||
out.reset()
|
out.reset()
|
||||||
@ -169,22 +180,22 @@ class StdlibRuntimeServerTest
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
val response = context.receiveN(3, timeout = 30)
|
val response =
|
||||||
response.length shouldEqual 3
|
context.receiveAllUntil(
|
||||||
response should contain allOf (
|
context.executionSuccessful(contextId),
|
||||||
Api.Response(requestId, Api.PushContextResponse(contextId)),
|
timeout = 30
|
||||||
context.executionSuccessful(contextId)
|
|
||||||
)
|
)
|
||||||
response.collect {
|
response should contain (
|
||||||
|
Api.Response(requestId, Api.PushContextResponse(contextId))
|
||||||
|
)
|
||||||
|
val collected = response.collect {
|
||||||
case Api.Response(
|
case Api.Response(
|
||||||
None,
|
None,
|
||||||
Api.SuggestionsDatabaseIndexUpdateNotification(xs)
|
Api.SuggestionsDatabaseModuleUpdateNotification(_, _, xs)
|
||||||
) =>
|
) =>
|
||||||
xs.nonEmpty shouldBe true
|
xs.nonEmpty shouldBe true
|
||||||
xs.flatMap(
|
}
|
||||||
_.updates.headOption.map(_.suggestion.module)
|
collected.nonEmpty shouldBe true
|
||||||
) should not contain "Test.Main"
|
|
||||||
} should have length 1
|
|
||||||
|
|
||||||
context.consumeOut shouldEqual List("Hello World!")
|
context.consumeOut shouldEqual List("Hello World!")
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,12 @@ trait FileVersionsRepo[F[_]] {
|
|||||||
*/
|
*/
|
||||||
def updateVersion(file: File, digest: Array[Byte]): F[Boolean]
|
def updateVersion(file: File, digest: Array[Byte]): F[Boolean]
|
||||||
|
|
||||||
|
/** Update the versions in batch.
|
||||||
|
*
|
||||||
|
* @param versions files with corresponding digests
|
||||||
|
*/
|
||||||
|
def updateVersions(versions: Seq[(File, Array[Byte])]): F[Unit]
|
||||||
|
|
||||||
/** Remove the version record.
|
/** Remove the version record.
|
||||||
*
|
*
|
||||||
* @param file the file path
|
* @param file the file path
|
||||||
|
@ -269,6 +269,7 @@ final class SqlSuggestionsRepo(db: SqlDatabase)(implicit ec: ExecutionContext)
|
|||||||
private def removeQuery(suggestion: Suggestion): DBIO[Option[Long]] = {
|
private def removeQuery(suggestion: Suggestion): DBIO[Option[Long]] = {
|
||||||
val (raw, _) = toSuggestionRow(suggestion)
|
val (raw, _) = toSuggestionRow(suggestion)
|
||||||
val selectQuery = Suggestions
|
val selectQuery = Suggestions
|
||||||
|
.filter(_.module === raw.module)
|
||||||
.filter(_.kind === raw.kind)
|
.filter(_.kind === raw.kind)
|
||||||
.filter(_.name === raw.name)
|
.filter(_.name === raw.name)
|
||||||
.filter(_.scopeStartLine === raw.scopeStartLine)
|
.filter(_.scopeStartLine === raw.scopeStartLine)
|
||||||
@ -306,13 +307,18 @@ final class SqlSuggestionsRepo(db: SqlDatabase)(implicit ec: ExecutionContext)
|
|||||||
private def removeAllByModuleQuery(
|
private def removeAllByModuleQuery(
|
||||||
modules: Seq[String]
|
modules: Seq[String]
|
||||||
): DBIO[(Long, Seq[Long])] = {
|
): DBIO[(Long, Seq[Long])] = {
|
||||||
|
if (modules.nonEmpty) {
|
||||||
val selectQuery = Suggestions.filter(_.module inSet modules)
|
val selectQuery = Suggestions.filter(_.module inSet modules)
|
||||||
val deleteQuery = for {
|
for {
|
||||||
rows <- selectQuery.result
|
rows <- selectQuery.result
|
||||||
n <- selectQuery.delete
|
n <- selectQuery.delete
|
||||||
version <- if (n > 0) incrementVersionQuery else currentVersionQuery
|
version <- if (n > 0) incrementVersionQuery else currentVersionQuery
|
||||||
} yield version -> rows.flatMap(_.id)
|
} yield version -> rows.flatMap(_.id)
|
||||||
deleteQuery
|
} else {
|
||||||
|
for {
|
||||||
|
version <- currentVersionQuery
|
||||||
|
} yield (version, Seq())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** The query to remove a list of suggestions.
|
/** The query to remove a list of suggestions.
|
||||||
@ -418,6 +424,9 @@ final class SqlSuggestionsRepo(db: SqlDatabase)(implicit ec: ExecutionContext)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Create a search query by the provided parameters.
|
/** Create a search query by the provided parameters.
|
||||||
|
*
|
||||||
|
* Even if the module is specified, the response includes all available
|
||||||
|
* global symbols (atoms and method).
|
||||||
*
|
*
|
||||||
* @param module the module name search parameter
|
* @param module the module name search parameter
|
||||||
* @param selfType the selfType search parameter
|
* @param selfType the selfType search parameter
|
||||||
@ -435,7 +444,8 @@ final class SqlSuggestionsRepo(db: SqlDatabase)(implicit ec: ExecutionContext)
|
|||||||
): Query[SuggestionsTable, SuggestionRow, Seq] = {
|
): Query[SuggestionsTable, SuggestionRow, Seq] = {
|
||||||
Suggestions
|
Suggestions
|
||||||
.filterOpt(module) {
|
.filterOpt(module) {
|
||||||
case (row, value) => row.module === value
|
case (row, value) =>
|
||||||
|
row.scopeStartLine === ScopeColumn.EMPTY || row.module === value
|
||||||
}
|
}
|
||||||
.filterOpt(selfType) {
|
.filterOpt(selfType) {
|
||||||
case (row, value) => row.selfType === value
|
case (row, value) => row.selfType === value
|
||||||
|
@ -30,6 +30,12 @@ final class SqlVersionsRepo(db: SqlDatabase)(implicit ec: ExecutionContext)
|
|||||||
override def updateVersion(file: File, digest: Array[Byte]): Future[Boolean] =
|
override def updateVersion(file: File, digest: Array[Byte]): Future[Boolean] =
|
||||||
db.run(updateVersionQuery(file, digest))
|
db.run(updateVersionQuery(file, digest))
|
||||||
|
|
||||||
|
/** @inheritdoc */
|
||||||
|
override def updateVersions(
|
||||||
|
versions: Seq[(File, Array[Byte])]
|
||||||
|
): Future[Unit] =
|
||||||
|
db.run(updateVersionsQuery(versions))
|
||||||
|
|
||||||
/** @inheritdoc */
|
/** @inheritdoc */
|
||||||
override def remove(file: File): Future[Unit] =
|
override def remove(file: File): Future[Unit] =
|
||||||
db.run(removeQuery(file))
|
db.run(removeQuery(file))
|
||||||
@ -77,11 +83,10 @@ final class SqlVersionsRepo(db: SqlDatabase)(implicit ec: ExecutionContext)
|
|||||||
): DBIO[Option[Array[Byte]]] = {
|
): DBIO[Option[Array[Byte]]] = {
|
||||||
val upsertQuery = FileVersions
|
val upsertQuery = FileVersions
|
||||||
.insertOrUpdate(FileVersionRow(file.toString, version))
|
.insertOrUpdate(FileVersionRow(file.toString, version))
|
||||||
val query = for {
|
for {
|
||||||
version <- getVersionQuery(file)
|
version <- getVersionQuery(file)
|
||||||
_ <- upsertQuery
|
_ <- upsertQuery
|
||||||
} yield version
|
} yield version
|
||||||
query.transactionally
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** The query to update the version if it differs from the recorded version.
|
/** The query to update the version if it differs from the recorded version.
|
||||||
@ -102,6 +107,23 @@ final class SqlVersionsRepo(db: SqlDatabase)(implicit ec: ExecutionContext)
|
|||||||
else DBIO.successful(None)
|
else DBIO.successful(None)
|
||||||
} yield !versionsEquals
|
} yield !versionsEquals
|
||||||
|
|
||||||
|
|
||||||
|
/** The query to update the versions in batch.
|
||||||
|
*
|
||||||
|
* @param versions files with corresponding digests
|
||||||
|
*/
|
||||||
|
private def updateVersionsQuery(
|
||||||
|
versions: Seq[(File, Array[Byte])]
|
||||||
|
): DBIO[Unit] =
|
||||||
|
if (versions.nonEmpty) {
|
||||||
|
def upsertQuery(file: File, version: Array[Byte]) = FileVersions
|
||||||
|
.insertOrUpdate(FileVersionRow(file.toString, version))
|
||||||
|
DBIO.sequence(versions.map(Function.tupled(upsertQuery))) >>
|
||||||
|
DBIO.successful(())
|
||||||
|
} else {
|
||||||
|
DBIO.successful(())
|
||||||
|
}
|
||||||
|
|
||||||
/** The query to remove the version record.
|
/** The query to remove the version record.
|
||||||
*
|
*
|
||||||
* @param file the file path
|
* @param file the file path
|
||||||
|
@ -108,6 +108,28 @@ class FileVersionsRepoTest extends AnyWordSpec with Matchers with RetrySpec {
|
|||||||
b4 shouldBe false
|
b4 shouldBe false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
"batch update digest" taggedAs Retry in withRepo { repo =>
|
||||||
|
val file1 = new File("/foo/1")
|
||||||
|
val file2 = new File("/foo/2")
|
||||||
|
val digest0 = nextDigest()
|
||||||
|
val digest1 = nextDigest()
|
||||||
|
val digest2 = nextDigest()
|
||||||
|
val input = Seq(file1 -> digest1, file2 -> digest2)
|
||||||
|
val action =
|
||||||
|
for {
|
||||||
|
_ <- repo.setVersion(file1, digest0)
|
||||||
|
_ <- repo.updateVersions(input)
|
||||||
|
v1 <- repo.getVersion(file1)
|
||||||
|
v2 <- repo.getVersion(file2)
|
||||||
|
} yield (v1, v2)
|
||||||
|
|
||||||
|
val (v1, v2) = Await.result(action, Timeout)
|
||||||
|
v1 shouldBe a[Some[_]]
|
||||||
|
v2 shouldBe a[Some[_]]
|
||||||
|
util.Arrays.equals(v1.get, digest1) shouldBe true
|
||||||
|
util.Arrays.equals(v2.get, digest2) shouldBe true
|
||||||
|
}
|
||||||
|
|
||||||
"delete digest" taggedAs Retry in withRepo { repo =>
|
"delete digest" taggedAs Retry in withRepo { repo =>
|
||||||
val file = new File("/foo/bar")
|
val file = new File("/foo/bar")
|
||||||
val digest = nextDigest()
|
val digest = nextDigest()
|
||||||
|
@ -204,6 +204,23 @@ class SuggestionsRepoTest extends AnyWordSpec with Matchers with RetrySpec {
|
|||||||
inserted should contain theSameElementsAs removed
|
inserted should contain theSameElementsAs removed
|
||||||
}
|
}
|
||||||
|
|
||||||
|
"remove all suggestions by empty module" taggedAs Retry in withRepo { repo =>
|
||||||
|
val action = for {
|
||||||
|
(_, idsIns) <- repo.insertAll(
|
||||||
|
Seq(
|
||||||
|
suggestion.atom,
|
||||||
|
suggestion.method,
|
||||||
|
suggestion.function,
|
||||||
|
suggestion.local
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(_, idsRem) <- repo.removeAllByModule(Seq())
|
||||||
|
} yield (idsIns.flatten, idsRem)
|
||||||
|
|
||||||
|
val (_, removed) = Await.result(action, Timeout)
|
||||||
|
removed.isEmpty shouldBe true
|
||||||
|
}
|
||||||
|
|
||||||
"remove all suggestions" taggedAs Retry in withRepo { repo =>
|
"remove all suggestions" taggedAs Retry in withRepo { repo =>
|
||||||
val action = for {
|
val action = for {
|
||||||
(_, Seq(id1, _, _, id4)) <- repo.insertAll(
|
(_, Seq(id1, _, _, id4)) <- repo.insertAll(
|
||||||
@ -492,15 +509,15 @@ class SuggestionsRepoTest extends AnyWordSpec with Matchers with RetrySpec {
|
|||||||
|
|
||||||
"search suggestion by empty module" taggedAs Retry in withRepo { repo =>
|
"search suggestion by empty module" taggedAs Retry in withRepo { repo =>
|
||||||
val action = for {
|
val action = for {
|
||||||
_ <- repo.insert(suggestion.atom)
|
id1 <- repo.insert(suggestion.atom)
|
||||||
_ <- repo.insert(suggestion.method)
|
id2 <- repo.insert(suggestion.method)
|
||||||
_ <- repo.insert(suggestion.function)
|
_ <- repo.insert(suggestion.function)
|
||||||
_ <- repo.insert(suggestion.local)
|
_ <- repo.insert(suggestion.local)
|
||||||
res <- repo.search(Some(""), None, None, None, None)
|
res <- repo.search(Some(""), None, None, None, None)
|
||||||
} yield res._2
|
} yield (res._2, Seq(id1, id2))
|
||||||
|
|
||||||
val res = Await.result(action, Timeout)
|
val (res, globals) = Await.result(action, Timeout)
|
||||||
res.isEmpty shouldEqual true
|
res should contain theSameElementsAs globals.flatten
|
||||||
}
|
}
|
||||||
|
|
||||||
"search suggestion by self type" taggedAs Retry in withRepo { repo =>
|
"search suggestion by self type" taggedAs Retry in withRepo { repo =>
|
||||||
|
Loading…
Reference in New Issue
Block a user