Skip to content
Snippets Groups Projects
Select Git revision
  • ee18fe594a0567a86c5aa43fc0fedc662516998d
  • master default protected
  • feature/PRXS-3383-CollectionsSort
  • feature/2781-SpacesLoggingMiddleware
  • feature/PRXS-3421-ImplementNewRefAPI
  • feature/PRXS-3143-3235-ReferenceOptions
  • feature/PRXS-3143-LimitReferenceFields
  • feature/PRXS-3234-FeaturePruneIdents
  • PRXS-3421-RecursiveReferences
  • feature/3109-SerializeFeature
  • release/0.33
  • feature/3109-RecoverySchema
  • feature/3109-feature
  • fix/PRXS-3369-ValidateFields
  • refactor/PRXS-3306-MovePkgGroup1
  • refactor/6-pkg-refactor-expr
  • fix/PRXS-3360-TemplateBuilderPatch
  • feature/3293-MongoV2
  • feature/3272-GoVersionUp
  • feature/PRXS-3218-HideTemplateActions
  • feature/PRXS-3234-PruneIdents
  • v0.33.1
  • v0.32.0
  • v0.31.1
  • v0.31.0
  • v0.30.0
  • v0.29.0
  • v0.28.0
  • v0.27.0-alpha.1+16
  • v0.27.0-alpha.1+15
  • v0.27.0-alpha.1+14
  • v0.27.0-alpha.1+13
  • v0.27.0-alpha.1+12
  • v0.27.0-alpha.1+11
  • v0.27.0-alpha.1+10
  • v0.27.0-alpha.1+9
  • v0.27.0-alpha.1+8
  • v0.27.0-alpha.1+7
  • v0.27.0-alpha.1+6
  • v0.27.0-alpha.1+5
  • v0.27.0-alpha.1+4
41 results

field_test.go

Blame
  • location.go 3.56 KiB
    package field
    
    import (
    	"context"
    
    	"git.perx.ru/perxis/perxis-go/pkg/errors"
    	"github.com/mitchellh/mapstructure"
    	"go.mongodb.org/mongo-driver/bson"
    	"go.mongodb.org/mongo-driver/mongo"
    	"go.mongodb.org/mongo-driver/mongo/options"
    )
    
    var locationType = &LocationType{}
    
    type LocationParameters struct{}
    
    func (p LocationParameters) Type() Type                                              { return locationType }
    func (p LocationParameters) Clone(reset bool) Parameters                             { return &LocationParameters{} }
    func (p LocationParameters) GetField(f *Field, name string) *Field                   { return nil }
    func (p LocationParameters) ListFields(f *Field, filter ...FieldFilterFunc) []*Field { return nil }
    
    func (p LocationParameters) GetMongoIndexes(path string, f *Field) []mongo.IndexModel {
    	var add, geo mongo.IndexModel
    	a := path + ".address"
    	g := path + ".geometry"
    	add.Options = options.Index().SetName(a)
    	//add.Options.SetSparse(true)
    	add.Options.SetPartialFilterExpression(bson.M{a: bson.M{"$exists": true}})
    	geo.Options = options.Index().SetName(g)
    	if f.Unique {
    		add.Options.SetUnique(true)
    		geo.Options.SetUnique(true)
    	}
    
    	if f.Indexed {
    		add.Keys = bson.D{{Key: a, Value: 1}}
    		geo.Keys = bson.D{{Key: g, Value: "2dsphere"}}
    	}
    	return []mongo.IndexModel{add, geo}
    }
    
    type LocationType struct{}
    
    type GeoJSON struct {
    	Type        string    `json:"type" bson:"type" mapstructure:"type,omitempty"`
    	Coordinates []float64 `json:"coordinates" bson:"coordinates" mapstructure:"coordinates"`
    }
    
    type GeoObject struct {
    	Address  string   `json:"address,omitempty" bson:"address" mapstructure:"address,omitempty"`
    	Geometry *GeoJSON `json:"geometry,omitempty" bson:"geometry" mapstructure:"geometry,omitempty"`
    }
    
    func (LocationType) Name() string {
    	return "location"
    }
    
    func (LocationType) NewParameters() Parameters {
    	return &LocationParameters{}
    }
    
    func (LocationType) IsEmpty(v interface{}) bool {
    	loc, _ := v.(*GeoObject)
    	return loc == nil || loc.Address != "" && loc.Geometry != nil
    }
    
    func (LocationType) Decode(_ context.Context, _ *Field, v interface{}) (interface{}, error) {
    
    	if v == nil {
    		return nil, nil
    	}
    
    	var g GeoObject
    	if err := mapstructure.Decode(v, &g); err != nil {
    		return nil, err
    	}
    
    	if g.Address == "" && g.Geometry == nil {
    		return nil, errors.New("address or coordinates required")
    	}
    
    	if g.Geometry != nil {
    		if len(g.Geometry.Coordinates) != 2 {
    			return nil, errors.New("latitude and longitude required")
    		}
    
    		lat := g.Geometry.Coordinates[0]
    		lon := g.Geometry.Coordinates[1]
    
    		if lat < -180 || lat > 180 {
    			return nil, errors.New("invalid longitude values, valid are between -180 and 180")
    		}
    
    		if lon < -90 || lon > 90 {
    			return nil, errors.New("invalid latitude values, valid are between -90 and 90")
    		}
    
    		if g.Geometry.Type != "Point" {
    			g.Geometry.Type = "Point"
    		}
    	}
    
    	return &g, nil
    }
    
    func (LocationType) Encode(_ context.Context, _ *Field, v interface{}) (interface{}, error) {
    
    	if v == nil {
    		return nil, nil
    	}
    
    	g, ok := v.(*GeoObject)
    	if !ok {
    		return nil, errors.New("couldn't encode GeoObject")
    	}
    
    	res := make(map[string]interface{})
    	if g.Address != "" {
    		res["address"] = g.Address
    	}
    
    	if g.Geometry != nil {
    		if len(g.Geometry.Coordinates) != 2 {
    			return nil, errors.New("latitude and longitude required")
    		}
    
    		lat := g.Geometry.Coordinates[0]
    		lon := g.Geometry.Coordinates[1]
    
    		res["geometry"] = map[string]interface{}{"type": g.Geometry.Type, "coordinates": []interface{}{lat, lon}}
    	}
    
    	return res, nil
    }
    
    func Location(o ...interface{}) *Field {
    	return NewField(&LocationParameters{}, o...)
    }