コード例 #1
0
ファイル: Query.cs プロジェクト: paultyng/GoogleVisualization
        public Query(Type elementType, string query, ModelMetadataProvider provider)
        {
            if (elementType == null) throw new ArgumentNullException("elementType");
            if (provider == null) throw new ArgumentNullException("provider");

            _elementType = elementType;
            _provider = provider;

            if (string.IsNullOrWhiteSpace(query)) query = string.Empty;

            _originalQuery = query;

            var grammar = new QueryLanguageGrammar();
            var language = new LanguageData(grammar);
            var parser = new Parser(language);
            var tree = parser.Parse(query);

            if (tree.Status == ParseTreeStatus.Parsed)
            {
                AssertEmpty(tree.Root.ChildNodes[2]); //groupBy
                AssertEmpty(tree.Root.ChildNodes[3]); //pivot
                AssertEmpty(tree.Root.ChildNodes[9]); //options

                _limit = ProcessIntNode(tree.Root.ChildNodes[5]);
                _offset = ProcessIntNode(tree.Root.ChildNodes[6]);

                //TODO: when handling pivot, need to rework this
                var metadata = provider.GetMetadataForType((Func<object>)null, elementType);
                var properties = metadata.Properties.ToList();

                if (tree.Root.ChildNodes[0].ChildNodes.Count == 0
                    || (tree.Root.ChildNodes[0].ChildNodes.Count == 2 && tree.Root.ChildNodes[0].ChildNodes[1].Token != null && tree.Root.ChildNodes[0].ChildNodes[1].Token.Value == "*")) //select *
                {
                    //select of all columns of elementType, just a pass through of all the columns
                    _outputType = elementType;
                    _selectStar = true;
                    _columns = MetadataToColumns(properties.OrderBy(p => p.Order));
                }
                else
                {
                    _selectStar = false;

                    //create custom output type unless select contains all columns just reordered...
                    var selectList = tree.Root.ChildNodes[0].ClauseList();

                    if (!selectList.Any(e => !string.Equals(e.Term.Name, "identifier", StringComparison.Ordinal)))
                    {
                        //all identifiers, so just pass through current type for simplicity, no projection, exclude columns on client side
                        _outputType = elementType;

                        var selectListJoin = selectList.Join(properties, i => i.ToPropertyName(), p => p.PropertyName, (i,p) => p).ToList();

                        if (selectListJoin.Count != selectList.Count) throw new QueryParseException("Some of the identifiers passed in the select clause do not exist.");

                        _columns = MetadataToColumns(selectListJoin);
                    }
                    else
                    {
                        throw new NotImplementedException();
                    }

                    //populate columns list
                }

                var labelList = tree.Root.ChildNodes[7].ClauseList();

                var labelListJoin = from l in labelList
                                    join c in _columns on l.ChildNodes[0].ToPropertyName() equals c.Name
                                    select new { l, c };

                foreach (var j in labelListJoin)
                {
                    j.c.Label = (string)j.l.ChildNodes[1].Token.Value;
                }

                var formatList = tree.Root.ChildNodes[8].ClauseList();

                var formatListJoin = from f in formatList
                                     join c in _columns on f.ChildNodes[0].ToPropertyName() equals c.Name
                                     select new { f, c };

                foreach (var j in formatListJoin)
                {
                    j.c.Label = (string)j.f.ChildNodes[1].Token.Value;
                }

                //TODO: handle where
                AssertEmpty(tree.Root.ChildNodes[1]); //where

                var orderByList = tree.Root.ChildNodes[4].ClauseList();

                var orderByListJoin = from o in orderByList
                                      join p in properties on o.ChildNodes[0].ToPropertyName() equals p.PropertyName into propertyGroup
                                      from p in propertyGroup.DefaultIfEmpty()
                                      select new { o, p };

                foreach (var o in orderByListJoin)
                {
                    if (o.p == null) throw new NotImplementedException("Can only order by identifiers.");

                    var ascending = true;

                    if (o.o.ChildNodes.Count == 2)
                    {
                        ascending = !string.Equals((string)o.o.ChildNodes[1].Token.Value, "desc", StringComparison.OrdinalIgnoreCase);
                    }

                    if (_orderBy == null)
                    {
                        if (ascending)
                        {
                            _orderBy = data => data.OrderBy(o.p.PropertyName);
                        }
                        else
                        {
                            _orderBy = data => data.OrderByDescending(o.p.PropertyName);
                        }
                    }
                    else
                    {
                        if (ascending)
                        {
                            _orderBy = data => _orderBy(data.OrderBy(o.p.PropertyName));
                        }
                        else
                        {
                            _orderBy = data => _orderBy(data.OrderByDescending(o.p.PropertyName));
                        }
                    }
                }
            }
            else
            {
                throw new QueryParseException("Query parsing resulted in an error.");
            }
        }