Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ export * from './transformers/Formatter';
export * from './transformers/SqlFormatter';
export * from './transformers/PostgresJsonQueryBuilder';
export * from './transformers/QueryBuilder'; // old name:QueryConverter
export * from './transformers/InsertQuerySelectValuesConverter';
export * from './transformers/SelectValueCollector';
export * from './transformers/SelectableColumnCollector';
export { DuplicateDetectionMode } from './transformers/SelectableColumnCollector';
Expand Down
71 changes: 56 additions & 15 deletions packages/core/src/models/BinarySelectQuery.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,22 @@
import { SourceExpression, SubQuerySource, SourceAliasExpression } from "./Clause";
import type { SelectQuery, CTEOptions } from "./SelectQuery";
import { SqlComponent } from "./SqlComponent";
import { RawString, SqlParameterValue } from "./ValueComponent";
import { CTENormalizer } from "../transformers/CTENormalizer";
import { SelectQueryParser } from "../parsers/SelectQueryParser";
import { ParameterCollector } from "../transformers/ParameterCollector";
import { ParameterHelper } from "../utils/ParameterHelper";
import { QueryBuilder } from "../transformers/QueryBuilder";
import { SimpleSelectQuery } from "./SimpleSelectQuery";
import { SourceExpression, SubQuerySource, SourceAliasExpression } from "./Clause";
import type {
SelectQuery,
InsertQueryConversionOptions,
UpdateQueryConversionOptions,
DeleteQueryConversionOptions,
MergeQueryConversionOptions
} from "./SelectQuery";
import { SqlComponent } from "./SqlComponent";
import { RawString, SqlParameterValue } from "./ValueComponent";
import { CTENormalizer } from "../transformers/CTENormalizer";
import { SelectQueryParser } from "../parsers/SelectQueryParser";
import { ParameterHelper } from "../utils/ParameterHelper";
import { QueryBuilder } from "../transformers/QueryBuilder";
import { SimpleSelectQuery } from "./SimpleSelectQuery";
import type { InsertQuery } from "./InsertQuery";
import type { UpdateQuery } from "./UpdateQuery";
import type { DeleteQuery } from "./DeleteQuery";
import type { MergeQuery } from "./MergeQuery";

/**
* Represents a binary SELECT expression (UNION/INTERSECT/EXCEPT) composed from two SelectQuery values.
Expand Down Expand Up @@ -154,11 +163,43 @@ export class BinarySelectQuery extends SqlComponent implements SelectQuery {
const parsedQuery = SelectQueryParser.parse(sql);
return this.except(parsedQuery);
}
public exceptAllRaw(sql: string): BinarySelectQuery {
const parsedQuery = SelectQueryParser.parse(sql);
return this.exceptAll(parsedQuery);
}

public exceptAllRaw(sql: string): BinarySelectQuery {
const parsedQuery = SelectQueryParser.parse(sql);
return this.exceptAll(parsedQuery);
}

/**
* Converts this query into an INSERT statement definition.
* @remarks The underlying simple query may be reordered so that column order matches the requested insert columns.
*/
public toInsertQuery(options: InsertQueryConversionOptions): InsertQuery {
return this.toSimpleQuery().toInsertQuery(options);
}

/**
* Converts this query into an UPDATE statement definition.
* @remarks The conversion can reorder the SELECT list produced by {@link toSimpleQuery}.
*/
public toUpdateQuery(options: UpdateQueryConversionOptions): UpdateQuery {
return this.toSimpleQuery().toUpdateQuery(options);
}

/**
* Converts this query into a DELETE statement definition.
* @remarks The conversion can reorder the SELECT list produced by {@link toSimpleQuery}.
*/
public toDeleteQuery(options: DeleteQueryConversionOptions): DeleteQuery {
return this.toSimpleQuery().toDeleteQuery(options);
}

/**
* Converts this query into a MERGE statement definition.
* @remarks The conversion can reorder the SELECT list produced by {@link toSimpleQuery}.
*/
public toMergeQuery(options: MergeQueryConversionOptions): MergeQuery {
return this.toSimpleQuery().toMergeQuery(options);
}

// Returns a SourceExpression wrapping this query as a subquery source.
// Optionally takes an alias name (default: "subq")
public toSource(alias: string = "subq"): SourceExpression {
Expand Down
89 changes: 69 additions & 20 deletions packages/core/src/models/SelectQuery.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import { SqlComponent } from "./SqlComponent";
import { InsertQuery } from "./InsertQuery";
import { SimpleSelectQuery } from "./SimpleSelectQuery";
import { BinarySelectQuery } from "./BinarySelectQuery";
import { ValuesQuery } from "./ValuesQuery";
import { SqlParameterValue } from "./ValueComponent";
import { SqlComponent } from "./SqlComponent";
import { InsertQuery } from "./InsertQuery";
import { SimpleSelectQuery } from "./SimpleSelectQuery";
import { BinarySelectQuery } from "./BinarySelectQuery";
import { ValuesQuery } from "./ValuesQuery";
import { SqlParameterValue } from "./ValueComponent";
import { UpdateQuery } from "./UpdateQuery";
import { DeleteQuery } from "./DeleteQuery";
import { MergeQuery } from "./MergeQuery";

/**
* Options that control how a Common Table Expression is materialized when the query is executed.
Expand All @@ -29,13 +32,47 @@ export { DuplicateCTEError, InvalidCTENameError, CTENotFoundError } from './CTEE
* Implementations are expected to surface the same error behaviour exercised in
* packages/core/tests/models/SelectQuery.cte-management.test.ts.
*/
export interface CTEManagement {
addCTE(name: string, query: SelectQuery, options?: CTEOptions): this;
removeCTE(name: string): this;
hasCTE(name: string): boolean;
getCTENames(): string[];
replaceCTE(name: string, query: SelectQuery, options?: CTEOptions): this;
}
export interface CTEManagement {
addCTE(name: string, query: SelectQuery, options?: CTEOptions): this;
removeCTE(name: string): this;
hasCTE(name: string): boolean;
getCTENames(): string[];
replaceCTE(name: string, query: SelectQuery, options?: CTEOptions): this;
}

export interface InsertQueryConversionOptions {
target: string;
columns?: string[];
}

export interface UpdateQueryConversionOptions {
target: string;
primaryKeys: string | string[];
columns?: string[];
sourceAlias?: string;
}

export interface DeleteQueryConversionOptions {
target: string;
primaryKeys: string | string[];
columns?: string[];
sourceAlias?: string;
}

export type MergeMatchedAction = "update" | "delete" | "doNothing";
export type MergeNotMatchedAction = "insert" | "doNothing";
export type MergeNotMatchedBySourceAction = "delete" | "doNothing";

export interface MergeQueryConversionOptions {
target: string;
primaryKeys: string | string[];
updateColumns?: string[];
insertColumns?: string[];
sourceAlias?: string;
matchedAction?: MergeMatchedAction;
notMatchedAction?: MergeNotMatchedAction;
notMatchedBySourceAction?: MergeNotMatchedBySourceAction;
}

/**
* Shared interface implemented by all select query variants.
Expand All @@ -48,10 +85,22 @@ export interface CTEManagement {
* ```
* Related tests: packages/core/tests/models/SelectQuery.toSimpleQuery.test.ts
*/
export interface SelectQuery extends SqlComponent {
readonly __selectQueryType: 'SelectQuery'; // Discriminator property for type safety
headerComments: string[] | null;
setParameter(name: string, value: SqlParameterValue): this;
toSimpleQuery(): SimpleSelectQuery;
}
export { SimpleSelectQuery, BinarySelectQuery, ValuesQuery, InsertQuery };
export interface SelectQuery extends SqlComponent {
readonly __selectQueryType: 'SelectQuery'; // Discriminator property for type safety
headerComments: string[] | null;
setParameter(name: string, value: SqlParameterValue): this;
toSimpleQuery(): SimpleSelectQuery;
toInsertQuery(options: InsertQueryConversionOptions): InsertQuery;
toUpdateQuery(options: UpdateQueryConversionOptions): UpdateQuery;
toDeleteQuery(options: DeleteQueryConversionOptions): DeleteQuery;
toMergeQuery(options: MergeQueryConversionOptions): MergeQuery;
}
export {
SimpleSelectQuery,
BinarySelectQuery,
ValuesQuery,
InsertQuery,
UpdateQuery,
DeleteQuery,
MergeQuery
};
74 changes: 61 additions & 13 deletions packages/core/src/models/SimpleSelectQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,27 @@ import { ValueParser } from "../parsers/ValueParser";
import { CTENormalizer } from "../transformers/CTENormalizer";
import { SelectableColumnCollector } from "../transformers/SelectableColumnCollector";
import { SourceParser } from "../parsers/SourceParser";
import { BinarySelectQuery } from "./BinarySelectQuery";
import type { SelectQuery, CTEOptions, CTEManagement } from "./SelectQuery";
import { DuplicateCTEError, InvalidCTENameError, CTENotFoundError } from "./CTEError";
import { SelectQueryParser } from "../parsers/SelectQueryParser";
import { Formatter } from "../transformers/Formatter";
import { TableColumnResolver } from "../transformers/TableColumnResolver";
import { UpstreamSelectQueryFinder } from "../transformers/UpstreamSelectQueryFinder";
import { QueryBuilder } from "../transformers/QueryBuilder";
import { ParameterHelper } from "../utils/ParameterHelper";
import { BinarySelectQuery } from "./BinarySelectQuery";
import type {
SelectQuery,
CTEOptions,
CTEManagement,
InsertQueryConversionOptions,
UpdateQueryConversionOptions,
DeleteQueryConversionOptions,
MergeQueryConversionOptions
} from "./SelectQuery";
import { DuplicateCTEError, InvalidCTENameError, CTENotFoundError } from "./CTEError";
import { SelectQueryParser } from "../parsers/SelectQueryParser";
import { Formatter } from "../transformers/Formatter";
import { TableColumnResolver } from "../transformers/TableColumnResolver";
import { UpstreamSelectQueryFinder } from "../transformers/UpstreamSelectQueryFinder";
import { QueryBuilder } from "../transformers/QueryBuilder";
import { ParameterHelper } from "../utils/ParameterHelper";
import type { InsertQuery } from "./InsertQuery";
import type { UpdateQuery } from "./UpdateQuery";
import type { DeleteQuery } from "./DeleteQuery";
import type { MergeQuery } from "./MergeQuery";

/**
* Represents a single SELECT statement with full clause support (WITH, JOIN, GROUP BY, etc.).
Expand Down Expand Up @@ -114,10 +126,46 @@ export class SimpleSelectQuery extends SqlComponent implements SelectQuery, CTEM
* @param rightQuery The right side of the UNION ALL
* @returns A new BinarySelectQuery representing "this UNION ALL rightQuery"
*/
public toUnionAll(rightQuery: SelectQuery): BinarySelectQuery {
return this.toBinaryQuery('union all', rightQuery);
}

public toUnionAll(rightQuery: SelectQuery): BinarySelectQuery {
return this.toBinaryQuery('union all', rightQuery);
}

/**
* Converts this query into an INSERT statement definition.
* @remarks
* Calling this method may reorder the current SELECT clause to match the requested column order.
*/
public toInsertQuery(options: InsertQueryConversionOptions): InsertQuery {
return QueryBuilder.buildInsertQuery(this, options);
}

/**
* Converts this query into an UPDATE statement definition.
* @remarks
* The conversion may reorder the SELECT list so that primary keys and updated columns align with the target table.
*/
public toUpdateQuery(options: UpdateQueryConversionOptions): UpdateQuery {
return QueryBuilder.buildUpdateQuery(this, options);
}

/**
* Converts this query into a DELETE statement definition.
* @remarks
* The SELECT clause may be reordered to ensure primary keys and comparison columns appear first.
*/
public toDeleteQuery(options: DeleteQueryConversionOptions): DeleteQuery {
return QueryBuilder.buildDeleteQuery(this, options);
}

/**
* Converts this query into a MERGE statement definition.
* @remarks
* This method may reorder the SELECT clause to align with the specified MERGE column lists.
*/
public toMergeQuery(options: MergeQueryConversionOptions): MergeQuery {
return QueryBuilder.buildMergeQuery(this, options);
}

/**
* Creates a new BinarySelectQuery with this query as the left side and the provided query as the right side,
* using INTERSECT as the operator.
Expand Down
6 changes: 6 additions & 0 deletions packages/core/src/models/SqlPrintToken.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,12 @@ export enum SqlPrintTokenContainerType {
ReturningClause = "ReturningClause",
SetClauseItem = "SetClauseItem",
CreateTableQuery = "CreateTableQuery",
MergeQuery = "MergeQuery",
MergeWhenClause = "MergeWhenClause",
MergeUpdateAction = "MergeUpdateAction",
MergeDeleteAction = "MergeDeleteAction",
MergeInsertAction = "MergeInsertAction",
MergeDoNothingAction = "MergeDoNothingAction",
CommentBlock = "CommentBlock", // Container for comment tokens with conditional newlines
// Add more as needed
}
Expand Down
65 changes: 53 additions & 12 deletions packages/core/src/models/ValuesQuery.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
import { ParameterHelper } from "../utils/ParameterHelper";
import { ParameterCollector } from "../transformers/ParameterCollector";
import { QueryBuilder } from "../transformers/QueryBuilder";
import { SelectQuery } from "./SelectQuery";
import { SimpleSelectQuery } from "./SimpleSelectQuery";
import { SqlParameterValue } from "./ValueComponent";
import { SqlComponent } from "./SqlComponent";
import { TupleExpression } from "./ValueComponent";
import { ParameterHelper } from "../utils/ParameterHelper";
import { QueryBuilder } from "../transformers/QueryBuilder";
import type {
SelectQuery,
InsertQueryConversionOptions,
UpdateQueryConversionOptions,
DeleteQueryConversionOptions,
MergeQueryConversionOptions
} from "./SelectQuery";
import { SimpleSelectQuery } from "./SimpleSelectQuery";
import { SqlParameterValue } from "./ValueComponent";
import { SqlComponent } from "./SqlComponent";
import { TupleExpression } from "./ValueComponent";
import type { InsertQuery } from "./InsertQuery";
import type { UpdateQuery } from "./UpdateQuery";
import type { DeleteQuery } from "./DeleteQuery";
import type { MergeQuery } from "./MergeQuery";

/**
* Represents a VALUES query in SQL.
Expand All @@ -28,10 +37,42 @@ export class ValuesQuery extends SqlComponent implements SelectQuery {
this.columnAliases = columnAliases;
}

public toSimpleQuery(): SimpleSelectQuery {
return QueryBuilder.buildSimpleQuery(this);
}

public toSimpleQuery(): SimpleSelectQuery {
return QueryBuilder.buildSimpleQuery(this);
}

/**
* Converts this VALUES query into an INSERT statement definition.
* @remarks The conversion may reorder the generated SELECT clause to align with the requested column order.
*/
public toInsertQuery(options: InsertQueryConversionOptions): InsertQuery {
return this.toSimpleQuery().toInsertQuery(options);
}

/**
* Converts this VALUES query into an UPDATE statement definition.
* @remarks The conversion may reorder the generated SELECT clause to align with the requested column order.
*/
public toUpdateQuery(options: UpdateQueryConversionOptions): UpdateQuery {
return this.toSimpleQuery().toUpdateQuery(options);
}

/**
* Converts this VALUES query into a DELETE statement definition.
* @remarks The conversion may reorder the generated SELECT clause to align with the requested column order.
*/
public toDeleteQuery(options: DeleteQueryConversionOptions): DeleteQuery {
return this.toSimpleQuery().toDeleteQuery(options);
}

/**
* Converts this VALUES query into a MERGE statement definition.
* @remarks The conversion may reorder the generated SELECT clause to align with the requested column order.
*/
public toMergeQuery(options: MergeQueryConversionOptions): MergeQuery {
return this.toSimpleQuery().toMergeQuery(options);
}

/**
* Sets the value of a parameter by name in this query.
* @param name Parameter name
Expand Down
Loading
Loading