public async void SaveResultsAsCsvExceptionTest() { // Execute a query var workspaceService = Common.GetPrimedWorkspaceService(Common.StandardQuery); var queryService = Common.GetPrimedExecutionService(new[] { Common.StandardTestData }, true, false, workspaceService); var executeParams = new QueryExecuteParams { QuerySelection = Common.WholeDocument, OwnerUri = Common.OwnerUri }; var executeRequest = RequestContextMocks.Create <QueryExecuteResult>(null); await Common.AwaitExecution(queryService, executeParams, executeRequest.Object); // Request to save the results as csv with incorrect filepath var saveParams = new SaveResultsAsCsvRequestParams { OwnerUri = Common.OwnerUri, ResultSetIndex = 0, BatchIndex = 0, FilePath = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "G:\\test.csv" : "/test.csv" }; SaveResultRequestError errMessage = null; var saveRequest = GetSaveResultsContextMock(null, err => errMessage = (SaveResultRequestError)err); // Call save results and wait on the save task await queryService.HandleSaveResultsAsCsvRequest(saveParams, saveRequest.Object); ResultSet selectedResultSet = queryService.ActiveQueries[saveParams.OwnerUri].Batches[saveParams.BatchIndex].ResultSets[saveParams.ResultSetIndex]; await selectedResultSet.GetSaveTask(saveParams.FilePath); // Expect to see error message VerifySaveResultsCallCount(saveRequest, Times.Never(), Times.Once()); Assert.NotNull(errMessage); Assert.False(File.Exists(saveParams.FilePath)); }
public async Task SaveResultsCsvNonExistentQuery() { // Given: A working query and workspace service WorkspaceService <SqlToolsSettings> ws = Common.GetPrimedWorkspaceService(null); QueryExecutionService qes = Common.GetPrimedExecutionService(null, false, false, ws); // If: I attempt to save a result set from a query that doesn't exist SaveResultsAsCsvRequestParams saveParams = new SaveResultsAsCsvRequestParams { OwnerUri = Common.OwnerUri // Won't exist because nothing has executed }; object error = null; var requestContext = RequestContextMocks.Create <SaveResultRequestResult>(null) .AddErrorHandling(o => error = o); await qes.HandleSaveResultsAsCsvRequest(saveParams, requestContext.Object); // Then: // ... An error event should have been fired // ... No success event should have been fired VerifyResponseCalls(requestContext, false, true); Assert.IsType <SaveResultRequestError>(error); Assert.NotNull(error); Assert.NotNull(((SaveResultRequestError)error).message); }
public void WriteRowWithCustomDelimiters() { // Setup: // ... Create a request params that has custom delimiter say pipe("|") then this delimiter should be used // ... Create a set of data to write // ... Create a memory location to store the data var requestParams = new SaveResultsAsCsvRequestParams { Delimiter = "|", IncludeHeaders = true }; List <DbCellValue> data = new List <DbCellValue> { new DbCellValue { DisplayValue = "item1" }, new DbCellValue { DisplayValue = "item2" } }; List <DbColumnWrapper> columns = new List <DbColumnWrapper> { new DbColumnWrapper(new TestDbColumn("column1")), new DbColumnWrapper(new TestDbColumn("column2")) }; byte[] output = new byte[8192]; // If: I write a row SaveAsCsvFileStreamWriter writer = new SaveAsCsvFileStreamWriter(new MemoryStream(output), requestParams); using (writer) { writer.WriteRow(data, columns); } // Then: // ... It should have written two lines string outputString = Encoding.UTF8.GetString(output).TrimEnd('\0', '\r', '\n'); string[] lines = outputString.Split(new[] { Environment.NewLine }, StringSplitOptions.None); Assert.Equal(2, lines.Length); // ... It should have written a header line with two, pipe("|") separated names string[] headerValues = lines[0].Split('|'); Assert.Equal(2, headerValues.Length); for (int i = 0; i < columns.Count; i++) { Assert.Equal(columns[i].ColumnName, headerValues[i]); } // Note: No need to check values, it is done as part of the previous tests }
/// <summary> /// Process request to save a resultSet to a file in CSV format /// </summary> internal async Task HandleSaveResultsAsCsvRequest(SaveResultsAsCsvRequestParams saveParams, RequestContext <SaveResultRequestResult> requestContext) { // Use the default CSV file factory if we haven't overridden it IFileStreamFactory csvFactory = CsvFileFactory ?? new SaveAsCsvFileStreamFactory { SaveRequestParams = saveParams, QueryExecutionSettings = Settings.QueryExecutionSettings }; await SaveResultsHelper(saveParams, requestContext, csvFactory); }
public void WriteRowWithCustomTextIdentifier() { // Setup: // ... Create a request params that has a text identifier set say single quotation marks("'") then this text identifier should be used // ... Create a set of data to write // ... Create a memory location to store the data var requestParams = new SaveResultsAsCsvRequestParams() { TextIdentifier = "\'", Delimiter = ";" }; List <DbCellValue> data = new List <DbCellValue> { new DbCellValue { DisplayValue = "item;1" }, new DbCellValue { DisplayValue = "item,2" }, new DbCellValue { DisplayValue = "item\"3" }, new DbCellValue { DisplayValue = "item\'4" } }; List <DbColumnWrapper> columns = new List <DbColumnWrapper> { new DbColumnWrapper(new TestDbColumn("column1")), new DbColumnWrapper(new TestDbColumn("column2")), new DbColumnWrapper(new TestDbColumn("column3")), new DbColumnWrapper(new TestDbColumn("column4")) }; byte[] output = new byte[8192]; // If: I write a row SaveAsCsvFileStreamWriter writer = new SaveAsCsvFileStreamWriter(new MemoryStream(output), requestParams); using (writer) { writer.WriteRow(data, columns); } // Then: // ... It should have splitten the columns by delimiter, embedded in text identifier when field contains delimiter or the text identifier string outputString = Encoding.UTF8.GetString(output).TrimEnd('\0', '\r', '\n'); Assert.Equal("\'item;1\';item,2;item\"3;\'item\'\'4\'", outputString); }
/// <summary> /// Request to save query results as CSV /// </summary> public async Task <SaveResultRequestResult> SaveAsCsv(string ownerUri, string filename, int batchIndex, int resultSetIndex) { var saveParams = new SaveResultsAsCsvRequestParams { OwnerUri = ownerUri, BatchIndex = batchIndex, ResultSetIndex = resultSetIndex, FilePath = filename }; var result = await Driver.SendRequest(SaveResultsAsCsvRequest.Type, saveParams); return(result); }
public async Task SaveResultAsCsvFailure() { // Given: // ... A working query and workspace service WorkspaceService <SqlToolsSettings> ws = Common.GetPrimedWorkspaceService(Common.StandardQuery); Dictionary <string, byte[]> storage; QueryExecutionService qes = Common.GetPrimedExecutionService(Common.ExecutionPlanTestDataSet, true, false, ws, out storage); // ... The query execution service has executed a query with results var executeParams = new ExecuteDocumentSelectionParams { QuerySelection = null, OwnerUri = Common.OwnerUri }; var executeRequest = RequestContextMocks.Create <ExecuteRequestResult>(null); await qes.HandleExecuteRequest(executeParams, executeRequest.Object); await qes.ActiveQueries[Common.OwnerUri].ExecutionTask; // If: I attempt to save a result set and get it to throw because of invalid column selection SaveResultsAsCsvRequestParams saveParams = new SaveResultsAsCsvRequestParams { BatchIndex = 0, FilePath = "qqq", OwnerUri = Common.OwnerUri, ResultSetIndex = 0, ColumnStartIndex = -1, ColumnEndIndex = 100, RowStartIndex = 0, RowEndIndex = 5 }; qes.CsvFileFactory = GetCsvStreamFactory(storage, saveParams); object error = null; var requestContext = RequestContextMocks.Create <SaveResultRequestResult>(null) .AddErrorHandling(e => error = e); await qes.HandleSaveResultsAsCsvRequest(saveParams, requestContext.Object); await qes.ActiveQueries[saveParams.OwnerUri] .Batches[saveParams.BatchIndex] .ResultSets[saveParams.ResultSetIndex] .SaveTasks[saveParams.FilePath]; // Then: // ... An error event should have been fired // ... No success event should have been fired VerifyResponseCalls(requestContext, false, true); Assert.IsType <SaveResultRequestError>(error); Assert.NotNull(error); Assert.NotNull(((SaveResultRequestError)error).message); }
public async void SaveResultsAsCsvWithSelectionSuccessTest() { // Execute a query var queryService = await Common.GetPrimedExecutionService(Common.CreateMockFactory(null, false), true, Common.GetPrimedWorkspaceService()); var executeParams = new QueryExecuteParams { QuerySelection = Common.WholeDocument, OwnerUri = Common.OwnerUri }; var executeRequest = RequestContextMocks.Create <QueryExecuteResult>(null); await queryService.HandleExecuteRequest(executeParams, executeRequest.Object); await queryService.ActiveQueries[Common.OwnerUri].ExecutionTask; // Request to save the results as csv with correct parameters var saveParams = new SaveResultsAsCsvRequestParams { OwnerUri = Common.OwnerUri, ResultSetIndex = 0, BatchIndex = 0, FilePath = "testwrite_2.csv", IncludeHeaders = true, RowStartIndex = 0, RowEndIndex = 0, ColumnStartIndex = 0, ColumnEndIndex = 0 }; SaveResultRequestResult result = null; var saveRequest = GetSaveResultsContextMock(qcr => result = qcr, null); queryService.ActiveQueries[Common.OwnerUri].Batches[0] = Common.GetBasicExecutedBatch(); // Call save results and wait on the save task await queryService.HandleSaveResultsAsCsvRequest(saveParams, saveRequest.Object); ResultSet selectedResultSet = queryService.ActiveQueries[saveParams.OwnerUri].Batches[saveParams.BatchIndex].ResultSets[saveParams.ResultSetIndex]; Task saveTask = selectedResultSet.GetSaveTask(saveParams.FilePath); await saveTask; // Expect to see a file successfully created in filepath and a success message Assert.Null(result.Messages); Assert.True(File.Exists(saveParams.FilePath)); VerifySaveResultsCallCount(saveRequest, Times.Once(), Times.Never()); // Delete temp file after test if (File.Exists(saveParams.FilePath)) { File.Delete(saveParams.FilePath); } }
public async Task SaveResultsAsCsvSuccess() { // Given: // ... A working query and workspace service WorkspaceService <SqlToolsSettings> ws = Common.GetPrimedWorkspaceService(Constants.StandardQuery); ConcurrentDictionary <string, byte[]> storage; QueryExecutionService qes = Common.GetPrimedExecutionService(Common.ExecutionPlanTestDataSet, true, false, false, ws, out storage); // ... The query execution service has executed a query with results var executeParams = new ExecuteDocumentSelectionParams { QuerySelection = null, OwnerUri = Constants.OwnerUri }; var executeRequest = RequestContextMocks.Create <ExecuteRequestResult>(null); await qes.HandleExecuteRequest(executeParams, executeRequest.Object); await qes.WorkTask; await qes.ActiveQueries[Constants.OwnerUri].ExecutionTask; // If: I attempt to save a result set from a query SaveResultsAsCsvRequestParams saveParams = new SaveResultsAsCsvRequestParams { OwnerUri = Constants.OwnerUri, FilePath = "qqq", BatchIndex = 0, ResultSetIndex = 0 }; qes.CsvFileFactory = GetCsvStreamFactory(storage, saveParams); var efv = new EventFlowValidator <SaveResultRequestResult>() .AddStandardResultValidator() .Complete(); await qes.HandleSaveResultsAsCsvRequest(saveParams, efv.Object); await qes.ActiveQueries[saveParams.OwnerUri] .Batches[saveParams.BatchIndex] .ResultSets[saveParams.ResultSetIndex] .SaveTasks[saveParams.FilePath]; // Then: // ... I should have a successful result // ... There should not have been an error efv.Validate(); }
/// <summary> /// Process request to save a resultSet to a file in CSV format /// </summary> internal async Task HandleSaveResultsAsCsvRequest(SaveResultsAsCsvRequestParams saveParams, RequestContext <SaveResultRequestResult> requestContext) { // retrieve query for OwnerUri Query result; if (!ActiveQueries.TryGetValue(saveParams.OwnerUri, out result)) { await requestContext.SendResult(new SaveResultRequestResult { Messages = SR.QueryServiceRequestsNoQuery }); return; } ResultSet selectedResultSet = result.Batches[saveParams.BatchIndex].ResultSets[saveParams.ResultSetIndex]; if (!selectedResultSet.IsBeingDisposed) { // Create SaveResults object and add success and error handlers to respective events SaveResults saveAsCsv = new SaveResults(); SaveResults.AsyncSaveEventHandler successHandler = async message => { selectedResultSet.RemoveSaveTask(saveParams.FilePath); await requestContext.SendResult(new SaveResultRequestResult { Messages = message }); }; saveAsCsv.SaveCompleted += successHandler; SaveResults.AsyncSaveEventHandler errorHandler = async message => { selectedResultSet.RemoveSaveTask(saveParams.FilePath); await requestContext.SendError(new SaveResultRequestError { message = message }); }; saveAsCsv.SaveFailed += errorHandler; saveAsCsv.SaveResultSetAsCsv(saveParams, requestContext, result); // Associate the ResultSet with the save task selectedResultSet.AddSaveTask(saveParams.FilePath, saveAsCsv.SaveTask); } }
public async Task SaveResultsCsvNonExistentQuery() { // Given: A working query and workspace service WorkspaceService <SqlToolsSettings> ws = Common.GetPrimedWorkspaceService(null); QueryExecutionService qes = Common.GetPrimedExecutionService(null, false, false, false, ws); // If: I attempt to save a result set from a query that doesn't exist SaveResultsAsCsvRequestParams saveParams = new SaveResultsAsCsvRequestParams { OwnerUri = Constants.OwnerUri // Won't exist because nothing has executed }; var evf = new EventFlowValidator <SaveResultRequestResult>() .AddStandardErrorValidation() .Complete(); await qes.HandleSaveResultsAsCsvRequest(saveParams, evf.Object); // Then: // ... An error event should have been fired // ... No success event should have been fired evf.Validate(); }
public void WriteRowWithoutColumnSelectionOrHeader() { // Setup: // ... Create a request params that has no selection made // ... Create a set of data to write // ... Create a memory location to store the data var requestParams = new SaveResultsAsCsvRequestParams(); List <DbCellValue> data = new List <DbCellValue> { new DbCellValue { DisplayValue = "item1" }, new DbCellValue { DisplayValue = "item2" } }; List <DbColumnWrapper> columns = new List <DbColumnWrapper> { new DbColumnWrapper(new TestDbColumn("column1")), new DbColumnWrapper(new TestDbColumn("column2")) }; byte[] output = new byte[8192]; // If: I write a row SaveAsCsvFileStreamWriter writer = new SaveAsCsvFileStreamWriter(new MemoryStream(output), requestParams); using (writer) { writer.WriteRow(data, columns); } // Then: It should write one line with 2 items, comma delimited string outputString = Encoding.UTF8.GetString(output).TrimEnd('\0', '\r', '\n'); string[] lines = outputString.Split(new[] { Environment.NewLine }, StringSplitOptions.None); Assert.Equal(1, lines.Length); string[] values = lines[0].Split(','); Assert.Equal(2, values.Length); }
public async void SaveResultsAsCsvSuccessTest() { // Execute a query var workplaceService = Common.GetPrimedWorkspaceService(Common.StandardQuery); var queryService = Common.GetPrimedExecutionService(new [] { Common.StandardTestData }, true, false, workplaceService); var executeParams = new QueryExecuteParams { QuerySelection = Common.WholeDocument, OwnerUri = Common.OwnerUri }; var executeRequest = RequestContextMocks.Create <QueryExecuteResult>(null); await Common.AwaitExecution(queryService, executeParams, executeRequest.Object); // Request to save the results as csv with correct parameters var saveParams = new SaveResultsAsCsvRequestParams { OwnerUri = Common.OwnerUri, ResultSetIndex = 0, BatchIndex = 0, FilePath = "testwrite_1.csv", IncludeHeaders = true }; SaveResultRequestResult result = null; var saveRequest = GetSaveResultsContextMock(qcr => result = qcr, null); // Call save results and wait on the save task await queryService.HandleSaveResultsAsCsvRequest(saveParams, saveRequest.Object); ResultSet selectedResultSet = queryService.ActiveQueries[saveParams.OwnerUri].Batches[saveParams.BatchIndex].ResultSets[saveParams.ResultSetIndex]; await selectedResultSet.GetSaveTask(saveParams.FilePath); // Expect to see a file successfully created in filepath and a success message VerifySaveResultsCallCount(saveRequest, Times.Once(), Times.Never()); Assert.Null(result.Messages); Assert.True(File.Exists(saveParams.FilePath)); // Delete temp file after test if (File.Exists(saveParams.FilePath)) { File.Delete(saveParams.FilePath); } }
public void WriteRowWithCustomEncoding() { // Setup: // ... Create a request params that has custom delimiter say pipe("|") then this delimiter should be used // ... Create a set of data to write // ... Create a memory location to store the data var requestParams = new SaveResultsAsCsvRequestParams { Encoding = "Windows-1252" }; List <DbCellValue> data = new List <DbCellValue> { new DbCellValue { DisplayValue = "ü" } }; List <DbColumnWrapper> columns = new List <DbColumnWrapper> { new DbColumnWrapper(new TestDbColumn("column1")) }; byte[] output = new byte[8192]; // If: I write a row SaveAsCsvFileStreamWriter writer = new SaveAsCsvFileStreamWriter(new MemoryStream(output), requestParams); using (writer) { writer.WriteRow(data, columns); } // Then: // ... It should have written the umlaut using the encoding Windows-1252 Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); string outputString = Encoding.GetEncoding("Windows-1252").GetString(output).TrimEnd('\0', '\r', '\n'); Assert.Equal("ü", outputString); }
public async Task SaveResultsAsCsvQueryNotFoundTest() { // Create a query execution service var workspaceService = Common.GetPrimedWorkspaceService(Common.StandardQuery); var queryService = Common.GetPrimedExecutionService(null, true, false, workspaceService); // Request to save the results as csv with query that is no longer active var saveParams = new SaveResultsAsCsvRequestParams { OwnerUri = "falseuri", ResultSetIndex = 0, BatchIndex = 0, FilePath = "testwrite_3.csv" }; SaveResultRequestResult result = null; var saveRequest = GetSaveResultsContextMock(qcr => result = qcr, null); await queryService.HandleSaveResultsAsCsvRequest(saveParams, saveRequest.Object); // Expect message that save failed VerifySaveResultsCallCount(saveRequest, Times.Once(), Times.Never()); Assert.NotNull(result.Messages); Assert.False(File.Exists(saveParams.FilePath)); }
/// <summary> /// Constructor, stores the CSV specific request params locally, chains into the base /// constructor /// </summary> /// <param name="stream">FileStream to access the CSV file output</param> /// <param name="requestParams">CSV save as request parameters</param> public SaveAsCsvFileStreamWriter(Stream stream, SaveResultsAsCsvRequestParams requestParams) : base(stream, requestParams) { saveParams = requestParams; }
public void WriteRowWithColumnSelection() { // Setup: // ... Create a request params that selects n-1 columns from the front and back // ... Create a set of data to write // ... Create a memory location to store the data var requestParams = new SaveResultsAsCsvRequestParams { ColumnStartIndex = 1, ColumnEndIndex = 2, RowStartIndex = 0, // Including b/c it is required to be a "save selection" RowEndIndex = 10, IncludeHeaders = true // Including headers to test both column selection logic }; List <DbCellValue> data = new List <DbCellValue> { new DbCellValue { DisplayValue = "item1" }, new DbCellValue { DisplayValue = "item2" }, new DbCellValue { DisplayValue = "item3" }, new DbCellValue { DisplayValue = "item4" } }; List <DbColumnWrapper> columns = new List <DbColumnWrapper> { new DbColumnWrapper(new TestDbColumn("column1")), new DbColumnWrapper(new TestDbColumn("column2")), new DbColumnWrapper(new TestDbColumn("column3")), new DbColumnWrapper(new TestDbColumn("column4")) }; byte[] output = new byte[8192]; // If: I write a row SaveAsCsvFileStreamWriter writer = new SaveAsCsvFileStreamWriter(new MemoryStream(output), requestParams); using (writer) { writer.WriteRow(data, columns); } // Then: // ... It should have written two lines string outputString = Encoding.UTF8.GetString(output).TrimEnd('\0', '\r', '\n'); string[] lines = outputString.Split(new[] { Environment.NewLine }, StringSplitOptions.None); Assert.Equal(2, lines.Length); // ... It should have written a header line with two, comma separated names string[] headerValues = lines[0].Split(','); Assert.Equal(2, headerValues.Length); for (int i = 1; i <= 2; i++) { Assert.Equal(columns[i].ColumnName, headerValues[i - 1]); } // ... The second line should have two, comma separated values string[] dataValues = lines[1].Split(','); Assert.Equal(2, dataValues.Length); for (int i = 1; i <= 2; i++) { Assert.Equal(data[i].DisplayValue, dataValues[i - 1]); } }
private static IFileStreamFactory GetCsvStreamFactory(IDictionary <string, byte[]> storage, SaveResultsAsCsvRequestParams saveParams) { Mock <IFileStreamFactory> mock = new Mock <IFileStreamFactory>(); mock.Setup(fsf => fsf.GetReader(It.IsAny <string>())) .Returns <string>(output => new ServiceBufferFileStreamReader(new MemoryStream(storage[output]), new QueryExecutionSettings())); mock.Setup(fsf => fsf.GetWriter(It.IsAny <string>())) .Returns <string>(output => { storage.Add(output, new byte[8192]); return(new SaveAsCsvFileStreamWriter(new MemoryStream(storage[output]), saveParams)); }); return(mock.Object); }
public void WriteRowsWithCustomLineSeperator() { // Setup: // ... Create a request params that has custom line seperator then this seperator should be used // ... Create a set of data to write // ... Create a memory location to store the data var requestParams = new SaveResultsAsCsvRequestParams { IncludeHeaders = true }; List <DbCellValue> data = new List <DbCellValue> { new DbCellValue { DisplayValue = "item1" }, new DbCellValue { DisplayValue = "item2" } }; List <DbColumnWrapper> columns = new List <DbColumnWrapper> { new DbColumnWrapper(new TestDbColumn("column1")), new DbColumnWrapper(new TestDbColumn("column2")) }; byte[] output; string outputString; string[] lines; SaveAsCsvFileStreamWriter writer; // If: I set default seperator and write a row requestParams.LineSeperator = null; output = new byte[8192]; writer = new SaveAsCsvFileStreamWriter(new MemoryStream(output), requestParams); using (writer) { writer.WriteRow(data, columns); } // Then: // ... It should have splitten the lines by system's default line seperator outputString = Encoding.UTF8.GetString(output).TrimEnd('\0', '\r', '\n'); lines = outputString.Split(new[] { Environment.NewLine }, StringSplitOptions.None); Assert.Equal(2, lines.Length); // If: I set \n (line feed) as seperator and write a row requestParams.LineSeperator = "\n"; output = new byte[8192]; writer = new SaveAsCsvFileStreamWriter(new MemoryStream(output), requestParams); using (writer) { writer.WriteRow(data, columns); } // Then: // ... It should have splitten the lines by \n outputString = Encoding.UTF8.GetString(output).TrimEnd('\0', '\r', '\n'); lines = outputString.Split(new[] { '\n' }, StringSplitOptions.None); Assert.Equal(2, lines.Length); // If: I set \r\n (carriage return + line feed) as seperator and write a row requestParams.LineSeperator = "\r\n"; output = new byte[8192]; writer = new SaveAsCsvFileStreamWriter(new MemoryStream(output), requestParams); using (writer) { writer.WriteRow(data, columns); } // Then: // ... It should have splitten the lines by \r\n outputString = Encoding.UTF8.GetString(output).TrimEnd('\0', '\r', '\n'); lines = outputString.Split(new[] { "\r\n" }, StringSplitOptions.None); Assert.Equal(2, lines.Length); }
/// <summary> /// Save results as CSV format to the file specified in saveParams /// </summary> /// <param name="saveParams"> Parameters from the request </param> /// <param name="requestContext"> Request context for save results </param> /// <param name="result"> Result query object </param> /// <returns></returns> internal void SaveResultSetAsCsv(SaveResultsAsCsvRequestParams saveParams, RequestContext <SaveResultRequestResult> requestContext, Query result) { // Run in a separate thread SaveTask = Task.Run(async() => { try { using (StreamWriter csvFile = new StreamWriter(File.Open(saveParams.FilePath, FileMode.Create, FileAccess.ReadWrite, FileShare.Read))) { ResultSetSubset resultSubset; int columnCount = 0; int rowCount = 0; int columnStartIndex = 0; int rowStartIndex = 0; // Get the requested resultSet from query Batch selectedBatch = result.Batches[saveParams.BatchIndex]; ResultSet selectedResultSet = (selectedBatch.ResultSets)[saveParams.ResultSetIndex]; // Set column, row counts depending on whether save request is for entire result set or a subset if (IsSaveSelection(saveParams)) { columnCount = saveParams.ColumnEndIndex.Value - saveParams.ColumnStartIndex.Value + 1; rowCount = saveParams.RowEndIndex.Value - saveParams.RowStartIndex.Value + 1; columnStartIndex = saveParams.ColumnStartIndex.Value; rowStartIndex = saveParams.RowStartIndex.Value; } else { columnCount = selectedResultSet.Columns.Length; rowCount = (int)selectedResultSet.RowCount; } // Write column names if include headers option is chosen if (saveParams.IncludeHeaders) { csvFile.WriteLine(string.Join(",", selectedResultSet.Columns.Skip(columnStartIndex).Take(columnCount).Select(column => EncodeCsvField(column.ColumnName) ?? string.Empty))); } for (int i = 0; i < (rowCount / BatchSize) + 1; i++) { int numberOfRows = (i < rowCount / BatchSize) ? BatchSize : (rowCount % BatchSize); if (numberOfRows == 0) { break; } // Retrieve rows and write as csv resultSubset = await result.GetSubset(saveParams.BatchIndex, saveParams.ResultSetIndex, rowStartIndex + i * BatchSize, numberOfRows); foreach (var row in resultSubset.Rows) { csvFile.WriteLine(string.Join(",", row.Skip(columnStartIndex).Take(columnCount).Select(field => EncodeCsvField((field != null) ? field.ToString() : "NULL")))); } } } // Successfully wrote file, send success result if (SaveCompleted != null) { await SaveCompleted(null); } } catch (Exception ex) { // Delete file when exception occurs if (FileUtils.SafeFileExists(saveParams.FilePath)) { FileUtils.SafeFileDelete(saveParams.FilePath); } if (SaveFailed != null) { await SaveFailed(ex.Message); } } }); }