Skip to main content
Glama

Convex MCP server

Official
by get-convex
id_strings.rs8.48 kB
use std::str::FromStr; use cmd_util::env::env_config; use common::version::Version; use database::{ TestFacingModel, UserFacingModel, }; use keybroker::Identity; use model::udf_config::{ types::UdfConfig, UdfConfigModel, }; use must_let::must_let; use proptest::prelude::*; use runtime::testing::{ TestDriver, TestRuntime, }; use value::{ assert_obj, id_v6::DeveloperDocumentId, ConvexValue, FieldName, InternalId, TableName, TableNamespace, }; use crate::test_helpers::{ UdfTest, UdfTestType, }; #[convex_macro::test_runtime] async fn test_table_mapping_from_system_udf(rt: TestRuntime) -> anyhow::Result<()> { UdfTest::run_test_with_isolate2(rt, async move |t: UdfTestType| { let mut tx = t.database.begin(Identity::system()).await?; let document = TestFacingModel::new(&mut tx) .insert_and_get("table".parse()?, assert_obj!()) .await?; let table_number = document.id().developer_id.table(); let table_number_field: FieldName = FieldName::from_str(table_number.to_string().as_ref())?; t.database.commit(tx).await?; let value = t.query("idStrings:getTableMapping", assert_obj!()).await?; must_let!(let ConvexValue::Object(entries) = value); assert_eq!( &ConvexValue::String("table".try_into()?), entries.get(&table_number_field).unwrap() ); Ok(()) }) .await } #[convex_macro::test_runtime] async fn test_system_normalize_id(rt: TestRuntime) -> anyhow::Result<()> { UdfTest::run_test_with_isolate2(rt, async move |t: UdfTestType| { let internal_id = InternalId::MIN; let mut tx = t.database.begin(Identity::system()).await?; let user_table_name: TableName = "boats".parse()?; UserFacingModel::new_root_for_test(&mut tx) .insert(user_table_name.clone(), assert_obj!()) .await?; let user_table_number = tx.table_mapping() .namespace(TableNamespace::test_user()) .id(&user_table_name)?.table_number; let storage_table_number = tx .table_mapping() .namespace(TableNamespace::test_user()) .id(&"_file_storage".parse()?)? .table_number; let indexes_table_number = tx.table_mapping().namespace(TableNamespace::test_user()).id(&"_index".parse()?)?.table_number; // Set the UDF server version to a version with string IDs UdfConfigModel::new(&mut tx, TableNamespace::test_user()) .set(UdfConfig::new_for_test(&t.rt, Version::parse("1000.0.0")?)) .await?; t.database.commit(tx).await?; let id_v6 = DeveloperDocumentId::new(storage_table_number, internal_id); // Correct virtual table name and number. must_let!(let ConvexValue::String(normalized_id) = t.query("idStrings:normalizeSystemId", assert_obj!( "id" => id_v6.encode(), "table" => "_storage", )).await?); assert_eq!(normalized_id.to_string(), id_v6.encode()); // Correct virtual table name and internal id. must_let!(let ConvexValue::String(normalized_id) = t.query("idStrings:normalizeSystemId", assert_obj!( "id" => internal_id.to_string(), "table" => "_storage", )).await?); assert_eq!(normalized_id.to_string(), id_v6.encode()); // Incorrect virtual table name. must_let!(let ConvexValue::Null = t.query("idStrings:normalizeSystemId", assert_obj!( "id" => id_v6.encode(), "table" => "_scheduled_functions", )).await?); // Physical table name and virtual table number doesn't work. must_let!(let ConvexValue::Null = t.query("idStrings:normalizeSystemId", assert_obj!( "id" => id_v6.encode(), "table" => "_file_storage", )).await?); // Physical table name and physical table number doesn't work. must_let!(let ConvexValue::Null = t.query("idStrings:normalizeSystemId", assert_obj!( "id" => DeveloperDocumentId::new(storage_table_number, internal_id).encode(), "table" => "_file_storage", )).await?); // System table that doesn't even have a virtual table doesn't work. must_let!(let ConvexValue::Null = t.query("idStrings:normalizeSystemId", assert_obj!( "id" => DeveloperDocumentId::new(indexes_table_number, internal_id).encode(), "table" => "_index", )).await?); // Virtual table with db.normalizeId throws error. t.query_js_error( "idStrings:normalizeId", assert_obj!( "id" => id_v6.encode(), "table" => "_storage", ), ) .await?; // User table with db.system.normalizeId throws error. t.query_js_error( "idStrings:normalizeSystemId", assert_obj!( "id" => DeveloperDocumentId::new(user_table_number, internal_id).encode(), "table" => user_table_name.to_string(), ), ) .await?; Ok(()) }).await } #[convex_macro::test_runtime] async fn test_virtual_id_query(rt: TestRuntime) -> anyhow::Result<()> { UdfTest::run_test_with_isolate2(rt, async move |t: UdfTestType| { let scheduled_id = t.mutation("idStrings:schedule", assert_obj!()).await?; t.query( "idStrings:queryVirtualId", assert_obj!("id" => scheduled_id), ) .await?; Ok(()) }) .await } // Since we run this test with proptest, don't run it in both isolate1 and // isolate2. async fn test_normalize_id(rt: TestRuntime, internal_id: InternalId) -> anyhow::Result<()> { let t = UdfTest::default(rt).await?; // Initialize table mapping with two tables let mut tx = t.database.begin(Identity::system()).await?; let table_name_a: TableName = "boats".parse()?; let table_name_b: TableName = "votes".parse()?; UserFacingModel::new_root_for_test(&mut tx) .insert(table_name_a.clone(), assert_obj!()) .await?; UserFacingModel::new_root_for_test(&mut tx) .insert(table_name_b.clone(), assert_obj!()) .await?; let table_number = tx .table_mapping() .namespace(TableNamespace::test_user()) .id(&table_name_a)? .table_number; // Set the UDF server version to a version with string IDs UdfConfigModel::new(&mut tx, TableNamespace::test_user()) .set(UdfConfig::new_for_test(&t.rt, Version::parse("1000.0.0")?)) .await?; t.database.commit(tx).await?; let id_v6 = DeveloperDocumentId::new(table_number, internal_id); // Test IDv6 and correct table name must_let!(let ConvexValue::Object(obj) = t.query("idStrings:normalizeId", assert_obj!( "id" => id_v6.encode(), "table" => table_name_a.to_string() )).await?); must_let!(let Some(ConvexValue::String(ref normalized_id)) = obj.get("normalized")); assert_eq!(normalized_id.to_string(), id_v6.encode()); // Test internal ID and correct table name must_let!(let ConvexValue::Object(obj) = t.query("idStrings:normalizeId", assert_obj!("id" => internal_id.to_string(), "table" => table_name_a.to_string() )).await?); must_let!(let Some(ConvexValue::String(ref normalized_id)) = obj.get("normalized")); assert_eq!(normalized_id.to_string(), id_v6.encode()); // Test IDv6 and incorrect table name must_let!(let ConvexValue::Object(obj) = t.query("idStrings:normalizeId", assert_obj!( "id" => id_v6.encode(), "table" => table_name_b.to_string() )).await?); must_let!(let Some(ConvexValue::Null) = obj.get("normalized")); // Test internal ID and incorrect table name must_let!(let ConvexValue::Object(obj) = t.query("idStrings:normalizeId", assert_obj!("id" => internal_id.to_string(), "table" => table_name_a.to_string() )).await?); must_let!(let Some(ConvexValue::String(_)) = obj.get("normalized")); Ok(()) } proptest! { #![proptest_config(ProptestConfig { cases: 32 * env_config("CONVEX_PROPTEST_MULTIPLIER", 1), failure_persistence: None, .. ProptestConfig::default() })] #[test] fn proptest_normalize_id(id in any::<InternalId>()) { let td = TestDriver::new(); let rt = td.rt(); td.run_until(test_normalize_id(rt, id)).unwrap(); } }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/get-convex/convex-backend'

If you have feedback or need assistance with the MCP directory API, please join our Discord server