-
Notifications
You must be signed in to change notification settings - Fork 4
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
Support concrete types and custom types #3
Conversation
For context: I'm trying to use The support for scanning into Happy to make any changes to patch style, etc. per your preferences; just let me know! Thanks for writing these libraries; they look great so far <3 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for this excellent PR!
I have a few minor nitpicks, please see the individual review comments.
Once you've made the changes, please could you squash all the commits into one with the message:
feat: support concrete types and custom types
pgxgeom_test.go
Outdated
assert.Equal(t, err.Error(), "pgxgeom: got *geom.Polygon, want *geom.Point") | ||
var scanArgError pgx.ScanArgError | ||
assert.True(t, errors.As(err, &scanArgError)) | ||
assert.Equal(t, scanArgError.Err.Error(), "pgxgeom: got *geom.Polygon, want *geom.Point") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use assert.EqualError
instead of assert.True
and assert.Equal
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, okay. I was intending to test only the part of the error message that is controlled by this package rather than the "can't scan into dest[0]" prefix that pgtype itself adds. But I've switched to EqualError
with the full message; done, and let me know if you see a better way to do this.
// GeomScanner enables PostGIS geometry/geography values to be scanned into | ||
// arbitrary Go types. For more context, see section "Extending Existing | ||
// PostgreSQL Type Support" of the README for jackc/pgx/v5/pgtype. | ||
type GeomScanner interface { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does GeomScanner
need to be exported? If not, please rename it to geomScanner
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good question. I think that they should be exported. Reasons: (1) it is semantically part of the public API and should be documented so that users know what methods they need to implement on their custom types; (2) this follows the pattern set by first-party codecs like pgtype.TimeValuer
/ pgtype.TimeScanner
, which are exported; and (3) in my code that declares custom types that implement these interfaces, I am declaring
var _ pgxgeom.GeomValuer = &MyMultiLineString{}
var _ pgxgeom.GeomScanner = &MyMultiLineString{}
to check at compile time that I have implemented the signatures correctly, which also requires that these symbols be exported.
If you disagree, let me know and I'm happy to amend; I have a preference but do not feel strongly about it.
pgxgeom_test.go
Outdated
|
||
g, err := ewkb.Unmarshal(bytes) | ||
assert.NoError(t, err) | ||
assert.Equal(t, g.(*geom.Point).FlatCoords(), []float64{1, 2}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use
assert.Equal(t, mustNewGeomFromWKT(t, "POINT(1 2)", 4326), geom)
instead of testing FlatCoords()
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done. This family of changes gives rise to "mustNewGeomFromWKT
- srid
always receives 4326
(unparam)", so I have removed that lint rule, too.
pgxgeom_test.go
Outdated
|
||
err = conn.QueryRow(ctx, polygonQuery, pgx.QueryResultFormats{format}).Scan(&point) | ||
assert.Error(t, err) | ||
assert.Equal(t, err, error(pgx.ScanArgError{Err: errCustomPointScan})) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use assert.ErrorEquals
instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done, with the caveat that we're now testing the string value instead of the error instance.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the quick review! Updated and squashed. I'm inferring from your request that you want the squash commit to be entirely without commit body (i.e., subject line only), but let me know if I misunderstood and I would be happy to add it back.
pgxgeom_test.go
Outdated
assert.Equal(t, err.Error(), "pgxgeom: got *geom.Polygon, want *geom.Point") | ||
var scanArgError pgx.ScanArgError | ||
assert.True(t, errors.As(err, &scanArgError)) | ||
assert.Equal(t, scanArgError.Err.Error(), "pgxgeom: got *geom.Polygon, want *geom.Point") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, okay. I was intending to test only the part of the error message that is controlled by this package rather than the "can't scan into dest[0]" prefix that pgtype itself adds. But I've switched to EqualError
with the full message; done, and let me know if you see a better way to do this.
pgxgeom_test.go
Outdated
|
||
err = conn.QueryRow(ctx, polygonQuery, pgx.QueryResultFormats{format}).Scan(&point) | ||
assert.Error(t, err) | ||
assert.Equal(t, err, error(pgx.ScanArgError{Err: errCustomPointScan})) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done, with the caveat that we're now testing the string value instead of the error instance.
// GeomScanner enables PostGIS geometry/geography values to be scanned into | ||
// arbitrary Go types. For more context, see section "Extending Existing | ||
// PostgreSQL Type Support" of the README for jackc/pgx/v5/pgtype. | ||
type GeomScanner interface { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good question. I think that they should be exported. Reasons: (1) it is semantically part of the public API and should be documented so that users know what methods they need to implement on their custom types; (2) this follows the pattern set by first-party codecs like pgtype.TimeValuer
/ pgtype.TimeScanner
, which are exported; and (3) in my code that declares custom types that implement these interfaces, I am declaring
var _ pgxgeom.GeomValuer = &MyMultiLineString{}
var _ pgxgeom.GeomScanner = &MyMultiLineString{}
to check at compile time that I have implemented the signatures correctly, which also requires that these symbols be exported.
If you disagree, let me know and I'm happy to amend; I have a preference but do not feel strongly about it.
pgxgeom_test.go
Outdated
|
||
g, err := ewkb.Unmarshal(bytes) | ||
assert.NoError(t, err) | ||
assert.Equal(t, g.(*geom.Point).FlatCoords(), []float64{1, 2}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done. This family of changes gives rise to "mustNewGeomFromWKT
- srid
always receives 4326
(unparam)", so I have removed that lint rule, too.
Thank you! All your reasoning makes sense. This is a fantastic PR :) |
Thank you! I am glad that you find it suitable. And thanks again for the quick review and the solid libraries! |
Previously, you could only scan into a
*geom.T
. Now, you can scan into a*geom.T
, or a*geom.Polygon
(with runtime checking), or any type that implements theGeomScanner
interface. This enables end users to define their own wrapper types for interoperability with other systems, such as ORMs that require specific methods to be defined on the types that are used on model fields.The public interface follows the extensibility pattern described in the documentation for
pgtype
, which is also used for first-partypgtype
codecs: e.g.,TimeCodec
usesTimeScanner
andTimeValuer
.Test Plan:
Unit tests included. I couldn't figure out how to get encoding tests to run in both text and binary formats, but I did manually verify that if you change the preferred format from binary to text then the appropriate codepath is exercised and the test still passes.