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); } }
public void AddRegistration(IResourceTypeRegistration registration) { lock (_registrationsByType) { lock (_registrationsByName) { if (_registrationsByType.ContainsKey(registration.Type)) { throw new InvalidOperationException(String.Format("The type `{0}` has already been registered.", registration.Type.FullName)); } IResourceTypeRegistration existingRegistration; if (_registrationsByName.TryGetValue(registration.ResourceTypeName, out existingRegistration)) { throw new InvalidOperationException( String.Format("Could not register `{0} under resource type name `{1}` because `{1}` has already been registered by `{2}`.", registration.Type.FullName, registration.ResourceTypeName, existingRegistration.Type.FullName)); } _registrationsByType.Add(registration.Type, registration); _registrationsByName.Add(registration.ResourceTypeName, registration); } } }
/// <inheritdoc /> public object CreateEphemeralResource(IResourceTypeRegistration resourceTypeRegistration, string id) { var obj = Activator.CreateInstance(resourceTypeRegistration.Type); resourceTypeRegistration.SetIdForResource(obj, id); return(obj); }
public StarshipOfficersRelatedResourceMaterializer(ResourceTypeRelationship relationship, DbContext dbContext, IQueryableResourceCollectionDocumentBuilder queryableResourceCollectionDocumentBuilder, ISortExpressionExtractor sortExpressionExtractor, IResourceTypeRegistration primaryTypeRegistration) : base(relationship, dbContext, queryableResourceCollectionDocumentBuilder, sortExpressionExtractor, primaryTypeRegistration) { _dbContext = dbContext; }
/// <summary> /// Gets an existing record from the store by ID, if it exists /// </summary> /// <returns></returns> protected virtual async Task <object> GetExistingRecord(IResourceTypeRegistration registration, string id, ResourceTypeRelationship[] relationshipsToInclude, CancellationToken cancellationToken) { var method = _openGetExistingRecordGenericMethod.MakeGenericMethod(registration.Type); var result = (dynamic)method.Invoke(this, new object[] { registration, id, relationshipsToInclude, cancellationToken }); return(await result); }
public StarshipShipCounselorRelatedResourceMaterializer( ISingleResourceDocumentBuilder singleResourceDocumentBuilder, IBaseUrlService baseUrlService, IResourceTypeRegistration primaryTypeRegistration, ResourceTypeRelationship relationship, DbContext dbContext) : base(singleResourceDocumentBuilder, baseUrlService, primaryTypeRegistration, relationship, dbContext) { _dbContext = dbContext; }
private IQueryable <TResource> FilterById <TResource>(string id, IResourceTypeRegistration resourceTypeRegistration, params Expression <Func <TResource, object> >[] includes) where TResource : class { var param = Expression.Parameter(typeof(TResource)); var filterByIdExpression = resourceTypeRegistration.GetFilterByIdExpression(param, id); var predicate = Expression.Lambda <Func <TResource, bool> >(filterByIdExpression, param); return(Filter(predicate, includes)); }
private IQueryable <TResource> FilterById <TResource>(string id, IResourceTypeRegistration resourceTypeRegistration) where TResource : class { var param = Expression.Parameter(typeof(TResource)); var filterByIdExpression = resourceTypeRegistration.GetFilterByIdExpression(param, id); var predicate = Expression.Lambda <Func <TResource, bool> >(filterByIdExpression, param); IQueryable <TResource> query = _dbContext.Set <TResource>(); return(query.Where(predicate)); }
/// <summary> /// Builds a new EntityFrameworkToOneRelatedResourceDocumentMaterializer /// </summary> public EntityFrameworkToOneRelatedResourceDocumentMaterializer( ISingleResourceDocumentBuilder singleResourceDocumentBuilder, IBaseUrlService baseUrlService, IResourceTypeRegistration primaryTypeRegistration, ResourceTypeRelationship relationship, DbContext dbContext) : base(singleResourceDocumentBuilder, baseUrlService) { _primaryTypeRegistration = primaryTypeRegistration; _relationship = relationship; _dbContext = dbContext; }
protected override Task SetIdForNewResource(IResourceObject resourceObject, object newObject, IResourceTypeRegistration typeRegistration) { // This is to facilitate testing creation of a resource with a server-provided ID if (typeRegistration.Type == typeof (Post) && String.IsNullOrEmpty(resourceObject.Id)) { ((Post) newObject).Id = "230"; return Task.FromResult(0); } return base.SetIdForNewResource(resourceObject, newObject, typeRegistration); }
/// <summary> /// Builds a new EntityFrameworkToManyRelatedResourceDocumentMaterializer. /// </summary> public EntityFrameworkToManyRelatedResourceDocumentMaterializer( ResourceTypeRelationship relationship, DbContext dbContext, IQueryableResourceCollectionDocumentBuilder queryableResourceCollectionDocumentBuilder, ISortExpressionExtractor sortExpressionExtractor, IResourceTypeRegistration primaryTypeRegistration) : base(queryableResourceCollectionDocumentBuilder, sortExpressionExtractor) { _relationship = relationship; _dbContext = dbContext; _primaryTypeRegistration = primaryTypeRegistration; }
/// <summary> /// Creates a new EntityFrameworkDocumentMaterializer /// </summary> public EntityFrameworkDocumentMaterializer( DbContext dbContext, IResourceTypeRegistration resourceTypeRegistration, IQueryableResourceCollectionDocumentBuilder queryableResourceCollectionDocumentBuilder, ISingleResourceDocumentBuilder singleResourceDocumentBuilder, IEntityFrameworkResourceObjectMaterializer entityFrameworkResourceObjectMaterializer, ISortExpressionExtractor sortExpressionExtractor, IBaseUrlService baseUrlService) { _dbContext = dbContext; _resourceTypeRegistration = resourceTypeRegistration; _queryableResourceCollectionDocumentBuilder = queryableResourceCollectionDocumentBuilder; _singleResourceDocumentBuilder = singleResourceDocumentBuilder; _entityFrameworkResourceObjectMaterializer = entityFrameworkResourceObjectMaterializer; _sortExpressionExtractor = sortExpressionExtractor; _baseUrlService = baseUrlService; }
/// <summary> /// Gets a record by ID /// </summary> protected async Task <TRecord> GetExistingRecordGeneric <TRecord>(IResourceTypeRegistration registration, string id, ResourceTypeRelationship[] relationshipsToInclude, CancellationToken cancellationToken) where TRecord : class { var param = Expression.Parameter(registration.Type); var filterExpression = registration.GetFilterByIdExpression(param, id); var lambda = Expression.Lambda <Func <TRecord, bool> >(filterExpression, param); var query = _dbContext.Set <TRecord>().AsQueryable() .Where(lambda); if (relationshipsToInclude != null) { query = relationshipsToInclude.Aggregate(query, (current, resourceTypeRelationship) => current.Include(resourceTypeRelationship.Property.Name)); } return(await query.FirstOrDefaultAsync(cancellationToken)); }
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); }
public void AddRegistration(IResourceTypeRegistration registration) { lock (_registrationsByType) { lock (_registrationsByName) { if (_registrationsByType.ContainsKey(registration.Type)) throw new InvalidOperationException(String.Format("The type `{0}` has already been registered.", registration.Type.FullName)); if (_registrationsByName.ContainsKey(registration.ResourceTypeName)) throw new InvalidOperationException( String.Format("The resource type name `{0}` has already been registered.", registration.ResourceTypeName)); _registrationsByType.Add(registration.Type, registration); _registrationsByName.Add(registration.ResourceTypeName, registration); } } }
private void AssertAttribute <TPropertyType, TTokenType>(IResourceTypeRegistration reg, string attributeName, JToken tokenToSet, TPropertyType expectedPropertyValue, TTokenType expectedTokenAfterSet, Func <AttributeGrabBag, TPropertyType> getPropertyFunc) { AssertAttributeHelper(reg, attributeName, tokenToSet, grabBag => { var propertyValueAfterSet = getPropertyFunc(grabBag); propertyValueAfterSet.Should().Be(expectedPropertyValue); }, token => { if (expectedTokenAfterSet == null) { token.Should().BeNull(); } else { var convertedTokenValue = token.Value <TTokenType>(); convertedTokenValue.Should().Be(expectedTokenAfterSet); } }); }
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> /// Allows implementers to control how a new resource's ID should be set. /// </summary> protected virtual Task SetIdForNewResource(IResourceObject resourceObject, object newObject, IResourceTypeRegistration typeRegistration) { if (resourceObject.Id != null) { typeRegistration.IdProperty.SetValue(newObject, Convert.ChangeType(resourceObject.Id, typeRegistration.IdProperty.PropertyType)); } return(Task.FromResult(0)); }
/// <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); } } } }
/// <summary> /// Allows implementers to control how a new resource's ID should be set. /// </summary> protected virtual Task SetIdForNewResource(IResourceObject resourceObject, object newObject, IResourceTypeRegistration typeRegistration) { typeRegistration.IdProperty.SetValue(newObject, resourceObject.Id); return(Task.FromResult(0)); }
protected override Task SetIdForNewResource(IResourceObject resourceObject, object newObject, IResourceTypeRegistration typeRegistration) { // This is to facilitate testing creation of a resource with a server-provided ID if (typeRegistration.Type == typeof(Post) && String.IsNullOrEmpty(resourceObject.Id)) { ((Post)newObject).Id = "230"; return(Task.FromResult(0)); } return(base.SetIdForNewResource(resourceObject, newObject, typeRegistration)); }