I'm trying to write my first beego web app and I'm trying to register some models, i register them in models/model.go's init() function, but when I run the command bee run, I get the following error:
no Model found, need register your model
main.go:
package main
import (
"fmt"
_ "test_blog/routers"
"time"
_ "github.com/lib/pq"
"github.com/astaxie/beego"
"github.com/astaxie/beego/orm"
)
func init() {
orm.RegisterDriver("postgres", orm.DRPostgres)
maxIdle := 30
maxConn := 30
orm.RegisterDataBase(
"default",
"postgres",
"postgres://user:password#localhost/test_db", maxIdle, maxConn
)
orm.DefaultTimeLoc = time.UTC
}
func main() {
// Database alias.
name := "default"
// Drop table and re-create.
force := false
// Print log.
verbose := false
// Error.
err := orm.RunSyncdb(name, force, verbose)
if err != nil {
fmt.Println(err)
}
beego.Run()
}
Note: force & verbose both were set to true before running bee run for the first time.
models.go:
package main
import "github.com/astaxie/beego/orm"
type User struct {
Name string
Posts []*Post `orm:"reverse(many)"`
}
type Post struct {
Title string `orm:"size(50)"`
Text string `orm:"size(4000)"`
Created time.Time `orm:"auto_now_add;type(datetime)"`
Updated time.Time `orm:"auto_now;type(datetime)"`
Author *User `orm:"rel(fk)"`
}
func init() {
orm.RegisterModel(new(User), new(Post))
}
try this:
in models.go, change package main to package models
in main.go, add import _ "test_blog/models"
Related
My code organization structure is like this
package_name/
server/
rpc_server.go
client_test.go
I register an RPC server to receive messages from other nodes.
type RPCMessageArgs struct {
Operation string
Info Message
}
type Message struct {
NodeID uint64
Payload interface{}
}
func init() {
gob.Register(BroadcastMessage{})
}
func main() {
// start rpc server
}
I start my RPC server in the server folder with the command go run rpc_server.go.
My test code in the client_test.go is as follows
package package_name
import (
"encoding/gob"
"log"
"net/rpc"
"strconv"
"testing"
)
type BroadcastMessage struct {
Payload interface{}
}
func TestClient(t *testing.T) {
gob.Register(BroadcastMessage{})
args := &RPCMessageArgs{}
args.Info.NodeID = 3
args.Info.Payload = &BroadcastMessage{}
reply := &RPCMessageReply{}
client, err := rpc.Dial("tcp", ":800"+strconv.Itoa(1))
if err != nil {
log.Fatal("dialing: ", err)
}
err = client.Call("RPCServer.RemoteCall", args, reply)
if err != nil {
log.Fatal("call error: ", err)
}
}
I get this error
call error: gob: name not registered for interface: "package_name.BroadcastMessage"
I made a very low-level mistake. I defined two type BroadcastMessage in two files, one in rpc_server.go and one in client_go.go. I should define these structures in a package, and then let these two files call these structures.
After the change, my code structure is as follows:
package_name/
args/
rpc_args.go
server/
rpc_server.go
client_test.go
Define the relevant structure in the rpc_args.go file, import the args package in other files, and then call the gob.Register() command in rpc_server.go and client_test.go to run normally.
I currently develop golang projects with xorm.
I want to use a cache to manage the result of sql queries called once. I expected that sql requests would be called once, and would not be called again, but they do get called again.
Also, Redis keys that get created do not appear in redis-cli(keys *).
Why are my sql queries getting called more than once?
package main
import (
"github.com/go-xorm/xorm"
_ "github.com/go-sql-driver/mysql"
xrc "github.com/go-xorm/xorm-redis-cache"
)
type User struct {
Id int
Name string
}
func main() {
engine, err := xorm.NewEngine("mysql", "root:#/xorm_test_db")
if nil != err {
log.Fatal(err)
}
engine.ShowSQL(true)
cacher := xrc.NewRedisCacher("localhost:6379", "", xrc.DEFAULT_EXPIRATION, engine.Logger())
engine.SetDefaultCacher(cacher)
engine.Get(User{Id: 1})
engine.Get(User{Id: 1})
}
Two things has to be addressed for the caching to work properly:
Table must have a Primary Key for it to be cached. So Id can be
made as Primary Key as follows:
type User struct {
Id int `xorm:"pk"`
Name string
}
The type User must be registered using Golang's encoding/gob package:
gob.Register(new(User))
Don't forget to drop the existing table and sync the new User structure.
// Drop the existing table
DROP TABLE user;
// Sync the User struct to table
engine.Sync(new(User))
// Create a sample user
engine.Insert(&User{Id: 1, Name: "user1"})
The corrected code would look something as follows:
package main
import (
"github.com/go-xorm/xorm"
_ "github.com/go-sql-driver/mysql"
xrc "github.com/go-xorm/xorm-redis-cache"
"encoding/gob"
)
type User struct {
Id int `xorm:"pk"`
Name string
}
func main() {
gob.Register(new(User))
engine, err := xorm.NewEngine("mysql", "root:#/xorm_test_db")
if nil != err {
log.Fatal(err)
}
engine.ShowSQL(true)
cacher := xrc.NewRedisCacher("localhost:6379", "", xrc.DEFAULT_EXPIRATION, engine.Logger())
engine.SetDefaultCacher(cacher)
engine.Get(User{Id: 1})
engine.Get(User{Id: 1})
}
I resolved that!
package main
import (
"github.com/go-xorm/xorm"
_ "github.com/go-sql-driver/mysql"
xrc "github.com/go-xorm/xorm-redis-cache"
"encoding/gob"
"log"
)
type User struct {
Id int `xorm:"pk"`
Name string `xorm:"'name'"`
}
func main() {
gob.Register(new(User))
engine, err := xorm.NewEngine("mysql", "root:#/xorm_test2?charset=utf8")
if nil != err {
log.Fatal(err)
}
engine.Sync(new(User))
engine.Insert(&User{Id: 1, Name: "user1"})
engine.ShowSQL(true)
cacher := xrc.NewRedisCacher("localhost:6379", "", xrc.DEFAULT_EXPIRATION, engine.Logger())
engine.SetDefaultCacher(cacher)
engine.MapCacher(&User{}, cacher)
engine.Get(&User{Id: 1})
engine.Get(&User{Id: 1})
}
I'm trying to write a restful api on golang. For http router I use gin-gonic, to interact with the database I use gorm.
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/postgres"
)
var db *gorm.DB
type Person struct {
ID uint `json:"id"`
FirstName string `json:"firstname"`
LastName string `json:"lastname"`
}
func main() {
// NOTE: See we’re using = to assign the global var
// instead of := which would assign it only in this function
db, err := gorm.Open("postgres", fmt.Sprintf("host=localhost sslmode=disable user=postgres password="))
if err != nil {
fmt.Println(err)
}
defer db.Close()
db.AutoMigrate(&Person{})
r := gin.Default()
r.GET("/people/", GetPeople)
r.GET("/people/:id", GetPerson)
r.POST("/people", CreatePerson)
r.Run(":8080")
}
func CreatePerson(c *gin.Context) {
var person Person
c.BindJSON(&person)
db.Create(&person)
c.JSON(200, person)
}
func GetPerson(c *gin.Context) {
id := c.Params.ByName("id")
var person Person
if err := db.Where("id = ?", id).First(&person).Error; err != nil {
c.AbortWithStatus(404)
fmt.Println(err)
} else {
c.JSON(200, person)
}
}
func GetPeople(c *gin.Context) {
var people []Person
if err := db.Find(&people).Error; err != nil {
c.AbortWithStatus(404)
fmt.Println(err)
} else {
c.JSON(200, people)
}
}
How do I split the code into multiple files so that a separate resource is in a separate file? How to use the router and database in another file?
UPDATE
With structure like this:
.
└── app
├── users.go
├── products.go
└── main.go
I have 2 problems:
db == nil in products.go and users.go
Redeclaration function (get, create ...) in different files, this solve by prefix in function declaration like CreateUser, CreateProduct, etc. But it may be solved by put code into another packages
main.go
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/postgres"
)
var (
db *gorm.DB
r *gin.Engine
)
func init() {
db, err := gorm.Open("postgres", fmt.Sprintf("host=localhost sslmode=disable user=postgres password="))
if err != nil {
fmt.Println(err)
}
defer db.Close()
r = gin.Default()
}
func main() {
r.Run(":8080")
}
products.go
package main
import (
"github.com/gin-gonic/gin"
"github.com/jinzhu/gorm"
)
type Product struct {
gorm.Model
Code string
Price uint
}
func init() {
db.AutoMigrate(&Product{}) // db -> nil
r.GET("/products", get)
}
func get(c *gin.Context) {
var product Product
db.First(&product, 1)
c.JSON(200, gin.H{
"product": product,
})
}
users.go
package main
import (
"github.com/gin-gonic/gin"
"github.com/jinzhu/gorm"
)
type User struct {
gorm.Model
Name string
}
func init() {
db.AutoMigrate(&User{}) // db -> nil
r.GET("/users", get)
}
// ./users.go:19: get redeclared in this block
// previous declaration at ./products.go:20
func get(c *gin.Context) {
var user User
db.First(&user, 1)
c.JSON(200, gin.H{
"user": user,
})
}
Since your db var is defined at the package level it's basically a global for that package an can be referenced in any file that lives in that package.
For example, in a project like this:
.
└── app
├── a.go
├── b.go
├── c.go
└── main.go
If db is defined inside main.go at the package level, as in your example, then code in files a.go, b.go, and c.go can use db.
It works the other way as well, any resource handlers defined in a.go, b.go, and c.go can be reference in main.go. Which means that in each of those files you can define a function that takes a router, the gin router, and sets the corresponding handlers, then inside main.go's main function you call those functions passing in the router r.
Update
First off, you're calling defer db.Close() inside of you init function, which means that right after init returns your db gets closed which is absolutely not what you want. Using defer db.Close() in main is fine because main terminates when your app terminates, closing the db at that point makes sense, but when init terminates your app didn't even start properly, the main is just getting executed and you still need your db.
If you want to use the init functions in each file to do initialization specific to that file, you have to ensure that whatever those init functions depend on, is initialized before they get executed.
In your example all of your init functions depend on db and r so you need to make sure these two are not nil. I'm not exactly sure what, in Go, the order of execution is for multiple init functions in a single package but what I know for sure is that package level variable expressions get initialized before the init functions are executed.
So what you can do is to use a function call to initialize the two package level variables like so:
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/postgres"
)
var (
db = func() *gorm.DB {
db, err := gorm.Open("postgres", fmt.Sprintf("host=localhost sslmode=disable user=postgres password="))
if err != nil {
// if you can't open a db connection you should stop the app,
// no point in continuing if you can't do anything useful.
panic(err)
}
return db
}() // <- call the anon function to get the db.
r = gin.Default()
)
func main() {
// you can call defer db.Close() here but you don't really need to
// because after main exists, that is, your app terminates, db
// will be closed automatically.
r.Run(":8080")
}
As to your second problem, in Go init is a special case and by that I mean that you can have multiple init functions inside a single package, and even inside a single file. This is not true of any other identifiers that you declare.
That means that inside a package, and declared at the package level, you can have only one db identifier, one get identifier, only one User identifier, etc. Whether you use suffiex e.g. getUser or packages user.Get is entirely up to you.
Note that you can redeclare an identifier in another scope, let's say you have type User struct { ... at the package level, and then a function declared in the same pacakge can inside its own scope declare a variable like so var User = "whatever", although it's probably not the best idea it will compile.
For more details see:
Package initialization
Update 2
If you want to split your code into multiple packages you just put your files into separate folders and make sure that the package declaration at the top of your file has the correct package name.
Here's an example:
└── app/
├── main.go
├── product/
│ ├── product.go
│ └── product_test.go
└── user/
├── user.go
└── user_test.go
Now your app/user/user.go code could look something like this.
package user
import (
"github.com/gin-gonic/gin"
"github.com/jinzhu/gorm"
)
var db *gorm.DB
type User struct {
gorm.Model
Name string
}
// custom and exported Init function, this will not be called automatically
// by the go runtime like the special `init` function and therefore must be called
// manually by the package that imports this one.
func Init(gormdb *gorm.DB, r *gin.Engine) {
db = gormdb // set package global
db.AutoMigrate(&User{})
r.GET("/users", get)
}
func get(c *gin.Context) {
var user User
db.First(&user, 1)
c.JSON(200, gin.H{
"user": user,
})
}
your app/product/product.go ...
package product
import (
"github.com/gin-gonic/gin"
"github.com/jinzhu/gorm"
)
var db *gorm.DB
type Product struct {
gorm.Model
Code string
Price uint
}
// custom and exported Init function, this will not be called automatically
// by the go runtime like the special `init` function and therefore must be called
// manually by the package that imports this one.
func Init(gormdb *gorm.DB, r *gin.Engine) {
db = gormdb // set package global
db.AutoMigrate(&Product{})
r.GET("/products", get)
}
func get(c *gin.Context) {
var product Product
db.First(&product, 1)
c.JSON(200, gin.H{
"product": product,
})
}
And your entry point at app/main.go ...
package main
import (
"fmt"
// This assumes that the app/ folder lives directly in $GOPATH if that's
// not the case the import won't work.
"app/product"
"app/user"
"github.com/gin-gonic/gin"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/postgres"
)
func main() {
db, err := gorm.Open("postgres", fmt.Sprintf("host=localhost sslmode=disable user=postgres password="))
if err != nil {
fmt.Println(err)
}
defer db.Close()
r := gin.Default()
// manually initialize imported packages
user.Init(db, r)
product.Init(db, r)
r.Run(":8080")
}
I understand the problem, as per the answer here, however, I could really use help or a more detailed code explanation of how it's overcome.
My situation is this: I used to have models and controllers separated, and in my models package I had a datastore.go file containing an interface of all the model functions:
package models
type DSDatabase interface {
CreateUser(ctx context.Context, username string, password []byte) (*datastore.Key, error)
// More model functions
}
type datastoreDB struct {
client *datastore.Client
}
var (
DB DSDatabase
_ DSDatabase = &datastoreDB{}
)
func init() {
// init datastore
}
This was all fine because the model functions were also located within the models package, so my functions in the controller package could freely call models.DB.CreateUser(ctx, "username", []byte("password")).
Now, I have decided to move all the above code to a datastore package, whereas the model for CreateUser is located in a user package. In other words, package user now contains both controller and model functions, for which the controller related functions rely on datastore package, while the DSDatabase interface rely on the user model functions.
I would really appreciate help figuring out how to overcome the import cycle while keeping the DSDatastore interface separate from all the other packages such as home and user.
in case the above is not clear enough, the above code has changed to:
package datastore
import (
"github.com/username/projectname/user"
)
type DSDatabase interface {
user.CreateUser(ctx context.Context, username string, passwoUserRegister(ctx context.Context, username string, password []byte) (*datastore.Key, error)
}
...
while in my user package I have this in a controller-related file:
package user
import (
"github.com/username/projectname/datastore"
)
func CreateUserPOST(w http.ResponseWriter, r *http.Request) {
// get formdata and such
datastore.DB.CreateUser(ctx, "username", []byte("password"))
}
and in another model-related file I have:
package user
import (
"github.com/username/projectname/datastore"
)
func (db *datastore.datastoreDB) CreateUser(ctx context.Context, username string) (*User, error) {
key := datastore.NameKey("User", username, nil)
var user User
err := db.client.Get(ctx, key, &user)
if err != nil {
return nil, err
}
return &user, nil
}
Which of course results in an import cycle, that I sadly can't figure out how to overcome..
First things first, you cannot define a method, in pacakge A, on a type declared in package B.
So this...
package user
import (
"github.com/username/projectname/datastore"
)
func (db *datastore.datastoreDB) CreateUser(ctx context.Context, username string) (*User, error) {
key := datastore.NameKey("User", username, nil)
var user User
err := db.client.Get(ctx, key, &user)
if err != nil {
return nil, err
}
return &user, nil
}
...should not even compile.
This here...
package datastore
import (
"github.com/username/projectname/user"
)
type DSDatabase interface {
user.CreateUser(ctx context.Context, username string, passwoUserRegister(ctx context.Context, username string, password []byte) (*datastore.Key, error)
}
...this is also invalid Go code.
As to your question... one thing you could do is to define the Datastore interface inside the user package and have the implementation live in another package, this lends itself nicely for when you need different implementations of one interface. If you do this your user package does not need to know about the datastore package anymore, the datastore package still has to know about the user package though, which is a OK.
An example:
package user
import (
"context"
)
type DSDatabase interface {
CreateUser(ctx context.Context, username string, password []byte) (*User, error)
// ...
}
// This can be set by the package that implements the interface
// or by any other package that imports the user package and
// a package that defines an implementation of the interface.
var DB DSDatabase
type User struct {
// ...
}
func CreateUserPOST(w http.ResponseWriter, r *http.Request) {
// get formdata and such
DB.CreateUser(ctx, "username", []byte("password"))
}
The package with the implementation of the interface:
package datastore
import (
"context"
"github.com/username/projectname/user"
)
// DB implements the user.DSDatabase interface.
type DB struct { /* ... */ }
func (db *DB) CreateUser(ctx context.Context, username string) (*user.User, error) {
key := datastore.NameKey("User", username, nil)
var user user.User
err := db.client.Get(ctx, key, &user)
if err != nil {
return nil, err
}
return &user, nil
}
func init() {
// make sure to initialize the user.DB variable that
// is accessed by the CreateUserPOST func or else you'll
// get nil reference panic.
user.DB = &DB{}
}
I'm trying to return a instance from the gorm.Open() return it i'm getting following error
controllers/db.go:34: cannot assign *gorm.DB to dc.DB (type gorm.DB) in multiple assignment
This is the db.go controller
package controllers
import (
//"fmt"
_ "github.com/go-sql-driver/mysql"
//v "github.com/spf13/viper"
"github.com/jinzhu/gorm"
)
type DBController struct {
DB gorm.DB
}
func (dc *DBController) InitDB() {
var err error
dc.DB, err = gorm.Open("mysql","root:12345#tcp(localhost:3306)/api")
if err != nil {
log.Fatalf("Error when connect database, the error is '%v'", err)
}
dc.DB.LogMode(true)
}
func (dc *DBController) GetDB() gorm.DB {
return dc.DB
}
What is reason for this error and how can i fix this?
You need and most probably you want to have a pointer in the structure of controller. Passing structure with a pointer to the database object (gorm.DB) will prevent Go from making a copy of this object (gorm.DB).
Do the following:
type DBController struct {
DB *gorm.DB
}
Now it should work fine.