Я пытаюсь реализовать нумерацию страниц в своем внутреннем API GO. API использует SQLC для абстракции к моей базе данных PostgreSQL. Проблема в том, что он возвращает пустые записи, и я не могу понять, что делаю не так. Ниже приведены соответствующие коды, относящиеся к моей текущей работе:
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
}
Пример вывода:
Executing GetAllFeeds with name: [], url: [], limit: 30, offset: 0 Rows: [] Total Records: 0
Исходная схема:
-- +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
);
Если я запустил следующее непосредственно в psql или даже pgAdmin, я получу все записи:
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;
Теперь мой вопрос: есть ли что-то, что мне может не хватать, поскольку я получаю пустые результаты, используя свой собственный код Golang? Добавлю: у меня есть собственные функции, которые считывают запросы из URL-адреса, поэтому я уверен в том, что именно читается. Смещение и предел по умолчанию равны 0 и 30, если они не указаны, поэтому API возвращает все записи.
Заранее спасибо.
@Brits Спасибо, сэр! Наверное, слишком устал, чтобы увидеть такую тривиальную ошибку. Не могли бы вы опубликовать, чтобы я установил это как ответ?
Судя по комментариям, ваш пункт where
включает в себя:
AND ($2 = '' OR url LIKE '%' || $2 || '%')
$2
— это GetAllFeedsParams.Column2
в коде go, и, если url
— пустая строка (как в примере), вы устанавливаете GetAllFeedsParams.Column2.Valid
в false
. Это означает, что параметр равен null
. В результате предложение where
фактически:
AND (null = '' OR url LIKE '%' || null || '%')
Это можно упростить до:
AND (null OR null)
Конечным результатом будет null
(это не true
, поэтому строка отклоняется).
Я полагаю, что вы устанавливаете
GetAllFeedsParams.Column2
наnull
(посколькуurl
— пустая строка, то естьurl != ""
— этоfalse
, поэтомуsql.NullString.Vaild
— этоfalse
). Это означает, что ваше предложениеwhere
фактически содержитnull = '' or url like '%' || null || '%'
(которое можно упростить доnull or null
, то естьnull
, то есть неtrue
).