public AzureClientHolder(AzureSettings setting, Progress progress = null, [CallerMemberName] string caller = null) { Assert.False(string.IsNullOrEmpty(setting.StorageContainer), "string.IsNullOrEmpty(setting.StorageContainer)"); Settings = setting; // keep only alphanumeric characters Settings.RemoteFolderName = _remoteFolder = GetRemoteFolder(caller); Client = RavenAzureClient.Create(Settings, DefaultConfiguration, progress); }
private void DeleteFromAzure(AzureSettings settings) { using (var client = RavenAzureClient.Create(settings, _settings.Configuration, progress: null, TaskCancelToken.Token)) { var key = CombinePathAndKey(settings.RemoteFolderName); client.DeleteBlobs(new List <string> { key }); if (_logger.IsInfoEnabled) { _logger.Info($"{ReportDeletion(AzureName)} container: {settings.StorageContainer}, with key: {key}"); } } }
private void UploadToAzure(AzureSettings settings, Stream stream, Progress progress) { using (var client = RavenAzureClient.Create(settings, _settings.Configuration, progress, TaskCancelToken.Token)) { var key = CombinePathAndKey(settings.RemoteFolderName); client.PutBlob(key, stream, new Dictionary <string, string> { { "Description", GetArchiveDescription() } }); if (_logger.IsInfoEnabled) { _logger.Info($"{ReportSuccess(AzureName)} container: {settings.StorageContainer}, with key: {key}"); } var runner = new AzureRetentionPolicyRunner(_retentionPolicyParameters, client); runner.Execute(); } }
private static async Task DeleteObjects(AzureSettings azureSettings, string prefix, string delimiter, bool listFolder = false) { if (azureSettings == null) { return; } try { using (var client = RavenAzureClient.Create(azureSettings, DefaultBackupConfiguration)) { var result = await client.ListBlobsAsync(prefix, delimiter, listFolder); List <string> filesToDelete; if (listFolder == false) { filesToDelete = result.List.Select(b => b.Name).ToList(); } else { filesToDelete = await ListAllFilesInFolders(client, result.List); } if (filesToDelete.Count == 0) { return; } client.DeleteBlobs(filesToDelete); } } catch (Exception) { // ignored } }
public async Task GetFolderPathOptions() { PeriodicBackupConnectionType connectionType; var type = GetStringValuesQueryString("type", false).FirstOrDefault(); if (type == null) { //Backward compatibility connectionType = PeriodicBackupConnectionType.Local; } else if (Enum.TryParse(type, out connectionType) == false) { throw new ArgumentException($"Query string '{type}' was not recognized as valid type"); } using (ServerStore.ContextPool.AllocateOperationContext(out JsonOperationContext context)) { var folderPathOptions = new FolderPathOptions(); ; switch (connectionType) { case PeriodicBackupConnectionType.Local: var isBackupFolder = GetBoolValueQueryString("backupFolder", required: false) ?? false; var path = GetStringQueryString("path", required: false); folderPathOptions = FolderPath.GetOptions(path, isBackupFolder, ServerStore.Configuration); break; case PeriodicBackupConnectionType.S3: var json = await context.ReadForMemoryAsync(RequestBodyStream(), "studio-tasks/format"); if (connectionType != PeriodicBackupConnectionType.Local && json == null) { throw new BadRequestException("No JSON was posted."); } var s3Settings = JsonDeserializationServer.S3Settings(json); if (s3Settings == null) { throw new BadRequestException("No S3Settings were found."); } if (string.IsNullOrWhiteSpace(s3Settings.AwsAccessKey) || string.IsNullOrWhiteSpace(s3Settings.AwsSecretKey) || string.IsNullOrWhiteSpace(s3Settings.BucketName) || string.IsNullOrWhiteSpace(s3Settings.AwsRegionName)) { break; } using (var client = new RavenAwsS3Client(s3Settings, ServerStore.Configuration.Backup)) { // fetching only the first 64 results for the auto complete var folders = await client.ListObjectsAsync(s3Settings.RemoteFolderName, "/", true, take : 64); if (folders != null) { foreach (var folder in folders.FileInfoDetails) { var fullPath = folder.FullPath; if (string.IsNullOrWhiteSpace(fullPath)) { continue; } folderPathOptions.List.Add(fullPath); } } } break; case PeriodicBackupConnectionType.Azure: var azureJson = await context.ReadForMemoryAsync(RequestBodyStream(), "studio-tasks/format"); if (connectionType != PeriodicBackupConnectionType.Local && azureJson == null) { throw new BadRequestException("No JSON was posted."); } var azureSettings = JsonDeserializationServer.AzureSettings(azureJson); if (azureSettings == null) { throw new BadRequestException("No AzureSettings were found."); } if (string.IsNullOrWhiteSpace(azureSettings.AccountName) || string.IsNullOrWhiteSpace(azureSettings.AccountKey) || string.IsNullOrWhiteSpace(azureSettings.StorageContainer)) { break; } using (var client = RavenAzureClient.Create(azureSettings, ServerStore.Configuration.Backup)) { var folders = (await client.ListBlobsAsync(azureSettings.RemoteFolderName, "/", true)); foreach (var folder in folders.List) { var fullPath = folder.Name; if (string.IsNullOrWhiteSpace(fullPath)) { continue; } folderPathOptions.List.Add(fullPath); } } break; case PeriodicBackupConnectionType.GoogleCloud: var googleCloudJson = await context.ReadForMemoryAsync(RequestBodyStream(), "studio-tasks/format"); if (connectionType != PeriodicBackupConnectionType.Local && googleCloudJson == null) { throw new BadRequestException("No JSON was posted."); } var googleCloudSettings = JsonDeserializationServer.GoogleCloudSettings(googleCloudJson); if (googleCloudSettings == null) { throw new BadRequestException("No AzureSettings were found."); } if (string.IsNullOrWhiteSpace(googleCloudSettings.BucketName) || string.IsNullOrWhiteSpace(googleCloudSettings.GoogleCredentialsJson)) { break; } using (var client = new RavenGoogleCloudClient(googleCloudSettings, ServerStore.Configuration.Backup)) { var folders = (await client.ListObjectsAsync(googleCloudSettings.RemoteFolderName)); var requestedPathLength = googleCloudSettings.RemoteFolderName.Split('/').Length; foreach (var folder in folders) { const char separator = '/'; var splitted = folder.Name.Split(separator); var result = string.Join(separator, splitted.Take(requestedPathLength)) + separator; if (string.IsNullOrWhiteSpace(result)) { continue; } folderPathOptions.List.Add(result); } } break; case PeriodicBackupConnectionType.FTP: case PeriodicBackupConnectionType.Glacier: throw new NotSupportedException(); default: throw new ArgumentOutOfRangeException(); } await using (var writer = new AsyncBlittableJsonTextWriter(context, ResponseBodyStream())) { context.Write(writer, new DynamicJsonValue { [nameof(FolderPathOptions.List)] = TypeConverter.ToBlittableSupportedType(folderPathOptions.List) }); } } }
public async Task TestPeriodicBackupCredentials() { var type = GetQueryStringValueAndAssertIfSingleAndNotEmpty("type"); if (Enum.TryParse(type, out PeriodicBackupConnectionType connectionType) == false) { throw new ArgumentException($"Unknown backup connection: {type}"); } using (ServerStore.ContextPool.AllocateOperationContext(out TransactionOperationContext context)) { DynamicJsonValue result; try { var connectionInfo = await context.ReadForMemoryAsync(RequestBodyStream(), "test-connection"); switch (connectionType) { case PeriodicBackupConnectionType.S3: var s3Settings = JsonDeserializationClient.S3Settings(connectionInfo); using (var awsClient = new RavenAwsS3Client(s3Settings, ServerStore.Configuration.Backup, cancellationToken: ServerStore.ServerShutdown)) { awsClient.TestConnection(); } break; case PeriodicBackupConnectionType.Glacier: var glacierSettings = JsonDeserializationClient.GlacierSettings(connectionInfo); using (var glacierClient = new RavenAwsGlacierClient(glacierSettings, ServerStore.Configuration.Backup, cancellationToken: ServerStore.ServerShutdown)) { glacierClient.TestConnection(); } break; case PeriodicBackupConnectionType.Azure: var azureSettings = JsonDeserializationClient.AzureSettings(connectionInfo); using (var azureClient = RavenAzureClient.Create(azureSettings, ServerStore.Configuration.Backup, cancellationToken: ServerStore.ServerShutdown)) { azureClient.TestConnection(); } break; case PeriodicBackupConnectionType.GoogleCloud: var googleCloudSettings = JsonDeserializationClient.GoogleCloudSettings(connectionInfo); using (var googleCloudClient = new RavenGoogleCloudClient(googleCloudSettings, ServerStore.Configuration.Backup, cancellationToken: ServerStore.ServerShutdown)) { await googleCloudClient.TestConnection(); } break; case PeriodicBackupConnectionType.FTP: var ftpSettings = JsonDeserializationClient.FtpSettings(connectionInfo); using (var ftpClient = new RavenFtpClient(ftpSettings)) { ftpClient.TestConnection(); } break; case PeriodicBackupConnectionType.Local: case PeriodicBackupConnectionType.None: default: throw new ArgumentOutOfRangeException(); } result = new DynamicJsonValue { [nameof(NodeConnectionTestResult.Success)] = true, }; } catch (Exception e) { result = new DynamicJsonValue { [nameof(NodeConnectionTestResult.Success)] = false, [nameof(NodeConnectionTestResult.Error)] = e.ToString() }; } await using (var writer = new AsyncBlittableJsonTextWriter(context, ResponseBodyStream())) { context.Write(writer, result); } } }
public AzureRestorePoints(BackupConfiguration configuration, SortedList <DateTime, RestorePoint> sortedList, TransactionOperationContext context, AzureSettings azureSettings) : base(sortedList, context) { _client = RavenAzureClient.Create(azureSettings, configuration); }
public async Task CanUseCustomPrefix() { var settings = GetAzureSettings(); try { using (var store = GetDocumentStore()) { var baseline = new DateTime(2020, 1, 1); using (var session = store.OpenAsyncSession()) { for (int i = 0; i < 31; i++) { await session.StoreAsync(new Order { Id = $"orders/{i}", OrderedAt = baseline.AddDays(i), ShipVia = $"shippers/{i}", Company = $"companies/{i}" }); } for (int i = 0; i < 28; i++) { await session.StoreAsync(new Order { Id = $"orders/{i + 31}", OrderedAt = baseline.AddMonths(1).AddDays(i), ShipVia = $"shippers/{i + 31}", Company = $"companies/{i + 31}" }); } await session.SaveChangesAsync(); } var script = @" var orderDate = new Date(this.OrderedAt); var year = orderDate.getFullYear(); var month = orderDate.getMonth() + 1; loadToOrders(partitionBy(['year', year], ['month', month], ['source', $customPartitionValue]), { Company : this.Company, ShipVia : this.ShipVia }); "; const string customPartition = "shop-16"; var etlDone = WaitForEtl(store, (n, statistics) => statistics.LoadSuccesses != 0); SetupAzureEtl(store, script, settings, customPartition); etlDone.Wait(TimeSpan.FromMinutes(1)); using (var client = RavenAzureClient.Create(settings, DefaultBackupConfiguration)) { var prefix = $"{settings.RemoteFolderName}/{CollectionName}"; var cloudObjects = await client.ListBlobsAsync(prefix, delimiter : string.Empty, listFolders : false); var list = cloudObjects.List.ToList(); Assert.Equal(2, list.Count); Assert.Contains($"/Orders/year=2020/month=1/source={customPartition}/", list[0].Name); Assert.Contains($"/Orders/year=2020/month=2/source={customPartition}/", list[1].Name); } } } finally { await DeleteObjects(settings, prefix : $"{settings.RemoteFolderName}/{CollectionName}", delimiter : string.Empty); } }
public async Task SimpleTransformation_MultiplePartitions() { var settings = GetAzureSettings(); var prefix = $"{settings.RemoteFolderName}/{CollectionName}/"; try { using (var store = GetDocumentStore()) { var baseline = DateTime.SpecifyKind(new DateTime(2020, 1, 1), DateTimeKind.Utc); using (var session = store.OpenAsyncSession()) { const int total = 31 + 28; // days in January + days in February for (int i = 0; i < total; i++) { var orderedAt = baseline.AddDays(i); await session.StoreAsync(new Order { Id = $"orders/{i}", OrderedAt = orderedAt, RequireAt = orderedAt.AddDays(7), ShipVia = $"shippers/{i}", Company = $"companies/{i}" }); } for (int i = 1; i <= 37; i++) { var index = i + total; var orderedAt = baseline.AddYears(1).AddMonths(1).AddDays(i); await session.StoreAsync(new Order { Id = $"orders/{index}", OrderedAt = orderedAt, RequireAt = orderedAt.AddDays(7), ShipVia = $"shippers/{index}", Company = $"companies/{index}" }); } await session.SaveChangesAsync(); } var etlDone = WaitForEtl(store, (n, statistics) => statistics.LoadSuccesses != 0 && statistics.LoadErrors == 0); var script = @" var orderDate = new Date(this.OrderedAt); loadToOrders(partitionBy( ['year', orderDate.getFullYear()], ['month', orderDate.getMonth() + 1] ), { Company : this.Company, ShipVia : this.ShipVia, RequireAt : this.RequireAt }); "; SetupAzureEtl(store, script, settings); etlDone.Wait(TimeSpan.FromMinutes(1)); var expectedFields = new[] { "RequireAt", "ShipVia", "Company", ParquetTransformedItems.DefaultIdColumn, ParquetTransformedItems.LastModifiedColumn }; using (var client = RavenAzureClient.Create(settings, DefaultBackupConfiguration)) { var cloudObjects = await client.ListBlobsAsync(prefix, delimiter : "/", listFolders : true); var list = cloudObjects.List.ToList(); Assert.Equal(2, list.Count); Assert.Contains("Orders/year=2020/", list[0].Name); Assert.Contains("Orders/year=2021/", list[1].Name); for (var index = 1; index <= list.Count; index++) { var folder = list[index - 1]; var objectsInFolder = await client.ListBlobsAsync(prefix : folder.Name, delimiter : "/", listFolders : true); var objects = objectsInFolder.List.ToList(); Assert.Equal(2, objects.Count); Assert.Contains($"month={index}/", objects[0].Name); Assert.Contains($"month={index + 1}/", objects[1].Name); } var files = await ListAllFilesInFolders(client, list); Assert.Equal(4, files.Count); foreach (var filePath in files) { var blob = await client.GetBlobAsync(filePath); await using var ms = new MemoryStream(); blob.Data.CopyTo(ms); using (var parquetReader = new ParquetReader(ms)) { Assert.Equal(1, parquetReader.RowGroupCount); Assert.Equal(expectedFields.Length, parquetReader.Schema.Fields.Count); using var rowGroupReader = parquetReader.OpenRowGroupReader(0); foreach (var field in parquetReader.Schema.Fields) { Assert.True(field.Name.In(expectedFields)); var data = rowGroupReader.ReadColumn((DataField)field).Data; Assert.True(data.Length == 31 || data.Length == 28 || data.Length == 27 || data.Length == 10); if (field.Name != "RequireAt") { continue; } var count = data.Length switch { 31 => 0, 28 => 31, 27 => 365 + 33, 10 => 365 + 33 + 27, _ => throw new ArgumentOutOfRangeException() }; foreach (var val in data) { var expectedOrderDate = new DateTimeOffset(DateTime.SpecifyKind(baseline.AddDays(count++), DateTimeKind.Utc)); var expected = expectedOrderDate.AddDays(7); Assert.Equal(expected, val); } } } } } } } finally { await DeleteObjects(settings, prefix, delimiter : "/", listFolder : true); } }
public async Task SimpleTransformation_NoPartition() { var settings = GetAzureSettings(); try { using (var store = GetDocumentStore()) { var baseline = new DateTime(2020, 1, 1).ToUniversalTime(); using (var session = store.OpenAsyncSession()) { for (int i = 0; i < 100; i++) { await session.StoreAsync(new Order { Id = $"orders/{i}", OrderedAt = baseline.AddDays(i), ShipVia = $"shippers/{i}", Company = $"companies/{i}" }); } await session.SaveChangesAsync(); } var etlDone = WaitForEtl(store, (n, statistics) => statistics.LoadSuccesses != 0); var script = @" loadToOrders(noPartition(), { OrderDate : this.OrderedAt Company : this.Company, ShipVia : this.ShipVia }); "; SetupAzureEtl(store, script, settings); etlDone.Wait(TimeSpan.FromMinutes(1)); using (var client = RavenAzureClient.Create(settings, DefaultBackupConfiguration)) { var prefix = $"{settings.RemoteFolderName}/{CollectionName}"; var cloudObjects = await client.ListBlobsAsync(prefix, delimiter : string.Empty, listFolders : false); var list = cloudObjects.List.ToList(); Assert.Equal(1, list.Count); var blob = await client.GetBlobAsync(list[0].Name); await using var ms = new MemoryStream(); blob.Data.CopyTo(ms); using (var parquetReader = new ParquetReader(ms)) { Assert.Equal(1, parquetReader.RowGroupCount); var expectedFields = new[] { "OrderDate", "ShipVia", "Company", ParquetTransformedItems.DefaultIdColumn, ParquetTransformedItems.LastModifiedColumn }; Assert.Equal(expectedFields.Length, parquetReader.Schema.Fields.Count); using var rowGroupReader = parquetReader.OpenRowGroupReader(0); foreach (var field in parquetReader.Schema.Fields) { Assert.True(field.Name.In(expectedFields)); var data = rowGroupReader.ReadColumn((DataField)field).Data; Assert.True(data.Length == 100); if (field.Name == ParquetTransformedItems.LastModifiedColumn) { continue; } var count = 0; foreach (var val in data) { if (field.Name == "OrderDate") { var expectedDto = new DateTimeOffset(DateTime.SpecifyKind(baseline.AddDays(count), DateTimeKind.Utc)); Assert.Equal(expectedDto, val); } else { var expected = field.Name switch { ParquetTransformedItems.DefaultIdColumn => $"orders/{count}", "Company" => $"companies/{count}", "ShipVia" => $"shippers/{count}", _ => null }; Assert.Equal(expected, val); } count++; } } } } } } finally { await DeleteObjects(settings); } }
public async Task CanModifyPartitionColumnName() { var settings = GetAzureSettings(); try { using (var store = GetDocumentStore()) { const string partitionColumn = "order_date"; var baseline = new DateTime(2020, 1, 1); using (var session = store.OpenAsyncSession()) { for (int i = 0; i < 31; i++) { await session.StoreAsync(new Order { Id = $"orders/{i}", OrderedAt = baseline.AddDays(i), ShipVia = $"shippers/{i}", Company = $"companies/{i}" }); } for (int i = 0; i < 28; i++) { await session.StoreAsync(new Order { Id = $"orders/{i + 31}", OrderedAt = baseline.AddMonths(1).AddDays(i), ShipVia = $"shippers/{i + 31}", Company = $"companies/{i + 31}" }); } await session.SaveChangesAsync(); } var etlDone = WaitForEtl(store, (n, statistics) => statistics.LoadSuccesses != 0); var script = @" var orderDate = new Date(this.OrderedAt); var year = orderDate.getFullYear(); var month = orderDate.getMonth(); var key = new Date(year, month); loadToOrders(partitionBy(['order_date', key]), { Company : this.Company, ShipVia : this.ShipVia }) "; var connectionStringName = $"{store.Database} to Azure"; var configuration = new OlapEtlConfiguration { Name = "olap-azure-test", ConnectionStringName = connectionStringName, RunFrequency = LocalTests.DefaultFrequency, Transforms = { new Transformation { Name = "MonthlyOrders", Collections = new List <string>{ "Orders" }, Script = script } } }; SetupAzureEtl(store, settings, configuration); etlDone.Wait(TimeSpan.FromMinutes(1)); using (var client = RavenAzureClient.Create(settings, DefaultBackupConfiguration)) { var prefix = $"{settings.RemoteFolderName}/{CollectionName}"; var cloudObjects = await client.ListBlobsAsync(prefix, string.Empty, false); var list = cloudObjects.List.ToList(); Assert.Equal(2, list.Count); Assert.Contains($"{partitionColumn}=2020-01-01", list[0].Name); Assert.Contains($"{partitionColumn}=2020-02-01", list[1].Name); } } } finally { await DeleteObjects(settings); } }
public async Task CanUploadToAzure() { var settings = GetAzureSettings(); try { using (var store = GetDocumentStore()) { var baseline = new DateTime(2020, 1, 1); using (var session = store.OpenAsyncSession()) { for (int i = 0; i < 31; i++) { await session.StoreAsync(new Order { Id = $"orders/{i}", OrderedAt = baseline.AddDays(i), ShipVia = $"shippers/{i}", Company = $"companies/{i}" }); } for (int i = 0; i < 28; i++) { await session.StoreAsync(new Order { Id = $"orders/{i + 31}", OrderedAt = baseline.AddMonths(1).AddDays(i), ShipVia = $"shippers/{i + 31}", Company = $"companies/{i + 31}" }); } await session.SaveChangesAsync(); } var etlDone = WaitForEtl(store, (n, statistics) => statistics.LoadSuccesses != 0); var script = @" var orderDate = new Date(this.OrderedAt); var year = orderDate.getFullYear(); var month = orderDate.getMonth(); var key = new Date(year, month); loadToOrders(partitionBy(key), { Company : this.Company, ShipVia : this.ShipVia }) "; SetupAzureEtl(store, script, settings); etlDone.Wait(TimeSpan.FromMinutes(1)); using (var client = RavenAzureClient.Create(settings, DefaultBackupConfiguration)) { var prefix = $"{settings.RemoteFolderName}/{CollectionName}"; var result = await client.ListBlobsAsync(prefix, delimiter : string.Empty, listFolders : false); var list = result.List.ToList(); Assert.Equal(2, list.Count); Assert.Contains("2020-01-01", list[0].Name); Assert.Contains("2020-02-01", list[1].Name); } } } finally { await DeleteObjects(settings); } }
public async Task CanLoadToMultipleTables() { const string salesTableName = "Sales"; var settings = GetAzureSettings(); try { using (var store = GetDocumentStore()) { var baseline = new DateTime(2020, 1, 1); using (var session = store.OpenAsyncSession()) { for (int i = 0; i < 31; i++) { var orderedAt = baseline.AddDays(i); var lines = new List <OrderLine>(); for (int j = 1; j <= 5; j++) { lines.Add(new OrderLine { Quantity = j * 10, PricePerUnit = i + j, Product = $"Products/{j}" }); } var o = new Order { Id = $"orders/{i}", OrderedAt = orderedAt, RequireAt = orderedAt.AddDays(7), Company = $"companies/{i}", Lines = lines }; await session.StoreAsync(o); } baseline = baseline.AddMonths(1); for (int i = 0; i < 28; i++) { var orderedAt = baseline.AddDays(i); var lines = new List <OrderLine>(); for (int j = 1; j <= 5; j++) { lines.Add(new OrderLine { Quantity = j * 10, PricePerUnit = i + j, Product = $"Products/{j}" }); } var o = new Order { Id = $"orders/{i + 31}", OrderedAt = orderedAt, RequireAt = orderedAt.AddDays(7), Company = $"companies/{i}", Lines = lines }; await session.StoreAsync(o); } await session.SaveChangesAsync(); } var etlDone = WaitForEtl(store, (n, statistics) => statistics.LoadSuccesses != 0); var script = @" var orderData = { Company : this.Company, RequireAt : new Date(this.RequireAt), ItemsCount: this.Lines.length, TotalCost: 0 }; var orderDate = new Date(this.OrderedAt); var year = orderDate.getFullYear(); var month = orderDate.getMonth(); var key = new Date(year, month); for (var i = 0; i < this.Lines.length; i++) { var line = this.Lines[i]; orderData.TotalCost += (line.PricePerUnit * line.Quantity); // load to 'sales' table loadToSales(partitionBy(key), { Qty: line.Quantity, Product: line.Product, Cost: line.PricePerUnit }); } // load to 'orders' table loadToOrders(partitionBy(key), orderData); "; SetupAzureEtl(store, script, settings); etlDone.Wait(TimeSpan.FromMinutes(1)); using (var client = RavenAzureClient.Create(settings, DefaultBackupConfiguration)) { var prefix = $"{settings.RemoteFolderName}/{CollectionName}"; var result = await client.ListBlobsAsync(prefix, delimiter : string.Empty, listFolders : false); var list = result.List.ToList(); Assert.Equal(2, list.Count); Assert.Contains("2020-01-01", list[0].Name); Assert.Contains("2020-02-01", list[1].Name); var blob = await client.GetBlobAsync(list[0].Name); await using var ms = new MemoryStream(); blob.Data.CopyTo(ms); using (var parquetReader = new ParquetReader(ms)) { Assert.Equal(1, parquetReader.RowGroupCount); var expectedFields = new[] { "Company", "RequireAt", "ItemsCount", "TotalCost", ParquetTransformedItems.DefaultIdColumn, ParquetTransformedItems.LastModifiedColumn }; Assert.Equal(expectedFields.Length, parquetReader.Schema.Fields.Count); using var rowGroupReader = parquetReader.OpenRowGroupReader(0); foreach (var field in parquetReader.Schema.Fields) { Assert.True(field.Name.In(expectedFields)); var data = rowGroupReader.ReadColumn((DataField)field).Data; Assert.True(data.Length == 31); } } } //sales using (var client = RavenAzureClient.Create(settings, DefaultBackupConfiguration)) { var prefix = $"{settings.RemoteFolderName}/{salesTableName}"; var result = await client.ListBlobsAsync(prefix, delimiter : string.Empty, listFolders : false); var list = result.List.ToList(); Assert.Equal(2, list.Count); Assert.Contains("2020-01-01", list[0].Name); Assert.Contains("2020-02-01", list[1].Name); var blob = await client.GetBlobAsync(list[1].Name); await using var ms = new MemoryStream(); blob.Data.CopyTo(ms); using (var parquetReader = new ParquetReader(ms)) { Assert.Equal(1, parquetReader.RowGroupCount); var expectedFields = new[] { "Qty", "Product", "Cost", ParquetTransformedItems.DefaultIdColumn, ParquetTransformedItems.LastModifiedColumn }; Assert.Equal(expectedFields.Length, parquetReader.Schema.Fields.Count); using var rowGroupReader = parquetReader.OpenRowGroupReader(0); foreach (var field in parquetReader.Schema.Fields) { Assert.True(field.Name.In(expectedFields)); var data = rowGroupReader.ReadColumn((DataField)field).Data; Assert.True(data.Length == 28 * 5); } } } } } finally { await DeleteObjects(settings, salesTableName); } }
public async Task SimpleTransformation() { var settings = GetAzureSettings(); try { using (var store = GetDocumentStore()) { var baseline = new DateTime(2020, 1, 1); using (var session = store.OpenAsyncSession()) { for (int i = 1; i <= 10; i++) { var o = new Order { Id = $"orders/{i}", OrderedAt = baseline.AddDays(i), Company = $"companies/{i}", ShipVia = $"shippers/{i}" }; await session.StoreAsync(o); } await session.SaveChangesAsync(); } var etlDone = WaitForEtl(store, (n, statistics) => statistics.LoadSuccesses != 0); var script = @" var orderDate = new Date(this.OrderedAt); var year = orderDate.getFullYear(); var month = orderDate.getMonth(); var key = new Date(year, month); loadToOrders(partitionBy(key), { Company : this.Company, ShipVia : this.ShipVia }) "; SetupAzureEtl(store, script, settings); etlDone.Wait(TimeSpan.FromMinutes(1)); using (var client = RavenAzureClient.Create(settings, DefaultBackupConfiguration)) { var prefix = $"{settings.RemoteFolderName}/{CollectionName}"; var result = await client.ListBlobsAsync(prefix, delimiter : string.Empty, listFolders : false); var list = result.List.ToList(); Assert.Equal(1, list.Count); var blob = await client.GetBlobAsync(list[0].Name); await using var ms = new MemoryStream(); blob.Data.CopyTo(ms); using (var parquetReader = new ParquetReader(ms)) { Assert.Equal(1, parquetReader.RowGroupCount); var expectedFields = new[] { "Company", "ShipVia", ParquetTransformedItems.DefaultIdColumn, ParquetTransformedItems.LastModifiedColumn }; Assert.Equal(expectedFields.Length, parquetReader.Schema.Fields.Count); using var rowGroupReader = parquetReader.OpenRowGroupReader(0); foreach (var field in parquetReader.Schema.Fields) { Assert.True(field.Name.In(expectedFields)); var data = rowGroupReader.ReadColumn((DataField)field).Data; Assert.True(data.Length == 10); if (field.Name == ParquetTransformedItems.LastModifiedColumn) { continue; } var count = 1; foreach (var val in data) { switch (field.Name) { case ParquetTransformedItems.DefaultIdColumn: Assert.Equal($"orders/{count}", val); break; case "Company": Assert.Equal($"companies/{count}", val); break; case "ShipVia": Assert.Equal($"shippers/{count}", val); break; } count++; } } } } } } finally { await DeleteObjects(settings); } }
public RestoreFromAzure(ServerStore serverStore, RestoreFromAzureConfiguration restoreFromConfiguration, string nodeTag, OperationCancelToken operationCancelToken) : base(serverStore, restoreFromConfiguration, nodeTag, operationCancelToken) { _client = RavenAzureClient.Create(restoreFromConfiguration.Settings, serverStore.Configuration.Backup); _remoteFolderName = restoreFromConfiguration.Settings.RemoteFolderName; }