-
Notifications
You must be signed in to change notification settings - Fork 1
feat: Add DDL parsers for DROP TABLE, DROP INDEX, and DROP CONSTRAINT statements #216
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,34 +1,187 @@ | ||
| import { SqlComponent } from "./SqlComponent"; | ||
| import type { SelectQuery } from "./SelectQuery"; | ||
| import { ColumnReference, FunctionCall, IdentifierString, RawString } from "./ValueComponent"; | ||
| import { | ||
| ColumnReference, | ||
| FunctionCall, | ||
| IdentifierString, | ||
| RawString, | ||
| ValueComponent, | ||
| TypeValue, | ||
| QualifiedName | ||
| } from "./ValueComponent"; | ||
| import { SimpleSelectQuery } from "./SimpleSelectQuery"; | ||
| import { SelectClause, SelectItem, FromClause, TableSource, SourceExpression } from "./Clause"; | ||
| import { SelectValueCollector } from "../transformers/SelectValueCollector"; | ||
|
|
||
| // Represents a CREATE TABLE query model | ||
| // Supports temporary tables and AS SELECT ... | ||
| export type ReferentialAction = 'cascade' | 'restrict' | 'no action' | 'set null' | 'set default'; | ||
| export type ConstraintDeferrability = 'deferrable' | 'not deferrable' | null; | ||
| export type ConstraintInitially = 'immediate' | 'deferred' | null; | ||
| export type MatchType = 'full' | 'partial' | 'simple' | null; | ||
|
|
||
| /** | ||
| * Represents a REFERENCES clause definition that can be shared between column and table constraints. | ||
| */ | ||
| export class ReferenceDefinition extends SqlComponent { | ||
| static kind = Symbol("ReferenceDefinition"); | ||
| targetTable: QualifiedName; | ||
| columns: IdentifierString[] | null; | ||
| matchType: MatchType; | ||
| onDelete: ReferentialAction | null; | ||
| onUpdate: ReferentialAction | null; | ||
| deferrable: ConstraintDeferrability; | ||
| initially: ConstraintInitially; | ||
|
|
||
| constructor(params: { | ||
| targetTable: QualifiedName; | ||
| columns?: IdentifierString[] | null; | ||
| matchType?: MatchType; | ||
| onDelete?: ReferentialAction | null; | ||
| onUpdate?: ReferentialAction | null; | ||
| deferrable?: ConstraintDeferrability; | ||
| initially?: ConstraintInitially; | ||
| }) { | ||
| super(); | ||
| this.targetTable = params.targetTable; | ||
| this.columns = params.columns ? [...params.columns] : null; | ||
| this.matchType = params.matchType ?? null; | ||
| this.onDelete = params.onDelete ?? null; | ||
| this.onUpdate = params.onUpdate ?? null; | ||
| this.deferrable = params.deferrable ?? null; | ||
| this.initially = params.initially ?? null; | ||
| } | ||
| } | ||
|
|
||
| export type ColumnConstraintKind = | ||
| | 'not-null' | ||
| | 'null' | ||
| | 'default' | ||
| | 'primary-key' | ||
| | 'unique' | ||
| | 'references' | ||
| | 'check' | ||
| | 'generated-always-identity' | ||
| | 'generated-by-default-identity' | ||
| | 'raw'; | ||
|
|
||
| /** | ||
| * Column-level constraint definition. | ||
| */ | ||
| export class ColumnConstraintDefinition extends SqlComponent { | ||
| static kind = Symbol("ColumnConstraintDefinition"); | ||
| kind: ColumnConstraintKind; | ||
| constraintName?: IdentifierString; | ||
| defaultValue?: ValueComponent; | ||
| checkExpression?: ValueComponent; | ||
| reference?: ReferenceDefinition; | ||
| rawClause?: RawString; | ||
|
|
||
| constructor(params: { | ||
| kind: ColumnConstraintKind; | ||
| constraintName?: IdentifierString; | ||
| defaultValue?: ValueComponent; | ||
| checkExpression?: ValueComponent; | ||
| reference?: ReferenceDefinition; | ||
| rawClause?: RawString; | ||
| }) { | ||
| super(); | ||
| this.kind = params.kind; | ||
| this.constraintName = params.constraintName; | ||
| this.defaultValue = params.defaultValue; | ||
| this.checkExpression = params.checkExpression; | ||
| this.reference = params.reference; | ||
| this.rawClause = params.rawClause; | ||
| } | ||
| } | ||
|
|
||
| export type TableConstraintKind = 'primary-key' | 'unique' | 'foreign-key' | 'check' | 'raw'; | ||
|
|
||
| /** | ||
| * Table-level constraint definition. | ||
| */ | ||
| export class TableConstraintDefinition extends SqlComponent { | ||
| static kind = Symbol("TableConstraintDefinition"); | ||
| kind: TableConstraintKind; | ||
| constraintName?: IdentifierString; | ||
| columns: IdentifierString[] | null; | ||
| reference?: ReferenceDefinition; | ||
| checkExpression?: ValueComponent; | ||
| rawClause?: RawString; | ||
| deferrable: ConstraintDeferrability; | ||
| initially: ConstraintInitially; | ||
|
|
||
| constructor(params: { | ||
| kind: TableConstraintKind; | ||
| constraintName?: IdentifierString; | ||
| columns?: IdentifierString[] | null; | ||
| reference?: ReferenceDefinition; | ||
| checkExpression?: ValueComponent; | ||
| rawClause?: RawString; | ||
| deferrable?: ConstraintDeferrability; | ||
| initially?: ConstraintInitially; | ||
| }) { | ||
| super(); | ||
| this.kind = params.kind; | ||
| this.constraintName = params.constraintName; | ||
| this.columns = params.columns ? [...params.columns] : null; | ||
| this.reference = params.reference; | ||
| this.checkExpression = params.checkExpression; | ||
| this.rawClause = params.rawClause; | ||
| this.deferrable = params.deferrable ?? null; | ||
| this.initially = params.initially ?? null; | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Represents a single column definition within CREATE TABLE. | ||
| */ | ||
| export class TableColumnDefinition extends SqlComponent { | ||
| static kind = Symbol("TableColumnDefinition"); | ||
| name: IdentifierString; | ||
| dataType?: TypeValue | RawString; | ||
| constraints: ColumnConstraintDefinition[]; | ||
|
|
||
| constructor(params: { | ||
| name: IdentifierString; | ||
| dataType?: TypeValue | RawString; | ||
| constraints?: ColumnConstraintDefinition[]; | ||
| }) { | ||
| super(); | ||
| this.name = params.name; | ||
| this.dataType = params.dataType; | ||
| this.constraints = params.constraints ? [...params.constraints] : []; | ||
| } | ||
| } | ||
|
|
||
| // Represents a CREATE TABLE query model that supports column definitions and AS SELECT variants. | ||
| export class CreateTableQuery extends SqlComponent { | ||
| /** SqlComponent kind symbol for visitor pattern */ | ||
| static kind = Symbol("CreateTableQuery"); | ||
| /** Table name (with optional schema) */ | ||
| tableName: IdentifierString; | ||
| /** If true, this is a temporary table */ | ||
| namespaces: string[] | null; | ||
| isTemporary: boolean; | ||
| /** If true, the statement includes IF NOT EXISTS */ | ||
| ifNotExists: boolean; | ||
| /** Optional: SELECT query for AS SELECT ... */ | ||
| columns: TableColumnDefinition[]; | ||
| tableConstraints: TableConstraintDefinition[]; | ||
| tableOptions?: RawString | null; | ||
| asSelectQuery?: SelectQuery; | ||
|
|
||
| constructor(params: { | ||
| tableName: string; | ||
| namespaces?: string[] | null; | ||
| isTemporary?: boolean; | ||
| ifNotExists?: boolean; | ||
| columns?: TableColumnDefinition[]; | ||
| tableConstraints?: TableConstraintDefinition[]; | ||
| tableOptions?: RawString | null; | ||
| asSelectQuery?: SelectQuery; | ||
| }) { | ||
| super(); | ||
| this.tableName = new IdentifierString(params.tableName); | ||
| this.namespaces = params.namespaces ? [...params.namespaces] : null; | ||
| this.isTemporary = params.isTemporary ?? false; | ||
| this.ifNotExists = params.ifNotExists ?? false; | ||
| this.columns = params.columns ? [...params.columns] : []; | ||
| this.tableConstraints = params.tableConstraints ? [...params.tableConstraints] : []; | ||
| this.tableOptions = params.tableOptions ?? null; | ||
| this.asSelectQuery = params.asSelectQuery; | ||
| } | ||
|
|
||
|
|
@@ -37,23 +190,36 @@ export class CreateTableQuery extends SqlComponent { | |
| */ | ||
| getSelectQuery(): SimpleSelectQuery { | ||
| let selectItems: SelectItem[]; | ||
|
|
||
| // Prefer explicit AS SELECT query columns when present. | ||
| if (this.asSelectQuery) { | ||
| // Use SelectValueCollector to get columns from asSelectQuery | ||
| const collector = new SelectValueCollector(); | ||
| const values = collector.collect(this.asSelectQuery); | ||
| selectItems = values.map(val => new SelectItem(val.value, val.name)); | ||
| } else if (this.columns.length > 0) { | ||
| // Use defined column names when the table definition is DDL-based. | ||
| selectItems = this.columns.map(column => new SelectItem( | ||
| new ColumnReference(null, column.name), | ||
| column.name.name | ||
| )); | ||
| } else { | ||
| // fallback: wildcard | ||
| // Fallback to wild-card selection when no column metadata is available. | ||
| selectItems = [new SelectItem(new RawString("*"))]; | ||
| } | ||
|
|
||
| // Build a simple SELECT ... FROM table query. | ||
| const qualifiedName = this.namespaces && this.namespaces.length > 0 | ||
| ? [...this.namespaces, this.tableName.name].join(".") | ||
| : this.tableName.name; | ||
|
|
||
| return new SimpleSelectQuery({ | ||
| selectClause: new SelectClause(selectItems), | ||
| fromClause: new FromClause( | ||
| new SourceExpression( | ||
| new TableSource(null, this.tableName.name), | ||
| new TableSource(null, qualifiedName), | ||
| null | ||
| ), | ||
| null // joins | ||
| null | ||
| ), | ||
| }); | ||
| } | ||
|
|
@@ -62,16 +228,20 @@ export class CreateTableQuery extends SqlComponent { | |
| * Returns a SelectQuery that counts all rows in this table. | ||
| */ | ||
| getCountQuery(): SimpleSelectQuery { | ||
| const qualifiedName = this.namespaces && this.namespaces.length > 0 | ||
| ? [...this.namespaces, this.tableName.name].join(".") | ||
| : this.tableName.name; | ||
|
|
||
|
Comment on lines
+231
to
+234
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same issue in getCountQuery: use namespaces-aware TableSource. Ensure proper qualification and quoting. - const qualifiedName = this.namespaces && this.namespaces.length > 0
- ? [...this.namespaces, this.tableName.name].join(".")
- : this.tableName.name;
+ const tableSource = new TableSource(this.namespaces ?? null, this.tableName);
@@
- new TableSource(null, qualifiedName),
+ tableSource,Also applies to: 241-245 🤖 Prompt for AI Agents |
||
| return new SimpleSelectQuery({ | ||
| selectClause: new SelectClause([ | ||
| new SelectItem(new FunctionCall(null, "count", new ColumnReference(null, "*"), null)) | ||
| ]), | ||
| fromClause: new FromClause( | ||
| new SourceExpression( | ||
| new TableSource(null, this.tableName.name), | ||
| new TableSource(null, qualifiedName), | ||
| null | ||
| ), | ||
| null // joins | ||
| null | ||
| ), | ||
| }); | ||
| } | ||
|
|
||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Schema qualification bug: passing dotted string as table name breaks quoting.
You build "schema.table" as a single IdentifierString with namespaces=null, yielding wrong output like "schema.table". Pass namespaces and table separately to TableSource.
Also applies to: 219-223
🤖 Prompt for AI Agents