Comments (6)
I think you should be able to compare the return value of StructScan
to sql.ErrNoRows
from sqlx.
That works—thanks! I had database/sql as a side-effect import (since I’m leaning on sqlx) and didn’t spot that. Might have to dig through the database/sql API a little more.
Additionally: it looks like the best way to do this when using sqlx.Queryx to pull into a slice of structs is check if rows.Next() == false
(or !rows.Next()
if you like) prior to err := sqlx.StructScan(&rows.Rows, &dest)
.
On 26 Jan 2014, at 11:38 AM, Kamil Kisiel [email protected] wrote:
I think you should be able to compare the return value of StructScan to sql.ErrNoRows
—
Reply to this email directly or view it on GitHub.
from sqlx.
This is somewhat related to the above—I'm pulling a set of results from the DB (using Postgres' full text search capabilities):
rows, err := db.Queryx(`SELECT * FROM listings
WHERE tsv @@ plainto_tsquery('pg_catalog.english', $1)
ORDER BY expiry_date DESC LIMIT $2`, searchTerm, pageLimit) // pageLimit is 10 in this case
if rows.Next() == false { // or rows.Rows.Next() ?
...
}
err = sqlx.StructScan(&rows.Rows, &results)
if err != nil {
...
}
I'm doing some testing and exactly one record matches the search term provided. Running the query directly (via the CLI) results the expected row (singular). When running this query using sqlx however, rows.Next()
returns true
and rows.Rows.Next()
returns false
.
If I change it to ensure that at least two (2) rows are returned, rows.Rows.Next()
also returns true
and StructScan populates my slice of structs (&results
) as expected.
In the case where I'm expecting anywhere between 0 and ∞ results, how should I be confirming that there are > 0 rows returned before calling StructScan(&rows.Rows, &results)
? I want to scan the results into a slice of structs even if there is just one result to keep the code generic (and in most cases, there will rarely be just one result).
from sqlx.
You want to know if there are rows before you go to scan? Is this to save on allocation? You can use the db.Select
shortcut, or just go ahead and sqlx.StructScan(&rows.Rows, &results)
anyway; if there are no rows, then len(results) == 0
.
If you want to avoid that allocation, you could make a zero-length &results
and pass that in:
rows, err := db.Queryx(...)
results := make([]MyType, 0, 0)
err = rows.StructScan(&rows.Rows, &results)
Keep in mind that I'm thinking very strongly of changing rows.Rows
from sql.Rows
to *sql.Rows
to avoid that copy and some potentially sticky situations that can arise from it.
Edit Also, in my tests, rows.Rows.Next()
and rows.Next()
return the same results. They should in fact be the same function. If you call one after the other with a single result, then you will get true
followed by false
, as the first call to Next will have moved the cursor past the last row.
from sqlx.
@jmoiron Thanks for looking into this.
I'm not particularly fussed on saving on allocation (but it is a nice thing to do). I'm already allocating the result slice as the function returns (listings []*Listing, exists bool, error err)
up front anyway.
You're right that I could replace db.Queryx(...)
+ sqlx.StructScan(&rows.Rows, &results)
with a single db.Select(...)
and I'll probably do that as it saves me having to also drop in an explicit defer rows.Close()
as well.
I was definitely running into that last gotcha though since I was checking the value of rows.Next()
before proceeding with the scan, which was (not obviously to me!) causing the cursor to move on.
rows, err := db.Queryx(`SELECT id, title, company, location FROM listings WHERE tsv @@ plainto_tsquery('pg_catalog.english', $1) ORDER BY expiry_date DESC LIMIT $2`, searchTerm, pageLimit)
if err != nil {
return ...
}
defer rows.Close()
if rows.Next() == false {
return ...
}
err = sqlx.StructScan(&rows.Rows, &results)
if err != nil {
return ...
}
Thanks again for investigating/helping out.
from sqlx.
Ah yes, sqlx.StructScan
is going to do the standard:
for rows.Next() {
...
}
It sorta assumes that you've processed as far as the cursor has gone. This is unlike rows.Scan
; but the analogy of that is rows.StructScan
; sqlx.StructScan
is there basically to implement select. It's a confusing name conflict; I think originally sqlx was just these functions, and eventually I realized that the iterative is really valuable for conserving memory and added all the wrapping.
Going to close this as I think everything is working more or less as it should. Glad I could help!
from sqlx.
Related Issues (20)
- Transaction insertion issue
- EASY ONE: SQLX not passing sql.Drivers() through
- BindNamed() should not be deprecated HOT 1
- record and record[] fields coming back as text
- Is this project abandoned? HOT 9
- ConnectContext should close the db when PingContext returns an error
- I NEED YOUR HELP!!! query_as! UPDATE ... SET ...RETURNING...(unsupported type user_role for param #1) HOT 3
- [Question] Inverse of Get/Select? HOT 4
- missing destination name for field while it is not selected
- Behavioural differences between `sql.Named` with query vs `NamedExecContext` cause `UPDATE` error HOT 2
- how to call sqlite3_create_function_v2
- [Proposal] Replace the Test Host Level DB's with containers.
- Issue with mocking PrepareNamed
- Tag new version for dependency security updates HOT 1
- Batch insert still not working HOT 1
- Mysql "... update nowait" does not return error
- bindvar for MSSQL HOT 3
- Creating a connection pool with custom connector
- GetContext not in any interface -- propose adding interface GetterContext
- `Select()` mangling binary data when using `sql.RawBytes`
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from sqlx.