protected override sealed async Task PersistModelAsync(PersistEvent @event, TModel model, Graph <TModel> graph, bool create)
        {
            var id         = ModelAnalyzer.GetIdentity(model);
            var streamName = EventStoreCommon.GetStreamName <TModel>(id);

            var eventStoreModel = new EventStoreEventModelData <TModel>()
            {
                Source     = @event.Source,
                SourceType = @event.Source?.GetType().Name,
                Model      = model,
                Graph      = graph
            };

            var data = EventStoreCommon.Serialize(eventStoreModel);

            var eventNumber = await Engine.AppendAsync(@event.ID, @event.Name, streamName, null, create?EventStoreState.NotExisting : EventStoreState.Existing, data);

            if (eventNumber > 0 && eventNumber % SaveStateEvery == 0)
            {
                var thisEventData = (await Engine.ReadBackwardsAsync(streamName, eventNumber, 1, null, null, null))[0];

                var where = ModelAnalyzer.GetIdentityExpression <TModel>(id);

                var eventStates = await Repo.QueryAsync(new EventQueryMany <TModel>(thisEventData.Date, thisEventData.Date, where));

                var eventState = eventStates.Where(x => x.Number == eventNumber).Single();

                await SaveModelStateAsync(id, eventState.Model, eventState.Number);
            }
        }
Exemplo n.º 2
0
        public async Task <bool> Rebuild(ulong?maxEventNumber = null, DateTime?maxEventDate = null)
        {
            var startEventNumber = LastEventNumber.HasValue ? LastEventNumber + 1 : null;

            //TODO error handle if aggregate doesn't exist?????
            var eventDatas = await this.eventStore.ReadAsync(streamName, startEventNumber, null, maxEventNumber, null, maxEventDate);

            if (eventDatas.Length == 0)
            {
                return(false);
            }

            if (!IsCreated)
            {
                IsCreated = true;
            }

            foreach (var eventData in eventDatas)
            {
                this.LastEventNumber = eventData.Number;
                this.LastEventDate   = eventData.Date;
                this.LastEventName   = eventData.EventName;
                if (eventData.Deleted)
                {
                    this.IsDeleted = true;
                }
                var eventModel = EventStoreCommon.Deserialize <IEvent>(eventData.Data.Span);
                await ApplyEvent(eventModel, eventModel.GetType());
            }
            return(true);
        }
        private async Task <(TModel, ulong?)> ReadModelStateAsync(object id, TemporalOrder?temporalOrder, DateTime?temporalDateFrom, ulong?temporalNumberFrom)
        {
            if (temporalOrder != TemporalOrder.Newest && !temporalDateFrom.HasValue && !temporalNumberFrom.HasValue)
            {
                return(null, null);
            }

            var streamName = EventStoreCommon.GetStateStreamName <TModel>(id);

            TModel model            = null;
            ulong? modelEventNumber = null;

            long?count = null;

            if (temporalOrder == TemporalOrder.Newest)
            {
                count = 1;
            }

            if (temporalOrder == TemporalOrder.Newest || temporalDateFrom.HasValue || temporalNumberFrom.HasValue)
            {
                var eventData = (await Engine.ReadBackwardsAsync(streamName, null, count, temporalNumberFrom, null, temporalDateFrom)).LastOrDefault();
                if (eventData != null)
                {
                    var eventState = EventStoreCommon.Deserialize <EvenStoreStateData <TModel> >(eventData.Data.Span);
                    modelEventNumber = eventState.Number;
                    model            = eventState.Model;
                }
            }

            return(model, modelEventNumber);
        }
        protected override sealed async Task DeleteModelAsync(PersistEvent @event, object[] ids)
        {
            foreach (var id in ids)
            {
                var streamName = EventStoreCommon.GetStreamName <TModel>(id);

                var eventNumber = await Engine.TerminateAsync(@event.ID, "Delete", streamName, null, EventStoreState.Existing);

                await SaveModelStateAsync(id, null, eventNumber);
            }
        }
Exemplo n.º 5
0
        public async Task Append <TEvent>(TEvent @event, bool validateEventNumber = false) where TEvent : IEvent
        {
            var eventType = typeof(TEvent);
            var eventName = eventType.Name;

            await ApplyEvent(@event, eventType);

            var eventBytes = EventStoreCommon.Serialize(@event);

            await this.eventStore.AppendAsync(Guid.NewGuid(), eventName, streamName, validateEventNumber?LastEventNumber : null, validateEventNumber?(LastEventNumber.HasValue ? EventStoreState.NotExisting : EventStoreState.Existing) : EventStoreState.Any, eventBytes);

            await Bus.DispatchAsync(@event);
        }
        private void SaveModelState(object id, TModel model, ulong eventNumber)
        {
            var streamName = EventStoreCommon.GetStateStreamName <TModel>(id);

            var eventState = new EvenStoreStateData <TModel>()
            {
                Model   = model,
                Number  = eventNumber,
                Deleted = model == null
            };
            var data = EventStoreCommon.Serialize(eventState);

            Engine.Append(Guid.NewGuid(), "StoreState", streamName, null, EventStoreState.Any, data);
        }
        private async Task <ICollection <EventModel <TModel> > > ReadEventModelsAsync(Query <TModel> query)
        {
            var many = query.Operation == QueryOperation.EventMany || query.Operation == QueryOperation.EventCount;
            var ids  = GetIDs(query);

            var models = new List <EventModel <TModel> >();

            foreach (var id in ids)
            {
                var streamName = EventStoreCommon.GetStreamName <TModel>(id);

                var(modelState, modelEventNumber) = await ReadModelStateAsync(id, query.TemporalOrder, query.TemporalDateFrom, query.TemporalNumberFrom);

                var eventDatas = await Engine.ReadBackwardsAsync(streamName, null, null, modelEventNumber + 1 ?? query.TemporalNumberTo, null, query.TemporalDateTo);

                var items = LoadEventModelsFromEventDatas(eventDatas, modelState, many, query);

                models.AddRange(items);
            }
            return(models);
        }
        private ICollection <TModel> ReadModels(Query <TModel> query)
        {
            var many = query.Operation == QueryOperation.Many || query.Operation == QueryOperation.Count;
            var ids  = GetIDs(query);

            var models = new List <TModel>();

            foreach (var id in ids)
            {
                var streamName = EventStoreCommon.GetStreamName <TModel>(id);

                var(modelState, modelEventNumber) = ReadModelState(id, query.TemporalOrder, query.TemporalDateFrom, query.TemporalNumberFrom);

                var eventDatas = Engine.ReadBackwards(streamName, null, null, modelEventNumber + 1, null, query.TemporalDateTo);

                var items = LoadModelsFromEventDatas(eventDatas, modelState, many, query);

                models.AddRange(items);
            }
            return(models);
        }
        private ICollection <EventModel <TModel> > LoadEventModelsFromEventDatas(EventStoreEventData[] eventDatas, TModel modelState, bool many, Query <TModel> query)
        {
            if (modelState == null && eventDatas.Length == 0)
            {
                return(Array.Empty <EventModel <TModel> >());
            }

            if (modelState == null)
            {
                modelState = Instantiator.CreateInstance <TModel>();
            }

            if (many)
            {
                switch (query.TemporalOrder ?? TemporalOrder.Newest)
                {
                case TemporalOrder.Newest:
                {
                    var eventModels = new List <EventModel <TModel> >();
                    foreach (var eventData in eventDatas.Reverse())
                    {
                        var eventModelData = EventStoreCommon.Deserialize <EventStoreEventModelData <TModel> >(eventData.Data.Span);
                        Mapper.MapTo(eventModelData.Model, modelState, eventModelData.Graph);

                        if (query.TemporalDateTo.HasValue && query.TemporalDateTo.Value < eventData.Date)
                        {
                            break;
                        }
                        if (query.TemporalNumberTo.HasValue && query.TemporalNumberTo.Value < eventData.Number)
                        {
                            break;
                        }
                        if ((!query.TemporalDateFrom.HasValue && !query.TemporalNumberFrom.HasValue) || (query.TemporalDateFrom.HasValue && eventData.Date >= query.TemporalDateFrom.Value) || (query.TemporalNumberFrom.HasValue && eventData.Number >= query.TemporalNumberFrom.Value))
                        {
                            var copy       = Mapper.Copy(modelState);
                            var eventModel = new EventModel <TModel>()
                            {
                                EventID   = eventData.EventID,
                                EventName = eventData.EventName,
                                Date      = eventData.Date,
                                Number    = eventData.Number,
                                Deleted   = eventData.Deleted,

                                Model = copy,

                                ModelChange = eventModelData.Model,
                                GraphChange = eventModelData.Graph,
                                Source      = eventModelData.Source,
                                SourceType  = eventModelData.SourceType
                            };
                            eventModels.Add(eventModel);
                        }
                    }
                    if (query.TemporalSkip.HasValue && query.TemporalTake.HasValue)
                    {
                        eventModels.Reverse();
                        return(eventModels.Skip(query.TemporalSkip.Value).Take(query.TemporalTake.Value).Reverse().ToArray());
                    }
                    else if (query.TemporalSkip.HasValue)
                    {
                        eventModels.Reverse();
                        return(eventModels.Skip(query.TemporalSkip.Value).Reverse().ToArray());
                    }
                    else if (query.TemporalTake.HasValue)
                    {
                        eventModels.Reverse();
                        return(eventModels.Take(query.TemporalTake.Value).Reverse().ToArray());
                    }
                    else
                    {
                        return(eventModels);
                    }
                }

                case TemporalOrder.Oldest:
                {
                    var eventModels = new List <EventModel <TModel> >();
                    var skipCount   = 0;
                    foreach (var eventData in eventDatas.Reverse())
                    {
                        var eventModelData = EventStoreCommon.Deserialize <EventStoreEventModelData <TModel> >(eventData.Data.Span);
                        Mapper.MapTo(eventModelData.Model, modelState, eventModelData.Graph);

                        if (query.TemporalDateTo.HasValue && query.TemporalDateTo.Value < eventData.Date)
                        {
                            break;
                        }
                        if (query.TemporalNumberTo.HasValue && query.TemporalNumberTo.Value < eventData.Number)
                        {
                            break;
                        }
                        if ((!query.TemporalDateFrom.HasValue && !query.TemporalNumberFrom.HasValue) || (query.TemporalDateFrom.HasValue && eventData.Date >= query.TemporalDateFrom.Value) || (query.TemporalNumberFrom.HasValue && eventData.Number >= query.TemporalNumberFrom.Value))
                        {
                            if (!query.TemporalSkip.HasValue || query.TemporalSkip.Value <= skipCount)
                            {
                                var copy       = Mapper.Copy(modelState);
                                var eventModel = new EventModel <TModel>()
                                {
                                    EventID   = eventData.EventID,
                                    EventName = eventData.EventName,
                                    Date      = eventData.Date,
                                    Number    = eventData.Number,
                                    Deleted   = eventData.Deleted,

                                    Model = copy,

                                    ModelChange = eventModelData.Model,
                                    GraphChange = eventModelData.Graph,
                                    Source      = eventModelData.Source,
                                    SourceType  = eventModelData.SourceType
                                };
                                eventModels.Add(eventModel);
                            }
                            else
                            {
                                skipCount++;
                            }
                        }
                    }
                    return(eventModels);
                }

                default:
                    throw new NotImplementedException();
                }
            }
            else
            {
                switch (query.TemporalOrder ?? TemporalOrder.Newest)
                {
                case TemporalOrder.Newest:
                {
                    EventStoreEventModelData <TModel> eventModelData = null;
                    EventStoreEventData thisEventData = null;
                    foreach (var eventData in eventDatas.Reverse())
                    {
                        thisEventData  = eventData;
                        eventModelData = EventStoreCommon.Deserialize <EventStoreEventModelData <TModel> >(eventData.Data.Span);
                        Mapper.MapTo(eventModelData.Model, modelState, eventModelData.Graph);

                        if (query.TemporalDateTo.HasValue && query.TemporalDateTo.Value < eventData.Date)
                        {
                            break;
                        }
                        if (!query.TemporalNumberTo.HasValue && eventData.Number < query.TemporalNumberTo.Value)
                        {
                            break;
                        }
                    }
                    var eventModel = new EventModel <TModel>()
                    {
                        EventID   = thisEventData.EventID,
                        EventName = thisEventData.EventName,
                        Date      = thisEventData.Date,
                        Number    = thisEventData.Number,
                        Deleted   = thisEventData.Deleted,

                        Model = modelState,

                        ModelChange = eventModelData.Model,
                        GraphChange = eventModelData.Graph,
                        Source      = eventModelData.Source,
                        SourceType  = eventModelData.SourceType
                    };
                    return(new EventModel <TModel>[] { eventModel });
                }

                case TemporalOrder.Oldest:
                {
                    EventStoreEventModelData <TModel> eventModelData = null;
                    EventStoreEventData thisEventData = null;
                    foreach (var eventData in eventDatas.Reverse())
                    {
                        thisEventData  = eventData;
                        eventModelData = EventStoreCommon.Deserialize <EventStoreEventModelData <TModel> >(eventData.Data.Span);
                        Mapper.MapTo(eventModelData.Model, modelState, eventModelData.Graph);

                        if (!query.TemporalDateFrom.HasValue || eventData.Date >= query.TemporalDateFrom)
                        {
                            break;
                        }
                        if (!query.TemporalNumberFrom.HasValue || eventData.Number >= query.TemporalNumberFrom.Value)
                        {
                            break;
                        }
                    }
                    var eventModel = new EventModel <TModel>()
                    {
                        EventID   = thisEventData.EventID,
                        EventName = thisEventData.EventName,
                        Date      = thisEventData.Date,
                        Number    = thisEventData.Number,
                        Deleted   = thisEventData.Deleted,

                        Model = modelState,

                        ModelChange = eventModelData.Model,
                        GraphChange = eventModelData.Graph,
                        Source      = eventModelData.Source,
                        SourceType  = eventModelData.SourceType
                    };
                    return(new EventModel <TModel>[] { eventModel });
                }

                default:
                    throw new NotImplementedException();
                }
            }
        }
        private ICollection <TModel> LoadModelsFromEventDatas(EventStoreEventData[] eventDatas, TModel modelState, bool many, Query <TModel> query)
        {
            if (modelState == null && eventDatas.Length == 0)
            {
                return(Array.Empty <TModel>());
            }

            if (modelState == null)
            {
                modelState = Instantiator.CreateInstance <TModel>();
            }

            if (many)
            {
                switch (query.TemporalOrder ?? TemporalOrder.Newest)
                {
                case TemporalOrder.Newest:
                {
                    var modelStates = new List <TModel>();
                    foreach (var eventData in eventDatas.Reverse())
                    {
                        var eventModel = EventStoreCommon.Deserialize <EventStoreEventModelData <TModel> >(eventData.Data.Span);
                        Mapper.MapTo(eventModel.Model, modelState, eventModel.Graph);

                        if (query.TemporalDateTo.HasValue && query.TemporalDateTo.Value < eventData.Date)
                        {
                            break;
                        }
                        if (query.TemporalNumberTo.HasValue && query.TemporalNumberTo.Value < eventData.Number)
                        {
                            break;
                        }
                        if ((!query.TemporalDateFrom.HasValue && !query.TemporalNumberFrom.HasValue) || (query.TemporalDateFrom.HasValue && eventData.Date >= query.TemporalDateFrom.Value) || (query.TemporalNumberFrom.HasValue && eventData.Number >= query.TemporalNumberFrom.Value))
                        {
                            var copy = Mapper.Copy(modelState);
                            modelStates.Add(copy);
                        }
                    }

                    if (query.TemporalSkip.HasValue && query.TemporalTake.HasValue)
                    {
                        modelStates.Reverse();
                        return(modelStates.Skip(query.TemporalSkip.Value).Take(query.TemporalTake.Value).Reverse().ToArray());
                    }
                    else if (query.TemporalSkip.HasValue)
                    {
                        modelStates.Reverse();
                        return(modelStates.Skip(query.TemporalSkip.Value).Reverse().ToArray());
                    }
                    else if (query.TemporalTake.HasValue)
                    {
                        modelStates.Reverse();
                        return(modelStates.Take(query.TemporalTake.Value).Reverse().ToArray());
                    }
                    else
                    {
                        return(modelStates);
                    }
                }

                case TemporalOrder.Oldest:
                {
                    var modelStates = new List <TModel>();
                    var skipCount   = 0;
                    foreach (var eventData in eventDatas.Reverse())
                    {
                        var eventModel = EventStoreCommon.Deserialize <EventStoreEventModelData <TModel> >(eventData.Data.Span);
                        Mapper.MapTo(eventModel.Model, modelState, eventModel.Graph);

                        if (query.TemporalDateTo.HasValue && query.TemporalDateTo.Value < eventData.Date)
                        {
                            break;
                        }
                        if (query.TemporalNumberTo.HasValue && query.TemporalNumberTo.Value < eventData.Number)
                        {
                            break;
                        }
                        if ((!query.TemporalDateFrom.HasValue && !query.TemporalNumberFrom.HasValue) || (query.TemporalDateFrom.HasValue && eventData.Date >= query.TemporalDateFrom.Value) || (query.TemporalNumberFrom.HasValue && eventData.Number >= query.TemporalNumberFrom.Value))
                        {
                            if (!query.TemporalSkip.HasValue || query.TemporalSkip.Value <= skipCount)
                            {
                                var copy = Mapper.Copy(modelState);
                                modelStates.Add(copy);
                                if (query.TemporalTake.HasValue && query.TemporalTake.Value == modelStates.Count)
                                {
                                    break;
                                }
                            }
                            else
                            {
                                skipCount++;
                            }
                        }
                    }
                    return(modelStates);
                }

                default:
                    throw new NotImplementedException();
                }
            }
            else
            {
                switch (query.TemporalOrder ?? TemporalOrder.Newest)
                {
                case TemporalOrder.Newest:
                {
                    foreach (var eventData in eventDatas.Reverse())
                    {
                        var eventModel = EventStoreCommon.Deserialize <EventStoreEventModelData <TModel> >(eventData.Data.Span);
                        Mapper.MapTo(eventModel.Model, modelState, eventModel.Graph);

                        if (query.TemporalDateTo.HasValue && query.TemporalDateTo.Value < eventData.Date)
                        {
                            break;
                        }
                        if (query.TemporalNumberTo.HasValue && eventData.Number < query.TemporalNumberTo.Value)
                        {
                            break;
                        }
                    }
                    return(new TModel[] { modelState });
                }

                case TemporalOrder.Oldest:
                {
                    foreach (var eventData in eventDatas.Reverse())
                    {
                        var eventModel = EventStoreCommon.Deserialize <EventStoreEventModelData <TModel> >(eventData.Data.Span);
                        Mapper.MapTo(eventModel.Model, modelState, eventModel.Graph);

                        if (query.TemporalDateFrom.HasValue && eventData.Date >= query.TemporalDateFrom.Value)
                        {
                            break;
                        }
                        if (query.TemporalNumberFrom.HasValue && eventData.Number >= query.TemporalNumberFrom.Value)
                        {
                            break;
                        }
                    }
                    return(new TModel[] { modelState });
                }

                default:
                    throw new NotImplementedException();
                }
            }
        }