UNPKG

@itwin/core-backend

Version:
197 lines (191 loc) • 8.4 kB
/*--------------------------------------------------------------------------------------------- * Copyright (c) Bentley Systems, Incorporated. All rights reserved. * See LICENSE.md in the project root for license terms and full copyright notice. *--------------------------------------------------------------------------------------------*/ var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) { if (value !== null && value !== void 0) { if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected."); var dispose, inner; if (async) { if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined."); dispose = value[Symbol.asyncDispose]; } if (dispose === void 0) { if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined."); dispose = value[Symbol.dispose]; if (async) inner = dispose; } if (typeof dispose !== "function") throw new TypeError("Object not disposable."); if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } }; env.stack.push({ value: value, dispose: dispose, async: async }); } else if (async) { env.stack.push({ async: true }); } return value; }; var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) { return function (env) { function fail(e) { env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e; env.hasError = true; } var r, s = 0; function next() { while (r = env.stack.pop()) { try { if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next); if (r.dispose) { var result = r.dispose.call(r.value); if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); }); } else s |= 1; } catch (e) { fail(e); } } if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve(); if (env.hasError) throw env.error; } return next(); }; })(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) { var e = new Error(message); return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e; }); import { SnapshotDb } from "../../../core-backend"; import { DbResult } from "@itwin/core-bentley"; import { ECSqlValueType, QueryOptionsBuilder, QueryRowFormat } from "@itwin/core-common"; import * as path from "path"; import * as fs from "fs"; import * as crypto from "crypto"; import { ECSqlDatasets } from "../dataset/ECSqlDatasets"; import { KnownTestLocations } from "../../KnownTestLocations"; import { format } from "sql-formatter"; // Call like this: // node lib\cjs\test\ecsql\src\ECSqlTestGenerator.js AllProperties.bim "SELECT * FROM meta.ECSchemaDef LIMIT 2" -t // node lib\cjs\test\ecsql\src\ECSqlTestGenerator.js AllProperties.bim "SELECT te.ECInstanceId [MyId], te.s, te.DT [Date], row_number() over(PARTITION BY te.DT ORDER BY te.ECInstanceId) as [RowNumber] from aps.TestElement te WHERE te.i < 106" -t async function runConcurrentQuery(imodel, sql) { const queryOptions = new QueryOptionsBuilder(); queryOptions.setRowFormat(QueryRowFormat.UseECSqlPropertyNames); const reader = imodel.createQueryReader(sql, undefined, queryOptions.getOptions()); const rows = await reader.toArray(); const metadata = await reader.getMetaData(); metadata.forEach((value) => delete value.extendType); return { metadata, rows }; } function pullAdditionalMetadataThroughECSqlStatement(imodel, metadata, sql) { const env_1 = { stack: [], error: void 0, hasError: false }; try { // eslint-disable-next-line @typescript-eslint/no-deprecated const stmt = __addDisposableResource(env_1, imodel.prepareStatement(sql), false); if (stmt.step() === DbResult.BE_SQLITE_ROW) { const colCount = stmt.getColumnCount(); if (colCount !== metadata.length) { // eslint-disable-next-line no-console console.error(`Column count mismatch: ${colCount} != ${metadata.length}. Not generating metadata from statement.`); return; } for (let i = 0; i < colCount; i++) { const colInfo = stmt.getValue(i).columnInfo; metadata[i].type = ECSqlValueType[colInfo.getType()]; const originPropertyName = colInfo.getOriginPropertyName(); if (originPropertyName !== undefined) metadata[i].originPropertyName = originPropertyName; } } } catch (e_1) { env_1.error = e_1; env_1.hasError = true; } finally { __disposeResources(env_1); } } function arrayToMarkdownTable(data) { if (data.length === 0) { return ""; } const headers = Array.from(data.reduce((headersSet, row) => { Object.keys(row).forEach(header => headersSet.add(header)); return headersSet; }, new Set())); const columnWidths = headers.map(header => Math.max(header.length, ...data.map(row => String(row[header]).length))); const formatRow = (row) => `| ${headers.map((header, i) => String(row[header]).padEnd(columnWidths[i])).join(" | ")} |`; const headerRow = formatRow(headers.reduce((acc, header) => ({ ...acc, [header]: header }), {})); const separatorRow = `| ${columnWidths.map(width => "-".repeat(width)).join(" | ")} |`; const dataRows = data.map(formatRow); return [headerRow, separatorRow, ...dataRows].join("\n"); } function generateHash(input) { return crypto.createHash('sha256').update(input).digest('hex').substring(0, 8); } function writeMarkdownFile(dataset, sql, columns, results, useTables) { const hash = generateHash(sql); if (sql.length > 100) { // we format the SQL if it's too long sql = format(sql, { language: "sqlite", keywordCase: "upper", "tabWidth": 2, indentStyle: "standard", logicalOperatorNewline: "after" }); } let markdownContent = `# GeneratedTest #${dataset} - ${hash} - dataset: ${dataset} \`\`\`sql ${sql} \`\`\` `; if (useTables) { markdownContent += ` ${arrayToMarkdownTable(columns)} ${arrayToMarkdownTable(results)} `; } else { markdownContent += ` \`\`\`json ${JSON.stringify({ columns }, null, 2)} \`\`\` \`\`\`json ${JSON.stringify(results, null, 2)} \`\`\` `; } const outputFilePath = path.join(__dirname, "generated.ecsql.md"); fs.appendFileSync(outputFilePath, markdownContent, "utf-8"); // eslint-disable-next-line no-console console.log(`Results written to ${outputFilePath}`); } async function main() { const args = process.argv.slice(2); if (args.length < 2) { // eslint-disable-next-line no-console console.error("Usage: ts-node ECDbMarkdownTestGenerator.ts <dataset> <sql>"); process.exit(1); } const [dataset, sql, tablesFlag] = args; const useTables = tablesFlag === "-t"; let imodel; try { await ECSqlDatasets.generateFiles(); const datasetFilePath = path.join(KnownTestLocations.outputDir, "ECSqlTests", dataset); imodel = SnapshotDb.openFile(datasetFilePath); const { metadata, rows } = await runConcurrentQuery(imodel, sql); pullAdditionalMetadataThroughECSqlStatement(imodel, metadata, sql); writeMarkdownFile(dataset, sql, metadata, rows, useTables); imodel.close(); imodel = undefined; } catch (error) { // eslint-disable-next-line no-console console.error("Error running query:", error); if (imodel) { imodel.close(); } process.exit(1); } } main().catch((error) => { // eslint-disable-next-line no-console console.error("Unhandled error in main:", error); process.exit(1); }); //# sourceMappingURL=ECSqlTestGenerator.js.map