Skip to main content
Glama
models.py10.4 kB
"""Database models for Writer MCP.""" from datetime import datetime from typing import List, Optional from ..database.connection import DatabaseConnection from ..utils.logger import get_logger logger = get_logger(__name__) class Character: """Character database model.""" def __init__( self, id: Optional[int] = None, name: str = "", description: str = "", tags: Optional[List[str]] = None, created_at: Optional[datetime] = None, updated_at: Optional[datetime] = None ): self.id = id self.name = name self.description = description self.tags = tags or [] self.created_at = created_at self.updated_at = updated_at @classmethod async def create( cls, db: DatabaseConnection, name: str, description: str, tags: Optional[List[str]] = None ) -> "Character": """Create a new character.""" query = """ INSERT INTO characters (name, description, tags, created_at, updated_at) VALUES ($1, $2, $3, NOW(), NOW()) RETURNING id, name, description, tags, created_at, updated_at """ results = await db.execute_query( query, (name, description, tags or []) ) result = results[0] if results else None if result: return cls( id=result['id'], name=result['name'], description=result['description'], tags=result['tags'], created_at=result['created_at'], updated_at=result['updated_at'] ) raise Exception("Failed to create character") @classmethod async def get_by_id(cls, db: DatabaseConnection, character_id: int) -> Optional["Character"]: """Get character by ID.""" query = """ SELECT id, name, description, tags, created_at, updated_at FROM characters WHERE id = $1 """ results = await db.execute_query(query, (character_id,)) result = results[0] if results else None if result: return cls( id=result['id'], name=result['name'], description=result['description'], tags=result['tags'], created_at=result['created_at'], updated_at=result['updated_at'] ) return None @classmethod async def search( cls, db: DatabaseConnection, query: str, limit: int = 10 ) -> List["Character"]: """Search characters by name or description.""" sql = """ SELECT id, name, description, tags, created_at, updated_at FROM characters WHERE name ILIKE $1 OR description ILIKE $1 ORDER BY CASE WHEN name ILIKE $1 THEN 1 ELSE 2 END, name LIMIT $2 """ search_pattern = f"%{query}%" results = await db.execute_query(sql, (search_pattern, limit)) return [ cls( id=row['id'], name=row['name'], description=row['description'], tags=row['tags'], created_at=row['created_at'], updated_at=row['updated_at'] ) for row in results ] class CharacterFact: """Character fact database model.""" def __init__( self, id: Optional[int] = None, character_id: int = 0, fact_type: str = "", content: str = "", embedding: Optional[List[float]] = None, created_at: Optional[datetime] = None, updated_at: Optional[datetime] = None ): self.id = id self.character_id = character_id self.fact_type = fact_type self.content = content self.embedding = embedding self.created_at = created_at self.updated_at = updated_at @classmethod async def create( cls, db: DatabaseConnection, character_id: int, fact_type: str, content: str, embedding: Optional[List[float]] = None ) -> "CharacterFact": """Create a new character fact.""" query = """ INSERT INTO character_facts (character_id, fact_type, content, embedding, created_at, updated_at) VALUES ($1, $2, $3, $4, NOW(), NOW()) RETURNING id, character_id, fact_type, content, embedding, created_at, updated_at """ results = await db.execute_query( query, (character_id, fact_type, content, embedding) ) result = results[0] if results else None if result: return cls( id=result['id'], character_id=result['character_id'], fact_type=result['fact_type'], content=result['content'], embedding=result['embedding'], created_at=result['created_at'], updated_at=result['updated_at'] ) raise Exception("Failed to create character fact") @classmethod async def search_by_content( cls, db: DatabaseConnection, query: str, character_id: Optional[int] = None, fact_type: Optional[str] = None, limit: int = 10 ) -> List["CharacterFact"]: """Search facts by content.""" conditions = ["content ILIKE $1"] params = [f"%{query}%"] param_count = 1 if character_id: param_count += 1 conditions.append(f"character_id = ${param_count}") params.append(character_id) if fact_type: param_count += 1 conditions.append(f"fact_type = ${param_count}") params.append(fact_type) param_count += 1 params.append(limit) sql = f""" SELECT id, character_id, fact_type, content, embedding, created_at, updated_at FROM character_facts WHERE {' AND '.join(conditions)} ORDER BY created_at DESC LIMIT ${param_count} """ results = await db.execute_query(sql, tuple(params)) return [ cls( id=row['id'], character_id=row['character_id'], fact_type=row['fact_type'], content=row['content'], embedding=row['embedding'], created_at=row['created_at'], updated_at=row['updated_at'] ) for row in results ] class CharacterRelation: """Character relationship database model.""" def __init__( self, id: Optional[int] = None, character_a_id: int = 0, character_b_id: int = 0, relation_type: str = "", description: str = "", strength: float = 0.5, created_at: Optional[datetime] = None, updated_at: Optional[datetime] = None ): self.id = id self.character_a_id = character_a_id self.character_b_id = character_b_id self.relation_type = relation_type self.description = description self.strength = strength self.created_at = created_at self.updated_at = updated_at @classmethod async def create( cls, db: DatabaseConnection, character_a_id: int, character_b_id: int, relation_type: str, description: str, strength: float = 0.5 ) -> "CharacterRelation": """Create a new character relationship.""" query = """ INSERT INTO character_relations (character_a_id, character_b_id, relation_type, description, strength, created_at, updated_at) VALUES ($1, $2, $3, $4, $5, NOW(), NOW()) RETURNING id, character_a_id, character_b_id, relation_type, description, strength, created_at, updated_at """ results = await db.execute_query( query, (character_a_id, character_b_id, relation_type, description, strength) ) result = results[0] if results else None if result: return cls( id=result['id'], character_a_id=result['character_a_id'], character_b_id=result['character_b_id'], relation_type=result['relation_type'], description=result['description'], strength=result['strength'], created_at=result['created_at'], updated_at=result['updated_at'] ) raise Exception("Failed to create character relationship") @classmethod async def get_by_characters( cls, db: DatabaseConnection, character_ids: List[int] ) -> List["CharacterRelation"]: """Get relationships between specific characters.""" if len(character_ids) < 2: return [] placeholders = ", ".join([f"${i+1}" for i in range(len(character_ids))]) sql = f""" SELECT id, character_a_id, character_b_id, relation_type, description, strength, created_at, updated_at FROM character_relations WHERE character_a_id IN ({placeholders}) AND character_b_id IN ({placeholders}) ORDER BY strength DESC, created_at DESC """ # Duplicate the character_ids for both IN clauses params = character_ids + character_ids results = await db.execute_query(sql, tuple(params)) return [ cls( id=row['id'], character_a_id=row['character_a_id'], character_b_id=row['character_b_id'], relation_type=row['relation_type'], description=row['description'], strength=row['strength'], created_at=row['created_at'], updated_at=row['updated_at'] ) for row in results ]

Latest Blog Posts

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/huangjien/writer-mcp'

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