I have a sqlx query function with interface as passing parameter, now i want to using the raw query string, how to omit this interface parameter?
func QuerySlice(query string, data interface{}) error {
q := queryString(query, data)
}
// If pass the data
data := struct {
id string `db:"id"`
}{
Id: id,
}
QuerySlice(query, data)
// The query sql is
SELECT
*
FROM
table
WHERE
id = :id
// Now i want the raw sql
SELECT
*
FROM
table
WHERE
id = 'XXX'
// How to pass the data interface to omit this parameter
If you are using NamedExec, you could pass a empty map to sqlx
QuerySlice(rawQuery, map[string]interface{}{})
Related
Let's say I have these struct that represent my models
type QuestionHeader struct {
QuestionHeaderId int `gorm:"primaryKey;column:question_id" json:"question_id"`
LevelId int `gorm:"column:level_id" json:"level_id"`
SubjectId int `gorm:"column:subject_id" json:"subject_id"`
QuestionBody []QuestionBody
QuestionSolution []QuestionSolution
OtherColumn1A string
OtherColumn2A string
}
type QuestionBody struct {
QuestionBody int `gorm:"primaryKey;column:question_id" json:"question_id"`
Value string `gorm:"column:value" json:"value"`
Type string `gorm:"column:type" json:"type"`
OtherColumn1B string
OtherColumn2B string
}
type QuestionSolution struct {
QuestionSolutionId int `gorm:"primaryKey;column:question_id" json:"question_id"`
Value string `gorm:"column:value" json:"value"`
Type string `gorm:"column:type" json:"type"`
OtherColumn1C string
OtherColumn2c string
}
Then I want to do a query with preload like this
qs.db().
Preload("QuestionHeader.QuestionBody", func(db *gorm.DB) *gorm.DB {
return db.Where("question_body.status = ?", 1)
// I only want to select certain column here
}).
Preload("QuestionHeader.QuestionSolution", func(db *gorm.DB) *gorm.DB {
return db.Where("question_solution.status = ?", 1)
// I only want to select certain column here
}).
Where("level_id = ?", 2).
Find(&questionHeaders) // I only want to select certain column here
But the catch with that code is, I will select all the columns based on my model property
What if I want to select only a certain column with preload?
For example, I want to select only type for QuestionBody
I know that you can create another struct for your select statement as described in the docs, but are there any other ways? I don't want to create a struct for every select statement
In Laravel Eloquent, you can do something like this
There are few issue that i would like to point out
You don't have the many2many association defined in QuestionHeader for QuestionBody or QuestionSolution
In query you are using status column but I don't seem them defined in QuestionBody or QuestionSolution
Rename QuestionBody id column to QuestionBodyId in QuestionBody
As per the points changes would be as below:
type QuestionHeader struct {
QuestionHeaderId int `gorm:"primaryKey;column:question_id" json:"question_id"`
LevelId int `gorm:"column:level_id" json:"level_id"`
SubjectId int `gorm:"column:subject_id" json:"subject_id"`
QuestionBody []QuestionBody `gorm:"many2many:question_header_question_bodies;"`
QuestionSolution []QuestionSolution `gorm:"many2many:question_header_question_solutions;"`
OtherColumn1A string
OtherColumn2A string
}
type QuestionBody struct {
QuestionBodyId int `gorm:"primaryKey;column:question_id" json:"question_id"`
Value string `gorm:"column:value" json:"value"`
Type string `gorm:"column:type" json:"type"`
Status uint8 `gorm:"column:status;default:0" json:"status"`
OtherColumn1B string
OtherColumn2B string
}
type QuestionSolution struct {
QuestionSolutionId int `gorm:"primaryKey;column:question_id" json:"question_id"`
Value string `gorm:"column:value" json:"value"`
Type string `gorm:"column:type" json:"type"`
Status uint8 `gorm:"column:status;default:0" json:"status"`
OtherColumn1C string
OtherColumn2c string
}
var questionHeaders QuestionHeader
db.
Preload("QuestionBody", func(db *gorm.DB) *gorm.DB {
return db.Where("Status = ?", 1).Select("QuestionBodyId", "Value")
}).
Preload("QuestionSolution", func(db *gorm.DB) *gorm.DB {
return db.Where("Status = ?", 1).Select("QuestionSolutionId", "Value")
}).
Where("level_id = ?", 2).
Select("SubjectId").
Find(&questionHeaders)
}
In Preload Select we would have to include the unique primary key for gorm to uniquely identify the associated slice of structs
I have a union on two concrete types Prodotto and ProdottoVariante both implements a interface of type Articolo.
union Articoli = Prodotto | ProdottoVariante
extend type Query {
articoli: [Articoli!]!
}
I want to query all Prodotto and all ProdottoVariante by typing articoli but I don't know how to resolve Articoli
I'm trying in this way:
func (r *queryResolver) Articoli(ctx context.Context) ([]model.Articoli, error) {
var articoli []model.Articoli
r.DB.Model(&model.Prodotto{}).Select("nome").Find(&articoli)
r.DB.Model(&model.ProdottoVariante{}).Select("nome").Find(&articoli)
return articoli, nil
}
and I'm querying in this way:
query {
articoli {
__typename
...on Prodotto {
nome
}
}
}
but I get this error:
{
"errors": [
{
"message": "must not be null",
"path": [
"articoli",
0
]
}
],
"data": null
}
sql: Scan error on column index 0, name "nome": unsupported Scan, storing driver.Value type string into type *model.Articoli
How to correctly resolve Unions with gorm?
You could always try to create a join between prodotto and prodotto_variante tables and select the needed columns to populate the fields in the Articoli struct.
I'm not sure how your prodotto and prodotto_variante tables relate to each other. I'm also assuming that the nome column is part of the prodotto table and that it corresponds to a field in the Articoli struct. The code would look something like this:
func (r *queryResolver) Articoli(ctx context.Context) ([]model.Articoli, error) {
var articoli []model.Articoli
err:= r.DB.Table("prodottos").
Join("JOIN prodotto_variantes pv ON prodotto.id = pv.prodotto_id").
Find(&articoli).Error
return articoli, err
}
The above code should populate the entire Articoli struct, if the struct fields match the columns in the prodottos table.
If you want to populate just some of the fields, you can do it in a couple of ways.
Example 1
// this should work if populating more than one field
err:= r.DB.Table("prodottos").
Join("JOIN prodotto_variantes pv ON prodotto.id = pv.prodotto_id").
Select("prodottos.id, prodottos.nome").
Find(&articoli).Error
Example 2
// this should work if you want to populate only one field
type Art struct {
Nome string
}
var arts []Art
err:= r.DB.Table("prodottos").
Join("JOIN prodotto_variantes pv ON prodotto.id = pv.prodotto_id").
Find(&arts).Error
I have a table like below
INSERT INTO switches VALUES ('33', 60, jsonb_build_object('IDs',jsonb_build_array('11', '2'),'ID', '33', 'Name', 'switch1'));
I have a struct/model
type switches struct {
ID string `gorm:"primary_key; unique; json:id"`
Generation uint32 `gorm:"type:integer; column:generation;" json:"generation" `
// Additional gorm type jsonb set, if not present causes field to be bytea
SwitchAttrs []byte `sql:"type:jsonb; not null; column:Switch_attrs;" gorm:"type:jsonb; json:switchAttrs"`
}
I can query in postgres
SELECT * FROM switches WHERE switch_attrs->'IDs' ? '2'
id | generation | data
----+-------+------------------
33 | 60 | {"IDs": ["33","2"] }
How do I construct a query on the jsonB column for a particular key(s)? I was not able to find any documentation for using model objects to query which explains how to use "in" operator. I understand its possible to do with raw query, but wanted to see how it can be done using model object. I am trying to make queries like below but it fails :(
db = db.Where("Switch_attrs->'IDs' ?", "2").Find(&switches)
OR
db = db.Where("Switch_attrs->'IDs' ?", []string{"2"}).Find(&switches)
OR
db = db.Where("Switch_attrs->'IDs' IN ?", []string{"2"}).Find(&switches)
OR
db = db.Where("Switch_attrs->>'IDs' ?", "2").Find(&switches) . Note that i am querying as switch_attrs->>'IDs' . i expect the o/p as text and hence passing the value as "2".
for the last query i keep getting error as
"Severity": "ERROR", "Code": "42601", "Message": "syntax error at
or near "$1"",
Redefine your model as below
type switches struct {
ID string `gorm:"primary_key; unique; json:id"`
Generation uint32 `gorm:"type:integer; column:generation;" json:"generation" `
// Additional gorm type jsonb set, if not present causes field to be bytea
SwitchAttrs SwitchAttr `sql:"type:jsonb; not null; column:Switch_attrs;" gorm:"type:jsonb; json:switchAttrs"`
}
Add this for SwitchAttr
type SwitchAttr struct {
data struct {
ID *int `json:"id"`
Generation *string `json:"generation"`
IDs []string `json:"IDs"`
} `json:"data"`
}
// Column JSONB field
func (a SwitchAttr) Value() (driver.Value, error) {
return json.Marshal(a)
}
// simply decodes a JSON-encoded value into the struct fields.
func (a *SwitchAttr) Scan(value interface{}) error {
b, ok := value.([]byte)
if !ok {
return errors.New("type assertion to []byte failed")
}
return json.Unmarshal(b, &a)
}
For Query,
db = db.Where("switchAttrs #> '{"data":{"IDs":<pass_your_array_of_string>}}'::jsonb").Find(&switches)
I am trying to implement the Value interfaces for a db model, however I only receive an empty object when the Value function is called. The models are stored in the table as Link's but when I read them I want to append an additional field by using the value interface, the function is called however I'm not sure how I can access the original entry so that I can append the name to it
I define my struct as such:
type Link struct {
Id string
Url string
}
type ReturnLink struct {
Link
Name string
}
func (l *Link) Scan(value interface{}) error {
fmt.Println("scan")
return nil
}
func (l Link) Value() (driver.Value, error) {
fmt.Println("value")
name := getName()
returnLink := ReturnLink{
Link: l,
Name: name,
}
return returnLink, nil
}
Once I have formed the query, I am able to scan the value into the struct:
var link ReturnLink
db.Model(&Link{}).Where("id = ?", id).Scan(&link)
This returns a correct link with an empty name when I don't define the Value interface, but once implemented it only returns null values for each field, is there something I'm missing?
I have also tried not implementing the scan interface but it changes nothing
I am trying to query all the results from a postgres table without where condition and map it with array of structs with the help of sqlx db Query by passing the args ...interface {}.
But the code pasted below never works, Instead of iterating and scanning the result one by one , is it possible to get the following code work ??
Inputs are much appreciated . Thank you
type CustomData struct {
ID string `db:"id" json:",omitempty"`
Name string `db:"name" json:",omitempty"`
Description string `db:"description" json:",omitempty"`
SourceID string `db:"sourceid" json:",omitempty"`
StatusID string `db:"statusid" json:",omitempty"`
StatusReason string `db:"statusreason" json:",omitempty"`
CreateTime string `db:"createtime" json:",omitempty"`
UpdateTime string `db:"updatetime" json:",omitempty"`
}
var myData []CustomData
*sqlx.DB.Query("SELECT id as ID, name as Name, description as Description, sourceid as SourceID, statusid as StatusID, statusreason as StatusReason, createtime as CreateTime, updatetime as UpdateTime FROM myschema.my_table", &myData)
// tried with following statement but din't work either
// *sqlx.DB.Query("SELECT * FROM myschema.my_table", &myData)
for _, data := range myData {
fmt.Println("--", data)
}
Expected results:
--- CustomData{1,x,x,x,x}
--- CustomData{2,x,x,x,x}
Actual:
Nothing..
You don't need to rename the fields in the query, since you're defining the actual DB fields in the struct tags.
If you want to scan directly to the slice of CustomData and if you are using SQLX, you should use the SQLX specific Select method, rather than the generic SQL Query. Slightly modified relevant example from the illustrated guide to SQLX (https://jmoiron.github.io/sqlx/#getAndSelect):
pp := []Place{}
err = db.Select(&pp, "SELECT * FROM place")
So in your case:
myData := []CustomData
err = db.Select(&myData, "SELECT * FROM myschema.my_table")
you can use the following:
for rows.Next() {
s := CustomData{}
if err := rows.Scan(&s); err != nil {
return err
}
fmt.Println(s)
}
and you can always use ORM library as gorm if you like code first approach or sqlboiler if you like DB first approach