sqlc-dev / sqlc

Generate type-safe code from SQL
https://sqlc.dev
MIT License
13.51k stars 810 forks source link

Parser can't handle this query #3682

Open domino14 opened 3 weeks ago

domino14 commented 3 weeks ago

Version

1.27.0

What happened?

query.sql:57:96: edited query syntax is invalid: syntax error at or near "ext"

If I replace the @now with sqlc.arg(now) though it works. I also get errors if I replace sqlc.arg(timezone) with @timezone

Relevant log output

No response

Database schema

CREATE TABLE wordvault_cards(
    user_id BIGINT NOT NULL,
    lexicon_name TEXT NOT NULL,
    alphagram TEXT NOT NULL,
    next_scheduled TIMESTAMPTZ NOT NULL,
    fsrs_card JSONB NOT NULL DEFAULT '{}',
    review_log JSONB NOT NULL DEFAULT '[]',
    UNIQUE(user_id, lexicon_name, alphagram));

SQL queries

-- name: GetDailyProgress :one
SELECT
    -- Count of new cards studied today
    SUM(CASE
        WHEN jsonb_array_length(review_log) = 1
        THEN 1
        ELSE 0
    END) AS new_cards,

    -- Count of reviewed cards studied today
    SUM(CASE
        WHEN jsonb_array_length(review_log) > 1
        THEN 1
        ELSE 0
    END) AS reviewed_cards,

    -- Rating breakdown for new cards
    COUNT(*) FILTER (
        WHERE jsonb_array_length(review_log) = 1
              AND (review_log->0->>'Rating')::int = 1
    ) AS new_rating_1,
    COUNT(*) FILTER (
        WHERE jsonb_array_length(review_log) = 1
              AND (review_log->0->>'Rating')::int = 2
    ) AS new_rating_2,
    COUNT(*) FILTER (
        WHERE jsonb_array_length(review_log) = 1
              AND (review_log->0->>'Rating')::int = 3
    ) AS new_rating_3,
    COUNT(*) FILTER (
        WHERE jsonb_array_length(review_log) = 1
              AND (review_log->0->>'Rating')::int = 4
    ) AS new_rating_4,

    -- Rating breakdown for reviewed cards
    COUNT(*) FILTER (
        WHERE jsonb_array_length(review_log) > 1
              AND (review_log->-1->>'Rating')::int = 1
    ) AS reviewed_rating_1,
    COUNT(*) FILTER (
        WHERE jsonb_array_length(review_log) > 1
              AND (review_log->-1->>'Rating')::int = 2
    ) AS reviewed_rating_2,
    COUNT(*) FILTER (
        WHERE jsonb_array_length(review_log) > 1
              AND (review_log->-1->>'Rating')::int = 3
    ) AS reviewed_rating_3,
    COUNT(*) FILTER (
        WHERE jsonb_array_length(review_log) > 1
              AND (review_log->-1->>'Rating')::int = 4
    ) AS reviewed_rating_4
FROM
    wordvault_cards
WHERE
    user_id = @user_id
    AND ((fsrs_card->>'LastReview')::timestamp AT TIME ZONE 'UTC' AT TIME ZONE sqlc.arg(timezone)::text)::date = (@now::timestamptz AT TIME ZONE sqlc.arg(timezone)::text)::date;

Configuration

version: "2"
sql:
- schema: "db/migrations"
  queries: "db/queries"
  engine: "postgresql"
  gen:
    go:
      out: "internal/stores/models"
      sql_package: "pgx/v5"
      overrides:
      - db_type: "uuid"
        go_type: "github.com/google/uuid.UUID"
      - column: "wordvault_params.params"
        go_type:
          import: "github.com/open-spaced-repetition/go-fsrs/v3"
          type: "Parameters"
      - column: "wordvault_cards.fsrs_card"
        go_type:
          import: "github.com/domino14/word_db_server/internal/stores"
          type: "Card"
      - column: "wordvault_cards.review_log"
        go_type:
          import: "github.com/domino14/word_db_server/internal/stores"
          type: "ReviewLog"
          slice: true

Playground URL

https://play.sqlc.dev/p/4ee8022578aa223609e351bfbc131f097328ba65d923d1e397ba33cf62d189aa

What operating system are you using?

Linux

What database engines are you using?

PostgreSQL

What type of code are you generating?

Go

ptman commented 3 weeks ago

So you have a workaround? Great!

PostgreSQL also supports alternative cast syntax. Instead of @now::timestamptz you can try CAST(@now AS timestamptz)