Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(*): add identifier attribute #23

Merged
merged 1 commit into from
Sep 28, 2022
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
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);
}
}