gopostgispgxent

How to store PostGIS Point with entgo / pgx?


I'm having trouble saving a PostGIS point with entgo and pgx.

I try to use the pgtype.Point type from pgx, the schema looks like this:

// Fields of the Event.
func (EventSchema) Fields() []ent.Field {
    return []ent.Field{
        field.UUID("id", uuid.UUID{}).Immutable().
            Annotations(&entsql.Annotation{
                Default: "gen_random_uuid()"
            }),
        field.Other("location", &pgtype.Point{}).
            SchemaType(map[string]string{
                dialect.Postgres: "geometry(point, 4326)"
            }).StorageKey("location").Optional(),
    }
}

In the database, the type of "location" is also geometry(point, 4326).

The query to create: db.EventSchema.Create().SetLocation(point).Save()

leads to the error: ERROR: parse error - invalid geometry (SQLSTATE XX000)

Can't I just use pgtype.Point here, but do some formatting? Or does anyone have a working example with a different point type, e.g. with go-geom?

Thanks for your help!


Solution

  • This solution worked for me, may it help you too.

    schema

    field.Other("location", &database.GeoJson{}).
      SchemaType(map[string]string{
        dialect.Postgres: "geometry(point, 4326)",
    }).StorageKey("location").Optional(),
    

    custom GeoJson type based on geojson.Geometry

    type GeoJson struct {
        *geojson.Geometry
    }
    
    func (t *GeoJson) Value() (driver.Value, error) {
        geometry, err := t.Decode()
        if err != nil {
            logging.Logger.Debug(err)
            return nil, err
        }
    
        encodedGeometry, err := ewkbhex.Encode(geometry, binary.LittleEndian)
        if err != nil {
            logging.Logger.Debug(err)
            return nil, err
        }
    
        return encodedGeometry, nil
    }
    
    func (t *GeoJson) Scan(value interface{}) error {
        // handle nil
        if value == nil {
            t = nil
            return nil
        }
    
        // parse as string
        stringValue, ok := value.(string)
        if !ok {
            return errors.New("value is no string")
        }
    
        geometry, err := ewkbhex.Decode(stringValue)
        if err != nil {
            return err
        }
    
        geometryAsBytes, err := geojson.Marshal(geometry)
        if err != nil {
            return err
        }
    
        var geoJson GeoJson
        if err := json.Unmarshal(geometryAsBytes, &geoJson); err != nil {
            return err
        }
    
        *t = geoJson
    
        return nil
    }
    

    example json payload

    "location": {
      "type": "Point",
      "coordinates": [22.666460, 31.180481]
     }