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
Original file line number Diff line number Diff line change
Expand Up @@ -306,24 +306,32 @@ private boolean mergePath(final PathPattern pathPattern, final ResultInternal re
* @return matching vertex or null
*/
private Vertex findNode(final NodePattern nodePattern, final Result result) {
if (!nodePattern.hasLabels() || !nodePattern.hasProperties()) {
// Can't match without label and properties
if (!nodePattern.hasLabels()) {
// Can't match without a label
return null;
}

final String label = nodePattern.getFirstLabel();

// Check if the type exists in the schema before iterating
if (!context.getDatabase().getSchema().existsType(label)) {
return null;
}

@SuppressWarnings("unchecked")
final Iterator<Identifiable> iterator = (Iterator<Identifiable>) (Object) context.getDatabase().iterateType(label, true);

// Evaluate property expressions against current result context
final Map<String, Object> evaluatedProperties = evaluateProperties(nodePattern.getProperties(), result);
// Evaluate property expressions against current result context (may be empty)
final Map<String, Object> evaluatedProperties = nodePattern.hasProperties()
? evaluateProperties(nodePattern.getProperties(), result)
: null;

// Find first vertex matching all properties
// Find first vertex matching all properties (or any vertex if no properties specified)
while (iterator.hasNext()) {
final Identifiable identifiable = iterator.next();
if (identifiable instanceof Vertex) {
final Vertex vertex = (Vertex) identifiable;
if (matchesProperties(vertex, evaluatedProperties)) {
if (evaluatedProperties == null || matchesProperties(vertex, evaluatedProperties)) {
return vertex;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,66 @@ void testMergeRelationship() {
assertThat(count).isEqualTo(1);
}

/**
* Test that MERGE with label only (no properties) finds existing node instead of creating duplicates.
* This is the pattern: MERGE (n:PIPELINE_CONFIG) ON CREATE SET n.pipelines = ["miaou"] ON MATCH SET n.pipelines = ["miaou"]
*/
@Test
void testMergeLabelOnlyFindsExistingNode() {
database.getSchema().createVertexType("PIPELINE_CONFIG");

// First MERGE should create the node
database.transaction(() -> {
final ResultSet result = database.command("opencypher",
"MERGE (n:PIPELINE_CONFIG) ON CREATE SET n.pipelines = ['miaou'] ON MATCH SET n.pipelines = ['miaou'] RETURN n.pipelines as pipelines");
assertThat(result.hasNext()).isTrue();
result.next();
});

// Second MERGE should find the existing node, not create a duplicate
database.transaction(() -> {
final ResultSet result = database.command("opencypher",
"MERGE (n:PIPELINE_CONFIG) ON CREATE SET n.pipelines = ['miaou'] ON MATCH SET n.pipelines = ['miaou'] RETURN n.pipelines as pipelines");
assertThat(result.hasNext()).isTrue();
result.next();
});

// Verify only one node exists
final ResultSet verify = database.query("opencypher",
"MATCH (n:PIPELINE_CONFIG) RETURN n");
int count = 0;
while (verify.hasNext()) {
verify.next();
count++;
}
assertThat(count).isEqualTo(1);
}

/**
* Test that MERGE with label only (no properties) correctly triggers ON CREATE SET on first call
* and ON MATCH SET on subsequent calls.
*/
@Test
void testMergeLabelOnlyWithOnCreateAndOnMatchSet() {
database.getSchema().createVertexType("SINGLETON");

// First MERGE should create and apply ON CREATE SET
ResultSet result = database.command("opencypher",
"MERGE (n:SINGLETON) ON CREATE SET n.status = 'created', n.count = 1 ON MATCH SET n.status = 'matched', n.count = 2 RETURN n");
assertThat(result.hasNext()).isTrue();
Vertex v = (Vertex) result.next().getProperty("n");
assertThat(v.get("status")).isEqualTo("created");
assertThat(((Number) v.get("count")).intValue()).isEqualTo(1);

// Second MERGE should match and apply ON MATCH SET
result = database.command("opencypher",
"MERGE (n:SINGLETON) ON CREATE SET n.status = 'created', n.count = 1 ON MATCH SET n.status = 'matched', n.count = 2 RETURN n");
assertThat(result.hasNext()).isTrue();
v = (Vertex) result.next().getProperty("n");
assertThat(v.get("status")).isEqualTo("matched");
assertThat(((Number) v.get("count")).intValue()).isEqualTo(2);
}

/**
* Test for issue #3217: Backticks in relationship types should be treated as escape characters,
* not included in the relationship type name.
Expand Down
Loading