public CommandScheduler(
     Func <IStore <TAggregate> > getStore,
     IETagChecker etagChecker)
 {
     if (getStore == null)
     {
         throw new ArgumentNullException(nameof(getStore));
     }
     if (etagChecker == null)
     {
         throw new ArgumentNullException(nameof(etagChecker));
     }
     this.getStore    = getStore;
     this.etagChecker = etagChecker;
 }
        /// <summary>
        /// Determines whether the command's precondition is satisfied, if it has one.
        /// </summary>
        /// <param name="preconditionChecker">The precondition checker.</param>
        /// <param name="scheduledCommand">The scheduled command.</param>
        /// <returns>True if the command has no precondition, or if its precondition is satisfied.</returns>
        /// <exception cref="System.ArgumentNullException"></exception>
        public static async Task <bool> IsPreconditionSatisfied(
            this IETagChecker preconditionChecker,
            IScheduledCommand scheduledCommand)
        {
            if (preconditionChecker == null)
            {
                throw new ArgumentNullException(nameof(preconditionChecker));
            }

            var precondition = scheduledCommand.DeliveryPrecondition;

            if (precondition == null)
            {
                return(true);
            }

            return(await preconditionChecker.HasBeenRecorded(
                       precondition.Scope,
                       precondition.ETag));
        }
        internal static async Task ApplyScheduledCommand <TAggregate>(
            this IStore <TAggregate> store,
            IScheduledCommand <TAggregate> scheduled,
            IETagChecker preconditionChecker = null)
            where TAggregate : class
        {
            TAggregate aggregate = null;
            Exception  exception;

            try
            {
                if (preconditionChecker != null &&
                    !await preconditionChecker.IsPreconditionSatisfied(scheduled))
                {
                    await FailScheduledCommand(store,
                                               scheduled,
                                               new PreconditionNotMetException(scheduled.DeliveryPrecondition));

                    return;
                }

                aggregate = await store.Get(scheduled.TargetId);

                var isConstructorCommand = scheduled.Command is ConstructorCommand <TAggregate>;

                if (aggregate == null)
                {
                    if (isConstructorCommand)
                    {
                        var ctor = typeof(TAggregate).GetConstructor(new[] { scheduled.Command.GetType() });

                        if (ctor == null)
                        {
                            throw new InvalidOperationException($"No constructor was found on type {typeof (TAggregate)} for constructor command {scheduled.Command}.");
                        }

                        aggregate = (TAggregate)ctor.Invoke(new[] { scheduled.Command });
                    }
                    else
                    {
                        throw new PreconditionNotMetException(
                                  $"No {typeof (TAggregate).Name} was found with id {scheduled.TargetId} so the command could not be applied.");
                    }
                }
                else if (isConstructorCommand)
                {
                    throw new ConcurrencyException($"Command target having id {scheduled.TargetId} already exists");
                }
                else
                {
                    await aggregate.ApplyAsync(scheduled.Command);
                }

                await store.Put(aggregate);

                scheduled.Result = new CommandSucceeded(scheduled);

                return;
            }
            catch (Exception ex)
            {
                exception = ex;
            }

            await FailScheduledCommand(store, scheduled, exception, aggregate);
        }