Sobes.tech
Back to questions
Middle+
4

Реализуй метод BulkCreateUsers на основе proto-файла: создай структуру проекта, бизнес-логику, репозиторий и SQL-запросы с соблюдением принципов SOLID

Companies where asked
Яндекс

Answer from AI

sobes.tech AI

Для реализации метода BulkCreateUsers на Go с использованием protobuf и соблюдением SOLID можно построить проект так:

  1. Структура проекта:
/internal
  /repository
    user_repository.go
  /service
    user_service.go
  /model
    user.go
  /proto
    user.proto
/cmd
  main.go
  1. Proto-файл (user.proto):
syntax = "proto3";
package user;

message User {
  string id = 1;
  string name = 2;
  string email = 3;
}

message BulkCreateUsersRequest {
  repeated User users = 1;
}

message BulkCreateUsersResponse {
  int32 created_count = 1;
}

service UserService {
  rpc BulkCreateUsers(BulkCreateUsersRequest) returns (BulkCreateUsersResponse);
}
  1. Модель пользователя (model/user.go):
type User struct {
  ID    string
  Name  string
  Email string
}
  1. Репозиторий (repository/user_repository.go):
package repository

import (
  "context"
  "database/sql"
  "strings"
  "your_project/internal/model"
)

type UserRepository interface {
  BulkCreate(ctx context.Context, users []model.User) (int, error)
}

type userRepository struct {
  db *sql.DB
}

func NewUserRepository(db *sql.DB) UserRepository {
  return &userRepository{db: db}
}

func (r *userRepository) BulkCreate(ctx context.Context, users []model.User) (int, error) {
  if len(users) == 0 {
    return 0, nil
  }

  // Пример SQL-запроса для bulk insert
  var (
    valueStrings []string
    valueArgs    []interface{}
  )

  for i, user := range users {
    valueStrings = append(valueStrings, fmt.Sprintf("($%d, $%d, $%d)", i*3+1, i*3+2, i*3+3))
    valueArgs = append(valueArgs, user.ID, user.Name, user.Email)
  }

  stmt := fmt.Sprintf("INSERT INTO users (id, name, email) VALUES %s", strings.Join(valueStrings, ","))

  res, err := r.db.ExecContext(ctx, stmt, valueArgs...)
  if err != nil {
    return 0, err
  }

  count, err := res.RowsAffected()
  if err != nil {
    return 0, err
  }

  return int(count), nil
}
  1. Сервис (service/user_service.go):
package service

import (
  "context"
  "your_project/internal/model"
  "your_project/internal/repository"
)

type UserService interface {
  BulkCreateUsers(ctx context.Context, users []model.User) (int, error)
}

type userService struct {
  repo repository.UserRepository
}

func NewUserService(repo repository.UserRepository) UserService {
  return &userService{repo: repo}
}

func (s *userService) BulkCreateUsers(ctx context.Context, users []model.User) (int, error) {
  // Валидация, бизнес-логика и т.д.
  // Например, проверка уникальности email, фильтрация пустых значений и т.п.

  return s.repo.BulkCreate(ctx, users)
}

Такой подход разделяет ответственность: репозиторий отвечает за работу с БД, сервис — за бизнес-логику, а proto-файл определяет контракт API. Это соответствует принципам SOLID, особенно единственной ответственности и инверсии зависимостей.