How to fetch last record in gorm? - go

I'm working on a golang application in which I need to fetch last record from the table so I'm not able to do it. I have models mention below:-
type SQLTransaction struct {
Id int `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
Version uint64 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty" gorm:"primaryKey"`
Hash string `protobuf:"bytes,3,opt,name=hash,proto3" json:"hash,omitempty"`
VmStatusId int `protobuf:"bytes,6,opt,name=vm_status_id,proto3" json:"vm_status_id,omitempty"`
}
Here is my gorm function in which I want to fetch the last record
func (mgr *manager) GetLastTxn() (int, error) {
var versionId int
resp := mgr.connection.Table("transactions").Last("", "version")
return versionId, resp.Error
}
Error:-
model value required
[0.053ms] [rows:0] SELECT * FROM `transactions` WHERE version ORDER BY `transactions`. DESC LIMIT 1
0 model value required
How can I achieve it please any help. Thanks in advance.

There are a couple of issues in your example that should be handled.
First, the error model value required suggests that the Last method needs a model to store the result. If you want the entire record with all the data you can do it like this:
var lastVersion SQLTransaction
resp := mgr.connection.Table("transactions").Last(&lastVersion)
If you only want the ID of the record, you do something like this:
var lastVersion struct {
ID int
}
resp := mgr.connection.Table("transactions").Last(&lastVersion)
Next, you don't need Last("", "version") because it doesn't do what you think it does. The first parameter is a pointer to your resulting object (which for all go-gorm methods always should be an object or a slice). The second one is a condition for the WHERE clause. So the correct syntax, if you don't need an additional WHERE clause, is:
resp := mgr.connection.Table("transactions").Last(&lastVersion)
If you look at the code of the Last method, it considers the primary key when it executes the method, so you don't even need any additional parameters or conditions.

Related

GORM unable to query all records using .Find()

I am trying to write a function to query all results that match a set of conditions and save them in a struct slice.
// Queries the database for the given set of fields and some string conditions specified as a map
func QueryAllRecords(db *gorm.DB, outputObject interface{}, conditions map[string]interface{}) {
result := db.Where(conditions).Find(&outputObject)
if result.Error != nil {
panic(result.Error)
}
log.Println(Utils.CreateLogMessage("Queried all records", outputObject))
}
According to the GORM docs (https://gorm.io/docs/query.html#Retrieving-all-objects), I can query all records using the .Find() function and then specify the struct where the output of the query will be saved.
This is where I make my function call to QueryAllRecords:
var outputObject []Models.Product
conditions := map[string]interface{}{"name": "Sample Product"}
DB.QueryAllRecords(db, outputObject, conditions)
fmt.Println(outputObject)
When I try to print outputObject, I get an empty an empty slice []. It seems like the .Find(&outputObject) is not saving the result in the slice like I want it to. I can successfully print outputObject within the function itself, but not after it has returned.
Use the DB.QueryAllRecords(db, outputObject, conditions) instead

Reflection to get field tag

In Go is there a good way to use reflection to get a field tag by just wrapping a field in a function from the reflect library?
I am basically trying to create a thin data access object that allows be to get the column name in the db without hard coding it all over the place.
Below is the struct with db column names as tags.
// Table Structures
type CusipTableRow struct {
Id int64 `db:"id"`
Cusip string `db:"cusip"`
Symbol string `db:"symbol"`
Active int8 `db:"active"`
Added_Time int32 `db:"added_timestamp"`
Description string `db:"description"`
Exchange string `db:"exchange"`
AssetType string `db:"asset_type"`
}
I am seeking a suggestion other than downloading another library on how to use reflection to essentially make a call like this to return a string with the tag value.
var row CusipTableRow
row.GetColumnName(row.Id) //Return column name based on tag.
I was considering possibly trying to use a map[address] fieldTag, but did not have luck getting that to work perhaps due to not fully having a grasp of the unsafe package. If that approach would have worked I was thinking a call like this could have worked:
row.GetColumnName(&row.Id) //Return column name based on tag.
You can get field tag given the address of the struct and the address of the field. Unsafe shenanigans are not required.
func GetColumnName(pstruct interface{}, pfield interface{}) string {
v := reflect.ValueOf(pstruct).Elem()
for i := 0; i < v.NumField(); i++ {
if v.Field(i).Addr().Interface() == pfield {
return v.Type().Field(i).Tag.Get("db")
}
}
panic("field not in struct")
}
Example use:
var v CusipTableRow
fmt.Println(GetColumnName(&v, &v.Added_Time)) // prints added_timestamp
Run it on the Go Playground.

Retrieve deleted rows on deletion

Is there a way to retrieve the rows deleted when calling Delete()?
I'd like to avoid using 'SELECT ... FOR UPDATE' to first get the list of rows I'm deleting.
type MyModel struct {
gorm.Model
....
}
res := db.Where("updated_at < ?", expirationDate).
Set("gorm:save_associations", false).
Delete(&MyModel{})
I noticed there is a res.Value attribute but it seems to be the empty struct I pass as argument of Delete().
Your query should be this way instead. db.Where does not return the struct. It modifies the pointer passed as parameter.
var res MyModel{}
db.Where("updated_at < ?", expirationDate).
Delete(&res)

LoadRelated of a list in beego

I am wondering how the correct approach is to load related fields in beego.
The doc explains it like this:
type User struct {
Id int
Name string
Posts []*Post `orm:"reverse(many)"`
}
user := User{Id: 1}
err := dORM.Read(&user)
num, err := dORM.LoadRelated(&user, "Posts")
This makes sense as long as I only query one record. What is the correct way to fetch related fields when I query all users?
A possible solution would be like this:
var users []*User
o.QueryTable(new(User)).All(&users)
for _, user := range users {
o.LoadRelated(controlCategory, "Posts")
}
However, this means I have to loop everytime over the complete list and make for every record a DB query to load all records.
Any suggestions? Thanks!

go-pg different count fields in struct and table

I use go-pg library and specify row in table "unit"
type UnitModel struct {
Id int
Name string
TableName struct{} `sql:"unit"`
}
but table unit contains more then 2 fields and when i call
var unit UnitModel
err := db.Model(&unit).Where("id = ?", id).Select()
get error "pg: can't find column alter_name in model".
How specify ignore other fields in table "unit"?
Read go-pg manual. There's an example, for your case is:
err := db.Model(&unit).Column("id", "name").Where("id = ?", id).Select()
In version 4.8.10 go-pg this bug fixed. If db table contain fields which not exist in structure error will not occur.

Resources