rawsql-ts
Version:
[beta]High-performance SQL parser and AST analyzer written in TypeScript. Provides fast parsing and advanced transformation capabilities.
153 lines • 7.02 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.SqlSortInjector = void 0;
const SelectQuery_1 = require("../models/SelectQuery");
const SelectableColumnCollector_1 = require("./SelectableColumnCollector");
const Clause_1 = require("../models/Clause");
const SelectQueryParser_1 = require("../parsers/SelectQueryParser");
/**
* SqlSortInjector injects sort conditions into a SelectQuery model,
* creating ORDER BY clauses based on provided sort conditions.
*/
class SqlSortInjector {
constructor(tableColumnResolver) {
this.tableColumnResolver = tableColumnResolver;
}
/**
* Removes ORDER BY clause from the given query.
* @param query The SelectQuery to modify
* @returns The modified SimpleSelectQuery with ORDER BY clause removed
*/
static removeOrderBy(query) {
// Convert string query to SimpleSelectQuery using SelectQueryParser if needed
if (typeof query === 'string') {
query = SelectQueryParser_1.SelectQueryParser.parse(query);
}
// Check if query is SimpleSelectQuery
if (!(query instanceof SelectQuery_1.SimpleSelectQuery)) {
throw new Error('Complex queries are not supported for ORDER BY removal');
}
// Create a new query without ORDER BY clause
return new SelectQuery_1.SimpleSelectQuery({
withClause: query.withClause,
selectClause: query.selectClause,
fromClause: query.fromClause,
whereClause: query.whereClause,
groupByClause: query.groupByClause,
havingClause: query.havingClause,
orderByClause: null, // Remove ORDER BY
windowClause: query.windowClause,
limitClause: query.limitClause,
offsetClause: query.offsetClause,
fetchClause: query.fetchClause,
forClause: query.forClause,
});
}
/**
* Injects sort conditions as ORDER BY clauses into the given query model.
* Appends to existing ORDER BY clause if present.
* @param query The SelectQuery to modify
* @param sortConditions A record of column names and sort conditions
* @returns The modified SimpleSelectQuery
*/
inject(query, sortConditions) {
// Convert string query to SimpleSelectQuery using SelectQueryParser if needed
if (typeof query === 'string') {
query = SelectQueryParser_1.SelectQueryParser.parse(query);
}
// Check if query is SimpleSelectQuery
if (!(query instanceof SelectQuery_1.SimpleSelectQuery)) {
throw new Error('Complex queries are not supported for sorting');
}
// Collect available columns including all JOIN table columns for sorting
const collector = new SelectableColumnCollector_1.SelectableColumnCollector(this.tableColumnResolver, false, // includeWildCard
SelectableColumnCollector_1.DuplicateDetectionMode.FullName, // Use FullName to preserve JOIN table columns
{ upstream: true } // Enable upstream collection for JOIN table sorting
);
const availableColumns = collector.collect(query);
// Validate that all specified columns exist
for (const columnName of Object.keys(sortConditions)) {
const columnEntry = availableColumns.find(item => item.name === columnName);
if (!columnEntry) {
throw new Error(`Column or alias '${columnName}' not found in current query`);
}
}
// Build new ORDER BY items
const newOrderByItems = [];
for (const [columnName, condition] of Object.entries(sortConditions)) {
const columnEntry = availableColumns.find(item => item.name === columnName);
if (!columnEntry)
continue; // Should not happen due to validation above
const columnRef = columnEntry.value;
// Validate condition
this.validateSortCondition(columnName, condition);
// Determine sort direction
let sortDirection;
if (condition.desc) {
sortDirection = Clause_1.SortDirection.Descending;
}
else {
sortDirection = Clause_1.SortDirection.Ascending; // Default to ASC
}
// Determine nulls position
let nullsPosition = null;
if (condition.nullsFirst) {
nullsPosition = Clause_1.NullsSortDirection.First;
}
else if (condition.nullsLast) {
nullsPosition = Clause_1.NullsSortDirection.Last;
}
// Create OrderByItem
const orderByItem = new Clause_1.OrderByItem(columnRef, sortDirection, nullsPosition);
newOrderByItems.push(orderByItem);
}
// Combine with existing ORDER BY clause if present
let finalOrderByItems = [];
if (query.orderByClause) {
// Append to existing ORDER BY
finalOrderByItems = [...query.orderByClause.order, ...newOrderByItems];
}
else {
// Create new ORDER BY
finalOrderByItems = newOrderByItems;
}
// Create new OrderByClause
const newOrderByClause = finalOrderByItems.length > 0
? new Clause_1.OrderByClause(finalOrderByItems)
: null;
// Create new query with updated ORDER BY clause
return new SelectQuery_1.SimpleSelectQuery({
withClause: query.withClause,
selectClause: query.selectClause,
fromClause: query.fromClause,
whereClause: query.whereClause,
groupByClause: query.groupByClause,
havingClause: query.havingClause,
orderByClause: newOrderByClause,
windowClause: query.windowClause,
limitClause: query.limitClause,
offsetClause: query.offsetClause,
fetchClause: query.fetchClause,
forClause: query.forClause,
});
}
/**
* Validates sort condition for a column
*/
validateSortCondition(columnName, condition) {
// Check for conflicting sort directions
if (condition.asc && condition.desc) {
throw new Error(`Conflicting sort directions for column '${columnName}': both asc and desc specified`);
}
// Check for conflicting nulls positions
if (condition.nullsFirst && condition.nullsLast) {
throw new Error(`Conflicting nulls positions for column '${columnName}': both nullsFirst and nullsLast specified`);
}
// Check if at least one option is specified
if (!condition.asc && !condition.desc && !condition.nullsFirst && !condition.nullsLast) {
throw new Error(`Empty sort condition for column '${columnName}': at least one sort option must be specified`);
}
}
}
exports.SqlSortInjector = SqlSortInjector;
//# sourceMappingURL=SqlSortInjector.js.map