Skip to content

Commit 5548a73

Browse files
committed
Update data type validation process
1 parent cecb26a commit 5548a73

File tree

5 files changed

+78
-48
lines changed

5 files changed

+78
-48
lines changed

JsonSchema/JsonSchema.csproj

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55
<Description>A simplified, concise, intuitive, and extensible JSON Schema</Description>
66
<Authors>Relogic Labs</Authors>
77
<Company>Relogic Labs</Company>
8-
<Version>1.4.0</Version>
9-
<PackageVersion>1.4.0</PackageVersion>
10-
<AssemblyVersion>1.4.0</AssemblyVersion>
8+
<Version>1.5.0</Version>
9+
<PackageVersion>1.5.0</PackageVersion>
10+
<AssemblyVersion>1.5.0</AssemblyVersion>
1111
<PackageTags>JsonSchema;Schema;Json;Validation;Assert;Test</PackageTags>
1212
<Copyright>Copyright © Relogic Labs. All rights reserved.</Copyright>
1313
<NeutralLanguage>en</NeutralLanguage>

JsonSchema/RelogicLabs/JsonSchema/Tree/RuntimeContext.cs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ public class RuntimeContext
99
{
1010
private readonly FunctionManager _functionManager;
1111
private readonly PragmaManager _pragmaManager;
12+
private int _disableCount;
1213

1314
internal MessageFormatter MessageFormatter { get; set; }
1415
public bool ThrowException { get; set; }
@@ -59,10 +60,23 @@ public JDefinition AddDefinition(JDefinition definition)
5960
internal bool AreEqual(double value1, double value2)
6061
=> Math.Abs(value1 - value2) < FloatingPointTolerance;
6162

63+
internal T TryMatch<T>(Func<T> function)
64+
{
65+
try
66+
{
67+
_disableCount += 1;
68+
return function();
69+
}
70+
finally
71+
{
72+
_disableCount -= 1;
73+
}
74+
}
75+
6276
internal bool FailWith(Exception exception)
6377
{
64-
if(ThrowException) throw exception;
65-
Exceptions.Enqueue(exception);
78+
if(ThrowException && _disableCount == 0) throw exception;
79+
if(_disableCount == 0) Exceptions.Enqueue(exception);
6680
return false;
6781
}
6882
}

JsonSchema/RelogicLabs/JsonSchema/Types/JDataType.cs

Lines changed: 39 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using RelogicLabs.JsonSchema.Utilities;
55
using static RelogicLabs.JsonSchema.Message.ErrorCode;
66
using static RelogicLabs.JsonSchema.Message.ErrorDetail;
7+
using static RelogicLabs.JsonSchema.Message.MatchReport;
78

89
namespace RelogicLabs.JsonSchema.Types;
910

@@ -14,7 +15,7 @@ public class JDataType : JBranch, INestedMode
1415
public required JAlias? Alias { get; init; }
1516
public required bool Nested { get; init; }
1617
public override IEnumerable<JNode> Children => _children;
17-
18+
1819
internal JDataType(IDictionary<JNode, JNode> relations) : base(relations) { }
1920

2021
internal override JNode Initialize()
@@ -27,51 +28,60 @@ internal override JNode Initialize()
2728

2829
public override bool Match(JNode node)
2930
{
30-
if(!Nested) return JsonType.Match(node);
31-
if(node is not JComposite composite) return FailWith(
32-
new JsonSchemaException(
33-
new ErrorDetail(DTYP02, InvalidNestedDataType),
34-
ExpectedDetail.AsInvalidDataType(this),
35-
ActualDetail.AsInvalidDataType(node)));
31+
if(!Nested) return _MatchCurrent(node);
32+
if(node is not JComposite composite) return false;
3633
IList<JNode> components = composite.GetComponents();
37-
return components.Select(MatchCurrent).AllTrue();
34+
return components.Select(_MatchCurrent).AllTrue();
3835
}
3936

40-
private bool MatchCurrent(JNode node)
37+
private bool _MatchCurrent(JNode node)
38+
=> MatchCurrent(node) == Success;
39+
40+
private MatchReport MatchCurrent(JNode node)
4141
{
42-
bool result = true;
43-
result &= JsonType.Match(node);
44-
if(Alias == null) return result;
42+
var result = JsonType.Match(node) ? Success : TypeError;
43+
if(Alias == null || result != Success) return result;
4544
Runtime.Definitions.TryGetValue(Alias, out var validator);
46-
if(validator == null) return FailWith(new DefinitionNotFoundException(
47-
MessageFormatter.FormatForSchema(DEFI03, Alias.Name, Context)));
48-
result &= validator.Match(node);
45+
if(validator == null) return AliasError;
46+
result = validator.Match(node) ? Success : ArgumentError;
4947
return result;
5048
}
5149

5250
internal bool MatchForReport(JNode node)
5351
{
54-
if(!Nested && !JsonType.Match(node)) return FailWith(
55-
new JsonSchemaException(new ErrorDetail(DTYP04, DataTypeMismatch),
56-
ExpectedDetail.AsDataTypeMismatch(this),
57-
ActualDetail.AsDataTypeMismatch(node)));
52+
if(!Nested) return MatchForReport(node, false);
5853
if(node is not JComposite composite) return FailWith(
5954
new JsonSchemaException(
60-
new ErrorDetail(DTYP05, InvalidNestedDataType),
61-
ExpectedDetail.AsInvalidDataType(this),
62-
ActualDetail.AsInvalidDataType(node)));
55+
new ErrorDetail(DTYP03, InvalidNestedDataType),
56+
ExpectedDetail.AsInvalidNestedDataType(this),
57+
ActualDetail.AsInvalidNestedDataType(node)));
6358
IList<JNode> components = composite.GetComponents();
6459
bool result = true;
65-
foreach(var c in components)
66-
{
67-
if(!MatchCurrent(c)) result &= FailWith(new JsonSchemaException(
68-
new ErrorDetail(DTYP06, DataTypeMismatch),
69-
ExpectedDetail.AsDataTypeMismatch(this),
70-
ActualDetail.AsDataTypeMismatch(c)));
71-
}
60+
foreach(var c in components) result &= MatchForReport(c, true);
7261
return result;
7362
}
7463

64+
private bool MatchForReport(JNode node, bool nested)
65+
{
66+
var result = MatchCurrent(node);
67+
if(ReferenceEquals(result, TypeError)) return FailWith(
68+
new JsonSchemaException(
69+
new ErrorDetail(TypeError.GetCode(nested), DataTypeMismatch),
70+
ExpectedDetail.AsDataTypeMismatch(this),
71+
ActualDetail.AsDataTypeMismatch(node)));
72+
if(ReferenceEquals(result, AliasError)) return FailWith(
73+
new DefinitionNotFoundException(
74+
MessageFormatter.FormatForSchema(AliasError.GetCode(nested),
75+
$"No definition found for {Alias!.Name}", Context)));
76+
if(ReferenceEquals(result, ArgumentError)) return FailWith(
77+
new JsonSchemaException(
78+
new ErrorDetail(ArgumentError.GetCode(nested),
79+
DataTypeArgumentFailed),
80+
ExpectedDetail.AsDataTypeArgumentFailed(this),
81+
ActualDetail.AsDataTypeArgumentFailed(node)));
82+
return true;
83+
}
84+
7585
public override bool Equals(object? obj)
7686
{
7787
if(ReferenceEquals(null, obj)) return false;

JsonSchema/RelogicLabs/JsonSchema/Types/JValidator.cs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,21 +40,28 @@ public override bool Match(JNode node)
4040
ExpectedDetail.AsValueMismatch(Value!),
4141
ActualDetail.AsValueMismatch(node)));
4242
var rDataType = MatchDataType(node);
43-
if(!rDataType) DataTypes.ForEach(d => d.MatchForReport(node));
4443
var fDataType = rDataType && DataTypes.Count != 0;
4544
bool rFunction = Functions.Where(f => f.IsApplicable(node) || !fDataType)
4645
.Select(f => f.Match(node)).ForEachTrue() || Functions.Count == 0;
4746
return rValue & rDataType & rFunction;
4847
}
4948

5049
private bool MatchDataType(JNode node)
50+
{
51+
if(Runtime.TryMatch(() => CheckDataType(node))) return true;
52+
DataTypes.Where(d => !d.Nested).ForEach(d => d.MatchForReport(node));
53+
DataTypes.Where(d => d.Nested).ForEach(d => d.MatchForReport(node));
54+
return false;
55+
}
56+
57+
private bool CheckDataType(JNode node)
5158
{
5259
var list1 = DataTypes.Where(d => !d.Nested).Select(d => d.Match(node)).ToList();
53-
var result1 = list1.AnyTrue() || list1.Count == 0;
60+
var result1 = list1.AnyTrue();
5461
var list2 = DataTypes.Where(d => d.Nested && (d.IsApplicable(node) || !result1))
5562
.Select(d => d.Match(node)).ToList();
5663
var result2 = list2.AnyTrue() || list2.Count == 0;
57-
return result1 && result2;
64+
return (result1 || list1.Count == 0) && result2;
5865
}
5966

6067
public override string ToString() => (

README.md

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ The next example represents an expanded version of the previous one, which bring
6868
%title: "Extended User Profile Dashboard API Response"
6969
%version: 2.0.0
7070
%include: RelogicLabs.JsonSchema.Tests.Positive.ExternalFunctions,
71-
RelogicLabs.JsonSchema.Tests
71+
RelogicLabs.JsonSchema.Tests
7272

7373
%pragma IgnoreUndefinedProperties: true
7474

@@ -92,7 +92,7 @@ The next example represents an expanded version of the previous one, which bring
9292
} #object #null
9393
}
9494

95-
%define $tags: @length(1, 10) #array($tag)
95+
%define $tags: @length(1, 10) #string*($tag) #array
9696
%define $tag: @length(3, 20) @regex("[A-Za-z_]+") #string
9797

9898
%schema:
@@ -101,10 +101,9 @@ The next example represents an expanded version of the previous one, which bring
101101
"id": @range(1, 10000) #integer,
102102
/*username does not allow special characters*/
103103
"username": @regex("[a-z_]{3,30}") #string,
104-
/*currently only one role is allowed by system*/
105-
"role": "user" #string,
104+
"role": @enum("user", "admin") #string,
106105
"isActive": #boolean, //user account current status
107-
"registeredAt": #time,
106+
"registeredAt": @time("DD-MM-YYYY hh:mm:ss") #string,
108107
"profile": {
109108
"firstName": @regex("[A-Za-z]{3,50}") #string,
110109
"lastName": @regex("[A-Za-z]{3,50}") #string,
@@ -139,9 +138,9 @@ The subsequent JSON sample is an illustrative example that successfully validate
139138
"user": {
140139
"id": 1234,
141140
"username": "johndoe",
142-
"role": "user",
141+
"role": "admin",
143142
"isActive": true,
144-
"registeredAt": "2023-09-06T15:10:30.639Z",
143+
"registeredAt": "06-09-2023 15:10:30",
145144
"profile": {
146145
"firstName": "John",
147146
"lastName": "Doe",
@@ -209,9 +208,9 @@ The subsequent JSON sample is an illustrative example that successfully validate
209208
"price": 1299.99,
210209
"inStock": false,
211210
"specs": {
212-
"cpu": "Intel i7",
213-
"ram": "16GB",
214-
"storage": "512GB SSD"
211+
"cpu": "Intel i11",
212+
"ram": "11GB",
213+
"storage": "11GB SSD"
215214
}
216215
}
217216
],
@@ -222,4 +221,4 @@ The subsequent JSON sample is an illustrative example that successfully validate
222221
}
223222
}
224223
```
225-
For more information about the schema syntax format and library functionalities, please refer to the reference documentation [here](https://relogiclabs.github.io/JsonSchema-DotNet/api/index.html).
224+
For more information about the schema syntax format and library functionalities, please refer to the reference documentation [here](https://relogiclabs.github.io/JsonSchema-DotNet/api/index.html).

0 commit comments

Comments
 (0)