Skip to content
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
17 changes: 12 additions & 5 deletions engine/src/main/java/com/arcadedb/graph/GraphEngine.java
Original file line number Diff line number Diff line change
Expand Up @@ -552,7 +552,10 @@ public boolean isVertexConnectedTo(final VertexInternal vertex, final Identifiab
return false;
}

public boolean isVertexConnectedTo(final VertexInternal vertex, final Identifiable toVertex, final Vertex.DIRECTION direction,
public boolean isVertexConnectedTo(
final VertexInternal vertex,
final Identifiable toVertex,
final Vertex.DIRECTION direction,
final String edgeType) {
if (toVertex == null)
throw new IllegalArgumentException("Destination vertex is null");
Expand All @@ -563,13 +566,17 @@ public boolean isVertexConnectedTo(final VertexInternal vertex, final Identifiab
if (edgeType == null)
throw new IllegalArgumentException("Edge type is null");

final int[] bucketFilter = vertex.getDatabase().getSchema().getType(edgeType).getBuckets(true).stream()
.mapToInt(x -> x.getFileId()).toArray();
final int[] bucketFilter = vertex.getDatabase()
.getSchema()
.getType(edgeType)
.getBuckets(true)
.stream()
.mapToInt(x -> x.getFileId())
.toArray();

if (direction == Vertex.DIRECTION.OUT || direction == Vertex.DIRECTION.BOTH) {
final EdgeLinkedList outEdges = getEdgeHeadChunk(vertex, Vertex.DIRECTION.OUT);
if (outEdges != null && outEdges.containsVertex(toVertex.getIdentity(), bucketFilter))
return true;
return outEdges != null && outEdges.containsVertex(toVertex.getIdentity(), bucketFilter);
}

if (direction == Vertex.DIRECTION.IN || direction == Vertex.DIRECTION.BOTH) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

import com.arcadedb.database.Database;
import com.arcadedb.exception.CommandSQLParsingException;
import com.arcadedb.index.TypeIndex;
import com.arcadedb.query.sql.parser.CreateEdgeStatement;
import com.arcadedb.query.sql.parser.Expression;
import com.arcadedb.query.sql.parser.Identifier;
Expand All @@ -28,8 +29,10 @@
import com.arcadedb.query.sql.parser.JsonArray;
import com.arcadedb.query.sql.parser.UpdateItem;
import com.arcadedb.schema.DocumentType;
import com.arcadedb.schema.EdgeType;

import java.util.*;
import java.util.ArrayList;
import java.util.List;

/**
* Created by luigidellaquila on 08/08/16.
Expand Down Expand Up @@ -85,7 +88,21 @@ public InsertExecutionPlan createExecutionPlan(final CommandContext context) {
handleGlobalLet(result, new Identifier("$__ARCADEDB_CREATE_EDGE_toV"), rightExpression, context);

final String uniqueIndexName;
uniqueIndexName = null;
if (context.getDatabase().getSchema().existsType(targetClass.getStringValue())) {
final EdgeType type = (EdgeType) context.getDatabase().getSchema().getType(targetClass.getStringValue());
uniqueIndexName = type.getAllIndexes(true)

.stream()
.peek(x -> System.out.println("Index: " + x.getName()))
.filter(TypeIndex::isUnique)
.filter(x -> x.getPropertyNames().size() == 2
&& x.getPropertyNames().contains("@out")
&& x.getPropertyNames().contains("@in"))
.map(TypeIndex::getName)
.findFirst()
.orElse(null);
} else
uniqueIndexName = null;

result.chain(
new CreateEdgesStep(targetClass, targetBucketName, uniqueIndexName, new Identifier("$__ARCADEDB_CREATE_EDGE_fromV"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,11 @@
import com.arcadedb.index.IndexCursor;
import com.arcadedb.query.sql.parser.Identifier;

import java.util.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;

/**
* Created by luigidellaquila on 28/11/16.
Expand All @@ -58,8 +62,14 @@ public class CreateEdgesStep extends AbstractExecutionStep {

private boolean initiated = false;

public CreateEdgesStep(final Identifier targetClass, final Identifier targetBucketName, final String uniqueIndex,
final Identifier fromAlias, final Identifier toAlias, final boolean unidirectional, final boolean ifNotExists,
public CreateEdgesStep(
final Identifier targetClass,
final Identifier targetBucketName,
final String uniqueIndex,
final Identifier fromAlias,
final Identifier toAlias,
final boolean unidirectional,
final boolean ifNotExists,
final CommandContext context) {
super(context);
this.targetClass = targetClass;
Expand Down Expand Up @@ -103,11 +113,20 @@ public Result next(final Object[] properties) {
if (currentTo == null)
throw new CommandExecutionException("Invalid TO vertex for edge");

if (ifNotExists)
if (ifNotExists) {
if (context.getDatabase().getGraphEngine()
.isVertexConnectedTo((VertexInternal) currentFrom, currentTo, Vertex.DIRECTION.OUT, targetClass.getStringValue()))
// SKIP CREATING EDGE
return null;
.isVertexConnectedTo((VertexInternal) currentFrom, currentTo, Vertex.DIRECTION.OUT, targetClass.getStringValue())) {

for (Edge existingEdge : context.getDatabase().getGraphEngine()
.getEdges((VertexInternal) currentFrom, Vertex.DIRECTION.OUT, targetClass.getStringValue())) {
if (existingEdge.getOut().equals(currentTo)) {
currentTo = null;
currentBatch++;
return new UpdatableResult(existingEdge.modify());
}
}
}
}

final String target = targetBucket != null ? "bucket:" + targetBucket.getStringValue() : targetClass.getStringValue();

Expand All @@ -119,7 +138,7 @@ public Result next(final Object[] properties) {
currentBatch++;
return result;
} finally {
if( context.isProfiling() ) {
if (context.isProfiling()) {
cost += (System.nanoTime() - begin);
}
}
Expand Down Expand Up @@ -223,7 +242,7 @@ protected void loadNextFromTo() {
this.currentTo = null;
}
} finally {
if( context.isProfiling() ) {
if (context.isProfiling()) {
cost += (System.nanoTime() - begin);
}
}
Expand Down Expand Up @@ -271,7 +290,7 @@ public String prettyPrint(final int depth, final int indent) {
result += spaces + " FOR EACH y in " + toAlias + "\n";
result +=
spaces + " CREATE EDGE " + targetClass + " FROM x TO y " + (unidirectional ? "UNIDIRECTIONAL" : "BIDIRECTIONAL");
if ( context.isProfiling() )
if (context.isProfiling())
result += " (" + getCostFormatted() + ")";

if (targetBucket != null)
Expand All @@ -287,8 +306,14 @@ public boolean canBeCached() {

@Override
public ExecutionStep copy(final CommandContext context) {
return new CreateEdgesStep(targetClass == null ? null : targetClass.copy(), targetBucket == null ? null : targetBucket.copy(),
uniqueIndexName, fromAlias == null ? null : fromAlias.copy(), toAlias == null ? null : toAlias.copy(), unidirectional,
ifNotExists, context);
return new CreateEdgesStep(
targetClass == null ? null : targetClass.copy(),
targetBucket == null ? null : targetBucket.copy(),
uniqueIndexName,
fromAlias == null ? null : fromAlias.copy(),
toAlias == null ? null : toAlias.copy(),
unidirectional,
ifNotExists,
context);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import com.arcadedb.exception.CommandSQLParsingException;
import com.arcadedb.graph.Edge;
import com.arcadedb.graph.MutableVertex;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.assertThat;
Expand Down Expand Up @@ -96,4 +97,52 @@ public void errorEdgesContentJsonArray() {
// EXPECTED
}
}

@Test
@DisplayName("createEdgeIfNotExists - test Issue #1763")
void createEdgeIfNotExists() {
database.transaction(() -> {
database.command("sqlscript", """
CREATE VERTEX TYPE vex;
CREATE EDGE TYPE edg;
CREATE PROPERTY edg.label STRING;
CREATE VERTEX vex;
CREATE VERTEX vex;
CREATE VERTEX vex;
""");
});

database.transaction(() -> {
final ResultSet rs = database.query("SQL", """
select from vex
""");
assertThat(rs.stream().count()).isEqualTo(3);
});
// CREATE EDGES FROM #1:0 TO [#1:1,#1:2]
database.transaction(() -> {
final ResultSet rs = database.command("sql", """
CREATE EDGE edg FROM #1:0 TO [#1:1,#1:2] IF NOT EXISTS
""");
assertThat(rs.stream().count()).isEqualTo(2);
});

// CREATE AGAIN (should not create any edge)
database.transaction(() -> {
final ResultSet rs = database.command("sql", """
CREATE EDGE edg FROM #1:0 TO [#1:1,#1:2] IF NOT EXISTS
""");
assertThat(rs.hasNext()).isTrue();
assertThat(rs.stream().count()).isEqualTo(2);
});

// CREATE AGAIN (should create 1 edge)
database.transaction(() -> {
final ResultSet rs = database.command("sql", """
CREATE EDGE edg FROM #1:0 TO [#1:1,#1:2,#1:0] IF NOT EXISTS
""");
assertThat(rs.hasNext()).isTrue();
assertThat(rs.stream().count()).isEqualTo(3);
});

}
}
Loading