private void AssertAttribute <TPropertyType, TTokenType>(IResourceTypeRegistration reg, string attributeName, JToken tokenToSet, TPropertyType expectedPropertyValue, TTokenType expectedTokenAfterSet, Func <AttributeGrabBag, TPropertyType> getPropertyFunc) { var grabBag = InitializeGrabBag(); var field = reg.GetFieldByName(attributeName); var attribute = (ResourceTypeAttribute)field; attribute.JsonKey.Should().Be(attributeName); attribute.SetValue(grabBag, tokenToSet); var propertyValueAfterSet = getPropertyFunc(grabBag); propertyValueAfterSet.Should().Be(expectedPropertyValue); var convertedToken = attribute.GetValue(grabBag); if (expectedTokenAfterSet == null) { convertedToken.Should().BeNull(); } else { var convertedTokenValue = convertedToken.Value <TTokenType>(); convertedTokenValue.Should().Be(expectedTokenAfterSet); } }
private void AssertAttributeHelper(IResourceTypeRegistration reg, string attributeName, JToken tokenToSet, Action <AttributeGrabBag> testPropertyValueAfterSet, Action <JToken> testTokenAfterSetAndGet) { var grabBag = InitializeGrabBag(); var field = reg.GetFieldByName(attributeName); var attribute = (ResourceTypeAttribute)field; attribute.JsonKey.Should().Be(attributeName); attribute.SetValue(grabBag, tokenToSet); testPropertyValueAfterSet(grabBag); var convertedToken = attribute.GetValue(grabBag); testTokenAfterSetAndGet(convertedToken); }
private Expression GetPredicate(string filterField, IResourceTypeRegistration registration, ParameterExpression param, string queryValue) { if (filterField == "id") { return(GetPredicateBodyForProperty(registration.IdProperty, queryValue, param)); } var resourceTypeField = registration.GetFieldByName(filterField); if (resourceTypeField == null) { throw JsonApiException.CreateForBadRequest( string.Format("No attribute {0} exists on the specified type.", filterField)); } if (string.IsNullOrWhiteSpace(queryValue)) { queryValue = null; } // See if it is a field property var fieldModelProperty = resourceTypeField as ResourceTypeAttribute; if (fieldModelProperty != null) { return(GetPredicateBodyForField(fieldModelProperty, queryValue, param)); } // See if it is a relationship property var relationshipModelProperty = resourceTypeField as ResourceTypeRelationship; if (relationshipModelProperty != null) { return(GetPredicateBodyForRelationship(relationshipModelProperty, queryValue, param)); } throw JsonApiException.CreateForBadRequest( string.Format("The attribute {0} is unsupported for filtering.", filterField)); }
/// <summary> /// Merges the field values of the given resource object into the materialized object /// </summary> /// <param name="resourceObject"></param> /// <param name="material"></param> /// <param name="registration"></param> /// <param name="cancellationToken"></param> /// <returns></returns> /// <exception cref="DeserializationException">Thrown when a semantically incorrect part of the document is encountered</exception> protected virtual async Task MergeFieldsIntoProperties(IResourceObject resourceObject, object material, IResourceTypeRegistration registration, CancellationToken cancellationToken) { foreach (var attributeValue in resourceObject.Attributes) { var attribute = registration.GetFieldByName(attributeValue.Key) as ResourceTypeAttribute; if (attribute == null) { continue; } attribute.SetValue(material, attributeValue.Value); } foreach (var relationshipValue in resourceObject.Relationships) { var linkage = relationshipValue.Value.Linkage; var typeRelationship = registration.GetFieldByName(relationshipValue.Key) as ResourceTypeRelationship; if (typeRelationship == null) { continue; } if (typeRelationship.IsToMany) { if (linkage == null) { throw new DeserializationException("Missing linkage for to-many relationship", "Expected an array for to-many linkage, but no linkage was specified.", "/data/relationships/" + relationshipValue.Key); } if (!linkage.IsToMany) { throw new DeserializationException("Invalid linkage for to-many relationship", "Expected an array for to-many linkage.", "/data/relationships/" + relationshipValue.Key + "/data"); } // TODO: One query per related object is going to be slow. At the very least, we should be able to group the queries by type var newCollection = new List <object>(); foreach (var resourceIdentifier in linkage.Identifiers) { var relatedObjectRegistration = _registry.GetRegistrationForResourceTypeName(resourceIdentifier.Type); var relatedObject = await GetExistingRecord(relatedObjectRegistration, resourceIdentifier.Id, null, cancellationToken); newCollection.Add(relatedObject); } var method = _openSetToManyRelationshipValueMethod.MakeGenericMethod(typeRelationship.RelatedType); method.Invoke(this, new[] { material, newCollection, typeRelationship }); } else { if (linkage == null) { throw new DeserializationException("Missing linkage for to-one relationship", "Expected an object for to-one linkage, but no linkage was specified.", "/data/relationships/" + relationshipValue.Key); } if (linkage.IsToMany) { throw new DeserializationException("Invalid linkage for to-one relationship", "Expected an object or null for to-one linkage", "/data/relationships/" + relationshipValue.Key + "/data"); } var identifier = linkage.Identifiers.FirstOrDefault(); if (identifier == null) { typeRelationship.Property.SetValue(material, null); } else { var relatedObjectRegistration = _registry.GetRegistrationForResourceTypeName(identifier.Type); var relatedObject = await GetExistingRecord(relatedObjectRegistration, identifier.Id, null, cancellationToken); typeRelationship.Property.SetValue(material, relatedObject); } } } }