Сделайте запрос к "id" или "slug" с одной переменной - PullRequest
0 голосов
/ 22 апреля 2020

У меня есть таблица «статей», где есть «id» и «slug» среди прочего. На странице html у меня есть список ссылок на статьи. Ссылка может содержать либо «id», либо «slug».

Но если в URL-адресе есть только число, это еще не значит, что это идентификатор - поэтому приведение к int для определения, будет ли это слаг или идентификатор, не будет работать .

  /articles/my_article
  /articles/35 
  /articles/666 --> still may be slug

У меня есть sql запрос:

import (
  "github.com/jackc/pgx/v4"
  //.........
)


// [..........]


vars := mux.Vars(req)
q1 := `
  SELECT
    ar.id,
    [.........]
  FROM
    articles AS ar
  WHERE ar.slug = $1 OR ar.id = $1`

ar := Article{}
row := db.QueryRow(context.Background(), q1, vars["id_or_slug"])
switch err := row.Scan(&ar.Id, /*[.......]*/); err {
case pgx.ErrNoRows:
  wrt.WriteHeader(http.StatusNotFound)
  wrt.Write([]byte("article not found"))
case nil:
  // good, article found

Я получаю:

ERROR: operator does not exist: bigint = text (SQLSTATE 42883)

1 Ответ

0 голосов
/ 23 апреля 2020

Вы можете "попытаться" преобразовать значение в целое число, и если преобразование не удастся, просто проигнорируйте ошибку и предоставьте значение идентификатора, известное , которое не присутствует в БД.

Выполнение преобразования с помощью Go:

slug := mux.Vars(req)["id_or_slug"]

// option 1:
id, err := strconv.ParseInt(slug, 10, 64)
if err != nil {
    id = -1 // provide a value that you're certain will not be present in the db
}

// option 2:
// if id 0 is good enough, you can skip error checking
// and use the following instead of the above.
id, _ := strconv.ParseInt(slug, 10, 64)

query := `SELECT ... FROM articles AS a
WHERE a.slug = $1
OR a.id = $2`

row := db.QueryRow(query, slug, id)

Выполнение преобразования с помощью postgres: (следующий фрагмент postgres взят из здесь .)

-- first create a postgres function that will do the conversion / cast
create or replace function cast_to_int(text, integer) returns integer as $$
begin
    return cast($1 as integer);
exception
    when invalid_text_representation then
        return $2;
end;
$$ language plpgsql immutable;

... и затем использовать это в go:

slug := mux.Vars(req)["id_or_slug"]

query := `SELECT ... FROM articles AS a
WHERE a.slug = $1
OR a.id = cast_to_int($1::text, -1)` // use the postgres function in the go query string

row := db.QueryRow(query, slug)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...