many2many in Gorm, really - go

I'm trying to use the many-to-many relationship in gorm. However, the example is a partial snippet, and my attempt at creating a similar example snippet is failing.
package main
import (
"github.com/jinzhu/gorm"
_ "github.com/mattn/go-sqlite3"
)
type Part struct {
gorm.Model
Name string
}
type Machine struct {
gorm.Model
Name string
Subtasks []Part `gorm:"many2many:parts;"`
}
func main() {
// Connect to the database
db, err := gorm.Open("sqlite3", "example.db")
if err != nil {
panic(err)
}
defer db.Close()
db.LogMode(true)
// Set up associations
if err := db.CreateTable(&Part{}).Error; err != nil {
panic(err)
}
if err := db.CreateTable(&Machine{}).Related(&[]Part{}).Error; err != nil {
panic(err)
}
}
This panics on the last CreateTable call: panic: invalid association []

I think you have to drop the Related-part. CreateTable doesnt need it as far as i can see.
if err := db.CreateTable(&Machine{}).Error; err != nil {
panic(err)
}
Works for me

Related

golang test error "cannot use as error value in assignment: *"gorm.io/gorm".DB does not implement error"

I am trying to test user registration with echo but I get an error.
Here is the specific error.
cannot use r.Create(id, name, password, email) (value of type *"gorm.io/gorm".DB) as error value in assignment: *"gorm.io/gorm".DB does not implement error
How can I resolve this error to make a correct test?
package test
import (
"regexp"
"testing"
sqlmock "github.com/DATA-DOG/go-sqlmock"
"github.com/...../model"
"github.com/jinzhu/gorm"
)
func getDBMock() (*gorm.DB, sqlmock.Sqlmock, error) {
db, mock, err := sqlmock.New()
if err != nil {
return nil, nil, err
}
gdb, err := gorm.Open("postgres", db)
if err != nil {
return nil, nil, err
}
return gdb, mock, nil
}
func TestCreate(t *testing.T) {
db, mock, err := getDBMock()
if err != nil {
t.Fatal(err)
}
defer db.Close()
db.LogMode(true)
r := model.Repository{DB: db}
id := "2222"
name := "BBBB"
password := "mfsdmSD34"
email := "dmvsdmvo#.com"
// Mock設定
mock.ExpectQuery(regexp.QuoteMeta(
`INSERT INTO "users" ("id","name","passowrd","email") VALUES ($1,$2,$3,$4)
RETURNING "users"."id"`)).WithArgs(id, name,password,email).
WillReturnRows(sqlmock.NewRows([]string{"id"}).AddRow(id))
// 実行
err = r.Create(id, name,password,email)
if err != nil {
t.Fatal(err)
}
}
package model
type User struct {
ID int `json:"id" gorm:"praimaly_key"`
Name string `json:"name"`
Password string `json:"password"`
Email string `json:"email"`
}
func CreateUser(user *User) {
db.Create(user)
}
func FindUser(u *User) User {
var user User
db.Where(u).First(&user)
return user
}
package model
import (
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
var db *gorm.DB
func init() {
var err Error
dsn := "user:pass#tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local"
db, err = gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
panic("failed to connect database")
}
db.AutoMigrate(&User{})
db.AutoMigrate(&Todo{})
}

Recommended way to make a client

Let's assume that I want to make a client, for example, MySQL client (but my question is generic and not just for MySQL client, any client), this is a sample code
func main() {
db, err := sql.Open("mysql", "root:<yourMySQLdatabasepassword>#tcp(127.0.0.1:3306)/test")
if err != nil {
panic(err.Error())
}
defer db.Close()
}
I want to move it into a function so I don't have to initialize it all over the place and here my question begins I can do it in various ways and I want to know which one is the recommended way
Here is functional way
func client() (client *sql.DB, err error) {
client, err = sql.Open("mysql", "root:<yourMySQLdatabasepassword>#tcp(127.0.0.1:3306)/test")
if err != nil {
panic(err.Error())
}
return
}
Global variable way
var client, err = sql.Open("mysql", "root:<yourMySQLdatabasepassword>#tcp(127.0.0.1:3306)/test")
init func way
var Client *sql.DB
func init() {
Client, err := sql.Open("mysql", "root:root#tcp(localhost:3306)/otp")
if err != nil {
panic(err.Error())
}
}
and finally struct way
type MSQL struct {
// Fields...
}
func (m *MSQL) Client() *sql.DB {
client, err := sql.Open("mysql", "root:<yourMySQLdatabasepassword>#tcp(127.0.0.1:3306)/test")
if err != nil {
panic(err.Error())
}
return client
}
// NewMysql().where(...)
I'm really confused here to select which one to follow
Exposing a public variable var Client *sql.DB is error prone as I can do <package>.Client = null from anywhere.
struct way is the way to go, As you can work with multiple connection each to a specific database at any time.
You can also use New() to pass in a config object or other props to customise other db props. like Max Connection.
package database;
type Db struct{
*db sql.DB
}
func New(driver, connection string) *Db {
db, err := sql.Open(driver, connection)
if err != nil {
panic(err)
}
if err = db.Ping(); err != nil {
panic(err)
}
/* configure details
db.SetConnMaxLifetime(conLifeTime)
db.SetMaxOpenConns(maxOpenConns)
db.SetMaxIdleConns(maxIdleConns)
*/
return &Db{db}
}
func (d *Db) Close() error {
return d.db.Close();
}
Its generic, you can pass any driver & connection string for creating a connection to any database.
connection database.New("mysql", "root:<yourMySQLdatabasepassword>#tcp(127.0.0.1:3306)/test")
usage database.Db.Where(...)
close connection database.Db.Close()

There is already an object named 'company_names' in the database

I use Gorm for Golang like this code,
func Connect() (*gorm.DB, error) {
var (
err error
db *gorm.DB
)
dsn := "sqlserver://User:12345#127.0.0.1:1433?database=gorm"
db, err = gorm.Open(sqlserver.Open(dsn), &gorm.Config{})
if err != nil {
return nil, err
}
err = db.Debug().AutoMigrate(&models.CompanyName{}, &models.CarModel{}, &models.CreateYear{}, &models.Diversity{})
if err != nil {
return nil, err
}
return db, nil
}
and in main.go
func main() {
db, err := Connect()
if err != nil {
panic("database connection failed")
}
ech := echo.New()
}
Ok in the first time when we run code, gorm create tables in database,but in the second time I got an error thet
mssql: There is already an object named 'table_names' in the database.
Do I have to delete db.Debug().AutoMigrate)(?

Calling function of a struct imported via plugin

I've a following plugin:
package main
type Test struct {
Id string
}
func (test *Test) GetId() string {
return test.Id
}
var V Test
I'm importing it within my app:
package main
import (
"fmt"
"plugin"
)
func main() {
p, err := plugin.Open("test.so")
if err != nil {
panic(err)
}
v, err := p.Lookup("V")
if err != nil {
panic(err)
}
fmt.Println(v)
}
Unfortunately I'm not able to call v.getId() on it - is there a way to expose all functions that are set on the given struct?
Lookup returns a Symbol, which is just an empty interface. In order to use this you need to assert the type you want. The documentation for Symbol example shows both symbols asserted to the expected types:
v, err := p.Lookup("V")
if err != nil {
panic(err)
}
f, err := p.Lookup("F")
if err != nil {
panic(err)
}
*v.(*int) = 7
f.(func())() // prints "Hello, number 7"
To do that in your program, create the type you want, which in this case is an interface because you're looking for a particular method set (see the "Tour of Go" section on interfaces, esp implicit implementation and type assertion)
Here we create the V interface in the main program to define the method we want, than use a type assertion on the symbol returned from Lookup:
type V interface {
GetId() string
}
func main() {
p, err := plugin.Open("plugin.so")
if err != nil {
panic(err)
}
s, err := p.Lookup("V")
if err != nil {
panic(err)
}
v := s.(V)
fmt.Println(v.GetId())
}

Golang import struct and share over all app

I would like to import package and create new struct in main() func.
// main.go
import "testapp/app"
a := app.GetApp()
db, err := a.ConnectDatabase()
if err != nil {
panic(err.Error())
}
// testapp/app.go
func (a *App) ConnectDatabase() {
db, err := sql.Open()
if err != nil {
panic(err.Error())
}
a.db = db
}
I've got error:
app.ConnectDatabase() used as value
How can I fix that?
you might want to solve this like:
// main.go
import "testapp/app"
func main(){
a := app.GetApp()
err := a.ConnectDatabase()
if err != nil {
panic(err.Error())
}
a.db. //interesting db code here
}
// testapp/app.go
func (a *App) ConnectDatabase() error{
db, err := sql.Open()
if err != nil {
return err
}
a.db = db
return nil
}

Resources