mirror of
https://github.com/Cernobor/oko-server.git
synced 2025-02-24 08:27:17 +00:00
remove description and category, introduce properties
* fatures no longer have distinct description and category fields * features now have a json field 'properties'
This commit is contained in:
parent
5deff38890
commit
b512bc0d2f
@ -20,12 +20,11 @@ type User struct {
|
|||||||
type Feature struct {
|
type Feature struct {
|
||||||
// ID is an ID of the feature.
|
// ID is an ID of the feature.
|
||||||
// When the feature is submitted by a client for creation (i.e. in Update.Create) it is considered a 'local' ID which must be unique across all submitted features.
|
// When the feature is submitted by a client for creation (i.e. in Update.Create) it is considered a 'local' ID which must be unique across all submitted features.
|
||||||
ID FeatureID `json:"id"`
|
ID FeatureID `json:"id"`
|
||||||
OwnerID *UserID `json:"owner_id"`
|
OwnerID *UserID `json:"owner_id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Description *string `json:"description"`
|
Properties map[string]interface{} `json:"properties"`
|
||||||
Category *string `json:"category"`
|
Geometry geojson.Geometry `json:"geometry"`
|
||||||
Geometry geojson.Geometry `json:"geometry"`
|
|
||||||
// PhotoIDs contains a list IDs of photos associated with the feature.
|
// PhotoIDs contains a list IDs of photos associated with the feature.
|
||||||
// When the feature is retrieved from the server, the IDs can be used to retrieve the photos.
|
// When the feature is retrieved from the server, the IDs can be used to retrieve the photos.
|
||||||
// When the feature is submitted by a client (created or updated, i.e. in Update.Create or Update.Update), this list is ignored (as photos are managed through Update.CreatePhotos and Update.DeletePhotos fields).
|
// When the feature is submitted by a client (created or updated, i.e. in Update.Create or Update.Update), this list is ignored (as photos are managed through Update.CreatePhotos and Update.DeletePhotos fields).
|
||||||
|
@ -10,8 +10,7 @@ CREATE TABLE IF NOT EXISTS features (
|
|||||||
id integer PRIMARY KEY AUTOINCREMENT,
|
id integer PRIMARY KEY AUTOINCREMENT,
|
||||||
owner_id integer REFERENCES users(id) ON DELETE CASCADE,
|
owner_id integer REFERENCES users(id) ON DELETE CASCADE,
|
||||||
name text NOT NULL,
|
name text NOT NULL,
|
||||||
description text,
|
properties text NOT NULL,
|
||||||
category text,
|
|
||||||
geom text NOT NULL
|
geom text NOT NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -274,10 +274,10 @@ func (s *Server) getFeatures(conn *sqlite.Conn) ([]models.Feature, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
features := make([]models.Feature, 0, 100)
|
features := make([]models.Feature, 0, 100)
|
||||||
err := sqlitex.Exec(conn, `select f.id, f.owner_id, f.name, f.description, f.category, f.geom, '[' || coalesce(group_concat(p.id, ', '), '') || ']'
|
err := sqlitex.Exec(conn, `select f.id, f.owner_id, f.name, f.properties, f.geom, '[' || coalesce(group_concat(p.id, ', '), '') || ']'
|
||||||
from features f
|
from features f
|
||||||
left join feature_photos p on f.id = p.feature_id
|
left join feature_photos p on f.id = p.feature_id
|
||||||
group by f.id, f.owner_id, f.name, f.description, f.category, f.geom`, func(stmt *sqlite.Stmt) error {
|
group by f.id, f.owner_id, f.name, f.properties, f.geom`, func(stmt *sqlite.Stmt) error {
|
||||||
|
|
||||||
id := stmt.ColumnInt64(0)
|
id := stmt.ColumnInt64(0)
|
||||||
|
|
||||||
@ -288,24 +288,21 @@ func (s *Server) getFeatures(conn *sqlite.Conn) ([]models.Feature, error) {
|
|||||||
|
|
||||||
name := stmt.ColumnText(2)
|
name := stmt.ColumnText(2)
|
||||||
|
|
||||||
var description *string
|
propertiesRaw := stmt.ColumnText(3)
|
||||||
if stmt.ColumnType(3) != sqlite.SQLITE_NULL {
|
var properties map[string]interface{}
|
||||||
description = ptrString(stmt.ColumnText(3))
|
err := json.Unmarshal([]byte(propertiesRaw), &properties)
|
||||||
}
|
|
||||||
|
|
||||||
var category *string
|
|
||||||
if stmt.ColumnType(4) != sqlite.SQLITE_NULL {
|
|
||||||
category = ptrString(stmt.ColumnText(4))
|
|
||||||
}
|
|
||||||
|
|
||||||
geomRaw := stmt.ColumnText(5)
|
|
||||||
var geom geojson.Geometry
|
|
||||||
err := json.Unmarshal([]byte(geomRaw), &geom)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to parse geometry for point id=%d: %w", id, err)
|
return fmt.Errorf("failed to parse properties for feature id=%d: %w", id, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
photosRaw := stmt.ColumnText(6)
|
geomRaw := stmt.ColumnText(4)
|
||||||
|
var geom geojson.Geometry
|
||||||
|
err = json.Unmarshal([]byte(geomRaw), &geom)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to parse geometry for feature id=%d: %w", id, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
photosRaw := stmt.ColumnText(5)
|
||||||
var photos []models.FeaturePhotoID
|
var photos []models.FeaturePhotoID
|
||||||
err = json.Unmarshal([]byte(photosRaw), &photos)
|
err = json.Unmarshal([]byte(photosRaw), &photos)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -313,13 +310,12 @@ func (s *Server) getFeatures(conn *sqlite.Conn) ([]models.Feature, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
feature := models.Feature{
|
feature := models.Feature{
|
||||||
ID: models.FeatureID(id),
|
ID: models.FeatureID(id),
|
||||||
OwnerID: (*models.UserID)(ownerID),
|
OwnerID: (*models.UserID)(ownerID),
|
||||||
Name: name,
|
Name: name,
|
||||||
Description: description,
|
Properties: properties,
|
||||||
Category: category,
|
Geometry: geom,
|
||||||
Geometry: geom,
|
PhotoIDs: photos,
|
||||||
PhotoIDs: photos,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
features = append(features, feature)
|
features = append(features, feature)
|
||||||
@ -332,7 +328,7 @@ func (s *Server) getFeatures(conn *sqlite.Conn) ([]models.Feature, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) addFeatures(conn *sqlite.Conn, features []models.Feature) (map[models.FeatureID]models.FeatureID, error) {
|
func (s *Server) addFeatures(conn *sqlite.Conn, features []models.Feature) (map[models.FeatureID]models.FeatureID, error) {
|
||||||
stmt, err := conn.Prepare("insert into features(owner_id, name, description, category, geom) values(?, ?, ?, ?, ?)")
|
stmt, err := conn.Prepare("insert into features(owner_id, name, properties, geom) values(?, ?, ?, ?)")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to prepare statement: %w", err)
|
return nil, fmt.Errorf("failed to prepare statement: %w", err)
|
||||||
}
|
}
|
||||||
@ -357,22 +353,24 @@ func (s *Server) addFeatures(conn *sqlite.Conn, features []models.Feature) (map[
|
|||||||
} else {
|
} else {
|
||||||
stmt.BindInt64(1, int64(*feature.OwnerID))
|
stmt.BindInt64(1, int64(*feature.OwnerID))
|
||||||
}
|
}
|
||||||
|
|
||||||
stmt.BindText(2, feature.Name)
|
stmt.BindText(2, feature.Name)
|
||||||
if feature.Description == nil {
|
|
||||||
stmt.BindNull(3)
|
if feature.Properties == nil {
|
||||||
|
stmt.BindText(3, "{}")
|
||||||
} else {
|
} else {
|
||||||
stmt.BindText(3, *feature.Description)
|
propertiesBytes, err := json.Marshal(feature.Properties)
|
||||||
}
|
if err != nil {
|
||||||
if feature.Category == nil {
|
return nil, fmt.Errorf("failed to marshal properties of feature id=%d: %w", feature.ID, err)
|
||||||
stmt.BindNull(4)
|
}
|
||||||
} else {
|
stmt.BindText(3, string(propertiesBytes))
|
||||||
stmt.BindText(4, *feature.Category)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
geomBytes, err := json.Marshal(feature.Geometry)
|
geomBytes, err := json.Marshal(feature.Geometry)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to marshal geometry of feature ID %d: %w", feature.ID, err)
|
return nil, fmt.Errorf("failed to marshal geometry of feature id=%d: %w", feature.ID, err)
|
||||||
}
|
}
|
||||||
stmt.BindText(5, string(geomBytes))
|
stmt.BindText(4, string(geomBytes))
|
||||||
|
|
||||||
_, err = stmt.Step()
|
_, err = stmt.Step()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -457,7 +455,7 @@ func (s *Server) addPhotos(conn *sqlite.Conn, createdFeatureMapping, addedFeatur
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) updateFeatures(conn *sqlite.Conn, features []models.Feature) error {
|
func (s *Server) updateFeatures(conn *sqlite.Conn, features []models.Feature) error {
|
||||||
stmt, err := conn.Prepare("update features set owner_id = ?, name = ?, description = ?, category = ?, geom = ? where id = ?")
|
stmt, err := conn.Prepare("update features set owner_id = ?, name = ?, properties = ?, geom = ? where id = ?")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to prepare statement: %w", err)
|
return fmt.Errorf("failed to prepare statement: %w", err)
|
||||||
}
|
}
|
||||||
@ -478,23 +476,26 @@ func (s *Server) updateFeatures(conn *sqlite.Conn, features []models.Feature) er
|
|||||||
} else {
|
} else {
|
||||||
stmt.BindInt64(1, int64(*feature.OwnerID))
|
stmt.BindInt64(1, int64(*feature.OwnerID))
|
||||||
}
|
}
|
||||||
|
|
||||||
stmt.BindText(2, feature.Name)
|
stmt.BindText(2, feature.Name)
|
||||||
if feature.Description == nil {
|
|
||||||
stmt.BindNull(3)
|
if feature.Properties == nil {
|
||||||
|
stmt.BindText(3, "{}")
|
||||||
} else {
|
} else {
|
||||||
stmt.BindText(3, *feature.Description)
|
propertiesBytes, err := json.Marshal(feature.Properties)
|
||||||
}
|
if err != nil {
|
||||||
if feature.Category == nil {
|
return fmt.Errorf("failed to marshal properties of feature id=%d: %w", feature.ID, err)
|
||||||
stmt.BindNull(4)
|
}
|
||||||
} else {
|
stmt.BindText(3, string(propertiesBytes))
|
||||||
stmt.BindText(4, *feature.Category)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
geomBytes, err := json.Marshal(feature.Geometry)
|
geomBytes, err := json.Marshal(feature.Geometry)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to marshal geometry of feature ID %d: %w", feature.ID, err)
|
return fmt.Errorf("failed to marshal geometry of feature ID %d: %w", feature.ID, err)
|
||||||
}
|
}
|
||||||
stmt.BindText(5, string(geomBytes))
|
stmt.BindText(4, string(geomBytes))
|
||||||
stmt.BindInt64(6, int64(feature.ID))
|
|
||||||
|
stmt.BindInt64(5, int64(feature.ID))
|
||||||
|
|
||||||
_, err = stmt.Step()
|
_, err = stmt.Step()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
Loading…
Reference in New Issue
Block a user