improve strongly typed validations for Work Set and other Work Data
This commit is contained in:
parent
79d86a933c
commit
3a96529a21
@ -1 +1 @@
|
|||||||
Subproject commit 8bea362b3ca08a642ba196b8670e8e44e5e799e3
|
Subproject commit 8638fc4c3a77de9b6fad3a9a17911995300e71c3
|
||||||
@ -52,4 +52,10 @@ public abstract class AttributeImplementation : ClassImplementation
|
|||||||
{
|
{
|
||||||
ExecuteBuildElementInternal(oms, targetInstance, elementContent, elementContentInstance, objCell);
|
ExecuteBuildElementInternal(oms, targetInstance, elementContent, elementContentInstance, objCell);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected abstract bool IsValidValueInternal(object value);
|
||||||
|
public bool IsValidValue(object value)
|
||||||
|
{
|
||||||
|
return IsValidValueInternal(value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -54,4 +54,9 @@ public class BooleanAttributeImplementation : AttributeImplementation<bool>
|
|||||||
objCell.Add("value", oms.GetAttributeValue<bool>(targetInstance, elementContentInstance));
|
objCell.Add("value", oms.GetAttributeValue<bool>(targetInstance, elementContentInstance));
|
||||||
objCell.Add("text", oms.GetAttributeValue<bool>(targetInstance, elementContentInstance) ? "Yes" : "No");
|
objCell.Add("text", oms.GetAttributeValue<bool>(targetInstance, elementContentInstance) ? "Yes" : "No");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override bool IsValidValueInternal(object value)
|
||||||
|
{
|
||||||
|
return value is bool;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -61,4 +61,9 @@ public class DateAttributeImplementation : AttributeImplementation<DateTime>
|
|||||||
objCell.Add("text", dt.ToString());
|
objCell.Add("text", dt.ToString());
|
||||||
objCell.Add("dateTimePrecision", "DAY");
|
objCell.Add("dateTimePrecision", "DAY");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override bool IsValidValueInternal(object value)
|
||||||
|
{
|
||||||
|
return value is DateTime;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -55,4 +55,9 @@ public class NumericAttributeImplementation : AttributeImplementation<decimal>
|
|||||||
objCell.Add("precision", 6);
|
objCell.Add("precision", 6);
|
||||||
objCell.Add("format", "#0.######");
|
objCell.Add("format", "#0.######");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override bool IsValidValueInternal(object value)
|
||||||
|
{
|
||||||
|
return value is decimal;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -77,4 +77,9 @@ public class TextAttributeImplementation : AttributeImplementation<string>
|
|||||||
objCell.Add("value", oms.GetAttributeValue<string>(targetInstance, elementContentInstance));
|
objCell.Add("value", oms.GetAttributeValue<string>(targetInstance, elementContentInstance));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override bool IsValidValueInternal(object value)
|
||||||
|
{
|
||||||
|
return value is string;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -68,4 +68,17 @@ public class ClassImplementationRegistry
|
|||||||
implementation = null;
|
implementation = null;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IEnumerable<T> GetAll<T>() where T : ClassImplementation
|
||||||
|
{
|
||||||
|
List<T> list = new List<T>();
|
||||||
|
foreach (KeyValuePair<Guid, ClassImplementation> kvp in implementations)
|
||||||
|
{
|
||||||
|
if (kvp.Value is T)
|
||||||
|
{
|
||||||
|
list.Add((T)kvp.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -66,6 +66,7 @@ namespace Mocha.Core
|
|||||||
public static Guid ValidateOnlyOnSubmit { get; } = new Guid("{400fcd8e-823b-4f4a-aa38-b444f763259b}");
|
public static Guid ValidateOnlyOnSubmit { get; } = new Guid("{400fcd8e-823b-4f4a-aa38-b444f763259b}");
|
||||||
public static Guid UserIsLoggedIn { get; } = new Guid("{8e93d9f3-a897-4c97-935c-b3427f90633b}");
|
public static Guid UserIsLoggedIn { get; } = new Guid("{8e93d9f3-a897-4c97-935c-b3427f90633b}");
|
||||||
public static Guid Derived { get; } = new Guid("{66991ca1-ef08-4f30-846c-4984c2a3139d}");
|
public static Guid Derived { get; } = new Guid("{66991ca1-ef08-4f30-846c-4984c2a3139d}");
|
||||||
|
public static Guid IncludeSubclasses { get; } = new Guid("{bc95f90e-d373-48be-b71e-283695afed5a}");
|
||||||
}
|
}
|
||||||
public static class Numeric
|
public static class Numeric
|
||||||
{
|
{
|
||||||
@ -87,5 +88,9 @@ namespace Mocha.Core
|
|||||||
|
|
||||||
public static Guid SecondaryOperandValue { get; } = new Guid("{253a04bb-feb7-474d-b608-43219a753ef8}"); // {e666aa75-6b53-47ea-9afa-369378e17b5d}
|
public static Guid SecondaryOperandValue { get; } = new Guid("{253a04bb-feb7-474d-b608-43219a753ef8}"); // {e666aa75-6b53-47ea-9afa-369378e17b5d}
|
||||||
}
|
}
|
||||||
|
public static class Date
|
||||||
|
{
|
||||||
|
public static Guid DateAndTime { get; } = new Guid("{ea71cc92-a5e9-49c1-b487-8ad178b557d2}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -137,6 +137,72 @@ public class OmsContext
|
|||||||
return defaultValue;
|
return defaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ValidateSubclassConstraints(InstanceHandle parm, System.Collections.IEnumerable en)
|
||||||
|
{
|
||||||
|
bool singular = false;
|
||||||
|
if (!Oms.TryGetAttributeValue<bool>(parm, Oms.GetInstance(KnownAttributeGuids.Boolean.Singular), out singular))
|
||||||
|
{
|
||||||
|
singular = false;
|
||||||
|
}
|
||||||
|
bool includeSubclasses = false;
|
||||||
|
if (!Oms.TryGetAttributeValue<bool>(parm, Oms.GetInstance(KnownAttributeGuids.Boolean.IncludeSubclasses), out includeSubclasses))
|
||||||
|
{
|
||||||
|
includeSubclasses = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ct = 0;
|
||||||
|
foreach (object o in en)
|
||||||
|
{
|
||||||
|
ct++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (singular && ct > 1)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("cannot assign multiple instances to a singular Work Set");
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (object o in en)
|
||||||
|
{
|
||||||
|
if (o is IInstanceReference ir)
|
||||||
|
{
|
||||||
|
IReadOnlyCollection<InstanceHandle> irs = Oms.GetRelatedInstances(parm, Oms.GetInstance(KnownRelationshipGuids.Work_Set__has_valid__Class));
|
||||||
|
if (irs.Count > 0)
|
||||||
|
{
|
||||||
|
if (includeSubclasses)
|
||||||
|
{
|
||||||
|
foreach (InstanceHandle possibleParentClass in irs)
|
||||||
|
{
|
||||||
|
if (!Oms.IsInstanceOf(ir, possibleParentClass))
|
||||||
|
{
|
||||||
|
throw new ArgumentException("instance reference must be an instance of appropriate class");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
InstanceHandle parentClass = Oms.GetParentClass(ir);
|
||||||
|
if (!irs.Contains(parentClass))
|
||||||
|
{
|
||||||
|
throw new ArgumentException("instance reference must be an instance of appropriate class");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private void ValidateAttributeConstraints(InstanceHandle parm, object value)
|
||||||
|
{
|
||||||
|
Guid parentClassGuid = Oms.GetGlobalIdentifier(Oms.GetParentClass(parm));
|
||||||
|
IEnumerable<AttributeImplementation> attrs = Oms.ClassImplementations.GetAll<AttributeImplementation>();
|
||||||
|
foreach (AttributeImplementation impl in attrs)
|
||||||
|
{
|
||||||
|
if (impl.ClassGuid == parentClassGuid && !impl.IsValidValue(value))
|
||||||
|
{
|
||||||
|
throw new ArgumentException(String.Format("value {0} cannot be converted to a `{1}`", value is string ? "\"" + value + "\"" : value, Oms.GetInstanceText(Oms.GetParentClass(parm))), nameof(value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void SetWorkData(IInstanceReference parm, object? value)
|
public void SetWorkData(IInstanceReference parm, object? value)
|
||||||
{
|
{
|
||||||
SetWorkData(parm.GetHandle(), value);
|
SetWorkData(parm.GetHandle(), value);
|
||||||
@ -147,75 +213,31 @@ public class OmsContext
|
|||||||
{
|
{
|
||||||
if (Oms.IsInstanceOf(parm, Oms.GetInstance(KnownInstanceGuids.Classes.WorkSet)))
|
if (Oms.IsInstanceOf(parm, Oms.GetInstance(KnownInstanceGuids.Classes.WorkSet)))
|
||||||
{
|
{
|
||||||
bool singular = false;
|
|
||||||
if (!Oms.TryGetAttributeValue<bool>(parm, Oms.GetInstance(KnownAttributeGuids.Boolean.Singular), out singular))
|
|
||||||
{
|
|
||||||
singular = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (value is IInstanceReference)
|
if (value is IInstanceReference)
|
||||||
{
|
{
|
||||||
IReadOnlyCollection<InstanceHandle> irs = Oms.GetRelatedInstances(parm, Oms.GetInstance(KnownRelationshipGuids.Work_Set__has_valid__Class));
|
ValidateSubclassConstraints(parm, new IInstanceReference[] { (IInstanceReference)value });
|
||||||
if (irs.Count > 0)
|
|
||||||
{
|
|
||||||
InstanceHandle ir = ((IInstanceReference)value).GetHandle();
|
|
||||||
InstanceHandle parentClass = Oms.GetParentClass(ir);
|
|
||||||
if (!irs.Contains(parentClass))
|
|
||||||
{
|
|
||||||
throw new ArgumentException("instance reference must be an instance of appropriate class");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (value is IEnumerable<InstanceHandle>)
|
else if (value is IEnumerable<InstanceHandle>)
|
||||||
{
|
{
|
||||||
IEnumerable<InstanceHandle> insts = (IEnumerable<InstanceHandle>)value;
|
ValidateSubclassConstraints(parm, (IEnumerable<InstanceHandle>)value);
|
||||||
if (singular && insts.Count() > 1)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException("Singular Work Set must only contain a single InstanceReference or be an array of InstanceReference that contains exactly zero or one item.");
|
|
||||||
}
|
|
||||||
IEnumerable<InstanceHandle> irs = Oms.GetRelatedInstances(parm, Oms.GetInstance(KnownRelationshipGuids.Work_Set__has_valid__Class));
|
|
||||||
if (irs.Count() > 0)
|
|
||||||
{
|
|
||||||
foreach (InstanceHandle ir in insts)
|
|
||||||
{
|
|
||||||
InstanceHandle parentClass = Oms.GetParentClass(ir);
|
|
||||||
if (!irs.Contains(parentClass))
|
|
||||||
{
|
|
||||||
throw new ArgumentException("instance reference must be an instance of appropriate class");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// value = ((IEnumerable<InstanceHandle>)value).FirstOrDefault();
|
|
||||||
}
|
}
|
||||||
else if (value is IEnumerable<InstanceWrapper>)
|
else if (value is IEnumerable<InstanceWrapper>)
|
||||||
{
|
{
|
||||||
IEnumerable<InstanceWrapper> insts = (IEnumerable<InstanceWrapper>)value;
|
ValidateSubclassConstraints(parm, (IEnumerable<InstanceWrapper>)value);
|
||||||
if (singular && insts.Count() > 1)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException("Singular Work Set must only contain a single InstanceReference or be an array of InstanceReference that contains exactly zero or one item.");
|
|
||||||
}
|
}
|
||||||
IEnumerable<InstanceHandle> irs = Oms.GetRelatedInstances(parm, Oms.GetInstance(KnownRelationshipGuids.Work_Set__has_valid__Class));
|
else if (value is IEnumerable<IInstanceReference>)
|
||||||
if (irs != null)
|
|
||||||
{
|
{
|
||||||
if (irs.Count() > 0)
|
ValidateSubclassConstraints(parm, (IEnumerable<IInstanceReference>)value);
|
||||||
{
|
|
||||||
foreach (InstanceWrapper iw in insts)
|
|
||||||
{
|
|
||||||
InstanceHandle ir = iw.GetHandle();
|
|
||||||
InstanceHandle parentClass = Oms.GetParentClass(ir);
|
|
||||||
if (!irs.Contains(parentClass))
|
|
||||||
{
|
|
||||||
throw new ArgumentException("instance reference must be an instance of appropriate class");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw new ArgumentException(String.Format("cannot assign literal data '{0}' to a Work Set", value));
|
throw new ArgumentException(String.Format("cannot assign literal data '{0}' to a Work Set", value));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ValidateAttributeConstraints(parm, value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_WorkData[parm] = value;
|
_WorkData[parm] = value;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -59,6 +59,28 @@ public class WorkSetTests : OmsTestsBase
|
|||||||
}, Throws.ArgumentException);
|
}, Throws.ArgumentException);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SingleValidClassConstraintWithInheritance()
|
||||||
|
{
|
||||||
|
// we should be able to put a `Text Attribute` instance into this Work Set if its valid class is `Attribute`
|
||||||
|
InstanceHandle c_Attribute = Oms.GetInstance(KnownInstanceGuids.Classes.Attribute);
|
||||||
|
InstanceHandle c_TextAttribute = Oms.GetInstance(KnownInstanceGuids.Classes.TextAttribute);
|
||||||
|
|
||||||
|
WorkSet workSet = Oms.CreateWorkSet("Dummy Work Set", true, new InstanceHandle[]
|
||||||
|
{
|
||||||
|
c_Attribute
|
||||||
|
});
|
||||||
|
Oms.SetAttributeValue(workSet, Oms.GetInstance(KnownAttributeGuids.Boolean.IncludeSubclasses), true);
|
||||||
|
|
||||||
|
InstanceHandle a_Name = Oms.GetInstance(KnownAttributeGuids.Text.Name);
|
||||||
|
|
||||||
|
OmsContext context = Oms.CreateContext();
|
||||||
|
Assert.That(delegate ()
|
||||||
|
{
|
||||||
|
context.SetWorkData(workSet, a_Name);
|
||||||
|
}, Throws.Nothing);
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void MultipleValidClassConstraintSingular()
|
public void MultipleValidClassConstraintSingular()
|
||||||
{
|
{
|
||||||
@ -151,4 +173,64 @@ public class WorkSetTests : OmsTestsBase
|
|||||||
context.SetWorkData(workSet, true);
|
context.SetWorkData(workSet, true);
|
||||||
}, Throws.ArgumentException);
|
}, Throws.ArgumentException);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TextAttributeWorkData()
|
||||||
|
{
|
||||||
|
OmsContext context = Oms.CreateContext();
|
||||||
|
Assert.That(delegate ()
|
||||||
|
{
|
||||||
|
// cannot assign boolean to Text Attribute
|
||||||
|
InstanceHandle a_Name = Oms.GetInstance(KnownAttributeGuids.Text.Name);
|
||||||
|
context.SetWorkData(a_Name, true);
|
||||||
|
}, Throws.ArgumentException);
|
||||||
|
Assert.That(delegate ()
|
||||||
|
{
|
||||||
|
// cannot assign DateTime to Text Attribute
|
||||||
|
InstanceHandle a_Name = Oms.GetInstance(KnownAttributeGuids.Text.Name);
|
||||||
|
context.SetWorkData(a_Name, DateTime.Now);
|
||||||
|
}, Throws.ArgumentException);
|
||||||
|
Assert.That(delegate ()
|
||||||
|
{
|
||||||
|
// cannot assign decimal to Text Attribute
|
||||||
|
InstanceHandle a_Name = Oms.GetInstance(KnownAttributeGuids.Text.Name);
|
||||||
|
context.SetWorkData(a_Name, 5.3M);
|
||||||
|
}, Throws.ArgumentException);
|
||||||
|
Assert.That(delegate ()
|
||||||
|
{
|
||||||
|
// can assign string to Text Attribute
|
||||||
|
InstanceHandle a_Name = Oms.GetInstance(KnownAttributeGuids.Text.Name);
|
||||||
|
context.SetWorkData(a_Name, "hello world");
|
||||||
|
}, Throws.Nothing);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void DateAttributeWorkData()
|
||||||
|
{
|
||||||
|
OmsContext context = Oms.CreateContext();
|
||||||
|
Assert.That(delegate ()
|
||||||
|
{
|
||||||
|
// cannot assign boolean to Date Attribute
|
||||||
|
InstanceHandle a_Name = Oms.GetInstance(KnownAttributeGuids.Date.DateAndTime);
|
||||||
|
context.SetWorkData(a_Name, true);
|
||||||
|
}, Throws.ArgumentException);
|
||||||
|
Assert.That(delegate ()
|
||||||
|
{
|
||||||
|
// cannot assign decimal to Date Attribute
|
||||||
|
InstanceHandle a_Name = Oms.GetInstance(KnownAttributeGuids.Date.DateAndTime);
|
||||||
|
context.SetWorkData(a_Name, 5.3M);
|
||||||
|
}, Throws.ArgumentException);
|
||||||
|
Assert.That(delegate ()
|
||||||
|
{
|
||||||
|
// cannot assign string to Date Attribute
|
||||||
|
InstanceHandle a_Name = Oms.GetInstance(KnownAttributeGuids.Date.DateAndTime);
|
||||||
|
context.SetWorkData(a_Name, "hello world");
|
||||||
|
}, Throws.ArgumentException);
|
||||||
|
Assert.That(delegate ()
|
||||||
|
{
|
||||||
|
// can assign DateTime to Date Attribute
|
||||||
|
InstanceHandle a_Name = Oms.GetInstance(KnownAttributeGuids.Date.DateAndTime);
|
||||||
|
context.SetWorkData(a_Name, DateTime.Now);
|
||||||
|
}, Throws.Nothing);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user