Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions async_postgres/pg_client.nim
Original file line number Diff line number Diff line change
Expand Up @@ -861,6 +861,21 @@ proc queryOne*(
else:
return none(Row)

proc queryRow*(
conn: PgConnection,
sql: string,
params: seq[PgParam] = @[],
resultFormat: ResultFormat = rfAuto,
timeout: Duration = ZeroDuration,
): Future[Row] {.async.} =
## Execute a query and return the first row.
## Raises `PgError` if no rows are returned.
let row =
await conn.queryOne(sql, params, resultFormat = resultFormat, timeout = timeout)
if row.isNone:
raise newException(PgError, "Query returned no rows")
return row.get

proc queryValue*(
conn: PgConnection,
sql: string,
Expand Down
15 changes: 15 additions & 0 deletions async_postgres/pg_pool.nim
Original file line number Diff line number Diff line change
Expand Up @@ -685,6 +685,21 @@ proc queryOne*(
return some(Row(data: qr.data, rowIdx: 0))
return none(Row)

proc queryRow*(
pool: PgPool,
sql: string,
params: seq[PgParam] = @[],
resultFormat: ResultFormat = rfAuto,
timeout: Duration = ZeroDuration,
): Future[Row] {.async.} =
## Execute a query and return the first row.
## Raises `PgError` if no rows are returned.
let row =
await pool.queryOne(sql, params, resultFormat = resultFormat, timeout = timeout)
if row.isNone:
raise newException(PgError, "Query returned no rows")
return row.get

proc queryValue*(
pool: PgPool,
sql: string,
Expand Down
16 changes: 16 additions & 0 deletions async_postgres/pg_pool_cluster.nim
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,14 @@ clusterForwards("read"):
timeout: Duration = ZeroDuration,
): Future[Option[Row]]

proc readQueryRow*(
cluster: PgPoolCluster,
sql: string,
params: seq[PgParam] = @[],
resultFormat: ResultFormat = rfAuto,
timeout: Duration = ZeroDuration,
): Future[Row]

proc readQueryValue*(
cluster: PgPoolCluster,
sql: string,
Expand Down Expand Up @@ -335,6 +343,14 @@ clusterForwards("write"):
timeout: Duration = ZeroDuration,
): Future[Option[Row]]

proc writeQueryRow*(
cluster: PgPoolCluster,
sql: string,
params: seq[PgParam] = @[],
resultFormat: ResultFormat = rfAuto,
timeout: Duration = ZeroDuration,
): Future[Row]

proc writeQueryValue*(
cluster: PgPoolCluster,
sql: string,
Expand Down
5 changes: 2 additions & 3 deletions examples/pool.nim
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
## Usage:
## nim c -r examples/pool.nim

import std/options
import pkg/async_postgres

proc main() {.async.} =
Expand Down Expand Up @@ -49,8 +48,8 @@ proc main() {.async.} =

proc cheapest(): Future[string] {.async.} =
pool.withConnection(conn):
let row = await conn.queryOne("SELECT name FROM products ORDER BY price LIMIT 1")
return options.get(row).getStr("name")
let row = await conn.queryRow("SELECT name FROM products ORDER BY price LIMIT 1")
return row.getStr("name")

# Launch concurrently, then await each result
let expCountFut = countExpensive()
Expand Down
45 changes: 45 additions & 0 deletions tests/test_e2e.nim
Original file line number Diff line number Diff line change
Expand Up @@ -4465,6 +4465,29 @@ suite "E2E: Convenience Query Methods":

waitFor t()

test "queryRow returns first row":
proc t() {.async.} =
let conn = await connect(plainConfig())
let row = await conn.queryRow("SELECT 1 AS a, 'hello' AS b")
doAssert row.getStr(0) == "1"
doAssert row.getStr(1) == "hello"
await conn.close()

waitFor t()

test "queryRow raises on no rows":
proc t() {.async.} =
let conn = await connect(plainConfig())
var raised = false
try:
discard await conn.queryRow("SELECT 1 WHERE false")
except PgError:
raised = true
doAssert raised
await conn.close()

waitFor t()

test "queryValue returns scalar":
proc t() {.async.} =
let conn = await connect(plainConfig())
Expand Down Expand Up @@ -4736,6 +4759,28 @@ suite "E2E: Convenience Query Methods":

waitFor t()

test "pool queryRow":
proc t() {.async.} =
let pool = await newPool(initPoolConfig(plainConfig(), minSize = 1, maxSize = 2))
let row = await pool.queryRow("SELECT 'pooled' AS v")
doAssert row.getStr("v") == "pooled"
await pool.close()

waitFor t()

test "pool queryRow raises on no rows":
proc t() {.async.} =
let pool = await newPool(initPoolConfig(plainConfig(), minSize = 1, maxSize = 2))
var raised = false
try:
discard await pool.queryRow("SELECT 1 WHERE false")
except PgError:
raised = true
doAssert raised
await pool.close()

waitFor t()

test "pool queryValue":
proc t() {.async.} =
let pool = await newPool(initPoolConfig(plainConfig(), minSize = 1, maxSize = 2))
Expand Down
15 changes: 15 additions & 0 deletions tests/test_pool_cluster.nim
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,13 @@ suite "Write routing":
expect(PgError):
discard waitFor cluster.writeQueryOne("SELECT 1")

test "writeQueryRow routes to primary":
let cluster = makeCluster()
cluster.primary.closed = true

expect(PgError):
discard waitFor cluster.writeQueryRow("SELECT 1")

test "writeQueryValue routes to primary":
let cluster = makeCluster()
cluster.primary.closed = true
Expand Down Expand Up @@ -456,6 +463,14 @@ suite "Read routing targets replica":
expect(PgError):
discard waitFor cluster.readQueryOne("SELECT 1")

test "readQueryRow routes to replica":
let cluster = makeCluster()
cluster.replica.closed = true
cluster.fallback = fallbackNone

expect(PgError):
discard waitFor cluster.readQueryRow("SELECT 1")

test "readQueryValue routes to replica":
let cluster = makeCluster()
cluster.replica.closed = true
Expand Down
Loading