I'm currently writing a REST API in Golang but I'm getting an error when making a GET request to an endpoint that then retrieves data from a Postgres database table. Specifically, this error is in relation to parsing a postgres array to a golang slice.
The error is as follows: sql: Scan error on column index 8, name "image_paths": pq: parsing array element index 0: pq: scanning to data.Image is not implemented; only sql.Scanner
This is the database with one entry (the relevant column is highlighted):
The relevant code is as follows:
func (s SpaceDetailsModel) GetForUser(filters Filters, id int64) ([]*SpaceDetails, Metadata, error) {
if id < 1 {
return nil, Metadata{}, ErrRecordNotFound
}
query := `
SELECT count(*) OVER(), id, created_At, space_owner_id, location_text, post_code, longitude, latitude, image_paths, space_description, booking_count, number_of_reviews, average_rating, version
FROM spaces
WHERE space_owner_id = $1 ORDER BY created_at DESC LIMIT $2 OFFSET $3`
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
args := []interface{}{id, filters.limit(), filters.offset()}
rows, err := s.DB.QueryContext(ctx, query, args...)
if err != nil {
return nil, Metadata{}, err
}
defer rows.Close()
totalRecords := 0
spaces := []*SpaceDetails{}
for rows.Next() {
var space SpaceDetails
err := rows.Scan(
&totalRecords,
&space.ID,
&space.CreatedAt,
&space.SpaceOwnerId,
&space.LocationText,
&space.PostCode,
&space.Coordinates.Longitude,
&space.Coordinates.Latitude,
pq.Array(&space.Images),
&space.SpaceDescription,
&space.BookingCount,
&space.NumberOfReviews,
&space.AverageRating,
&space.Version,
)
if err != nil {
return nil, Metadata{}, err
}
spaces = append(spaces, &space)
}
if err = rows.Err(); err != nil {
return nil, Metadata{}, err
}
metadata := calculateMetadata(totalRecords, filters.Page, filters.PageSize)
return spaces, metadata, nil
}
The stack trace is:
PS C:\Users\bcart\OneDrive\Desktop\Project\Project Z\Code\Parkit>
go run ./cmd/api
{"level":"INFO","time":"2022-07-28T13:40:14Z","message":"database connection pool established"}
{"level":"INFO","time":"2022-07-28T13:40:14Z","message":"starting server","properties":{"addr":":4000","env":"development"}}
{"level":"ERROR","time":"2022-07-28T13:40:19Z","message":"sql: Scan error on column index 8, name \"image_paths\": pq: parsing array element index 0: pq: scanning to data.Image is not implemented; only sql.Scanner","properties":{"request_method":"POST","request_url":"/api/v1/days_bookings_record"},"trace":"goroutine 22 [running]:\nruntime/debug.Stack(0x31011630, 0xeda7488c3, 0x0)\n\tC:/Program Files/Go/src/runtime/debug/stack.go:24 +0xa5\nparkit/internal/jsonlog.(*Logger).print(0xc000054600, 0xc0000fe001, 0xc0000fe000, 0x99, 0xc00009cc60, 0x0, 0x0, 0x0)\n\tC:/Users/bcart/OneDrive/Desktop/Project/Project Z/Code/Parkit/internal/jsonlog/jsonlog.go:80 +0x475\nparkit/internal/jsonlog.(*Logger).PrintError(0xc000054600, 0xbd9ba0, 0xc00009a2e0, 0xc00009cc60)\n\tC:/Users/bcart/OneDrive/Desktop/Project/Project Z/Code/Parkit/internal/jsonlog/jsonlog.go:52 +0x69\nmain.(*application).logError(0xc0000be000, 0xc0000c6300, 0xbd9ba0, 0xc00009a2e0)\n\tC:/Users/bcart/OneDrive/Desktop/Project/Project Z/Code/Parkit/cmd/api/errors.go:9 +0x145\nmain.(*application).serverErrorResponse(0xc0000be000, 0xbe03e0, 0xc0000883c0, 0xc0000c6300, 0xbd9ba0, 0xc00009a2e0)\n\tC:/Users/bcart/OneDrive/Desktop/Project/Project Z/Code/Parkit/cmd/api/errors.go:26 +0x54\nmain.(*application).createDaysBookingsRecordHandler(0xc0000be000, 0xbe03e0, 0xc0000883c0, 0xc0000c6300)\n\tC:/Users/bcart/OneDrive/Desktop/Project/Project Z/Code/Parkit/cmd/api/spacebookings.go:39 +0x6cd\nnet/http.HandlerFunc.ServeHTTP(0xc0000a4340, 0xbe03e0, 0xc0000883c0, 0xc0000c6300)\n\tC:/Program Files/Go/src/net/http/server.go:2069 +0x4b\ngithub.com/julienschmidt/httprouter.(*Router).Handler.func1(0xbe03e0, 0xc0000883c0, 0xc0000c6300, 0x0, 0x0, 0x0)\n\tC:/Users/bcart/go/pkg/mod/github.com/julienschmidt/[email protected]/router.go:275 +0x1e7\ngithub.com/julienschmidt/httprouter.(*Router).ServeHTTP(0xc000088180, 0xbe03e0, 0xc0000883c0, 0xc0000c6300)\n\tC:/Users/bcart/go/pkg/mod/github.com/julienschmidt/[email protected]/router.go:387 +0xc7e\nmain.(*application).authenticate.func1(0xbe03e0, 0xc0000883c0, 0xc0000c6200)\n\tC:/Users/bcart/OneDrive/Desktop/Project/Project Z/Code/Parkit/cmd/api/middleware.go:128 +0x423\nnet/http.HandlerFunc.ServeHTTP(0xc00009a0a0, 0xbe03e0, 0xc0000883c0, 0xc0000c6200)\n\tC:/Program Files/Go/src/net/http/server.go:2069 +0x4b\nmain.(*application).rateLimit.func2(0xbe03e0, 0xc0000883c0, 0xc0000c6200)\n\tC:/Users/bcart/OneDrive/Desktop/Project/Project Z/Code/Parkit/cmd/api/middleware.go:84 +0x82\nnet/http.HandlerFunc.ServeHTTP(0xc00009c2a0, 0xbe03e0, 0xc0000883c0, 0xc0000c6200)\n\tC:/Program Files/Go/src/net/http/server.go:2069 +0x4b\nmain.(*application).enableCORS.func1(0xbe03e0, 0xc0000883c0, 0xc0000c6200)\n\tC:/Users/bcart/OneDrive/Desktop/Project/Project Z/Code/Parkit/cmd/api/middleware.go:208 +0x3ec\nnet/http.HandlerFunc.ServeHTTP(0xc00009a0c0, 0xbe03e0, 0xc0000883c0, 0xc0000c6200)\n\tC:/Program Files/Go/src/net/http/server.go:2069 +0x4b\nmain.(*application).recoverPanic.func1(0xbe03e0, 0xc0000883c0, 0xc0000c6200)\n\tC:/Users/bcart/OneDrive/Desktop/Project/Project Z/Code/Parkit/cmd/api/middleware.go:30 +0x98\nnet/http.HandlerFunc.ServeHTTP(0xc00009a0e0, 0xbe03e0, 0xc0000883c0, 0xc0000c6200)\n\tC:/Program Files/Go/src/net/http/server.go:2069 +0x4b\ngithub.com/felixge/httpsnoop.CaptureMetrics.func1(0xbe03e0, 0xc0000883c0)\n\tC:/Users/bcart/go/pkg/mod/github.com/felixge/[email protected]/capture_metrics.go:29 +0x53\ngithub.com/felixge/httpsnoop.(*Metrics).CaptureMetrics(0xc0000960a8, 0xbdfe70, 0xc0000c80e0, 0xc000073ab0)\n\tC:/Users/bcart/go/pkg/mod/github.com/felixge/[email protected]/capture_metrics.go:84 +0x1e7\ngithub.com/felixge/httpsnoop.CaptureMetricsFn(...)\n\tC:/Users/bcart/go/pkg/mod/github.com/felixge/[email protected]/capture_metrics.go:39\ngithub.com/felixge/httpsnoop.CaptureMetrics(0xbda7e0, 0xc00009a0e0, 0xbdfe70, 0xc0000c80e0, 0xc0000c6200, 0x970ca7, 0xc0000aa2ec, 0x1e0edbf0778)\n\tC:/Users/bcart/go/pkg/mod/github.com/felixge/[email protected]/capture_metrics.go:28 +0xae\nmain.(*application).metrics.func1(0xbdfe70, 0xc0000c80e0, 0xc0000c6200)\n\tC:/Users/bcart/OneDrive/Desktop/Project/Project Z/Code/Parkit/cmd/api/middleware.go:223 +0x87\nnet/http.HandlerFunc.ServeHTTP(0xc0000aa0c0, 0xbdfe70, 0xc0000c80e0, 0xc0000c6200)\n\tC:/Program Files/Go/src/net/http/server.go:2069 +0x4b\nnet/http.serverHandler.ServeHTTP(0xc0000c8000, 0xbdfe70, 0xc0000c80e0, 0xc0000c6200)\n\tC:/Program Files/Go/src/net/http/server.go:2887 +0xaa\nnet/http.(*conn).serve(0xc00008a140, 0xbe0f20, 0xc0000aa240)\n\tC:/Program Files/Go/src/net/http/server.go:1952 +0x8cd\ncreated by net/http.(*Server).Serve\n\tC:/Program Files/Go/src/net/http/server.go:3013 +0x3b8\n"}
2022/07/28 14:40:19 http: superfluous response.WriteHeader call from github.com/felixge/httpsnoop.(*Metrics).CaptureMetrics.func1.1 (capture_metrics.go:53)
Does anyone know what is causing this error and how to resolve it?
database/sql
package expects support for encoding/decoding only the basic types (string
,int
, etc.), plus thetime.Time
type, and perhaps a handful of others, but not more. Then the the driver that you are using can (doesn't have to) extend the support to additional, more complex types (e.g.lib/pq
has array support but it's not automatic). And, finally, if neither the stdlib nor the driver support your type, you can opt to implement thesql.Scanner
anddriver.Valuer
interfaces to add the support to a specific type yourself. - mkopriva