public void HandleSubscription(CollectionSubscription subscription, Type dbContextType, IServiceProvider requestServiceProvider, ConnectionBase connection, KeyValuePair <Type, string> property, List <ChangeResponse> collectionChanges, List <ChangeResponse> allChanges) { try { bool anyCollectionChanges = collectionChanges.Any(); if ((anyCollectionChanges && subscription.Prefilters.Any(prefilter => prefilter is IAfterQueryPrefilter || prefilter is TakePrefilter || prefilter is SkipPrefilter)) || HasIncludePrefilterWithChange(subscription, allChanges)) { SapphireDbContext db = dbContextAccessor.GetContext(dbContextType, requestServiceProvider); IQueryable <object> collectionValues = db.GetCollectionValues(requestServiceProvider, connection.Information, property, subscription.Prefilters); IAfterQueryPrefilter afterQueryPrefilter = subscription.Prefilters.OfType <IAfterQueryPrefilter>().FirstOrDefault(); if (afterQueryPrefilter != null) { afterQueryPrefilter.Initialize(property.Key); _ = connection.Send(new QueryResponse() { ReferenceId = subscription.ReferenceId, Result = afterQueryPrefilter.Execute(collectionValues) }); } else { _ = connection.Send(new QueryResponse() { ReferenceId = subscription.ReferenceId, Result = collectionValues .AsEnumerable() .Select(v => v.GetAuthenticatedQueryModel(connection.Information, serviceProvider)) .ToList() }); } } else if (anyCollectionChanges) { IEnumerable <WherePrefilter> wherePrefilters = subscription.Prefilters.OfType <WherePrefilter>(); foreach (WherePrefilter wherePrefilter in wherePrefilters) { wherePrefilter.Initialize(property.Key); Func <object, bool> whereFunction = wherePrefilter.WhereExpression.Compile(); collectionChanges = collectionChanges.Where((change) => whereFunction(change.Value)).ToList(); } collectionChanges.ForEach(change => { object value = change.Value.GetAuthenticatedQueryModel(connection.Information, requestServiceProvider); _ = connection.Send(change.CreateResponse(subscription.ReferenceId, value)); }); } } catch (Exception ex) { SubscribeCommand tempErrorCommand = new SubscribeCommand() { CollectionName = subscription.CollectionName, ReferenceId = subscription.ReferenceId, Prefilters = subscription.Prefilters }; _ = connection.Send(tempErrorCommand.CreateExceptionResponse <ResponseBase>(ex)); logger.LogError( $"Error handling subscription '{subscription.ReferenceId}' of {subscription.CollectionName}"); logger.LogError(ex.Message); } }
public void HandleCollections(ConnectionBase connection, string contextName, Type dbContextType, List <ChangeResponse> changes, IServiceProvider requestServiceProvider) { IEnumerable <IGrouping <string, CollectionSubscription> > subscriptionGroupings = connection.Subscriptions .Where(s => s.ContextName == contextName) .GroupBy(s => s.CollectionName); foreach (IGrouping <string, CollectionSubscription> subscriptionGrouping in subscriptionGroupings) { KeyValuePair <Type, string> property = dbContextType.GetDbSetType(subscriptionGrouping.Key); List <ChangeResponse> changesForCollection = changes .Where(c => c.CollectionName == subscriptionGrouping.Key) .ToList(); AuthModelInfo modelInfo = property.Key.GetAuthModelInfos(); IEnumerable <ChangeResponse> authenticatedChanges = changesForCollection; if (modelInfo.QueryEntryAuthAttributes.Any()) { authenticatedChanges = changesForCollection .Where(change => change.State == ChangeResponse.ChangeState.Deleted || property.Key.CanQueryEntry(connection.Information, requestServiceProvider, change.Value)); IEnumerable <ChangeResponse> oldLoadedNotAllowed = changesForCollection .Where(change => change.State == ChangeResponse.ChangeState.Modified && !property.Key.CanQueryEntry(connection.Information, requestServiceProvider, change.Value)) .Select(change => { ChangeResponse newChangeResponse = change.CreateResponse(null, change.Value); newChangeResponse.State = ChangeResponse.ChangeState.Deleted; return(newChangeResponse); }); authenticatedChanges = authenticatedChanges.Concat(oldLoadedNotAllowed); } List <ChangeResponse> collectionChanges = authenticatedChanges.ToList(); if (collectionChanges.Any()) { QueryFunctionAttribute queryFunctionAttribute = property.Key.GetCustomAttribute <QueryFunctionAttribute>(false); if (queryFunctionAttribute != null) { var queryFunctionInfo = property.Key.GetMethod(queryFunctionAttribute.Function, BindingFlags.Default | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static); if (queryFunctionInfo != null) { object[] methodParameters = queryFunctionInfo.CreateParameters(connection.Information, serviceProvider); dynamic queryFunctionExpression = ((dynamic)queryFunctionInfo.Invoke(null, methodParameters)).Compile(); collectionChanges = collectionChanges.Where(change => queryFunctionExpression(change.Value)) .ToList(); } } } foreach (CollectionSubscription subscription in subscriptionGrouping) { Task.Run(() => { HandleSubscription(subscription, dbContextType, requestServiceProvider, connection, property, collectionChanges, changes); }); } } }
public void HandleSubscription(CollectionSubscription subscription, Type dbContextType, IServiceProvider requestServiceProvider, ConnectionBase connection, KeyValuePair <Type, string> property, List <ChangeResponse> collectionChanges, List <ChangeResponse> allChanges) { try { bool anyCollectionChanges = collectionChanges.Any(); if ((anyCollectionChanges && subscription.Prefilters.Any(prefilter => prefilter is IAfterQueryPrefilter || prefilter is TakePrefilter || prefilter is SkipPrefilter)) || HasIncludePrefilterWithChange(subscription, allChanges)) { SapphireDbContext db = dbContextAccessor.GetContext(dbContextType, requestServiceProvider); IQueryable <object> collectionValues = db.GetCollectionValues(requestServiceProvider, connection.Information, property, subscription.Prefilters); IAfterQueryPrefilter afterQueryPrefilter = subscription.Prefilters.OfType <IAfterQueryPrefilter>().FirstOrDefault(); if (afterQueryPrefilter != null) { afterQueryPrefilter.Initialize(property.Key); _ = connection.Send(new QueryResponse() { ReferenceId = subscription.ReferenceId, Result = afterQueryPrefilter.Execute(collectionValues) }); } else { _ = connection.Send(new QueryResponse() { ReferenceId = subscription.ReferenceId, Result = collectionValues .AsEnumerable() .Select(v => v.GetAuthenticatedQueryModel(connection.Information, serviceProvider)) .ToList() }); } } else if (anyCollectionChanges) { IEnumerable <WherePrefilter> wherePrefilters = subscription.Prefilters.OfType <WherePrefilter>(); List <ChangeResponse> oldValuesUnloadResponses = new List <ChangeResponse>(); List <ChangeResponse> newValuesLoadResponses = new List <ChangeResponse>(); foreach (WherePrefilter wherePrefilter in wherePrefilters) { wherePrefilter.Initialize(property.Key); // Values that did change know do match the oldValuesUnloadResponses.AddRange( collectionChanges .Where(change => change.State == ChangeResponse.ChangeState.Modified && !wherePrefilter.WhereExpressionCompiled(change.Value) && wherePrefilter.WhereExpressionCompiled(change.OriginalValue)) .Select(change => { ChangeResponse newChangeResponse = change.CreateResponse(null, change.Value); newChangeResponse.State = ChangeResponse.ChangeState.Deleted; return(newChangeResponse); }) ); newValuesLoadResponses.AddRange( collectionChanges .Where(change => change.State == ChangeResponse.ChangeState.Modified && wherePrefilter.WhereExpressionCompiled(change.Value) && !wherePrefilter.WhereExpressionCompiled(change.OriginalValue)) .Select(change => { ChangeResponse newChangeResponse = change.CreateResponse(null, change.Value); newChangeResponse.State = ChangeResponse.ChangeState.Added; return(newChangeResponse); }) ); collectionChanges = collectionChanges .Where((change) => wherePrefilter.WhereExpressionCompiled(change.Value)).ToList(); } IEnumerable <ChangeResponse> changesForWherePrefilter = oldValuesUnloadResponses .Concat(newValuesLoadResponses) .GroupBy(v => v.Value) .Select(g => g.LastOrDefault()); collectionChanges = collectionChanges.Concat(changesForWherePrefilter).ToList(); ChangesResponse changesResponse = new ChangesResponse() { ReferenceId = subscription.ReferenceId, Changes = collectionChanges.Select(change => { object value = change.Value.GetAuthenticatedQueryModel(connection.Information, requestServiceProvider); return(change.CreateResponse(subscription.ReferenceId, value)); }).ToList() }; if (changesResponse.Changes.Any()) { _ = connection.Send(changesResponse); } } } catch (Exception ex) { SubscribeCommand tempErrorCommand = new SubscribeCommand() { CollectionName = subscription.CollectionName, ReferenceId = subscription.ReferenceId, Prefilters = subscription.Prefilters }; _ = connection.Send(tempErrorCommand.CreateExceptionResponse <ResponseBase>(ex)); logger.LogError( $"Error handling subscription '{subscription.ReferenceId}' of {subscription.CollectionName}"); logger.LogError(ex.Message); } }