package services import ( "fmt" "git.linuxforward.com/byop/byop-engine/dbstore" "git.linuxforward.com/byop/byop-engine/models" ) // AppService handles business logic for apps type AppService struct { store *dbstore.AppStore } // NewAppService creates a new AppService func NewAppService(store *dbstore.AppStore) *AppService { return &AppService{store: store} } // CreateApp creates a new deployment app func (s *AppService) CreateApp(app *models.App) error { // Validate app configuration if err := validateAppConfig(app.Config); err != nil { return fmt.Errorf("invalid app configuration: %w", err) } // Persist the app return s.store.Create(app) } // GetApp retrieves an app by ID func (s *AppService) GetApp(id int64) (*models.App, error) { app, err := s.store.GetByID(id) if err != nil { return nil, fmt.Errorf("failed to retrieve app: %w", err) } return app, nil } // UpdateApp updates an existing app func (s *AppService) UpdateApp(app *models.App) error { if app.ID == 0 { return fmt.Errorf("app ID is required for update") } // Check if app exists existingApp, err := s.store.GetByID(app.ID) if err != nil { return fmt.Errorf("failed to check if app exists: %w", err) } if existingApp == nil { return fmt.Errorf("app with ID %d not found", app.ID) } // Validate app configuration if err := validateAppConfig(app.Config); err != nil { return fmt.Errorf("invalid app configuration: %w", err) } return s.store.Update(app) } // DeleteApp deletes an app by ID func (s *AppService) DeleteApp(id int64) error { // Check if app exists app, err := s.store.GetByID(id) if err != nil { return fmt.Errorf("failed to check if app exists: %w", err) } if app == nil { return fmt.Errorf("app with ID %d not found", id) } // Check if the app has deployments appWithDeployments, err := s.store.GetAppWithDeployments(id) if err != nil { return fmt.Errorf("failed to check app deployments: %w", err) } // Don't allow deletion if there are active deployments if len(appWithDeployments.Deployments) > 0 { return fmt.Errorf("cannot delete app with active deployments") } return s.store.Delete(id) } // ListApps retrieves all apps with optional filtering func (s *AppService) ListApps(filter map[string]interface{}) ([]*models.App, error) { return s.store.List(filter) } // GetAppDeployments retrieves all deployments for an app func (s *AppService) GetAppDeployments(id int64) ([]models.Deployment, error) { // First check if the app exists app, err := s.store.GetByID(id) if err != nil { return nil, fmt.Errorf("failed to check if app exists: %w", err) } if app == nil { return nil, fmt.Errorf("app with ID %d not found", id) } // Get app with deployments appWithDeployments, err := s.store.GetAppWithDeployments(id) if err != nil { return nil, fmt.Errorf("failed to retrieve app deployments: %w", err) } return appWithDeployments.Deployments, nil } // GetAppByVersion retrieves an app by name and version func (s *AppService) GetAppByVersion(name, version string) (*models.App, error) { app, err := s.store.GetByVersion(name, version) if err != nil { return nil, fmt.Errorf("failed to retrieve app: %w", err) } return app, nil } // validateAppConfig validates the app configuration func validateAppConfig(config models.AppConfig) error { // Validate that at least one component is defined if len(config.Components) == 0 { return fmt.Errorf("app must define at least one component") } // Validate each component in the app for i, component := range config.Components { if component.Name == "" { return fmt.Errorf("component at index %d must have a name", i) } // Validate resource configuration if component.Resources.CPU == "" { return fmt.Errorf("component '%s' must specify CPU resources", component.Name) } if component.Resources.Memory == "" { return fmt.Errorf("component '%s' must specify memory resources", component.Name) } } // Add additional validation logic as needed return nil }