import benchmark from 'benchmark' import initSqlJs from 'sql.js' import lodash from 'lodash' import Papa from 'papaparse' import useragent from 'ua-parser-js' describe('SQLite build benchmark', function () { let parsedCsv let sqlModule let selectDb before(async function () { parsedCsv = await parseCsv('http://localhost:9876/base/sample.csv') sqlModule = await initSqlJs() selectDb = new sqlModule.Database() importToTable(selectDb, parsedCsv) }) function benchmarkImport() { const db = new sqlModule.Database() try { importToTable(db, parsedCsv) } finally { db.close() } } function benchmarkSelect() { const result = selectDb.exec(` SELECT county, AVG(avg_depth) avg_depth_c FROM ( SELECT s.county, s.town, COUNT(*) cnt, AVG(s.DrilledDepth) avg_depth FROM csv_import s JOIN csv_import USING(hole) WHERE s.town IS NOT NULL GROUP BY 1, 2 ORDER BY 4 DESC ) GROUP BY 1 ORDER BY 2 DESC `) console.assert(result.values.length == 56, 'Unexpected size of result set') } it('run', async function () { const suite = createSuite() suite.add('import', { initCount: 3, minSamples: 50, fn: benchmarkImport }) suite.add('select', { initCount: 3, minSamples: 50, fn: benchmarkSelect }) await run(suite) }) }) function importToTable(db, parsedCsv, chunkSize = 1024) { const columnListString = parsedCsv.meta.fields.join(', ') db.exec(`CREATE TABLE csv_import(${columnListString})`) const params = parsedCsv.meta.fields.map(name => '?').join(', ') const insertStmt = db.prepare(`INSERT INTO csv_import VALUES(${params})`) chunkArray(parsedCsv.data, chunkSize).map(function (chunk) { db.exec('BEGIN') chunk.map(row => insertStmt.run(Object.values(row))) db.exec('COMMIT') }) } class PromiseWrapper { constructor() { this.promise = new Promise((resolve, reject) => { this.reject = reject this.resolve = resolve }) } } function parseCsv(url) { return new Promise((resolve, reject) => { Papa.parse(url, { header: true, download: true, skipEmptyLines: 'greedy', complete: results => resolve(results), error: (error, file) => reject(error) }) }) } function chunkArray(arr, size) { return arr.reduce(function (result, value, index) { const chunkIndex = Math.floor(index / size) if (!(chunkIndex in result)) { result[chunkIndex] = [] } result[chunkIndex].push(value) return result }, []) } function createSuite() { // Combined workaround from: // - https://github.com/bestiejs/benchmark.js/issues/106 // - https://github.com/bestiejs/benchmark.js/issues/237 // Benchmark could not pick up lodash otherwise const bm = benchmark.runInContext({ _: lodash }) // Avoid `ReferenceError: Benchmark is not defined` error because Benchmark is assumed // to be in window window.Benchmark = bm return new bm.Suite() } function run(suite) { const suiteResult = new PromiseWrapper() suite .on('cycle', function (event) { console.info(String(event.target)) }) .on('complete', function () { console.log( JSON.stringify({ browser: useragent(navigator.userAgent).browser, result: this.filter('successful') }) ) suiteResult.resolve() }) .on('error', function (event) { console.error('Benchmark failed', String(event.target)) suiteResult.reject() }) .run({ async: true }) return suiteResult.promise }