How GORM reads the value of the alias field - postgresql

When querying data, an alias is set for a field. How do I use GORM to read the value of the alias field into the structure?
Table Structure
DROP TABLE IF EXISTS "test"."test";
CREATE TABLE "test"."test" (
"id" varchar(32) NOT NULL,
"name" varchar(255) COLLATE "pg_catalog"."default",
"remark" varchar(255) COLLATE "pg_catalog"."default"
);
ALTER TABLE "test"."test" ADD CONSTRAINT "test_pkey" PRIMARY KEY ("id");
Table corresponding model structure
type Test struct {
ID string `gorm:"column:id;type:varchar(32);primaryKey;comment:Unique ID" json:"id"`
Name string `gorm:"column:name;type:varchar(255);comment:Name Info" json:"name"`
Remark string `gorm:"column:remark;type:varchar(255);comment:Remark Info" json:"remark"`
MoreInfo string `gorm:"-" json:"moreInfo"` // Non-table field
}
GORM query
gormDB is the initialized gorm database connection.
test := Test{ID: "0000000001"}
gormDB.Select("*, 'testMoreInfoVal' AS more_Info").Where(&test).Find(&test)
Q: How to use GORM to read the alias field more_Info that does not exist in the table into the MoreInfo property of the Test structure?

If the table structure is set and you aren't using AutoMigrate then this is solved by just changing your tags to make MoreInfo a read-only field and making sure you use the alias more_info to match the way Gorm does DB -> Go naming translation.
type Test struct {
ID string `gorm:"column:id;type:varchar(32);primaryKey;comment:Unique ID" json:"id"`
Name string `gorm:"column:name;type:varchar(255);comment:Name Info" json:"name"`
Remark string `gorm:"column:remark;type:varchar(255);comment:Remark Info" json:"remark"`
MoreInfo string `gorm:"->" json:"moreInfo"` // Non-table field
}
gormDB.Select("*, 'testMoreInfoVal' AS more_info").Where(&test).Find(&test)
If you are using AutoMigration then the problem will be that a more_info column will be created in your table, though Gorm will prevent writing to that column when using the struct.
What you could do in that case is use a new struct which embeds the Test struct like so:
type Test struct {
ID string `gorm:"column:id;type:varchar(32);primaryKey;comment:Unique ID" json:"id"`
Name string `gorm:"column:name;type:varchar(255);comment:Name Info" json:"name"`
Remark string `gorm:"column:remark;type:varchar(255);comment:Remark Info" json:"remark"`
}
type TestExt struct{
Test
MoreInfo string `gorm:"->" json:"moreInfo"`
}
testext := TestExt{}
gormDB.Model(&Test{}).
Select("*, 'testMoreInfoVal' AS more_info").
Where(Test{ID: "0000000001"}).
Find(&testext)

Related

Golang Gorm Automigrate not create filed type "time"

My struct looks like:
type AdvertContent struct {
Id string `gorm:"column:id;primaryKey;type:uuid;default:uuid_generate_v4()" json:"id" example:"4ff8eb91-640b-4e26-a50f-3bcd1f933d0c"`
FromTime *time.Time `gorm:"column:from_time;type:time;" json:"fromTime,omitempty" example:"HH:MM"`
ToTime *time.Time `gorm:"column:to_time;type:time;" json:"toTime,omitempty" example:"HH:MM"`
} //#name AdvertContent
func (this AdvertContent) TableName() string {
return "advert_content"
}
When I use gorm.AutoMigrate, table fields from_time and to_time created with type timestampz, not time.
Gorm debug mode:
CREATE TABLE "advert_content" ("id" uuid DEFAULT uuid_generate_v4(),"from_time" timestamptz,"to_time" timestamptz)
How can I create table with time type fields?
when using specified database data type, it needs to be a full
database data type, for example: MEDIUMINT UNSIGNED NOT NULL
AUTO_INCREMENT
You should use the database data type like this

How to scan into nested structs with sqlx?

Let's assume that I have two models,
type Customer struct {
Id int `json:"id" db:"id"`
Name string `json:"name" db:"name"`
Address Address `json:"adress"`
}
type Address struct {
Street string `json:"street" db:"street"`
City string `json:"city" db:"city"`
}
// ...
customer := models.Customer{}
err := db.Get(&customer , `select * from users where id=$1 and name=$2`, id, name)
But this scan throws an error as: missing destination name street in *models.Customer
Am I doing something wrong? As you can see I already updated the db corresponding of the value. I doubled check so case sensitivity shouldn't be a problem.
Or is it not possible using https://github.com/jmoiron/sqlx?
I can see it in the documentation but still couldn't figure out how to solve it.
http://jmoiron.github.io/sqlx/#advancedScanning
The users table is declared as:
CREATE TABLE `users` (
`id` varchar(256) NOT NULL,
`name` varchar(150) NOT NULL,
`street` varchar(150) NOT NULL,
`city` varchar(150) NOT NULL,
)
The very link you posted gives you an hint about how to do this:
StructScan is deceptively sophisticated. It supports embedded structs, and assigns to fields using the same precedence rules that Go uses for embedded attribute and method access
So given your DB schema, you can simply embed Address into Customer:
type Customer struct {
Id int `json:"id" db:"id"`
Name string `json:"name" db:"name"`
Address
}
In your original code, Address was a field with its own db tag. This is not correct, and by the way your schema has no address column at all. (it appears you edited it out of your code snippet)
By embedding the struct into Customer instead, Address fields including tags are promoted into Customer and sqlx will be able to populate them from your query result.
Warning: embedding the field will also flatten the output of any JSON marshalling. It will become:
{
"id": 1,
"name": "foo",
"street": "bar",
"city": "baz"
}
If you want to place street and city into a JSON address object as based on your original struct tags, the easiest way is probably to remap the DB struct to your original type.
You could also scan the query result into a map[string]interface{} but then you have to be careful about how Postgres data types are represented in Go.
I had the same problem and came up with a slightly more elegant solution than #blackgreen's.
He's right, the easiest way is to embed the objects, but I do it in a temporary object instead of making the original messier.
You then add a function to convert your temp (flat) object into your real (nested) one.
type Customer struct {
Id int `json:"id" db:"id"`
Name string `json:"name" db:"name"`
Address Address `json:"adress"`
}
type Address struct {
Street string `json:"street" db:"street"`
City string `json:"city" db:"city"`
}
type tempCustomer struct {
Customer
Address
}
func (c *tempCustomer) ToCustomer() Customer {
customer := c.Customer
customer.Address = c.Address
return customer
}
Now you can scan into tempCustomer and simply call tempCustomer.ToCustomer before you return. This keeps your JSON clean and doesn't require a custom scan function.

Querying string array with gorm

I'm trying to select items of a table with a column of type text[].
The result of the field brandIds always return null
my struct:
type User struct {
Email string `json:"email"`
Name string `json:"name"`
BrandIds pq.StringArray `gorm:"type:text[]" json:"brandIds"`
}
the code:
var users []dtos.User
db.Table("user").Find(&users)
data, _ := json.Marshal(users)
Name and emails returns fine... But the brandIds always return null.
Type of brandIds column is text[]
Postgres have some troubles with camelCase column names. When I named BrandIds gorm was looking for column bran_id
I needed to specify the column name so I have added the gorm:"column:brandId" to tell gorm whats the name of the column.

Struggling to manually create relations with gorm / migrate

I have an sql structure like so:
CREATE TABLE resources (
id SERIAL PRIMARY KEY,
title TEXT NOT NULL,
created_at TIMESTAMPTZ NOT NULL,
updated_at TIMESTAMPTZ NOT NULL,
deleted_at TIMESTAMPTZ
);
CREATE TABLE tags (
name TEXT PRIMARY KEY
);
What sql do I need to write, how can I tell gorm that I want a Resource to have many Tags? This is what I have currently go-wise:
package models
import (
"github.com/jinzhu/gorm"
)
type Tag struct {
Name string `gorm:"PRIMARY_KEY"`
}
type Resource struct {
gorm.Model
Title string
Tags []Tag `gorm:""`
}
Note that I explicitly do not want to auto-migrate via gorm. I am using the migrate tool to handle migrations and want to specifically handle them manually, not with go.
To define a has many relationship, a foreign key must exist.
So for your case Tag should be:
type Tag struct {
gorm.Model
Name string `gorm:"PRIMARY_KEY"`
ResourceID int
}
and Resource:
type Resource struct {
gorm.Model
Title string
Tags []Tag `gorm:"foreignkey:ResourceID"`
}
And your sql structure should have that foreign key ResourceID column.
Not sure if you have already checked this but it contains more details in case you need them: https://gorm.io/docs/has_many.html#Foreign-Key

Golang: gorm use Find(&model) for non gorm migrate table

There is table customer_account (postgres) which one was migrate from YII2.
DDL:
CREATE TABLE public.test_table (
id INTEGER PRIMARY KEY NOT NULL DEFAULT nextval('test_table_id_seq'::regclass),
data JSONB
);
In go project i try to get value from this table.
type TableGo struct {
Id int
Data string `gorm:"type:jsonb"`
}
table := TableGo{}
db.Where("id = ?", 75).Find(&table)
println(table.Data)
But there is (pq: relation "table_gos" does not exist)
How i can link structure which table without db.AutoMigrate(&TableGo{})?
I think table name in your migration script is wrong. Because it is not in GORM convention. If you want to use that name,you can use following method in your model for custom table name.
func (m *Model) TableName() string {
return "custom_table_name"
}
Found the solution:
func(TableGo) TableName() string {
return "account_status"
}