sqlc-dev / sqlc

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

Overridden type works for ARRAY of objects but not for a single object #3534

Open kayshav opened 1 month ago

kayshav commented 1 month ago

Version

1.27.0

What happened?

Have a simple ddl for an object in postgres. It uses a TYPE both as an ARRAY and also as a simple object. The sqlc.yaml has an override to map the TYPE (see sqlc.yaml). In the generated code, the ARRAY is mapped correctly to the overridden type but the simple object is mapped to sql.NullString.

Relevant log output

In the generated code, we see:

type FleetmanagerSchemaTag struct {
        CreateDate pgtype.Timestamp
        ID         int64
        Name       string
        Owner      sql.NullString
        Devices    []common.ObjRef
}
Notice that the Devices element is mapped to []ObjRef correctly but the Owner element is mapped to NullString. And both are of type ObjRef

Database schema

ddls.sql
-- Create schema for fleet manager. 
CREATE SCHEMA fleetmanager_schema;

-- Add schema to search path
SET search_path TO fleetmanager_schema, public;

-- Using a domain to ensure that the obj_id and obj_type that are declared in a type are not null
CREATE DOMAIN nonnull_string VARCHAR(255) NOT NULL;
CREATE DOMAIN nonull_int8 int8 NOT NULL;

CREATE TYPE fleetmanager_schema.obj_ref AS  (
    obj_id nonnull_int8,
    obj_type nonnull_string
);

And the Go struct definition is:
type ObjRef struct {

        ObjId string `json:"obj_id" range:"min=8,max=32"`

        ObjType string `json:"obj_type" range:"min=3,max=32"`
}
-----

CREATE TABLE fleetmanager_schema.tag (
   create_date TIMESTAMP DEFAULT NOW() NOT NULL,
   id int8 NOT NULL,
    PRIMARY KEY (id),

   name VARCHAR(255) NOT NULL,
   owner fleetmanager_schema.obj_ref,
   devices fleetmanager_schema.obj_ref ARRAY
);

SQL queries

-----------------queries.sql
-- name: InsertTag :one
INSERT INTO fleetmanager_schema.tag (
    create_date,  name, name,  owner, devices
) VALUES (
             $1, $2, $3, $4, $5
         ) RETURNING *;

-- name: GetTag :one
SELECT *
FROM fleetmanager_schema.tag
WHERE id = $1;

Configuration

------sqlc.yaml
version: "2"
sql:
  - engine: "postgresql"
    queries: "./queries.sql"
    schema: "./ddls.sql"
    gen:
      go:
        package: "db"
        out: "./generated"
        sql_package: "pgx/v5"
        overrides:
          - go_type:
              import: "fleet-api-server/generated/common"
              type: "ObjRef"
            db_type: "fleetmanager_schema.obj_ref"
            null: false

Playground URL

No response

What operating system are you using?

Linux

What database engines are you using?

PostgreSQL

What type of code are you generating?

Go

kayshav commented 1 month ago

On further testing, if I add the NOT NULL attribute to the Owner element, then the generated code is correct `CREATE TABLE fleetmanager_schema.tag ( create_date TIMESTAMP DEFAULT NOW() NOT NULL, id int8 NOT NULL, PRIMARY KEY (id),

name VARCHAR(255) NOT NULL, owner fleetmanager_schema.obj_ref NOT NULL, -- This NOT NULL leads to proper code generation devices fleetmanager_schema.obj_ref ARRAY );

type FleetmanagerSchemaTag struct { CreateDate pgtype.Timestamp ID int64 Name string Owner common,ObjRef Devices []common.ObjRef }`

higordasneves commented 2 days ago

@kayshav I think this behavior is expected, considering that although the nonnull_int8 and nonnull_string types of obj_ref are not null, there is still a possibility that the value of obj_ref is null, for example:

insert into tag(create_date, id, name, owner, devices)
values (now(), 1, 'name', null, null);

The query will not fail, so it is possible to have records with the owner field as null. As the documentation states, if the null parameter in the overrides configuration is set to false, nullable fields will not be overridden.