preliminary scaffolding for supporting OMS database modeling via .NET classes
This commit is contained in:
parent
999f05b8b4
commit
d69e83c974
@ -1,6 +1,19 @@
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Mocha.Core.Modeling;
|
||||
|
||||
public class OmsClass
|
||||
{
|
||||
public Guid GlobalIdentifier { get; internal set; } = Guid.Empty;
|
||||
|
||||
protected object GetAttributeValue()
|
||||
{
|
||||
StackTrace st = new StackTrace();
|
||||
StackFrame frame = st.GetFrame(0);
|
||||
return 1;
|
||||
}
|
||||
protected void SetAttributeValue(object value)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,7 @@
|
||||
using System.Globalization;
|
||||
using System.Reflection;
|
||||
using MBS.Core.Reflection;
|
||||
using Mocha.Core.Modeling.PropertyImplementations;
|
||||
|
||||
namespace Mocha.Core.Modeling;
|
||||
|
||||
@ -13,6 +15,9 @@ public class OmsDatabase
|
||||
Oms = oms;
|
||||
_Type = this.GetType();
|
||||
|
||||
// First create all the classes we've defined in the database.
|
||||
// These are nested types of the class derived from OmsDatabase.
|
||||
|
||||
Type[] nestedTypes = null;
|
||||
try
|
||||
{
|
||||
@ -33,6 +38,44 @@ public class OmsDatabase
|
||||
|
||||
CreateClass(t);
|
||||
}
|
||||
|
||||
foreach (Type t in nestedTypes)
|
||||
{
|
||||
if (t == null) continue;
|
||||
if (t.IsAbstract) continue;
|
||||
|
||||
if (!t.IsSubclassOf(typeof(OmsClass)))
|
||||
continue;
|
||||
|
||||
SetupClassProperties(t);
|
||||
}
|
||||
|
||||
// Now that our schema is set up, go through OmsDatabase public properties
|
||||
// and assign OmsPropertyImplementations to the properties which represent
|
||||
// Lists of instances.
|
||||
FieldInfo[] fis = _Type.GetFields(BindingFlags.Public | BindingFlags.Instance);
|
||||
foreach (FieldInfo fi in fis)
|
||||
{
|
||||
if (fi.FieldType.IsSubclassOfGeneric(typeof(ICollection<>)))
|
||||
{
|
||||
// this is a collection of instances of the given type, which must inherit from OmsClass
|
||||
Type genericTypeArg = fi.FieldType.GenericTypeArguments[0];
|
||||
if (!genericTypeArg.IsSubclassOf(typeof(OmsClass)))
|
||||
{
|
||||
throw new InvalidOperationException("Generic type argument of collection type must inherit from OmsClass");
|
||||
}
|
||||
|
||||
fi.SetValue(this, OmsInstanceList.CreateGeneric(this, genericTypeArg));
|
||||
}
|
||||
else if (fi.FieldType.IsSubclassOf(typeof(OmsClass)))
|
||||
{
|
||||
// pi.SetValue(this, new OmsNonsingularRelationshipProperty());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateClass(Type t)
|
||||
@ -53,12 +96,6 @@ public class OmsDatabase
|
||||
}
|
||||
}
|
||||
|
||||
PropertyInfo[] properties = t.GetProperties(BindingFlags.Public | BindingFlags.Instance);
|
||||
foreach (PropertyInfo property in properties)
|
||||
{
|
||||
SetupClassProperty(t, property);
|
||||
}
|
||||
|
||||
if (globalIdentifier == Guid.Empty)
|
||||
{
|
||||
globalIdentifier = Guid.NewGuid();
|
||||
@ -68,8 +105,40 @@ public class OmsDatabase
|
||||
Oms.CreateClass(className, globalIdentifier);
|
||||
}
|
||||
|
||||
private void SetupClassProperties(Type t)
|
||||
{
|
||||
PropertyInfo[] properties = t.GetProperties(BindingFlags.Public | BindingFlags.Instance);
|
||||
foreach (PropertyInfo property in properties)
|
||||
{
|
||||
SetupClassProperty(t, property);
|
||||
}
|
||||
}
|
||||
|
||||
public static Guid GetGlobalIdentifierForClass(Type t)
|
||||
{
|
||||
if (!t.IsSubclassOf(typeof(OmsClass)))
|
||||
{
|
||||
throw new InvalidOperationException("Must be subclass of OmsClass");
|
||||
}
|
||||
|
||||
object[] attrs = t.GetCustomAttributes(false);
|
||||
foreach (object attr in attrs)
|
||||
{
|
||||
if (attr is OmsGlobalIdentifierAttribute)
|
||||
{
|
||||
return ((OmsGlobalIdentifierAttribute)attr).GlobalIdentifier;
|
||||
}
|
||||
}
|
||||
return Guid.Empty;
|
||||
}
|
||||
|
||||
private void SetupClassProperty(Type t, PropertyInfo pi)
|
||||
{
|
||||
if (pi.PropertyType == typeof(Guid) && pi.Name == "GlobalIdentifier")
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
object[] propertyAttrs = pi.GetCustomAttributes(false);
|
||||
Guid globalIdentifier = Guid.Empty;
|
||||
foreach (object attr in propertyAttrs)
|
||||
@ -85,10 +154,72 @@ public class OmsDatabase
|
||||
globalIdentifier = Guid.NewGuid();
|
||||
}
|
||||
|
||||
InstanceHandle relationshipInstance = Oms.CreateInstanceOf(Oms.GetInstance(KnownInstanceGuids.Classes.Relationship), globalIdentifier);
|
||||
ApplyNativeAttributes(relationshipInstance, propertyAttrs);
|
||||
Guid myGuid = GetGlobalIdentifierForClass(t);
|
||||
InstanceHandle sourceClassInstance = Oms.GetInstance(myGuid);
|
||||
InstanceHandle propertyInstance = InstanceHandle.Empty;
|
||||
|
||||
if (pi.PropertyType.IsSubclassOfGeneric(typeof(ICollection<>)))
|
||||
{
|
||||
Type arg = pi.PropertyType.GenericTypeArguments[0];
|
||||
Guid guid = GetGlobalIdentifierForClass(arg);
|
||||
InstanceHandle relationshipDestinationClassInstance = Oms.GetInstance(guid);
|
||||
|
||||
CreateRelationship(out propertyInstance, globalIdentifier, sourceClassInstance, relationshipDestinationClassInstance, false);
|
||||
}
|
||||
else if (pi.PropertyType.IsSubclassOf(typeof(OmsClass)))
|
||||
{
|
||||
Guid guid = GetGlobalIdentifierForClass(pi.PropertyType);
|
||||
InstanceHandle relationshipDestinationClassInstance = Oms.GetInstance(guid);
|
||||
|
||||
CreateRelationship(out propertyInstance, globalIdentifier, sourceClassInstance, relationshipDestinationClassInstance, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
// attribute
|
||||
if (pi.PropertyType == typeof(string))
|
||||
{
|
||||
// Text Attribute
|
||||
CreateAttribute(out propertyInstance, Oms.GetInstance(KnownInstanceGuids.Classes.TextAttribute), pi.Name);
|
||||
}
|
||||
else if (pi.PropertyType == typeof(bool))
|
||||
{
|
||||
// Boolean Attribute
|
||||
CreateAttribute(out propertyInstance, Oms.GetInstance(KnownInstanceGuids.Classes.BooleanAttribute), pi.Name);
|
||||
}
|
||||
else if (pi.PropertyType == typeof(decimal)
|
||||
|| pi.PropertyType == typeof(int))
|
||||
{
|
||||
// Numeric Attribute
|
||||
CreateAttribute(out propertyInstance, Oms.GetInstance(KnownInstanceGuids.Classes.NumericAttribute), pi.Name);
|
||||
}
|
||||
else if (pi.PropertyType == typeof(DateTime))
|
||||
{
|
||||
// Date Attribute
|
||||
CreateAttribute(out propertyInstance, Oms.GetInstance(KnownInstanceGuids.Classes.DateAttribute), pi.Name);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException(String.Format("OMS type of property with CLR type '{0}' could not be determined", pi.PropertyType));
|
||||
}
|
||||
}
|
||||
|
||||
ApplyNativeAttributes(propertyInstance, propertyAttrs);
|
||||
}
|
||||
|
||||
private void CreateAttribute(out InstanceHandle propertyInstance, InstanceHandle attributeClassInstance, string name)
|
||||
{
|
||||
propertyInstance = Oms.CreateInstanceOf(attributeClassInstance);
|
||||
Oms.SetAttributeValue(propertyInstance, Oms.GetInstance(KnownAttributeGuids.Text.Name), name);
|
||||
}
|
||||
|
||||
private void CreateRelationship(out InstanceHandle relationshipInstance, Guid globalIdentifier, InstanceHandle sourceClassInstance, InstanceHandle relationshipDestinationClassInstance, bool relationshipSingular)
|
||||
{
|
||||
relationshipInstance = Oms.CreateInstanceOf(Oms.GetInstance(KnownInstanceGuids.Classes.Relationship), globalIdentifier);
|
||||
Oms.AssignRelationship(relationshipInstance, Oms.GetInstance(KnownRelationshipGuids.Relationship__has_source__Class), sourceClassInstance);
|
||||
Oms.AssignRelationship(relationshipInstance, Oms.GetInstance(KnownRelationshipGuids.Relationship__has_destination__Class), relationshipDestinationClassInstance);
|
||||
Oms.SetAttributeValue(relationshipInstance, Oms.GetInstance(KnownAttributeGuids.Boolean.Singular), relationshipSingular);
|
||||
}
|
||||
|
||||
private void ApplyNativeAttributes(InstanceHandle inst, object[] propertyAttrs)
|
||||
{
|
||||
foreach (object attr in propertyAttrs)
|
||||
|
||||
96
mocha-dotnet/src/lib/Mocha.Core/Modeling/OmsInstanceList.cs
Normal file
96
mocha-dotnet/src/lib/Mocha.Core/Modeling/OmsInstanceList.cs
Normal file
@ -0,0 +1,96 @@
|
||||
using System.Collections;
|
||||
|
||||
namespace Mocha.Core.Modeling;
|
||||
|
||||
public class OmsInstanceList
|
||||
{
|
||||
internal static OmsInstanceList CreateGeneric(OmsDatabase omsdb, Type type)
|
||||
{
|
||||
Guid gl = OmsDatabase.GetGlobalIdentifierForClass(type);
|
||||
|
||||
Type t = typeof(OmsInstanceList<>);
|
||||
Type concrete = t.MakeGenericType(new Type[] { type });
|
||||
return (OmsInstanceList) concrete.Assembly.CreateInstance(concrete.FullName, false, System.Reflection.BindingFlags.Default, null, new object[] { omsdb, gl }, null, null);
|
||||
}
|
||||
}
|
||||
|
||||
public class OmsInstanceList<T> : OmsInstanceList, IList<T> where T : OmsClass
|
||||
{
|
||||
private OmsDatabase omsdb;
|
||||
private Guid classGuid;
|
||||
|
||||
public OmsInstanceList(OmsDatabase omsdb, Guid classGuid)
|
||||
{
|
||||
this.omsdb = omsdb;
|
||||
this.classGuid = classGuid;
|
||||
}
|
||||
|
||||
public T this[int index] { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
|
||||
|
||||
public int Count
|
||||
{
|
||||
get
|
||||
{
|
||||
InstanceHandle ih = omsdb.Oms.GetInstance(classGuid);
|
||||
return omsdb.Oms.CountInstances(ih);
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsReadOnly => throw new NotImplementedException();
|
||||
|
||||
public void Add(T item)
|
||||
{
|
||||
if (item.GlobalIdentifier == Guid.Empty)
|
||||
{
|
||||
Guid localClassGuid = OmsDatabase.GetGlobalIdentifierForClass(item.GetType());
|
||||
Guid localInstanceGuid = Guid.NewGuid();
|
||||
|
||||
omsdb.Oms.CreateInstanceOf(omsdb.Oms.GetInstance(localClassGuid), localInstanceGuid);
|
||||
}
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool Contains(T item)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void CopyTo(T[] array, int arrayIndex)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public int IndexOf(T item)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void Insert(int index, T item)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool Remove(T item)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void RemoveAt(int index)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,5 @@
|
||||
namespace Mocha.Core.Modeling.PropertyImplementations;
|
||||
|
||||
public class OmsNonsingularRelationshipProperty : OmsRelationshipProperty
|
||||
{
|
||||
}
|
||||
@ -0,0 +1,6 @@
|
||||
namespace Mocha.Core.Modeling.PropertyImplementations;
|
||||
|
||||
public abstract class OmsRelationshipProperty
|
||||
{
|
||||
|
||||
}
|
||||
@ -116,12 +116,19 @@ public class MiniOms : MemoryOms
|
||||
CreateRelationship(c_Class, "has", c_Attribute, KnownRelationshipGuids.Class__has__Attribute, false, "for", KnownRelationshipGuids.Attribute__for__Class);
|
||||
AddAttribute(c_Class, a_Name);
|
||||
|
||||
AddAttribute(c_Attribute, a_Name);
|
||||
|
||||
AddAttribute(c_Relationship, a_RelationshipType);
|
||||
AddAttribute(c_Relationship, a_Singular);
|
||||
|
||||
//* ========== Superclass / Subclass Relationships ========== *//
|
||||
CreateRelationship(c_Class, "has super", c_Class, KnownRelationshipGuids.Class__has_super__Class, false, "has sub", KnownRelationshipGuids.Class__has_sub__Class);
|
||||
|
||||
AddSuperClass(c_TextAttribute, c_Attribute);
|
||||
AddSuperClass(c_BooleanAttribute, c_Attribute);
|
||||
AddSuperClass(c_NumericAttribute, c_Attribute);
|
||||
AddSuperClass(c_DateAttribute, c_Attribute);
|
||||
|
||||
c_WorkSet = CreateClass("Work Set", KnownInstanceGuids.Classes.WorkSet);
|
||||
SetInstanceKey(c_WorkSet, new InstanceKey(1, 15));
|
||||
AddAttribute(c_WorkSet, a_Name);
|
||||
|
||||
@ -9,19 +9,36 @@ public class VehicleForHireDB : OmsDatabase
|
||||
[OmsName("Business"), OmsGlobalIdentifier("{c4e1d676-726c-42f4-9edb-a0ca0ee0e612}")]
|
||||
public class Business : OmsClass
|
||||
{
|
||||
public Business(string name)
|
||||
{
|
||||
Name = name;
|
||||
}
|
||||
|
||||
[OmsGlobalIdentifier("{9153A637-992E-4712-ADF2-B03F0D9EDEA6}")]
|
||||
public readonly string Name;
|
||||
|
||||
/// <summary>
|
||||
/// Business.has Driver
|
||||
/// </summary>
|
||||
/// <value></value>
|
||||
[OmsRelationshipType("has"), OmsGlobalIdentifier("{63e5ab3a-4009-4af9-8171-5b23472c1c8c}")]
|
||||
public OmsRelationship<Business, Driver> Drivers { get; }
|
||||
public readonly IList<Driver> Drivers;
|
||||
|
||||
/// <summary>
|
||||
/// Business.has Vehicle
|
||||
/// </summary>
|
||||
/// <value></value>
|
||||
[OmsRelationshipType("has"), OmsGlobalIdentifier("{c54125f6-c3b0-40b2-99f9-e0ed20a75bfa}")]
|
||||
public OmsRelationship<Business, Driver> Vehicles { get; }
|
||||
public readonly IList<Vehicle> Vehicles;
|
||||
|
||||
[OmsRelationshipType("has"), OmsGlobalIdentifier("{9d4946c3-db8d-4f27-b21b-52e9b0fdf231}")]
|
||||
public BusinessPermit Permit;
|
||||
}
|
||||
|
||||
[OmsName("Business Permit"), OmsGlobalIdentifier("{7680b302-c9c2-4275-abf8-373adafbf58e}")]
|
||||
public class BusinessPermit : OmsClass
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
[OmsName("Driver"), OmsGlobalIdentifier("{10c51c07-c757-4b00-b406-d54c99460f32}")]
|
||||
@ -43,13 +60,20 @@ public class VehicleForHireDB : OmsDatabase
|
||||
[OmsName("Vehicle Permit"), OmsGlobalIdentifier("{38a492b9-901f-4074-af45-642e812b51f5}")]
|
||||
public class VehiclePermit : OmsClass
|
||||
{
|
||||
[OmsName("Permit Index"), OmsGlobalIdentifier("{759f4beb-ee43-47b8-9add-16967bba8ec8}")]
|
||||
public int PermitIndex { get { return (int) GetAttributeValue(); } set { SetAttributeValue(value); } }
|
||||
|
||||
[OmsName("Permit Name"), OmsGlobalIdentifier("{c4f4a59f-c246-4d88-a2fd-588195d5e943}")]
|
||||
public string PermitName { get; set; }
|
||||
}
|
||||
|
||||
public readonly IList<Business> Businesses;
|
||||
}
|
||||
|
||||
public class VehicleForHireTests : OmsModelingTestsBase
|
||||
{
|
||||
protected override OmsDatabase GetDatabase() => new VehicleForHireDB();
|
||||
private OmsDatabase db = new VehicleForHireDB();
|
||||
protected override OmsDatabase GetDatabase() => db;
|
||||
|
||||
[Test]
|
||||
public void ClassesCreated()
|
||||
@ -61,8 +85,12 @@ public class VehicleForHireTests : OmsModelingTestsBase
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RelationshipsCreated()
|
||||
{
|
||||
public void RelationshipsCreated() {
|
||||
CheckRelationshipExists(new Guid("{867126b9-294e-454f-b9c5-88df44353014}"), new Guid("{4b6f186c-babe-4c42-840b-3840373f68c2}"), "has", new Guid("{38a492b9-901f-4074-af45-642e812b51f5}"));
|
||||
|
||||
VehicleForHireDB db = (VehicleForHireDB) GetDatabase();
|
||||
|
||||
VehicleForHireDB.Business busn = new VehicleForHireDB.Business("Ryde Rentals Transportation");
|
||||
db.Businesses.Add(busn);
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user