Skip to content
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

docs: add documentation and examples for sqlc.narg #1579

Closed
wants to merge 11 commits into from
31 changes: 31 additions & 0 deletions docs/howto/named_parameters.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,34 @@ SET
END
RETURNING *;
```

## Nullable parameters

sqlc infers the nullability of any specified parameters, and often does exactly
what you want. If you want finer control over the nullability of your
parameters, you may use `sql.narg()` (**n**ullable arg) to override the default
behavior. Using `sql.narg` tells sqlc to ignore whatever nullability it has
inferred and generate a nullable parameter instead. There is no nullable
equivalent of the `@` syntax.

Here is an example that uses a single query to allow updating an author's
name, bio or both.

```sql
-- name: UpdateAuthor :one
UPDATE author
SET
name = coalesce(sqlc.narg('name'), name),
bio = coalesce(sqlc.narg('bio'), bio)
WHERE id = sqlc.arg('id');
```

The following code is generated:

```go
type UpdateAuthorParams struct {
Name sql.NullString
Bio sql.NullString
ID int64
}
```
9 changes: 8 additions & 1 deletion examples/authors/mysql/query.sql
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,16 @@ ORDER BY name;
INSERT INTO authors (
name, bio
) VALUES (
?, ?
?, ?
);

/* name: DeleteAuthor :exec */
DELETE FROM authors
WHERE id = ?;

/* name: UpdateAuthor :exec */
UPDATE authors
SET
name = coalesce(sqlc.narg('name'), name),
bio = coalesce(sqlc.narg('bio'), bio)
WHERE id = sqlc.arg('id');
21 changes: 20 additions & 1 deletion examples/authors/mysql/query.sql.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions examples/authors/postgresql/query.sql
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,10 @@ RETURNING *;
-- name: DeleteAuthor :exec
DELETE FROM authors
WHERE id = $1;

-- name: UpdateAuthor :exec
UPDATE authors
SET
name = coalesce(sqlc.narg('name'), name),
bio = coalesce(sqlc.narg('bio'), bio)
WHERE id = sqlc.arg('id');
19 changes: 19 additions & 0 deletions examples/authors/postgresql/query.sql.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,11 @@ interface Queries {
@Throws(SQLException::class)
fun listAuthors(): List<Author>

@Throws(SQLException::class)
fun updateAuthor(
name: String?,
bio: String?,
id: Long)

}

Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const val createAuthor = """-- name: createAuthor :execresult
INSERT INTO authors (
name, bio
) VALUES (
?, ?
?, ?
)
"""

Expand All @@ -31,6 +31,14 @@ SELECT id, name, bio FROM authors
ORDER BY name
"""

const val updateAuthor = """-- name: updateAuthor :exec
UPDATE authors
SET
name = coalesce(?, name),
bio = coalesce(?, bio)
WHERE id = ?
"""

class QueriesImpl(private val conn: Connection) : Queries {

@Throws(SQLException::class)
Expand Down Expand Up @@ -96,5 +104,19 @@ class QueriesImpl(private val conn: Connection) : Queries {
}
}

@Throws(SQLException::class)
override fun updateAuthor(
name: String?,
bio: String?,
id: Long) {
conn.prepareStatement(updateAuthor).use { stmt ->
stmt.setString(1, name)
stmt.setString(2, bio)
stmt.setLong(3, id)

stmt.execute()
}
}

}

Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,11 @@ interface Queries {
@Throws(SQLException::class)
fun listAuthors(): List<Author>

@Throws(SQLException::class)
fun updateAuthor(
name: String?,
bio: String?,
id: Long)

}

Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,14 @@ SELECT id, name, bio FROM authors
ORDER BY name
"""

const val updateAuthor = """-- name: updateAuthor :exec
UPDATE authors
SET
name = coalesce(?, name),
bio = coalesce(?, bio)
WHERE id = ?
"""

class QueriesImpl(private val conn: Connection) : Queries {

@Throws(SQLException::class)
Expand Down Expand Up @@ -103,5 +111,19 @@ class QueriesImpl(private val conn: Connection) : Queries {
}
}

@Throws(SQLException::class)
override fun updateAuthor(
name: String?,
bio: String?,
id: Long) {
conn.prepareStatement(updateAuthor).use { stmt ->
stmt.setString(1, name)
stmt.setString(2, bio)
stmt.setLong(3, id)

stmt.execute()
}
}

}

Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ interface Queries {
fun updateBookISBN(
title: String,
tags: List<String>,
isbn: String,
bookId: Int)
bookId: Int,
isbn: String)

}

Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ class QueriesImpl(private val conn: Connection) : Queries {
results.getString(2),
results.getString(3),
results.getString(4),
(results.getArray(5).array as Array<String>).toList()
(results.getArray(5).array as? Array<*>)?.filterIsInstance<String>()!!.toList()
))
}
ret
Expand All @@ -127,7 +127,7 @@ class QueriesImpl(private val conn: Connection) : Queries {
results.getString(5),
results.getInt(6),
results.getObject(7, OffsetDateTime::class.java),
(results.getArray(8).array as Array<String>).toList()
(results.getArray(8).array as? Array<*>)?.filterIsInstance<String>()!!.toList()
))
}
ret
Expand Down Expand Up @@ -184,7 +184,7 @@ class QueriesImpl(private val conn: Connection) : Queries {
results.getString(5),
results.getInt(6),
results.getObject(7, OffsetDateTime::class.java),
(results.getArray(8).array as Array<String>).toList()
(results.getArray(8).array as? Array<*>)?.filterIsInstance<String>()!!.toList()
)
if (results.next()) {
throw SQLException("expected one row in result set, but got many")
Expand Down Expand Up @@ -239,7 +239,7 @@ class QueriesImpl(private val conn: Connection) : Queries {
results.getString(5),
results.getInt(6),
results.getObject(7, OffsetDateTime::class.java),
(results.getArray(8).array as Array<String>).toList()
(results.getArray(8).array as? Array<*>)?.filterIsInstance<String>()!!.toList()
)
if (results.next()) {
throw SQLException("expected one row in result set, but got many")
Expand All @@ -266,13 +266,13 @@ class QueriesImpl(private val conn: Connection) : Queries {
override fun updateBookISBN(
title: String,
tags: List<String>,
isbn: String,
bookId: Int) {
bookId: Int,
isbn: String) {
conn.prepareStatement(updateBookISBN).use { stmt ->
stmt.setString(1, title)
stmt.setArray(2, conn.createArrayOf("pg_catalog.varchar", tags.toTypedArray()))
stmt.setString(3, isbn)
stmt.setInt(4, bookId)
stmt.setInt(3, bookId)
stmt.setString(4, isbn)

stmt.execute()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,10 @@ interface Queries {
fun listVenues(city: String): List<Venue>

@Throws(SQLException::class)
fun updateCityName(name: String, slug: String)
fun updateCityName(slug: String, name: String)

@Throws(SQLException::class)
fun updateVenueName(name: String, slug: String): Int?
fun updateVenueName(slug: String, name: String): Int?

@Throws(SQLException::class)
fun venueCountByCity(): List<VenueCountByCityRow>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,6 @@ class QueriesImpl(private val conn: Connection) : Queries {
override fun deleteVenue(slug: String) {
conn.prepareStatement(deleteVenue).use { stmt ->
stmt.setString(1, slug)
stmt.setString(2, slug)

stmt.execute()
}
Expand Down Expand Up @@ -199,13 +198,13 @@ class QueriesImpl(private val conn: Connection) : Queries {
val ret = Venue(
results.getInt(1),
Status.lookup(results.getString(2))!!,
(results.getArray(3).array as Array<String>).map { v -> Status.lookup(v)!! }.toList(),
(results.getArray(3).array as? Array<*>)?.filterIsInstance<String>()!!.map { v -> Status.lookup(v)!! }.toList(),
results.getString(4),
results.getString(5),
results.getString(6),
results.getString(7),
results.getString(8),
(results.getArray(9).array as Array<String>).toList(),
(results.getArray(9).array as? Array<*>)?.filterIsInstance<String>()!!.toList(),
results.getObject(10, LocalDateTime::class.java)
)
if (results.next()) {
Expand Down Expand Up @@ -242,13 +241,13 @@ class QueriesImpl(private val conn: Connection) : Queries {
ret.add(Venue(
results.getInt(1),
Status.lookup(results.getString(2))!!,
(results.getArray(3).array as Array<String>).map { v -> Status.lookup(v)!! }.toList(),
(results.getArray(3).array as? Array<*>)?.filterIsInstance<String>()!!.map { v -> Status.lookup(v)!! }.toList(),
results.getString(4),
results.getString(5),
results.getString(6),
results.getString(7),
results.getString(8),
(results.getArray(9).array as Array<String>).toList(),
(results.getArray(9).array as? Array<*>)?.filterIsInstance<String>()!!.toList(),
results.getObject(10, LocalDateTime::class.java)
))
}
Expand All @@ -257,20 +256,20 @@ class QueriesImpl(private val conn: Connection) : Queries {
}

@Throws(SQLException::class)
override fun updateCityName(name: String, slug: String) {
override fun updateCityName(slug: String, name: String) {
conn.prepareStatement(updateCityName).use { stmt ->
stmt.setString(1, name)
stmt.setString(2, slug)
stmt.setString(1, slug)
stmt.setString(2, name)

stmt.execute()
}
}

@Throws(SQLException::class)
override fun updateVenueName(name: String, slug: String): Int? {
override fun updateVenueName(slug: String, name: String): Int? {
return conn.prepareStatement(updateVenueName).use { stmt ->
stmt.setString(1, name)
stmt.setString(2, slug)
stmt.setString(1, slug)
stmt.setString(2, name)

val results = stmt.executeQuery()
if (!results.next()) {
Expand Down
15 changes: 15 additions & 0 deletions examples/python/src/authors/query.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,15 @@
"""


UPDATE_AUTHOR = """-- name: update_author \\:exec
UPDATE authors
SET
name = coalesce(:p1, name),
bio = coalesce(:p2, bio)
WHERE id = :p3
"""


class Querier:
def __init__(self, conn: sqlalchemy.engine.Connection):
self._conn = conn
Expand Down Expand Up @@ -74,6 +83,9 @@ def list_authors(self) -> Iterator[models.Author]:
bio=row[2],
)

def update_author(self, *, name: Optional[str], bio: Optional[str], id: int) -> None:
self._conn.execute(sqlalchemy.text(UPDATE_AUTHOR), {"p1": name, "p2": bio, "p3": id})


class AsyncQuerier:
def __init__(self, conn: sqlalchemy.ext.asyncio.AsyncConnection):
Expand Down Expand Up @@ -110,3 +122,6 @@ async def list_authors(self) -> AsyncIterator[models.Author]:
name=row[1],
bio=row[2],
)

async def update_author(self, *, name: Optional[str], bio: Optional[str], id: int) -> None:
await self._conn.execute(sqlalchemy.text(UPDATE_AUTHOR), {"p1": name, "p2": bio, "p3": id})
Loading