// return namespaces
        public string[] CompileTo(AssemblyName assemblyToBuild, string namespaceName, out BuildCodeResult[] generatedBuildCodes)
        {
            var namespaces = new List<string>();
            var generatedCodes = new List<BuildCodeResult>();

            var code = new StringBuilder();
            code.AppendLine("using System;");
            code.AppendLine("using System.IO;");
            code.AppendLine("using System.Text;");
            code.AppendLine("using System.Linq;");
            code.AppendLine("using System.Collections;");
            code.AppendLine("using System.Collections.Generic;");
            code.AppendLine("using System.Windows.Forms.DataVisualization.Charting;");
            code.AppendLine("using System.Threading;");
            code.AppendLine("using Google.Apis.Auth.OAuth2;");
            code.AppendLine("using Google.Apis.Bigquery.v2;");
            code.AppendLine("using Google.Apis.Services;");
            code.AppendLine("using Google.Apis.Util.Store;");
            code.AppendLine("using BigQuery.Linq;");

            code.Append(BuildCustomContext(namespaceName));


            foreach (var schema in Schemas.Where(x => x.GroupedMetaTableSchemas.Any()))
            {
                var namingStoragePerDataset = new DuplicateNamingStorage();

                var tableCodes = schema.GroupedMetaTableSchemas
                     .SelectMany(x =>
                     {
                         var concat = Enumerable.Empty<BuildCodeResult[]>();
                         if (x.IsGrouped)
                         {
                             var f = x.MetaTableSchemas.First();
                             concat = new[] { f.BuildCSharpClasses(outTablePrefixClassIfMatched: true, namingStorage: namingStoragePerDataset) };
                         }

                         return concat.Concat(x.MetaTableSchemas.Select(y => y.BuildCSharpClasses(outTablePrefixClassIfMatched: false, namingStorage: namingStoragePerDataset)));
                     })
                     .SelectMany(xs => xs)
                     .Distinct(x => x.ClassName)
                     .ToArray();

                var typeCode = string.Join(Environment.NewLine + Environment.NewLine, tableCodes.Select(x => x.Code));

                var template = $@"
namespace {namespaceName}.{NameConverter.ConvertSafeName(schema.DatasetName)}
{{
{typeCode}
}}";

                code.Append(template);
                namespaces.Add($"{namespaceName}.{NameConverter.ConvertSafeName(schema.DatasetName)}");
                generatedCodes.AddRange(tableCodes);
            }

            CompilerResults results;
            using (var codeProvider = new CSharpCodeProvider(new Dictionary<string, string>() { { "CompilerVersion", "v4.0" } }))
            {
                var options = new CompilerParameters(
                    new[]
                    {
                        "mscorlib.dll", "System.dll", "System.Core.dll", "System.Xml.dll", "System.Data.dll",
                        "System.Windows.Forms.dll", "System.Windows.Forms.DataVisualization.dll",
                        typeof(LINQPad.DataContextBase).Assembly.Location,
                        typeof(BigQueryContext).Assembly.Location,
                        typeof(BigqueryService).Assembly.Location,
                        typeof(GoogleWebAuthorizationBroker).Assembly.Location,
                        typeof(BaseClientService).Assembly.Location,
                        typeof(Google.GoogleApiException).Assembly.Location,
                        typeof(Google.Apis.Auth.JsonWebToken).Assembly.Location,
                        typeof(FileDataStore).Assembly.Location
                    }.Distinct().ToArray(),
                    assemblyToBuild.CodeBase,
                    true);
                results = codeProvider.CompileAssemblyFromSource(options, code.ToString());
            }

            if (results.Errors.Count > 0)
            {
                throw new Exception
                    ("Cannot compile typed context: " + results.Errors[0].ErrorText + " (line " + results.Errors[0].Line + ")");
            }

            generatedBuildCodes = generatedCodes.ToArray();
            return namespaces.ToArray();
        }
        public List<ExplorerItem> BuildExplorerItems(BuildCodeResult[] generatedCodes)
        {
            var tableRangeLookupDictionary = generatedCodes
                .Where(x => x.IsTablePrefix)
                .Distinct(x => x.MetaTableSchema)
                .ToDictionary(x => x.MetaTableSchema);

            var tableLookupDictionary = generatedCodes
                .Where(x => x.IsTableName)
                .Distinct(x => x.MetaTableSchema)
                .ToDictionary(x => x.MetaTableSchema);

            var matchTableRange = new Regex(@"\d{8}$");

            var list = new List<ExplorerItem>();

            foreach (var dataset in this.Schemas)
            {
                var root = new ExplorerItem(dataset.DatasetName, ExplorerItemKind.Category, ExplorerIcon.Box);

                // regularTable = 1, view = 2, tableRange = 3
                var lookup = dataset.GroupedMetaTableSchemas.ToLookup(x =>
                {
                    return (x.IsGrouped)
                        ? 3
                        : x.MetaTableSchemas.First().TableInfo.type;
                });

                // View/Table = this.From<T>()
                // Range = this.FromDateRange<T>()

                var tableRanges = new ExplorerItem("Ranges", ExplorerItemKind.Category, ExplorerIcon.Schema)
                {
                    Children = lookup[3].Select(g =>
                    {
                        var x = g.MetaTableSchemas.First();

                        var groupingChild = new ExplorerItem($"Tables ({g.MetaTableSchemas.Length})", ExplorerItemKind.Category, ExplorerIcon.Table)
                        {
                            Children = g.MetaTableSchemas.Select(y =>
                            {
                                var className = tableLookupDictionary.GetOrDefault(y)?.ClassName ?? y.ToClassName(false);

                                return new ExplorerItem(y.TableInfo.table_id, ExplorerItemKind.QueryableObject, ExplorerIcon.Table)
                                {
                                    DragText = $"From<{className}>()",
                                    ToolTipText = y.TableInfo.ToFullTableName(),
                                };
                            }).ToList()
                        };

                        var propertyList = new List<ExplorerItem> { groupingChild };
                        propertyList.AddRange(BuildColumnExplorerItems(x.Fields));

                        var classNameCheck = tableRangeLookupDictionary.GetOrDefault(x)?.ClassName ?? x.ToClassName(true);

                        var item = new ExplorerItem(g.ShortTablePrefix, ExplorerItemKind.QueryableObject, ExplorerIcon.Schema)
                        {
                            DragText = $"FromDateRange<{classNameCheck}>()",
                            ToolTipText = x.TableInfo.ToFullTableName(),
                            Children = propertyList
                        };
                        return item;
                    }).ToList()
                };

                var views = new ExplorerItem("Views", ExplorerItemKind.Category, ExplorerIcon.View)
                {
                    Children = lookup[2].Select(g =>
                    {
                        var x = g.MetaTableSchemas.First();
                        var className = tableLookupDictionary.GetOrDefault(x)?.ClassName ?? x.ToClassName(false);

                        var item = new ExplorerItem(x.TableInfo.table_id, ExplorerItemKind.QueryableObject, ExplorerIcon.View)
                        {
                            DragText = $"From<{className}>()",
                            ToolTipText = x.TableInfo.ToFullTableName(),
                            Children = BuildColumnExplorerItems(x.Fields)
                        };
                        return item;
                    }).ToList()
                };

                var tables = new ExplorerItem("Tables", ExplorerItemKind.Category, ExplorerIcon.Table)
                {
                    Children = lookup[1].Select(g =>
                    {
                        var x = g.MetaTableSchemas.First();
                        var className = tableLookupDictionary.GetOrDefault(x)?.ClassName ?? x.ToClassName(false);

                        var item = new ExplorerItem(x.TableInfo.table_id, ExplorerItemKind.QueryableObject, ExplorerIcon.Table)
                        {
                            DragText = $"From<{className}>()",
                            ToolTipText = x.TableInfo.ToFullTableName(),
                            Children = BuildColumnExplorerItems(x.Fields)
                        };
                        return item;
                    }).ToList()
                };

                // RangeTables

                root.Children = new List<ExplorerItem> { tableRanges, views, tables };
                list.Add(root);
            }

            return list;
        }