rawsql-ts
Version:
[beta]High-performance SQL parser and AST analyzer written in TypeScript. Provides fast parsing and advanced transformation capabilities.
122 lines • 5.86 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.InsertQuerySelectValuesConverter = void 0;
const InsertQuery_1 = require("../models/InsertQuery");
const ValuesQuery_1 = require("../models/ValuesQuery");
const SimpleSelectQuery_1 = require("../models/SimpleSelectQuery");
const BinarySelectQuery_1 = require("../models/BinarySelectQuery");
const Clause_1 = require("../models/Clause");
const ValueComponent_1 = require("../models/ValueComponent");
/**
* Utility to convert INSERT ... VALUES statements into INSERT ... SELECT UNION ALL form and vice versa.
* Enables easier column-by-column comparison across multi-row inserts.
*/
class InsertQuerySelectValuesConverter {
/**
* Converts an INSERT query that uses VALUES into an equivalent INSERT ... SELECT UNION ALL form.
* The original InsertQuery remains untouched; the returned InsertQuery references cloned structures.
*/
static toSelectUnion(insertQuery) {
const valuesQuery = insertQuery.selectQuery;
if (!(valuesQuery instanceof ValuesQuery_1.ValuesQuery)) {
throw new Error("InsertQuery selectQuery is not a VALUES query.");
}
if (!valuesQuery.tuples.length) {
throw new Error("VALUES query does not contain any tuples.");
}
const columns = insertQuery.insertClause.columns;
if (!columns || columns.length === 0) {
throw new Error("Cannot convert to SELECT form without explicit column list.");
}
const columnNames = columns.map(col => col.name);
const selectQueries = valuesQuery.tuples.map(tuple => {
if (tuple.values.length !== columnNames.length) {
throw new Error("Tuple value count does not match column count.");
}
const items = columnNames.map((name, idx) => new Clause_1.SelectItem(tuple.values[idx], name));
const selectClause = new Clause_1.SelectClause(items);
return new SimpleSelectQuery_1.SimpleSelectQuery({ selectClause });
});
let combined = selectQueries[0];
for (let i = 1; i < selectQueries.length; i++) {
if (combined instanceof SimpleSelectQuery_1.SimpleSelectQuery) {
combined = combined.toUnionAll(selectQueries[i]);
}
else if (combined instanceof BinarySelectQuery_1.BinarySelectQuery) {
combined.appendSelectQuery("union all", selectQueries[i]);
}
else {
throw new Error("Unsupported SelectQuery type during UNION ALL construction.");
}
}
return new InsertQuery_1.InsertQuery({
withClause: insertQuery.withClause,
insertClause: insertQuery.insertClause,
selectQuery: combined,
returning: insertQuery.returningClause
});
}
/**
* Converts an INSERT query that leverages SELECT statements (with optional UNION ALL)
* into an equivalent INSERT ... VALUES representation.
*/
static toValues(insertQuery) {
const columns = insertQuery.insertClause.columns;
if (!columns || columns.length === 0) {
throw new Error("Cannot convert to VALUES form without explicit column list.");
}
if (!insertQuery.selectQuery) {
throw new Error("InsertQuery does not have a selectQuery to convert.");
}
const columnNames = columns.map(col => col.name);
const simpleQueries = this.flattenSelectQueries(insertQuery.selectQuery);
if (!simpleQueries.length) {
throw new Error("No SELECT components found to convert.");
}
const tuples = simpleQueries.map(query => {
var _a, _b;
if (query.fromClause || (query.whereClause && query.whereClause.condition)) {
throw new Error("SELECT queries with FROM or WHERE clauses cannot be converted to VALUES.");
}
const valueMap = new Map();
for (const item of query.selectClause.items) {
const identifier = (_b = (_a = item.identifier) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : null;
if (!identifier) {
throw new Error("Each SELECT item must have an alias matching target columns.");
}
if (!valueMap.has(identifier)) {
valueMap.set(identifier, item.value);
}
}
const rowValues = columnNames.map(name => {
const value = valueMap.get(name);
if (!value) {
throw new Error(`Column '${name}' is not provided by the SELECT query.`);
}
return value;
});
return new ValueComponent_1.TupleExpression(rowValues);
});
const valuesQuery = new ValuesQuery_1.ValuesQuery(tuples, columnNames);
return new InsertQuery_1.InsertQuery({
withClause: insertQuery.withClause,
insertClause: insertQuery.insertClause,
selectQuery: valuesQuery,
returning: insertQuery.returningClause
});
}
static flattenSelectQueries(selectQuery) {
if (selectQuery instanceof SimpleSelectQuery_1.SimpleSelectQuery) {
return [selectQuery];
}
if (selectQuery instanceof BinarySelectQuery_1.BinarySelectQuery) {
return [
...this.flattenSelectQueries(selectQuery.left),
...this.flattenSelectQueries(selectQuery.right)
];
}
throw new Error("Unsupported SelectQuery subtype for conversion.");
}
}
exports.InsertQuerySelectValuesConverter = InsertQuerySelectValuesConverter;
//# sourceMappingURL=InsertQuerySelectValuesConverter.js.map