Commit 54308cc
Multiple-create: Request Validation (#2057)
## Why make this change?
With support for multiple-create, we introduce additional flexibility in
the GraphQL schema where we make the referencing fields in an entity
optional because their value can be derived from insertions in the
referenced entity. So to say, _the values of referencing fields in a
referencing entity can have 3 sources of truth_. The value for a
referencing field can be derived via:
1. User input data
2. Insertion in the parent referenced entity (if current entity is a
referencing entity for a relationship with its parent entity)
3. Insertion in the child referenced entity (if the current entity is a
referencing entity for a relationship with its child entity)
**_They can all exist at the same time, or none of them can. Presence of
more than one sources of truth leads to possible conflicting values for
the referencing column. Thus, at a time, we want exactly one of them to
be present - so that we exactly one source of truth_**. This needs us to
do request validation during request execution, so that only valid GQL
mutations reach the query generation/query execution stage. This PR adds
the logic for the same.
## What is this change?
- Added class `MultipleMutationInputValidator.cs` to perform the
validations for a multiple-create mutation.
- Added class `MultipleMutationEntityInputValidationContext` to store
relevant information while performing validations on a particular
entity.
- A call to the method
`MultipleMutationInputValidator.ValidateGraphQLValueNode()` will be made
_just after Authorization_ - request validation only occurs when the
user is authorized to execute the mutation.
- The method `MultipleMutationInputValidator.ValidateGraphQLValueNode()`
makes recursive call to itself to parse out the entire create mutation
request body based on an entity or relationship basis. Meaning, this
method will be called on the top-level entity, followed by all the
relationships for that entity, followed by all the relationships for the
entity's relationships and so on....
- The actual validation for the input data for an entity (top-level
entity or a nested entity) which includes column fields and relationship
fields is done by the method
`GraphQLRequestValidator.ValidateObjectFieldNodes()` which is called
from the method `ValidateGraphQLValueNode()`.
- The method `ValidateObjectFieldNodes()` contains logic to ensure that
when the current entity acts as the referencing entity for the
relationships with its target entity, then the current entity should not
specify a value for the referencing fields - as the values for the
referencing fields will be derived from the insertion in the referenced
target entity. Note: The determination of referencing entity is done via
a call to `MultipleCreateOrderHelper.GetReferencingEntityName()` method
added via: #2056.
- The method `ValidateObjectFieldNodes()` makes calls to
1. `ValidateAbsenceOfReferencingColumnsInTargetEntity()`: To validate
that the current entity does not specify value for referencing columns
to its parent entity (when parent entity is the referenced entity).
2. `ProcessRelationshipField()`: To process a relationship field and
does several things. Please refer to method summary.
3. `ValidateAbsenceOfRepeatedReferencingColumn()`: This method is called
for all the relationships with the current entity which are included in
the request body. This ensures that referencing columns in the
referencing entity (whichever entity, either source or target turns out
as the referencing entity) does not hold references to multiple columns
in the referenced entity - to avoid multiple sources of truth for the
referencing column's value. (Issue:
#2019)
4. `ValidatePresenceOfRequiredColumnsForInsertion()`: To ensure that we
have one source of truth for values for referencing fields.
5. `ValidateRelationshipFields()`: Recursively perform the same
validations for all the relationships with the current entity included
in the mutation request body.
`
## How was this tested?
- [x] Integration Tests - Added tests to
`MultipleMutationIntegrationTests.cs` to validate:
1. Throwing exception for absence of source of truth for referencing
column for create one mutations
2. Throwing exception for absence of source of truth for referencing
column for create multiple mutations.
3. Throwing exception for presence of multiple sources of truth for
referencing column for create one mutations.
4. Throwing exception for presence of multiple sources of truth for
referencing column for create one mutations.
## Sample Request(s)
1. Request:

Response:

2. Request:

Response:

3. Request and response:

---------
Co-authored-by: Shyam Sundar J <[email protected]>
Co-authored-by: Sean Leonard <[email protected]>1 parent a352f71 commit 54308cc
File tree
15 files changed
+1400
-8
lines changed- config-generators
- src
- Config
- Core
- Models
- Resolvers
- Services
- MetadataProviders
- OpenAPI
- Service.GraphQLBuilder
- Service.Tests
- Configuration
- Snapshots
- SqlTests/GraphQLMutationTests
- Unittests/MultipleCreateUnitTests
15 files changed
+1400
-8
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | | - | |
| 1 | + | |
2 | 2 | | |
3 | 3 | | |
4 | 4 | | |
| |||
33 | 33 | | |
34 | 34 | | |
35 | 35 | | |
| 36 | + | |
| 37 | + | |
36 | 38 | | |
37 | 39 | | |
38 | 40 | | |
| |||
145 | 147 | | |
146 | 148 | | |
147 | 149 | | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
148 | 153 | | |
149 | 154 | | |
150 | 155 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
31 | 31 | | |
32 | 32 | | |
33 | 33 | | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
34 | 38 | | |
35 | 39 | | |
36 | 40 | | |
| |||
Lines changed: 48 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
96 | 96 | | |
97 | 97 | | |
98 | 98 | | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
99 | 118 | | |
100 | 119 | | |
101 | 120 | | |
| |||
1225 | 1244 | | |
1226 | 1245 | | |
1227 | 1246 | | |
1228 | | - | |
| 1247 | + | |
1229 | 1248 | | |
1230 | 1249 | | |
1231 | 1250 | | |
| |||
1236 | 1255 | | |
1237 | 1256 | | |
1238 | 1257 | | |
1239 | | - | |
| 1258 | + | |
1240 | 1259 | | |
1241 | 1260 | | |
1242 | 1261 | | |
1243 | 1262 | | |
1244 | 1263 | | |
1245 | | - | |
| 1264 | + | |
1246 | 1265 | | |
1247 | 1266 | | |
1248 | 1267 | | |
| |||
Lines changed: 25 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
208 | 208 | | |
209 | 209 | | |
210 | 210 | | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
211 | 236 | | |
212 | 237 | | |
Lines changed: 32 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1911 | 1911 | | |
1912 | 1912 | | |
1913 | 1913 | | |
| 1914 | + | |
| 1915 | + | |
| 1916 | + | |
| 1917 | + | |
| 1918 | + | |
| 1919 | + | |
| 1920 | + | |
| 1921 | + | |
| 1922 | + | |
| 1923 | + | |
| 1924 | + | |
| 1925 | + | |
| 1926 | + | |
| 1927 | + | |
| 1928 | + | |
| 1929 | + | |
| 1930 | + | |
| 1931 | + | |
| 1932 | + | |
| 1933 | + | |
| 1934 | + | |
| 1935 | + | |
| 1936 | + | |
| 1937 | + | |
| 1938 | + | |
| 1939 | + | |
| 1940 | + | |
| 1941 | + | |
| 1942 | + | |
| 1943 | + | |
| 1944 | + | |
| 1945 | + | |
1914 | 1946 | | |
1915 | 1947 | | |
1916 | 1948 | | |
0 commit comments