/// <summary>
        /// Parses the supplied expression into a hierarchical list-based representation for easier consumption.
        /// </summary>
        /// <param name="fieldsExpression">The fields expression to be parsed.</param>
        /// <returns>A hierarchical list-based representation of the fields expression.</returns>
        public IReadOnlyList <SelectedResourceMember> ParseFields(string fieldsExpression)
        {
            if (string.IsNullOrEmpty(fieldsExpression))
            {
                throw new ArgumentException("Field selection expression was not supplied.");
            }

            fieldsExpression = fieldsExpression.Trim();

            int anchor = 0;
            int pos    = 0;

            var state = ParseState.SeekingMember;

            var allMembers = new List <SelectedResourceMember>();

            var stack = new Stack <List <SelectedResourceMember> >();

            var members = allMembers;

            while (pos < fieldsExpression.Length || state == ParseState.ChildrenParsed)
            {
                switch (state)
                {
                case ParseState.AllMembersIncluded:

                    if (fieldsExpression[pos] != ')')
                    {
                        throw new ArgumentException("Fields expression uses '*' without enclosing parenthesis.");
                    }

                    state = ParseState.ChildrenParsed;
                    break;

                case ParseState.SeekingMember:

                    // Skip over leading spaces
                    if (fieldsExpression[pos] == ' ')
                    {
                        anchor = ++pos;
                    }

                    // Check for the "all" symbol
                    else if (fieldsExpression[pos] == '*')
                    {
                        state = ParseState.AllMembersIncluded;
                        pos++;
                    }

                    // Check for premature child fields closing symbol with no children listed
                    else if (fieldsExpression[pos] == ')' && !members.Any())
                    {
                        throw new ArgumentException(
                                  "Fields sub-expression does not contain any field names.");
                    }
                    else
                    {
                        state = ParseState.ParsingMember;
                    }

                    break;

                case ParseState.ParsingMember:

                    if (fieldsExpression[pos] == ',')
                    {
                        state = ParseState.MemberParsed;
                    }
                    else if (fieldsExpression[pos] == '(')
                    {
                        state = ParseState.ParsingChildren;
                    }
                    else if (fieldsExpression[pos] == ')')
                    {
                        state = ParseState.ChildrenParsed;
                    }
                    else if (fieldsExpression[pos] == ' ')
                    {
                        state = ParseState.MemberParsed;
                    }
                    else if (!(char.IsLetterOrDigit(fieldsExpression[pos]) || fieldsExpression[pos] == '_'))
                    {
                        throw new ArgumentException(
                                  string.Format("Unexpected character '{0}' in member name in field selection expression.", fieldsExpression[pos]));
                    }
                    else
                    {
                        pos++;
                    }

                    break;

                case ParseState.MemberParsed:
                    string parsedMemberName = fieldsExpression.Substring(anchor, pos - anchor);

                    if (!string.IsNullOrEmpty(parsedMemberName))
                    {
                        members.Add(new SelectedResourceMember(parsedMemberName));
                    }

                    state  = ParseState.SeekingMember;
                    anchor = ++pos;
                    break;

                case ParseState.ParsingChildren:
                    var currentMember = new SelectedResourceMember(fieldsExpression.Substring(anchor, pos - anchor));
                    members.Add(currentMember);
                    state  = ParseState.SeekingMember;
                    anchor = ++pos;

                    stack.Push(members);
                    members = currentMember.Children;

                    break;

                case ParseState.ChildrenParsed:
                    string memberName = fieldsExpression.Substring(anchor, pos - anchor);

                    if (!string.IsNullOrEmpty(memberName) && memberName != ")")
                    {
                        members.Add(new SelectedResourceMember(memberName));
                    }

                    anchor = ++pos;

                    if (!stack.Any())
                    {
                        throw new ArgumentException("Fields expression contains too many closing parenthesis.");
                    }

                    members = stack.Pop();

                    state = ParseState.SeekingMember;
                    break;
                }
            }

            string finalMemberName = fieldsExpression.Substring(anchor, pos - anchor);

            if (!string.IsNullOrEmpty(finalMemberName))
            {
                members.Add(new SelectedResourceMember(finalMemberName));
            }

            if (stack.Count != 0)
            {
                throw new ArgumentException("Fields expression contains unclosed parenthesis.");
            }

            return(allMembers);
        }
        public IList <IDictionary> ProcessResults(
            CompositeQuery query,
            Hashtable parentRow,
            string[] parentKeys,
            IReadOnlyList <SelectedResourceMember> fieldSelections,
            NullValueHandling nullValueHandling,
            IDictionary <string, string> recursiveChildKeyMap = null)
        {
            var results = new List <IDictionary>();

            var currentEnumerator = query.GetEnumerator(parentRow, parentKeys, recursiveChildKeyMap);

            do
            {
                // Nothing to enumerate?
                if (currentEnumerator == null || currentEnumerator.IsComplete)
                {
                    return(results);
                }

                // Get current row
                var currentRow = (Hashtable)currentEnumerator.Current;

                if (currentRow == null)
                {
                    break;
                }

                // If the child is outside the context of the parent, quit processing
                if (parentRow != null && !IsChildRow(parentKeys, parentRow, recursiveChildKeyMap, currentRow))
                {
                    break;
                }

                // Convert the row to serializable form
                var resultItem = GetItem(currentRow, query.DataFields, query.OrderedFieldNames, fieldSelections, nullValueHandling);

                // Process the children
                foreach (var childQuery in query.ChildQueries)
                {
                    SelectedResourceMember selectedMember = null;

                    string childCollectionName = childQuery.DisplayName;

                    // Check to see if this collection should be included
                    if (fieldSelections != null && fieldSelections.Count > 0)
                    {
                        selectedMember = fieldSelections.FirstOrDefault(x => x.Equals(childCollectionName) || x.Equals("*"));

                        if (selectedMember == null)
                        {
                            continue;
                        }
                    }

                    resultItem[childCollectionName] =
                        ProcessResults(
                            childQuery,
                            currentRow,
                            query.KeyFields,
                            selectedMember == null
                                    ? null
                                    : selectedMember.Children,
                            nullValueHandling)
                        .ApplyCardinality(childQuery.IsSingleItemResult);
                }

                // Is the current query recursive?
                if (query.IsRecursive)
                {
                    // Need to add a child "self" collection with recursion
                    resultItem[query.DisplayName] = ProcessResults(
                        query,
                        currentRow,
                        query.KeyFields,
                        fieldSelections,
                        nullValueHandling,
                        query.RecursiveChildKeyMap);

                    // Strip out hierarchical support fields from the response
                    resultItem.Keys.OfType <string>()
                    .Where(k => k.StartsWith(CompositeDefinitionHelper.HierarchyMarker))
                    .ToList()
                    .ForEach(k => resultItem.Remove(k));

                    // Add the row - we're done.
                    results.Add(resultItem);
                }
                else
                {
                    // Just add the row - we're done.
                    results.Add(resultItem);
                }
            }while (currentEnumerator.MoveNext());

            return(results);
        }