I am trying to implement pagination in my GO backend API. The API uses SQLC for the abstraction through to my PostgreSQL database. The issue is, It returns blank records and i cannot figure out what am doing wrong. The following are relevant codes pertaining to my current work:
const getAllFeeds = `-- name: GetAllFeeds :many
SELECT count(*) OVER(), id, created_at, updated_at, name, url, user_id, version
FROM feeds
WHERE ($1 = '' OR to_tsvector('simple', name) @@ plainto_tsquery('simple', $1))
AND ($2 = '' OR url LIKE '%' || $2 || '%')
ORDER BY id ASC
LIMIT $3 OFFSET $4
`
type GetAllFeedsParams struct {
Column1 interface{}
Column2 interface{}
Limit int32
Offset int32
}
type GetAllFeedsRow struct {
Count int64
ID uuid.UUID
CreatedAt time.Time
UpdatedAt time.Time
Name string
Url string
UserID int64
Version int32
}
func (q *Queries) GetAllFeeds(ctx context.Context, arg GetAllFeedsParams) ([]GetAllFeedsRow, error) {
rows, err := q.db.QueryContext(ctx, getAllFeeds,
arg.Column1,
arg.Column2,
arg.Limit,
arg.Offset,
)
if err != nil {
return nil, err
}
defer rows.Close()
var items []GetAllFeedsRow
for rows.Next() {
var i GetAllFeedsRow
if err := rows.Scan(
&i.Count,
&i.ID,
&i.CreatedAt,
&i.UpdatedAt,
&i.Name,
&i.Url,
&i.UserID,
&i.Version,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
func (m FeedModel) GetAllFeeds(name string, url string, filters Filters) ([]*Feed, Metadata, error) {
// create our timeout context. All of them will just be 5 seconds
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
// retrieve our data
fmt.Printf("Executing GetAllFeeds with name: [%s], url: [%s], limit: %d, offset: %d\n",
name, url, filters.limit(), filters.offset())
rows, err := m.DB.GetAllFeeds(ctx, database.GetAllFeedsParams{
Column1: name,
Column2: sql.NullString{String: url, Valid: url != ""}, // Convert string to sql.NullString
Limit: int32(filters.limit()),
Offset: int32(filters.offset()),
})
//check for an error
if err != nil {
return nil, Metadata{}, err
}
fmt.Println("Rows: ", rows)
totalRecords := 0
feeds := []*Feed{}
for _, row := range rows {
var feed Feed
totalRecords = int(row.Count)
feed.ID = row.ID
feed.CreatedAt = row.CreatedAt
feed.UpdatedAt = row.UpdatedAt
feed.Name = row.Name
feed.Url = row.Url
feed.Version = row.Version
feed.UserID = row.UserID
feeds = append(feeds, &feed)
}
// Generate a Metadata struct, passing in the total record count and pagination
// parameters from the client.
metadata := calculateMetadata(totalRecords, filters.Page, filters.PageSize)
return feeds, metadata, nil
}
Sample output:
Executing GetAllFeeds with name: [], url: [], limit: 30, offset: 0 Rows: [] Total Records: 0
Initial schema:
-- +goose Up
CREATE TABLE feeds(
id UUID PRIMARY KEY,
created_at timestamp(0) with time zone NOT NULL DEFAULT NOW(),
updated_at timestamp(0) with time zone NOT NULL DEFAULT NOW(),
name TEXT NOT NULL,
url TEXT UNIQUE NOT NULL,
version INT NOT NULL DEFAULT 1,
user_id bigserial NOT NULL REFERENCES users(id) ON DELETE CASCADE
);
If I run the following directly in psql or even pgAdmin i get All records:
SELECT count(*) OVER(), id, created_at, updated_at, name, url, user_id, version
FROM feeds
WHERE (to_tsvector('simple', name) @@ plainto_tsquery('simple','' ) OR ''= '')
AND (url LIKE '%' || '' || '%' OR '' = '')
ORDER BY id ASC
LIMIT 30 OFFSET 0;
Now my question is, is there anything I may be missing since am getting empty results back using my own Golang code?. Just to add, I have my own functions that read the queries from the URL, so am sure on what is read. The offset and limit defaults to 0 and 30 if none is provided so the API returns all records.
Thank you in Advance.
As per the comments your where
clause includes:
AND ($2 = '' OR url LIKE '%' || $2 || '%')
$2
is GetAllFeedsParams.Column2
in the go code and, if url
is an empty string (which it is in the example), you set GetAllFeedsParams.Column2.Valid
to false
. This means that the parameter is null
. The upshot of this is that the where
clause is effectively:
AND (null = '' OR url LIKE '%' || null || '%')
This can be simplified to:
AND (null OR null)
The final result being null
(which is not true
so the row is rejected).