package store import ( "encoding/json" "time" "git.zhouxhere.com/zhouxhere/maptile/model" "github.com/google/uuid" "github.com/pkg/errors" "github.com/twpayne/go-geom" "github.com/twpayne/go-geom/encoding/geojson" ) // ListFeature 获取要素列表 func (s *Store) ListFeature(query *model.FeatureList) ([]model.Feature, int, error) { queryStr := ` SELECT id, name, ST_AsGeoJSON(geometry) AS geometry, status, created_at, updated_at FROM feature WHERE 1 = 1 ` if query.Status != "" { queryStr += " AND status = :status" } if query.Name != "" { queryStr += " AND name LIKE :name" } queryStr += " ORDER BY status, created_at DESC" queryStr += " LIMIT :limit OFFSET :offset" namedParams := map[string]interface{}{ "status": query.Status, "name": "'%" + query.Name + "%'", "limit": query.Size, "offset": (query.Page - 1) * query.Size, } queryStr, args, err := s.DB.BindNamed(queryStr, namedParams) if err != nil { return nil, 0, err } // 执行查询 features := []model.Feature{} if err := s.DB.Select(&features, queryStr, args...); err != nil { return nil, 0, err } countQuery := ` SELECT COUNT(*) FROM feature WHERE 1 = 1 ` if query.Status != "" { countQuery += " AND status = :status" } if query.Name != "" { countQuery += " AND name LIKE :name" } countQuery, countArgs, err := s.DB.BindNamed(countQuery, namedParams) if err != nil { return nil, 0, err } var count int if err := s.DB.Get(&count, countQuery, countArgs...); err != nil { return nil, 0, err } return features, count, nil } // GetFeatureByID 获取要素 func (s *Store) GetFeatureByID(id uuid.UUID) (*model.Feature, error) { query := ` SELECT id, name, ST_AsGeoJSON(geometry) AS geometry, status, created_at, updated_at FROM feature WHERE id = :id ` f := &model.Feature{} if err := s.DB.Get(f, query, id); err != nil { return nil, err } return f, nil } // CreateFeature 创建要素 func (s *Store) CreateFeature(feature *model.FeatureCreate) (*model.Feature, error) { // 将传入的 JSON 格式的 geometry 转换为 geom.T 类型 geometryBytes, err := json.Marshal(feature.Geometry) if err != nil { return nil, err } var geomT geom.T if err := geojson.Unmarshal(geometryBytes, &geomT); err != nil { return nil, errors.New("invalid GeoJSON format") } query := ` INSERT INTO feature (id, name, geometry, status, created_at, updated_at) VALUES (:id, :name, ST_GeomFromGeoJSON(:geometry), :status, :created_at, :updated_at) ` f := &model.Feature{ ID: uuid.New(), Name: feature.Name, Geometry: geometryBytes, Status: model.StatusNormal, CreatedAt: time.Now().Unix(), UpdatedAt: time.Now().Unix(), } _, err = s.DB.NamedExec(query, f) return f, err } // UpdateFeature 更新要素 func (s *Store) UpdateFeature(feature *model.FeatureUpdate) (*model.Feature, error) { // 将传入的 JSON 格式的 geometry 转换为 geom.T 类型 geometryBytes, err := json.Marshal(feature.Geometry) if err != nil { return nil, err } var geomT geom.T if err := geojson.Unmarshal(geometryBytes, &geomT); err != nil { return nil, errors.New("invalid GeoJSON format") } query := ` UPDATE feature SET name = :name, geometry = ST_GeomFromGeoJSON(:geometry), updated_at = :updated_at WHERE id = :id ` f := &model.Feature{ ID: feature.ID, Name: feature.Name, Geometry: geometryBytes, UpdatedAt: time.Now().Unix(), } _, err = s.DB.NamedExec(query, f) return f, err } // DeleteFeature 删除要素 func (s *Store) DeleteFeature(feature *model.FeatureDeleteOrBanned) error { query := ` UPDATE feature SET status = :status, updated_at = :updated_at WHERE id = :id ` f := &model.Feature{ ID: feature.ID, Status: model.StatusDeleted, UpdatedAt: time.Now().Unix(), } _, err := s.DB.NamedExec(query, f) return err } // BannedFeature 禁用要素 func (s *Store) BannedFeature(feature *model.FeatureDeleteOrBanned) error { query := ` UPDATE feature SET status = :status, updated_at = :updated_at WHERE id = :id ` f := &model.Feature{ ID: feature.ID, Status: model.StatusBanned, UpdatedAt: time.Now().Unix(), } _, err := s.DB.NamedExec(query, f) return err }