diff --git a/database/api/src/main/java/com/albertoventurini/graphdbplugin/database/api/GraphDatabaseApi.java b/database/api/src/main/java/com/albertoventurini/graphdbplugin/database/api/GraphDatabaseApi.java index 91426ad2..df793370 100644 --- a/database/api/src/main/java/com/albertoventurini/graphdbplugin/database/api/GraphDatabaseApi.java +++ b/database/api/src/main/java/com/albertoventurini/graphdbplugin/database/api/GraphDatabaseApi.java @@ -6,6 +6,7 @@ */ package com.albertoventurini.graphdbplugin.database.api; +import com.albertoventurini.graphdbplugin.database.api.data.GraphDatabaseVersion; import com.albertoventurini.graphdbplugin.database.api.data.GraphMetadata; import com.albertoventurini.graphdbplugin.database.api.query.GraphQueryResult; @@ -18,4 +19,6 @@ public interface GraphDatabaseApi { GraphQueryResult execute(String query, Map statementParameters); GraphMetadata metadata(); + + GraphDatabaseVersion getVersion(); } diff --git a/database/api/src/main/java/com/albertoventurini/graphdbplugin/database/api/data/GraphDatabaseVersion.java b/database/api/src/main/java/com/albertoventurini/graphdbplugin/database/api/data/GraphDatabaseVersion.java new file mode 100644 index 00000000..7db07ee8 --- /dev/null +++ b/database/api/src/main/java/com/albertoventurini/graphdbplugin/database/api/data/GraphDatabaseVersion.java @@ -0,0 +1,15 @@ +/** + * Copied and adapted from plugin + * Graph Database Support + * by Neueda Technologies, Ltd. + * Modified by Alberto Venturini, 2022 + */ +package com.albertoventurini.graphdbplugin.database.api.data; + +public interface GraphDatabaseVersion { + String toString(); + + String idFunction(); + + Object idToParameter(String id); +} diff --git a/database/neo4j/src/main/java/com/albertoventurini/graphdbplugin/database/neo4j/bolt/Neo4jBoltDatabase.java b/database/neo4j/src/main/java/com/albertoventurini/graphdbplugin/database/neo4j/bolt/Neo4jBoltDatabase.java index d83479bf..e8d0c99b 100644 --- a/database/neo4j/src/main/java/com/albertoventurini/graphdbplugin/database/neo4j/bolt/Neo4jBoltDatabase.java +++ b/database/neo4j/src/main/java/com/albertoventurini/graphdbplugin/database/neo4j/bolt/Neo4jBoltDatabase.java @@ -7,9 +7,12 @@ package com.albertoventurini.graphdbplugin.database.neo4j.bolt; import com.albertoventurini.graphdbplugin.database.api.GraphDatabaseApi; +import com.albertoventurini.graphdbplugin.database.api.data.GraphDatabaseVersion; import com.albertoventurini.graphdbplugin.database.api.data.GraphMetadata; import com.albertoventurini.graphdbplugin.database.api.query.GraphQueryResult; +import com.albertoventurini.graphdbplugin.database.neo4j.bolt.data.Neo4jGraphDatabaseVersion; import com.albertoventurini.graphdbplugin.database.neo4j.bolt.query.Neo4jBoltQueryResult; +import com.albertoventurini.graphdbplugin.database.neo4j.bolt.query.Neo4jBoltQueryResultRow; import org.neo4j.driver.AuthToken; import org.neo4j.driver.AuthTokens; import org.neo4j.driver.Driver; @@ -21,14 +24,21 @@ import org.neo4j.driver.exceptions.ClientException; import java.nio.channels.UnresolvedAddressException; +import java.util.Arrays; import java.util.Collections; import java.util.Map; +import java.util.stream.IntStream; /** * Communicates with Neo4j 3.0+ database using Bolt driver. */ public class Neo4jBoltDatabase implements GraphDatabaseApi { + private static final String VERSION_QUERY = """ + CALL dbms.components() YIELD versions + RETURN versions[0] AS version + """; + private final String url; private final AuthToken auth; private final SessionConfig dbConfig; @@ -110,4 +120,19 @@ public GraphQueryResult execute(String query, Map statementParam public GraphMetadata metadata() { throw new IllegalStateException("Not implemented"); } + + @Override + public GraphDatabaseVersion getVersion() { + var result = execute(VERSION_QUERY); + var row = result.getRows().get(0); + var neo4jRow = (Neo4jBoltQueryResultRow) row; + var rawVersion = neo4jRow.getValue("version").asString(); + var parsedVersion = IntStream.concat( + Arrays.stream(rawVersion.split("\\.", 4)) + .limit(3) + .mapToInt(Integer::parseInt), + IntStream.generate(() -> 0) + ).limit(3).toArray(); + return new Neo4jGraphDatabaseVersion(parsedVersion[0], parsedVersion[1], parsedVersion[2]); + } } diff --git a/database/neo4j/src/main/java/com/albertoventurini/graphdbplugin/database/neo4j/bolt/data/Neo4jBoltNode.java b/database/neo4j/src/main/java/com/albertoventurini/graphdbplugin/database/neo4j/bolt/data/Neo4jBoltNode.java index 3151f3c9..ef4f3d77 100644 --- a/database/neo4j/src/main/java/com/albertoventurini/graphdbplugin/database/neo4j/bolt/data/Neo4jBoltNode.java +++ b/database/neo4j/src/main/java/com/albertoventurini/graphdbplugin/database/neo4j/bolt/data/Neo4jBoltNode.java @@ -21,7 +21,7 @@ public class Neo4jBoltNode implements GraphNode { private final List types; public Neo4jBoltNode(Node value) { - this.id = String.valueOf(value.id()); + this.id = String.valueOf(value.elementId()); this.types = Iterables.asList(value.labels()); this.propertyContainer = new Neo4jBoltPropertyContainer(value.asMap()); } diff --git a/database/neo4j/src/main/java/com/albertoventurini/graphdbplugin/database/neo4j/bolt/data/Neo4jBoltRelationship.java b/database/neo4j/src/main/java/com/albertoventurini/graphdbplugin/database/neo4j/bolt/data/Neo4jBoltRelationship.java index 057148ce..1ceb6bb5 100644 --- a/database/neo4j/src/main/java/com/albertoventurini/graphdbplugin/database/neo4j/bolt/data/Neo4jBoltRelationship.java +++ b/database/neo4j/src/main/java/com/albertoventurini/graphdbplugin/database/neo4j/bolt/data/Neo4jBoltRelationship.java @@ -26,12 +26,12 @@ public class Neo4jBoltRelationship implements GraphRelationship { private GraphNode endNode; public Neo4jBoltRelationship(Relationship rel) { - this.id = String.valueOf(rel.id()); + this.id = String.valueOf(rel.elementId()); this.types = Collections.singletonList(rel.type()); this.propertyContainer = new Neo4jBoltPropertyContainer(rel.asMap()); - this.startNodeId = String.valueOf(rel.startNodeId()); - this.endNodeId = String.valueOf(rel.endNodeId()); + this.startNodeId = String.valueOf(rel.startNodeElementId()); + this.endNodeId = String.valueOf(rel.endNodeElementId()); } public Neo4jBoltRelationship(String id, List types, GraphPropertyContainer propertyContainer, String startNodeId, String endNodeId) { diff --git a/database/neo4j/src/main/java/com/albertoventurini/graphdbplugin/database/neo4j/bolt/data/Neo4jGraphDatabaseVersion.java b/database/neo4j/src/main/java/com/albertoventurini/graphdbplugin/database/neo4j/bolt/data/Neo4jGraphDatabaseVersion.java new file mode 100644 index 00000000..131934e1 --- /dev/null +++ b/database/neo4j/src/main/java/com/albertoventurini/graphdbplugin/database/neo4j/bolt/data/Neo4jGraphDatabaseVersion.java @@ -0,0 +1,33 @@ +/** + * Copied and adapted from plugin + * Graph Database Support + * by Neueda Technologies, Ltd. + * Modified by Alberto Venturini, 2022 + */ +package com.albertoventurini.graphdbplugin.database.neo4j.bolt.data; + +import com.albertoventurini.graphdbplugin.database.api.data.GraphDatabaseVersion; + +public record Neo4jGraphDatabaseVersion(int major, int minor, int patch) implements GraphDatabaseVersion { + + @Override + public String toString() { + return "Neo4j/" + major + "." + minor + "." + patch; + } + + @Override + public String idFunction() { + if (major >= 5) { + return "elementId"; + } + return "id"; + } + + @Override + public Object idToParameter(String id) { + if (major >= 5) { + return id; + } + return Long.parseLong(id); + } +} diff --git a/graph-database-plugin/src/main/resources/META-INF/plugin.xml b/graph-database-plugin/src/main/resources/META-INF/plugin.xml index 1e77c982..d9d8cabe 100644 --- a/graph-database-plugin/src/main/resources/META-INF/plugin.xml +++ b/graph-database-plugin/src/main/resources/META-INF/plugin.xml @@ -130,6 +130,8 @@ serviceImplementation="com.albertoventurini.graphdbplugin.jetbrains.ui.datasource.DataSourcesView"/> + diff --git a/platform/src/main/java/icons/GraphIcons.java b/platform/src/main/java/icons/GraphIcons.java index 329f3b7b..f929ad7c 100644 --- a/platform/src/main/java/icons/GraphIcons.java +++ b/platform/src/main/java/icons/GraphIcons.java @@ -27,6 +27,7 @@ public static final class Window { } public static final class Nodes { + public static final Icon VERSION = AllIcons.Actions.InlayGear; public static final Icon INDEX = AllIcons.Nodes.ResourceBundle; public static final Icon CONSTRAINT = AllIcons.Nodes.C_protected; public static final Icon LABEL = AllIcons.Nodes.Class; diff --git a/testing/integration-neo4j/src/test/java/com/albertoventurini/graphdbplugin/test/integration/neo4j/tests/database/common/AbstractDataSourceMetadataTest.java b/testing/integration-neo4j/src/test/java/com/albertoventurini/graphdbplugin/test/integration/neo4j/tests/database/common/AbstractDataSourceMetadataTest.java index ec95b66a..2f47a94c 100644 --- a/testing/integration-neo4j/src/test/java/com/albertoventurini/graphdbplugin/test/integration/neo4j/tests/database/common/AbstractDataSourceMetadataTest.java +++ b/testing/integration-neo4j/src/test/java/com/albertoventurini/graphdbplugin/test/integration/neo4j/tests/database/common/AbstractDataSourceMetadataTest.java @@ -7,11 +7,9 @@ package com.albertoventurini.graphdbplugin.test.integration.neo4j.tests.database.common; import com.albertoventurini.graphdbplugin.jetbrains.component.datasource.metadata.DataSourceMetadata; -import com.albertoventurini.graphdbplugin.jetbrains.component.datasource.metadata.neo4j.Neo4jProcedureMetadata; import com.albertoventurini.graphdbplugin.jetbrains.component.datasource.state.DataSourceApi; import com.albertoventurini.graphdbplugin.test.integration.neo4j.util.base.BaseIntegrationTest; -import java.util.List; import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; @@ -32,13 +30,13 @@ public void setUp() throws Exception { public abstract DataSourceApi getDataSource(); public void testMetadataExists() throws ExecutionException, InterruptedException { - Optional metadata = component().dataSourcesMetadata().getMetadata(getDataSource()).get(); + Optional metadata = component().dataSourcesMetadata().updateMetadata(getDataSource()).get(); assertThat(metadata).isPresent(); } protected DataSourceMetadata getMetadata() { try { - CompletableFuture> futureMeta = component().dataSourcesMetadata().getMetadata(getDataSource()); + CompletableFuture> futureMeta = component().dataSourcesMetadata().updateMetadata(getDataSource()); return futureMeta.get(30, TimeUnit.SECONDS) .orElseThrow(() -> new IllegalStateException("Metadata should not be null")); } catch (InterruptedException | ExecutionException | TimeoutException e) { diff --git a/ui/jetbrains/src/main/java/com/albertoventurini/graphdbplugin/jetbrains/component/datasource/DataSourcesComponent.java b/ui/jetbrains/src/main/java/com/albertoventurini/graphdbplugin/jetbrains/component/datasource/DataSourcesComponent.java index 7fc3f825..c29f1c90 100644 --- a/ui/jetbrains/src/main/java/com/albertoventurini/graphdbplugin/jetbrains/component/datasource/DataSourcesComponent.java +++ b/ui/jetbrains/src/main/java/com/albertoventurini/graphdbplugin/jetbrains/component/datasource/DataSourcesComponent.java @@ -57,9 +57,7 @@ public DataSourcesComponentState getState() { } public void refreshAllMetadata() { - getDataSourceContainer().getDataSources().forEach(d -> { - componentMetadata.getMetadata(d); - }); + getDataSourceContainer().getDataSources().forEach(componentMetadata::updateMetadata); } // // @NotNull diff --git a/ui/jetbrains/src/main/java/com/albertoventurini/graphdbplugin/jetbrains/component/datasource/metadata/DataSourcesComponentMetadata.java b/ui/jetbrains/src/main/java/com/albertoventurini/graphdbplugin/jetbrains/component/datasource/metadata/DataSourcesComponentMetadata.java index ddba0490..3a704ef9 100644 --- a/ui/jetbrains/src/main/java/com/albertoventurini/graphdbplugin/jetbrains/component/datasource/metadata/DataSourcesComponentMetadata.java +++ b/ui/jetbrains/src/main/java/com/albertoventurini/graphdbplugin/jetbrains/component/datasource/metadata/DataSourcesComponentMetadata.java @@ -12,6 +12,7 @@ import com.albertoventurini.graphdbplugin.jetbrains.component.datasource.metadata.neo4j.Neo4jMetadataBuilder; import com.albertoventurini.graphdbplugin.jetbrains.component.datasource.metadata.neo4j.Neo4jRelationshipTypeMetadata; import com.albertoventurini.graphdbplugin.jetbrains.component.datasource.state.DataSourceApi; +import com.albertoventurini.graphdbplugin.jetbrains.database.VersionService; import com.albertoventurini.graphdbplugin.jetbrains.services.ExecutorService; import com.albertoventurini.graphdbplugin.jetbrains.ui.datasource.metadata.MetadataRetrieveEvent; import com.intellij.openapi.application.ApplicationManager; @@ -31,16 +32,18 @@ public class DataSourcesComponentMetadata { private CypherMetadataProviderService cypherMetadataProviderService; private ExecutorService executorService; private MessageBus messageBus; + private VersionService versionService; public DataSourcesComponentMetadata(final Project project) { messageBus = project.getMessageBus(); cypherMetadataProviderService = project.getService(CypherMetadataProviderService.class); executorService = ApplicationManager.getApplication().getService(ExecutorService.class); + versionService = project.getService(VersionService.class); handlers.put(DataSourceType.NEO4J_BOLT, new Neo4jMetadataBuilder()); } - public CompletableFuture> getMetadata(DataSourceApi dataSource) { + public CompletableFuture> updateMetadata(DataSourceApi dataSource) { MetadataRetrieveEvent metadataRetrieveEvent = messageBus.syncPublisher(MetadataRetrieveEvent.METADATA_RETRIEVE_EVENT); metadataRetrieveEvent.startMetadataRefresh(dataSource); @@ -84,5 +87,7 @@ private void updateNeo4jBoltMetadata(DataSourceApi dataSource, Neo4jMetadata met metadata.propertyKeys().forEach(container::addPropertyKey); metadata.procedures().forEach(p -> container.addProcedure(p.name(), p.signature(), p.description())); metadata.functions().forEach(f -> container.addFunction(f.name(), f.signature(), f.description())); + + versionService.updatedVersion(dataSource, metadata.version()); } } diff --git a/ui/jetbrains/src/main/java/com/albertoventurini/graphdbplugin/jetbrains/component/datasource/metadata/neo4j/Neo4jMetadata.java b/ui/jetbrains/src/main/java/com/albertoventurini/graphdbplugin/jetbrains/component/datasource/metadata/neo4j/Neo4jMetadata.java index 65a0f632..f389655a 100644 --- a/ui/jetbrains/src/main/java/com/albertoventurini/graphdbplugin/jetbrains/component/datasource/metadata/neo4j/Neo4jMetadata.java +++ b/ui/jetbrains/src/main/java/com/albertoventurini/graphdbplugin/jetbrains/component/datasource/metadata/neo4j/Neo4jMetadata.java @@ -1,10 +1,12 @@ package com.albertoventurini.graphdbplugin.jetbrains.component.datasource.metadata.neo4j; +import com.albertoventurini.graphdbplugin.database.api.data.GraphDatabaseVersion; import com.albertoventurini.graphdbplugin.jetbrains.component.datasource.metadata.DataSourceMetadata; import java.util.*; public record Neo4jMetadata( + GraphDatabaseVersion version, List functions, List procedures, List constraints, diff --git a/ui/jetbrains/src/main/java/com/albertoventurini/graphdbplugin/jetbrains/component/datasource/metadata/neo4j/Neo4jMetadataBuilder.java b/ui/jetbrains/src/main/java/com/albertoventurini/graphdbplugin/jetbrains/component/datasource/metadata/neo4j/Neo4jMetadataBuilder.java index 816a83cf..2959f18b 100644 --- a/ui/jetbrains/src/main/java/com/albertoventurini/graphdbplugin/jetbrains/component/datasource/metadata/neo4j/Neo4jMetadataBuilder.java +++ b/ui/jetbrains/src/main/java/com/albertoventurini/graphdbplugin/jetbrains/component/datasource/metadata/neo4j/Neo4jMetadataBuilder.java @@ -1,6 +1,8 @@ package com.albertoventurini.graphdbplugin.jetbrains.component.datasource.metadata.neo4j; import com.albertoventurini.graphdbplugin.database.api.GraphDatabaseApi; +import com.albertoventurini.graphdbplugin.database.api.data.GraphDatabaseVersion; +import com.albertoventurini.graphdbplugin.database.neo4j.bolt.data.Neo4jGraphDatabaseVersion; import com.albertoventurini.graphdbplugin.database.neo4j.bolt.query.Neo4jBoltQueryResultRow; import com.albertoventurini.graphdbplugin.jetbrains.component.datasource.metadata.DataSourceMetadata; import com.albertoventurini.graphdbplugin.jetbrains.component.datasource.metadata.MetadataBuilder; @@ -50,6 +52,7 @@ public DataSourceMetadata buildMetadata(DataSourceApi dataSource) { final var databaseManager = ApplicationManager.getApplication().getService(DatabaseManagerService.class); final GraphDatabaseApi db = databaseManager.getDatabaseFor(dataSource); + GraphDatabaseVersion version = new Neo4jGraphDatabaseVersion(0, 0, 0); final List indexes = new ArrayList<>(); final List procedures = new ArrayList<>(); final List constraints = new ArrayList<>(); @@ -60,8 +63,9 @@ public DataSourceMetadata buildMetadata(DataSourceApi dataSource) { procedures.addAll(getProcedures(db)); constraints.addAll(getConstraints(db)); functions.addAll(getFunctions(db)); + version = db.getVersion(); } catch (Exception e) { - LOG.warn("Unable to load indexes, constraints, procedures, or functions from the current database. Please upgrade to Neo4j 4.2+ to fix this."); + LOG.warn("Unable to load indexes, constraints, procedures, functions, or version from the current database. Please upgrade to Neo4j 4.2+ to fix this."); } final var propertyKeys = getPropertyKeys(db); @@ -69,6 +73,7 @@ public DataSourceMetadata buildMetadata(DataSourceApi dataSource) { final var relationshipTypes = getRelationshipTypes(db); return new Neo4jMetadata( + version, functions, procedures, constraints, diff --git a/ui/jetbrains/src/main/java/com/albertoventurini/graphdbplugin/jetbrains/database/DiffService.java b/ui/jetbrains/src/main/java/com/albertoventurini/graphdbplugin/jetbrains/database/DiffService.java index 2cf1b1e2..584c36d5 100644 --- a/ui/jetbrains/src/main/java/com/albertoventurini/graphdbplugin/jetbrains/database/DiffService.java +++ b/ui/jetbrains/src/main/java/com/albertoventurini/graphdbplugin/jetbrains/database/DiffService.java @@ -20,36 +20,42 @@ public class DiffService { private final QueryExecutionService service; + private final VersionService versionService; public DiffService(Project project) { - this.service = new QueryExecutionService(project, project.getMessageBus()); + service = new QueryExecutionService(project, project.getMessageBus()); + versionService = project.getService(VersionService.class); } public void updateNode(DataSourceApi api, GraphEntity oldNode, GraphEntity newNode) { - - String query = "MATCH (n) WHERE ID(n) = $id " + - diffLabels(oldNode.getTypes(), newNode.getTypes()) + - " SET n = $props" + - " RETURN n"; - service.executeQuery(api, new ExecuteQueryPayload(query, - ImmutableMap.of( - "id", Long.parseLong(oldNode.getId()), - "props", newNode.getPropertyContainer().getProperties()), - null)); + versionService.getVersion(api) + .thenAccept(version -> { + String query = "MATCH (n) WHERE " + version.idFunction() + "(n) = $id " + + diffLabels(oldNode.getTypes(), newNode.getTypes()) + + " SET n = $props" + + " RETURN n"; + service.executeQuery(api, new ExecuteQueryPayload(query, + ImmutableMap.of( + "id", version.idToParameter(oldNode.getId()), + "props", newNode.getPropertyContainer().getProperties()), + null)); + }); } public void updateRelationShip(DataSourceApi api, GraphEntity relationship, GraphEntity updatedRel) { - - String query = "MATCH ()-[n]->() WHERE ID(n) = $id " + - " SET n = $props" + - " RETURN n"; - service.executeQuery(api, new ExecuteQueryPayload(query, - ImmutableMap.of( - "id", Long.parseLong(relationship.getId()), - "props", updatedRel.getPropertyContainer().getProperties()), - null)); + versionService.getVersion(api) + .thenAccept(version -> { + String query = "MATCH ()-[n]->() WHERE " + version.idFunction() + "(n) = $id " + + " SET n = $props" + + " RETURN n"; + service.executeQuery(api, new ExecuteQueryPayload(query, + ImmutableMap.of( + "id", version.idToParameter(relationship.getId()), + "props", updatedRel.getPropertyContainer().getProperties()), + null)); + }); } public void saveNewNode(DataSourceApi api, GraphEntity newNode) { diff --git a/ui/jetbrains/src/main/java/com/albertoventurini/graphdbplugin/jetbrains/database/VersionService.java b/ui/jetbrains/src/main/java/com/albertoventurini/graphdbplugin/jetbrains/database/VersionService.java new file mode 100644 index 00000000..bf8c74aa --- /dev/null +++ b/ui/jetbrains/src/main/java/com/albertoventurini/graphdbplugin/jetbrains/database/VersionService.java @@ -0,0 +1,69 @@ +/** + * Copied and adapted from plugin + * Graph Database Support + * by Neueda Technologies, Ltd. + * Modified by Alberto Venturini, 2022 + */ +package com.albertoventurini.graphdbplugin.jetbrains.database; + +import com.albertoventurini.graphdbplugin.database.api.data.GraphDatabaseVersion; +import com.albertoventurini.graphdbplugin.jetbrains.component.datasource.state.DataSourceApi; +import com.albertoventurini.graphdbplugin.jetbrains.services.ExecutorService; +import com.albertoventurini.graphdbplugin.jetbrains.ui.console.event.VersionFetchingProcessEvent; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.project.Project; +import com.intellij.util.messages.MessageBus; + +import java.util.HashMap; +import java.util.concurrent.CompletableFuture; + +public final class VersionService { + private final HashMap> versionRegistry; + private final MessageBus messageBus; + private final DatabaseManagerService databaseManager; + private final ExecutorService executorService; + + VersionService(Project project) { + versionRegistry = new HashMap<>(); + messageBus = project.getMessageBus(); + databaseManager = ApplicationManager.getApplication().getService(DatabaseManagerService.class); + executorService = ApplicationManager.getApplication().getService(ExecutorService.class); + } + + public synchronized CompletableFuture getVersion(DataSourceApi api) { + final var key = api.getName(); + final var version = versionRegistry.get(key); + if (version != null && !version.isCompletedExceptionally()) { + return version; + } + final var future = fetchVersion(api); + versionRegistry.put(key, future); + return future; + } + + public synchronized void updatedVersion(DataSourceApi api, GraphDatabaseVersion version) { + final var key = api.getName(); + final var future = new CompletableFuture(); + future.complete(version); + versionRegistry.put(key, future); + } + + private CompletableFuture fetchVersion(DataSourceApi api) { + VersionFetchingProcessEvent event = messageBus.syncPublisher(VersionFetchingProcessEvent.VERSION_FETCHING_PROCESS_TOPIC); + event.processStarted(api); + final var future = new CompletableFuture(); + final var db = databaseManager.getDatabaseFor(api); + executorService.runInBackground( + db::getVersion, + version -> { + event.versionReceived(version); + future.complete(version); + }, + ex -> { + event.handleError(ex); + future.completeExceptionally(ex); + } + ); + return future; + } +} diff --git a/ui/jetbrains/src/main/java/com/albertoventurini/graphdbplugin/jetbrains/ui/console/event/VersionFetchingProcessEvent.java b/ui/jetbrains/src/main/java/com/albertoventurini/graphdbplugin/jetbrains/ui/console/event/VersionFetchingProcessEvent.java new file mode 100644 index 00000000..181d9962 --- /dev/null +++ b/ui/jetbrains/src/main/java/com/albertoventurini/graphdbplugin/jetbrains/ui/console/event/VersionFetchingProcessEvent.java @@ -0,0 +1,24 @@ +/** + * Copied and adapted from plugin + * Graph Database Support + * by Neueda Technologies, Ltd. + * Modified by Alberto Venturini, 2022 + */ +package com.albertoventurini.graphdbplugin.jetbrains.ui.console.event; + +import com.albertoventurini.graphdbplugin.database.api.data.GraphDatabaseVersion; +import com.albertoventurini.graphdbplugin.jetbrains.component.datasource.state.DataSourceApi; +import com.intellij.util.messages.Topic; + +public interface VersionFetchingProcessEvent { + + Topic VERSION_FETCHING_PROCESS_TOPIC = + Topic.create("GraphDatabaseConsole.VersionFetchingProcessTopic", VersionFetchingProcessEvent.class); + + void processStarted(DataSourceApi dataSource); + + void versionReceived(GraphDatabaseVersion version); + + + void handleError(Exception exception); +} diff --git a/ui/jetbrains/src/main/java/com/albertoventurini/graphdbplugin/jetbrains/ui/console/log/LogPanel.java b/ui/jetbrains/src/main/java/com/albertoventurini/graphdbplugin/jetbrains/ui/console/log/LogPanel.java index 662d32b7..e5bfe698 100644 --- a/ui/jetbrains/src/main/java/com/albertoventurini/graphdbplugin/jetbrains/ui/console/log/LogPanel.java +++ b/ui/jetbrains/src/main/java/com/albertoventurini/graphdbplugin/jetbrains/ui/console/log/LogPanel.java @@ -6,10 +6,12 @@ */ package com.albertoventurini.graphdbplugin.jetbrains.ui.console.log; +import com.albertoventurini.graphdbplugin.database.api.data.GraphDatabaseVersion; import com.albertoventurini.graphdbplugin.jetbrains.actions.execute.ExecuteQueryPayload; import com.albertoventurini.graphdbplugin.jetbrains.component.datasource.state.DataSourceApi; import com.albertoventurini.graphdbplugin.jetbrains.ui.console.event.QueryExecutionProcessEvent; import com.albertoventurini.graphdbplugin.jetbrains.ui.console.event.QueryParametersRetrievalErrorEvent; +import com.albertoventurini.graphdbplugin.jetbrains.ui.console.event.VersionFetchingProcessEvent; import com.albertoventurini.graphdbplugin.jetbrains.ui.datasource.interactions.DataSourceDialog; import com.albertoventurini.graphdbplugin.jetbrains.ui.datasource.metadata.MetadataRetrieveEvent; import com.intellij.execution.filters.TextConsoleBuilderFactory; @@ -17,7 +19,6 @@ import com.intellij.execution.ui.ConsoleViewContentType; import com.intellij.icons.AllIcons; import com.intellij.openapi.Disposable; -import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.popup.IconButton; import com.intellij.openapi.ui.popup.JBPopupFactory; @@ -26,7 +27,6 @@ import com.intellij.util.messages.MessageBus; import com.intellij.util.ui.JBUI; import com.albertoventurini.graphdbplugin.database.api.query.GraphQueryResult; -import com.albertoventurini.graphdbplugin.jetbrains.component.datasource.metadata.DataSourceMetadata; import com.albertoventurini.graphdbplugin.jetbrains.ui.console.GraphConsoleView; import org.jetbrains.annotations.Nullable; @@ -107,6 +107,26 @@ public void executionCompleted(ExecuteQueryPayload payload) { } }); + messageBus.connect().subscribe(VersionFetchingProcessEvent.VERSION_FETCHING_PROCESS_TOPIC, new VersionFetchingProcessEvent() { + @Override + public void processStarted(DataSourceApi dataSource) { + info(String.format("Fetching database version for %s:", dataSource.getName())); + newLine(); + } + + @Override + public void versionReceived(GraphDatabaseVersion version) { + info(String.format("Version discovered: %s", version)); + newLine(); + } + + @Override + public void handleError(Exception exception) { + error("Error occurred: "); + printException(exception); + } + }); + messageBus.connect().subscribe(MetadataRetrieveEvent.METADATA_RETRIEVE_EVENT, new MetadataRetrieveEvent() { @Override public void startMetadataRefresh(DataSourceApi nodeDataSource) { diff --git a/ui/jetbrains/src/main/java/com/albertoventurini/graphdbplugin/jetbrains/ui/datasource/metadata/DataSourceMetadataUpdateService.java b/ui/jetbrains/src/main/java/com/albertoventurini/graphdbplugin/jetbrains/ui/datasource/metadata/DataSourceMetadataUpdateService.java index 42c54c5d..e0a45427 100644 --- a/ui/jetbrains/src/main/java/com/albertoventurini/graphdbplugin/jetbrains/ui/datasource/metadata/DataSourceMetadataUpdateService.java +++ b/ui/jetbrains/src/main/java/com/albertoventurini/graphdbplugin/jetbrains/ui/datasource/metadata/DataSourceMetadataUpdateService.java @@ -59,15 +59,15 @@ public CompletableFuture updateDataSourceMetadataUi( final DataSourceType sourceType = nodeDataSource.getDataSourceType(); return treeUpdaters.get(sourceType) - .map(updater -> getMetadataAndApplyHandler(updater, node, nodeDataSource)) + .map(updater -> updateMetadataAndApplyHandler(updater, node, nodeDataSource)) .orElse(completedFuture(false)); } - private CompletableFuture getMetadataAndApplyHandler( + private CompletableFuture updateMetadataAndApplyHandler( final DataSourceTreeUpdater updater, final PatchedDefaultMutableTreeNode node, final DataSourceApi nodeDataSource) { - return dataSourcesComponent.getMetadata(nodeDataSource) + return dataSourcesComponent.updateMetadata(nodeDataSource) .thenApply(data -> data.map(d -> { updater.updateTree(node, d); return true; diff --git a/ui/jetbrains/src/main/java/com/albertoventurini/graphdbplugin/jetbrains/ui/datasource/metadata/Neo4jBoltTreeUpdater.java b/ui/jetbrains/src/main/java/com/albertoventurini/graphdbplugin/jetbrains/ui/datasource/metadata/Neo4jBoltTreeUpdater.java index 81c79641..bd573296 100644 --- a/ui/jetbrains/src/main/java/com/albertoventurini/graphdbplugin/jetbrains/ui/datasource/metadata/Neo4jBoltTreeUpdater.java +++ b/ui/jetbrains/src/main/java/com/albertoventurini/graphdbplugin/jetbrains/ui/datasource/metadata/Neo4jBoltTreeUpdater.java @@ -1,5 +1,6 @@ package com.albertoventurini.graphdbplugin.jetbrains.ui.datasource.metadata; +import com.albertoventurini.graphdbplugin.database.api.data.GraphDatabaseVersion; import com.albertoventurini.graphdbplugin.jetbrains.component.datasource.metadata.neo4j.*; import com.albertoventurini.graphdbplugin.jetbrains.component.datasource.state.DataSourceApi; import com.albertoventurini.graphdbplugin.jetbrains.ui.datasource.tree.LabelTreeNodeModel; @@ -20,6 +21,7 @@ */ final class Neo4jBoltTreeUpdater implements DataSourceTreeUpdater { + private static final String VERSION_TITLE = "version: %s"; private static final String RELATIONSHIP_TYPES_TITLE = "relationship types (%s)"; private static final String PROPERTY_KEYS_TITLE = "property keys"; private static final String LABELS_TITLE = "labels (%s)"; @@ -38,6 +40,7 @@ public void updateTree( TreeNodeModelApi model = (TreeNodeModelApi) dataSourceRootTreeNode.getUserObject(); DataSourceApi dataSourceApi = model.getDataSourceApi(); + dataSourceRootTreeNode.add(createVersionNode(neo4jMetadata.version(), dataSourceApi)); dataSourceRootTreeNode.add(createConstraintsNode(neo4jMetadata.constraints(), dataSourceApi)); dataSourceRootTreeNode.add(createIndexesNode(neo4jMetadata.indexes(), dataSourceApi)); dataSourceRootTreeNode.add(createLabelsNode(neo4jMetadata, dataSourceApi)); @@ -53,6 +56,16 @@ public void updateTree( } } + @NotNull + private PatchedDefaultMutableTreeNode createVersionNode( + final GraphDatabaseVersion version, + final DataSourceApi dataSourceApi) { + return of(new MetadataTreeNodeModel( + VERSION, + dataSourceApi, + VERSION_TITLE.formatted(version.toString()), + GraphIcons.Nodes.VERSION)); + } @NotNull private PatchedDefaultMutableTreeNode createFunctionNode( final List functionMetadata, diff --git a/ui/jetbrains/src/main/java/com/albertoventurini/graphdbplugin/jetbrains/ui/datasource/tree/Neo4jTreeNodeType.java b/ui/jetbrains/src/main/java/com/albertoventurini/graphdbplugin/jetbrains/ui/datasource/tree/Neo4jTreeNodeType.java index fb08ddd4..5beff0ee 100644 --- a/ui/jetbrains/src/main/java/com/albertoventurini/graphdbplugin/jetbrains/ui/datasource/tree/Neo4jTreeNodeType.java +++ b/ui/jetbrains/src/main/java/com/albertoventurini/graphdbplugin/jetbrains/ui/datasource/tree/Neo4jTreeNodeType.java @@ -9,6 +9,7 @@ public enum Neo4jTreeNodeType implements NodeType { ROOT, DATASOURCE, + VERSION, INDEXES, INDEX, CONSTRAINTS, diff --git a/ui/jetbrains/src/test/java/com/albertoventurini/graphdbplugin/jetbrains/ui/datasource/metadata/ContextMenuTest.java b/ui/jetbrains/src/test/java/com/albertoventurini/graphdbplugin/jetbrains/ui/datasource/metadata/ContextMenuTest.java index 4b655a4d..5c7dcab0 100644 --- a/ui/jetbrains/src/test/java/com/albertoventurini/graphdbplugin/jetbrains/ui/datasource/metadata/ContextMenuTest.java +++ b/ui/jetbrains/src/test/java/com/albertoventurini/graphdbplugin/jetbrains/ui/datasource/metadata/ContextMenuTest.java @@ -6,6 +6,7 @@ */ package com.albertoventurini.graphdbplugin.jetbrains.ui.datasource.metadata; +import com.albertoventurini.graphdbplugin.database.neo4j.bolt.data.Neo4jGraphDatabaseVersion; import com.albertoventurini.graphdbplugin.jetbrains.component.datasource.DataSourceType; import com.albertoventurini.graphdbplugin.jetbrains.component.datasource.metadata.neo4j.*; import com.albertoventurini.graphdbplugin.jetbrains.ui.datasource.metadata.dto.DataSourceContextMenu; @@ -28,11 +29,7 @@ import java.util.Enumeration; import java.util.HashMap; -import static java.util.Collections.singletonList; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.assertEquals; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; /** * Test that the correct context menu is associated with @@ -71,6 +68,7 @@ public void setUp() throws Exception { "List all labels in the database."); final Neo4jMetadata metadata = new Neo4jMetadata( + new Neo4jGraphDatabaseVersion(0, 0, 0), Collections.emptyList(), Collections.singletonList(procedure), Collections.singletonList(constraintMetadata), diff --git a/ui/jetbrains/src/test/java/com/albertoventurini/graphdbplugin/jetbrains/ui/datasource/metadata/DataSourceMetadataUpdateServiceTest.java b/ui/jetbrains/src/test/java/com/albertoventurini/graphdbplugin/jetbrains/ui/datasource/metadata/DataSourceMetadataUpdateServiceTest.java index d711dfe7..8d3b0064 100644 --- a/ui/jetbrains/src/test/java/com/albertoventurini/graphdbplugin/jetbrains/ui/datasource/metadata/DataSourceMetadataUpdateServiceTest.java +++ b/ui/jetbrains/src/test/java/com/albertoventurini/graphdbplugin/jetbrains/ui/datasource/metadata/DataSourceMetadataUpdateServiceTest.java @@ -33,7 +33,7 @@ public void setUp() throws Exception { final var treeUpdaters = mock(DataSourceTreeUpdaters.class); final var dataSourceMetadata = mock(DataSourceMetadata.class); - when(metadataComponent.getMetadata(any())) + when(metadataComponent.updateMetadata(any())) .thenReturn(CompletableFuture.completedFuture(Optional.of(dataSourceMetadata))); final var treeUpdater = mock(DataSourceTreeUpdater.class); diff --git a/ui/jetbrains/src/test/java/com/albertoventurini/graphdbplugin/jetbrains/ui/datasource/metadata/Neo4JBoltTreeUpdaterTest.java b/ui/jetbrains/src/test/java/com/albertoventurini/graphdbplugin/jetbrains/ui/datasource/metadata/Neo4JBoltTreeUpdaterTest.java index a4cb9593..79413e98 100644 --- a/ui/jetbrains/src/test/java/com/albertoventurini/graphdbplugin/jetbrains/ui/datasource/metadata/Neo4JBoltTreeUpdaterTest.java +++ b/ui/jetbrains/src/test/java/com/albertoventurini/graphdbplugin/jetbrains/ui/datasource/metadata/Neo4JBoltTreeUpdaterTest.java @@ -6,6 +6,7 @@ */ package com.albertoventurini.graphdbplugin.jetbrains.ui.datasource.metadata; +import com.albertoventurini.graphdbplugin.database.neo4j.bolt.data.Neo4jGraphDatabaseVersion; import com.albertoventurini.graphdbplugin.jetbrains.component.datasource.DataSourceType; import com.albertoventurini.graphdbplugin.jetbrains.component.datasource.metadata.neo4j.*; import com.albertoventurini.graphdbplugin.jetbrains.component.datasource.state.impl.DataSourceV1; @@ -58,6 +59,7 @@ public void setUp() { "List all labels in the database."); final Neo4jMetadata metadata = new Neo4jMetadata( + new Neo4jGraphDatabaseVersion(0, 0, 0), Collections.emptyList(), Collections.singletonList(procedure), Collections.singletonList(constraintMetadata),