示例#1
0
        /// <summary>
        /// Read includes paths using comma delimiter: xxx include $.Books[*], $.Customer
        /// </summary>
        public string[] ReadIncludes(StringScanner s)
        {
            if (s.Scan(@"\s*include[s]?\s+").Length > 0)
            {
                var includes = new List <string>();
                var include  = BsonExpression.ReadExpression(s, true);

                if (include == null)
                {
                    throw LiteException.SyntaxError(s, "Missing include paths");
                }

                while (include != null && !s.HasTerminated)
                {
                    includes.Add(include);

                    // capture next only if found comma symbol
                    include = s.Scan(@"\s*,\s*").Length > 0 ?
                              BsonExpression.ReadExpression(s, true) :
                              null;
                }

                return(includes.ToArray());
            }

            return(new string[0]);
        }
示例#2
0
        public IEnumerable <BsonValue> Execute(StringScanner s, LiteEngine engine)
        {
            var col = this.ReadCollection(engine, s);

            // try read any kind of expression
            var expression = BsonExpression.ReadExpression(s, false, false);

            // if not found a valid one, try read only as path (will add $. before)
            if (expression == null)
            {
                expression = BsonExpression.ReadExpression(s, true, true);
            }

            var query = Query.All();

            // support into new_collection
            var into   = s.Scan(@"\s*into\s+([\w-]+)", 1);
            var autoId = BsonType.ObjectId;

            // checks for autoId
            if (into.Length > 0)
            {
                var sid = s.Scan(@"\s+_?id:(int32|int64|int|long|objectid|datetime|date|guid)", 1).Trim().ToLower();
                autoId =
                    sid == "int32" || sid == "int" ? BsonType.Int32 :
                    sid == "int64" || sid == "long" ? BsonType.Int64 :
                    sid == "date" || sid == "datetime" ? BsonType.DateTime :
                    sid == "guid" ? BsonType.Guid : BsonType.ObjectId;
            }

            if (s.Scan(@"\s*where\s*").Length > 0)
            {
                query = this.ReadQuery(s, true);
            }

            var skipLimit = this.ReadSkipLimit(s);
            var includes  = this.ReadIncludes(s);

            s.ThrowIfNotFinish();

            var docs = engine.Find(col, query, includes, skipLimit.Key, skipLimit.Value);

            if (into.Length > 0)
            {
                // insert into results to other collection collection
                var count = engine.InsertBulk(into, this.Execute(docs, expression), autoId: autoId);

                // return inserted documents
                return(new BsonValue[] { count });
            }
            else
            {
                return(this.Execute(docs, expression).Select(x => x as BsonValue));
            }
        }
示例#3
0
        public IEnumerable <BsonValue> Execute(StringScanner s, LiteEngine engine)
        {
            var col    = this.ReadCollection(engine, s);
            var value  = JsonSerializer.Deserialize(s);
            var sid    = s.Scan(@"\s+_?id:(int32|int64|int|long|objectid|datetime|date|guid)", 1).Trim().ToLower();
            var autoId =
                sid == "int32" || sid == "int" ? BsonType.Int32 :
                sid == "int64" || sid == "long" ? BsonType.Int64 :
                sid == "date" || sid == "datetime" ? BsonType.DateTime :
                sid == "guid" ? BsonType.Guid : BsonType.ObjectId;

            s.ThrowIfNotFinish();

            if (value.IsArray)
            {
                var count = engine.InsertBulk(col, value.AsArray.RawValue.Select(x => x.AsDocument), autoId: autoId);

                yield return(count);
            }
            else if (value.IsDocument)
            {
                engine.Insert(col, new BsonDocument[] { value.AsDocument }, autoId);

                yield return(value.AsDocument["_id"]);
            }
            else
            {
                throw LiteException.SyntaxError(s, "Invalid JSON value (must be a document or an array)");
            }
        }
示例#4
0
        public IEnumerable <BsonValue> Execute(StringScanner s, LiteEngine engine)
        {
            var col   = this.ReadCollection(engine, s);
            var index = s.Scan(this.FieldPattern).Trim().ThrowIfEmpty("Missing field index name", s);

            s.ThrowIfNotFinish();

            yield return(engine.DropIndex(col, index));
        }
示例#5
0
        public IEnumerable <BsonValue> Execute(StringScanner s, LiteEngine engine)
        {
            var col     = this.ReadCollection(engine, s);
            var newName = s.Scan(@"[\w-]+").ThrowIfEmpty("Invalid new collection name", s);

            s.ThrowIfNotFinish();

            yield return(engine.RenameCollection(col, newName));
        }
示例#6
0
        public IEnumerable <BsonValue> Execute(StringScanner s, LiteEngine engine)
        {
            var col   = this.ReadCollection(engine, s);
            var index = s.Scan(this.FieldPattern).Trim();

            if (!s.HasTerminated)
            {
                throw LiteException.SyntaxError(s, "Invalid field/index name");
            }

            yield return(engine.Min(col, index.Length == 0 ? "_id" : index));
        }
示例#7
0
        public IEnumerable <BsonValue> Execute(StringScanner s, LiteEngine engine)
        {
            var col      = this.ReadCollection(engine, s);
            var filename = s.Scan(@".*");

            using (var sr = new StreamReader(new FileStream(filename, System.IO.FileMode.Open)))
            {
                var docs = JsonSerializer.DeserializeArray(sr);

                yield return(engine.InsertBulk(col, docs.Select(x => x.AsDocument)));
            }
        }
示例#8
0
        /// <summary>
        /// Read includes paths using comma delimiter: xxx include $.Books[*], $.Customer
        /// </summary>
        public string[] ReadIncludes(StringScanner s)
        {
            if (s.Scan(@"\s*include[s]?\s+").Length > 0)
            {
                var includes = new List <string>();
                var include  = BsonExpression.ReadExpression(s, true, true);

                while (include != null)
                {
                    includes.Add(include.Source);

                    // capture next only if found comma symbol
                    include = s.Scan(@"\s*,\s*").Length > 0 ?
                              BsonExpression.ReadExpression(s, true, true) :
                              null;
                }

                return(includes.ToArray());
            }

            return(new string[0]);
        }
示例#9
0
        private Query ReadOneQuery(StringScanner s)
        {
            var field = BsonExpression.ReadExpression(s, false) ?? s.Scan(this.FieldPattern).Trim().ThrowIfEmpty("Invalid field", s);
            var oper  = s.Scan(@"\s*(=|!=|>=|<=|>|<|like|starts[Ww]ith|in|between|contains)\s*").Trim().ToLower().ThrowIfEmpty("Invalid query operator", s);

            if (s.HasTerminated)
            {
                throw LiteException.SyntaxError(s, "Missing value");
            }

            var value = JsonSerializer.Deserialize(s);

            switch (oper)
            {
            case "=": return(Query.EQ(field, value));

            case "!=": return(Query.Not(field, value));

            case ">": return(Query.GT(field, value));

            case ">=": return(Query.GTE(field, value));

            case "<": return(Query.LT(field, value));

            case "<=": return(Query.LTE(field, value));

            case "like":
            case "startswith": return(Query.StartsWith(field, value));

            case "in": return(Query.In(field, value.AsArray));

            case "between": return(Query.Between(field, value.AsArray[0], value.AsArray[1]));

            case "contains": return(Query.Contains(field, value));

            default: throw new LiteException("Invalid query operator");
            }
        }
示例#10
0
        public KeyValuePair <int, int> ReadSkipLimit(StringScanner s)
        {
            var skip  = 0;
            var limit = int.MaxValue;

            if (s.Match(@"\s*skip\s+\d+"))
            {
                skip = Convert.ToInt32(s.Scan(@"\s*skip\s+(\d+)\s*", 1));
            }

            if (s.Match(@"\s*limit\s+\d+"))
            {
                limit = Convert.ToInt32(s.Scan(@"\s*limit\s+(\d+)\s*", 1));
            }

            // skip can be before or after limit command
            if (s.Match(@"\s*skip\s+\d+"))
            {
                skip = Convert.ToInt32(s.Scan(@"\s*skip\s+(\d+)\s*", 1));
            }

            return(new KeyValuePair <int, int>(skip, limit));
        }
示例#11
0
        public IEnumerable <BsonValue> Execute(StringScanner s, LiteEngine engine)
        {
            var    col        = this.ReadCollection(engine, s);
            var    field      = s.Scan(this.FieldPattern).Trim().ThrowIfEmpty("Invalid field/index name", s);
            var    unique     = false;
            string expression = null;

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

            if (s.HasTerminated == false)
            {
                unique = s.Scan(@"unique\s*").Length > 0;

                if (s.Scan(@"\s*using\s+(.+)").Length > 0)
                {
                    expression = BsonExpression.ReadExpression(s, true, false)?.Source;
                }
            }

            s.ThrowIfNotFinish();

            yield return(engine.EnsureIndex(col, field, unique, expression));
        }
示例#12
0
        public IEnumerable <BsonValue> Execute(StringScanner s, LiteEngine engine)
        {
            var fs       = new LiteStorage(engine);
            var id       = this.ReadId(s);
            var filename = s.Scan(@"\s*.*").Trim();

            var file = fs.FindById(id);

            if (file != null)
            {
                file.SaveAs(filename);

                yield return(file.AsDocument);
            }
        }
示例#13
0
        private Query ReadInlineQuery(StringScanner s)
        {
            var left = this.ReadOneQuery(s);
            var oper = s.Scan(@"\s+(and|or)\s+").ToLower().Trim();

            // there is no right side
            if (oper.Length == 0)
            {
                return(left);
            }

            var right = this.ReadInlineQuery(s);

            return(oper == "and" ? Query.And(left, right) : Query.Or(left, right));
        }
示例#14
0
        public IEnumerable <BsonValue> Execute(StringScanner s, LiteEngine engine)
        {
            var fs = new LiteStorage(engine);
            var id = this.ReadId(s);

            var filename = s.Scan(@"\s*.*").Trim();

            if (!File.Exists(filename))
            {
                throw new IOException("File " + filename + " not found");
            }

            var file = fs.Upload(id, filename);

            yield return(file.AsDocument);
        }
示例#15
0
        public Query ReadQuery(StringScanner s, bool required)
        {
            s.Scan(@"\s*");

            if (required && s.HasTerminated)
            {
                throw LiteException.SyntaxError(s, "Unexpected finish of line");
            }

            if (s.HasTerminated || s.Match(@"skip\s+\d") || s.Match(@"limit\s+\d") || s.Match(@"include[s]?\s+[\$\w]"))
            {
                return(Query.All());
            }

            return(this.ReadInlineQuery(s));
        }
示例#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();

                // execute command
                var count = 0;

                foreach (var doc in engine.Find(col, query))
                {
                    var docChanged = false;

                    foreach (var update in updates)
                    {
                        var itemChanged = false;

                        if (update.Value == null)
                        {
                            itemChanged = doc.Set(update.Path, update.Expr, update.Add);
                        }
                        else
                        {
                            itemChanged = doc.Set(update.Path, update.Value, update.Add);
                        }

                        if (itemChanged)
                        {
                            docChanged = true;
                        }
                    }

                    // execute update only if document was changed
                    if (docChanged)
                    {
                        engine.Update(col, doc);

                        count++;
                    }
                }

                yield return(count);
            }
        }
示例#17
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 query   = Query.All();
                var updates = new Update();

                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)?.Source : null;

                    if (action == "+=" && value != null)
                    {
                        updates.Add(path, value);
                    }
                    else if (action == "+=" && expr != null)
                    {
                        updates.AddExpr(path, expr);
                    }
                    else if (action == "=" && value != null)
                    {
                        updates.Set(path, value);
                    }
                    else if (action == "=" && expr != null)
                    {
                        updates.SetExpr(path, expr);
                    }
                    else
                    {
                        throw LiteException.SyntaxError(s);
                    }

                    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();

                yield return(engine.Update(col, query, updates));
            }
        }
示例#18
0
 public bool IsFileCommand(StringScanner s, string command)
 {
     return(s.Scan(@"fs\." + command + @"\s*").Length > 0);
 }
示例#19
0
        public IEnumerable <BsonValue> Execute(StringScanner s, LiteEngine engine)
        {
            var col    = this.ReadCollection(engine, s);
            var fields = new Dictionary <string, BsonExpression>();
            var index  = 0;

            // read all fields definitions (support AS as keyword no name field)
            while (!s.HasTerminated)
            {
                // try read any kind of expression
                var expression = BsonExpression.ReadExpression(s, false, false);

                // if not found a valid one, try read only as path (will add $. before)
                if (expression == null)
                {
                    expression = BsonExpression.ReadExpression(s, true, true);
                }

                var key = s.Scan(@"\s*as\s+([\w-]+)", 1).TrimToNull()
                          ?? this.NamedField(expression)
                          ?? ("expr" + (++index));

                // if key already exits, add with another name
                while (fields.ContainsKey(key))
                {
                    key = "expr" + (++index);
                }

                fields.Add(key, expression);

                if (s.Scan(@"\s*,\s*").Length > 0)
                {
                    continue;
                }
                break;
            }

            // select command required output value, path or expression
            if (fields.Count == 0)
            {
                throw LiteException.SyntaxError(s, "Missing select path");
            }

            var query = Query.All();

            if (s.Scan(@"\s*where\s*").Length > 0)
            {
                query = this.ReadQuery(s, true);
            }

            var skipLimit = this.ReadSkipLimit(s);
            var includes  = this.ReadIncludes(s);

            s.ThrowIfNotFinish();

            var docs = engine.Find(col, query, includes, skipLimit.Key, skipLimit.Value);

            foreach (var doc in docs)
            {
                // if is a single value, return as just field
                if (fields.Count == 1)
                {
                    foreach (var value in fields.Values.First().Execute(doc, false))
                    {
                        yield return(value);
                    }
                }
                else
                {
                    var output = new BsonDocument();

                    foreach (var field in fields)
                    {
                        output[field.Key] = field.Value.Execute(doc, true).First();
                    }

                    yield return(output);
                }
            }
        }
示例#20
0
 public bool IsCommand(StringScanner s)
 {
     return(s.Scan(@"db.info$").Length > 0);
 }
示例#21
0
 /// <summary>
 /// Read collection name from db.(collection).(command)
 /// </summary>
 public string ReadCollection(LiteEngine db, StringScanner s)
 {
     return(s.Scan(@"db\.([\w-]+)\.\w+\s*", 1));
 }
示例#22
0
 /// <summary>
 /// Read Id file
 /// </summary>
 public string ReadId(StringScanner s)
 {
     return(s.Scan(LiteFileInfo.ID_PATTERN.Substring(1, LiteFileInfo.ID_PATTERN.Length - 2)));
 }