Getting A Database Locked Error When Using Golang and SQLite - sqlite

I'm experiencing a database locked error in this piece of code.
The thing is I already wrote pretty similar code to this and I wasn't getting any errors.
But now when I run it, I get a Database Locked Error with the error code 5.
The error occurs on the tx.Commit() statement.
Here's the code itself:
type UserRepository struct {
db *driver.QuestionlyDb
}
/*
Creates a new user sql driver that executes user sql statements on the sql driver.
*/
func CreateUserRepository(db *driver.QuestionlyDb) *UserRepository {
return &UserRepository{db: db}
}
/*
Create a new user row in the database.
*/
func (ur *UserRepository) CreateUser(u *User) error {
tx, err := ur.db.Begin()
if err != nil {
return err
}
stmt, err := tx.Prepare(`INSERT INTO users (id, email, password, username) VALUES (?, ?, ?, ?);`)
if err != nil {
_ = tx.Rollback()
return err
}
defer stmt.Close()
_, err = stmt.Exec(u.GetID(), u.GetEmail(), u.GetPassword(), u.GetUsername())
if err != nil {
tx.Rollback()
return err
}
if err := tx.Commit(); err != nil {
return err
}
return nil
}
The database connection is created in the following way:
type QuestionlyDb struct {
*sql.DB
}
/*
Creates a new database connection.
*/
func CreateDatabase() (*QuestionlyDb, error) {
db, err := connectToDb()
if err != nil {
return nil, err
}
sqlDb := &QuestionlyDb{db}
return sqlDb, nil
}
// TODO: Set db name as env variable
func connectToDb() (*sql.DB, error) {
db, err := sql.Open("sqlite3", "./questionly.db")
if err != nil {
return nil, err
}
return db, err
}

Related

Iterating over collection and subcollecion in firestore

I'm trying to find a more efficient way to iterate over a collection with its subcollections in firestore with go than a nested for loop. I have a collection called Place with a subcollection Ticket.
These are the two structs that I'm working with:
type Place struct {
PlaceName string `json:"placeName"`
PlaceLocation string `json:"placeLocation"`
PhoneNumber string `json:"phoneNumber"`
NumTickets []Ticket `json:"numTickets"`
}
type Ticket struct {
TicketType string `json:"ticketType"`
NumberTicketsAvail int64 `json:"numberTicketsAvail"`
}
And, here's the piece of code that I have at the moment:
func (*repo) FindAll() ([]entity.Place, error) {
ctx := context.Background()
client, err := firestore.NewClient(ctx, projectID)
if err != nil {
log.Fatalf("Failed to create a firestore client: %v", err)
return nil, err
}
defer client.Close()
var places []entity.Place
it := client.Collection(collectionName).Documents(ctx)
for {
doc, err := it.Next()
if err == iterator.Done {
break
}
if err != nil {
log.Fatalf("Failed to iterate: %v", err)
return nil, err
}
ticketRef := doc.Ref.Collection("Ticket")
var tickets []entity.Ticket
it := ticketRef.Documents(ctx)
for {
doc, err := it.Next()
if err == iterator.Done {
break
}
if err != nil {
log.Fatalf("Failed to iterate over tickets: %v", err)
return nil, err
}
ticket := entity.Ticket{
TicketType: doc.Data()["TicketType"].(string),
NumberTicketsAvail: doc.Data()["NumberTicketsAvail"].(int64),
}
tickets = append(tickets, ticket)
}
place := entity.Place{
PlaceName: doc.Data()["PlaceName"].(string),
PlaceLocation: doc.Data()["PlaceLocation"].(string),
PhoneNumber: doc.Data()["PhoneNumber"].(string),
NumTickets: tickets,
}
places = append(places, place)
}
return places, nil
}

How should I handle the errors when I try to write in DB

Not sure how should I deal with errors when I try to write in DB in this particular case:
So I use this func to insert in DB
func SaveToDB(dateid string, content string) {
db, err := sql.Open("mysql", dbLink)
if err != nil {
log.Fatal(err)
}
queryString := fmt.Sprintf("INSERT INTO balances (dateid, content) VALUES('%v','%v');", dateid, content)
rows, err := db.Query(queryString)
if err != nil {
log.Fatal(err)
}
defer rows.Close()
}
But I would like to don't stop the server when error is duplicate so I tried this version:
func SaveToDB(dateid string, content string) {
db, err := sql.Open("mysql", dbLink)
if err != nil {
log.Fatal(err)
}
queryString := fmt.Sprintf("INSERT INTO balances (dateid, content) VALUES('%v','%v');", dateid, content)
rows, err1 := db.Query(queryString)
if err1 != nil {
thisErr, err2 := regexp.MatchString("Error 1062: Duplicate entry", err.Error())
if err2 != nil {
log.Fatal("ERROR: error occured while trying to perform regex on SaveToDB", err2)
}
if thisErr == true {
log.Println("ERROR: Not able to save in DB due to ducplicate: ", err1)
}else{log.Fatal("ERROR: error occured when trying to save to DB: ", err1)}
}
defer rows.Close()
}
But in this situation I receive panic. So how I can stop this function from executing before it reaches "defer rows.Close()"? I guess that is the reason for panic...
Don't use log.Fatal and install deferred code once you have the correct data:
rows, err := db.Query(queryString)
if err != nil {
log.Error(err)
return
}
defer rows.Close()

How i can update data firebase with specific key in golang?

I am using golang and firego for connecting to Firebase. I want to update my data Statusfrom ON to OFF with key IDAgent: 7. This is my Database Structure
Image
Assumption : I don't know child active_chat. How can i update data in active_chat/-Koja8GuFplEN3kjbfPO where IDAgent = 7
I have tried this code
x := map[string]string{"Status": "OFF"}
ref.OrderBy("IDAgent").EqualTo("7").Update(x)
but this code wrong query.
In two ways you can do, as per Firebase doc with firego client library. Drafted answer based on from firego README.md.
Note: You have not provided the complete path of the structure, I have drafted the answer based on screenshot. So update your JSON path accordingly.
Approach 1:
f := firego.New("https://my-firebase-app.firebaseIO.com/active-chat/Koja8GuFpIEN3kjbfPO.json", nil)
x := map[string]string{
"Status": "OFF",
}
if err := f.Update(x); err != nil {
log.Fatal(err)
}
Approach 2:
f := firego.New("https://my-firebase-app.firebaseIO.com", nil)
f = f.Ref("/active-chat/Koja8GuFpIEN3kjbfPO.json")
x := map[string]string{
"Status": "OFF",
}
if err := f.Update(x); err != nil {
log.Fatal(err)
}
Update for 2022:
package main
import (
"context"
"fmt"
"time"
firestore "cloud.google.com/go/firestore"
firebase "firebase.google.com/go"
"google.golang.org/api/option"
)
type (
myDocument struct {
Cars []Car `firestore:"cars"`
carsCount int64 `firestore:"car_count"`
UpdateTime string `firestore:"update_time"`
}
Car struct {
Name string `firestore:"name"`
YearBuilt string `firestore:"year_built"`
}
)
func getFirebaseClient(ctx context.Context) (*firestore.Client, error) {
sa := option.WithCredentialsFile("Path_To_Firebase_Key")
// Initialize firebase app with admin privileges
app, err := firebase.NewApp(ctx, nil, sa)
if err != nil {
err = fmt.Errorf("getFirestoreClient failed: %s", err)
return nil, err
}
// Create client
client, err := app.Firestore(ctx)
if err != nil {
err = fmt.Errorf("failed to connect to firestore: %v", err)
return nil, err
}
return client, nil
}
func main() {
// Create context
ctx := context.Background()
// Get firebase client
client, err := getFirebaseClient(ctx)
if err != nil {
panic(err)
}
// Create car struct
newCar := Car{
"Volvo_Series1",
"1920",
}
// Update time
newTime := time.Now().UTC().Format("Monday, 01-02-2006 15:04:05")
// Updates to document
updates := []firestore.Update{
{Path: "cars", Value: firestore.ArrayUnion(newCar)},
{Path: "car_count", Value: firestore.Increment(1)},
{Path: "update_date", Value: newTime},
}
// OPTION A)
// Create collection reference
collectionRef := client.Collection("cars")
// Create document reference
docRef := collectionRef.Doc("12345")
// Update document
_, err = docRef.Update(ctx, updates)
if err != nil {
err := fmt.Errorf("failed updating document: %s from %s collection %v", docRef.ID, docRef.Parent.ID, err)
panic(err)
}
// OPTION B)
_, err = client.Collection("cars").Doc("12345").Update(ctx, updates)
if err != nil {
err := fmt.Errorf("failed updating document: %s from %s collection %v", docRef.ID, docRef.Parent.ID, err)
panic(err)
}
}

Stream HAR events

I have a long running app that I'd like to monitor in real time. HAR files allow me to do this after the fact, but as they are an "archive", they don't allow me to do this in real time.
Is their anyway to stream the "events" array of the HAR file so I can process them as they are generated?
This can be firefox or chrome.
So with some help from https://github.com/mafredri/cdp/tree/master/example/screencast I figured out how to do this in go with chrome's debugger api
What this code doesn't do is tie the request body to the response (where it isn't available), but as I show the RequestID will be consistent so if one serializes event processing (say via locking) one can save the body and use it when the response event is seen.
package main
import (
"context"
"log"
"github.com/mafredri/cdp"
"github.com/mafredri/cdp/cdpcmd"
"github.com/mafredri/cdp/devtool"
"github.com/mafredri/cdp/rpcc"
)
func main() {
if err := run(); err != nil {
panic(err)
}
}
func run() error {
ctx, cancel := context.WithCancel(context.TODO())
defer cancel()
devt := devtool.New("http://localhost:9222")
page, err := devt.Get(ctx, devtool.Page)
if err != nil {
return err
}
conn, err := rpcc.DialContext(ctx, page.WebSocketDebuggerURL)
if err != nil {
return err
}
defer conn.Close()
c := cdp.NewClient(conn)
err = c.Page.Enable(ctx)
if err != nil {
return err
}
loadEventFired, err := c.Page.LoadEventFired(ctx)
if err != nil {
return err
}
_, err = c.Page.Navigate(ctx, cdpcmd.NewPageNavigateArgs("https://github.com/"))
if err != nil {
return err
}
_, err = loadEventFired.Recv()
if err != nil {
return err
}
loadEventFired.Close()
a := &cdpcmd.NetworkEnableArgs{}
a.SetMaxResourceBufferSize(32000)
a.SetMaxTotalBufferSize(96000)
err = c.Network.Enable(ctx, a)
responseEvents, err := c.Network.ResponseReceived(ctx)
requestEvents, err := c.Network.RequestWillBeSent(ctx)
go func() {
defer responseEvents.Close()
for {
ev, err := responseEvents.Recv()
if err != nil {
log.Printf("Failed to receive network event: %v", err)
return
}
log.Printf("requestid = %v, url = %v", ev.RequestID, ev.Response.URL)
}
}()
go func() {
defer requestEvents.Close()
for {
ev, err := requestEvents.Recv()
if err != nil {
log.Printf("Failed to receive network event: %v", err)
return
}
log.Printf("requestid = %v, url = %v", ev.RequestID, ev.Request.URL)
}
}()
select {}
return nil
}

How can you upload files as a []byte in go?

I would like to use golang post request, upload pictures, but I do not want to pass filepath, just want to pass [] byte
The following article are not what I need because they are used os.Open
golang POST data using the Content-Type multipart/form-data
func Upload(url, file string) (err error) {
// Prepare a form that you will submit to that URL.
var b bytes.Buffer
w := multipart.NewWriter(&b)
// Add your image file
f, err := os.Open(file)
if err != nil {
return
}
defer f.Close()
fw, err := w.CreateFormFile("image", file)
if err != nil {
return
}
if _, err = io.Copy(fw, f); err != nil {
return
}
// Add the other fields
if fw, err = w.CreateFormField("key"); err != nil {
return
}
if _, err = fw.Write([]byte("KEY")); err != nil {
return
}
// Don't forget to close the multipart writer.
// If you don't close it, your request will be missing the terminating boundary.
w.Close()
// Now that you have a form, you can submit it to your handler.
req, err := http.NewRequest("POST", url, &b)
if err != nil {
return
}
// Don't forget to set the content type, this will contain the boundary.
req.Header.Set("Content-Type", w.FormDataContentType())
// Submit the request
client := &http.Client{}
res, err := client.Do(req)
if err != nil {
return
}
// Check the response
if res.StatusCode != http.StatusOK {
err = fmt.Errorf("bad status: %s", res.Status)
}
return
}
Since you use
if _, err = io.Copy(fw, f); err != nil {
return
}
You may as well edit your code to:
Add new import: "bytes"
Change the method signature to func Upload(url string, file []byte) (err error)
Use io.Copy(fw, bytes.NewReader(f))

Resources