UNPKG

rawsql-ts

Version:

High-performance SQL parser and AST analyzer written in TypeScript. Provides fast parsing and advanced transformation capabilities.

151 lines 6.76 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.FixtureCteBuilder = void 0; const Clause_1 = require("../models/Clause"); const SelectQuery_1 = require("../models/SelectQuery"); const ValueComponent_1 = require("../models/ValueComponent"); const DDLToFixtureConverter_1 = require("./DDLToFixtureConverter"); class FixtureCteBuilder { /** * Creates fixture definitions from a SQL string containing DDL (CREATE TABLE) and INSERT statements. * * @param sql The SQL string containing DDL and INSERTs. * @returns An array of FixtureTableDefinition objects. */ static fromSQL(sql) { const fixtureJson = DDLToFixtureConverter_1.DDLToFixtureConverter.convert(sql); return this.fromJSON(fixtureJson); } /** * Converts JSON fixture definitions to FixtureTableDefinition format. * Accepts an object where keys are table names and values contain columns and rows. * * @param jsonDefinitions Object with table definitions * @returns Array of FixtureTableDefinition * * @example * ```typescript * const json = { * users: { * columns: [ * { name: 'id', type: 'integer' }, * { name: 'name', type: 'text' } * ], * rows: [ * { id: 1, name: 'Alice' }, * { id: 2, name: 'Bob' } * ] * } * }; * const fixtures = FixtureCteBuilder.fromJSON(json); * ``` */ static fromJSON(jsonDefinitions) { const fixtures = []; for (const [tableName, def] of Object.entries(jsonDefinitions)) { if (def && Array.isArray(def.columns)) { const columns = def.columns.map(c => ({ name: c.name, typeName: c.type, defaultValue: c.default })); let rows = []; if (Array.isArray(def.rows)) { // Convert array of objects to array of arrays based on column order rows = def.rows.map(rowObj => { return columns.map(col => { return rowObj[col.name] !== undefined ? rowObj[col.name] : null; }); }); } fixtures.push({ tableName, columns, rows }); } } return fixtures; } /** Builds CommonTable representations for the provided fixtures. */ static buildFixtures(fixtures) { return fixtures.map((fixture) => this.buildFixture(fixture)); } static buildFixture(fixture) { const query = this.buildSelectQuery(fixture); // Wrap the query into a CommonTable for later WITH clause injection. return new Clause_1.CommonTable(query, fixture.tableName, null); } static buildSelectQuery(fixture) { const columnCount = fixture.columns.length; // Always produce at least one row even when the fixture carries zero entries. const rows = fixture.rows.length > 0 ? fixture.rows : [new Array(columnCount).fill(null)]; const selectQueries = rows.map((row) => this.buildSelectRow(fixture.columns, row)); if (selectQueries.length === 0) { throw new Error('No rows to build SELECT query'); } let result = selectQueries[0]; // Build UNION ALL chain for multiple rows for (let i = 1; i < selectQueries.length; i++) { // Both SimpleSelectQuery and BinarySelectQuery have toUnionAll/unionAll methods if (result instanceof SelectQuery_1.SimpleSelectQuery) { result = result.toUnionAll(selectQueries[i]); } else { // BinarySelectQuery has unionAll method result = result.unionAll(selectQueries[i]); } } // Handle empty fixture case: add WHERE 1 = 0 to make it return no rows if (fixture.rows.length === 0 && result instanceof SelectQuery_1.SimpleSelectQuery) { const falseCondition = new ValueComponent_1.BinaryExpression(new ValueComponent_1.LiteralValue(1), '=', new ValueComponent_1.LiteralValue(0)); result.whereClause = new Clause_1.WhereClause(falseCondition); } return result; } static buildSelectRow(columns, row) { // Build select items that respect optional type annotations. const items = columns.map((column, index) => { const value = index < row.length ? row[index] : null; const literalValue = this.createLiteralValue(value); let expression = literalValue; if (column.typeName) { const typeValue = new ValueComponent_1.TypeValue(null, new ValueComponent_1.RawString(column.typeName)); expression = new ValueComponent_1.CastExpression(literalValue, typeValue); } return new Clause_1.SelectItem(expression, column.name); }); const selectClause = new Clause_1.SelectClause(items); return new SelectQuery_1.SimpleSelectQuery({ selectClause }); } static createLiteralValue(value) { if (value === null || value === undefined) { return new ValueComponent_1.LiteralValue(null); } if (typeof value === 'number') { return new ValueComponent_1.LiteralValue(Number.isFinite(value) ? value : null); } if (typeof value === 'boolean') { // Preserve boolean literals so the printer emits TRUE/FALSE instead of quoted strings return new ValueComponent_1.LiteralValue(value); } if (typeof value === 'bigint') { // Convert bigint to string to preserve precision // LiteralValue accepts string|number|boolean|null, and when isStringLiteral is false, // the printer will output it as-is without quotes return new ValueComponent_1.LiteralValue(value.toString()); } if (typeof Buffer !== 'undefined' && value instanceof Buffer) { // For Buffer, we'll create a hex string literal return new ValueComponent_1.LiteralValue(`X'${value.toString('hex')}'`); } if (typeof value === 'string') { // Store the raw string value WITHOUT quotes or escaping // The SqlPrinter will handle escaping when printing return new ValueComponent_1.LiteralValue(value, undefined, true); } return new ValueComponent_1.LiteralValue(String(value), undefined, true); } } exports.FixtureCteBuilder = FixtureCteBuilder; //# sourceMappingURL=FixtureCteBuilder.js.map