Skip to content

Commit 1b847a3

Browse files
committed
Improve support for functions
- add IsArray field for function parameters - support struct creation for table returns from funcs
1 parent 25dcd15 commit 1b847a3

File tree

28 files changed

+1530
-204
lines changed

28 files changed

+1530
-204
lines changed

examples/booktest/postgresql/db_test.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ package booktest
55

66
import (
77
"context"
8+
"database/sql"
9+
"reflect"
810
"testing"
911
"time"
1012

@@ -14,6 +16,11 @@ import (
1416
func TestBooks(t *testing.T) {
1517
db, cleanup := sqltest.PostgreSQL(t, []string{"schema.sql"})
1618
defer cleanup()
19+
defer func() {
20+
if _, err := db.Exec("DROP SCHEMA IF EXISTS sqlc_book_schema CASCADE"); err != nil {
21+
t.Fatal(err)
22+
}
23+
}()
1724

1825
ctx := context.Background()
1926
dq := New(db)
@@ -24,6 +31,16 @@ func TestBooks(t *testing.T) {
2431
t.Fatal(err)
2532
}
2633

34+
// for https://github.com/kyleconroy/sqlc/issues/1322
35+
bIdRaw, err := dq.CreateAuthorViaFunc(ctx, "Known Master")
36+
if err != nil {
37+
t.Fatal(err)
38+
}
39+
bIdRawType := reflect.TypeOf(bIdRaw)
40+
if bIdRawType.String() != reflect.TypeOf(sql.NullInt32{}).String() {
41+
t.Fatalf("unexpected type: want sql.NullInt32, got %s", bIdRawType)
42+
}
43+
2744
// create transaction
2845
tx, err := db.Begin()
2946
if err != nil {
@@ -143,6 +160,19 @@ func TestBooks(t *testing.T) {
143160
t.Logf("Book %d: '%s', Author: '%s', ISBN: '%s' Tags: '%v'\n", ab.BookID, ab.Title, ab.Name.String, ab.Isbn, ab.Tags)
144161
}
145162

163+
booksByTagsViaFunc, err := dq.BooksByTagsViaFunc(ctx, []string{"cool", "other", "someother"})
164+
if err != nil {
165+
t.Fatal(err)
166+
}
167+
if len(booksByTagsViaFunc) != len(res) {
168+
t.Fatalf("got unequal number of books. wanted %d, got %d", len(res), len(booksByTagsViaFunc))
169+
}
170+
for i, bookByTag := range res {
171+
if booksByTagsViaFunc[i].Isbn.String != bookByTag.Isbn {
172+
t.Fatalf("unexpected book: wanted (%+v), got (%+v)", res, bookByTag)
173+
}
174+
}
175+
146176
// TODO: call say_hello(varchar)
147177

148178
// get book 4 and delete

examples/booktest/postgresql/models.go

Lines changed: 13 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

examples/booktest/postgresql/query.sql

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,14 @@ SELECT
2323
tags
2424
FROM books
2525
LEFT JOIN authors ON books.author_id = authors.author_id
26-
WHERE tags && $1::varchar[];
26+
WHERE tags && $1::varchar[]
27+
ORDER BY name, title ASC;
28+
29+
-- name: BooksByTagsViaFunc :many
30+
SELECT * FROM sqlc_book_schema.books_by_tags_func($1::VARCHAR[]);
31+
32+
-- name: CreateAuthorViaFunc :one
33+
SELECT * FROM create_author_func($1);
2734

2835
-- name: CreateAuthor :one
2936
INSERT INTO authors (name) VALUES ($1)

examples/booktest/postgresql/query.sql.go

Lines changed: 45 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

examples/booktest/postgresql/schema.sql

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,34 @@ END;
3030
$$ LANGUAGE plpgsql;
3131

3232
CREATE INDEX books_title_lower_idx ON books(title);
33+
34+
-- to test query return type / schema interaction
35+
CREATE SCHEMA sqlc_book_schema;
36+
37+
CREATE OR REPLACE FUNCTION sqlc_book_schema.books_by_tags_func(_tags VARCHAR[])
38+
RETURNS TABLE(book_id INT, title TEXT, name TEXT, isbn TEXT, tags VARCHAR[]) AS $$
39+
BEGIN
40+
RETURN QUERY
41+
SELECT
42+
b.book_id,
43+
b.title,
44+
a.name,
45+
b.isbn,
46+
b.tags
47+
FROM books b
48+
LEFT JOIN authors a ON b.author_id = a.author_id
49+
WHERE b.tags && _tags
50+
ORDER BY name, title ASC
51+
;
52+
END;
53+
$$ LANGUAGE plpgsql;
54+
55+
CREATE OR REPLACE FUNCTION create_author_func(_name TEXT)
56+
RETURNS TABLE(id INTEGER) AS $$
57+
BEGIN
58+
INSERT INTO authors(name)
59+
VALUES (_name)
60+
RETURNING author_id into id;
61+
RETURN NEXT;
62+
END;
63+
$$ LANGUAGE plpgsql;

examples/kotlin/src/main/kotlin/com/example/booktest/postgresql/Models.kt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,15 @@ data class Book (
3232
val tags: List<String>
3333
)
3434

35+
data class CreateAuthorFunc (
36+
val id: Int?
37+
)
38+
39+
data class SqlcBookSchemaBooksByTagsFunc (
40+
val bookId: Int?,
41+
val title: String?,
42+
val name: String?,
43+
val isbn: String?,
44+
val tags: String?
45+
)
46+

examples/kotlin/src/main/kotlin/com/example/booktest/postgresql/Queries.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,18 @@ interface Queries {
1414
@Throws(SQLException::class)
1515
fun booksByTags(dollar1: List<String>): List<BooksByTagsRow>
1616

17+
@Throws(SQLException::class)
18+
fun booksByTagsViaFunc(dollar1: List<String>): List<SqlcBookSchemaBooksByTagsFunc>
19+
1720
@Throws(SQLException::class)
1821
fun booksByTitleYear(title: String, year: Int): List<Book>
1922

2023
@Throws(SQLException::class)
2124
fun createAuthor(name: String): Author?
2225

26+
@Throws(SQLException::class)
27+
fun createAuthorViaFunc(name: String): Int??
28+
2329
@Throws(SQLException::class)
2430
fun createBook(
2531
authorId: Int,

examples/kotlin/src/main/kotlin/com/example/booktest/postgresql/QueriesImpl.kt

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ SELECT
2020
FROM books
2121
LEFT JOIN authors ON books.author_id = authors.author_id
2222
WHERE tags && ?::varchar[]
23+
ORDER BY name, title ASC
2324
"""
2425

2526
data class BooksByTagsRow (
@@ -30,6 +31,10 @@ data class BooksByTagsRow (
3031
val tags: List<String>
3132
)
3233

34+
const val booksByTagsViaFunc = """-- name: booksByTagsViaFunc :many
35+
SELECT book_id, title, name, isbn, tags FROM sqlc_book_schema.books_by_tags_func(?::VARCHAR[])
36+
"""
37+
3338
const val booksByTitleYear = """-- name: booksByTitleYear :many
3439
SELECT book_id, author_id, isbn, book_type, title, year, available, tags FROM books
3540
WHERE title = ? AND year = ?
@@ -40,6 +45,10 @@ INSERT INTO authors (name) VALUES (?)
4045
RETURNING author_id, name
4146
"""
4247

48+
const val createAuthorViaFunc = """-- name: createAuthorViaFunc :one
49+
SELECT id FROM create_author_func(?)
50+
"""
51+
4352
const val createBook = """-- name: createBook :one
4453
INSERT INTO books (
4554
author_id,
@@ -110,6 +119,26 @@ class QueriesImpl(private val conn: Connection) : Queries {
110119
}
111120
}
112121

122+
@Throws(SQLException::class)
123+
override fun booksByTagsViaFunc(dollar1: List<String>): List<SqlcBookSchemaBooksByTagsFunc> {
124+
return conn.prepareStatement(booksByTagsViaFunc).use { stmt ->
125+
stmt.setArray(1, conn.createArrayOf("pg_catalog.varchar", dollar1.toTypedArray()))
126+
127+
val results = stmt.executeQuery()
128+
val ret = mutableListOf<SqlcBookSchemaBooksByTagsFunc>()
129+
while (results.next()) {
130+
ret.add(SqlcBookSchemaBooksByTagsFunc(
131+
results.getInt(1),
132+
results.getString(2),
133+
results.getString(3),
134+
results.getString(4),
135+
results.getString(5)
136+
))
137+
}
138+
ret
139+
}
140+
}
141+
113142
@Throws(SQLException::class)
114143
override fun booksByTitleYear(title: String, year: Int): List<Book> {
115144
return conn.prepareStatement(booksByTitleYear).use { stmt ->
@@ -154,6 +183,23 @@ class QueriesImpl(private val conn: Connection) : Queries {
154183
}
155184
}
156185

186+
@Throws(SQLException::class)
187+
override fun createAuthorViaFunc(name: String): Int?? {
188+
return conn.prepareStatement(createAuthorViaFunc).use { stmt ->
189+
stmt.setString(1, name)
190+
191+
val results = stmt.executeQuery()
192+
if (!results.next()) {
193+
return null
194+
}
195+
val ret = results.getInt(1)
196+
if (results.next()) {
197+
throw SQLException("expected one row in result set, but got many")
198+
}
199+
ret
200+
}
201+
}
202+
157203
@Throws(SQLException::class)
158204
override fun createBook(
159205
authorId: Int,

examples/python/src/booktest/models.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import dataclasses
55
import datetime
66
import enum
7-
from typing import List
7+
from typing import List, Optional
88

99

1010
class BookType(str, enum.Enum):
@@ -28,3 +28,17 @@ class Book:
2828
year: int
2929
available: datetime.datetime
3030
tags: List[str]
31+
32+
33+
@dataclasses.dataclass()
34+
class CreateAuthorFunc:
35+
id: Optional[int]
36+
37+
38+
@dataclasses.dataclass()
39+
class SqlcBookSchemaBooksByTagsFunc:
40+
book_id: Optional[int]
41+
title: Optional[str]
42+
name: Optional[str]
43+
isbn: Optional[str]
44+
tags: Optional[str]

0 commit comments

Comments
 (0)