diff --git a/src/ts_generator/sql_parser/translate_query.rs b/src/ts_generator/sql_parser/translate_query.rs index a295b18b..a5bab621 100644 --- a/src/ts_generator/sql_parser/translate_query.rs +++ b/src/ts_generator/sql_parser/translate_query.rs @@ -1,9 +1,12 @@ use async_recursion::async_recursion; -use sqlparser::ast::{FunctionArg, FunctionArgExpr, Query, Select, SelectItem, SetExpr, TableFactor, TableWithJoins}; +use sqlparser::ast::{ + FunctionArg, FunctionArgExpr, LimitClause, Query, Select, SelectItem, SetExpr, TableFactor, TableWithJoins, +}; use std::collections::HashMap; use super::expressions::{ - translate_expr::translate_expr, translate_table_with_joins::translate_table_with_joins, + translate_expr::{get_expr_placeholder, translate_expr}, + translate_table_with_joins::translate_table_with_joins, translate_wildcard_expr::translate_wildcard_expr, }; use crate::ts_generator::sql_parser::quoted_strings::{DisplayIndent, DisplayTableAlias}; @@ -244,10 +247,23 @@ pub async fn translate_query( let body = *query.body.clone(); match body { SetExpr::Select(select) => { - translate_select(ts_query, table_with_joins, &select, db_conn, alias, is_selection).await + translate_select(ts_query, table_with_joins, &select, db_conn, alias, is_selection).await? } _ => Err(TsGeneratorError::Unknown(format!( "Unknown query type while processing query: {query}" - ))), + )))?, + } + + if let Some(limit_clause) = &query.limit_clause { + let exprs = match limit_clause { + LimitClause::LimitOffset { limit, offset, .. } => { + vec![limit.as_ref(), offset.as_ref().map(|offset| &offset.value)] + } + LimitClause::OffsetCommaLimit { offset, limit } => vec![Some(offset), Some(limit)], + }; + for expr in exprs.into_iter().flatten() { + ts_query.insert_param(&TsFieldType::Number, &false, &get_expr_placeholder(expr))?; + } } + Ok(()) } diff --git a/tests/demo/clauses/limit_offset.queries.ts b/tests/demo/clauses/limit_offset.queries.ts index 5ea75d95..99354523 100644 --- a/tests/demo/clauses/limit_offset.queries.ts +++ b/tests/demo/clauses/limit_offset.queries.ts @@ -46,7 +46,7 @@ export interface ILimitWithOrderByQuery { result: ILimitWithOrderByResult; } -export type PaginationWithParamsParams = [string | null]; +export type PaginationWithParamsParams = [string | null, number, number]; export interface IPaginationWithParamsResult { id: number; diff --git a/tests/demo/clauses/limit_offset.snapshot.ts b/tests/demo/clauses/limit_offset.snapshot.ts index 5ea75d95..99354523 100644 --- a/tests/demo/clauses/limit_offset.snapshot.ts +++ b/tests/demo/clauses/limit_offset.snapshot.ts @@ -46,7 +46,7 @@ export interface ILimitWithOrderByQuery { result: ILimitWithOrderByResult; } -export type PaginationWithParamsParams = [string | null]; +export type PaginationWithParamsParams = [string | null, number, number]; export interface IPaginationWithParamsResult { id: number; diff --git a/tests/mysql_query_parameters.rs b/tests/mysql_query_parameters.rs index fbe5fcf5..679a9d18 100644 --- a/tests/mysql_query_parameters.rs +++ b/tests/mysql_query_parameters.rs @@ -267,4 +267,50 @@ export interface ISomeQueryQuery { result: ISomeQueryResult; } "#, min_mysql: (5, 7)); + + #[rustfmt::skip] +run_test!(should_pick_query_params_from_limit_and_offset, TestConfig::new("mysql", true, None, None), + +//// TS query //// +r#" +const someQuery = sql`SELECT id, name FROM items WHERE rarity = ? LIMIT ? OFFSET ?`; +"#, + +//// Generated TS interfaces //// +r#" +export type SomeQueryParams = [string | null, number, number]; + +export interface ISomeQueryResult { + id: number; + name: string; +} + +export interface ISomeQueryQuery { + params: SomeQueryParams; + result: ISomeQueryResult; +} +"#); + + #[rustfmt::skip] +run_test!(should_pick_query_params_from_offset_comma_limit, TestConfig::new("mysql", true, None, None), + +//// TS query //// +r#" +const someQuery = sql`SELECT id, name FROM items WHERE rarity = ? LIMIT ?, ?`; +"#, + +//// Generated TS interfaces //// +r#" +export type SomeQueryParams = [string | null, number, number]; + +export interface ISomeQueryResult { + id: number; + name: string; +} + +export interface ISomeQueryQuery { + params: SomeQueryParams; + result: ISomeQueryResult; +} +"#); } diff --git a/tests/sqlite_query_parameters.rs b/tests/sqlite_query_parameters.rs index b9bc2dca..fde6bbd2 100644 --- a/tests/sqlite_query_parameters.rs +++ b/tests/sqlite_query_parameters.rs @@ -273,6 +273,39 @@ export interface ISomeQueryResult { price: number | null; } +export interface ISomeQueryQuery { + params: SomeQueryParams; + result: ISomeQueryResult; +} +"#; + + assert_eq!( + expected.trim().to_string().flatten(), + type_file.trim().to_string().flatten() + ); + Ok(()) + } + + #[test] + fn should_pick_query_params_from_limit_and_offset() -> Result<(), Box> { + let schema = "CREATE TABLE items (id INTEGER PRIMARY KEY NOT NULL, name TEXT NOT NULL, price REAL);"; + + let ts_content = r#" +import { sql } from 'sqlx-ts' + +const someQuery = sql`SELECT id, name FROM items WHERE name = ? LIMIT ? OFFSET ?` +"#; + + let (_, type_file) = run_sqlite_test(schema, ts_content, true)?; + + let expected = r#" +export type SomeQueryParams = [string, number, number]; + +export interface ISomeQueryResult { + id: number; + name: string; +} + export interface ISomeQueryQuery { params: SomeQueryParams; result: ISomeQueryResult;