Условные репозитории в Golang

В настоящее время я использую Go API, где у меня есть репозитории, позволяющие получать данные из базы данных MySQL.

Но я хотел бы реализовать те же репозитории для получения тех же данных, но из базы данных MongoDB, что сейчас для меня сложно.

Вот мой код:

// My vehicle repository file

// Repository handling Vehicle
type VehicleRepository struct {
    conn  *sqlx.DB
}

func (r *VehicleRepository) GetVehicles(ctx context.Context, brand string) (vehicle.Vehicle, error) {
    var vehicles []*vehicle.Vehicle
    param := map[string]interface{}{"brand": brand}

    query := "SELECT * FROM vehicles WHERE brand = :brand"

    rows, err := r.conn.NamedQueryContext(ctx, query, param)
    if err != nil {
        return nil, errors.Wrap(err, "query execution")
    }

    return vehicles, nil
}

// and in another file I create a repository object with all my repository (here only "Vehicle" but in reality I have plenty)
type Repositories struct {
    Vehicle    *VehicleRepository
}

func CreateRepositories(conn c.Connections) *Repositories {
    return &Repositories{
        Vehicles:      &VehicleRepository{conn, l},
    }
}

Этот код работает хорошо, но он обрабатывает только каждый случай одновременно (либо в режиме MySQL, либо в режиме MongoDB), но сейчас мне нужно обрабатывать как MySQL, так и MongoDB, и использовать репозиторий MongoDB в зависимости от моей конфигурации API, которую можно изменить. на лету.

Я пробовал несколько вещей:

1) Реализация различных репозиториев

Я попытался переименовать свой vehicle.go репозиторий vehicle.mysql.go и создать vehicle.mongodb.go, реализующий репозиторий mongodb. Я переименовал структуру VehicleRepository в VehicleMySQLRepository и создал VehicleMongoDBRepository в vehicle.mongodb.go, но когда я пытаюсь связать ее со своей Repositories в своей CreateRepositories, она ломается:

type Repositories struct {
    // Here I have `VehicleRepository` but it didn't exist anymore, and I can't set Vehicle to `VehicleMySQLRepository | VehicleMongoDBRepository`
    Vehicle    *VehicleRepository
}

func CreateRepositories(conn c.Connections, condition bool) *Repositories {
    if condition == true {
        return &Repositories{
            // Here I could do this:
            // Vehicles: &VehicleMySQLRepository{conn.Mysql, l},
            // Vehicles: &VehicleMongoDBRepository{conn.Mongo, l},
            // but it won't work because `Vehicles` will be declared multiple time, and I can't
            // have multiple `Vehicles` like `VehiclesMongo` & `VehiclesMysql`, etc...
            // because it will break all my calls on `Vehicles` in +50 files, and in reality
            // I've got over 30 repositories, if I need to duplicate each ones of them it won't do...

            Vehicles: &VehicleRepository{conn.Mongo, l},
        }
    }
    return &Repositories{
        Vehicles:     &VehicleRepository{conn.Mysql, l},
    }
}

2) Условная компиляция

Я подумал, что могу создать как vehicle.mysql.go, так и vehicle.mongodb.go, реализовав соответствующий репозиторий и скомпилировав его только с помощью go build -tags mongo и co. Это работает, но мне нужно обрабатывать оба репозитория одновременно, в моем интерфейсе пользователи могут выбирать, будут ли они использовать базу данных MySQL или MongoDB, поэтому я не могу каждый раз на лету перекомпилировать свой бэкэнд с хорошей реализацией.


3) Сохранение одних и тех же репозиториев

Я также пытался не менять репозиторий и обрабатывать соединение MySQL и MongoDB в самой функции, например, в методе GetVehicles() строка query условно устанавливается для запроса MySQL или запроса MongoDB, это работает, но реализация довольно грубая, я очень хотелось бы, чтобы вариант 1) работал.


Я не знаю, достаточно ли ясна моя проблема, при необходимости не стесняйтесь запрашивать дополнительную информацию в комментариях.

Вы можете реализовать это с помощью интерфейсов. Надеюсь это поможет. stackoverflow.com/questions/39092925/…

PRATHEESH PC 09.03.2024 16:15
Создание API ввода вопросов на разных языках программирования (Python, PHP, Go и Node.js)
Создание API ввода вопросов на разных языках программирования (Python, PHP, Go и Node.js)
API ввода вопросов - это полезный инструмент для интеграции моделей машинного обучения, таких как ChatGPT, в приложения, требующие обработки...
1
1
97
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

VehicleMySQLRepository и VehicleMongoDBRepository — это разные структуры. Поэтому в вашем коде невозможно иметь член репозитория с обоими типами в качестве членов.

Используйте интерфейсы вместо структур в качестве членов репозитория. Вот пример, созданный с использованием вашего кода в качестве ссылки.

package main

import (
    "context"
)

type Vehicle struct {
}

type VehicleRepository interface {
    GetVehicles(ctx context.Context, brand string) ([]Vehicle, error)
}

type VehicleMySQLRepository struct {
}

func (r *VehicleMySQLRepository) GetVehicles(ctx context.Context, brand string) ([]Vehicle, error) {
    var vehicles []Vehicle
    //...
    return vehicles, nil
}

type VehicleMongoRepository struct {
}

func (r *VehicleMongoRepository) GetVehicles(ctx context.Context, brand string) ([]Vehicle, error) {
    var vehicles []Vehicle
    //...
    return vehicles, nil
}

type Repositories struct {
    Vehicle VehicleRepository
}

type Connections struct {
}

func CreateRepositories(conn Connections, condition bool) *Repositories {
    if condition == true {
        return &Repositories{
            Vehicle: &VehicleMySQLRepository{},
        }
    }
    return &Repositories{
        Vehicle:     &VehicleMongoRepository{},
    }
}

func main() {

}

Другие вопросы по теме