Wrapper to expose typed properties over ConnectionInfo.DriverData.
        /// <summary>
        /// Build a model of the current Azure storage account. This model will be used to generate
        /// the typed code as well as the schema needed by LINQPad.
        /// </summary>
        /// <param name="properties">The current configuration.</param>
        /// <returns>A list of <see cref="CloudTable"/> instances that describe the current Azure
        /// storage model.</returns>
        private static IEnumerable <CloudTable> GetModel(StorageAccountProperties properties)
        {
            // make sure that we can make at least ModelLoadMaxParallelism concurrent
            // cals to azure table storage
            ServicePointManager.DefaultConnectionLimit = properties.ModelLoadMaxParallelism;

            var tableClient = properties.GetStorageAccount().CreateCloudTableClient();

            // First get a list of all tables
            var model = (from tableName in tableClient.ListTables()
                         select new CloudTable
            {
                Name = tableName.Name
            }).ToList();

            var options = new ParallelOptions()
            {
                MaxDegreeOfParallelism = properties.ModelLoadMaxParallelism
            };

            Parallel.ForEach(model, options, table =>
            {
                var threadTableClient = properties.GetStorageAccount().CreateCloudTableClient();

                var tableColumns = threadTableClient.GetTableReference(table.Name).ExecuteQuery(new TableQuery().Take(properties.NumberOfRows))
                                   .SelectMany(row => row.Properties)
                                   .GroupBy(column => column.Key)
                                   .Select(grp => new TableColumn
                {
                    Name     = grp.Key,
                    TypeName = GetType(grp.First().Value.PropertyType)
                });

                var baseColumns = new List <TableColumn>
                {
                    new TableColumn {
                        Name = "PartitionKey", TypeName = GetType(EdmType.String)
                    },
                    new TableColumn {
                        Name = "RowKey", TypeName = GetType(EdmType.String)
                    },
                    new TableColumn {
                        Name = "Timestamp", TypeName = GetType(EdmType.DateTime)
                    },
                    new TableColumn {
                        Name = "ETag", TypeName = GetType(EdmType.String)
                    }
                };

                table.Columns = tableColumns.Concat(baseColumns).ToArray();
            });

            return(model);
        }
        /// <summary>
        /// Build a model of the current Azure storage account. This model will be used to generate
        /// the typed code as well as the schema needed by LINQPad.
        /// </summary>
        /// <param name="properties">The current configuration.</param>
        /// <returns>A list of <see cref="CloudTable"/> instances that describe the current Azure
        /// storage model.</returns>
        private static IEnumerable <CloudTable> GetModel(StorageAccountProperties properties)
        {
            var tableClient = properties.GetStorageAccount().CreateCloudTableClient();

            var dataContext = tableClient.GetDataServiceContext();

            // Entity deserialization has to be handled in a particular way since we are using a GenericEntity to
            // to read all tables
            dataContext.ReadingEntity += OnReadingEntity;

            // First get a list of all tables
            var model = (from tableName in tableClient.ListTables()
                         select new CloudTable
            {
                Name = tableName
            }).ToList();

            // Then go through them
            foreach (var table in model)
            {
                // Read the first entity to determine the table's schema
                var firstRow = dataContext.CreateQuery <GenericEntity>(table.Name).Take(1).FirstOrDefault();

                if (null == firstRow)
                {
                    // If there is no first entity, set a list with the mandatory PartitionKey, RowKey and
                    // Timestamp columns, which we know always exist
                    table.Columns = new[]
                    {
                        new TableColumn {
                            Name = "PartitionKey", TypeName = GetType("Edm.String")
                        },
                        new TableColumn {
                            Name = "RowKey", TypeName = GetType("Edm.String")
                        },
                        new TableColumn {
                            Name = "Timestamp", TypeName = GetType("Edm.DateTime")
                        }
                    };
                }
                else
                {
                    // Otherwise create a new TableColumn for each type
                    table.Columns = from columnName in firstRow.Properties
                                    select new TableColumn
                    {
                        Name     = columnName.Key,
                        TypeName = GetType(columnName.Value)
                    };
                }
            }

            return(model);
        }
Example #3
0
        /// <summary>
        /// Gets the context constructor arguments.
        /// </summary>
        /// <param name="connectionInfo">The connection info.</param>
        /// <returns>An ordered collection of objects to pass to the data context as arguments.</returns>
        public override object[] GetContextConstructorArguments(IConnectionInfo connectionInfo)
        {
            var properties = new StorageAccountProperties(connectionInfo);

            var storageAccount = properties.GetStorageAccount();

            return(new object[]
            {
                storageAccount.CreateCloudTableClient()
            });
        }
Example #4
0
        /// <summary>
        /// Shows the connection dialog.
        /// </summary>
        /// <param name="connectionInfo">The connection info.</param>
        /// <param name="isNewConnection">if set to <c>true</c> [is new connection].</param>
        /// <returns></returns>
        public override bool ShowConnectionDialog(IConnectionInfo connectionInfo, bool isNewConnection)
        {
            if (isNewConnection)
            {
                var prop = new StorageAccountProperties(connectionInfo);
                prop.UseHttps     = true;
                prop.NumberOfRows = 100;
            }

            bool?result = new ConnectionDialog(connectionInfo).ShowDialog();

            return(result == true);
        }
Example #5
0
        /// <summary>Gets the text to display in the root Schema Explorer node for a given connection info.</summary>
        /// <param name="cxInfo">The connection information.</param>
        /// <returns>The text to display in the root Schema Explorer node for a given connection info</returns>
        public override string GetConnectionDescription(IConnectionInfo cxInfo)
        {
            var accountProperties = new StorageAccountProperties(cxInfo);

            var description = accountProperties.DisplayName;

            if (accountProperties.AzureEnvironment != AzureEnvironment.AzureGlobalCloud)
            {
                description += $" ({accountProperties.AzureEnvironment.Name})";
            }

            return(description);
        }
        /// <summary>
        /// Gets the context constructor arguments.
        /// </summary>
        /// <param name="connectionInfo">The connection info.</param>
        /// <returns>An ordered collection of objects to pass to the data context as arguments.</returns>
        public override object[] GetContextConstructorArguments(IConnectionInfo connectionInfo)
        {
            var properties = new StorageAccountProperties(connectionInfo);

            var storageAccount = properties.GetStorageAccount();

            return(new object[]
            {
                storageAccount.TableEndpoint.ToString(),
                storageAccount.Credentials,
                storageAccount
            });
        }
Example #7
0
        /// <summary>
        /// Shows the connection dialog.
        /// </summary>
        /// <param name="connectionInfo">The connection info.</param>
        /// <param name="isNewConnection">if set to <c>true</c> [is new connection].</param>
        /// <returns></returns>
        public override bool ShowConnectionDialog(IConnectionInfo cxInfo, ConnectionDialogOptions dialogOptions)
        {
            if (dialogOptions.IsNewConnection)
            {
                _ = new StorageAccountProperties(cxInfo)
                {
                    UseHttps     = true,
                    NumberOfRows = 100
                };
            }

            bool?result = new ConnectionDialog(cxInfo).ShowDialog();

            return(result == true);
        }
        /// <summary>
        /// Gets the schema and builds the assembly.
        /// </summary>
        /// <param name="properties">The current configuration.</param>
        /// <param name="name">The <see cref="AssemblyName"/> instace of the assembly being created.</param>
        /// <param name="namepace">The namespace to be used in the generated code.</param>
        /// <param name="typeName">Name of the type of the typed data context.</param>
        /// <returns>A list of <see cref="ExplorerItem"/> instaces that describes the current schema.</returns>
        public static List <ExplorerItem> GetSchemaAndBuildAssembly(StorageAccountProperties properties, AssemblyName name, string @namepace, string typeName)
        {
            // Get the model from Azure storage
            var model = GetModel(properties);

            // Generate C# code
            var code = GenerateCode(typeName, @namepace, model);

            // And compile the code into the assembly
            BuildAssembly(name, code);

            // Generate the schema for LINQPad
            List <ExplorerItem> schema = GetSchema(model);

            return(schema);
        }
        /// <summary>
        /// Gets the schema and builds the assembly.
        /// </summary>
        /// <param name="properties">The current configuration.</param>
        /// <param name="driverFolder">The driver folder. Used to resolve dependencies.</param>
        /// <param name="name">The <see cref="AssemblyName"/> instace of the assembly being created.</param>
        /// <param name="namepace">The namespace to be used in the generated code.</param>
        /// <param name="typeName">Name of the type of the typed data context.</param>
        /// <returns>A list of <see cref="ExplorerItem"/> instaces that describes the current schema.</returns>
        public static List<ExplorerItem> GetSchemaAndBuildAssembly(StorageAccountProperties properties, string driverFolder, AssemblyName name, string @namepace, string typeName)
        {
            // Get the model from Azure storage
            var model = GetModel(properties);

            // Generate C# code
            var code = GenerateCode(typeName, @namepace, model);

            // And compile the code into the assembly
            BuildAssembly(name, driverFolder, code);

            // Generate the schema for LINQPad
            List<ExplorerItem> schema = GetSchema(model);

            return schema;
        }
Example #10
0
        /// <summary>
        /// Build a model of the current Azure storage account. This model will be used to generate
        /// the typed code as well as the schema needed by LINQPad.
        /// </summary>
        /// <param name="properties">The current configuration.</param>
        /// <returns>A list of <see cref="CloudTable"/> instances that describe the current Azure
        /// storage model.</returns>
        private static IEnumerable <CloudTable> GetModel(StorageAccountProperties properties)
        {
            var tableClient = properties.GetStorageAccount().CreateCloudTableClient();

            // First get a list of all tables
            var model = (from tableName in tableClient.ListTables()
                         select new CloudTable
            {
                Name = tableName.Name
            }).ToList();

            // Then go through them
            foreach (var table in model)
            {
                var tableColumns = tableClient.GetTableReference(table.Name).ExecuteQuery(new TableQuery().Take(properties.NumberOfRows))
                                   .SelectMany(row => row.Properties)
                                   .GroupBy(column => column.Key)
                                   .Select(grp => new TableColumn
                {
                    Name     = grp.Key,
                    TypeName = GetType(grp.First().Value.PropertyType)
                });

                var baseColumns = new List <TableColumn>
                {
                    new TableColumn {
                        Name = "PartitionKey", TypeName = GetType(EdmType.String)
                    },
                    new TableColumn {
                        Name = "RowKey", TypeName = GetType(EdmType.String)
                    },
                    new TableColumn {
                        Name = "Timestamp", TypeName = GetType(EdmType.DateTime)
                    },
                    new TableColumn {
                        Name = "ETag", TypeName = GetType(EdmType.String)
                    }
                };

                table.Columns = tableColumns.Concat(baseColumns).ToArray();
            }

            return(model);
        }
Example #11
0
        /// <summary>
        /// Gets the context constructor arguments.
        /// </summary>
        /// <param name="connectionInfo">The connection info.</param>
        /// <returns>An ordered collection of objects to pass to the data context as arguments.</returns>
        public override object[] GetContextConstructorArguments(IConnectionInfo connectionInfo)
        {
            var properties = new StorageAccountProperties(connectionInfo);

            var storageAccount = properties.GetStorageAccount();

            return new object[]
            {
                storageAccount.CreateCloudTableClient()
            };
        }
        /// <summary>
        /// Gets the context constructor arguments.
        /// </summary>
        /// <param name="connectionInfo">The connection info.</param>
        /// <returns>An ordered collection of objects to pass to the data context as arguments.</returns>
        public override object[] GetContextConstructorArguments(IConnectionInfo connectionInfo)
        {
            var properties = new StorageAccountProperties(connectionInfo);

            var storageAccount = properties.GetStorageAccount();

            return new object[]
            {
                storageAccount.TableEndpoint.ToString(),
                storageAccount.Credentials,
                storageAccount
            };
        }
        /// <summary>
        /// Build a model of the current Azure storage account. This model will be used to generate
        /// the typed code as well as the schema needed by LINQPad.
        /// </summary>
        /// <param name="properties">The current configuration.</param>
        /// <returns>A list of <see cref="CloudTable"/> instances that describe the current Azure
        /// storage model.</returns>
        private static IEnumerable<CloudTable> GetModel(StorageAccountProperties properties)
        {
            var tableClient = properties.GetStorageAccount().CreateCloudTableClient();

            var dataContext = tableClient.GetDataServiceContext();

            // Entity deserialization has to be handled in a particular way since we are using a GenericEntity to
            // to read all tables
            dataContext.ReadingEntity += OnReadingEntity;

            // First get a list of all tables
            var model = (from tableName in tableClient.ListTables()
                         select new CloudTable
                         {
                             Name = tableName
                         }).ToList();

            // Then go through them
            foreach (var table in model)
            {
                // Read the first entity to determine the table's schema
                var firstRow = dataContext.CreateQuery<GenericEntity>(table.Name).Take(1).FirstOrDefault();

                if (null == firstRow)
                {
                    // If there is no first entity, set a list with the mandatory PartitionKey, RowKey and
                    // Timestamp columns, which we know always exist
                    table.Columns = new[]
                    {
                        new TableColumn { Name = "PartitionKey", TypeName = GetType("Edm.String") },
                        new TableColumn { Name = "RowKey", TypeName = GetType("Edm.String") },
                        new TableColumn { Name = "Timestamp", TypeName = GetType("Edm.DateTime") }
                    };
                }
                else
                {
                    // Otherwise create a new TableColumn for each type
                    table.Columns = from columnName in firstRow.Properties
                                    select new TableColumn
                                    {
                                        Name = columnName.Key,
                                        TypeName = GetType(columnName.Value)
                                    };
                }
            }

            return model;
        }
Example #14
0
        /// <summary>
        /// Build a model of the current Azure storage account. This model will be used to generate
        /// the typed code as well as the schema needed by LINQPad.
        /// </summary>
        /// <param name="properties">The current configuration.</param>
        /// <returns>A list of <see cref="CloudTable"/> instances that describe the current Azure
        /// storage model.</returns>
        private static IEnumerable<CloudTable> GetModel(StorageAccountProperties properties)
        {
            var tableClient = properties.GetStorageAccount().CreateCloudTableClient();

            // First get a list of all tables
            var model = (from tableName in tableClient.ListTables()
                         select new CloudTable
                         {
                             Name = tableName.Name
                         }).ToList();

            // Then go through them
            foreach (var table in model)
            {
                var tableColumns = tableClient.GetTableReference(table.Name).ExecuteQuery(new TableQuery().Take(properties.NumberOfRows))
                    .SelectMany(row => row.Properties)
                    .GroupBy(column => column.Key)
                    .Select(grp => new TableColumn
                     {
                         Name = grp.Key,
                         TypeName = GetType(grp.First().Value.PropertyType)
                     });

                var baseColumns = new List<TableColumn>
                {
                    new TableColumn { Name = "PartitionKey", TypeName = GetType(EdmType.String) },
                    new TableColumn { Name = "RowKey", TypeName = GetType(EdmType.String) },
                    new TableColumn { Name = "Timestamp", TypeName = GetType(EdmType.DateTime) },
                    new TableColumn { Name = "ETag", TypeName = GetType(EdmType.String) }
                };

                table.Columns = tableColumns.Concat(baseColumns).ToArray();
            }

            return model;
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="ConnectionDialog"/> class.
        /// </summary>
        /// <param name="connectionInfo">The connection info.</param>
        public ConnectionDialog(IConnectionInfo connectionInfo)
        {
            InitializeComponent();

            DataContext = new StorageAccountProperties(connectionInfo);
        }
Example #16
0
        /// <summary>
        /// Shows the connection dialog.
        /// </summary>
        /// <param name="connectionInfo">The connection info.</param>
        /// <param name="isNewConnection">if set to <c>true</c> [is new connection].</param>
        /// <returns></returns>
        public override bool ShowConnectionDialog(IConnectionInfo connectionInfo, bool isNewConnection)
        {
            if (isNewConnection)
            {
                var prop = new StorageAccountProperties(connectionInfo);
                prop.UseHttps = true;
                prop.NumberOfRows = 100;
            }

            bool? result = new ConnectionDialog(connectionInfo).ShowDialog();
            return result == true;
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="ConnectionDialog"/> class.
        /// </summary>
        /// <param name="connectionInfo">The connection info.</param>
        public ConnectionDialog(IConnectionInfo connectionInfo)
        {
            InitializeComponent();

            DataContext = new StorageAccountProperties(connectionInfo);
        }