-
Notifications
You must be signed in to change notification settings - Fork 885
Type annotations for query parameters #2800
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
In the named parameter example, I would expect the syntax to be
so that it's consistent with the |
I don't like the repetition of the |
Love this. Been type casting params for awhile now, but this is a much cleaner solution imo. 👍 Does this mean we no longer would need |
@Emyrk I just update the proposal with a slightly different syntax, which allows for specifying type information without change the nullability of a parameter. |
Yes, we just added a bit more clarity about that to the proposal. |
A first step towards implementing #2800
@kyleconroy @andrewmbenton Would it be okay to use generated model structs in place of query params? By having a syntax like this:
or any syntax that hints using model struct as params. I was able to achieve that by applyning new config option called
version: "2"
sql:
- engine: "postgresql"
queries: "./db/queries"
schema: "./db/migrations"
gen:
go:
package: "store"
sql_package: "pgx/v5"
out: "./internal/store"
params_struct_overrides:
- method_name: CreateProduct
model_name: Product
type Product struct {
ID int64 `json:"id"`
StoreID int32 `json:"store_id"`
CategoryID int32 `json:"category_id"`
Name string `json:"name"`
Brand *string `json:"brand"`
Slug string `json:"slug"`
ImageLinks []byte `json:"image_links"`
Specs []byte `json:"specs"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
}
const createProduct = `-- name: CreateProduct :one
INSERT INTO products
(store_id, category_id, name, brand, slug, image_links, specs)
VALUES
($1, $2, $3, $4, $5, $6, $7)
RETURNING id
`
func (q *Queries) CreateProduct(ctx context.Context, p Product) (int64, error) {
row := q.db.QueryRow(ctx, createProduct,
p.StoreID,
p.CategoryID,
p.Name,
p.Brand,
p.Slug,
p.ImageLinks,
p.Specs,
)
var id int64
err := row.Scan(&id)
return id, err
} However, enabling such override by type annotations would be much preferable though. |
I also have wanted this feature, but there are potentially better ways to solve this (eg My fear of overrides is you lose some of the power of sqlc, which is making sure the models always match the query. If custom models are supported, is there anyway to add some "linting" or something that would warn the user when a new column is added and their custom model does not have it? The query has all selected columns, so that would be possible. Just food for thought that custom structs might want some additional support to keep them "in line" with the sql. |
👍 again for this. Would be really helpful alongside type overrides for some edge case stuff. Currently trying to get tuples to work as parameters |
Uh oh!
There was an error while loading. Please reload this page.
I propose adding type annotations for query parameters. Users will no longer need to cast parameters to the desired type. This proposal builds on Andrew's query annotation
work for
vet
.Unified syntax
We added the
@sqlc-vet-disable
annotation to disable vet rules on a per-querybasis. We can extend this syntax to support other per-query configuration
options.
The current syntax for query name and command are different, so we'll
standardize on the
@
prefix. This will be the new, preferred syntax for nameand command.
The existing syntax will continue to work, but it will be an error to use both
annotations on a single query.
Query command
Today, queries must have a name and a command. With the new syntax, the
command option will default to
exec
.Validation
sqlc will delegate command validation to codegen plugins, allowing plugins to implement new commands without having
to merge anything into sqlc.
If you want to still validate those, you can simulate the current behavior by
using this vet rule.
Type annotations for query parameters
The
@param
annotation supports passing type information without having to usea cast.
-- @param name type
Casts are required today when sqlc infers an incorrect type, but these
casts are passed down to the engine itself, possibly hurting performance.
For example, this cast is required to get sqlc working correctly, but isn't needed at runtime.
Here's what it looks like with the new syntax. The type annotation is
engine-specific and is the same that you'd pass to CAST or CREATE TABLE.
If a parameter has a type annotation, that will be used instead of inferring the
type from the query.
NULL values
sqlc will infer the nullability of parameters by default. You can force a parameter to be nullable using the
?
operator, or not null using the!
operator.Positional parameters
If your parameters do not have a given name, you can refer to them by number to add a type annotation and nullability.
For PostgreSQL:
And for MySQL or SQLite:
sqlc.arg / sqlc.narg
Using the proposed annotation syntax allows you to replace
sqlc.arg()
andsqlc.narg()
.For example this query with
sqlc.arg()
andsqlc.narg()
is equivalent to this one without
sqlc.arg
andsqlc.narg
will continue to work, but will likely be deprecated in favor of the@foo
syntax.You can use
sqlc.arg()
with the new@param
annotation syntax (to avoid explicit casts), but notsqlc.narg()
. This constraintis intended to eliminate confusion about precedence of nullability directives.
So for example this will work
but this won't
To make this work, switch
sqlc.narg
tosqlc.arg
and add a?
to the param annotation.Why comments?
We're using comments instead of
sqlc.*
functions to avoid engine-specific parsing issues. For example, we've run into issues with the MySQL parser not support functions in certain parameter locations.Full example
This is the normal example from the playground using the new syntax.
Future
The plan is to use similar annotations to support type annotations for output columns and values, Go type overrides for parameters and outputs, and JSON unmarshal / marshal hints.
The text was updated successfully, but these errors were encountered: