Skip to content

Added neo4j db schema info #48

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 14, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -96,3 +96,5 @@ hs_err_pid*
idea-flex.skeleton
/book-dev
/_book
/.ideaDataSources
/dataSources
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ public static final class Window {
}

public static final class Nodes {
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;
public static final Icon RELATIONSHIP_TYPE = AllIcons.Vcs.Arrow_right;
public static final Icon PROPERTY_KEY = AllIcons.Nodes.Property;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
import java.util.Optional;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.toList;

public class DataSourcesComponentMetadata implements ProjectComponent {

private CypherMetadataProviderService cypherMetadataProviderService;
Expand Down Expand Up @@ -57,11 +59,16 @@ private DataSourceMetadata getNeo4jBoltMetadata(DataSourceApi dataSource) {
GraphDatabaseApi db = databaseManager.getDatabaseFor(dataSource);
Neo4jBoltCypherDataSourceMetadata metadata = new Neo4jBoltCypherDataSourceMetadata();

GraphQueryResult indexesResult = db.execute("CALL db.indexes()");
GraphQueryResult constraintsResult = db.execute("CALL db.constraints()");
GraphQueryResult labelsQueryResult = db.execute("CALL db.labels()");
GraphQueryResult relationshipQueryResult = db.execute("CALL db.relationshipTypes()");
GraphQueryResult propertyKeysResult = db.execute("CALL db.propertyKeys()");
GraphQueryResult storedProceduresResult = db.execute("CALL dbms.procedures()");

metadata.addIndexes(indexesResult);
metadata.addConstraints(constraintsResult);

List<String> listOfLabels = extractLabels(labelsQueryResult);
if (!listOfLabels.isEmpty()) {
GraphQueryResult labelCount = db.execute(queryLabelCount(listOfLabels));
Expand All @@ -78,8 +85,8 @@ private DataSourceMetadata getNeo4jBoltMetadata(DataSourceApi dataSource) {
metadata.addStoredProcedures(storedProceduresResult);

boolean supportsUserFunctions = metadata.getMetadata(Neo4jBoltCypherDataSourceMetadata.STORED_PROCEDURES)
.stream()
.anyMatch((map) -> map.get("name").equals("dbms.functions"));
.stream()
.anyMatch((map) -> map.get("name").equals("dbms.functions"));

if (supportsUserFunctions) {
GraphQueryResult userFunctionsResult = db.execute("CALL dbms.functions()");
Expand All @@ -92,31 +99,31 @@ private DataSourceMetadata getNeo4jBoltMetadata(DataSourceApi dataSource) {
private List<String> extractRelationshipTypes(GraphQueryResult relationshipQueryResult) {
GraphQueryResultColumn column = relationshipQueryResult.getColumns().get(0);
return relationshipQueryResult.getRows()
.stream()
.map(row -> (String) row.getValue(column))
.collect(Collectors.toList());
.stream()
.map(row -> (String) row.getValue(column))
.collect(toList());
}

private List<String> extractLabels(GraphQueryResult labelsQueryResult) {
GraphQueryResultColumn column = labelsQueryResult.getColumns().get(0);
return labelsQueryResult.getRows()
.stream()
.map(row -> (String) row.getValue(column))
.collect(Collectors.toList());
.stream()
.map(row -> (String) row.getValue(column))
.collect(toList());
}

private String queryRelationshipTypeCount(List<String> relationshipTypes) {
return relationshipTypes
.stream()
.map(relationshipType -> "MATCH ()-[r:" + relationshipType + "]->() RETURN count(r)")
.collect(Collectors.joining(" UNION "));
.stream()
.map(relationshipType -> "MATCH ()-[r:" + relationshipType + "]->() RETURN count(r)")
.collect(Collectors.joining(" UNION "));
}

private String queryLabelCount(List<String> labels) {
return labels
.stream()
.map(label -> "MATCH (n:" + label + ") RETURN count(n)")
.collect(Collectors.joining(" UNION "));
.stream()
.map(label -> "MATCH (n:" + label + ") RETURN count(n)")
.collect(Collectors.joining(" UNION "));
}

private void updateNeo4jBoltMetadata(DataSourceApi dataSource, Neo4jBoltCypherDataSourceMetadata metadata) {
Expand All @@ -125,23 +132,23 @@ private void updateNeo4jBoltMetadata(DataSourceApi dataSource, Neo4jBoltCypherDa
CypherMetadataContainer container = cypherMetadataProviderService.getContainer(dataSource.getName());

metadata.getLabels()
.stream()
.map(Neo4jLabelMetadata::getName)
.forEach(container::addLabel);
.stream()
.map(Neo4jLabelMetadata::getName)
.forEach(container::addLabel);
metadata.getRelationshipTypes()
.stream()
.map(Neo4jRelationshipTypeMetadata::getName)
.forEach(container::addRelationshipType);
.stream()
.map(Neo4jRelationshipTypeMetadata::getName)
.forEach(container::addRelationshipType);
metadata.getMetadata(Neo4jBoltCypherDataSourceMetadata.PROPERTY_KEYS).stream()
.map((row) -> row.get("propertyKey"))
.forEach(container::addPropertyKey);
.map((row) -> row.get("propertyKey"))
.forEach(container::addPropertyKey);
metadata.getMetadata(Neo4jBoltCypherDataSourceMetadata.STORED_PROCEDURES)
.forEach(row -> container.addProcedure(row.get("name"), row.get("signature"), row.get("description")));
.forEach(row -> container.addProcedure(row.get("name"), row.get("signature"), row.get("description")));

List<Map<String, String>> userFunctionMetadata = metadata.getMetadata(Neo4jBoltCypherDataSourceMetadata.USER_FUNCTIONS);
if (userFunctionMetadata != null) {
userFunctionMetadata
.forEach(row -> container.addUserFunction(row.get("name"), row.get("signature"), row.get("description")));
.forEach(row -> container.addUserFunction(row.get("name"), row.get("signature"), row.get("description")));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@

public class Neo4jBoltCypherDataSourceMetadata implements DataSourceMetadata {

public static final String INDEXES = "indexes";
public static final String CONSTRAINTS = "constraints";
public static final String PROPERTY_KEYS = "propertyKeys";
public static final String STORED_PROCEDURES = "procedures";
public static final String USER_FUNCTIONS = "functions";
Expand Down Expand Up @@ -94,4 +96,12 @@ public void addRelationshipType(Neo4jRelationshipTypeMetadata relationshipTypeMe
public List<Neo4jRelationshipTypeMetadata> getRelationshipTypes() {
return relationshipTypes;
}

public void addIndexes(GraphQueryResult indexesResult) {
addDataSourceMetadata(INDEXES, indexesResult);
}

public void addConstraints(GraphQueryResult constraintsResult) {
addDataSourceMetadata(CONSTRAINTS, constraintsResult);
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.neueda.jetbrains.plugin.graphdb.jetbrains.ui.datasource.metadata;

import com.intellij.ui.treeStructure.PatchedDefaultMutableTreeNode;
import com.neueda.jetbrains.plugin.graphdb.jetbrains.component.datasource.metadata.DataSourceMetadata;
import com.neueda.jetbrains.plugin.graphdb.jetbrains.component.datasource.metadata.DataSourcesComponentMetadata;
import com.neueda.jetbrains.plugin.graphdb.jetbrains.component.datasource.metadata.Neo4jBoltCypherDataSourceMetadata;
import com.neueda.jetbrains.plugin.graphdb.jetbrains.component.datasource.state.DataSourceApi;
Expand All @@ -10,6 +11,10 @@
import com.neueda.jetbrains.plugin.graphdb.jetbrains.ui.datasource.tree.TreeNodeModelApi;
import com.neueda.jetbrains.plugin.graphdb.platform.GraphIcons;

import javax.swing.tree.MutableTreeNode;
import java.util.List;
import java.util.Map;

import static com.neueda.jetbrains.plugin.graphdb.jetbrains.ui.datasource.tree.Neo4jTreeNodeType.*;

public class DataSourceMetadataUi {
Expand All @@ -19,6 +24,8 @@ public class DataSourceMetadataUi {
private static final String LABELS_TITLE = "labels (%s)";
private static final String STORED_PROCEDURES_TITLE = "stored procedures";
private static final String USER_FUNCTIONS_TITLE = "user functions";
private static final String INDEXES_TITLE = "indexes (%s)";
private static final String CONSTRAINTS_TITLE = "constraints (%s)";

private final DataSourcesComponentMetadata dataSourcesComponent;

Expand Down Expand Up @@ -46,6 +53,9 @@ boolean updateNeo4jBoltCypherMetadataUi(PatchedDefaultMutableTreeNode dataSource
TreeNodeModelApi model = (TreeNodeModelApi) dataSourceRootTreeNode.getUserObject();
DataSourceApi dataSourceApi = model.getDataSourceApi();

dataSourceRootTreeNode.add(createConstraintsNode(dataSourceMetadata, dataSourceApi));
dataSourceRootTreeNode.add(createIndexesNode(dataSourceMetadata, dataSourceApi));

// Labels
int labelCount = dataSourceMetadata.getLabels().size();
PatchedDefaultMutableTreeNode labelsTreeNode = new PatchedDefaultMutableTreeNode(
Expand Down Expand Up @@ -108,6 +118,35 @@ boolean updateNeo4jBoltCypherMetadataUi(PatchedDefaultMutableTreeNode dataSource
return true;
}

private MutableTreeNode createIndexesNode(DataSourceMetadata dataSourceMetadata, DataSourceApi dataSourceApi) {
List<Map<String, String>> indexesMetadata =
dataSourceMetadata.getMetadata(Neo4jBoltCypherDataSourceMetadata.INDEXES);
PatchedDefaultMutableTreeNode indexTreeNode = new PatchedDefaultMutableTreeNode(
new MetadataTreeNodeModel(INDEXES,
dataSourceApi,
String.format(INDEXES_TITLE, indexesMetadata.size()),
GraphIcons.Nodes.INDEX));
indexesMetadata
.forEach(row -> indexTreeNode.add(of(new MetadataTreeNodeModel(INDEX, dataSourceApi,
row.get("description").substring(6) + " " + row.get("state")))));

return indexTreeNode;
}

private MutableTreeNode createConstraintsNode(DataSourceMetadata dataSourceMetadata, DataSourceApi dataSourceApi) {
List<Map<String, String>> constraintsMetadata =
dataSourceMetadata.getMetadata(Neo4jBoltCypherDataSourceMetadata.CONSTRAINTS);
PatchedDefaultMutableTreeNode indexTreeNode = new PatchedDefaultMutableTreeNode(
new MetadataTreeNodeModel(CONSTRAINTS, dataSourceApi,
String.format(CONSTRAINTS_TITLE, constraintsMetadata.size()), GraphIcons.Nodes.CONSTRAINT));
constraintsMetadata
.forEach(row ->
indexTreeNode.add(of(new MetadataTreeNodeModel(CONSTRAINT, dataSourceApi,
row.get("description").substring(11)))));

return indexTreeNode;
}

private PatchedDefaultMutableTreeNode of(MetadataTreeNodeModel model) {
return new PatchedDefaultMutableTreeNode(model);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
public enum Neo4jTreeNodeType implements NodeType {
ROOT,
DATASOURCE,
INDEXES,
INDEX,
CONSTRAINTS,
CONSTRAINT,
LABELS,
LABEL,
RELATIONSHIPS,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,13 @@ public void setUp() {
HashMap<String, String> propertyKeys = new HashMap<>();
propertyKeys.put("propertyKey", PROPERTY);

HashMap<String, String> indexes = new HashMap<>();
indexes.put("description", "index ON (:aaa)");
indexes.put("state", "ONLINE");

HashMap<String, String> constraints = new HashMap<>();
constraints.put("description", "constraint ON (:aaa) UNIQUE");

HashMap<String, String> procedures = new HashMap<>();
procedures.put("signature", "db.labels() :: (label :: STRING?)");
procedures.put("name", "db.labels");
Expand All @@ -60,6 +67,8 @@ public void setUp() {
metadata.addDataSourceMetadata(PROPERTY_KEYS, singletonList(propertyKeys));
metadata.addDataSourceMetadata(STORED_PROCEDURES, singletonList(procedures));
metadata.addDataSourceMetadata(USER_FUNCTIONS, singletonList(new HashMap<>()));
metadata.addDataSourceMetadata(INDEXES, singletonList(indexes));
metadata.addDataSourceMetadata(CONSTRAINTS, singletonList(constraints));

ui.updateNeo4jBoltCypherMetadataUi(datasource, metadata);
}
Expand Down