Skip to content

Commit

Permalink
feat(*): add identifier attribute (#23)
Browse files Browse the repository at this point in the history
Signed-off-by: Simon Stone <Simon.Stone@docusign.com>

Signed-off-by: Simon Stone <Simon.Stone@docusign.com>
  • Loading branch information
Simon Stone authored Sep 28, 2022
1 parent d5a2dad commit eb32cc2
Show file tree
Hide file tree
Showing 6 changed files with 101 additions and 1 deletion.
42 changes: 42 additions & 0 deletions AccordProject.Concerto.Tests/ConcertoUtilsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -104,4 +104,46 @@ public void CannotParseTypeWithEmptyVersion()
var ex = Assert.Throws<Exception>(() => ConcertoUtils.ParseType("org.example@.Foo"));
Assert.Equal("Invalid fully qualified name \"org.example@.Foo\"", ex.Message);
}

[Fact]
public void HasIdentifierTrueForTypeWithIdentifier()
{
var employee = new Employee() { EmployeeId = "12345678" };
Assert.True(ConcertoUtils.HasIdentifier(employee));
}

[Fact]
public void HasIdentifierTrueForTypeWithInheritedIdentifier()
{
var manager = new Manager() { EmployeeId = "12345678" };
Assert.True(ConcertoUtils.HasIdentifier(manager));
}

[Fact]
public void HasIdentifierFalseForTypeWithoutIdentifier()
{
var project = new Project() {};
Assert.False(ConcertoUtils.HasIdentifier(project));
}

[Fact]
public void GetIdentifierReturnsForTypeWithIdentifier()
{
var employee = new Employee() { EmployeeId = "12345678" };
Assert.Equal("12345678", ConcertoUtils.GetIdentifier(employee));
}

[Fact]
public void GetIdentifierReturnsForTypeWithInheritedIdentifier()
{
var manager = new Manager() { EmployeeId = "12345678" };
Assert.Equal("12345678", ConcertoUtils.GetIdentifier(manager));
}

[Fact]
public void GetIdentifierReturnsForTypeWithoutIdentifier()
{
var project = new Project() {};
Assert.Null(ConcertoUtils.GetIdentifier(project));
}
}
7 changes: 7 additions & 0 deletions AccordProject.Concerto.Tests/TestTypes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ public class Employee : Person {
public Department? Department { get; set; }
[Newtonsoft.Json.JsonProperty("manager")]
public Employee Manager { get; set; }
[AccordProject.Concerto.Identifier()]
[Newtonsoft.Json.JsonProperty("employeeId")]
public string EmployeeId { get; set; }
}
Expand All @@ -53,3 +54,9 @@ public class Manager : Employee {
[Newtonsoft.Json.JsonProperty("budget")]
public float Budget { get; set; }
}
[AccordProject.Concerto.Type(Namespace = "org.accordproject.concerto.test", Version = "1.2.3", Name = "Project")]
[Newtonsoft.Json.JsonConverter(typeof(AccordProject.Concerto.ConcertoConverterNewtonsoft))]
public class Project : Concept {
[Newtonsoft.Json.JsonProperty("$class")]
public override string _Class { get; } = "org.accordproject.concerto.test@1.2.3.Project";
}
4 changes: 4 additions & 0 deletions AccordProject.Concerto.Tests/data/employee.cto
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,7 @@ participant Employee identified by employeeId extends Person {
participant Manager extends Employee {
o Double budget optional
}

concept Project {

}
9 changes: 8 additions & 1 deletion AccordProject.Concerto/ConcertoAttributes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
namespace AccordProject.Concerto;

[AttributeUsage(AttributeTargets.Class)]
public class TypeAttribute : Attribute {
public class TypeAttribute : Attribute
{
public string Namespace;
public string? Version;
public string Name;
Expand All @@ -29,3 +30,9 @@ public ConcertoType ToType()
};
}
}

[AttributeUsage(AttributeTargets.Property)]
public class IdentifierAttribute : Attribute
{

}
2 changes: 2 additions & 0 deletions AccordProject.Concerto/ConcertoTypes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ public abstract class Concept {
public abstract class Asset : Concept {
[Newtonsoft.Json.JsonProperty("$class")]
public override string _Class { get; } = "concerto@1.0.0.Asset";
[AccordProject.Concerto.Identifier()]
[Newtonsoft.Json.JsonProperty("$identifier")]
public string _Identifier { get; set; }
}
Expand All @@ -32,6 +33,7 @@ public abstract class Asset : Concept {
public abstract class Participant : Concept {
[Newtonsoft.Json.JsonProperty("$class")]
public override string _Class { get; } = "concerto@1.0.0.Participant";
[AccordProject.Concerto.Identifier()]
[Newtonsoft.Json.JsonProperty("$identifier")]
public string _Identifier { get; set; }
}
Expand Down
38 changes: 38 additions & 0 deletions AccordProject.Concerto/ConcertoUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
* limitations under the License.
*/

namespace AccordProject.Concerto;

using System.Reflection;

/// <summary>
/// This class represents a Concerto type, for example org.example@1.2.3.Foo.
/// </summary>
Expand Down Expand Up @@ -107,4 +111,38 @@ public static ConcertoType ParseType(string fqn)
}
return new ConcertoType() { Namespace = ns, Version = version, Name = name };
}

public static bool HasIdentifier(Concept concept)
{
var type = concept.GetType();
var identifierProperty = FindIdentifierProperty(type);
return identifierProperty is not null;
}

public static string? GetIdentifier(Concept concept)
{
var type = concept.GetType();
var identifierProperty = FindIdentifierProperty(type);
if (identifierProperty is null)
{
return null;
}
return identifierProperty.GetValue(concept) as string;
}

private static PropertyInfo? FindIdentifierProperty(Type type)
{
var properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
var identifierProperty = properties.FirstOrDefault(property => property.GetCustomAttributes(typeof(IdentifierAttribute), false).Length > 0);
if (identifierProperty is not null)
{
return identifierProperty;
}
var baseType = type.BaseType;
if (baseType is null)
{
return null;
}
return FindIdentifierProperty(baseType);
}
}

0 comments on commit eb32cc2

Please sign in to comment.