how do I query a sqlite db in go? [closed] - sqlite

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 1 year ago.
Improve this question
I'm trying to get an array of "Search" structs.
type Searches struct {
id int
count int
search string
}
func get_recent_searches(db *sql.DB, limit int) []Searches {
var searches []Searches
var query = "select from searches brder by count desc limit ?"
st, err := db.Prepare(query)
result, err := st.Exec(limit)
if err != nil { panic(err) }
/*
for rows.Next() {
item := Searches{}
err2 := rows.Scan(&item.id, &item.count, &item.search)
if err2 != nil { panic(err2) }
searches = append(searches, item)
}
*/
return result
}
Here is the error:
src/main.go:72:2: cannot use result (type sql.Result) as type []Searches in return argument

package main
import (
"fmt"
"log"
"database/sql"
_ "github.com/mattn/go-sqlite3" // Import go-sqlite3 library
)
// Searches ...
type Searches struct {
id int
count int
search string
}
func getRecentSearches(db *sql.DB, limit int) []Searches {
var searches []Searches
row, err := db.Query("SELECT * FROM search ORDER BY count LIMIT ?", limit)
if err != nil {
log.Fatal(err)
}
defer row.Close()
for row.Next() { // Iterate and fetch the records from result cursor
item := Searches{}
err := row.Scan(&item.id, &item.count, &item.search)
if err != nil {
log.Fatal(err)
}
searches = append(searches, item)
}
return searches
}
func main() {
searchDB, _ := sql.Open("sqlite3", "./search.db") // Open the created SQLite File
defer searchDB.Close() // Defer Closing the database
// Get and print the first 5 records to the console
searches := getRecentSearches(searchDB, 4)
fmt.Printf("ID\tCount\tSearch\n")
for _, item := range searches {
fmt.Printf("%d\t%d\t%s\n", item.id, item.count, item.search)
}
}

This link explains how to use SQLite with go: https://astaxie.gitbooks.io/build-web-application-with-golang/content/en/05.3.html
But the error you are seeing is because your function is defined as
func get_recent_searches(db *sql.DB, limit int) []Searches {}
It must return []Searches (a slice of Searches structs). (NB I would probably name a single search result as Search).
Adding the fixes suggested by #Peter Gloor (Query to return rows, rather than an Exec to change data) and removing the limit placeholder, your code could be
func get_recent_searches(db *sql.DB, limit int) []Searches {
searches := make([]Searches,0)
query := "select * from searches order by count desc"
st, err := db.Prepare(query)
if err != nil { panic(err) }
rows, err := st.Query(limit)
if err != nil { panic(err) }
for rows.Next() {
item := Searches{}
err2 := rows.Scan(&item.id, &item.count, &item.search)
if err2 != nil { panic(err2) }
searches = append(searches, item)
}
return searches
}

Related

I'm struggling to append an id from mysql to the URL

I'm trying to append an id (and other info) to the url, so I can access it later, but I can't find the right method after some research.
I've tried to use Get() method, query(), Add(), but I couldn't redirect the URL.
var email_ployer string
func RegisterNewPloyer(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/ployer/register" {
http.Error(w, "404 not found.", http.StatusNotFound)
return
}
db := connect.ConnectDB()
defer db.Close()
switch r.Method {
case "POST":
email_ployer = r.FormValue("email")
senha := r.FormValue("senha")
senha, _ = HashPassword(senha)
tx, _ := db.Begin()
stmt, _ := tx.Prepare("INSERT INTO ployers(email_ployer, senha_ployer) VALUES(?,?)")
_, erro := stmt.Exec(email_ployer, senha)
if erro != nil {
tx.Rollback()
log.Fatal(erro)
}
tx.Commit()
}
Redirect(w, r)
}
func Redirect(w http.ResponseWriter, r *http.Request) {
db2 := connect.ConnectDB()
defer db2.Close()
var id string
tx, _ := db2.Begin()
rows, _ := tx.Query("SELECT id FROM ployers WHERE email_ployer = '?'", email_ployer)
for rows.Next() {
if err := rows.Scan(&id); err != nil {
log.Fatal(err)
}
if err := rows.Err(); err != nil {
log.Fatal(err)
}
}
http.Redirect(w, r, x, http.StatusSeeOther)
}
func main() {
http.HandleFunc("/ployer/seja-um-de-nos", LoadPloyerContent)
http.HandleFunc("/ployer/register", register.RegisterNewPloyer)
http.HandleFunc("/ployer/complete/", LoadPloyerContent)
http.HandleFunc("/ployer/register-received", LoadPloyerContent)
log.Fatal(http.ListenAndServe(":3306", nil))
}
In my system, I want the user to register his E-mail and password, create an new user in the DB and redirect the URL to something like localhost:3306/ployer/complete/id
Just use res.LastInsertId() to get the id and pass it to your redirect function, and build the url:
func RegisterNewPloyer(w http.ResponseWriter, r *http.Request) {
//...
//...
res, erro := stmt.Exec(email_ployer, senha)
if erro != nil {
tx.Rollback()
log.Fatal(erro)
}
tx.Commit()
id, erro := res.LastInsertId()
if erro != nil {
log.Fatal(erro)
}
Redirect(w, r, id)
}
func Redirect(w http.ResponseWriter, r *http.Request, id int64) {
uri := fmt.Sprintf("http://localhost:3306/ployer/complete/%d", id)
http.Redirect(w, r, uri, http.StatusSeeOther)
}
You should use url.Values to construct a map of query string values. Later on, you can use Encode method to generate encoded query string. Assign this value to Url.RawQuery to get the final output.
e.g.:
base, _ := url.Parse("https://www.foo.com/")
// Create an instance of Values to hold your query string parameters
values := url.Values{}
values.Add("abc", "def")
// Set the encoded output to RawQuery attribute of Url
base.RawQuery = values.Encode()
println(base.String())
If you are starting with a URL that already has query string parameters and you want add/modify items in it, use Query() method to obtain a reference to parsed map.
e.g.:
base, _ := url.Parse("https://www.foo.com/?a=b")
values := base.Query()
values.Set("a", "c")
values.Set("x", "y")
// Set the encoded output to RawQuery attribute of Url
base.RawQuery = values.Encode()
println(base.String())

How to detect an empty result with Go Firebase-Admin SDK when data at the path doesn't exists

I'm using the following code to get an object from a Firebase realtime database.
type Item struct {
title string `json:"title"`
}
var item Item
if err := db.NewRef("/items/itemid").Get(ctx, &item); err != nil {
log.Infof(ctx, "An error occured %v", err.Error())
}
log.Infof(ctx, "Item %v", item)
If no data exists at the given path in the realtime database the SDK will not return an error, instead I will end up with an empty struct in the variable item.
What would be the cleanest/most readable way to detect that the data at the path is not there?
I've searched for hours but couldn't find a clear cut answer to this question.
Here's one way to solve this problem:
type NullableItem struct {
Item struct {
Title string `json:"title"`
}
IsNull bool
}
func (i *NullableItem) UnmarshalJSON(b []byte) error {
if string(b) == "null" {
i.IsNull = true
return nil
}
return json.Unmarshal(b, &i.Item)
}
func TestGetNonExisting(t *testing.T) {
var i NullableItem
r := client.NewRef("items/non_existing")
if err := r.Get(context.Background(), &i); err != nil {
t.Fatal(err)
}
if !i.IsNull {
t.Errorf("Get() = %v; want IsNull = true", i)
}
}
As a best practice you should also implement MarshalJSON() function.

Loop over a slice of structs and update value

I am getting data from source A and storing it in a slice of structs like so:
type ProductPrice struct {
Type string
Sku string
UnitPrice string
PriceList string
standardPrice string
specialPrice string
specialStart string
specialEnd string
pricingUnit string
categoryCode string
isOnSpecial bool
}
func getProductPricesFromDatabase(instance string) []ProductPrice {
rows, err := myDBConnection.Query(// My query here)
if err != nil {
log.Fatal("There was an issue with the query for product price: ", err)
}
defer rows.Close()
var productPrices []ProductPrice
for rows.Next() {
var product = ProductPrice{}
err := rows.Scan(
&product.Type,
&product.Sku,
&product.standardPrice,
&product.specialPrice,
&product.specialStart,
&product.specialEnd,
&product.pricingUnit,
&product.PriceList,
&product.categoryCode,
)
if err != nil {
log.Fatal("product price scan error: ", err)
}
productPrices = append(productPrices, product)
}
return productPrices
}
I am then getting some data from source B and storing it in a slice of structs like so:
type ContractProductPrice struct {
CustID string
PriceBy string
AppliesTo string
PriceList string
StartDate string
EndDate string
PricingAdjustmentType string
PricingAdjustmentValue string
UseLowest string
}
func getContractProductPricesFromDatabase(instance string) []ContractProductPrice {
rows, err := myDBConnection.Query(// My query here)
if err != nil {
log.Fatal("There was an issue with the query for contract product price: ", err)
}
defer rows.Close()
var contractProductPrices []ContractProductPrice
for rows.Next() {
var product = ContractProductPrice{}
err := rows.Scan(
&product.CustID,
&product.PriceBy,
&product.AppliesTo,
&product.PriceList,
&product.StartDate,
&product.EndDate,
&product.PricingAdjustmentType,
&product.PricingAdjustmentValue,
&product.UseLowest,
)
if err != nil {
log.Fatal("contract product price scan error: ", err)
}
contractProductPrices = append(contractProductPrices, product)
}
return contractProductPrices
}
After getting the data from source B, I am wanting to update the slice of structs from source A with some data from source B.
productPrices := getProductPricesFromDatabase(instance)
contractProductPrices := getContractProductPricesFromDatabase(instance)
processedProductPrices := processProductPricesFromDatabase(productPrices, contractProductPrices)
func processProductPricesFromDatabase(productPrices []ProductPrice, contractProductPrices []ContractProductPrice) []ProductPrice {
// Loop over contact prices and update relevant product prices
for _, contractPrice := range contractProductPrices {
for _, product := range productPrices {
if contractPrice.AppliesTo == product.Sku {
product.UnitPrice = contractPrice.PricingAdjustmentValue
}
}
}
return productPrices
}
However, after this runs, the unit prices in processedProductPrices is still empty.
From my searching, I understand what the issue is; Go passes by value and so I am not updating the original memory address and so the values are not changing.
However, I do not understand/know what I need to change to fix this given I am working with a slice of structs rather than a simpler example of a slice of number/strings etc.
How can I update productPrices so that when I return it, processedProductPrices is equal to the updated productPrices slice of structs?
Anytime you're dealing with values that you know you'll need to modify, it is best, at least in my opinion, to use pointers. They'll make your life easier.
So instead of:
func getProductPricesFromDatabase(instance string) []ProductPrice {
// ...
var productPrices []ProductPrice
for rows.Next() {
var product = ProductPrice{}
// ...
}
return productPrices
}
I would recommend you refactor your code to:
func getProductPricesFromDatabase(instance string) []*ProductPrice {
// ...
var productPrices []*ProductPrice
for rows.Next() {
var product = new(ProductPrice)
// ...
}
return productPrices
}
Now do the same with getContractProductPricesFromDatabase and finally update the argument types to your processProductPricesFromDatabase function:
func processProductPricesFromDatabase(productPrices []*ProductPrice, contractProductPrices []*ContractProductPrice) []*ProductPrice {
// Loop over contact prices and update relevant product prices
for _, contractPrice := range contractProductPrices {
for _, product := range productPrices {
if contractPrice.AppliesTo == product.Sku {
product.UnitPrice = contractPrice.PricingAdjustmentValue
}
}
}
return productPrices
}
As an alternative, if you want to keep using non-pointer types, you can directly modify the values referenced by the slice by indexing into it.
func processProductPricesFromDatabase(productPrices []ProductPrice, contractProductPrices []ContractProductPrice) []ProductPrice {
// Loop over contact prices and update relevant product prices
for _, contractPrice := range contractProductPrices {
for i, _ := range productPrices {
if contractPrice.AppliesTo == productPrices[i].Sku {
productPrices[i].UnitPrice = contractPrice.PricingAdjustmentValue
}
}
}
return productPrices
}

My string has special characters and the output of http/template adds "(MISSING)" to it

Im trying to build a small website, I use the html/template to create dynamic pages. One thing on the pages is a list of URL's inside those urls sometimes I need character encoding. for special characters like ô (%C3%B4).
When i try to parse the variables into a page using html/template i get the following as a result: %!c(MISSING)3%!b(MISSING)4. I have no clue what is wrong here
type Search_list struct {
Search_name string
Search_url string
Search_price float64
}
func generateSearchPage(language int, q string) (string, error) {
/* ommited, fetshing data from elasticsrearch*/
sl := []Search_list{}
var urle *url.URL
//looping through ES results and putting them in a custom List
for _, res := range data.Hits.Hits {
//
//Encode Url
var err error
urle, err = url.Parse(res.Source.URL)
if err != nil {
continue
// TODO: add log
}
//I've tried already the following:
fmt.Println(res.Source.URL) //ô
fmt.Println(url.QueryUnescape(res.Source.URL)) //ô
fmt.Println(urle.String()) //%C3%B4
u, _ := url.QueryUnescape(res.Source.URL)
sl = append(sl, Search_list{res.Source.Name, u, res.Source.Price})
}
var buffer bytes.Buffer
t := template.New("Index template")
t, err = t.Parse(page_layout[language][PageTypeSearch])
if err != nil {
panic(err)
}
err = t.Execute(&buffer, Search_data{
Title: translations[language]["homepage"],
Page_title: WebSiteName,
Listed_items: sl,
})
if err != nil {
panic(err)
}
return buffer.String(), nil // %!c(MISSING)3%!b(MISSING)4
}
# Moshe Revah
thanks for the help, in the meantime I found the error
Later in the code I send my generated page to the http client with
fmt.Fprintf(w, page) // Here was the error b/c of the % symbols
I just changed it to
fmt.Fprint(w, page)
and it works perfect

Display Foreign Keys of Foreign Keys in Go GORM

I was able to partially solve this with this case
Unfortunately, the Preload() function doesn't seem to work with delving further down in the related object set.
To clarify, I have the following models:
type Room struct {
gorm.Model
Name string
Games []Game `gorm:"ForeignKey:RoomID"`
}
type Game struct {
gorm.Model
RoomID int `gorm:"index"`
Players []Player `gorm:"ForeignKey:GameID"`
}
type Player struct {
gorm.Model
Name string
GameID int `gorm:"index"`
}
When I create a new object with a new Room, Game, and Player object created I get the following data returned (json encoded):
{"Value":{"ID":26,"CreatedAt":"2016-05-15T01:21:22.426234189-07:00","UpdatedAt":"2016-05-15T01:21:22.426234189-07:00","DeletedAt":null,"Name":"foo","Games":[{"ID":17,"CreatedAt":"2016-05-15T01:21:22.427026134-07:00","UpdatedAt":"2016-05-15T01:21:22.427026134-07:00","DeletedAt":null,"RoomID":26,"Turns":null,"Players":[{"ID":4,"CreatedAt":"2016-05-15T01:21:22.427560561-07:00","UpdatedAt":"2016-05-15T01:21:22.427560561-07:00","DeletedAt":null,"Name":"TestPlayer","GameID":17}],"Counter":1,"Assigned":false}],"Testing":false},"Error":null,"RowsAffected":1}
But if I try to query the structure with a preload() function, I get the following:
{"Value":{"ID":26,"CreatedAt":"2016-05-15T01:21:22.426234189-07:00","UpdatedAt":"2016-05-15T01:21:22.426234189-07:00","DeletedAt":null,"Name":"foo","Games":[{"ID":17,"CreatedAt":"2016-05-15T01:21:22.427026134-07:00","UpdatedAt":"2016-05-15T01:21:22.427026134-07:00","DeletedAt":null,"RoomID":26,"Turns":null,"Players":null,"Counter":1,"Assigned":false}],"Testing":false},"Error":null,"RowsAffected":1}
Note that the Players section is now null. Here's my room registration and room query functions:
func RegisterRoom(w http.ResponseWriter, r *http.Request) {
err := r.ParseForm()
if err != nil {
// Handle error
}
// r.PostForm is a map of our POST form values
room := Room{
Name: r.PostFormValue("label"),
Games: []Game{{
Counter: 1,
Players: []Player{{Name: r.PostFormValue("username")}},
}},
}
t := db.Create(&room)
if err := json.NewEncoder(w).Encode(t); err != nil {
panic(err)
}
}
func RoomShow(w http.ResponseWriter, r *http.Request) {
var rm Room
vars := mux.Vars(r)
roomId := vars["roomId"]
id, _ := strconv.Atoi(roomId)
room := db.Preload("Games").First(&rm, id)
result := db.Find(&room)
json.NewEncoder(w).Encode(result)
}
Solved it! Answer was under Nested Preloading smacks forehead

Resources