Skip to content

Commit 8aaacc3

Browse files
committed
Add MERGE, DELETE, UNWIND, index and constraint support
- Add Merge and Delete operations to NodeGenerator and RelationshipGenerator - Add ON CREATE SET and ON MATCH SET support to Merge operations - Add IndexGenerator for CREATE/DROP INDEX on nodes and relationships - Add ConstraintGenerator for UNIQUE, NODE KEY and NOT NULL constraints - Add UnwindGenerator for batch MERGE operations on nodes and relationships - Rename Node1/Node2 to NodeLeft/NodeRight and NodeId1/NodeId2 to NodeIdLeft/NodeIdRight - Update .NET target to net9.0
1 parent 916b5ee commit 8aaacc3

26 files changed

Lines changed: 1963 additions & 192 deletions

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -326,5 +326,8 @@ ASALocalRun/
326326
# NVidia Nsight GPU debugger configuration file
327327
*.nvuser
328328

329-
# MFractors (Xamarin productivity tool) working folder
329+
# MFractors (Xamarin productivity tool) working folder
330330
.mfractor/
331+
332+
# Local tools config
333+
.claude/

Cypher.ScriptGenerator.Test/Cypher.ScriptGenerator.Test.csproj

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
4-
<TargetFramework>netcoreapp2.1</TargetFramework>
4+
<TargetFramework>net9.0</TargetFramework>
55

66
<IsPackable>false</IsPackable>
77
</PropertyGroup>
88

99
<ItemGroup>
10-
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
11-
<PackageReference Include="xunit" Version="2.4.0" />
12-
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.0" />
10+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.13.0" />
11+
<PackageReference Include="xunit" Version="2.9.3" />
12+
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2" />
1313
</ItemGroup>
1414

1515
<ItemGroup>
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
using Cypher.ScriptGenerator.Generators;
2+
using Cypher.ScriptGenerator.Models;
3+
using System.Collections.Generic;
4+
using Xunit;
5+
6+
namespace Cypher.ScriptGenerator.Test.Generators
7+
{
8+
public class ConstraintGeneratorTest
9+
{
10+
private readonly ConstraintGenerator _constraintGenerator;
11+
12+
public ConstraintGeneratorTest()
13+
{
14+
_constraintGenerator = new ConstraintGenerator();
15+
}
16+
17+
[Trait("ConstraintGenerator", "Create unique constraint")]
18+
[Fact(DisplayName = "Without name")]
19+
public void CreateUniqueWithoutName()
20+
{
21+
var script = _constraintGenerator.Create(new ConstraintDefinition
22+
{
23+
Label = "Person",
24+
Properties = new List<string> { "name" },
25+
Type = ConstraintType.Unique
26+
});
27+
28+
Assert.Equal("CREATE CONSTRAINT FOR (n:Person) ASSERT n.name IS UNIQUE", script);
29+
}
30+
31+
[Trait("ConstraintGenerator", "Create unique constraint")]
32+
[Fact(DisplayName = "With name")]
33+
public void CreateUniqueWithName()
34+
{
35+
var script = _constraintGenerator.Create(new ConstraintDefinition
36+
{
37+
Name = "person_name_unique",
38+
Label = "Person",
39+
Properties = new List<string> { "name" },
40+
Type = ConstraintType.Unique
41+
});
42+
43+
Assert.Equal("CREATE CONSTRAINT person_name_unique FOR (n:Person) ASSERT n.name IS UNIQUE", script);
44+
}
45+
46+
[Trait("ConstraintGenerator", "Create node key constraint")]
47+
[Fact(DisplayName = "Single property")]
48+
public void CreateNodeKeySingleProperty()
49+
{
50+
var script = _constraintGenerator.Create(new ConstraintDefinition
51+
{
52+
Label = "Person",
53+
Properties = new List<string> { "email" },
54+
Type = ConstraintType.NodeKey
55+
});
56+
57+
Assert.Equal("CREATE CONSTRAINT FOR (n:Person) ASSERT (n.email) IS NODE KEY", script);
58+
}
59+
60+
[Trait("ConstraintGenerator", "Create node key constraint")]
61+
[Fact(DisplayName = "Multiple properties")]
62+
public void CreateNodeKeyMultipleProperties()
63+
{
64+
var script = _constraintGenerator.Create(new ConstraintDefinition
65+
{
66+
Label = "Person",
67+
Properties = new List<string> { "name", "email" },
68+
Type = ConstraintType.NodeKey
69+
});
70+
71+
Assert.Equal("CREATE CONSTRAINT FOR (n:Person) ASSERT (n.name, n.email) IS NODE KEY", script);
72+
}
73+
74+
[Trait("ConstraintGenerator", "Create node key constraint")]
75+
[Fact(DisplayName = "With name and multiple properties")]
76+
public void CreateNamedNodeKeyMultipleProperties()
77+
{
78+
var script = _constraintGenerator.Create(new ConstraintDefinition
79+
{
80+
Name = "person_key",
81+
Label = "Person",
82+
Properties = new List<string> { "name", "email" },
83+
Type = ConstraintType.NodeKey
84+
});
85+
86+
Assert.Equal("CREATE CONSTRAINT person_key FOR (n:Person) ASSERT (n.name, n.email) IS NODE KEY", script);
87+
}
88+
89+
[Trait("ConstraintGenerator", "Create not null constraint")]
90+
[Fact(DisplayName = "Node property")]
91+
public void CreateNotNullNode()
92+
{
93+
var script = _constraintGenerator.Create(new ConstraintDefinition
94+
{
95+
Label = "Person",
96+
Properties = new List<string> { "name" },
97+
Type = ConstraintType.NotNull
98+
});
99+
100+
Assert.Equal("CREATE CONSTRAINT FOR (n:Person) ASSERT n.name IS NOT NULL", script);
101+
}
102+
103+
[Trait("ConstraintGenerator", "Create not null constraint")]
104+
[Fact(DisplayName = "Relationship property")]
105+
public void CreateNotNullRelationship()
106+
{
107+
var script = _constraintGenerator.Create(new ConstraintDefinition
108+
{
109+
Label = "KNOWS",
110+
Properties = new List<string> { "since" },
111+
Type = ConstraintType.NotNull,
112+
IsRelationship = true
113+
});
114+
115+
Assert.Equal("CREATE CONSTRAINT FOR ()-[r:KNOWS]-() ASSERT r.since IS NOT NULL", script);
116+
}
117+
118+
[Trait("ConstraintGenerator", "Create not null constraint")]
119+
[Fact(DisplayName = "With name")]
120+
public void CreateNotNullWithName()
121+
{
122+
var script = _constraintGenerator.Create(new ConstraintDefinition
123+
{
124+
Name = "person_name_not_null",
125+
Label = "Person",
126+
Properties = new List<string> { "name" },
127+
Type = ConstraintType.NotNull
128+
});
129+
130+
Assert.Equal("CREATE CONSTRAINT person_name_not_null FOR (n:Person) ASSERT n.name IS NOT NULL", script);
131+
}
132+
133+
[Trait("ConstraintGenerator", "Drop constraint")]
134+
[Fact(DisplayName = "Drop by name")]
135+
public void Drop()
136+
{
137+
var script = _constraintGenerator.Drop("person_name_unique");
138+
139+
Assert.Equal("DROP CONSTRAINT person_name_unique", script);
140+
}
141+
}
142+
}
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
using Cypher.ScriptGenerator.Generators;
2+
using Cypher.ScriptGenerator.Models;
3+
using System.Collections.Generic;
4+
using Xunit;
5+
6+
namespace Cypher.ScriptGenerator.Test.Generators
7+
{
8+
public class IndexGeneratorTest
9+
{
10+
private readonly IndexGenerator _indexGenerator;
11+
12+
public IndexGeneratorTest()
13+
{
14+
_indexGenerator = new IndexGenerator();
15+
}
16+
17+
[Trait("IndexGenerator", "Create index")]
18+
[Fact(DisplayName = "Without name")]
19+
public void CreateWithoutName()
20+
{
21+
var script = _indexGenerator.Create(new IndexDefinition
22+
{
23+
Label = "Person",
24+
Properties = new List<string> { "name" }
25+
});
26+
27+
Assert.Equal("CREATE INDEX FOR (n:Person) ON (n.name)", script);
28+
}
29+
30+
[Trait("IndexGenerator", "Create index")]
31+
[Fact(DisplayName = "With name")]
32+
public void CreateWithName()
33+
{
34+
var script = _indexGenerator.Create(new IndexDefinition
35+
{
36+
Name = "person_name",
37+
Label = "Person",
38+
Properties = new List<string> { "name" }
39+
});
40+
41+
Assert.Equal("CREATE INDEX person_name FOR (n:Person) ON (n.name)", script);
42+
}
43+
44+
[Trait("IndexGenerator", "Create index")]
45+
[Fact(DisplayName = "Composite index")]
46+
public void CreateComposite()
47+
{
48+
var script = _indexGenerator.Create(new IndexDefinition
49+
{
50+
Label = "Person",
51+
Properties = new List<string> { "name", "age" }
52+
});
53+
54+
Assert.Equal("CREATE INDEX FOR (n:Person) ON (n.name, n.age)", script);
55+
}
56+
57+
[Trait("IndexGenerator", "Create index")]
58+
[Fact(DisplayName = "Named composite index")]
59+
public void CreateNamedComposite()
60+
{
61+
var script = _indexGenerator.Create(new IndexDefinition
62+
{
63+
Name = "person_name_age",
64+
Label = "Person",
65+
Properties = new List<string> { "name", "age" }
66+
});
67+
68+
Assert.Equal("CREATE INDEX person_name_age FOR (n:Person) ON (n.name, n.age)", script);
69+
}
70+
71+
[Trait("IndexGenerator", "Create index")]
72+
[Fact(DisplayName = "Relationship index")]
73+
public void CreateForRelationship()
74+
{
75+
var script = _indexGenerator.Create(new IndexDefinition
76+
{
77+
Label = "KNOWS",
78+
Properties = new List<string> { "since" },
79+
IsRelationship = true
80+
});
81+
82+
Assert.Equal("CREATE INDEX FOR ()-[r:KNOWS]-() ON (r.since)", script);
83+
}
84+
85+
[Trait("IndexGenerator", "Create index")]
86+
[Fact(DisplayName = "Named relationship index")]
87+
public void CreateNamedForRelationship()
88+
{
89+
var script = _indexGenerator.Create(new IndexDefinition
90+
{
91+
Name = "knows_since",
92+
Label = "KNOWS",
93+
Properties = new List<string> { "since" },
94+
IsRelationship = true
95+
});
96+
97+
Assert.Equal("CREATE INDEX knows_since FOR ()-[r:KNOWS]-() ON (r.since)", script);
98+
}
99+
100+
[Trait("IndexGenerator", "Drop index")]
101+
[Fact(DisplayName = "Drop by name")]
102+
public void Drop()
103+
{
104+
var script = _indexGenerator.Drop("person_name");
105+
106+
Assert.Equal("DROP INDEX person_name", script);
107+
}
108+
}
109+
}

0 commit comments

Comments
 (0)