Skip to content
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

Fixes #2395: The apoc.cypher.runSchemaFile doesn't support full text indexes (#3084) #3248

Merged
merged 1 commit into from
Mar 28, 2023
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 5 additions & 2 deletions extended/src/main/java/apoc/cypher/CypherExtended.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import apoc.util.collection.Iterators;
import org.apache.commons.lang3.StringUtils;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.QueryExecutionType;
import org.neo4j.graphdb.QueryStatistics;
import org.neo4j.graphdb.Result;
import org.neo4j.graphdb.Transaction;
Expand Down Expand Up @@ -222,8 +223,10 @@ private String removeShellControlCommands(String stmt) {
return stmt;
}

private boolean isSchemaOperation(String stmt) {
return stmt.matches("(?is).*(create|drop)\\s+(index|constraint).*");
private boolean isSchemaOperation(String statement) {
return db.executeTransactionally("EXPLAIN " + statement, Collections.emptyMap(),
res -> QueryExecutionType.QueryType.SCHEMA_WRITE.equals(res.getQueryExecutionType().queryType())
);
}
private boolean isPeriodicOperation(String stmt) {
return stmt.matches("(?is).*using\\s+periodic.*") || stmt.matches("(?is).*in\\s+transactions.*");
Expand Down
66 changes: 50 additions & 16 deletions extended/src/test/java/apoc/cypher/CypherExtendedTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
import org.neo4j.graphdb.Transaction;
import org.neo4j.graphdb.schema.ConstraintDefinition;
import org.neo4j.graphdb.schema.IndexDefinition;
import org.neo4j.graphdb.schema.IndexType;
import org.neo4j.graphdb.schema.Schema;
import org.neo4j.test.rule.DbmsRule;
import org.neo4j.test.rule.ImpermanentDbmsRule;

Expand All @@ -22,15 +24,19 @@
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.concurrent.TimeUnit;
import java.util.stream.StreamSupport;

import static apoc.ApocConfig.APOC_IMPORT_FILE_ENABLED;
import static apoc.ApocConfig.apocConfig;
import static apoc.util.TestUtil.testCall;
import static apoc.util.TestUtil.testCallCount;
import static apoc.util.TestUtil.testCallEmpty;
import static apoc.util.TestUtil.testResult;
import static apoc.util.Util.map;
import static org.hamcrest.Matchers.hasEntry;
import static org.junit.Assert.*;
import static org.neo4j.driver.internal.util.Iterables.count;

/**
* @author mh
Expand Down Expand Up @@ -61,8 +67,8 @@ public static void tearDown() {
public void clearDB() {
db.executeTransactionally("MATCH (n) DETACH DELETE n");
try (Transaction tx = db.beginTx()) {
tx.schema().getIndexes().forEach(IndexDefinition::drop);
tx.schema().getConstraints().forEach(ConstraintDefinition::drop);
tx.schema().getIndexes().forEach(IndexDefinition::drop);
tx.commit();
}
}
Expand Down Expand Up @@ -282,32 +288,60 @@ public void testRunFilesMultiple() throws Exception {
}

@Test
@Ignore
public void testSchemaRunFile() throws Exception {
public void testSchemaRunFile() {
final int expectedBefore;
try (Transaction tx = db.beginTx()) {
expectedBefore = count(tx.schema().getIndexes());
}

testResult(db, "CALL apoc.cypher.runSchemaFile('schema.cypher')",
r -> {
Map<String, Object> row = r.next();
Map result = (Map) row.get("result");
assertEquals(1L, toLong(result.get("indexesAdded")));
});
}

@Test
@Ignore
public void testSchemaRunFiles() throws Exception {
testResult(db, "CALL apoc.cypher.runSchemaFiles(['constraints.cypher', 'drop_constraints.cypher', 'index.cypher'])",
r -> {
Map<String, Object> row = r.next();
Map result = (Map) row.get("result");
assertEquals(1L, toLong(result.get("constraintsAdded")));
row = r.next();
result = (Map) row.get("result");
assertEquals(1L, toLong(result.get("constraintsRemoved")));
assertEquals(1L, toLong(result.get("indexesAdded")));
row = r.next();
result = (Map) row.get("result");
assertEquals(1L, toLong(result.get("indexesAdded")));

row = r.next();
result = (Map) row.get("result");
assertEquals(1L, toLong(result.get("indexesAdded")));
assertFalse(r.hasNext());
});

try (Transaction tx = db.beginTx()) {
assertEquals(expectedBefore + 4, count(tx.schema().getIndexes()));
}
}

@Test
public void testSchemaRunFiles() {
schemaAssertions(Collections.emptyList(), Collections.emptyList());

testCallEmpty(db, "CALL apoc.cypher.runSchemaFiles($files, {statistics: false})",
map("files", List.of("constraints.cypher", "drop_constraints.cypher", "schema.cypher")));

final List<String> another_cons = List.of("CustomerIndex1", "CustomerIndex21", "CustomerIndex231", "another_cons", "node_index_name");
final List<String> another_cons1 = List.of("another_cons");

schemaAssertions(another_cons, another_cons1);
}

private void schemaAssertions(List<String> expectedIdx, List<String> expectedCons) {
try (Transaction tx = db.beginTx()) {
final Schema schema = tx.schema();
schema.awaitIndexesOnline(20, TimeUnit.SECONDS);
final List<String> actualIdx = StreamSupport.stream(schema.getIndexes().spliterator(), false)
.filter(idx -> !idx.getIndexType().equals(IndexType.LOOKUP))
.map(IndexDefinition::getName).sorted().collect(Collectors.toList());
final List<String> actualCons = StreamSupport.stream(schema.getConstraints().spliterator(), false)
.map(ConstraintDefinition::getName).sorted()
.collect(Collectors.toList());
assertEquals(expectedIdx, actualIdx);
assertEquals(expectedCons, actualCons);
}
}

@Test
Expand Down
3 changes: 2 additions & 1 deletion extended/src/test/resources/constraints.cypher
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
CREATE CONSTRAINT uniqueConstraint FOR (n:Person) REQUIRE n.name IS UNIQUE;
CREATE CONSTRAINT uniqueConstraint FOR (n:Person) REQUIRE n.name IS UNIQUE;
CREATE CONSTRAINT another_cons FOR (n:AnotherLabel) REQUIRE n.name IS UNIQUE;
5 changes: 4 additions & 1 deletion extended/src/test/resources/schema.cypher
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
CREATE INDEX FOR (n:Node) ON (n.id);
CREATE FULLTEXT INDEX CustomerIndex1 FOR (n:Customer1) ON EACH [n.name1];
CREATE FULLTEXT INDEX CustomerIndex21 FOR (n:Customer21) ON EACH [n.name12];
CREATE FULLTEXT INDEX CustomerIndex231 FOR (n:Customer213) ON EACH [n.name123];
CREATE INDEX node_index_name FOR (n:Person) ON (n.surname);
2 changes: 2 additions & 0 deletions full/src/test/resources/constraints.cypher
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
CREATE CONSTRAINT ON (n:Person) ASSERT n.name IS UNIQUE;
CREATE CONSTRAINT another_cons ON (n:AnotherLabel) ASSERT n.name IS UNIQUE;
4 changes: 4 additions & 0 deletions full/src/test/resources/schema.cypher
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
CREATE FULLTEXT INDEX CustomerIndex1 FOR (n:Customer1) ON EACH [n.name1];
CREATE FULLTEXT INDEX CustomerIndex21 FOR (n:Customer21) ON EACH [n.name12];
CREATE FULLTEXT INDEX CustomerIndex231 FOR (n:Customer213) ON EACH [n.name123];
CREATE INDEX node_index_name FOR (n:Person) ON (n.surname);