Gorm Can't Insert Value into Sqlite - database

I use dao layer to init sqlitedb and try to insert a col into db in main.go
The Problem is When the main.go is finish and the database is created.But No any data in db..
my model.go is here
package model
import "gorm.io/gorm"
type User struct {
gorm.Model
Username string `json:"username"`
Password string `json:"password"`
}
and my gorm dao.go is here
package dao
import (
"go_blog/model"
"log"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
)
type Manager interface {
AddUser(user *model.User)
}
type manager struct {
db *gorm.DB
}
var Mgr Manager
func init() {
db, err := gorm.Open(sqlite.Open("database/blog.db"), &gorm.Config{})
if err != nil {
log.Fatal("Failed to INIT db:", err)
}
Mgr = &manager{db: db}
db.AutoMigrate(&model.User{})
log.Fatal("Init DB Successful")
}
func (mgr *manager) AddUser(user *model.User) {
mgr.db.Create(user)
}
when I use main.go to run the Mgr.AddUser function,I look into sqlite db,but the DB is no any data in there...So Confuse..
main.go is here
package main
import (
"go_blog/dao"
"go_blog/model"
)
func main() {
user := model.User{
Username: "tom",
Password: "123",
}
dao.Mgr.AddUser(&user)
}

Related

GORM failed when changing to using pgx: migrator.go:206:65: undefined: gorm.ColumnType

I had this on my go project using GORM:
import (
(...)
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/postgres"
)
func main() {
(...)
db, err := gorm.Open("postgres", dsn)
if err != nil {
panic(err)
}
defer db.Close()
}
I was able to open the connection to the DB and do all my transactions. If I change to:
import (
(...)
"github.com/jinzhu/gorm"
"gorm.io/driver/postgres"
)
func main(){
(...)
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
if err != nil {
panic(err)
}
defer db.Close()
}
it will give me an error on go build:
# gorm.io/driver/postgres
$GOPATH\pkg\mod\gorm.io\driver\postgres#v1.0.5\migrator.go:206:65: undefined: gorm.ColumnType
$GOPATH\pkg\mod\gorm.io\driver\postgres#v1.0.5\migrator.go:207:23: undefined: gorm.ColumnType
I got this from the official page:
https://gorm.io/docs/connecting_to_the_database.html
I changed to using the same library... my bad.
Instead of
"github.com/jinzhu/gorm"
use this:
"gorm.io/gorm"
along the same driver
So now it looks like this:
import (
(...)
"gorm.io/gorm"
"gorm.io/driver/postgres"
)
func main(){
(...)
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
if err != nil {
panic(err)
}
defer db.Close()
}
You might need to upgrade to a newer version of gorm.
I got this error when using v1.20.4.
gorm.io/gorm v1.20.7 works for me

How to stop golang gRPC server with a function?

Looking at the helloworld example from grpc-go, how can I add a StopGrpcServer() function to stop gRPC server?
I'm trying to make a shared C library file of gRPC server which can be used to start and stop the gRPC server by invoking the functions via ffi.
In my tests I am able to start the gRPC server with StartGrpcServer() but I'm feeling lost how to implement StopGrpcServer().
package main
import C
import (
"context"
"log"
"net"
"google.golang.org/grpc"
pb "google.golang.org/grpc/examples/helloworld/helloworld"
)
const (
port = ":50051"
)
// server is used to implement helloworld.GreeterServer.
type server struct {
pb.UnimplementedGreeterServer
}
// SayHello implements helloworld.GreeterServer
func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
log.Printf("Received: %v", in.GetName())
return &pb.HelloReply{Message: "Hello " + in.GetName()}, nil
}
//export StopGrpcServer
func (s *server) StopGrpcServer() {
s.Stop()
}
//export StartGrpcServer
func StartGrpcServer() {
lis, err := net.Listen("tcp", port)
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
s := grpc.NewServer()
pb.RegisterGreeterServer(s, &server{})
if err := s.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
}
func main() {}
Would really appreciate some help on it.
Thanks,
Satinder
Thanks for the hint #Marc. I am able to solve the problem by declaring *grpc.Server variable globally outside StartGrpcServer(), and then using it in StopGrpcServer().
Here's the working code:
package main
import C
import (
"context"
"log"
"net"
"google.golang.org/grpc"
pb "google.golang.org/grpc/examples/helloworld/helloworld"
)
var srv *grpc.Server
const (
port = ":50051"
)
// server is used to implement helloworld.GreeterServer.
type server struct {
pb.UnimplementedGreeterServer
}
// SayHello implements helloworld.GreeterServer
func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
log.Printf("Received: %v", in.GetName())
return &pb.HelloReply{Message: "Hello " + in.GetName()}, nil
}
//export StopGrpcServer
func StopGrpcServer() {
srv.Stop()
}
//export StartGrpcServer
func StartGrpcServer() {
lis, err := net.Listen("tcp", port)
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
srv = grpc.NewServer()
pb.RegisterGreeterServer(srv, &server{})
if err := srv.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
}
func main() {}
// Compile with command:
// go build -o greeter.so -buildmode=c-shared server.go

How to reuse MongoDB connection in Go

I would like to connect my server that was written in Go with a MongoDB but I'm not sure how to do it in an efficient way. A couple of examples I found implemented it like shown below.
libs/mongodb/client.go
package mongodb
import (
"context"
"log"
"project/keys"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
func GetClient() *mongo.Database {
client, err := mongo.Connect(
context.Background(),
options.Client().ApplyURI(keys.GetKeys().MONGO_URI),
)
if err != nil {
log.Fatal(err)
}
return client.Database(keys.GetKeys().MONGO_DB_NAME)
}
services/user/findOne.go
package userservices
import (
"context"
"log"
"project/libs/mongodb"
"project/models"
"go.mongodb.org/mongo-driver/bson"
)
func FindOne(filter bson.M) (models.User, error) {
var user models.User
collection := mongodb.GetClient().Collection("users")
result := collection.FindOne(context.TODO(), filter)
if result.Err() != nil {
return user, result.Err()
}
if err := result.Decode(&user); err != nil {
log.Println("Failed to decode user with error:", err)
return user, err
}
return user, nil
}
The GetClient function returns a database instance that is then used throughout the app. This seems to work, but I'm wondering if this really is best practice as it seems to create a new connection every time a new client is requested as shown in the second code snippet or is that assumption incorrect? I also thought about converting GetClient to a singleton, that always returns the same database instance but how would a lost connection be handled in that case? Thank you
I do it this way. Do it once at the service start and then pass the MongoDatastore object around to orchestrator, service layers and repository layers. I am using the "github.com/mongodb/mongo-go-driver/mongo" driver for mongo. I think it internally monitors and recycles idle connections. Hence, we don't have to bother about broken connections as long as reference to the mongo.Client object is not lost.
const CONNECTED = "Successfully connected to database: %v"
type MongoDatastore struct {
db *mongo.Database
Session *mongo.Client
logger *logrus.Logger
}
func NewDatastore(config config.GeneralConfig, logger *logrus.Logger) *MongoDatastore {
var mongoDataStore *MongoDatastore
db, session := connect(config, logger)
if db != nil && session != nil {
// log statements here as well
mongoDataStore = new(MongoDatastore)
mongoDataStore.db = db
mongoDataStore.logger = logger
mongoDataStore.Session = session
return mongoDataStore
}
logger.Fatalf("Failed to connect to database: %v", config.DatabaseName)
return nil
}
func connect(generalConfig config.GeneralConfig, logger *logrus.Logger) (a *mongo.Database, b *mongo.Client) {
var connectOnce sync.Once
var db *mongo.Database
var session *mongo.Client
connectOnce.Do(func() {
db, session = connectToMongo(generalConfig, logger)
})
return db, session
}
func connectToMongo(generalConfig config.GeneralConfig, logger *logrus.Logger) (a *mongo.Database, b *mongo.Client) {
var err error
session, err := mongo.NewClient(generalConfig.DatabaseHost)
if err != nil {
logger.Fatal(err)
}
session.Connect(context.TODO())
if err != nil {
logger.Fatal(err)
}
var DB = session.Database(generalConfig.DatabaseName)
logger.Info(CONNECTED, generalConfig.DatabaseName)
return DB, session
}
You may now create your repository as below:-
type TestRepository interface{
Find(ctx context.Context, filters interface{}) []Document, error
}
type testRepository struct {
store *datastore.MongoDatastore
}
func (r *testRepository) Find(ctx context.Context , filters interface{}) []Document, error{
cur, err := r.store.GetCollection("some_collection_name").Find(ctx, filters)
if err != nil {
return nil, err
}
defer cur.Close(ctx)
var result = make([]models.Document, 0)
for cur.Next(ctx) {
var currDoc models.Document
err := cur.Decode(&currDoc)
if err != nil {
//log here
continue
}
result = append(result, currDoc)
}
return result, err
}
I solved it doing this
var CNX = Connection()
func Connection() *mongo.Client {
// Set client options
clientOptions := options.Client().ApplyURI("mongodb://localhost:27017")
// Connect to MongoDB
client, err := mongo.Connect(context.TODO(), clientOptions)
if err != nil {
log.Fatal(err)
}
// Check the connection
err = client.Ping(context.TODO(), nil)
if err != nil {
log.Fatal(err)
}
fmt.Println("Connected to MongoDB!")
return client
}
//calll connection
func main() {
collection := db.CNX.Database("tasks").Collection("task")
}
output "Connected to MongoDB!"

Find method to get records in DB returning empty datasets

Now, I try to make an API with using GAE+CloudSQL.
I made this code.
package main
import (
"encoding/json"
"fmt"
_ "github.com/go-sql-driver/mysql"
"github.com/jinzhu/gorm"
"log"
"net/http"
"os"
)
type Person struct {
gorm.Model
Name string `json:"name"`
Age int `json:"age"`
}
var db *gorm.DB
func main() {
db = DB()
http.HandleFunc("/user", func(w http.ResponseWriter, r *http.Request) {
defer db.Close()
var people []Person
db.Find(&people)
str, _ := json.Marshal(people)
fmt.Printf("%s\n", str)
return
})
port := os.Getenv("PORT")
if port == "" {
port = "8080"
log.Printf("Defaulting to port %s", port)
}
log.Printf("Listening on port %s", port)
log.Fatal(http.ListenAndServe(fmt.Sprintf(":%s", port), nil))
}
func DB() *gorm.DB {
var (
connectionName = os.Getenv("CLOUDSQL_CONNECTION_NAME")
user = os.Getenv("CLOUDSQL_USER")
password = os.Getenv("CLOUDSQL_PASSWORD")
socket = os.Getenv("CLOUDSQL_SOCKET_PREFIX")
databaseName = os.Getenv("CLOUDSQL_DATABASE_NAME")
option = os.Getenv("CLOUDSQL_OPTION")
)
if socket == "" {
socket = "/cloudsql"
}
if option == "" {
option = "?parseTime=true"
}
dbURI := fmt.Sprintf("%s:%s#unix(%s/%s)/%s%s", user, password, socket, connectionName, databaseName, option)
conn, err := gorm.Open("mysql", dbURI)
if err != nil {
panic(fmt.Sprintf("DB: %v", err))
}
return conn
}
With the help of cloud I can get people data.
people.length is equal to the number of DB datas.
But, what I am getting is
person.Name is "" and person.Age = 0.
I cannot understand why I could not get any data.
Please tell me how to fix this issue.
I found how to be able to get correct person.Name and person.Age.
I've wrote defer db.Close() in http.HandleFunc. So, once this function is called, DB connection is closed.
I should put defer db.Close() at the beginning of the main function.
I'm sorry for a simple mistake, but refreshed to understand.

Get Object by specific field

I'm actually learning go, following some tutorial as this one to build an Resftul API app.
First time Using Go and mongoDB, I don't understand well, how to get specific key in certain document of my collection.
Actually I have this object model :
type Numobject struct {
ID bson.ObjectId `bson:"_id" json:"id"`
Text string `bson:"text" json:"text"`
Number int `bson:"number" json:"number"`
Found bool `bson:"found" json:"found"`
Type string `bson:"type" json:"type"`
}
And I can have a specific object by ID with this function :
// Find Object by ID
func (m *NumObjectDAO) FindByNumber(id string) (Numobject, error) {
var numObject Numobject
err := db.C(COLLECTION).FindId(bson.ObjectIdHex(id)).One(&numObject)
return numObject, err
}
I call my method in main.go as follow
package main
import (
"encoding/json"
"log"
"net/http"
"github.com/gorilla/mux"
"gopkg.in/mgo.v2/bson"
. "github.com/sandaleRaclette/03-coddingChallenge/config"
. "github.com/sandaleRaclette/03-coddingChallenge/dao"
. "github.com/sandaleRaclette/03-coddingChallenge/models"
)
// Save the configuration of mongodatabase (localhost and which db use) in Config array
var config = Config{}
var dao = NumObjectDAO{}
// GET list of all objects
func AllObjectsEndPoint(w http.ResponseWriter, r *http.Request) {
movies, err := dao.FindAll()
if err != nil {
respondWithError(w, http.StatusInternalServerError, err.Error())
return
}
respondWithJson(w, http.StatusOK, movies)
}
// GET an Object by its ID
func FindObjectEndpoint(w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
numObject, err := dao.FindByNumber(params["number"])
if err != nil {
respondWithError(w, http.StatusBadRequest, "Invalid Object ID")
return
}
respondWithJson(w, http.StatusOK, numObject)
}
// Respond Methods
func respondWithError(w http.ResponseWriter, code int, msg string) {
respondWithJson(w, code, map[string]string{"error": msg})
}
func respondWithJson(w http.ResponseWriter, code int, payload interface{}) {
response, _ := json.Marshal(payload)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(code)
w.Write(response)
}
// Parse the configuration file 'config.toml', and establish a connection to DB
func init() {
config.Read()
dao.Server = config.Server
dao.Database = config.Database
dao.Connect()
}
// Define HTTP request routes and define the differents endpoints
func main() {
r := mux.NewRouter()
r.HandleFunc("/api/v1/trivia", AllObjectsEndPoint).Methods("GET")
r.HandleFunc("/api/v1/trivia/{number}", FindObjectEndpoint).Methods("GET")
if err := http.ListenAndServe(":3000", r); err != nil {
log.Fatal(err)
}
}
There is other methods than getting an object by ID? How can I get an object with a specific key as Number or Type following my model ?
I want to obtain something like this when I GET "/api/v1/trivia/45000000" :
{
"id": "5aa554c89d63b0d3580449a5",
"text": "45000000 is the number of turkeys Americans eat at Thanksgiving annually.",
"number": 45000000,
"found": true,
"type": "trivia"
}
I'm actually looking here for some answers but I have some difficulties with query... If someone can give me beginner explanation...
Use Find for general queries:
err := db.c(COLLECTION).Find(bson.D{{"Number", 10}}).One(&numobjecct)

Resources