diff --git a/ERMine.Core.UnitTesting/Parsing/ModelParserTest.cs b/ERMine.Core.UnitTesting/Parsing/ModelParserTest.cs
index aea649e..8c84d41 100644
--- a/ERMine.Core.UnitTesting/Parsing/ModelParserTest.cs
+++ b/ERMine.Core.UnitTesting/Parsing/ModelParserTest.cs
@@ -82,6 +82,94 @@ public void Parse_TwoEntitiesAndRelationship_Label()
var entityRelationships = ModelParser.EntityRelationships.Parse(input);
Assert.AreEqual(3, entityRelationships.Count());
+ Assert.AreEqual(2, entityRelationships.Count(e => e is Entity));
+ Assert.AreEqual(1, entityRelationships.Count(r => r is Relationship));
+
+ }
+
+ [TestMethod]
+ public void Parse_TwoRelationships_Label()
+ {
+ var input = "[Student] *-isfriend-* [Student]" + "\r\n";
+ input += "[Student] *-follow-* [Course]\r\n";
+
+ var entityRelationships = ModelParser.Relationships.Parse(input);
+
+ Assert.AreEqual(2, entityRelationships.Count());
+
+ }
+
+ [TestMethod]
+ public void Parse_OneTernary_Label()
+ {
+ var input = "-SupplySchedule- [Vendor]* [Part]+ [Warehouse]+\r\n";
+
+ var entityRelationships = ModelParser.Relationships.Parse(input);
+
+ Assert.AreEqual(1, entityRelationships.Count());
+
+ }
+
+ [TestMethod]
+ public void Parse_ThreeRelationships_Label()
+ {
+ var input = "[Student] *-isfriend-* [Student]" + "\r\n";
+ input += "[Student] *-follow-* [Course]\r\n";
+ input += "-SupplySchedule- [Vendor]* [Part]+ [Warehouse]+\r\n";
+
+ var entityRelationships = ModelParser.Relationships.Parse(input);
+
+ Assert.AreEqual(3, entityRelationships.Count());
+ Assert.AreEqual(3, entityRelationships.Count(r => r is Relationship));
+
+ }
+
+ [TestMethod]
+ public void Parse_ThreeEntitiesAndTernaryRelationship_Label()
+ {
+ var input = "[Warehouse]" + "\r\n";
+ input += "-SupplySchedule- [Vendor]* [Part]+ [Warehouse]+" + "\r\n";
+ input += "[Part]" + "\r\n";
+ input += "[Vendor]" + "\r\n";
+
+ var entityRelationships = ModelParser.EntityRelationships.Parse(input);
+
+ Assert.AreEqual(3, entityRelationships.Count(e => e is Entity));
+ Assert.AreEqual(1, entityRelationships.Count(r => r is Relationship));
+
+ }
+
+ [TestMethod]
+ public void Parse_TwiceThreeRelationship_Label()
+ {
+ var input = "[Warehouse]" + "\r\n";
+ input += "-SupplySchedule- [Vendor]* [Part]+ [Warehouse]+" + "\r\n";
+ input += "[Part]" + "\r\n";
+ input += "[Vendor]" + "\r\n";
+ input += "[Student] *-isfriend-* [Student]" + "\r\n";
+ input += "[Student] *-follow-* [Course]\r\n";
+
+ var entityRelationships = ModelParser.EntityRelationships.Parse(input);
+
+ Assert.AreEqual(3, entityRelationships.Count(e => e is Entity));
+ Assert.AreEqual(3, entityRelationships.Count(r => r is Relationship));
+
+ }
+
+ [TestMethod]
+ public void Parse_TwiceThree2Relationship_Label()
+ {
+ var input = "[Warehouse]" + "\r\n";
+ input += "-SupplySchedule- [Vendor]* [Part]+ [Warehouse]+" + "\r\n";
+ input += "[Student] *-isfriend-* [Student]" + "\r\n";
+ input += "[Student] *-follow-* [Course]\r\n";
+ input += "[Part]" + "\r\n";
+ input += "[Vendor]" + "\r\n";
+
+ var entityRelationships = ModelParser.EntityRelationships.Parse(input);
+
+ Assert.AreEqual(3, entityRelationships.Count(e => e is Entity));
+ Assert.AreEqual(3, entityRelationships.Count(r => r is Relationship));
}
}
diff --git a/ERMine.Core.UnitTesting/Parsing/RelationshipParserTest.cs b/ERMine.Core.UnitTesting/Parsing/RelationshipParserTest.cs
index b2463fe..7d1ed6b 100644
--- a/ERMine.Core.UnitTesting/Parsing/RelationshipParserTest.cs
+++ b/ERMine.Core.UnitTesting/Parsing/RelationshipParserTest.cs
@@ -14,7 +14,7 @@ public class RelationshipParserTest
public void Relationship_Binary_WithLabel()
{
var input = "[Student] +-follow-* [Course]";
- var relationship = RelationshipParser.Relationship.Parse(input);
+ var relationship = RelationshipBinaryParser.Relationship.Parse(input);
Assert.AreEqual("follow", relationship.Label);
Assert.AreEqual("Student", relationship.Entities.ElementAt(0).Label);
@@ -27,7 +27,7 @@ public void Relationship_Binary_WithLabel()
public void Relationship_Binary_WithoutLabel()
{
var input = "[Post]*--1[Comment]";
- var relationship = RelationshipParser.Relationship.Parse(input);
+ var relationship = RelationshipBinaryParser.Relationship.Parse(input);
Assert.AreEqual(null, relationship.Label);
Assert.AreEqual("Post", relationship.Entities.ElementAt(0).Label);
@@ -40,12 +40,27 @@ public void Relationship_Binary_WithoutLabel()
public void Relationship_Binary_Self()
{
var input = "[Employee] *-manages-1 [Employee]";
- var relationship = RelationshipParser.Relationship.Parse(input);
+ var relationship = RelationshipBinaryParser.Relationship.Parse(input);
Assert.AreEqual("Employee", relationship.Entities.ElementAt(0).Label);
Assert.AreEqual("Employee", relationship.Entities.ElementAt(1).Label);
Assert.IsTrue(relationship.Entities.ElementAt(0).Label == relationship.Entities.ElementAt(1).Label);
}
+ [TestMethod]
+ public void Relationship_Ternary_Simple()
+ {
+ var input = "-SupplySchedule- [Vendor]* [Part]+ [Warehouse]+ ";
+ var relationship = RelationshipTernaryParser.Relationship.Parse(input);
+
+ Assert.AreEqual("Vendor", relationship.Entities.ElementAt(0).Label);
+ Assert.AreEqual(Cardinality.ZeroOrMore, relationship.Cardinality.ElementAt(0));
+ Assert.AreEqual("Part", relationship.Entities.ElementAt(1).Label);
+ Assert.AreEqual(Cardinality.OneOrMore, relationship.Cardinality.ElementAt(1));
+ Assert.AreEqual("Warehouse", relationship.Entities.ElementAt(2).Label);
+ Assert.AreEqual(Cardinality.OneOrMore, relationship.Cardinality.ElementAt(2));
+
+ }
+
}
}
diff --git a/ERMine.Core/ERMine.Core.csproj b/ERMine.Core/ERMine.Core.csproj
index 289b312..4f06f9a 100644
--- a/ERMine.Core/ERMine.Core.csproj
+++ b/ERMine.Core/ERMine.Core.csproj
@@ -56,7 +56,8 @@
-
+
+
diff --git a/ERMine.Core/Modeling/Factory/RelationshipFactory.cs b/ERMine.Core/Modeling/Factory/RelationshipFactory.cs
index 968f6c9..708d78e 100644
--- a/ERMine.Core/Modeling/Factory/RelationshipFactory.cs
+++ b/ERMine.Core/Modeling/Factory/RelationshipFactory.cs
@@ -17,6 +17,15 @@ public Relationship Create(string label, IEnumerable>
return relationship;
}
+ public Relationship Create(string label, IEnumerable> members)
+ {
+ var relationship = new Relationship(members.Count());
+ relationship.Label = label;
+ foreach (var item in members)
+ relationship.Add(new Entity(item.Item1), item.Item2);
+ return relationship;
+ }
+
public Relationship Create(string label, string firstEntity, Cardinality firstCardinality, string secondEntity, Cardinality secondCardinality)
{
var tuples = new List>();
diff --git a/ERMine.Core/Parsing/ModelParser.cs b/ERMine.Core/Parsing/ModelParser.cs
index 5f109fa..d868b69 100644
--- a/ERMine.Core/Parsing/ModelParser.cs
+++ b/ERMine.Core/Parsing/ModelParser.cs
@@ -10,15 +10,25 @@ namespace ERMine.Core.Parsing
{
static class ModelParser
{
+ public readonly static Parser> Relationships =
+ (
+ from binaryRelationships in RelationshipBinaryParser.Relationship.Many()
+ from ternaryRelationships in RelationshipTernaryParser.Relationship.Many()
+ select binaryRelationships
+ .Union(ternaryRelationships)
+ );
+
+ public readonly static Parser> Entities =
+ (
+ from entities in EntityParser.Entity.Many()
+ select entities
+ );
+
readonly static Parser> EntityRelationship =
(
- from relationships in RelationshipParser.Relationship.Optional()
- from entities in EntityParser.Entity.Optional()
- select entities.IsDefined && relationships.IsDefined
- ? Enumerable.Repeat(entities.GetOrDefault() as IEntityRelationship, 1)
- .Union(Enumerable.Repeat(relationships.GetOrDefault() as IEntityRelationship, 1))
- : entities.IsDefined ? Enumerable.Repeat(entities.GetOrDefault() as IEntityRelationship, 1)
- : Enumerable.Repeat(relationships.GetOrDefault() as IEntityRelationship, 1)
+ from relationships in Relationships.Many()
+ from entity in EntityParser.Entity.Optional()
+ select entity.IsDefined ? relationships.SelectMany(r => r).Union(Enumerable.Repeat((IEntityRelationship) entity.GetOrDefault(), 1)) : relationships.SelectMany(r => r)
);
public readonly static Parser> EntityRelationships =
diff --git a/ERMine.Core/Parsing/RelationshipParser.cs b/ERMine.Core/Parsing/RelationshipBinaryParser.cs
similarity index 97%
rename from ERMine.Core/Parsing/RelationshipParser.cs
rename to ERMine.Core/Parsing/RelationshipBinaryParser.cs
index 22b8fad..57acd3e 100644
--- a/ERMine.Core/Parsing/RelationshipParser.cs
+++ b/ERMine.Core/Parsing/RelationshipBinaryParser.cs
@@ -8,7 +8,7 @@
namespace ERMine.Core.Parsing
{
- static class RelationshipParser
+ static class RelationshipBinaryParser
{
readonly static Parser Cardinality =
(
diff --git a/ERMine.Core/Parsing/RelationshipTernaryParser.cs b/ERMine.Core/Parsing/RelationshipTernaryParser.cs
new file mode 100644
index 0000000..ca91a43
--- /dev/null
+++ b/ERMine.Core/Parsing/RelationshipTernaryParser.cs
@@ -0,0 +1,53 @@
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Sprache;
+using ERMine.Core.Modeling;
+using ERMine.Core.Modeling.Factory;
+using System;
+
+namespace ERMine.Core.Parsing
+{
+ static class RelationshipTernaryParser
+ {
+ readonly static Parser Cardinality =
+ (
+ from cardinality in Parse.Char('*').Return(Modeling.Cardinality.ZeroOrMore)
+ .Or(Parse.Char('?').Return(Modeling.Cardinality.ZeroOrOne)
+ .Or(Parse.Char('1').Return(Modeling.Cardinality.ExactyOne)
+ .Or(Parse.Char('+').Return(Modeling.Cardinality.OneOrMore)
+ )))
+ select cardinality
+ );
+
+ public readonly static Parser Relationship =
+ (
+
+ from firstSeparator in Parse.Char('-')
+ from label in Grammar.Textual.Optional()
+ from secondSeparator in Parse.Char('-')
+ from firstEntity in Grammar.BracketTextual
+ from firstCardinality in Cardinality
+ from secondEntity in Grammar.BracketTextual
+ from secondCardinality in Cardinality
+ from thirdEntity in Grammar.BracketTextual
+ from thirdCardinality in Cardinality
+ select new RelationshipFactory().Create( label.GetOrDefault()
+ , new List>()
+ {
+ new Tuple (firstEntity, firstCardinality)
+ , new Tuple (secondEntity, secondCardinality)
+ , new Tuple (thirdEntity, thirdCardinality)
+ }
+ )
+ );
+
+ public readonly static Parser> Relationships =
+ (
+ Relationship.Many()
+ );
+
+
+ }
+}
diff --git a/README.md b/README.md
index ff5fa74..13133d8 100644
--- a/README.md
+++ b/README.md
@@ -43,12 +43,16 @@ Derivated attributes are noted with a percentage (%).
# Relationships
-Currently, ERMine supports unary and binary relationships
+Currently, ERMine supports unary, binary and ternary relationships
-*first_entity_name* [ ? | 1 | * | + ] - *ralationship_name* - [ ? | 1 | * | + ] *second_entity_name*
+*first_entity_name* [ ? | 1 | * | + ] - *relationship_name* - [ ? | 1 | * | + ] *second_entity_name*
for unary relationships the name of the first and second entities must be identical.
+Ternary relationships are noted differently
+
+*relationship_name* *first_entity_name* [ ? | 1 | * | + ] *second_entity_name* [ ? | 1 | * | + ] *third_entity_name* [ ? | 1 | * | + ]
+
## Cardinalities
* ```?``` stands for O..1