Назад к вопросам
Middle+
5
Реализуй метод BulkCreateUsers на основе proto-файла: создай структуру проекта, бизнес-логику, репозиторий и SQL-запросы с соблюдением принципов SOLID
Компании, где спрашивали
Яндекс
Ответ от нейросети
sobes.tech AI
Для реализации метода BulkCreateUsers на Go с использованием protobuf и соблюдением SOLID можно построить проект так:
- Структура проекта:
/internal
/repository
user_repository.go
/service
user_service.go
/model
user.go
/proto
user.proto
/cmd
main.go
- 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);
}
- Модель пользователя (model/user.go):
type User struct {
ID string
Name string
Email string
}
- Репозиторий (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
}
- Сервис (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, особенно единственной ответственности и инверсии зависимостей.