@@ -58,4 +58,136 @@ type ScoreAndTestsRow struct {
5858 Student Student
5959 TestScore TestScore
6060}
61- ```
61+ ```
62+
63+ #### Nested JSON objects and arrays
64+
65+ ` sqlc.jsonb_build_object."Name"(key, value, key, value, ...) ` builds a named
66+ Go struct from an inline JSON shape — a typed wrapper around Postgres's
67+ ` jsonb_build_object ` , so keys must be string literals. This is most useful
68+ for pulling a one-to-many relationship into a single query as a slice
69+ field, instead of running a separate query per parent row. It's ** pgx/v5
70+ only** : ` sqlc generate ` fails with a clear error for any other
71+ ` sql_package ` .
72+
73+ ` "Name" ` is required and must be a double-quoted identifier in that
74+ position, not an argument — Postgres parses this as a 3-part qualified
75+ function name (` catalog.schema.name ` ), and sqlc reads the struct name
76+ directly off of it.
77+
78+ ``` sql
79+ CREATE TABLE authors (
80+ id bigserial PRIMARY KEY ,
81+ name text NOT NULL
82+ );
83+
84+ CREATE TABLE books (
85+ id bigserial PRIMARY KEY ,
86+ author_id bigint NOT NULL REFERENCES authors (id),
87+ title text NOT NULL
88+ );
89+ ```
90+
91+ ``` sql
92+ -- name: GetAuthors :many
93+ SELECT
94+ sqlc .embed (authors),
95+ ARRAY(
96+ SELECT sqlc .jsonb_build_object ." Book" (' id' , books .id , ' title' , books .title )
97+ FROM books
98+ WHERE books .author_id = authors .id
99+ ) AS books
100+ FROM authors;
101+ ```
102+
103+ ``` go
104+ type GetAuthorsRow struct {
105+ Author Author
106+ Books []Book
107+ }
108+
109+ type Book struct {
110+ ID int64 ` json:"id"`
111+ Title string ` json:"title"`
112+ }
113+ ```
114+
115+ No custom ` Scan ` /` Value ` methods, no wrapper type — ` Books ` is a plain
116+ ` []Book ` ; pgx v5 decodes the ` jsonb[] ` column into it directly. A lone
117+ ` sqlc.jsonb_build_object."Name"(...) ` (not wrapped in ` ARRAY(...) ` ) works
118+ the same way and produces a plain struct field instead of a slice:
119+
120+ ``` sql
121+ -- name: GetAuthorSummary :one
122+ SELECT sqlc .jsonb_build_object ." AuthorSummary" (' name' , name) AS summary FROM authors LIMIT 1 ;
123+ ```
124+
125+ ``` go
126+ type GetAuthorSummaryRow struct {
127+ Summary AuthorSummary
128+ }
129+ ```
130+
131+ Two queries that use the same explicit name reuse the same Go type, as long
132+ as their shapes match (this works even mixing scalar and ` ARRAY(...) ` uses
133+ of the same name). A shape mismatch, or a name that collides with an
134+ existing model/enum type, fails generation with an error instead of
135+ emitting Go code that won't compile.
136+
137+ ##### Overriding generated names
138+
139+ The struct name and individual field names can be overridden via the
140+ ` rename ` option:
141+
142+ ``` json
143+ {
144+ "rename" : {
145+ "Book" : " BookSummary" ,
146+ "Book.id" : " BookID"
147+ }
148+ }
149+ ```
150+
151+ ` "Book" ` renames the type; ` "Book.id" ` renames just the ` id ` field within
152+ it, without affecting other types that also have an ` id ` key. Use the plain
153+ key (` "id" ` ) instead to rename that field everywhere.
154+
155+ ##### Embedding a whole row as JSON
156+
157+ Listing every column by hand is tedious when you just want the whole row.
158+ ` sqlc.embed.jsonb(table) ` builds a JSON object from all of a table's columns,
159+ the same way ` sqlc.embed(table) ` gives you the table's model — but as a
160+ single JSON value, so it can be nested inside ` ARRAY(...) ` to return a slice
161+ of rows from one query:
162+
163+ ``` sql
164+ -- name: GetAuthorsWithBooks :many
165+ SELECT
166+ authors .id ,
167+ ARRAY(SELECT sqlc .embed .jsonb(books) FROM books WHERE books .author_id = authors .id ) AS books
168+ FROM authors;
169+ ```
170+
171+ ``` go
172+ type GetAuthorsWithBooksRow struct {
173+ ID int64 ` json:"id"`
174+ Books []Book ` json:"books"`
175+ }
176+
177+ type Book struct {
178+ ID int64 ` json:"id"`
179+ AuthorID int64 ` json:"author_id"`
180+ Title string ` json:"title"`
181+ }
182+ ```
183+
184+ The generated struct is named from the result alias — singularized for the
185+ ` ARRAY(...) ` case (` AS books ` → ` Book ` ), or used as-is for a scalar
186+ ` sqlc.embed.jsonb(table) AS author ` (→ ` Author ` ). Fields, types and JSON keys
187+ come from the table's columns, so the object always decodes cleanly. Under
188+ the hood the call is rewritten to ` to_jsonb(table) ` , which you'll see in
189+ ` EXPLAIN ` output and logs.
190+
191+ Like ` sqlc.jsonb_build_object ` , this is pgx/v5 only, and the generated name
192+ must not collide with a model or another JSON type; use the ` rename ` option
193+ if it does.
0 commit comments