Skip to content

Commit d41d3e4

Browse files
authored
fix(sql) :: add tests that check rewriter guards and what reaches the database (#1422)
1 parent 28eccf4 commit d41d3e4

1 file changed

Lines changed: 129 additions & 0 deletions

File tree

src/webserver/database/sql.rs

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,33 @@ mod tests {
375375
assert!(!query.sql.contains("sqlpage."));
376376
}
377377

378+
#[test]
379+
fn emulated_concat_keeps_nested_call_per_row() {
380+
let FileStatement::Query(Query {
381+
body: QueryBody::Database(query),
382+
..
383+
}) = one("select concat(sqlpage.url_encode(value), '!') as encoded from t")
384+
else {
385+
panic!("expected database query");
386+
};
387+
assert!(query.bindings.is_empty());
388+
assert_eq!(query.row_input_json.len(), 1);
389+
assert!(!query.sql.contains("sqlpage."));
390+
assert_eq!(
391+
query.computed_columns.as_ref(),
392+
[OutputColumn {
393+
name: "encoded".into(),
394+
value: SqlPageExpr::Concat {
395+
arguments: Box::new([
396+
call(SqlPageFunctionName::url_encode, [row(0)]),
397+
text("!"),
398+
]),
399+
null_behavior: ConcatNullBehavior::IgnoreNull,
400+
},
401+
}]
402+
);
403+
}
404+
378405
#[test]
379406
fn parentheses_keep_nested_call_per_row() {
380407
let FileStatement::Query(Query {
@@ -621,6 +648,31 @@ mod tests {
621648
assert!(query.must_buffer_rows());
622649
}
623650

651+
#[test]
652+
fn only_nested_run_sql_requires_buffering() {
653+
let FileStatement::Query(Query {
654+
body: QueryBody::Database(query),
655+
..
656+
}) = one("select coalesce(sqlpage.url_encode(path), '') from files")
657+
else {
658+
panic!("expected database query");
659+
};
660+
assert!(!query.must_buffer_rows());
661+
}
662+
663+
#[test]
664+
fn distinct_is_rejected_only_when_a_projection_is_computed_by_sqlpage() {
665+
assert_eq!(
666+
sql_for(SupportedDatabase::Postgres, "select distinct a from t"),
667+
"SELECT DISTINCT a FROM t"
668+
);
669+
let FileStatement::Error(err) = one("select distinct sqlpage.url_encode(a) as x from t")
670+
else {
671+
panic!("expected an error");
672+
};
673+
assert!(err.to_string().contains("DISTINCT"), "{err}");
674+
}
675+
624676
#[test]
625677
fn documented_facet_query_is_accepted() {
626678
let stmt = one("select category as title, \
@@ -644,6 +696,30 @@ mod tests {
644696
assert_eq!(query.columns.len(), 1);
645697
}
646698

699+
#[test]
700+
fn boolean_literal_stays_a_literal_in_the_static_simple_select() {
701+
let FileStatement::Query(Query {
702+
body: QueryBody::StaticSimpleSelect(query),
703+
..
704+
}) = one("select 'shell' as component, true as fixed_top_menu")
705+
else {
706+
panic!("expected a single SQLPage-owned row");
707+
};
708+
assert_eq!(
709+
query.columns.as_ref(),
710+
[
711+
OutputColumn {
712+
name: "component".into(),
713+
value: text("shell"),
714+
},
715+
OutputColumn {
716+
name: "fixed_top_menu".into(),
717+
value: SqlPageExpr::Literal(serde_json::Value::Bool(true)),
718+
},
719+
]
720+
);
721+
}
722+
647723
#[test]
648724
fn concat_operator_uses_backend_null_behavior_in_sqlpage_expressions() {
649725
for database_type in [SupportedDatabase::Oracle, SupportedDatabase::Mssql] {
@@ -862,4 +938,57 @@ mod tests {
862938
"SELECT value FROM t LIMIT $1"
863939
);
864940
}
941+
942+
#[test]
943+
fn with_and_limit_clauses_are_never_folded_into_a_constant_row() {
944+
let query = rewrite_database(
945+
"with d as (insert into t(a) values ($v) returning a) \
946+
select 'redirect' as component, '/index.sql' as link",
947+
);
948+
assert!(query.sql.contains("INSERT INTO"), "{}", query.sql);
949+
assert_eq!(query.bindings.as_ref(), [variable("v")]);
950+
951+
assert_eq!(
952+
sql_for(SupportedDatabase::Postgres, "select 'a' as x limit 0"),
953+
"SELECT 'a' AS x LIMIT 0"
954+
);
955+
}
956+
957+
#[test]
958+
fn a_database_operand_keeps_the_whole_projection_in_the_database() {
959+
assert_eq!(
960+
sql_for(SupportedDatabase::Postgres, "select 'x' || now() as v"),
961+
"SELECT 'x' || now() AS v"
962+
);
963+
}
964+
965+
#[test]
966+
fn concat_operator_is_rewritten_to_a_function_only_on_sql_server() {
967+
assert_eq!(
968+
sql_for(SupportedDatabase::Mssql, "select a || b from t"),
969+
"SELECT CONCAT(a, b) FROM t"
970+
);
971+
assert_eq!(
972+
sql_for(SupportedDatabase::Postgres, "select a || b from t"),
973+
"SELECT a || b FROM t"
974+
);
975+
}
976+
977+
#[test]
978+
fn modifiers_on_a_sqlpage_function_are_rejected() {
979+
for src in [
980+
"select sqlpage.url_encode(a) over () from t",
981+
"select sqlpage.url_encode(a) filter (where a > 1) from t",
982+
"select sqlpage.url_encode(a) ignore nulls from t",
983+
"select sqlpage.url_encode(a) within group (order by a) from t",
984+
] {
985+
let FileStatement::Error(error) = one(src) else {
986+
panic!("expected a rewrite error for `{src}`");
987+
};
988+
assert!(
989+
error.to_string().contains("Modifiers are not supported"),
990+
"`{src}` produced: {error}"
991+
);
992+
}
993+
}
865994
}

0 commit comments

Comments
 (0)