Generated SQL query with "WHERE (1 <> 1)" condition - postgresql

I'm trying to query a many-to-many relationship using the Gorm ORM for Go.
I have two structs: User & Address.
type User struct {
// gorm.Model
UUID string `gorm:"type:uuid;primary_key;auto_increment:false"`
Firstname string
// ...
Addresses []Address `gorm:"many2many:useraddresses"`
}
// Address represents the Postgres SQL address model
type Address struct {
UUID string `gorm:"type:uuid;primary_key;auto_increment:false"`
Line1 string
// ...
}
I took inspiration from the many-to-many example shown here in the documentation, (except I used a slice of users []User instead of a single user).
var u []User
var a []Address
If I query just using the users as a Model, all users are returned (sends sql query SELECT * FROM "users"):
db.Model(&u).Find(&u)
However, if I include related Addresses, surgeons are returned, but no Addresses:
db.Model(&u).Related(&a, "Addresses").Find(&u)
This creates another sql query that precedes the first:
SELECT "addresses".*
FROM "addresses" INNER JOIN "useraddresses" ON "useraddresses"."address_uuid" = "addresses"."uuid"
WHERE (1 <> 1)
Of course, the where false condition prevents any addresses from being returned.
Can anyone shed light on how I can include the addresses using the db.Model method of Gorm?

Related

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.

Get association objects with order from JoinTable using GORM

I have two models
type Holder struct {
OwnModel
Title string `json:"title"`
Exercises []Exercise `json:"exercises" gorm:"many2many:holder_exercises_new;"`
}
type Exercise struct {
OwnModel
Title string `json:"title"`
}
And join table
type HolderExercisesNew struct {
OwnModel
HolderID int64 `json:"holder_id"`
ExerciseID int64 `json:"exercise_id"`
Order int64 `json:"order"` // my custom param for ordering
}
I want to preload Exercises to Holders but ordered by "Order" param in join table.
For example i have
holders := []models.Holder{}
database.Preload("Exercises").Find(&holders)
It gives me holders with embedded exercises but in random order.
Is there a way to get Exercises in order set in join table?
I tried what seemed obvious to me, which is using Custom Preloading SQL:
holders := []models.Holder{}
database.
Preload("Exercises", func(tx *gorm.DB) *gorm.DB {
return tx.Order("holder_exercises_new.order ASC")
}).
Find(&holders)
But that didn't work because GORM separates the loading into two queries, one of the join table and another of the joined table. A workaround I found would be, sans error checking:
holders := []models.Holder{}
database.Find(&holders)
for i := range holders {
database.
Model(&holders[i]).
Order("holder_exercises_new.order ASC").
Association("Exercises").
Find(&holders[i].Exercises)
}

Convert a postgres row into golang struct with array field

I am having postgres db table as
CREATE TABLE foo (
name varchar(50),
types varchar(50)[],
role varchar[10]
);
and corresponding struct in go:
type Foo struct {
Name string `db:"name"`
Types []string `db:"types"`
Role string `db:"role"`
}
I want to fetch db rows into my struct. Right now I am able to do this by using:
var foo Foo
query := `SELECT name, types, roles FROM foo LIMIT 1`
err = dbConn.QueryRow(query).Scan(&foo.Name, pq.Array(&foo.Types), &foo.Role)
But I want to achieve the same using direct mapping. Something like:
var foo []Foo
query := `SELECT name, types, roles FROM foo`
dbWrapper.err = dbConn.Select(&foo, query)
Above snippet gives me error because of Types being pq array. Is it possible to directly map pq array as a part of struct?
Thanks to https://stackoverflow.com/a/44385791/10138004, I am able to solve this pq driver for sqlx (https://godoc.org/github.com/lib/pq) itself by replacing []string with pq.StringArray.
So, updated struct looks like:
type Foo struct {
Name string `db:"name"`
Types pq.StringArray `db:"types"` //this is what changed.
Role string `db:"role"`
}
and direct mapping is working like a charm now
var foo []Foo
query := `SELECT name, types, roles FROM foo`
dbWrapper.err = dbConn.Select(&foo, query)
You can use pg-go lib for that. Please look at pg.Model(). It's possible to pass an entire struct to it.

inserting relationships go-pg PostgreSQL

I've got 2 structs to represent a ManyToMany relationship. User and Note
type User struct {
ID int
Name string
Notes []*Note
}
type Note struct {
TableName struct{} `sql:"user_notes"`
ID int
Text string
}
Now let's say I want to insert a new user and also at the same time add a few notes.
I would expect this to insert a user and its note(s):
note := Note{
Text: "alohaa dude",
}
user := User{
Name: "peter",
Notes: []Note{no},
}
s.DB.Insert(&user)
However this only saves the user and not the user and the note. In go-pg do I have to do this manually or is there an automated way through the ORM?
Rodrigo, same problem statement is being discussed here: https://github.com/go-pg/pg/issues/478
This functionality is not supported in go-pg at this time and you might want to try a db prepare approach to insert with relationships.

How to create association one to many and many to one between two entities in gorm?

I'm new in Grails. I have a problem with generation association many to one and one to many between two tables. I'm using postgresql database.
Employee.groovy
class Employee {
String firstName
String lastName
int hoursLimit
Contact contact
Account account
Unit unit
char isBoss
static hasMany = [positionTypes:PositionType, employeePlans: EmployeePlan]
}
EmployeePlan.groovy
class EmployeePlan {
AcademicYear academicYear
HourType hourType
int hours
float weightOfSubject
Employee employee
static belongsTo = [SubjectPlan]
}
I'd like to have access from employee to list of employeePlans and access from EmployeePlan to Employee instance. Unfortunately GORM generates only two tables Employee and EmployeePlan with employee_id. I don't have third table which should have two columns employee_id and employee_plan_id. Could you help me ?
I think your setup is correct, as you write from Employee class you can access to a collection of EmployeePlan (take care, that if you don't explicitly define EmployeePlan like a List, it will be a Set by default) and from EmployeePlan you can access Employee.
If you need List, you can define it like that:
class Employee {
String firstName
String lastName
int hoursLimit
Contact contact
Account account
Unit unit
char isBoss
//explicitly define List
List<EmployeePlan> employeePlans
static hasMany = [positionTypes:PositionType, employeePlans: EmployeePlan]
}
But back to your question. You'd like to have join table between Employee and employeePlan, but why? Its not necessary, since you have bidirectional mapping with sets (unordered), grails will not create a join table. Can you explain why do you need it? In grails the references will be auto-populated, so I don't see any issue here.
If need to preserve order of employeePlans, then define it as List, shown above, and grails will create a join table with corresponding indexes.
have you read the ref-doc? it gives you the answer immediately:
class Person {
String firstName
static hasMany = [addresses: Address]
static mapping = {
table 'people'
firstName column: 'First_Name'
addresses joinTable: [name: 'Person_Addresses',
key: 'Person_Id',
column: 'Address_Id']
}
}