Skip to content
This repository was archived by the owner on Jul 7, 2026. It is now read-only.

Commit a2fc577

Browse files
committed
airbyte: run PostgreSQL queries with pgxpool & scany
Signed-off-by: VirtualTam <virtualtam@flibidi.net>
1 parent 4c77f80 commit a2fc577

5 files changed

Lines changed: 58 additions & 59 deletions

File tree

CHANGELOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,15 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
66
and this project adheres to [Semantic Versioning](https://semver.org/).
77

8-
## [v2.2.0](https://github.com/botify-labs/airbyte_exporter/releases/tag/v2.2.0) - UNRELEASED
8+
## [v2.2.0](https://github.com/botify-labs/airbyte_exporter/releases/tag/v2.2.0) - 2023-10-25
99

1010
### Changed
1111

1212
- Require Go 1.21
1313
- Bump base Docker image to Debian 12 Bookworm
1414
- Update direct and transitive dependencies
15+
- Rework the Repository to run PostgreSQL queries using the concurrency-safe `pgxpool` package
16+
and scanning helpers from `scany`
1517

1618

1719
## [v2.1.0](https://github.com/botify-labs/airbyte_exporter/releases/tag/v2.1.0) - 2023-06-19

cmd/airbyte_exporter/exporter_command.go

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,15 @@
55
package main
66

77
import (
8+
"context"
89
"fmt"
910
"net/url"
1011
"os"
1112
"path/filepath"
1213
"strings"
1314

15+
"github.com/jackc/pgx/v5/pgxpool"
1416
_ "github.com/jackc/pgx/v5/stdlib"
15-
"github.com/jmoiron/sqlx"
1617
"github.com/rs/zerolog"
1718
"github.com/rs/zerolog/log"
1819
"github.com/spf13/cobra"
@@ -103,24 +104,35 @@ func NewExporterCommand() *cobra.Command {
103104
)
104105

105106
// Database connection pool
106-
db, err := sqlx.Connect(databaseDriver, databaseURI)
107+
pgxPool, err := pgxpool.New(context.Background(), databaseURI)
107108
if err != nil {
108109
log.Error().
109110
Err(err).
110111
Str("database_driver", databaseDriver).
111112
Str("database_addr", databaseAddr).
112113
Str("database_name", databaseName).
113-
Msg("failed to connect to database")
114+
Msg("database: failed to create connection pool")
114115
return err
115116
}
117+
118+
if err := pgxPool.Ping(context.Background()); err != nil {
119+
log.Error().
120+
Err(err).
121+
Str("database_driver", databaseDriver).
122+
Str("database_addr", databaseAddr).
123+
Str("database_name", databaseName).
124+
Msg("database: failed to ping")
125+
return err
126+
}
127+
116128
log.Info().
117129
Str("database_driver", databaseDriver).
118130
Str("database_addr", databaseAddr).
119131
Str("database_name", databaseName).
120-
Msg("successfully connected to database")
132+
Msg("database: successfully created connection pool")
121133

122134
// Airbyte Exporter services
123-
airbyteRepository := airbyte.NewRepository(db)
135+
airbyteRepository := airbyte.NewRepository(pgxPool)
124136
airbyteService := airbyte.NewService(airbyteRepository)
125137

126138
httpServer := newServer(airbyteService, listenAddr)

go.mod

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ module github.com/botify-labs/airbyte_exporter/v2
33
go 1.21
44

55
require (
6+
github.com/georgysavva/scany/v2 v2.0.0
67
github.com/jackc/pgx/v5 v5.4.3
7-
github.com/jmoiron/sqlx v1.3.5
88
github.com/justinas/alice v1.2.0
99
github.com/prometheus/client_golang v1.17.0
1010
github.com/rs/zerolog v1.31.0
@@ -20,6 +20,7 @@ require (
2020
github.com/inconshreveable/mousetrap v1.1.0 // indirect
2121
github.com/jackc/pgpassfile v1.0.0 // indirect
2222
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
23+
github.com/jackc/puddle/v2 v2.2.1 // indirect
2324
github.com/magiconair/properties v1.8.7 // indirect
2425
github.com/mattn/go-colorable v0.1.13 // indirect
2526
github.com/mattn/go-isatty v0.0.20 // indirect
@@ -41,6 +42,7 @@ require (
4142
go.uber.org/multierr v1.11.0 // indirect
4243
golang.org/x/crypto v0.14.0 // indirect
4344
golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect
45+
golang.org/x/sync v0.3.0 // indirect
4446
golang.org/x/sys v0.13.0 // indirect
4547
golang.org/x/text v0.13.0 // indirect
4648
google.golang.org/protobuf v1.31.0 // indirect

go.sum

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk
5050
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
5151
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
5252
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
53+
github.com/cockroachdb/cockroach-go/v2 v2.2.0 h1:/5znzg5n373N/3ESjHF5SMLxiW4RKB05Ql//KWfeTFs=
54+
github.com/cockroachdb/cockroach-go/v2 v2.2.0/go.mod h1:u3MiKYGupPPjkn3ozknpMUpxPaNLTFWAya419/zv6eI=
5355
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
5456
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
5557
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -66,12 +68,14 @@ github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0X
6668
github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
6769
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
6870
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
71+
github.com/georgysavva/scany/v2 v2.0.0 h1:RGXqxDv4row7/FYoK8MRXAZXqoWF/NM+NP0q50k3DKU=
72+
github.com/georgysavva/scany/v2 v2.0.0/go.mod h1:sigOdh+0qb/+aOs3TVhehVT10p8qJL7K/Zhyz8vWo38=
6973
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
7074
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
7175
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
72-
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
73-
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
7476
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
77+
github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw=
78+
github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
7579
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
7680
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
7781
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
@@ -144,8 +148,8 @@ github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/
144148
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
145149
github.com/jackc/pgx/v5 v5.4.3 h1:cxFyXhxlvAifxnkKKdlxv8XqUf59tDlYjnV5YYfsJJY=
146150
github.com/jackc/pgx/v5 v5.4.3/go.mod h1:Ig06C2Vu0t5qXC60W8sqIthScaEnFvojjj9dSljmHRA=
147-
github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g=
148-
github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ=
151+
github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk=
152+
github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
149153
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
150154
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
151155
github.com/justinas/alice v1.2.0 h1:+MHSA/vccVCF4Uq37S42jwlkvI2Xzl7zTPCN5BnZNVo=
@@ -159,8 +163,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
159163
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
160164
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
161165
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
162-
github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0=
163-
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
166+
github.com/lib/pq v1.10.0 h1:Zx5DJFEYQXio93kgXnQ09fXNiUKsqv4OUEu2UtGcB1E=
167+
github.com/lib/pq v1.10.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
164168
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
165169
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
166170
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
@@ -169,14 +173,13 @@ github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/
169173
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
170174
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
171175
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
172-
github.com/mattn/go-sqlite3 v1.14.6 h1:dNPt6NO46WmLVt2DLNpwczCmdV5boIZ6g/tlDrlRUbg=
173-
github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
174176
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg=
175177
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k=
176178
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
177179
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
178180
github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4=
179181
github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
182+
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
180183
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
181184
github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
182185
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
@@ -217,6 +220,7 @@ github.com/spf13/viper v1.17.0 h1:I5txKw7MJasPL/BrfkbA0Jyo/oELqVmux4pR/UxOMfI=
217220
github.com/spf13/viper v1.17.0/go.mod h1:BmMMMLQXSbcHK6KAOiFLz0l5JHrU89OdIRHvsk0+yVI=
218221
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
219222
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
223+
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
220224
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
221225
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
222226
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
@@ -337,6 +341,8 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ
337341
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
338342
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
339343
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
344+
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
345+
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
340346
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
341347
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
342348
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=

internal/airbyte/repository.go

Lines changed: 21 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -4,39 +4,37 @@
44

55
package airbyte
66

7-
import "github.com/jmoiron/sqlx"
7+
import (
8+
"context"
9+
10+
"github.com/georgysavva/scany/v2/pgxscan"
11+
"github.com/jackc/pgx/v5/pgxpool"
12+
)
813

914
// Repository provides an abstraction layer to perform SQL queries against the
1015
// Airbyte PostgreSQL database.
1116
type Repository struct {
12-
db *sqlx.DB
17+
pool *pgxpool.Pool
1318
}
1419

1520
// NewRepository initializes and returns an Airbyte Repository.
16-
func NewRepository(db *sqlx.DB) *Repository {
21+
func NewRepository(pool *pgxpool.Pool) *Repository {
1722
return &Repository{
18-
db: db,
23+
pool: pool,
1924
}
2025
}
2126

2227
// actorCountQuery provides a helper to run a SQL query that returns rows to be marshaled
2328
// as a slice of ActorCount.
2429
func (r *Repository) actorCountQuery(query string) ([]ActorCount, error) {
25-
rows, err := r.db.Queryx(query)
30+
rows, err := r.pool.Query(context.Background(), query)
2631
if err != nil {
2732
return []ActorCount{}, err
2833
}
2934

3035
var actorCounts []ActorCount
31-
32-
for rows.Next() {
33-
var actorCount ActorCount
34-
35-
if err := rows.StructScan(&actorCount); err != nil {
36-
return []ActorCount{}, err
37-
}
38-
39-
actorCounts = append(actorCounts, actorCount)
36+
if err := pgxscan.ScanAll(&actorCounts, rows); err != nil {
37+
return []ActorCount{}, err
4038
}
4139

4240
return actorCounts, nil
@@ -45,21 +43,14 @@ func (r *Repository) actorCountQuery(query string) ([]ActorCount, error) {
4543
// connectionCountQuery provides a helper to run a SQL query that returns rows to be marshaled
4644
// as a slice of ConnectionCount.
4745
func (r *Repository) connectionCountQuery(query string) ([]ConnectionCount, error) {
48-
rows, err := r.db.Queryx(query)
46+
rows, err := r.pool.Query(context.Background(), query)
4947
if err != nil {
5048
return []ConnectionCount{}, err
5149
}
5250

5351
var connectionCounts []ConnectionCount
54-
55-
for rows.Next() {
56-
var connectionCount ConnectionCount
57-
58-
if err := rows.StructScan(&connectionCount); err != nil {
59-
return []ConnectionCount{}, err
60-
}
61-
62-
connectionCounts = append(connectionCounts, connectionCount)
52+
if err := pgxscan.ScanAll(&connectionCounts, rows); err != nil {
53+
return []ConnectionCount{}, err
6354
}
6455

6556
return connectionCounts, nil
@@ -68,21 +59,14 @@ func (r *Repository) connectionCountQuery(query string) ([]ConnectionCount, erro
6859
// connectionSyncAgeQuery provides a helper to run a SQL query that returns rows to be marshaled
6960
// as a slice of ConnectionSyncAge.
7061
func (r *Repository) connectionSyncAgeQuery(query string) ([]ConnectionSyncAge, error) {
71-
rows, err := r.db.Queryx(query)
62+
rows, err := r.pool.Query(context.Background(), query)
7263
if err != nil {
7364
return []ConnectionSyncAge{}, err
7465
}
7566

7667
var connectionSyncAges []ConnectionSyncAge
77-
78-
for rows.Next() {
79-
var connectionSyncAge ConnectionSyncAge
80-
81-
if err := rows.StructScan(&connectionSyncAge); err != nil {
82-
return []ConnectionSyncAge{}, err
83-
}
84-
85-
connectionSyncAges = append(connectionSyncAges, connectionSyncAge)
68+
if err := pgxscan.ScanAll(&connectionSyncAges, rows); err != nil {
69+
return []ConnectionSyncAge{}, err
8670
}
8771

8872
return connectionSyncAges, nil
@@ -91,21 +75,14 @@ func (r *Repository) connectionSyncAgeQuery(query string) ([]ConnectionSyncAge,
9175
// jobCountQuery provides a helper to run a SQL query that returns rows to be marshaled
9276
// as a slice of JobCount.
9377
func (r *Repository) jobCountQuery(query string) ([]JobCount, error) {
94-
rows, err := r.db.Queryx(query)
78+
rows, err := r.pool.Query(context.Background(), query)
9579
if err != nil {
9680
return []JobCount{}, err
9781
}
9882

9983
var jobCounts []JobCount
100-
101-
for rows.Next() {
102-
var jobCount JobCount
103-
104-
if err := rows.StructScan(&jobCount); err != nil {
105-
return []JobCount{}, err
106-
}
107-
108-
jobCounts = append(jobCounts, jobCount)
84+
if err := pgxscan.ScanAll(&jobCounts, rows); err != nil {
85+
return []JobCount{}, err
10986
}
11087

11188
return jobCounts, nil

0 commit comments

Comments
 (0)