Skip to main content
Glama

Convex MCP server

Official
by get-convex
patch.rs4.14 kB
use std::collections::BTreeMap; use common::{ types::MaybeValue, value::{ ConvexObject, FieldName, }, }; use serde_json::Value as JsonValue; /// A object used in patch. Similar to GenericObject but also allows top level /// undefined fields. #[derive(Clone, Debug, PartialEq, Eq)] pub struct PatchValue { fields: BTreeMap<FieldName, MaybeValue>, } impl PatchValue { pub fn apply(self, original: ConvexObject) -> anyhow::Result<ConvexObject> { let mut original_fields: BTreeMap<_, _> = original.into(); for (field, maybe_value) in self.fields { match maybe_value.0 { Some(value) => { original_fields.insert(field, value); }, None => { original_fields.remove(&field); }, } } original_fields.try_into() } } impl From<BTreeMap<FieldName, MaybeValue>> for PatchValue { fn from(fields: BTreeMap<FieldName, MaybeValue>) -> Self { Self { fields } } } impl TryFrom<JsonValue> for PatchValue { type Error = anyhow::Error; fn try_from(json_value: JsonValue) -> anyhow::Result<Self> { match json_value { JsonValue::Object(map) => { let mut fields = BTreeMap::new(); for (key, value) in map { fields.insert(key.parse()?, MaybeValue::try_from(value)?); } Ok(fields.into()) }, _ => { anyhow::bail!("Value must be an Object"); }, } } } impl From<ConvexObject> for PatchValue { fn from(obj: ConvexObject) -> Self { let mut fields = BTreeMap::new(); for (field, value) in obj.into_iter() { fields.insert(field, MaybeValue::from(value)); } fields.into() } } #[macro_export] /// Create an patch object from field/value pairs. macro_rules! patch_value { ($($field:expr => $val:expr),* $(,)?) => { { use common::types::MaybeValue; use $crate::PatchValue; use std::collections::BTreeMap; #[allow(unused)] let mut fields = BTreeMap::new(); { $( fields.insert($field.parse()?, MaybeValue($val)); )* } PatchValue::try_from(fields) } }; } #[cfg(test)] mod tests { use common::assert_obj; use value::{ assert_val, ConvexObject, }; #[test] fn test_apply() -> anyhow::Result<()> { // Overwrite duplicate fields instead of merging sub-fields. let original: ConvexObject = assert_obj!( "name" => { "first" => "Mr", "last" => "Fantastik", }, "job" => "mechanic", ); let patch = patch_value!( "name" => Some(assert_val!({ "first" => "Mr", "surname" => "Fantastik", })), "job" => Some("engineer".try_into()?), )?; // shallow merge let expected = assert_obj!( "name" => { "first" => "Mr", "surname" => "Fantastik", }, "job" => "engineer", ); assert_eq!(patch.apply(original.clone())?, expected); // delete a top level field. let delete_job = patch_value!("job" => None)?; let expected = assert_obj!( "name" => { "first" => "Mr", "last" => "Fantastik", }, ); assert_eq!(delete_job.apply(original.clone())?, expected); // deleting a top level fields that doesn't exist should be a no-op. let delete_missing = patch_value!("missing" => None)?; let expected = assert_obj!( "name" => { "first" => "Mr", "last" => "Fantastik", }, "job" => "mechanic", ); assert_eq!(delete_missing.apply(original)?, expected); Ok(()) } }

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