Decode spanner row fields to nested structs golang - go

I have two structs
type Row struct{
ID string
Status string
details Details
}
type Details struct{
SessionID string
Location string
Project string
}
And I get data like this
Select a.ID, a.Status, b.SessionID, b.Location, b.Project from table1 as a left join table2 as b on a.ID == b.SessionID
Now, to get all the select info in a row I need to change the struct and add the fields in it instead of a struct(Details) which is essentially duplicating fields in Row and Details (which I need for other purpose as well).
type Row struct{
ID string
Status string
SessionID string
Location string
Project string
}
r := Row{}
spanner.row.ToStruct(&r) // this works
but is there a simplified way to get the data without having to duplicate the fields in the struct or specifying each field in spanner.row.Column? I read that spanner.row.ToStruct does not support destination struct to have a struct as field as that's not a supported column type, but what's a better workaround?
Thanks!

I have not worked on the google cloud scanner directly but from the Go language point of view, How about embedding the Structs?
i.e.:
type Row struct{
ID string
Status string
Details
}
type Details struct{
SessionID string
Location string
Project string
}
r := Row{}
spanner.row.ToStruct(&r)

Related

update a map whose value is an array of object but get error

I just started learning Golang today. So, I suppose this question is a basic one howerver I tried what I can try, but get error.
So, I have defined a Student struct type:
type Student struct {
firstname string `json:"first_name"`
id int `json:"id"`
}
I want to have a map data structure, in which the map's key represent "class id" & the value of each key in this map is an array of Student. This is what I have tried:
var studentsMap = make(map[int][]Student)
func registerStudent(classId int, studentName string, studentId int) {
var studentsInClass = studentsMap[classId]
if studentsInClass == nil {
studentsInClass = []Student{}
}
// append the new student to the studentsInClass array
var updatedStudentsArr = append(studentsInClass, Student{studentName, studentId})
// update the map for this class id with updated array of students
// Compiler ERROR: Cannot use 'updatedStudentsArr' (type []Student) as the type Student
studentsMap[classId] = updatedStudentsArr
}
As you see in my comment in the code, when I try to update the studentsMap with the new array, I get compiler error Cannot use 'updatedStudentsArr' (type []Student) as the type Student. Why is that? My guess is that I defined wrongly the studentsMap map type, but how to fix?
The code you posted seems to be working fine, as pointed out by #nipuna in the comments.
As a small note, when you test for a key,value existence in go you get two values, the latter being a boolean. You can thus use the following to test whether studentsMap[classId] exists
studentsInClass, ok := studentsMap[classId]
if !ok {
studentsInClass = []Student{}
}
Regarding your second question related to #Volker's comment, you can read more about exporting struct fields in the following answers.
If you are using an IDE, it might be warning you about it (e.g. in VSCode I get struct field firstname has json tag but is not exported).
https://stackoverflow.com/a/50320595/5621318
https://stackoverflow.com/a/11129474/5621318
https://stackoverflow.com/a/25595269/5621318

How to Ignore database columns not specified in the struct

I have mentioned two fields(Name, Age) in my golang Struct after few days I have added one more fields in my database(Name,Age, Salary ) not in golandg struct.It shows errors like(Error 1364: Field 'salary' doesn't have a default value). How to ignore fileds in my struct dynamically
type Employee struct {
Name string `json:"name"
Age int `json:"age"
}
In future i will add more fileds but i don't want mention in struct
Based on the error you are getting, it seems like you are trying to insert a row into a MySQL database, and the new row you added does not have a default value. So your options are to :
Add a default value to the new column - See: https://dev.mysql.com/doc/refman/8.0/en/data-type-defaults.html
Add a field for the column into your Go struct and supply a value for it.

parsing query values to substruct using pgx

Prefacing this that im very new with Go and pgx. Is there a way to easily parse substruct values from a query?
So I do a Join query like:
rows, err := conn.Query(context.Background(),
`SELECT
rdr.id AS r_Id,
rdr.field1 AS r_Field2,
rdr.field2 AS r_Field2,
contact.firstname AS c_FirstName,
contact.lastname AS c_LastName,
contact.id AS c_Id
FROM rdr
INNER JOIN contact ON rdr.contact=contact.id`)
Then my structs are
type Rdr struct {
Id int32
Field1 int32
Contact Contact
Field2 time.Time
}
type Contact struct {
Id int
FirstName string
LastName string
}
How can I parse the data returned in the rows into my Rdr struct. I would need to parse the correct fields into the Contact, ideally at the same time, but i dont see how to do that. I cant see how Scan would do it. We were looking at the FieldDescriptions and the Values but it gets very messy. Is there an easy/common way to do this? I imagine its a very common issue.

"Creation At" time in GORM Customise Join table

I am trying to customize many2many table join. I have two tables from which I want to have taken the ids and want another field, which will tell me when the entry in the join table was made. The ids are coming fine, but the "created_at" is not updating and shows "Null" instead of time.
// this is the table join struct which I want to make
type UserChallenges struct {
gorm.JoinTableHandler
CreatedAt time.Time
UserID int
ChallengeID int
}
//hook before create
func (UserChallenges) BeforeCreate(Db \*gorm.DB) error {
Db.SetJoinTableHandler(&User{}, "ChallengeId", &UserChallenges{})
return nil
}
This is not giving any error on the build. Please tell me what I am missing so that I can get the creation time field in this.
PS - The documentation of GORM on gorm.io is still showing SetupJoinTable method but it is deprecated in the newer version. There is a SetJoinTableHandler but there is no documentation available for it anywhere.
The thing to get about using a Join Table model is that if you want to access fields inside the model, you must query it explicitly.
That is using db.Model(&User{ID: 1}).Association("Challenges").Find(&challenges) or db.Preload("Challenges").Find(&users), etc. will just give you collections of the associated struct and in those there is no place in which to put the extra fields!
For that you would do:
joins := []UserChallenges{}
db.Where("user_id = ?", user.ID).Find(&joins)
// now joins contains all the records in the join table pertaining to user.ID,
// you can access joins[i].CreatedAt for example.
If you wanted also to retrieve the Challenges with that, you could modify your join struct to integrate the BelongsTo relation that it has with Challenge and preload it:
type UserChallenges struct {
UserID int `gorm:"primaryKey"`
ChallengeID int `gorm:"primaryKey"`
Challenge Challenge
CreatedAt time.Time
}
joins := []UserChallenges{}
db.Where("user_id = ?", user.ID).Joins("Challenge").Find(&joins)
// now joins[i].Challenge is populated

Jmoiron SQLX Golang common interface

I am new to golang and using Jmoiron Sqlx package for querying the Postgres Database(select query) . The waY I am doing is creating a sql string and calling Select(dest interface{}, query string,args) method. While it works well , the problem is I am generating my sql String dynamically and as such the destination structure should be different for each response .
For ex : - One query can be
Select a,b,c,d from table A ;
the other can be
Select x,y,z from Table B;
From what i understand , there should be two different structs defined for Select Method to work i.e.
Struct Resp1{
a string
b string
c string
d string
}
And,
Struct Resp2{
x string
y string
z string
}
And then invoke select as db.Select(&resp1,query,args) and db.Select(&resp2,query,args)
I am thinking if its possible for me to define a common Struct
say Resp3{
a string
b string
c string
d string
x string
y string
z string
}
And based on my select query populates only the matching columns (i.e only a,b,c,d for first and x,y,z for second) .
I tried searching but couldnt get any leads .
I could not get answer to this here and since I needed this , I dug up myself and I found how to solve this in an efficient way .
To solve this one can define all your String values as sql.NullString , integer as sql.int64 , float as sql.float64 etc .
So Say your table is having columns a,b,c,d,e,f and for some response you only have to display a,b,d for some other d,e and so on . Instead of creating different structures and mapping them in db.Select(...) statement Just define ur struct as follows
a sql.NullString `json:"whatever u wish to have as key,omitempty"`
b sql.NullString `json:"b,omitempty"`
c sql.NullString `json:"c,omitempty"`
d sql.int64 `json:"d,omitempty"`
e sql.float64 `json:"e,omitempty"`
Remember sql.NullString will be Marshalled to json with an additional key displayed (Valid:boolean) . You can follow approach here to fix that How can I work with sql NULL values and JSON in Golang in a good way?
Hope this is helpful to someone.!!
Usually your struct should represent all fields of SQL table, not only fields that you are fetching in SELECT, so you can just do SELECT * FROM... and deserialize response from db to your struct Resp3.

Resources