123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200 |
- package dbstore
- import (
- "context"
- "database/sql"
- "fmt"
- "git.linuxforward.com/byop/byop-engine/models"
- "github.com/pkg/errors"
- )
- // Component operations
- func (s *SQLiteStore) CreateComponent(ctx context.Context, component *models.Component) (int, error) {
- query := `INSERT INTO components (user_id, name, description, type, status, config, repository, branch) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`
- result, err := s.db.ExecContext(ctx, query, component.UserID, component.Name, component.Description, component.Type, component.Status, component.Config, component.Repository, component.Branch)
- if err != nil {
- return 0, models.NewErrInternalServer("failed to create component", err)
- }
- id, err := result.LastInsertId()
- if err != nil {
- return 0, models.NewErrInternalServer("failed to get last insert ID for component", err)
- }
- return int(id), nil
- }
- func (s *SQLiteStore) GetComponentsByUserID(ctx context.Context, userID int) ([]models.Component, error) {
- query := `SELECT id, user_id, name, description, type, status, config, repository, branch, error_msg, current_image_tag, current_image_uri, created_at, updated_at FROM components WHERE user_id = ?`
- rows, err := s.db.QueryContext(ctx, query, userID)
- if err != nil {
- return nil, models.NewErrInternalServer(fmt.Sprintf("failed to query components for user ID %d", userID), err)
- }
- defer rows.Close()
- var components []models.Component
- for rows.Next() {
- var component models.Component
- err := rows.Scan(&component.ID, &component.UserID, &component.Name, &component.Description, &component.Type, &component.Status, &component.Config, &component.Repository, &component.Branch, &component.ErrorMsg, &component.CurrentImageTag, &component.CurrentImageURI, &component.CreatedAt, &component.UpdatedAt)
- if err != nil {
- return nil, models.NewErrInternalServer("failed to scan component row", err)
- }
- components = append(components, component)
- }
- if err = rows.Err(); err != nil {
- return nil, models.NewErrInternalServer(fmt.Sprintf("error iterating component rows for user ID %d", userID), err)
- }
- return components, nil
- }
- // GetAllComponents retrieves all components
- func (s *SQLiteStore) GetAllComponents(ctx context.Context) ([]models.Component, error) {
- query := `SELECT id, user_id, name, description, type, status, config, repository, branch, error_msg, current_image_tag, current_image_uri, created_at, updated_at FROM components`
- rows, err := s.db.QueryContext(ctx, query)
- if err != nil {
- return nil, models.NewErrInternalServer("failed to query all components", err)
- }
- defer rows.Close()
- var components []models.Component
- for rows.Next() {
- var component models.Component
- err := rows.Scan(&component.ID, &component.UserID, &component.Name, &component.Description, &component.Type, &component.Status, &component.Config, &component.Repository, &component.Branch, &component.ErrorMsg, &component.CurrentImageTag, &component.CurrentImageURI, &component.CreatedAt, &component.UpdatedAt)
- if err != nil {
- return nil, models.NewErrInternalServer("failed to scan component row", err)
- }
- components = append(components, component)
- }
- if err = rows.Err(); err != nil {
- return nil, models.NewErrInternalServer("error iterating all component rows", err)
- }
- return components, nil
- }
- // GetComponentByID retrieves a component by ID
- func (s *SQLiteStore) GetComponentByID(ctx context.Context, id int) (*models.Component, error) {
- component := &models.Component{}
- query := `SELECT id, user_id, name, description, type, status, config, repository, branch, error_msg, current_image_tag, current_image_uri, created_at, updated_at FROM components WHERE id = ?`
- err := s.db.QueryRowContext(ctx, query, id).Scan(&component.ID, &component.UserID, &component.Name, &component.Description, &component.Type, &component.Status, &component.Config, &component.Repository, &component.Branch, &component.ErrorMsg, &component.CurrentImageTag, &component.CurrentImageURI, &component.CreatedAt, &component.UpdatedAt)
- if err != nil {
- if errors.Is(err, sql.ErrNoRows) {
- return nil, models.NewErrNotFound(fmt.Sprintf("component with ID %d not found", id), err)
- }
- return nil, models.NewErrInternalServer(fmt.Sprintf("failed to get component with ID %d", id), err)
- }
- return component, nil
- }
- // UpdateComponent updates an existing component
- func (s *SQLiteStore) UpdateComponent(ctx context.Context, component models.Component) error {
- query := `UPDATE components SET name = ?, description = ?, type = ?, status = ?, config = ?, repository = ?, branch = ?, current_image_tag = ?, current_image_uri = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?`
- result, err := s.db.ExecContext(ctx, query, component.Name, component.Description, component.Type, component.Status, component.Config, component.Repository, component.Branch, component.CurrentImageTag, component.CurrentImageURI, component.ID)
- if err != nil {
- return models.NewErrInternalServer(fmt.Sprintf("failed to update component with ID %d", component.ID), err)
- }
- rowsAffected, err := result.RowsAffected()
- if err != nil {
- return models.NewErrInternalServer(fmt.Sprintf("failed to get rows affected for component update ID %d", component.ID), err)
- }
- if rowsAffected == 0 {
- return models.NewErrNotFound(fmt.Sprintf("component with ID %d not found for update", component.ID), nil)
- }
- return nil
- }
- // UpdateComponentStatus updates the validation status of a component
- func (s *SQLiteStore) UpdateComponentStatus(ctx context.Context, id int, status, errorMsg string) error {
- query := `
- UPDATE components
- SET status = ?, error_msg = ?, updated_at = CURRENT_TIMESTAMP
- WHERE id = ?
- `
- result, err := s.db.ExecContext(ctx, query, status, errorMsg, id)
- if err != nil {
- return models.NewErrInternalServer(fmt.Sprintf("failed to update component status for ID %d", id), err)
- }
- rowsAffected, err := result.RowsAffected()
- if err != nil {
- return models.NewErrInternalServer(fmt.Sprintf("failed to get rows affected for component status update ID %d", id), err)
- }
- if rowsAffected == 0 {
- return models.NewErrNotFound(fmt.Sprintf("component with ID %d not found for status update", id), nil)
- }
- return nil
- }
- // UpdateComponentImageInfo updates the image information for a component after a successful build
- func (s *SQLiteStore) UpdateComponentImageInfo(ctx context.Context, componentID int, imageTag, imageURI string) error {
- query := `
- UPDATE components
- SET current_image_tag = ?, current_image_uri = ?, updated_at = CURRENT_TIMESTAMP
- WHERE id = ?
- `
- result, err := s.db.ExecContext(ctx, query, imageTag, imageURI, componentID)
- if err != nil {
- return models.NewErrInternalServer(fmt.Sprintf("failed to update component image info for ID %d", componentID), err)
- }
- rowsAffected, err := result.RowsAffected()
- if err != nil {
- return models.NewErrInternalServer(fmt.Sprintf("failed to get rows affected for component image info update ID %d", componentID), err)
- }
- if rowsAffected == 0 {
- return models.NewErrNotFound(fmt.Sprintf("component with ID %d not found for image info update", componentID), nil)
- }
- return nil
- }
- // DeleteComponent deletes a component by ID with verification checks
- func (s *SQLiteStore) DeleteComponent(ctx context.Context, id int) error {
- // First check if the component exists
- _, err := s.GetComponentByID(ctx, id)
- if err != nil {
- return err // GetComponentByID already returns custom errors
- }
- // Check if the component is used in any apps
- apps, err := s.GetAllApps(ctx) // Use context-aware GetAllApps
- if err != nil {
- // GetAllApps should return a custom error if it fails
- return models.NewErrInternalServer(fmt.Sprintf("failed to check component usage in apps for component ID %d", id), err)
- }
- var appsUsingComponent []string
- for _, app := range apps {
- for _, componentID := range app.Components {
- if componentID == id {
- appsUsingComponent = append(appsUsingComponent, app.Name)
- break
- }
- }
- }
- if len(appsUsingComponent) > 0 {
- return models.NewErrConflict(fmt.Sprintf("cannot delete component: it is used in the following app(s): %v. Please remove it from these apps first", appsUsingComponent), nil)
- }
- // If no apps use this component, proceed with deletion
- query := `DELETE FROM components WHERE id = ?`
- result, err := s.db.ExecContext(ctx, query, id)
- if err != nil {
- return models.NewErrInternalServer(fmt.Sprintf("failed to delete component with ID %d", id), err)
- }
- rowsAffected, err := result.RowsAffected()
- if err != nil {
- return models.NewErrInternalServer(fmt.Sprintf("failed to get rows affected for component deletion ID %d", id), err)
- }
- if rowsAffected == 0 {
- // This case should ideally be caught by GetComponentByID earlier, but as a safeguard:
- return models.NewErrNotFound(fmt.Sprintf("component with ID %d not found for deletion", id), nil)
- }
- return nil
- }
|