diff --git a/src/ts_generator/sql_parser/translate_stmt.rs b/src/ts_generator/sql_parser/translate_stmt.rs index 331a63f7..f967500d 100644 --- a/src/ts_generator/sql_parser/translate_stmt.rs +++ b/src/ts_generator/sql_parser/translate_stmt.rs @@ -50,9 +50,17 @@ pub async fn translate_stmt( Statement::Delete(delete) => match &delete.from { FromTable::WithFromKeyword(from) => { let table_name = get_default_table(from); - let table_name = table_name.as_str(); + let table_name_str = table_name.as_str(); let selection = delete.selection.to_owned().unwrap(); - translate_delete(ts_query, &selection, table_name, db_conn).await?; + translate_delete(ts_query, &selection, table_name_str, db_conn).await?; + + // Handle RETURNING clause if present + if delete.returning.is_some() { + let returning = delete.returning.clone().unwrap(); + let query_for_logging = sql_statement.to_string(); + let query_for_logging_str = &query_for_logging.as_str(); + translate_insert_returning(ts_query, &returning, table_name_str, db_conn, query_for_logging_str).await?; + } } FromTable::WithoutKeyword(_) => Err(TsGeneratorError::FromWithoutKeyword(sql_statement.to_string()))?, }, @@ -61,7 +69,7 @@ pub async fn translate_stmt( assignments, from, selection, - returning: _, + returning, or: _, limit: _, } => { @@ -79,6 +87,24 @@ pub async fn translate_stmt( }; translate_update(ts_query, table, assignments, &from_table, selection, db_conn).await?; + + // Handle RETURNING clause if present + if returning.is_some() { + let returning_items = returning.clone().unwrap(); + // Extract table name from TableWithJoins + let table_name = get_default_table(&vec![table.clone()]); + let table_name_str = table_name.as_str(); + let query_for_logging = sql_statement.to_string(); + let query_for_logging_str = &query_for_logging.as_str(); + translate_insert_returning( + ts_query, + &returning_items, + table_name_str, + db_conn, + query_for_logging_str, + ) + .await?; + } } _ => {} } diff --git a/tests/demo/delete/delete_returning.queries.ts b/tests/demo/delete/delete_returning.queries.ts new file mode 100644 index 00000000..a43bc19b --- /dev/null +++ b/tests/demo/delete/delete_returning.queries.ts @@ -0,0 +1,50 @@ +export type DeleteReturningAllParams = [number]; + +export interface IDeleteReturningAllResult { + flavorText: string | null; + id: number; + inventoryId: number | null; + name: string; + rarity: string | null; +} + +export interface IDeleteReturningAllQuery { + params: DeleteReturningAllParams; + result: IDeleteReturningAllResult; +} + +export type DeleteReturningSpecificParams = [number]; + +export interface IDeleteReturningSpecificResult { + id: number; + name: string; +} + +export interface IDeleteReturningSpecificQuery { + params: DeleteReturningSpecificParams; + result: IDeleteReturningSpecificResult; +} + +export type DeleteReturningWithAliasParams = [number]; + +export interface IDeleteReturningWithAliasResult { + deletedId: number; + deletedName: string; +} + +export interface IDeleteReturningWithAliasQuery { + params: DeleteReturningWithAliasParams; + result: IDeleteReturningWithAliasResult; +} + +export type DeleteReturningExpressionParams = [number]; + +export interface IDeleteReturningExpressionResult { + id: number; + upperName: string; +} + +export interface IDeleteReturningExpressionQuery { + params: DeleteReturningExpressionParams; + result: IDeleteReturningExpressionResult; +} diff --git a/tests/demo/delete/delete_returning.snapshot.ts b/tests/demo/delete/delete_returning.snapshot.ts new file mode 100644 index 00000000..a43bc19b --- /dev/null +++ b/tests/demo/delete/delete_returning.snapshot.ts @@ -0,0 +1,50 @@ +export type DeleteReturningAllParams = [number]; + +export interface IDeleteReturningAllResult { + flavorText: string | null; + id: number; + inventoryId: number | null; + name: string; + rarity: string | null; +} + +export interface IDeleteReturningAllQuery { + params: DeleteReturningAllParams; + result: IDeleteReturningAllResult; +} + +export type DeleteReturningSpecificParams = [number]; + +export interface IDeleteReturningSpecificResult { + id: number; + name: string; +} + +export interface IDeleteReturningSpecificQuery { + params: DeleteReturningSpecificParams; + result: IDeleteReturningSpecificResult; +} + +export type DeleteReturningWithAliasParams = [number]; + +export interface IDeleteReturningWithAliasResult { + deletedId: number; + deletedName: string; +} + +export interface IDeleteReturningWithAliasQuery { + params: DeleteReturningWithAliasParams; + result: IDeleteReturningWithAliasResult; +} + +export type DeleteReturningExpressionParams = [number]; + +export interface IDeleteReturningExpressionResult { + id: number; + upperName: string; +} + +export interface IDeleteReturningExpressionQuery { + params: DeleteReturningExpressionParams; + result: IDeleteReturningExpressionResult; +} diff --git a/tests/demo/delete/delete_returning.ts b/tests/demo/delete/delete_returning.ts new file mode 100644 index 00000000..ed7d932c --- /dev/null +++ b/tests/demo/delete/delete_returning.ts @@ -0,0 +1,30 @@ +import { sql } from 'sqlx-ts' + +// Issue #226: DELETE with RETURNING clause should generate types +const deleteReturningAll = sql` +-- @name: delete returning all +DELETE FROM items +WHERE id = $1 +RETURNING * +` + +const deleteReturningSpecific = sql` +-- @name: delete returning specific +DELETE FROM items +WHERE id = $1 +RETURNING id, name +` + +const deleteReturningWithAlias = sql` +-- @name: delete returning with alias +DELETE FROM items +WHERE id = $1 +RETURNING id AS deleted_id, name AS deleted_name +` + +const deleteReturningExpression = sql` +-- @name: delete returning expression +DELETE FROM items +WHERE id = $1 +RETURNING id, UPPER(name) AS upper_name +` diff --git a/tests/demo/update/update_returning.queries.ts b/tests/demo/update/update_returning.queries.ts new file mode 100644 index 00000000..56a965ee --- /dev/null +++ b/tests/demo/update/update_returning.queries.ts @@ -0,0 +1,50 @@ +export type UpdateReturningAllParams = [string, number]; + +export interface IUpdateReturningAllResult { + flavorText: string | null; + id: number; + inventoryId: number | null; + name: string; + rarity: string | null; +} + +export interface IUpdateReturningAllQuery { + params: UpdateReturningAllParams; + result: IUpdateReturningAllResult; +} + +export type UpdateReturningSpecificParams = [string, number]; + +export interface IUpdateReturningSpecificResult { + id: number; + name: string; +} + +export interface IUpdateReturningSpecificQuery { + params: UpdateReturningSpecificParams; + result: IUpdateReturningSpecificResult; +} + +export type UpdateReturningWithAliasParams = [string, number]; + +export interface IUpdateReturningWithAliasResult { + updatedId: number; + updatedName: string; +} + +export interface IUpdateReturningWithAliasQuery { + params: UpdateReturningWithAliasParams; + result: IUpdateReturningWithAliasResult; +} + +export type UpdateReturningExpressionParams = [string, number]; + +export interface IUpdateReturningExpressionResult { + id: number; + lowerName: string; +} + +export interface IUpdateReturningExpressionQuery { + params: UpdateReturningExpressionParams; + result: IUpdateReturningExpressionResult; +} diff --git a/tests/demo/update/update_returning.snapshot.ts b/tests/demo/update/update_returning.snapshot.ts new file mode 100644 index 00000000..56a965ee --- /dev/null +++ b/tests/demo/update/update_returning.snapshot.ts @@ -0,0 +1,50 @@ +export type UpdateReturningAllParams = [string, number]; + +export interface IUpdateReturningAllResult { + flavorText: string | null; + id: number; + inventoryId: number | null; + name: string; + rarity: string | null; +} + +export interface IUpdateReturningAllQuery { + params: UpdateReturningAllParams; + result: IUpdateReturningAllResult; +} + +export type UpdateReturningSpecificParams = [string, number]; + +export interface IUpdateReturningSpecificResult { + id: number; + name: string; +} + +export interface IUpdateReturningSpecificQuery { + params: UpdateReturningSpecificParams; + result: IUpdateReturningSpecificResult; +} + +export type UpdateReturningWithAliasParams = [string, number]; + +export interface IUpdateReturningWithAliasResult { + updatedId: number; + updatedName: string; +} + +export interface IUpdateReturningWithAliasQuery { + params: UpdateReturningWithAliasParams; + result: IUpdateReturningWithAliasResult; +} + +export type UpdateReturningExpressionParams = [string, number]; + +export interface IUpdateReturningExpressionResult { + id: number; + lowerName: string; +} + +export interface IUpdateReturningExpressionQuery { + params: UpdateReturningExpressionParams; + result: IUpdateReturningExpressionResult; +} diff --git a/tests/demo/update/update_returning.ts b/tests/demo/update/update_returning.ts new file mode 100644 index 00000000..392a8cf6 --- /dev/null +++ b/tests/demo/update/update_returning.ts @@ -0,0 +1,34 @@ +import { sql } from 'sqlx-ts' + +// Issue #226: UPDATE with RETURNING clause should generate types +const updateReturningAll = sql` +-- @name: update returning all +UPDATE items +SET name = $1 +WHERE id = $2 +RETURNING * +` + +const updateReturningSpecific = sql` +-- @name: update returning specific +UPDATE items +SET name = $1 +WHERE id = $2 +RETURNING id, name +` + +const updateReturningWithAlias = sql` +-- @name: update returning with alias +UPDATE items +SET name = $1 +WHERE id = $2 +RETURNING id AS updated_id, name AS updated_name +` + +const updateReturningExpression = sql` +-- @name: update returning expression +UPDATE items +SET name = $1 +WHERE id = $2 +RETURNING id, LOWER(name) AS lower_name +`