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
2 changes: 1 addition & 1 deletion .github/workflows/rust.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ jobs:
cache-provider: "github"

- name: Run clippy
run: cargo clippy
run: cargo clippy --lib --all-features -- -D warnings

- name: Run rustfmt
run: cargo fmt -- --check
16 changes: 16 additions & 0 deletions src/ts_generator/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,22 @@ pub enum TsGeneratorError {
TableFactorWhileProcessingTableWithJoins(String),
#[error("[E014] Failed to find a table name from a FROM statement: statement: `{0}`")]
UnknownErrorWhileProcessingTableWithJoins(String),
#[error("[E015] Table expressions are not supported in INSERT statements - query: `{0}`")]
TableExpressionInInsertStatement(String),
#[error("[E016] Column '{column}' not found in table '{table}'. Available columns: {available_columns}")]
ColumnNotFoundInTable {
column: String,
table: String,
available_columns: String,
},
#[error("[E017] Failed to process INSERT statement: {reason}. Query: `{query}`")]
InsertStatementProcessingFailed { reason: String, query: String },
#[error("[E018] Failed to process UPDATE statement: {reason}. Query: `{query}`")]
UpdateStatementProcessingFailed { reason: String, query: String },
#[error("[E019] Table '{table}' not found in database schema. Check that the table exists and is accessible.")]
TableNotFoundInSchema { table: String },
#[error("[E020] Failed to infer table name while processing WHERE clause. Query: `{query}`")]
TableNameInferenceFailedInWhere { query: String },
#[error("Unknown error: `{0}`")]
Unknown(String),
}
4 changes: 2 additions & 2 deletions src/ts_generator/generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,8 @@ pub fn write_single_ts_file(sqls_to_write: String) -> Result<()> {
))?;

let parent_output_path: Option<&Path> = output.parent();
if parent_output_path.is_some() {
fs::create_dir_all(parent_output_path.unwrap())?;
if let Some(parent_output_path) = parent_output_path {
fs::create_dir_all(parent_output_path)?;
}

let mut file_to_write = OpenOptions::new()
Expand Down
69 changes: 51 additions & 18 deletions src/ts_generator/sql_parser/expressions/translate_expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,15 +124,17 @@ pub async fn get_sql_query_param(
single_table_name: &Option<&str>,
table_with_joins: &Option<Vec<TableWithJoins>>,
db_conn: &DBConn,
) -> Option<(TsFieldType, bool, Option<String>)> {
) -> Result<Option<(TsFieldType, bool, Option<String>)>, TsGeneratorError> {
let table_name: Option<String>;

if table_with_joins.is_some() {
table_name = translate_table_from_expr(table_with_joins, &left.clone()).ok();
} else if single_table_name.is_some() {
table_name = single_table_name.map(|x| x.to_string());
} else {
panic!("failed to find an appropriate table name while processing WHERE statement")
return Err(TsGeneratorError::TableNameInferenceFailedInWhere {
query: left.to_string(),
});
}

let column_name = translate_column_name_expr(left);
Expand All @@ -149,15 +151,27 @@ pub async fn get_sql_query_param(
.await
.fetch_table(&table_names, db_conn)
.await
.unwrap_or_else(|| panic!("Failed to fetch columns for table {table_name}"));
.ok_or_else(|| TsGeneratorError::TableNotFoundInSchema {
table: table_name.clone(),
})?;

// get column and return TsFieldType
let column = columns
.get(column_name.as_str())
.unwrap_or_else(|| panic!("Failed to find the column from the table schema of {table_name}"));
Some((column.field_type.to_owned(), column.is_nullable, Some(expr_placeholder)))
let column = columns.get(column_name.as_str()).ok_or_else(|| {
let available_columns = columns.keys().map(|k| k.as_str()).collect::<Vec<_>>().join(", ");
TsGeneratorError::ColumnNotFoundInTable {
column: column_name.clone(),
table: table_name.clone(),
available_columns,
}
})?;

Ok(Some((
column.field_type.to_owned(),
column.is_nullable,
Some(expr_placeholder),
)))
}
_ => None,
_ => Ok(None),
}
}

Expand Down Expand Up @@ -298,7 +312,7 @@ pub async fn translate_expr(
// OPERATORS START //
/////////////////////
Expr::BinaryOp { left, op: _, right } => {
let param = get_sql_query_param(left, right, single_table_name, table_with_joins, db_conn).await;
let param = get_sql_query_param(left, right, single_table_name, table_with_joins, db_conn).await?;
if let Some((value, is_nullable, index)) = param {
let _ = ts_query.insert_param(&value, &is_nullable, &index);
Ok(())
Expand Down Expand Up @@ -341,7 +355,7 @@ pub async fn translate_expr(
table_with_joins,
db_conn,
)
.await;
.await?;

if let Some((value, is_nullable, index)) = result {
let array_item = TsFieldType::Array(Box::new(value));
Expand Down Expand Up @@ -369,8 +383,8 @@ pub async fn translate_expr(
low,
high,
} => {
let low = get_sql_query_param(expr, low, single_table_name, table_with_joins, db_conn).await;
let high = get_sql_query_param(expr, high, single_table_name, table_with_joins, db_conn).await;
let low = get_sql_query_param(expr, low, single_table_name, table_with_joins, db_conn).await?;
let high = get_sql_query_param(expr, high, single_table_name, table_with_joins, db_conn).await?;
if let Some((value, is_nullable, placeholder)) = low {
ts_query.insert_param(&value, &is_nullable, &placeholder)?;
}
Expand Down Expand Up @@ -731,16 +745,35 @@ pub async fn translate_assignment(
let value = get_expr_placeholder(&assignment.value);

if value.is_some() {
let table_details = &DB_SCHEMA
let table_details = DB_SCHEMA
.lock()
.await
.fetch_table(&vec![table_name], db_conn)
.await
.unwrap();
let column_name = translate_column_name_assignment(assignment).unwrap();
let field = table_details
.get(&column_name)
.unwrap_or_else(|| panic!("Failed to find the column detail for {column_name}"));
.ok_or_else(|| TsGeneratorError::TableNotFoundInSchema {
table: table_name.to_string(),
})?;

let column_name = translate_column_name_assignment(assignment).ok_or_else(|| {
TsGeneratorError::UpdateStatementProcessingFailed {
reason: "Failed to extract column name from assignment".to_string(),
query: format!("UPDATE {} SET {} = ...", table_name, assignment),
}
})?;

let field = table_details.get(&column_name).ok_or_else(|| {
let available_columns = table_details
.keys()
.map(|k| k.as_str())
.collect::<Vec<_>>()
.join(", ");
TsGeneratorError::ColumnNotFoundInTable {
column: column_name.clone(),
table: table_name.to_string(),
available_columns,
}
})?;

let _ = ts_query.insert_param(&field.field_type, &field.is_nullable, &value);
}
Ok(())
Expand Down
47 changes: 30 additions & 17 deletions src/ts_generator/sql_parser/translate_insert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,24 +41,32 @@ pub async fn translate_insert(
if placeholder.is_some() {
let match_col = &columns
.get(column)
.unwrap_or_else(|| {
panic!(
r#"
Failed to process values of insert statement as column names are not provided or incorrectly specified

Try specifying column names
```
INSERT INTO table_name (column1, column2, column3, ...)
VALUES (value1, value2, value3, ...);
```
"#
)
})
.ok_or_else(|| {
TsGeneratorError::InsertStatementProcessingFailed {
reason: format!(
"Column at position {} is not provided in the column list. Expected {} columns but found {} values.",
column, columns.len(), values.len()
),
query: format!(
"INSERT INTO {} VALUES (...). Try specifying column names explicitly: INSERT INTO {} (column1, column2, ...) VALUES (...)",
table_name, table_name
),
}
})?
.value;

let field = table_details
.get(match_col.as_str())
.unwrap_or_else(|| panic!("Column {match_col} is not found while processing insert params"));
let field = table_details.get(match_col.as_str()).ok_or_else(|| {
let available_columns = table_details
.keys()
.map(|k| k.as_str())
.collect::<Vec<_>>()
.join(", ");
TsGeneratorError::ColumnNotFoundInTable {
column: match_col.clone(),
table: table_name.to_string(),
available_columns,
}
})?;

if value.to_string() == "?" {
// If the placeholder is `'?'`, we can process it using insert_value_params and generate nested params type
Expand Down Expand Up @@ -104,7 +112,12 @@ VALUES (value1, value2, value3, ...);
SetExpr::Update(update) => translate_stmt(ts_query, &update, None, conn).await?,
SetExpr::Delete(delete) => translate_stmt(ts_query, &delete, None, conn).await?,
SetExpr::Merge(merge) => translate_stmt(ts_query, &merge, None, conn).await?,
SetExpr::Table(_) => unimplemented!("Table expressions are not supported in INSERT statements"),
SetExpr::Table(table) => {
return Err(TsGeneratorError::TableExpressionInInsertStatement(format!(
"INSERT INTO {} ... FROM {}",
table_name, table
)));
}
}

Ok(())
Expand Down
8 changes: 6 additions & 2 deletions src/ts_generator/sql_parser/translate_query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,12 @@ pub async fn translate_select(
let mut table_name: Option<&str> = None;
if full_table_with_joins.is_some() && !full_table_with_joins.as_ref().unwrap().is_empty() {
table_name_owned = Some(
translate_table_with_joins(full_table_with_joins, &select_item)
.unwrap_or_else(|_| panic!("{}", format!("Default FROM table is not found from the query {select}"))),
translate_table_with_joins(full_table_with_joins, &select_item).map_err(|_| {
TsGeneratorError::UnknownErrorWhileProcessingTableWithJoins(format!(
"Default FROM table is not found from the query: {}. Ensure your query has a valid FROM clause.",
select
))
})?,
);
table_name = table_name_owned.as_deref();
}
Expand Down
2 changes: 1 addition & 1 deletion src/ts_generator/types/ts_query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,7 @@ impl TsQuery {
.and_then(|m| m.as_str().parse::<i32>().ok())
.ok_or(TsGeneratorError::UnknownPlaceholder(format!(
"{placeholder} is not a valid placeholder parameter in PostgreSQL"
)))? as i32
)))?
} else {
// No pattern matches the provided placeholder, simply exit out of the function
return Ok(());
Expand Down
Loading