maptile/store/feature.go

168 lines
4.1 KiB
Go
Executable File

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
}