|
1 | | -import { CsvDataUtil } from './CsvDataUtil'; |
| 1 | +import { CsvFileWriter } from './CsvFileWriter'; |
2 | 2 | import { DataUtils } from './DataUtils'; |
3 | 3 | import * as sqlite3 from 'sqlite3'; |
4 | 4 |
|
@@ -355,16 +355,40 @@ export class DatabaseUtil |
355 | 355 | { |
356 | 356 | try |
357 | 357 | { |
358 | | - //Unpack the params Map to a plain key-value pair object to pass to sqlite |
| 358 | + //Create our CSV file writer |
| 359 | + let writer = await CsvFileWriter.createWriter(csvFile); |
| 360 | + |
| 361 | + //Unpack the params Map to a plain key-value pair object to pass to SQLite |
359 | 362 | let paramsUnpacked : any = {}; |
360 | 363 | params.forEach((value : Object, key : string) => { paramsUnpacked[key] = value; }); |
361 | 364 |
|
362 | | - //Perform the query |
363 | | - let rows = await DatabaseUtil.all(db, query, paramsUnpacked); |
364 | | - let data = DatabaseUtil.reshapeForCsv(rows); |
| 365 | + //Determine how many rows will be returned by the query |
| 366 | + //(Note that this will only function correctly for simple queries that only feature one FROM clause) |
| 367 | + let countQuery = query.replace(/SELECT .+ FROM/i, 'SELECT COUNT(*) AS total FROM'); |
| 368 | + let totalRows = (await DatabaseUtil.get(db, countQuery, paramsUnpacked))['total']; |
| 369 | + |
| 370 | + //Strip any trailing semicolon from the query string so we can append our offset and limit clauses |
| 371 | + query = query.trim(); |
| 372 | + query = (query.endsWith(';') ? query.substr(0, query.length-1) : query); |
| 373 | + |
| 374 | + //Process the data in batches |
| 375 | + const batchSize = 50000; |
| 376 | + for (let offset = 0; offset < totalRows; offset += batchSize) |
| 377 | + { |
| 378 | + //Retrieve the results for the current batch |
| 379 | + let batch = await DatabaseUtil.all(db, query + ` LIMIT ${batchSize} OFFSET ${offset};`, paramsUnpacked); |
| 380 | + |
| 381 | + //Only include the header row in the first batch |
| 382 | + let data = DatabaseUtil.reshapeForCsv(batch); |
| 383 | + if (offset > 0) { |
| 384 | + data = data.slice(1); |
| 385 | + } |
| 386 | + |
| 387 | + //Write the current batch of rows to the CSV file |
| 388 | + await writer.write(data); |
| 389 | + } |
365 | 390 |
|
366 | | - //Write the data to the CSV file |
367 | | - await CsvDataUtil.writeCsv(csvFile, data); |
| 391 | + await writer.close(); |
368 | 392 | return true; |
369 | 393 | } |
370 | 394 | catch (err) |
|
0 commit comments