/// <summary>
 /// Sort the documents of resultset in descending order according to a key (support only one OrderBy)
 /// </summary>
 public ILiteQueryableAsync <T> OrderByDescending(BsonExpression keySelector)
 {
     _wrappedQuery.OrderByDescending(keySelector);
     return(this);
 }
Esempio n. 2
0
        public void Expressions_Scalar_Path()
        {
            BsonDocument doc;

            BsonValue S(string s)
            {
                return(BsonExpression.Create(s).ExecuteScalar(doc));
            }

            ;

            // direct path navigation
            doc = J("{ a: 1, b: null, c: true, d:[1,2], e:{d:4} }");

            S("a").ExpectValue(1);
            S("b").ExpectValue(BsonValue.Null);
            S("c").ExpectValue(true);
            S("d").ExpectArray(1, 2);
            S("e").ExpectJson("{d:4}");

            // dive into subdocumentos
            doc = J("{ a: { b: { c: { d: 1 } } } }");

            S("a").ExpectJson("{ b: { c: { d: 1 } } }");
            S("a.b").ExpectJson("{ c: { d: 1 } }");
            S("a.b.c").ExpectJson("{ d: 1 }");
            S("a.b.c.d").ExpectValue(1);

            // Missing field
            doc = J("{ a: { b: 1 } }");

            S("b").ExpectValue(BsonValue.Null);
            S("a.c").ExpectValue(BsonValue.Null);
            S("x.j").ExpectValue(BsonValue.Null);

            // Array fixed position
            doc = J("{ a: [1, 2, 3] }");

            S("a[0]").ExpectValue(1);
            S("a[1]").ExpectValue(2);
            S("a[-1]").ExpectValue(3);
            S("a[99]").ExpectValue(BsonValue.Null);

            // Root and Current in array
            doc = J("{ a: [ { b: 1, c: 2 }, { b: 2, c: 3 } ], i: 0 }");

            S("FIRST(a[@.b = 1].c)").ExpectValue(2);
            S("FIRST(a[b = 2].c)").ExpectValue(3);

            // Complex field name
            doc = J("{ \"a b\": 1, \"c d\": { \"x y\": 2 }, x: { \"$y!z\\\"'\": 3 } }");

            S("$.[\"a b\"]").ExpectValue(1);
            S("$.['c d'].['x y']").ExpectValue(2);
            S("$.x.[\"$y!z\\\"'\"]").ExpectValue(3);

            // Object creation
            S("'lite' + \"db\"").ExpectValue("litedb");
            S("true").ExpectValue(true);
            S("123").ExpectValue(123);
            S("{ a: 1}").ExpectJson("{ a: 1}");
            S("{ b: 1+1 }").ExpectJson("{ b: 2 }");
            S("{'a-b':1, \"x+1\": 2, 'y': 3}").ExpectJson("{\"a-b\": 1, \"x+1\": 2, y: 3 }");

            // Document simplified notation declaration
            doc = J("{ a: 1, b: 2, c: 3, d: {e: 4, f: 5 }}");

            S("{ a }").ExpectJson("{ a: 1 }");
            S("{ a, c }").ExpectJson("{ a: 1, c: 3 }");
            S("{ d, z: d.e }").ExpectJson("{ d: { e: 4, f: 5 }, z: 4 }");

            // Document simplified notation with complex key
            doc = J("{ \"a b\": 1, c: 2 }");

            S("{ 'a b', z:  null }").ExpectJson("{ \"a b\": 1, z: null }");
            S("{ 'c' }").ExpectJson("{ c: 2 }");
        }
Esempio n. 3
0
 public IEnumerable <T> Get(BsonExpression predicate, int skip = 0, int limit = int.MaxValue)
 {
     return(LiteDb.GetCollection <T>(CollectionName).Find(predicate, skip, limit));
 }
Esempio n. 4
0
        /// <summary>
        /// INCLUDE: Do include in result document according path expression - Works only with DocumentLookup
        /// </summary>
        protected IEnumerable <BsonDocument> Include(IEnumerable <BsonDocument> source, BsonExpression path)
        {
            // cached services
            string          last     = null;
            Snapshot        snapshot = null;
            IndexService    indexer  = null;
            DataService     data     = null;
            CollectionIndex index    = null;
            IDocumentLookup lookup   = null;

            foreach (var doc in source)
            {
                foreach (var value in path.Execute(doc, _pragmas.Collation)
                         .Where(x => x.IsDocument || x.IsArray)
                         .ToList())
                {
                    // if value is document, convert this ref document into full document (do another query)
                    if (value.IsDocument)
                    {
                        DoInclude(value.AsDocument);
                    }
                    else
                    {
                        // if value is array, do same per item
                        foreach (var item in value.AsArray
                                 .Where(x => x.IsDocument)
                                 .Select(x => x.AsDocument))
                        {
                            DoInclude(item);
                        }
                    }
                }

                yield return(doc);
            }

            void DoInclude(BsonDocument value)
            {
                // works only if is a document
                var refId  = value["$id"];
                var refCol = value["$ref"];

                // if has no reference, just go out
                if (refId.IsNull || !refCol.IsString)
                {
                    return;
                }

                // do some cache re-using when is same $ref (almost always is the same $ref collection)
                if (last != refCol.AsString)
                {
                    last = refCol.AsString;

                    // initialize services
                    snapshot = _transaction.CreateSnapshot(LockMode.Read, last, false);
                    indexer  = new IndexService(snapshot, _pragmas.Collation);
                    data     = new DataService(snapshot);

                    lookup = new DatafileLookup(data, _pragmas.UtcDate, null);

                    index = snapshot.CollectionPage?.PK;
                }

                // fill only if index and ref node exists
                if (index != null)
                {
                    var node = indexer.Find(index, refId, false, Query.Ascending);

                    if (node != null)
                    {
                        // load document based on dataBlock position
                        var refDoc = lookup.Load(node);

                        value.Remove("$id");
                        value.Remove("$ref");

                        refDoc.CopyTo(value);
                    }
                    else
                    {
                        // set in ref document that was not found
                        value.Add("$missing", true);
                    }
                }
            }
        }
Esempio n. 5
0
 private BsonExpression TestExpr <T>(Expression <Func <T, object> > expr, BsonExpression expect, params BsonValue[] args)
 {
     return(this.Test <T, object>(expr, expect, args));
 }
Esempio n. 6
0
        /// <summary>
        /// Create a new index (or do nothing if already exists) to a collection/field
        /// </summary>
        public bool EnsureIndex(string collection, string name, BsonExpression expression, bool unique)
        {
            if (collection.IsNullOrWhiteSpace())
            {
                throw new ArgumentNullException(nameof(collection));
            }
            if (name.IsNullOrWhiteSpace())
            {
                throw new ArgumentNullException(nameof(name));
            }
            if (expression == null)
            {
                throw new ArgumentNullException(nameof(expression));
            }
            if (expression.IsIndexable == false)
            {
                throw new ArgumentException("Index expressions must contains at least one document field. Used methods must be immutable. Parameters are not supported.", nameof(expression));
            }

            if (name.Length > INDEX_NAME_MAX_LENGTH)
            {
                throw LiteException.InvalidIndexName(name, collection, "MaxLength = " + INDEX_NAME_MAX_LENGTH);
            }
            if (!name.IsWord())
            {
                throw LiteException.InvalidIndexName(name, collection, "Use only [a-Z$_]");
            }
            if (name.StartsWith("$"))
            {
                throw LiteException.InvalidIndexName(name, collection, "Index name can't starts with `$`");
            }

            if (name == "_id")
            {
                return(false);               // always exists
            }
            return(this.AutoTransaction(transaction =>
            {
                var snapshot = transaction.CreateSnapshot(LockMode.Write, collection, true);
                var collectionPage = snapshot.CollectionPage;
                var indexer = new IndexService(snapshot, _header.Pragmas.Collation);
                var data = new DataService(snapshot);

                // check if index already exists
                var current = collectionPage.GetCollectionIndex(name);

                // if already exists, just exit
                if (current != null)
                {
                    // but if expression are different, throw error
                    if (current.Expression != expression.Source)
                    {
                        throw LiteException.IndexAlreadyExist(name);
                    }

                    return false;
                }

                LOG($"create index `{collection}.{name}`", "COMMAND");

                // create index head
                var index = indexer.CreateIndex(name, expression.Source, unique);
                var count = 0u;

                // read all objects (read from PK index)
                foreach (var pkNode in new IndexAll("_id", LiteDB.Query.Ascending).Run(collectionPage, indexer))
                {
                    using (var reader = new BufferReader(data.Read(pkNode.DataBlock)))
                    {
                        var doc = reader.ReadDocument(expression.Fields);

                        // first/last node in this document that will be added
                        IndexNode last = null;
                        IndexNode first = null;

                        // get values from expression in document
                        var keys = expression.Execute(doc, _header.Pragmas.Collation);

                        // adding index node for each value
                        foreach (var key in keys)
                        {
                            // when index key is an array, get items inside array.
                            // valid only for first level (if this items are another array, this arrays will be indexed as array)
                            if (key.IsArray)
                            {
                                var arr = key.AsArray;

                                foreach (var itemKey in arr)
                                {
                                    // insert new index node
                                    var node = indexer.AddNode(index, itemKey, pkNode.DataBlock, last);

                                    if (first == null)
                                    {
                                        first = node;
                                    }

                                    last = node;

                                    count++;
                                }
                            }
                            else
                            {
                                // insert new index node
                                var node = indexer.AddNode(index, key, pkNode.DataBlock, last);

                                if (first == null)
                                {
                                    first = node;
                                }

                                last = node;

                                count++;
                            }
                        }

                        // fix single linked-list in pkNode
                        if (first != null)
                        {
                            last.SetNextNode(pkNode.NextNode);
                            pkNode.SetNextNode(first.Position);
                        }
                    }

                    transaction.Safepoint();
                }

                return true;
            }));
        }
Esempio n. 7
0
        /// <summary>
        /// WHERE: Filter document according expression. Expression must be an Bool result
        /// </summary>
        protected IEnumerable <BsonDocument> Filter(IEnumerable <BsonDocument> source, BsonExpression expr)
        {
            foreach (var doc in source)
            {
                // checks if any result of expression is true
                var result = expr.ExecuteScalar(doc, _pragmas.Collation);

                if (result.IsBoolean && result.AsBoolean)
                {
                    yield return(doc);
                }
            }
        }
 /// <summary>
 /// Sort the documents of resultset in ascending (or descending) order according to a key (support only one OrderBy)
 /// </summary>
 public ILiteQueryableAsync <T> OrderBy(BsonExpression keySelector, int order = Query.Ascending)
 {
     _wrappedQuery.OrderBy(keySelector, order);
     return(this);
 }
Esempio n. 9
0
 public override Album GetById(long id)
 {
     return(repo.Include(BsonExpression.Create("$.Songs[*]")).FindById(id));
 }
 /// <summary>
 /// Load cross reference documents from path expression (DbRef reference)
 /// </summary>
 public ILiteQueryableAsync <T> Include(BsonExpression path)
 {
     _wrappedQuery.Include(path);
     return(this);
 }
 /// <summary>
 /// Filters a sequence of documents based on a predicate expression
 /// </summary>
 public ILiteQueryableAsync <T> Where(BsonExpression predicate)
 {
     _wrappedQuery.Where(predicate);
     return(this);
 }
 /// <summary>
 /// Transform input document into a new output document. Can be used with each document, group by or all source
 /// </summary>
 public ILiteQueryableAsyncResult <BsonDocument> Select(BsonExpression selector)
 {
     return(new LiteQueryableAsync <BsonDocument>((ILiteQueryable <BsonDocument>)_wrappedQuery.Select(selector), _liteDatabaseAsync));
 }
 /// <summary>
 /// Filter documents after group by pipe according to predicate expression (requires GroupBy and support only one Having)
 /// </summary>
 public ILiteQueryableAsync <T> Having(BsonExpression predicate)
 {
     _wrappedQuery.Having(predicate);
     return(this);
 }
 /// <summary>
 /// Groups the documents of resultset according to a specified key selector expression (support only one GroupBy)
 /// </summary>
 public ILiteQueryableAsync <T> GroupBy(BsonExpression keySelector)
 {
     _wrappedQuery.GroupBy(keySelector);
     return(this);
 }
Esempio n. 15
0
 public override IEnumerable <Playlist> All()
 {
     return(repo
            .Include(BsonExpression.Create("$.Songs[*]"))
            .FindAll());
 }
Esempio n. 16
0
        public IEnumerable <BsonValue> Execute(StringScanner s, LiteEngine engine)
        {
            var col = this.ReadCollection(engine, s);

            // single document update
            if (s.Match(@"\s*\{"))
            {
                var doc = JsonSerializer.Deserialize(s.ToString()).AsDocument;

                s.ThrowIfNotFinish();

                yield return(engine.Update(col, doc));
            }
            // query update
            else
            {
                // db.colName.update
                //     field = value,
                //     array += valueToAdd,
                // where _id = 1
                //   and ...

                var updates = new List <UpdateData>();
                var query   = Query.All();

                while (!s.HasTerminated)
                {
                    var path   = BsonExpression.ReadExpression(s, true, true).Source;
                    var action = s.Scan(@"\s*\+?=\s*").Trim().ThrowIfEmpty("Invalid operator (support = or +=)", s);
                    var value  = this.ReadBsonValue(s);
                    var expr   = value == null?BsonExpression.ReadExpression(s, true, false) : null;

                    if (action != "+=" && action != "=")
                    {
                        throw LiteException.SyntaxError(s);
                    }
                    if (value == null && expr == null)
                    {
                        throw LiteException.SyntaxError(s);
                    }

                    updates.Add(new UpdateData {
                        Path = path, Value = value, Expr = expr, Add = action == "+="
                    });

                    s.Scan(@"\s*");

                    if (s.Scan(@",\s*").Length > 0)
                    {
                        continue;
                    }
                    else if (s.Scan(@"where\s*").Length > 0 || s.HasTerminated)
                    {
                        break;
                    }
                    else
                    {
                        throw LiteException.SyntaxError(s);
                    }
                }

                if (!s.HasTerminated)
                {
                    query = this.ReadQuery(s, false);
                }

                s.ThrowIfNotFinish();

                // fetch documents to update
                var count = engine.Update(col, this.FetchDocuments(engine, col, query, updates));

                yield return(count);
            }
        }
Esempio n. 17
0
        /// <summary>
        /// Pipe: Run select expression over all recordset
        /// </summary>
        private IEnumerable <BsonDocument> SelectAll(IEnumerable <BsonDocument> source, BsonExpression select)
        {
            var defaultName = select.DefaultFieldName();
            var result      = select.Execute(source);

            //TODO: pode ter algum tipo de CACHE caso a expressão contenha mais de 1 "UseSource"...
            // evita executar todo pipe -- pior dos casos dá um ToArray() (ou usa um DocumentGroup)

            foreach (var value in result)
            {
                if (value.IsDocument)
                {
                    yield return(value.AsDocument);
                }
                else
                {
                    yield return(new BsonDocument {
                        [defaultName] = value
                    });
                }
            }
        }
Esempio n. 18
0
 public Select(BsonExpression expression, bool all)
 {
     this.Expression = expression;
     this.All        = all;
 }
Esempio n. 19
0
        /// <summary>
        /// Update documents using transform expression (must return a scalar/document value) using predicate as filter
        /// </summary>
        public int UpdateMany(string collection, BsonExpression transform, BsonExpression predicate)
        {
            if (collection.IsNullOrWhiteSpace())
            {
                throw new ArgumentNullException(nameof(collection));
            }
            if (transform == null)
            {
                throw new ArgumentNullException(nameof(transform));
            }

            return(this.AutoTransaction(transaction =>
            {
                return this.Update(collection, transformDocs());

                IEnumerable <BsonDocument> transformDocs()
                {
                    var q = new Query {
                        Select = "$", ForUpdate = true
                    };

                    if (predicate != null)
                    {
                        q.Where.Add(predicate);
                    }

                    using (var reader = this.Query(collection, q))
                    {
                        while (reader.Read())
                        {
                            var doc = reader.Current.AsDocument;

                            var id = doc["_id"];
                            var value = transform.ExecuteScalar(doc);

                            if (!value.IsDocument)
                            {
                                throw new ArgumentException("Extend expression must return a document", nameof(transform));
                            }

                            var result = value.AsDocument;

                            // be sure result document will contain same _id as current doc
                            if (result.TryGetValue("_id", out var newId))
                            {
                                if (newId != id)
                                {
                                    throw LiteException.InvalidUpdateField("_id");
                                }
                            }
                            else
                            {
                                result["_id"] = id;
                            }

                            yield return result;
                        }
                    }
                }
            }));
        }
Esempio n. 20
0
 /// <summary>
 /// Delete all documents based on predicate expression. Returns how many documents was deleted
 /// </summary>
 public Task <int> DeleteManyAsync(BsonExpression predicate)
 {
     return(Database.EnqueueAsync(
                () => UnderlyingCollection.DeleteMany(predicate)));
 }
Esempio n. 21
0
        /// <summary>
        /// ORDER BY: Sort documents according orderby expression and order asc/desc
        /// </summary>
        protected IEnumerable <BsonDocument> OrderBy(IEnumerable <BsonDocument> source, BsonExpression expr, int order, int offset, int limit)
        {
            var keyValues = source
                            .Select(x => new KeyValuePair <BsonValue, PageAddress>(expr.ExecuteScalar(x, _pragmas.Collation), x.RawId));

            using (var sorter = new SortService(_tempDisk, order, _pragmas))
            {
                sorter.Insert(keyValues);

                LOG($"sort {sorter.Count} keys in {sorter.Containers.Count} containers", "SORT");

                var result = sorter.Sort().Skip(offset).Take(limit);

                foreach (var keyValue in result)
                {
                    var doc = _lookup.Load(keyValue.Value);

                    yield return(doc);
                }
            }
        }
Esempio n. 22
0
        private IEnumerable <BsonDocument> SelectMany(IEnumerable <BsonDocument> source, BsonExpression select)
        {
            var defaultName = select.DefaultFieldName();

            foreach (var doc in source)
            {
                var values = select.Execute(doc, _pragmas.Collation);
                foreach (var value in values)
                {
                    if (value.IsDocument)
                    {
                        yield return(value.AsDocument);
                    }
                    else
                    {
                        yield return(new BsonDocument {
                            [defaultName] = value
                        });
                    }
                }
            }
        }
 public bool EnsureIndex(string collection, string name, BsonExpression expression, bool unique)
 {
     return(_engine.EnsureIndex(collection, name, expression, unique));
 }
Esempio n. 24
0
        /// <summary>
        /// Pipe: Run select expression over all recordset
        /// </summary>
        private IEnumerable <BsonDocument> SelectAll(IEnumerable <BsonDocument> source, BsonExpression select)
        {
            var cached = new DocumentCacheEnumerable(source, _lookup);

            var defaultName = select.DefaultFieldName();
            var result      = select.Execute(cached, _pragmas.Collation);

            foreach (var value in result)
            {
                if (value.IsDocument)
                {
                    yield return(value.AsDocument);
                }
                else
                {
                    yield return(new BsonDocument {
                        [defaultName] = value
                    });
                }
            }
        }
Esempio n. 25
0
 private BsonExpression TestPredicate <T>(Expression <Func <T, bool> > expr, BsonExpression expect, params BsonValue[] args)
 {
     return(this.Test <T, bool>(expr, expect, args));
 }
Esempio n. 26
0
 public IEnumerable <T> Find(BsonExpression predicate)
 {
     return(Tablet.Find(predicate));
 }
Esempio n. 27
0
 /// <summary>
 /// Run an include action in each document returned by Find(), FindById(), FindOne() and All() methods to load DbRef documents
 /// Returns a new Collection with this action included
 /// </summary>
 public ILiteCollectionAsync <T> Include(BsonExpression keySelector)
 {
     return(new LiteCollectionAsync <T>(UnderlyingCollection.Include(keySelector), Database));
 }
Esempio n. 28
0
 public T FindObj(BsonExpression predicate)
 {
     return(Find(predicate).FirstOrDefault());
 }
Esempio n. 29
0
 public T GetFirstOrDefault(BsonExpression predicate)
 {
     return(LiteDb.GetCollection <T>(CollectionName).FindOne(predicate));
 }
Esempio n. 30
0
 /// <summary>
 /// Find all files that match with predicate expression.
 /// </summary>
 public Task <IEnumerable <LiteFileInfo <TFileId> > > FindAsync(BsonExpression predicate)
 {
     return(_liteDatabaseAsync.EnqueueAsync(
                () => _wrappedStorage.Find(predicate)));
 }