Skip to content
Open
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
110 changes: 109 additions & 1 deletion store/postgres/src/relational/query_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ use crate::{
block_range::BoundSide,
layout_for_tests::{Namespace, make_dummy_site},
relational::{Catalog, ColumnType, Layout},
relational_queries::{FindRangeQuery, FromColumnValue, InsertQuery},
relational_queries::{
FindPossibleDeletionsQuery, FindRangeQuery, FromColumnValue, InsertQuery,
},
};

use crate::relational_queries::Filter;
Expand Down Expand Up @@ -200,6 +202,112 @@ fn test_id_type_casting(table: &crate::relational::Table, expected_cast: &str, t
);
}

#[test]
fn find_possible_deletions_query_id_type_casting() {
let string_schema = "
type StringEntity @entity {
id: String!,
name: String
}";

let bytes_schema = "
type BytesEntity @entity {
id: Bytes!,
address: Bytes
}";

let int8_schema = "
type Int8Entity @entity {
id: Int8!,
value: Int8
}";

let string_layout = test_layout(string_schema);
let bytes_layout = test_layout(bytes_schema);
let int8_layout = test_layout(int8_schema);

let string_table = string_layout
.table_for_entity(
&string_layout
.input_schema
.entity_type("StringEntity")
.unwrap(),
)
.unwrap();
let bytes_table = bytes_layout
.table_for_entity(
&bytes_layout
.input_schema
.entity_type("BytesEntity")
.unwrap(),
)
.unwrap();
let int8_table = int8_layout
.table_for_entity(&int8_layout.input_schema.entity_type("Int8Entity").unwrap())
.unwrap();

test_possible_deletions_id_type_casting(
string_table.as_ref(),
"e.id::bytea",
"String ID should be cast to bytea",
);
test_possible_deletions_id_type_casting(
bytes_table.as_ref(),
"e.id",
"Bytes ID should remain as e.id",
);
test_possible_deletions_id_type_casting(
int8_table.as_ref(),
"e.id::text::bytea",
"Int8 ID should be cast to text then bytea",
);

let tables = vec![
string_table.as_ref(),
bytes_table.as_ref(),
int8_table.as_ref(),
];
let query = FindPossibleDeletionsQuery::new(&tables, 100);
let sql = debug_query::<Pg, _>(&query).to_string();

assert!(
sql.contains("id::bytea"),
"String entity ID casting should be present in possible-deletions UNION query, got: {}",
sql
);
assert!(
sql.contains("e.id"),
"Bytes entity ID should be present in possible-deletions UNION query"
);
assert!(
sql.contains("id::text::bytea"),
"Int8 entity ID casting should be present in possible-deletions UNION query, got: {}",
sql
);
assert!(
sql.contains("union all"),
"Multiple tables should generate UNION ALL queries"
);
}

fn test_possible_deletions_id_type_casting(
table: &crate::relational::Table,
expected_cast: &str,
test_name: &str,
) {
let tables = vec![table];
let query = FindPossibleDeletionsQuery::new(&tables, 100);
let sql = debug_query::<Pg, _>(&query).to_string();

assert!(
sql.contains(expected_cast),
"{}: Expected '{}' in SQL, got: {}",
test_name,
expected_cast,
sql
);
}

fn insert_sql_for_schema(gql: &str, entity_type_name: &str) -> String {
use graph::components::store::write::EntityModification;

Expand Down
13 changes: 12 additions & 1 deletion store/postgres/src/relational_queries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2090,7 +2090,18 @@ impl<'a> QueryFragment<Pg> for FindPossibleDeletionsQuery<'a> {
} else {
out.push_sql("0 as causality_region, ");
}
out.push_sql("e.id\n");
let pk_column = table.primary_key();

// Cast id to bytea so that every branch of the UNION has the same
// column type; the id can be text, bytea, or numeric depending on the
// entity type, and `UNION ALL` requires a common type per column.
match pk_column.column_type {
ColumnType::String => out.push_sql("e.id::bytea"),
ColumnType::Bytes => out.push_sql("e.id"),
ColumnType::Int8 => out.push_sql("e.id::text::bytea"),
_ => out.push_sql("e.id::bytea"),
}
out.push_sql("\n");
out.push_sql(" from ");
out.push_sql(table.qualified_name.as_str());
out.push_sql(" e\n where ");
Expand Down