Jmoiron SQLX Golang common interface - go

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.

Related

Decode spanner row fields to nested structs golang

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)

Composer query to match a participant reference

So I have a query like this:
query selectOrder{
description: "Select an Order that matches a Client reference and an Order Number"
statement:
SELECT com.x.Order
WHERE (client == _$client AND orderNumber == _$orderNumber)
}
The order is something like this:
asset Order identified by uuid {
o String uuid
--> Client client
o String orderNumber
--> Item[] items
}
How do I pass the reference to the client to the query?
I tried the reference and was told to toJSON it.
I tried that and it won't parse the thing - there's a clear issue with the parsing of the query.
I can't find the answer in the docs, so I'm wondering if anyone has done this or if I have to save the client id instead of the reference to client and lose the integrity.
EDIT: For completeness for the first answer below.
I'm trying to add an Item to the array of Items.
My Item object is defined like this:
asset Item identified by uuid {
o String uuid
o DateTime timestamp
o String orderNumber
--> Client client
o String[] message
}
When the transaction is invoked the single object passed in is the Item.
I'm setting Item.client as the _$client value in the query.
Should I be pre-pending it with "resource:"?
I'm asking because I thought that was in the reference string already - at least it is in the view in the playground.
EDIT2:
So I manually construct the following variable:
var RSRC = 'resource:com.x.Client#XYZ123'
Set that as the client in this query
return query('selectOrder', {agency : RSRC, orderNumber : orderNumber});
But I'm still getting this:
Error: unknown operator "0" - should be one of $eq, $lte, $lt, $gt,
$gte, $exists, $ne, $in, $nin, $size, $mod, $regex, $elemMatch, $type
or $all
What next?
Embedding the "resource..." string in quotes didn't work either.
Your query looks ok, but you need to pass a string with the format:
resource:type.Name#instance for the relationship.
E.g. resource:org.acme.Car#123ABC

Sqlx "missing destination name" for struct tag through pointer

I have a model like this:
type Course struct {
Name string `db:"course_name"`
}
type Group struct {
Course *Course
}
type Groups []Group
And when i try to do sqlx.Select for Groups with a query like this:
SELECT c.name as course_name FROM courses as c;
I get
missing destination name course_name in *main.Groups
error.
What is the issue with this code?
You need to use sqlx.Select when you are selecting multiple rows and you want to scan the result into a slice, as is the case for your query, otherwise use sqlx.Get for a single row.
In addition, you can't scan directly into a Group struct because none of its fields are tagged (unlike the Course struct), and the Course field isn't embedded.
Try:
course := Course{}
courses := []Course{}
db.Get(&course, "SELECT name AS course_name FROM courses LIMIT 1")
db.Select(&courses, "SELECT name AS course_name FROM courses")
I changed Course *Course to Course Course - no effect.
When i made it embedded like this:
type Group struct {
Course
}
it worked.
This is also valid:
type Group struct {
*Course
}
Looks like sqlx doesn't understand anything except embedded fields.
Ok, so when you are using an embbeded struct with Sqlx, capitalization is important, at least in my case.
You need to refer to the embedded struct in your sql, like so:
select name as "course.name" from courses...
Notice that course is lower case and the naming involves a dot/period between table and column.
Then your Get or Select should work just fine.

Gocql custom marshaller

I have a table with a tuple column that is made up of an int64 paired with a uuid:
CREATE TABLE ks.mytable {
fileid frozen <tuple <bigint, uuid>>,
hits counter,
...
and I can currently set the field using a cql statement like:
UPDATE ks.mytable hits = hits + 1 WHERE fileid=(? ?);
and I pass in 2 variables as arguments, an int64 and a gocql.UUID.
Instead of moving 2 variables around everywhere, I want to put these in a struct, something like
type MyID struct {
id int64
uid gocql.UUID
}
then use a Marshaller to pass these into the UPDATE statement.
Is this possible? I am not sure if I can pass in a single variable for the tuple field. If so, how can I do this? I can't figure out how - I was trying to mimic https://github.com/gocql/gocql/blob/master/marshal_test.go#L935 but I'm getting errors where I can't set the fields in the struct (cannot refer to unexported field or method proto)
As you mentioned, you are getting the following error:
cannot refer to unexported field or method proto
This means you need to export your fields inside the struct and that means beginning with a capital letter in Go. So your struct should be:
type MyID struct {
Id int64
Uid gocql.UUID
}
Then, it should work.

How can I cast a Integer to a String in EJBQL

I got a Entity with a Integer
#Entity(name=customer)
public Customer {
...
#Column
private int number;
...
//getter,setter
}
Now I want to cast this Integer in a query to compare it with an other value.
I tried this Query:
"SELECT c FROM customer c WHERE CAST(c.number AS TEXT) LIKE '1%'"
But it doesn't work.
This works in some of my code using Hibernate:
SELECT c FROM customer c WHERE STR(c.number) LIKE '1%'
In general, this is what the Hibernate docs (14.10 Expressions) say on casting:
str() for converting numeric or temporal values to a readable string
cast(... as ...), where the second argument is the name of a Hibernate
type, and extract(... from ...) if ANSI cast() and extract() is
supported by the underlying database
Since EJB3 EJBQL has been (almost) replaced by JPQL. In EJBQL and according to http://docs.oracle.com/cd/E11035_01/kodo41/full/html/ejb3_langref.html in JPQL as well there is no functionality to CAST a property of an entity.
So like I already told there are two options left:
Use a native Query.
Add special cast methods to the entities.
You need to specify the column you're selecting from table alias c, and since EJBQL doesn't support a cast function, pass a string into the query instead of text. (This effectively allows your program to do the cast before it gets to EJBQL.)
The example below is in SQL Server, but should give you the idea:
declare #numberText as varchar(50)
set #numberText = '1'
SELECT c.CustomerNumber FROM customer c
WHERE c.CustomerNumber LIKE #numbertext + '%'
So instead of private int number use private string numberText.
NOTE: I edited this answer after OP confirmed EJBQL does not support a CAST function.

Resources