mod query_test_utils;
#[cfg(test)]
mod relational_query_tests {
use super::query_test_utils::shared::*; use parse_rs::query::ParseQuery;
use parse_rs::Parse; use parse_rs::ParseError;
use serde::{Deserialize, Serialize};
use serde_json::{json, Value};
use uuid::Uuid;
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
struct Author {
#[serde(rename = "objectId", skip_serializing_if = "Option::is_none")]
object_id: Option<String>,
name: String,
birth_year: Option<i32>,
}
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
struct Book {
#[serde(rename = "objectId", skip_serializing_if = "Option::is_none")]
object_id: Option<String>,
title: String,
author_ptr: Value, pages: Option<i32>,
}
async fn setup_author_book_data(
client: &Parse,
author_class_name: &str,
book_class_name: &str,
) -> Result<(Author, Book), ParseError> {
let author_data = json!({ "name": "Test Author", "birth_year": 1980 });
let created_author_response = client
.create_object(author_class_name, &author_data)
.await?;
let author_id = created_author_response.object_id;
let author_obj = Author {
object_id: Some(author_id.clone()), name: "Test Author".to_string(),
birth_year: Some(1980),
};
let book_data = json!({
"title": "Test Book About Pointers",
"author_ptr": {
"__type": "Pointer",
"className": author_class_name,
"objectId": author_id
},
"pages": 300
});
let created_book_response = client.create_object(book_class_name, &book_data).await?;
let book_id = created_book_response.object_id;
let book_obj = Book {
object_id: Some(book_id.clone()), title: "Test Book About Pointers".to_string(),
author_ptr: book_data["author_ptr"].clone(), pages: Some(300),
};
Ok((author_obj, book_obj))
}
#[tokio::test]
async fn test_query_include_pointer() -> Result<(), ParseError> {
let client = setup_client();
let author_class = format!("Author_{}", Uuid::new_v4().simple());
let book_class = format!("Book_{}", Uuid::new_v4().simple());
cleanup_test_class(&client, &author_class).await;
cleanup_test_class(&client, &book_class).await;
let (expected_author, _expected_book) =
setup_author_book_data(&client, &author_class, &book_class).await?;
let mut query_include = ParseQuery::new(&book_class);
query_include.include(&["author_ptr"]);
let results_include: Vec<Book> = query_include
.find(&client)
.await
.expect("Query with include failed");
assert_eq!(results_include.len(), 1, "Expected one book with include");
let book_with_include = results_include.first().unwrap();
assert_eq!(book_with_include.title, "Test Book About Pointers");
match book_with_include.author_ptr.as_object() {
Some(author_map) => {
assert_ne!(
author_map.get("__type").and_then(Value::as_str),
Some("Pointer"),
"author_ptr should be a full object, not a pointer stub"
);
assert_eq!(
author_map.get("name").and_then(Value::as_str),
Some(expected_author.name.as_str())
);
assert_eq!(
author_map.get("birth_year").and_then(Value::as_i64),
expected_author.birth_year.map(|y| y as i64)
);
}
None => panic!("author_ptr was not an object when included"),
}
let query_no_include = ParseQuery::new(&book_class);
let results_no_include: Vec<Book> = query_no_include
.find(&client)
.await
.expect("Query without include failed");
assert_eq!(
results_no_include.len(),
1,
"Expected one book without include"
);
let book_without_include = results_no_include.first().unwrap();
assert_eq!(book_without_include.title, "Test Book About Pointers");
match book_without_include.author_ptr.as_object() {
Some(author_map) => {
assert_eq!(
author_map.get("__type").and_then(Value::as_str),
Some("Pointer"),
"author_ptr should be a pointer stub"
);
assert_eq!(
author_map.get("className").and_then(Value::as_str),
Some(author_class.as_str())
);
assert_eq!(
author_map.get("objectId").and_then(Value::as_str),
Some(expected_author.object_id.as_ref().unwrap().as_str())
);
}
None => panic!("author_ptr was not an object (pointer stub) when not included"),
}
cleanup_test_class(&client, &book_class).await;
cleanup_test_class(&client, &author_class).await;
Ok(())
}
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
struct SelectItem {
#[serde(rename = "objectId", skip_serializing_if = "Option::is_none")]
object_id: Option<String>,
#[serde(rename = "createdAt", skip_serializing_if = "Option::is_none")]
created_at: Option<String>,
#[serde(rename = "updatedAt", skip_serializing_if = "Option::is_none")]
updated_at: Option<String>,
name: String,
value: Option<i32>, category: Option<String>, is_active: Option<bool>, }
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
struct GenericItem {
#[serde(rename = "objectId")]
object_id: String,
#[serde(flatten)]
fields: serde_json::Map<String, Value>,
}
#[tokio::test]
async fn test_query_select_keys() -> Result<(), ParseError> {
let client = setup_client();
let class_name = format!("SelectTestItem_{}", Uuid::new_v4().simple());
cleanup_test_class(&client, &class_name).await;
let item1_data = json!({
"name": "Item Alpha",
"value": 100,
"category": "A",
"is_active": true
});
let _item1 = create_test_object(&client, &class_name, item1_data.clone()).await?;
let item2_data = json!({
"name": "Item Beta",
"value": 200,
"category": "B",
"is_active": false
});
let _item2 = create_test_object(&client, &class_name, item2_data.clone()).await?;
let mut query_select = ParseQuery::new(&class_name);
query_select.select(&["name", "category"]);
let results_select: Vec<GenericItem> = query_select
.find(&client)
.await
.expect("Query with select failed");
assert_eq!(results_select.len(), 2, "Expected two items with select");
for item in results_select {
assert!(
item.fields.contains_key("name"),
"Selected field 'name' should be present"
);
assert!(
item.fields.contains_key("category"),
"Selected field 'category' should be present"
);
assert!(
!item.fields.contains_key("value"),
"Unselected field 'value' should be absent"
);
assert!(
!item.fields.contains_key("is_active"),
"Unselected field 'is_active' should be absent"
);
assert!(
item.fields.contains_key("createdAt"),
"'createdAt' should be present by default"
);
assert!(
item.fields.contains_key("updatedAt"),
"'updatedAt' should be present by default"
);
}
let query_no_select = ParseQuery::new(&class_name);
let results_no_select: Vec<GenericItem> = query_no_select
.find(&client)
.await
.expect("Query without select failed");
assert_eq!(
results_no_select.len(),
2,
"Expected two items without select"
);
for item in results_no_select {
assert!(item.fields.contains_key("name"));
assert!(item.fields.contains_key("value"));
assert!(item.fields.contains_key("category"));
assert!(item.fields.contains_key("is_active"));
}
cleanup_test_class(&client, &class_name).await;
Ok(())
}
}