public void Build_A_Document_Subscription()
        {
            var collectionName = "testCollection";
            var id             = new BsonValue(Guid.NewGuid());
            var collSub        = new CollectionSubscription <Model>(_db.NotificationService)
            {
                Collection = collectionName,
            };

            var collBuilder = new CollectionSubscriptionBuilder <Model>(_db.NotificationService, collSub);
            var docBuilder  = collBuilder.Id(id) as DocumentSubscriptionBuilder <Model>;


            var docSub = (docBuilder as ISubscriptionBuilderBase).Subscription as DocumentSubscription <Model>;

            docSub.Collection.Should().Be(collectionName);
            docSub.Id.Should().Be(id);
            // before subscribing
            docSub.Observer.Should().BeNull();

            docBuilder.Subscribe(obj => { });

            // after subscribing
            docSub.Observer.Should().NotBeNull();
        }
Exemple #2
0
        /// <summary>
        /// Notify one subscription
        /// </summary>
        public void Notify <T>(CollectionSubscription <T> collectionSubscription) where T : class
        {
            if (_database is null)
            {
                throw new InvalidOperationException("notification service is not initialized");
            }

            var nextValue = _database.GetCollection <T>(collectionSubscription.Collection).Query().ToList();

            Task.Run(() => collectionSubscription.Observer?.OnNext(nextValue));
        }
Exemple #3
0
        internal void NotifyIfNeeded <T>(CollectionSubscription <T> collectionSubscription, NotificationCache cache) where T : class
        {
            if (cache.Broadcasts.Contains(collectionSubscription.Collection))
            {
                Notify(collectionSubscription);
                return;
            }

            if (cache.Collections.Contains(collectionSubscription.Collection))
            {
                Notify(collectionSubscription);
                return;
            }
        }
        public async Task AddSubscription(CollectionSubscription subscription)
        {
            await Lock.WaitAsync();

            try
            {
                if (Subscriptions.All(s => s.ReferenceId != subscription.ReferenceId))
                {
                    Subscriptions.Add(subscription);
                }
            }
            finally
            {
                Lock.Release();
            }
        }
Exemple #5
0
        public void Unsubscribe_From_DB_When_Disposing()
        {
            var subscriptions = new SubscriptionDict();
            var sub1          = new DocumentSubscription <Model>(_db.NotificationService);
            var sub2          = new CollectionSubscription <Model>(_db.NotificationService);

            subscriptions.TryAdd(sub1, default);
            subscriptions.TryAdd(sub2, default);
            subscriptions.Keys.Should().HaveCount(2);
            subscriptions.Keys.Should().Contain(sub1);
            subscriptions.Keys.Should().Contain(sub2);

            using (var unsubscriber = new Unsubscriber(subscriptions, sub1))
            { }

            subscriptions.Keys.Should().HaveCount(1);
            subscriptions.Keys.Should().Contain(sub2);
        }
        public async Task <ResponseBase> Handle(HttpInformation context, SubscribeCommand command)
        {
            ResponseBase response = CollectionHelper.GetCollection(GetContext(command.ContextName), command, context, serviceProvider);

            if (response.Error == null)
            {
                CollectionSubscription collectionSubscription = new CollectionSubscription()
                {
                    CollectionName = command.CollectionName.ToLowerInvariant(),
                    ContextName    = command.ContextName.ToLowerInvariant(),
                    ReferenceId    = command.ReferenceId,
                    Prefilters     = command.Prefilters
                };

                await Connection.AddSubscription(collectionSubscription);
            }

            return(response);
        }
        public void Build_A_Collection_Subscription()
        {
            var collectionName = "testCollection";
            var id             = new BsonValue(Guid.NewGuid());
            var sub            = new CollectionSubscription <Model>(_db.NotificationService)
            {
                Collection = collectionName,
            };

            var builder = new CollectionSubscriptionBuilder <Model>(_db.NotificationService, sub);

            sub.Collection.Should().Be(collectionName);
            // before subscribing
            sub.Observer.Should().BeNull();

            builder.Subscribe(listObj => { });

            // after subscribing
            sub.Observer.Should().NotBeNull();
        }
        private bool HasIncludePrefilterWithChange(CollectionSubscription subscription, List <ChangeResponse> allChanges)
        {
            List <IncludePrefilter> includePrefilters = subscription.Prefilters.OfType <IncludePrefilter>().ToList();

            if (!includePrefilters.Any())
            {
                return(false);
            }

            List <string> affectedCollections = includePrefilters
                                                .SelectMany(prefilter => prefilter.AffectedCollectionNames)
                                                .Distinct()
                                                .ToList();

            return(allChanges.Any(change =>
                                  change.CollectionName.Equals(subscription.CollectionName,
                                                               StringComparison.InvariantCultureIgnoreCase)) ||
                   affectedCollections.Any(collectionName => allChanges.Any(change =>
                                                                            change.CollectionName.Equals(collectionName, StringComparison.InvariantCultureIgnoreCase))));
        }
        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 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);
            }
        }