Ejemplo n.º 1
0
        public virtual void Add <T>(T instance) where T : class
        {
            if (instance == null)
            {
                throw new ArgumentNullException(nameof(instance));
            }
            var type  = typeof(T);
            var value = _idAccessor.GetId(instance);
            var key   = _idManager.GetFromId(typeof(T), value);

            if (key == null)
            {
                key = _idManager.GenerateId(type);
                _idAccessor.SetId(instance, key.Id);
            }

            var entry = new SessionEntry()
            {
                Action   = ActionType.Add,
                Instance = instance,
                Key      = key
            };

            _sessionCache.Attach(entry);
        }
        public ITransaction Setup(IEnumerable <object> items)
        {
            var txnEntries = items.Select(x =>
            {
                var type = x.GetType().Name;
                var id   = _idAccessor.GetId(x)?.ToString();
                var rev  = _revisionAccessor.GetRevision(x)?.ToString();
                var txn  = new TransactionEntry()
                {
                    DateTime  = DateTime.UtcNow,
                    Id        = $"{id}-{type}",
                    ActualId  = id,
                    ActualRev = rev,
                    Type      = type
                };
                return(txn);
            });

            var transaction = new Transaction(_couchDb, _idAccessor, _revisionAccessor);

            try
            {
                transaction.Init(txnEntries);
            }
            catch (Exception e)
            {
                transaction.Rollback(e);
                throw;
            }

            return(transaction);
        }
Ejemplo n.º 3
0
        public Task <IEnumerable <LoadContext> > Execute(QueryContext context,
                                                         Next <QueryContext, IEnumerable <LoadContext> > next)
        {
            var ctx   = context;
            var q     = ctx.Query;
            var query = new MongoQueryRequest
            {
                Selector = q.Selector,
                Limit    = q.Limit,
                Skip     = q.Skip,
                Sort     = q.Sort
            };

            var allDocs = _couchDb.MongoQuery(query);

            //using the loaded docs, update the context entries.
            var results =
                (from entity in allDocs.Docs
                 let id = _idAccessor.GetId(entity)
                          let key = _idManager.GetFromId(entity.GetType(), id)
                                    select new LoadContext()
            {
                Entity = entity,
                Key = key,
                Type = entity.GetType()
            }).ToList();

            return(Task.FromResult((IEnumerable <LoadContext>)results));
        }
        public Task Execute(IEnumerable <LoadContext> context, Next <IEnumerable <LoadContext> > next)
        {
            var items = context.ToList(); //ensure 1 iteration over list. (tasks to run once)

            //we do not want to load items which have been loaded from the cache
            var toLoad  = items.Where(x => !x.LoadedFromCache).ToDictionary(loadContext => loadContext.Key.CouchDbId);
            var allDocs = _couchDb.LoadAllEntities(new AllDocsRequest()
            {
                Keys = toLoad.Keys
            });

            //using the loaded docs, update the context entries.
            foreach (var entity in allDocs.Rows.Select(x => x.Doc))
            {
                var id  = _idAccessor.GetId(entity);
                var key = _idManager.GetFromId(entity.GetType(), id);
                toLoad[key.CouchDbId].Entity = entity;
            }

            return(Task.CompletedTask);
        }
Ejemplo n.º 5
0
        public void Init(IEnumerable <TransactionEntry> txnEntries)
        {
            _txnEntries = new Dictionary <string, TransactionEntry>();
            foreach (var txnEntry in txnEntries)
            {
                txnEntry.TransactionId = _id;
                _txnEntries.Add(txnEntry.ActualId, txnEntry);
            }

            var now = DateTime.UtcNow;

            bool HasExpired(DateTime time) => new TimeSpan(now.Ticks - time.Ticks).TotalSeconds > 5;

            var existingTransactionEntries = _couchDb
                                             .LoadAllEntities(
                new AllDocsRequest()
            {
                Keys = _txnEntries.Values.Select(x => x.Id)        //checking against transaction key for documents
            })
                                             .Rows
                                             .Select(x => x.Doc)
                                             .Cast <TransactionEntry>()
                                             .ToList();

            var hasTransactionLockConflict = existingTransactionEntries.Any(x => HasExpired(x.DateTime));

            if (hasTransactionLockConflict)
            {
                throw new TransactionException(existingTransactionEntries.Select(x => x.Id).ToList());
            }

            var payload = new BulkDocsRequest()
            {
                Docs = _txnEntries.Values.Select(
                    txn => new BulkDocRequest()
                {
                    Id      = txn.Id,
                    Content = txn
                })
            };

            _results = _couchDb.BulkApplyChanges(payload).ToList();

            //now we have a txn (lock) we confirm the target docs are still on the same rev
            var conflictingDocs = _couchDb.LoadAllEntities(
                new AllDocsRequest()
            {
                Keys = _txnEntries.Values.Select(x => x.ActualId)
            })
                                  .Rows
                                  .Select(x => x.Doc)
                                  .Select(x => new
            {
                Id  = _idAccessor.GetId(x).ToString(),
                Rev = _revisionAccessor.GetRevision(x)?.ToString()
            })
                                  .Where(x =>
            {
                if (!_txnEntries.TryGetValue(x.Id, out var entry))
                {
                    return(false);
                }
                return(entry.ActualRev != x.Rev);
            })
                                  .ToList();

            if (conflictingDocs.Any())
            {
                throw new AggregateException(conflictingDocs.Select(x => new ConflictException(x.Id, x.Rev, "conflict", "stale reference")));
            }
        }