Skip to main content
Glama
complex_example.go14.1 kB
package main import ( "context" "encoding/json" "errors" "fmt" "log" "sync" "time" ) // Constants const ( MaxConnections = 100 DefaultTimeout = 30 * time.Second APIVersion = "1.0.0" ) // Error types var ( ErrNotConnected = errors.New("not connected to database") ErrUserNotFound = errors.New("user not found") ErrInvalidEmail = errors.New("invalid email format") ErrValidationFailed = errors.New("validation failed") ) // Interfaces type DatabaseConnection interface { Connect(ctx context.Context) error ExecuteQuery(ctx context.Context, query string, args ...interface{}) (*QueryResult, error) Close() error BeginTransaction(ctx context.Context) (Transaction, error) } type Transaction interface { Commit() error Rollback() error ExecuteQuery(ctx context.Context, query string, args ...interface{}) (*QueryResult, error) } type Cache interface { Get(key string) (interface{}, bool) Set(key string, value interface{}, ttl time.Duration) Delete(key string) Clear() } type Logger interface { Info(msg string, fields ...interface{}) Error(msg string, fields ...interface{}) Debug(msg string, fields ...interface{}) Warn(msg string, fields ...interface{}) } // Database implementations type PostgresConnection struct { host string port int database string username string password string connected bool mu sync.RWMutex } func NewPostgresConnection(host string, port int, database, username, password string) *PostgresConnection { return &PostgresConnection{ host: host, port: port, database: database, username: username, password: password, } } func (p *PostgresConnection) Connect(ctx context.Context) error { p.mu.Lock() defer p.mu.Unlock() // Simulate connection logic select { case <-time.After(100 * time.Millisecond): p.connected = true return nil case <-ctx.Done(): return ctx.Err() } } func (p *PostgresConnection) ExecuteQuery(ctx context.Context, query string, args ...interface{}) (*QueryResult, error) { p.mu.RLock() defer p.mu.RUnlock() if !p.connected { return nil, ErrNotConnected } // Simulate query execution select { case <-time.After(50 * time.Millisecond): return &QueryResult{Rows: []map[string]interface{}{}}, nil case <-ctx.Done(): return nil, ctx.Err() } } func (p *PostgresConnection) Close() error { p.mu.Lock() defer p.mu.Unlock() p.connected = false return nil } func (p *PostgresConnection) BeginTransaction(ctx context.Context) (Transaction, error) { return &PostgresTransaction{conn: p}, nil } type PostgresTransaction struct { conn *PostgresConnection } func (t *PostgresTransaction) Commit() error { return nil } func (t *PostgresTransaction) Rollback() error { return nil } func (t *PostgresTransaction) ExecuteQuery(ctx context.Context, query string, args ...interface{}) (*QueryResult, error) { return t.conn.ExecuteQuery(ctx, query, args...) } type MySQLConnection struct { connectionString string connected bool } func NewMySQLConnection(connectionString string) *MySQLConnection { return &MySQLConnection{ connectionString: connectionString, } } func (m *MySQLConnection) Connect(ctx context.Context) error { m.connected = true return nil } func (m *MySQLConnection) ExecuteQuery(ctx context.Context, query string, args ...interface{}) (*QueryResult, error) { if !m.connected { return nil, ErrNotConnected } return &QueryResult{Rows: []map[string]interface{}{}}, nil } func (m *MySQLConnection) Close() error { m.connected = false return nil } func (m *MySQLConnection) BeginTransaction(ctx context.Context) (Transaction, error) { return &MySQLTransaction{conn: m}, nil } type MySQLTransaction struct { conn *MySQLConnection } func (t *MySQLTransaction) Commit() error { return nil } func (t *MySQLTransaction) Rollback() error { return nil } func (t *MySQLTransaction) ExecuteQuery(ctx context.Context, query string, args ...interface{}) (*QueryResult, error) { return t.conn.ExecuteQuery(ctx, query, args...) } // Cache implementation type MemoryCache struct { data map[string]cacheItem mu sync.RWMutex } type cacheItem struct { value interface{} expiry time.Time } func NewMemoryCache() *MemoryCache { cache := &MemoryCache{ data: make(map[string]cacheItem), } // Start cleanup goroutine go cache.cleanup() return cache } func (c *MemoryCache) Get(key string) (interface{}, bool) { c.mu.RLock() defer c.mu.RUnlock() item, exists := c.data[key] if !exists { return nil, false } if time.Now().After(item.expiry) { delete(c.data, key) return nil, false } return item.value, true } func (c *MemoryCache) Set(key string, value interface{}, ttl time.Duration) { c.mu.Lock() defer c.mu.Unlock() c.data[key] = cacheItem{ value: value, expiry: time.Now().Add(ttl), } } func (c *MemoryCache) Delete(key string) { c.mu.Lock() defer c.mu.Unlock() delete(c.data, key) } func (c *MemoryCache) Clear() { c.mu.Lock() defer c.mu.Unlock() c.data = make(map[string]cacheItem) } func (c *MemoryCache) cleanup() { ticker := time.NewTicker(1 * time.Minute) defer ticker.Stop() for range ticker.C { c.mu.Lock() now := time.Now() for key, item := range c.data { if now.After(item.expiry) { delete(c.data, key) } } c.mu.Unlock() } } // Data models type User struct { ID int64 `json:"id"` Username string `json:"username"` Email string `json:"email"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` IsActive bool `json:"is_active"` Metadata map[string]interface{} `json:"metadata"` } func NewUser(username, email string) *User { now := time.Now() return &User{ ID: time.Now().UnixNano(), // Simple ID generation Username: username, Email: email, CreatedAt: now, UpdatedAt: now, IsActive: true, Metadata: make(map[string]interface{}), } } func (u *User) ValidateEmail() bool { // Simple email validation return len(u.Email) > 0 && len(u.Email) < 255 && contains(u.Email, "@") && contains(u.Email, ".") } func (u *User) UpdateTimestamp() { u.UpdatedAt = time.Now() } func (u *User) ToJSON() ([]byte, error) { return json.Marshal(u) } func UserFromJSON(data []byte) (*User, error) { var user User err := json.Unmarshal(data, &user) return &user, err } type Product struct { ID int64 `json:"id"` Name string `json:"name"` Price float64 `json:"price"` Category string `json:"category"` Description string `json:"description"` Tags []string `json:"tags"` CreatedAt time.Time `json:"created_at"` } func NewProduct(name string, price float64, category string) *Product { return &Product{ ID: time.Now().UnixNano(), Name: name, Price: price, Category: category, Tags: make([]string, 0), CreatedAt: time.Now(), } } func (p *Product) AddTag(tag string) { for _, existingTag := range p.Tags { if existingTag == tag { return // Tag already exists } } p.Tags = append(p.Tags, tag) } // Service layer type UserService struct { db DatabaseConnection cache Cache logger Logger } func NewUserService(db DatabaseConnection, cache Cache, logger Logger) *UserService { return &UserService{ db: db, cache: cache, logger: logger, } } func (s *UserService) CreateUser(ctx context.Context, username, email string) (*User, error) { user := NewUser(username, email) if !user.ValidateEmail() { s.logger.Error("Invalid email format", "email", email) return nil, ErrInvalidEmail } tx, err := s.db.BeginTransaction(ctx) if err != nil { s.logger.Error("Failed to begin transaction", "error", err) return nil, err } defer func() { if err != nil { tx.Rollback() } }() query := "INSERT INTO users (username, email, created_at, updated_at) VALUES ($1, $2, $3, $4)" _, err = tx.ExecuteQuery(ctx, query, user.Username, user.Email, user.CreatedAt, user.UpdatedAt) if err != nil { s.logger.Error("Failed to insert user", "error", err, "username", username) return nil, err } err = tx.Commit() if err != nil { s.logger.Error("Failed to commit transaction", "error", err) return nil, err } // Cache the user cacheKey := fmt.Sprintf("user:%d", user.ID) s.cache.Set(cacheKey, user, 1*time.Hour) s.logger.Info("User created successfully", "user_id", user.ID, "username", username) return user, nil } func (s *UserService) GetUser(ctx context.Context, id int64) (*User, error) { // Check cache first cacheKey := fmt.Sprintf("user:%d", id) if cached, found := s.cache.Get(cacheKey); found { if user, ok := cached.(*User); ok { s.logger.Debug("User found in cache", "user_id", id) return user, nil } } // Query database query := "SELECT id, username, email, created_at, updated_at, is_active FROM users WHERE id = $1" result, err := s.db.ExecuteQuery(ctx, query, id) if err != nil { s.logger.Error("Failed to query user", "error", err, "user_id", id) return nil, err } if len(result.Rows) == 0 { return nil, ErrUserNotFound } row := result.Rows[0] user := &User{ ID: row["id"].(int64), Username: row["username"].(string), Email: row["email"].(string), CreatedAt: row["created_at"].(time.Time), UpdatedAt: row["updated_at"].(time.Time), IsActive: row["is_active"].(bool), Metadata: make(map[string]interface{}), } // Cache the result s.cache.Set(cacheKey, user, 1*time.Hour) s.logger.Debug("User retrieved from database", "user_id", id) return user, nil } func (s *UserService) UpdateUser(ctx context.Context, id int64, updates map[string]interface{}) error { user, err := s.GetUser(ctx, id) if err != nil { return err } // Apply updates if username, ok := updates["username"]; ok { user.Username = username.(string) } if email, ok := updates["email"]; ok { user.Email = email.(string) } if isActive, ok := updates["is_active"]; ok { user.IsActive = isActive.(bool) } user.UpdateTimestamp() // Update cache cacheKey := fmt.Sprintf("user:%d", id) s.cache.Set(cacheKey, user, 1*time.Hour) s.logger.Info("User updated successfully", "user_id", id) return nil } // Configuration type AppConfig struct { DebugMode bool `json:"debug_mode"` LogLevel string `json:"log_level"` DatabaseURL string `json:"database_url"` CacheSize int `json:"cache_size"` MaxConnections int `json:"max_connections"` RequestTimeout time.Duration `json:"request_timeout"` } func NewAppConfig() *AppConfig { return &AppConfig{ DebugMode: false, LogLevel: "INFO", DatabaseURL: "postgresql://localhost:5432/myapp", CacheSize: 1000, MaxConnections: MaxConnections, RequestTimeout: DefaultTimeout, } } func (c *AppConfig) LoadFromEnv() { // In a real implementation, this would load from environment variables c.DebugMode = true c.LogLevel = "DEBUG" } // Logger implementation type ConsoleLogger struct { level string } func NewConsoleLogger(level string) *ConsoleLogger { return &ConsoleLogger{level: level} } func (l *ConsoleLogger) Info(msg string, fields ...interface{}) { l.log("INFO", msg, fields...) } func (l *ConsoleLogger) Error(msg string, fields ...interface{}) { l.log("ERROR", msg, fields...) } func (l *ConsoleLogger) Debug(msg string, fields ...interface{}) { if l.level == "DEBUG" { l.log("DEBUG", msg, fields...) } } func (l *ConsoleLogger) Warn(msg string, fields ...interface{}) { l.log("WARN", msg, fields...) } func (l *ConsoleLogger) log(level, msg string, fields ...interface{}) { timestamp := time.Now().Format(time.RFC3339) fmt.Printf("[%s] %s: %s", level, timestamp, msg) for i := 0; i < len(fields); i += 2 { if i+1 < len(fields) { fmt.Printf(" %v=%v", fields[i], fields[i+1]) } } fmt.Println() } // Query result type QueryResult struct { Rows []map[string]interface{} RowCount int } // Utility functions func InitializeDatabase(config *AppConfig) (DatabaseConnection, error) { if contains(config.DatabaseURL, "postgresql") { return NewPostgresConnection("localhost", 5432, "myapp", "user", "password"), nil } else if contains(config.DatabaseURL, "mysql") { return NewMySQLConnection(config.DatabaseURL), nil } return nil, errors.New("unsupported database type") } func contains(s, substr string) bool { return len(s) >= len(substr) && (s == substr || (len(s) > len(substr) && (s[:len(substr)] == substr || s[len(s)-len(substr):] == substr || containsSubstring(s, substr)))) } func containsSubstring(s, substr string) bool { for i := 0; i <= len(s)-len(substr); i++ { if s[i:i+len(substr)] == substr { return true } } return false } // Main application func main() { ctx := context.Background() config := NewAppConfig() config.LoadFromEnv() logger := NewConsoleLogger(config.LogLevel) db, err := InitializeDatabase(config) if err != nil { log.Fatal("Failed to initialize database:", err) } err = db.Connect(ctx) if err != nil { log.Fatal("Failed to connect to database:", err) } defer db.Close() cache := NewMemoryCache() userService := NewUserService(db, cache, logger) // Create sample user user, err := userService.CreateUser(ctx, "john_doe", "john@example.com") if err != nil { logger.Error("Failed to create user", "error", err) return } logger.Info("Created user successfully", "user", user.Username) // Get user retrievedUser, err := userService.GetUser(ctx, user.ID) if err != nil { logger.Error("Failed to get user", "error", err) return } logger.Info("Retrieved user successfully", "user", retrievedUser.Username) // Update user updates := map[string]interface{}{ "is_active": false, } err = userService.UpdateUser(ctx, user.ID, updates) if err != nil { logger.Error("Failed to update user", "error", err) return } logger.Info("Application completed successfully") }

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/kensave/CodeCortX-MCP'

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