evnuh
@evnuh
Поиск Гугл помог мне, впусти и ты его в свой дом

Смаршалить в JSON поля внешней структуры через метод внутренней, или один метод для всех типов?

Итак, дженериков нет, пытаюсь решить тупейшую проблему.

Есть структуры
type User struct {
   ID int
   Name string
}

type Admin struct {
   User
   Level int
}

И еще структур типа Admin много, все они включают в себя User

Теперь хочу сохранять их в базу, в которой всё в json. Задача: написать один раз метод/функцию сохранения, а не дублировать код для каждого типа.
То есть хочу иметь одну функцию, которая будет:
1. Маршалить структуру со всеми полями. То есть User превратится в {id: 1, name: "zhora"}, а Admin превратится в {id: 1, name: "gena", level: 2}
2. Сохранить этот json в базу по ID.

func (i *User) Save() {
	data, err := json.Marshal(i)
	check(err)
	if i.ID == 0 {
		_, err = app.DB.Exec(`INSERT INTO users(data) VALUES ($1) `, string(data))
	} else {
		_, err = app.DB.Exec(`UPDATE users SET data = $1 WHERE id=$2`, string(data), i.ID)
	}
	check(err)
}


Сейчас приходится для каждого нового типа тупо копировать целиком функцию, изменяя только тип ресивера. Можно ли этого избежать?
  • Вопрос задан
  • 196 просмотров
Решения вопроса 2
bitver
@bitver
Разрабатывая на go я уяснил одну очень важную особенность - нельзя думать так как бы вы это делали на другом языке, а надо думать как в go. Не хочу вдаваться в вашу проблему, но думаю что есть выход, например, не создавать столько структур.

По вопросу: делаете интерфейс с геттерами/сеттерами и 1 функцию принимающую этот интерфейс в качестве аргумента. Юзаете функцию, отдавая ей ссылку на объект структуры.

Да-да, не получится сделать метод, и сделать через задницу, но это по меркам многих других языков, в го - это норма.

Можно ещё поиграться с рефлексией или генераторами. 1ое не go-way, 2ое норм, но надо заморочится с генерацией.
Ответ написан
evnuh
@evnuh Автор вопроса
Поиск Гугл помог мне, впусти и ты его в свой дом
Решение дали на stackoverflow и как подсказал Никита

Решение простое -
func Save(i interface{}, id int) {
    data, err := json.Marshal(i)
    check(err)
    if id == 0 {
        _, err = app.DB.Exec(`INSERT INTO users(data) VALUES ($1) `, string(data))
    } else {
        _, err = app.DB.Exec(`UPDATE users SET data = $1 WHERE id=$2`, string(data), id)
    }
    check(err)
}

и вызывать
u := User{}
a := Admin{}

Save(u, u.ID)
Save(a, a.ID)


Мне потом ещё потребовалось присваивать ID, вернувшееся из базы обратно в структуру, поэтому я сделал
interface Model {
    getID()
    setID()
}

Сделал реализацию этого интерфейса для User и использовал его вместо interface{}
func Save(i model) {
	data, err := json.Marshal(i)
	var id int
	check(err)
	if i.getID() == 0 {
		err = app.DB.QueryRow(`INSERT INTO users(data) VALUES ($1) RETURNING id`, string(data)).Scan(&id)
		i.setID(id)
	} else {
		_, err = app.DB.Exec(`UPDATE users SET data = $1 WHERE id=$2`, string(data), i.getID())
	}
	check(err)
}
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы