Exemplo n.º 1
0
        /// <summary>
        /// Implements delete based on IDs enumerable
        /// </summary>
        public int Delete(string collection, IEnumerable <BsonValue> ids)
        {
            if (collection.IsNullOrWhiteSpace())
            {
                throw new ArgumentNullException(nameof(collection));
            }
            if (ids == null)
            {
                throw new ArgumentNullException(nameof(ids));
            }

            return(this.AutoTransaction(transaction =>
            {
                var snapshot = transaction.CreateSnapshot(LockMode.Write, collection, false);
                var collectionPage = snapshot.CollectionPage;
                var data = new DataService(snapshot);
                var indexer = new IndexService(snapshot, _header.Pragmas.Collation);

                if (collectionPage == null)
                {
                    return 0;
                }

                var count = 0;
                var pk = collectionPage.PK;

                foreach (var id in ids)
                {
                    var pkNode = indexer.Find(pk, id, false, LiteDB.Query.Ascending);

                    // if pk not found, continue
                    if (pkNode == null)
                    {
                        continue;
                    }

                    // remove object data
                    data.Delete(pkNode.DataBlock);

                    if (pkNode.NextNode.IsEmpty)
                    {
                        ;
                    }


                    // delete all nodes (start in pk node)
                    indexer.DeleteAll(pkNode.Position);

                    transaction.Safepoint();

                    count++;
                }

                return count;
            }));
        }
Exemplo n.º 2
0
        public override async IAsyncEnumerable <IndexNode> Execute(IndexService indexer, CollectionIndex index)
        {
            var node = await indexer.Find(index, _value, false, Query.Ascending);

            if (node == null)
            {
                yield break;
            }

            yield return(node);

            if (index.Unique == false)
            {
                // navigate in both sides to return all nodes found
                var first = node;

                // first go forward
                while (!node.Next[0].IsEmpty && ((node = await indexer.GetNode(node.Next[0])).Key.CompareTo(_value, indexer.Collation) == 0))
                {
                    if (node.Key.IsMinValue || node.Key.IsMaxValue)
                    {
                        break;
                    }

                    yield return(node);
                }

                node = first;

                // and than, go backward
                while (!node.Prev[0].IsEmpty && ((node = await indexer.GetNode(node.Prev[0])).Key.CompareTo(_value, indexer.Collation) == 0))
                {
                    if (node.Key.IsMinValue || node.Key.IsMaxValue)
                    {
                        break;
                    }

                    yield return(node);
                }
            }
        }
Exemplo n.º 3
0
        private IEnumerable <IndexNode> ExecuteStartsWith(IndexService indexer, CollectionIndex index)
        {
            // find first indexNode
            var first = indexer.Find(index, _startsWith, true, this.Order);
            var node  = first;

            // if collection exists but are empty
            if (first == null)
            {
                yield break;
            }

            // first, go backward to get all same values
            while (node != null)
            {
                // if current node are edges exit while
                if (node.Key.IsMinValue || node.Key.IsMaxValue)
                {
                    break;
                }

                var valueString = node.Key.IsString ? node.Key.AsString : node.Key.ToString();

                if (_equals ?
                    valueString.Equals(_startsWith, StringComparison.OrdinalIgnoreCase) :
                    valueString.StartsWith(_startsWith, StringComparison.OrdinalIgnoreCase))
                {
                    // must still testing SqlLike method for rest of pattern - only if exists more to test (avoid slow SqlLike test)
                    if ((_testSqlLike == false) ||
                        (_testSqlLike == true && valueString.SqlLike(_pattern) == true))
                    {
                        yield return(node);
                    }
                }
                else
                {
                    break;
                }

                node = indexer.GetNode(node.GetNextPrev(0, -this.Order));
            }

            // move fordward
            node = indexer.GetNode(first.GetNextPrev(0, this.Order));

            while (node != null)
            {
                // if current node are edges exit while
                if (node.Key.IsMinValue || node.Key.IsMaxValue)
                {
                    break;
                }

                var valueString = node.Key.IsString ? node.Key.AsString : node.Key.ToString();

                if (_equals ?
                    valueString.Equals(_pattern, StringComparison.OrdinalIgnoreCase) :
                    valueString.StartsWith(_startsWith, StringComparison.OrdinalIgnoreCase))
                {
                    // must still testing SqlLike method for rest of pattern - only if exists more to test (avoid slow SqlLike test)
                    if (node.DataBlock.IsEmpty == false &&
                        ((_testSqlLike == false) ||
                         (_testSqlLike == true && valueString.SqlLike(_pattern) == true)))
                    {
                        yield return(node);
                    }
                }
                else
                {
                    break;
                }

                // first, go backward to get all same values
                node = indexer.GetNode(node.GetNextPrev(0, this.Order));
            }
        }
Exemplo n.º 4
0
        /// <summary>
        /// Implement internal update document
        /// </summary>
        private bool UpdateDocument(Snapshot snapshot, CollectionPage col, BsonDocument doc, IndexService indexer, DataService data)
        {
            // normalize id before find
            var id = doc["_id"];

            // validate id for null, min/max values
            if (id.IsNull || id.IsMinValue || id.IsMaxValue)
            {
                throw LiteException.InvalidDataType("_id", id);
            }

            // find indexNode from pk index
            var pkNode = indexer.Find(col.PK, id, false, LiteDB.Query.Ascending);

            // if not found document, no updates
            if (pkNode == null)
            {
                return(false);
            }

            // update data storage
            data.Update(col, pkNode.DataBlock, doc);

            // get all current non-pk index nodes from this data block (slot, key, nodePosition)
            var oldKeys = indexer.GetNodeList(pkNode.NextNode)
                          .Select(x => new Tuple <byte, BsonValue, PageAddress>(x.Slot, x.Key, x.Position))
                          .ToArray();

            // build a list of all new key index keys
            var newKeys = new List <Tuple <byte, BsonValue, string> >();

            foreach (var index in col.GetCollectionIndexes().Where(x => x.Name != "_id"))
            {
                // getting all keys from expression over document
                var keys = index.BsonExpr.Execute(doc, _header.Pragmas.Collation);

                foreach (var key in keys)
                {
                    newKeys.Add(new Tuple <byte, BsonValue, string>(index.Slot, key, index.Name));
                }
            }

            if (oldKeys.Length == 0 && newKeys.Count == 0)
            {
                return(true);
            }

            // get a list of all nodes that are in oldKeys but not in newKeys (must delete)
            var toDelete = new HashSet <PageAddress>(oldKeys
                                                     .Where(x => newKeys.Any(n => n.Item1 == x.Item1 && n.Item2 == x.Item2) == false)
                                                     .Select(x => x.Item3));

            // get a list of all keys that are not in oldKeys (must insert)
            var toInsert = newKeys
                           .Where(x => oldKeys.Any(o => o.Item1 == x.Item1 && o.Item2 == x.Item2) == false)
                           .ToArray();

            // if nothing to change, just exit
            if (toDelete.Count == 0 && toInsert.Length == 0)
            {
                return(true);
            }

            // delete nodes and return last keeped node in list
            var last = indexer.DeleteList(pkNode.Position, toDelete);

            // now, insert all new nodes
            foreach (var elem in toInsert)
            {
                var index = col.GetCollectionIndex(elem.Item3);

                last = indexer.AddNode(index, elem.Item2, pkNode.DataBlock, last);
            }

            return(true);
        }
Exemplo n.º 5
0
        public override IEnumerable <IndexNode> Execute(IndexService indexer, CollectionIndex index)
        {
            // if order are desc, swap start/end values
            var start = this.Order == Query.Ascending ? _start : _end;
            var end   = this.Order == Query.Ascending ? _end : _start;

            var startEquals = this.Order == Query.Ascending ? _startEquals : _endEquals;
            var endEquals   = this.Order == Query.Ascending ? _endEquals : _startEquals;

            // find first indexNode (or get from head/tail if Min/Max value)
            var first =
                start.Type == BsonType.MinValue ? indexer.GetNode(index.Head) :
                start.Type == BsonType.MaxValue ? indexer.GetNode(index.Tail) :
                indexer.Find(index, start, true, this.Order);

            var node = first;

            // if startsEquals, return all equals value from start linked list
            if (startEquals && node != null)
            {
                // going backward in same value list to get first value
                while (!node.GetNextPrev(0, -this.Order).IsEmpty&& ((node = indexer.GetNode(node.GetNextPrev(0, -this.Order))).Key.CompareTo(start) == 0))
                {
                    if (node.Key.IsMinValue || node.Key.IsMaxValue)
                    {
                        break;
                    }

                    yield return(node);
                }

                node = first;
            }

            // returns (or not) equals start value
            while (node != null)
            {
                var diff = node.Key.CompareTo(start);

                // if current value are not equals start, go out this loop
                if (diff != 0)
                {
                    break;
                }

                if (startEquals && !(node.Key.IsMinValue || node.Key.IsMaxValue))
                {
                    yield return(node);
                }

                node = indexer.GetNode(node.GetNextPrev(0, this.Order));
            }

            // navigate using next[0] do next node - if less or equals returns
            while (node != null)
            {
                var diff = node.Key.CompareTo(end);

                if (endEquals && diff == 0 && !(node.Key.IsMinValue || node.Key.IsMaxValue))
                {
                    yield return(node);
                }
                else if (diff == -this.Order && !(node.Key.IsMinValue || node.Key.IsMaxValue))
                {
                    yield return(node);
                }
                else
                {
                    break;
                }

                node = indexer.GetNode(node.GetNextPrev(0, this.Order));
            }
        }