Skip to main content
Glama

Convex MCP server

Official
by get-convex
table_name.rs7.43 kB
use std::{ fmt::{ self, Debug, }, ops::Deref, str::FromStr, }; use derive_more::{ Display, FromStr, }; use serde::Serialize; #[cfg(doc)] use crate::ResolvedDocumentId; use crate::{ document_id::InternalId, field_name::FieldName, heap_size::HeapSize, identifier::{ check_valid_identifier, MIN_IDENTIFIER, }, DeveloperDocumentId, Namespace, Size, }; /// A table is a metadata table if and only if it has this prefix. pub const METADATA_PREFIX: &str = "_"; /// Unique name for a table. Tables contain documents referenced by /// [`ResolvedDocumentId`]. Eventually we'll want a layer of indirection here to /// allow users to rename their tables. #[derive(Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, derive_more::Display)] pub struct TableName(String); impl FromStr for TableName { type Err = anyhow::Error; fn from_str(s: &str) -> Result<Self, Self::Err> { check_valid_identifier(s)?; Ok(Self(s.to_owned())) } } impl Debug for TableName { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Debug::fmt(&self.0, f) } } impl Deref for TableName { type Target = str; fn deref(&self) -> &Self::Target { &self.0 } } impl From<TableName> for String { fn from(t: TableName) -> Self { t.0 } } impl HeapSize for TableName { fn heap_size(&self) -> usize { self.0.heap_size() } } impl TableName { /// Is this table in the system namespace? /// TODO(Rebecca): move system tables to a different namespace to avoid /// conflicts with virtual tables pub fn is_system(&self) -> bool { self.0.starts_with(METADATA_PREFIX) } pub fn is_valid_virtual(&self) -> bool { self.0.starts_with(METADATA_PREFIX) } /// Minimum valid [`TableName`]. (See the regex above.) pub fn min() -> Self { MIN_IDENTIFIER.parse().expect("Min table name invalid?") } } impl Namespace for TableName { fn is_system(&self) -> bool { self.0.starts_with(METADATA_PREFIX) } } #[cfg(any(test, feature = "testing"))] impl TableName { pub fn system_strategy() -> impl proptest::strategy::Strategy<Value = TableName> { use crate::identifier::arbitrary_regexes::SYSTEM_IDENTIFIER_REGEX; SYSTEM_IDENTIFIER_REGEX.prop_filter_map("Generated invalid system TableName", |s| { TableName::from_str(&s).ok() }) } pub fn user_strategy() -> impl proptest::strategy::Strategy<Value = TableName> { use crate::identifier::arbitrary_regexes::USER_IDENTIFIER_REGEX; USER_IDENTIFIER_REGEX.prop_filter_map("Generated invalid user TableName", |s| { TableName::from_str(&s).ok() }) } } #[derive(Default)] pub enum TableType { #[default] Either, User, System, } #[cfg(any(test, feature = "testing"))] impl proptest::arbitrary::Arbitrary for TableName { type Parameters = TableType; type Strategy = impl proptest::strategy::Strategy<Value = TableName>; fn arbitrary_with(ty: Self::Parameters) -> Self::Strategy { use proptest::prelude::*; match ty { TableType::Either => { prop_oneof![TableName::system_strategy(), TableName::user_strategy(),].boxed() }, TableType::User => TableName::user_strategy().boxed(), TableType::System => TableName::system_strategy().boxed(), } } } impl From<TableName> for FieldName { fn from(table: TableName) -> FieldName { table.0.parse().expect("TableName not valid FieldName") } } #[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Clone, Copy, FromStr, Display, Hash)] #[cfg_attr(any(test, feature = "testing"), derive(proptest_derive::Arbitrary))] pub struct TabletId(pub InternalId); impl TabletId { pub const MAX: TabletId = TabletId(InternalId::MAX); pub const MIN: TabletId = TabletId(InternalId::MIN); pub fn document_id_to_string(&self, internal_id: InternalId) -> String { format!("{}|{}", *self, internal_id) } } impl HeapSize for TabletId { fn heap_size(&self) -> usize { 0 } } #[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Clone, Copy, Display, Hash, Serialize)] pub struct TableNumber(u32); #[cfg(any(test, feature = "testing"))] use proptest::prelude::*; #[cfg(any(test, feature = "testing"))] impl Arbitrary for TableNumber { type Parameters = (); type Strategy = impl proptest::strategy::Strategy<Value = TableNumber>; fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { any::<u32>().prop_filter_map("Invalid table number", |x| TableNumber::try_from(x).ok()) } } impl From<TableNumber> for u32 { fn from(n: TableNumber) -> u32 { n.0 } } impl TryFrom<u32> for TableNumber { type Error = anyhow::Error; fn try_from(value: u32) -> Result<Self, Self::Error> { anyhow::ensure!(value > 0); Ok(TableNumber(value)) } } impl HeapSize for TableNumber { fn heap_size(&self) -> usize { 0 } } impl TableNumber { pub const MAX: TableNumber = TableNumber(u32::MAX); pub const MIN: TableNumber = TableNumber(1); pub fn document_id_to_string(&self, internal_id: InternalId) -> String { let id_v6 = DeveloperDocumentId::new(*self, internal_id); id_v6.encode() } pub fn increment(self) -> anyhow::Result<Self> { Ok(Self( self.0 .checked_add(1) .ok_or_else(|| anyhow::anyhow!("Table number overflow"))?, )) } } #[derive(PartialEq, Eq, Debug, Clone, Copy)] pub struct TabletIdAndTableNumber { pub table_number: TableNumber, pub tablet_id: TabletId, } impl Size for TableNumber { fn size(&self) -> usize { // In order to compute size consistently for both DocumentId<TableName> and // DocumentId<TableId> so it represents the size as stored in persistence, // assume that the size is the maximum internal id size. InternalId::MAX_SIZE } fn nesting(&self) -> usize { 0 } } impl Size for TabletId { fn size(&self) -> usize { // In order to compute size consistently for both DocumentId<TableName> and // DocumentId<TableId> so it represents the size as stored in persistence, // assume that the size is the maximum internal id size. InternalId::MAX_SIZE } fn nesting(&self) -> usize { 0 } } #[cfg(test)] mod tests { use super::TableName; #[test] fn table_name_valid() { assert!("hello_world".parse::<TableName>().is_ok()); assert!("one_two_three_four_five".parse::<TableName>().is_ok()); assert!("alpha_num3r1c".parse::<TableName>().is_ok()); } #[test] fn table_name_invalid() { assert!("one_tw!o_three_four_five".parse::<TableName>().is_err()); assert!("_____".parse::<TableName>().is_err()); assert!("".parse::<TableName>().is_err()); assert!("sujays_edgè_cäsê".parse::<TableName>().is_err()); } #[test] fn table_name_is_system() -> anyhow::Result<()> { assert!("_hello_world".parse::<TableName>()?.is_system()); assert!("_elephant3".parse::<TableName>()?.is_system()); assert!(!"elephant3".parse::<TableName>()?.is_system()); 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