UPDATE: Submission module
All checks were successful
Build and Release / release (push) Successful in 1m14s
All checks were successful
Build and Release / release (push) Successful in 1m14s
This commit is contained in:
@@ -1,9 +1,7 @@
|
||||
package request
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
type CreateCommitDto struct {
|
||||
SnapshotJson json.RawMessage `json:"snapshot_json" validate:"required"`
|
||||
SnapshotJson *CommitSnapshot `json:"snapshot_json" validate:"required"`
|
||||
EditSummary string `json:"edit_summary" validate:"required,max=500"`
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
package request
|
||||
|
||||
type SearchEntityDto struct {
|
||||
Cursor string `json:"cursor" query:"cursor" validate:"omitempty,uuid"`
|
||||
Limit int `json:"limit" query:"limit" validate:"omitempty,min=1,max=100"`
|
||||
Name string `json:"name" query:"name" validate:"omitempty,max=255"`
|
||||
Cursor string `json:"cursor" query:"cursor" validate:"omitempty,uuid"`
|
||||
Limit int `json:"limit" query:"limit" validate:"omitempty,min=1,max=100"`
|
||||
Name string `json:"name" query:"name" validate:"omitempty,max=255"`
|
||||
ProjectID *string `json:"project_id" query:"project_id" validate:"omitempty,uuid"`
|
||||
}
|
||||
|
||||
@@ -7,4 +7,5 @@ type SearchGeometryDto struct {
|
||||
MaxLat *float64 `json:"max_lat" query:"max_lat" validate:"required,gte=-90,lte=90"`
|
||||
TimePoint *int32 `json:"time" query:"time" validate:"omitempty,number"`
|
||||
EntityID *string `json:"entity_id" query:"entity_id" validate:"omitempty,uuid"`
|
||||
ProjectID *string `json:"project_id" query:"project_id" validate:"omitempty,uuid"`
|
||||
}
|
||||
|
||||
@@ -3,73 +3,63 @@ package request
|
||||
import "encoding/json"
|
||||
|
||||
type CommitSnapshot struct {
|
||||
SchemaVersion int `json:"schema_version" validate:"required"`
|
||||
Section SectionRef `json:"section" validate:"required"`
|
||||
EditorFeatureCollection *FeatureCollection `json:"editor_feature_collection,omitempty" validate:"omitempty"`
|
||||
Entities []EntitySnapshot `json:"entities,omitempty" validate:"omitempty,dive"`
|
||||
Geometries []GeometrySnapshot `json:"geometries,omitempty" validate:"omitempty,dive"`
|
||||
LinkScopes []LinkScopeSnapshot `json:"link_scopes,omitempty" validate:"omitempty,dive"`
|
||||
Wikis []WikiSnapshot `json:"wikis,omitempty" validate:"omitempty,dive"`
|
||||
EntityWikis []EntityWikiLinkSnapshot `json:"entity_wikis,omitempty" validate:"omitempty,dive"`
|
||||
}
|
||||
|
||||
|
||||
type SectionRef struct {
|
||||
ID string `json:"id" validate:"required"`
|
||||
Title string `json:"title" validate:"required"`
|
||||
EditorFeatureCollection *FeatureCollection `json:"editor_feature_collection,omitempty" validate:"omitempty"`
|
||||
Entities []*EntitySnapshot `json:"entities,omitempty" validate:"omitempty,dive"`
|
||||
Geometries []*GeometrySnapshot `json:"geometries,omitempty" validate:"omitempty,dive"`
|
||||
Wikis []*WikiSnapshot `json:"wikis,omitempty" validate:"omitempty,dive"`
|
||||
GeometryEntity []*GeometryEntitySnapshot `json:"geometry_entity,omitempty" validate:"omitempty,dive"`
|
||||
EntityWiki []*EntityWikiLinkSnapshot `json:"entity_wiki,omitempty" validate:"omitempty,dive"`
|
||||
EntityWikis []*EntityWikiLinkSnapshot `json:"entity_wikis,omitempty" validate:"omitempty,dive"`
|
||||
}
|
||||
|
||||
type FeatureCollection struct {
|
||||
Type string `json:"type" validate:"required,eq=FeatureCollection"`
|
||||
Features []Feature `json:"features" validate:"required,dive"`
|
||||
Type string `json:"type" validate:"required,eq=FeatureCollection"`
|
||||
Features []*Feature `json:"features" validate:"required,dive"`
|
||||
}
|
||||
|
||||
type Feature struct {
|
||||
Type string `json:"type" validate:"required,eq=Feature"`
|
||||
Properties FeatureProperties `json:"properties" validate:"required"`
|
||||
Geometry json.RawMessage `json:"geometry" validate:"required"`
|
||||
Type string `json:"type" validate:"required,eq=Feature"`
|
||||
Properties *FeatureProperties `json:"properties" validate:"required"`
|
||||
Geometry json.RawMessage `json:"geometry" validate:"required"`
|
||||
}
|
||||
|
||||
type FeatureProperties struct {
|
||||
ID any `json:"id" validate:"required"`
|
||||
Type string `json:"type,omitempty"`
|
||||
TimeStart *float64 `json:"time_start,omitempty"`
|
||||
TimeEnd *float64 `json:"time_end,omitempty"`
|
||||
Binding []string `json:"binding,omitempty"`
|
||||
EntityID string `json:"entity_id,omitempty"`
|
||||
EntityIDs []string `json:"entity_ids,omitempty"`
|
||||
EntityName string `json:"entity_name,omitempty"`
|
||||
EntityNames []string `json:"entity_names,omitempty"`
|
||||
EntityTypeID string `json:"entity_type_id,omitempty"`
|
||||
ID any `json:"id" validate:"required"`
|
||||
Type string `json:"type,omitempty"`
|
||||
GeometryPreset string `json:"geometry_preset,omitempty"`
|
||||
TimeStart *float64 `json:"time_start,omitempty"`
|
||||
TimeEnd *float64 `json:"time_end,omitempty"`
|
||||
Binding []string `json:"binding,omitempty"`
|
||||
EntityID string `json:"entity_id,omitempty" validate:"omitempty,uuidv7"`
|
||||
EntityIDs []string `json:"entity_ids,omitempty" validate:"omitempty,dive,uuidv7"`
|
||||
EntityName string `json:"entity_name,omitempty"`
|
||||
EntityNames []string `json:"entity_names,omitempty"`
|
||||
EntityTypeID string `json:"entity_type_id,omitempty" validate:"omitempty,uuidv7"`
|
||||
}
|
||||
|
||||
type EntitySnapshot struct {
|
||||
ID string `json:"id" validate:"required"`
|
||||
Source string `json:"source,omitempty" validate:"omitempty,oneof=inline ref"`
|
||||
Ref *Ref `json:"ref,omitempty" validate:"omitempty"`
|
||||
Operation string `json:"operation,omitempty" validate:"omitempty,oneof=create update delete reference"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Slug string `json:"slug,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
TypeID string `json:"type_id,omitempty"`
|
||||
Status *int `json:"status,omitempty" validate:"omitempty,oneof=0 1"`
|
||||
IsDeleted *int `json:"is_deleted,omitempty" validate:"omitempty,oneof=0 1"`
|
||||
BaseUpdatedAt string `json:"base_updated_at,omitempty"`
|
||||
BaseHash string `json:"base_hash,omitempty"`
|
||||
ID string `json:"id" validate:"required,uuidv7"`
|
||||
Source string `json:"source,omitempty" validate:"omitempty,oneof=inline ref"`
|
||||
Operation string `json:"operation,omitempty" validate:"omitempty,oneof=create update delete reference"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Slug *string `json:"slug,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
TypeID string `json:"type_id,omitempty"`
|
||||
Status *int `json:"status,omitempty" validate:"omitempty,oneof=0 1"`
|
||||
BaseUpdatedAt string `json:"base_updated_at,omitempty"`
|
||||
BaseHash string `json:"base_hash,omitempty"`
|
||||
}
|
||||
|
||||
type GeometrySnapshot struct {
|
||||
ID string `json:"id" validate:"required"`
|
||||
ID string `json:"id" validate:"required,uuidv7"`
|
||||
Source string `json:"source,omitempty" validate:"omitempty,oneof=inline ref"`
|
||||
Ref *Ref `json:"ref,omitempty" validate:"omitempty"`
|
||||
Operation string `json:"operation,omitempty" validate:"omitempty,oneof=create update delete reference"`
|
||||
Type string `json:"type,omitempty"`
|
||||
Type string `json:"type" validate:"required"`
|
||||
DrawGeometry json.RawMessage `json:"draw_geometry,omitempty"`
|
||||
Binding []string `json:"binding,omitempty"`
|
||||
TimeStart *float64 `json:"time_start,omitempty"`
|
||||
TimeEnd *float64 `json:"time_end,omitempty"`
|
||||
BBox *BBox `json:"bbox,omitempty" validate:"omitempty"`
|
||||
IsDeleted *int `json:"is_deleted,omitempty" validate:"omitempty,oneof=0 1"`
|
||||
BaseUpdatedAt string `json:"base_updated_at,omitempty"`
|
||||
BaseHash string `json:"base_hash,omitempty"`
|
||||
}
|
||||
@@ -81,31 +71,26 @@ type BBox struct {
|
||||
MaxLat float64 `json:"max_lat" validate:"required"`
|
||||
}
|
||||
|
||||
type LinkScopeSnapshot struct {
|
||||
GeometryID string `json:"geometry_id" validate:"required"`
|
||||
Operation string `json:"operation" validate:"required,eq=reference"` // Theo doc chỉ có "reference"
|
||||
EntityIDs []string `json:"entity_ids" validate:"required,min=1"` // Đã link thì phải có ít nhất 1 entity
|
||||
BaseLinksHash string `json:"base_links_hash,omitempty"`
|
||||
type GeometryEntitySnapshot struct {
|
||||
GeometryID string `json:"geometry_id" validate:"required,uuidv7"`
|
||||
EntityID string `json:"entity_id" validate:"required,uuidv7"`
|
||||
BaseLinksHash string `json:"base_links_hash,omitempty"`
|
||||
}
|
||||
|
||||
type WikiSnapshot struct {
|
||||
ID string `json:"id" validate:"required"`
|
||||
ID string `json:"id" validate:"required,uuidv7"`
|
||||
Source string `json:"source,omitempty" validate:"omitempty,oneof=inline ref"`
|
||||
Ref *Ref `json:"ref,omitempty" validate:"omitempty"`
|
||||
Operation string `json:"operation,omitempty" validate:"omitempty,oneof=create update delete reference"`
|
||||
Title string `json:"title" validate:"required"`
|
||||
Doc json.RawMessage `json:"doc,omitempty"`
|
||||
UpdatedAt string `json:"updated_at,omitempty"`
|
||||
IsDeleted *int `json:"is_deleted,omitempty" validate:"omitempty,oneof=0 1"`
|
||||
}
|
||||
|
||||
type EntityWikiLinkSnapshot struct {
|
||||
EntityID string `json:"entity_id" validate:"required"`
|
||||
WikiID string `json:"wiki_id" validate:"required"`
|
||||
EntityID string `json:"entity_id" validate:"required,uuidv7"`
|
||||
WikiID string `json:"wiki_id" validate:"required,uuidv7"`
|
||||
Operation string `json:"operation,omitempty" validate:"omitempty,oneof=reference delete"`
|
||||
IsDeleted *int `json:"is_deleted,omitempty" validate:"omitempty,oneof=0 1"`
|
||||
}
|
||||
|
||||
type Ref struct {
|
||||
ID string `json:"id" validate:"required"`
|
||||
}
|
||||
// Legacy / Compatibility
|
||||
IsDeleted *int `json:"is_deleted,omitempty" validate:"omitempty,oneof=0 1"`
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
package request
|
||||
|
||||
type SearchWikiDto struct {
|
||||
Cursor string `json:"cursor" query:"cursor" validate:"omitempty,uuid"`
|
||||
Limit int `json:"limit" query:"limit" validate:"omitempty,min=1,max=100"`
|
||||
Title string `json:"title" query:"title" validate:"omitempty,max=1000"`
|
||||
EntityID string `json:"entity_id" query:"entity_id" validate:"omitempty,uuid"`
|
||||
Cursor string `json:"cursor" query:"cursor" validate:"omitempty,uuid"`
|
||||
ProjectID *string `json:"project_id" query:"project_id" validate:"omitempty,uuid"`
|
||||
Limit int `json:"limit" query:"limit" validate:"omitempty,min=1,max=100"`
|
||||
Title string `json:"title" query:"title" validate:"omitempty,max=1000"`
|
||||
EntityID string `json:"entity_id" query:"entity_id" validate:"omitempty,uuid"`
|
||||
}
|
||||
|
||||
@@ -5,9 +5,11 @@ import "time"
|
||||
type EntityResponse struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Slug string `json:"slug,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
ThumbnailUrl string `json:"thumbnail_url,omitempty"`
|
||||
IsDeleted bool `json:"is_deleted"`
|
||||
CreatedAt *time.Time `json:"created_at"`
|
||||
UpdatedAt *time.Time `json:"updated_at"`
|
||||
ProjectID string `json:"project_id"`
|
||||
Status *int16 `json:"status,omitempty"`
|
||||
IsDeleted bool `json:"is_deleted,omitempty"`
|
||||
CreatedAt *time.Time `json:"created_at,omitempty"`
|
||||
UpdatedAt *time.Time `json:"updated_at,omitempty"`
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ type GeometryResponse struct {
|
||||
TimeStart int32 `json:"time_start,omitempty"`
|
||||
TimeEnd int32 `json:"time_end,omitempty"`
|
||||
Bbox *Bbox `json:"bbox,omitempty"`
|
||||
ProjectID string `json:"project_id"`
|
||||
IsDeleted bool `json:"is_deleted,omitempty"`
|
||||
CreatedAt *time.Time `json:"created_at,omitempty"`
|
||||
UpdatedAt *time.Time `json:"updated_at,omitempty"`
|
||||
|
||||
@@ -14,19 +14,24 @@ type MemberSimpleResponse struct {
|
||||
AvatarUrl string `json:"avatar_url"`
|
||||
}
|
||||
|
||||
type ProjectResponse struct {
|
||||
ID string `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
LatestCommitID *string `json:"latest_commit_id,omitempty"`
|
||||
ProjectStatus string `json:"project_status"`
|
||||
LockedBy *string `json:"locked_by,omitempty"`
|
||||
IsDeleted bool `json:"is_deleted"`
|
||||
UserID string `json:"user_id"`
|
||||
CreatedAt *time.Time `json:"created_at"`
|
||||
UpdatedAt *time.Time `json:"updated_at"`
|
||||
User *UserSimpleResponse `json:"user,omitempty"`
|
||||
Commits []CommitSimpleResponse `json:"commits"`
|
||||
SubmissionIds []string `json:"submission_ids"`
|
||||
Members []MemberSimpleResponse `json:"members"`
|
||||
type SubmissionSimpleResponse struct {
|
||||
ID string `json:"id"`
|
||||
Status string `json:"status"`
|
||||
}
|
||||
|
||||
type ProjectResponse struct {
|
||||
ID string `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
LatestCommitID *string `json:"latest_commit_id,omitempty"`
|
||||
ProjectStatus string `json:"project_status"`
|
||||
LockedBy *string `json:"locked_by,omitempty"`
|
||||
IsDeleted bool `json:"is_deleted"`
|
||||
UserID string `json:"user_id"`
|
||||
CreatedAt *time.Time `json:"created_at"`
|
||||
UpdatedAt *time.Time `json:"updated_at"`
|
||||
User *UserSimpleResponse `json:"user,omitempty"`
|
||||
Commits []CommitSimpleResponse `json:"commits"`
|
||||
Submissions []SubmissionSimpleResponse `json:"submissions"`
|
||||
Members []MemberSimpleResponse `json:"members"`
|
||||
}
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
package response
|
||||
|
||||
import "time"
|
||||
import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
)
|
||||
|
||||
type WikiResponse struct {
|
||||
ID string `json:"id"`
|
||||
Title string `json:"title,omitempty"`
|
||||
Content string `json:"content,omitempty"`
|
||||
IsDeleted bool `json:"is_deleted,omitempty"`
|
||||
CreatedAt *time.Time `json:"created_at,omitempty"`
|
||||
UpdatedAt *time.Time `json:"updated_at,omitempty"`
|
||||
ID string `json:"id"`
|
||||
Title string `json:"title,omitempty"`
|
||||
Content json.RawMessage `json:"content,omitempty"`
|
||||
ProjectID string `json:"project_id"`
|
||||
IsDeleted bool `json:"is_deleted,omitempty"`
|
||||
CreatedAt *time.Time `json:"created_at,omitempty"`
|
||||
UpdatedAt *time.Time `json:"updated_at,omitempty"`
|
||||
}
|
||||
|
||||
@@ -204,3 +204,31 @@ func (q *Queries) SearchCommits(ctx context.Context, arg SearchCommitsParams) ([
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const updateCommitSnapshot = `-- name: UpdateCommitSnapshot :one
|
||||
UPDATE commits
|
||||
SET snapshot_json = $2
|
||||
WHERE id = $1
|
||||
RETURNING id, project_id, snapshot_json, snapshot_hash, user_id, edit_summary, is_deleted, created_at
|
||||
`
|
||||
|
||||
type UpdateCommitSnapshotParams struct {
|
||||
ID pgtype.UUID `json:"id"`
|
||||
SnapshotJson json.RawMessage `json:"snapshot_json"`
|
||||
}
|
||||
|
||||
func (q *Queries) UpdateCommitSnapshot(ctx context.Context, arg UpdateCommitSnapshotParams) (Commit, error) {
|
||||
row := q.db.QueryRow(ctx, updateCommitSnapshot, arg.ID, arg.SnapshotJson)
|
||||
var i Commit
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.ProjectID,
|
||||
&i.SnapshotJson,
|
||||
&i.SnapshotHash,
|
||||
&i.UserID,
|
||||
&i.EditSummary,
|
||||
&i.IsDeleted,
|
||||
&i.CreatedAt,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
@@ -13,27 +13,39 @@ import (
|
||||
|
||||
const createEntity = `-- name: CreateEntity :one
|
||||
INSERT INTO entities (
|
||||
name, description, thumbnail_url
|
||||
id, name, slug, description, project_id, status
|
||||
) VALUES (
|
||||
$1, $2, $3
|
||||
COALESCE($6::uuid, uuidv7()), $1, $2, $3, $4, $5
|
||||
)
|
||||
RETURNING id, name, description, thumbnail_url, is_deleted, created_at, updated_at
|
||||
RETURNING id, project_id, name, slug, description, status, is_deleted, created_at, updated_at
|
||||
`
|
||||
|
||||
type CreateEntityParams struct {
|
||||
Name string `json:"name"`
|
||||
Description pgtype.Text `json:"description"`
|
||||
ThumbnailUrl pgtype.Text `json:"thumbnail_url"`
|
||||
Name string `json:"name"`
|
||||
Slug pgtype.Text `json:"slug"`
|
||||
Description pgtype.Text `json:"description"`
|
||||
ProjectID pgtype.UUID `json:"project_id"`
|
||||
Status pgtype.Int2 `json:"status"`
|
||||
ID pgtype.UUID `json:"id"`
|
||||
}
|
||||
|
||||
func (q *Queries) CreateEntity(ctx context.Context, arg CreateEntityParams) (Entity, error) {
|
||||
row := q.db.QueryRow(ctx, createEntity, arg.Name, arg.Description, arg.ThumbnailUrl)
|
||||
row := q.db.QueryRow(ctx, createEntity,
|
||||
arg.Name,
|
||||
arg.Slug,
|
||||
arg.Description,
|
||||
arg.ProjectID,
|
||||
arg.Status,
|
||||
arg.ID,
|
||||
)
|
||||
var i Entity
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.ProjectID,
|
||||
&i.Name,
|
||||
&i.Slug,
|
||||
&i.Description,
|
||||
&i.ThumbnailUrl,
|
||||
&i.Status,
|
||||
&i.IsDeleted,
|
||||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
@@ -41,6 +53,17 @@ func (q *Queries) CreateEntity(ctx context.Context, arg CreateEntityParams) (Ent
|
||||
return i, err
|
||||
}
|
||||
|
||||
const deleteEntitiesByIDs = `-- name: DeleteEntitiesByIDs :exec
|
||||
UPDATE entities
|
||||
SET is_deleted = true
|
||||
WHERE id = ANY($1::uuid[])
|
||||
`
|
||||
|
||||
func (q *Queries) DeleteEntitiesByIDs(ctx context.Context, dollar_1 []pgtype.UUID) error {
|
||||
_, err := q.db.Exec(ctx, deleteEntitiesByIDs, dollar_1)
|
||||
return err
|
||||
}
|
||||
|
||||
const deleteEntity = `-- name: DeleteEntity :exec
|
||||
UPDATE entities
|
||||
SET
|
||||
@@ -54,7 +77,7 @@ func (q *Queries) DeleteEntity(ctx context.Context, id pgtype.UUID) error {
|
||||
}
|
||||
|
||||
const getEntitiesByIDs = `-- name: GetEntitiesByIDs :many
|
||||
SELECT id, name, description, thumbnail_url, is_deleted, created_at, updated_at FROM entities WHERE id = ANY($1::uuid[]) AND is_deleted = false
|
||||
SELECT id, project_id, name, slug, description, status, is_deleted, created_at, updated_at FROM entities WHERE id = ANY($1::uuid[]) AND is_deleted = false
|
||||
`
|
||||
|
||||
func (q *Queries) GetEntitiesByIDs(ctx context.Context, dollar_1 []pgtype.UUID) ([]Entity, error) {
|
||||
@@ -68,9 +91,47 @@ func (q *Queries) GetEntitiesByIDs(ctx context.Context, dollar_1 []pgtype.UUID)
|
||||
var i Entity
|
||||
if err := rows.Scan(
|
||||
&i.ID,
|
||||
&i.ProjectID,
|
||||
&i.Name,
|
||||
&i.Slug,
|
||||
&i.Description,
|
||||
&i.ThumbnailUrl,
|
||||
&i.Status,
|
||||
&i.IsDeleted,
|
||||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const getEntitiesByProjectId = `-- name: GetEntitiesByProjectId :many
|
||||
SELECT id, project_id, name, slug, description, status, is_deleted, created_at, updated_at
|
||||
FROM entities
|
||||
WHERE project_id = $1 AND is_deleted = false
|
||||
`
|
||||
|
||||
func (q *Queries) GetEntitiesByProjectId(ctx context.Context, projectID pgtype.UUID) ([]Entity, error) {
|
||||
rows, err := q.db.Query(ctx, getEntitiesByProjectId, projectID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
items := []Entity{}
|
||||
for rows.Next() {
|
||||
var i Entity
|
||||
if err := rows.Scan(
|
||||
&i.ID,
|
||||
&i.ProjectID,
|
||||
&i.Name,
|
||||
&i.Slug,
|
||||
&i.Description,
|
||||
&i.Status,
|
||||
&i.IsDeleted,
|
||||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
@@ -86,7 +147,7 @@ func (q *Queries) GetEntitiesByIDs(ctx context.Context, dollar_1 []pgtype.UUID)
|
||||
}
|
||||
|
||||
const getEntityById = `-- name: GetEntityById :one
|
||||
SELECT id, name, description, thumbnail_url, is_deleted, created_at, updated_at
|
||||
SELECT id, project_id, name, slug, description, status, is_deleted, created_at, updated_at
|
||||
FROM entities
|
||||
WHERE id = $1 AND is_deleted = false
|
||||
`
|
||||
@@ -96,9 +157,11 @@ func (q *Queries) GetEntityById(ctx context.Context, id pgtype.UUID) (Entity, er
|
||||
var i Entity
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.ProjectID,
|
||||
&i.Name,
|
||||
&i.Slug,
|
||||
&i.Description,
|
||||
&i.ThumbnailUrl,
|
||||
&i.Status,
|
||||
&i.IsDeleted,
|
||||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
@@ -107,23 +170,30 @@ func (q *Queries) GetEntityById(ctx context.Context, id pgtype.UUID) (Entity, er
|
||||
}
|
||||
|
||||
const searchEntities = `-- name: SearchEntities :many
|
||||
SELECT id, name, description, thumbnail_url, is_deleted, created_at, updated_at
|
||||
SELECT id, project_id, name, slug, description, status, is_deleted, created_at, updated_at
|
||||
FROM entities
|
||||
WHERE is_deleted = false
|
||||
AND name ILIKE '%' || $1::text || '%'
|
||||
AND ($2::uuid IS NULL OR id < $2::uuid)
|
||||
AND ($1::uuid IS NULL OR project_id = $1::uuid)
|
||||
AND name ILIKE '%' || $2::text || '%'
|
||||
AND ($3::uuid IS NULL OR id < $3::uuid)
|
||||
ORDER BY id DESC
|
||||
LIMIT $3
|
||||
LIMIT $4
|
||||
`
|
||||
|
||||
type SearchEntitiesParams struct {
|
||||
ProjectID pgtype.UUID `json:"project_id"`
|
||||
Name string `json:"name"`
|
||||
CursorID pgtype.UUID `json:"cursor_id"`
|
||||
LimitCount int32 `json:"limit_count"`
|
||||
}
|
||||
|
||||
func (q *Queries) SearchEntities(ctx context.Context, arg SearchEntitiesParams) ([]Entity, error) {
|
||||
rows, err := q.db.Query(ctx, searchEntities, arg.Name, arg.CursorID, arg.LimitCount)
|
||||
rows, err := q.db.Query(ctx, searchEntities,
|
||||
arg.ProjectID,
|
||||
arg.Name,
|
||||
arg.CursorID,
|
||||
arg.LimitCount,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -133,9 +203,11 @@ func (q *Queries) SearchEntities(ctx context.Context, arg SearchEntitiesParams)
|
||||
var i Entity
|
||||
if err := rows.Scan(
|
||||
&i.ID,
|
||||
&i.ProjectID,
|
||||
&i.Name,
|
||||
&i.Slug,
|
||||
&i.Description,
|
||||
&i.ThumbnailUrl,
|
||||
&i.Status,
|
||||
&i.IsDeleted,
|
||||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
@@ -154,32 +226,40 @@ const updateEntity = `-- name: UpdateEntity :one
|
||||
UPDATE entities
|
||||
SET
|
||||
name = COALESCE($1, name),
|
||||
description = COALESCE($2, description),
|
||||
thumbnail_url = COALESCE($3, thumbnail_url)
|
||||
WHERE id = $4 AND is_deleted = false
|
||||
RETURNING id, name, description, thumbnail_url, is_deleted, created_at, updated_at
|
||||
slug = COALESCE($2, slug),
|
||||
description = COALESCE($3, description),
|
||||
project_id = COALESCE($4, project_id),
|
||||
status = COALESCE($5, status)
|
||||
WHERE id = $6 AND is_deleted = false
|
||||
RETURNING id, project_id, name, slug, description, status, is_deleted, created_at, updated_at
|
||||
`
|
||||
|
||||
type UpdateEntityParams struct {
|
||||
Name pgtype.Text `json:"name"`
|
||||
Description pgtype.Text `json:"description"`
|
||||
ThumbnailUrl pgtype.Text `json:"thumbnail_url"`
|
||||
ID pgtype.UUID `json:"id"`
|
||||
Name pgtype.Text `json:"name"`
|
||||
Slug pgtype.Text `json:"slug"`
|
||||
Description pgtype.Text `json:"description"`
|
||||
ProjectID pgtype.UUID `json:"project_id"`
|
||||
Status pgtype.Int2 `json:"status"`
|
||||
ID pgtype.UUID `json:"id"`
|
||||
}
|
||||
|
||||
func (q *Queries) UpdateEntity(ctx context.Context, arg UpdateEntityParams) (Entity, error) {
|
||||
row := q.db.QueryRow(ctx, updateEntity,
|
||||
arg.Name,
|
||||
arg.Slug,
|
||||
arg.Description,
|
||||
arg.ThumbnailUrl,
|
||||
arg.ProjectID,
|
||||
arg.Status,
|
||||
arg.ID,
|
||||
)
|
||||
var i Entity
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.ProjectID,
|
||||
&i.Name,
|
||||
&i.Slug,
|
||||
&i.Description,
|
||||
&i.ThumbnailUrl,
|
||||
&i.Status,
|
||||
&i.IsDeleted,
|
||||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
|
||||
@@ -38,30 +38,42 @@ func (q *Queries) BulkDeleteEntityGeometriesByEntityId(ctx context.Context, enti
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const bulkDeleteEntityGeometriesByGeometryID = `-- name: BulkDeleteEntityGeometriesByGeometryID :exec
|
||||
DELETE FROM entity_geometries
|
||||
WHERE geometry_id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) BulkDeleteEntityGeometriesByGeometryID(ctx context.Context, geometryID pgtype.UUID) error {
|
||||
_, err := q.db.Exec(ctx, bulkDeleteEntityGeometriesByGeometryID, geometryID)
|
||||
return err
|
||||
}
|
||||
|
||||
const createEntityGeometries = `-- name: CreateEntityGeometries :exec
|
||||
INSERT INTO entity_geometries (
|
||||
entity_id, geometry_id
|
||||
entity_id, geometry_id, project_id
|
||||
)
|
||||
SELECT $1, unnest($2::uuid[])
|
||||
SELECT $1, unnest($3::uuid[]), $2
|
||||
ON CONFLICT DO NOTHING
|
||||
`
|
||||
|
||||
type CreateEntityGeometriesParams struct {
|
||||
EntityID pgtype.UUID `json:"entity_id"`
|
||||
ProjectID pgtype.UUID `json:"project_id"`
|
||||
GeometryIds []pgtype.UUID `json:"geometry_ids"`
|
||||
}
|
||||
|
||||
func (q *Queries) CreateEntityGeometries(ctx context.Context, arg CreateEntityGeometriesParams) error {
|
||||
_, err := q.db.Exec(ctx, createEntityGeometries, arg.EntityID, arg.GeometryIds)
|
||||
_, err := q.db.Exec(ctx, createEntityGeometries, arg.EntityID, arg.ProjectID, arg.GeometryIds)
|
||||
return err
|
||||
}
|
||||
|
||||
const createGeometry = `-- name: CreateGeometry :one
|
||||
INSERT INTO geometries (
|
||||
geo_type, draw_geometry, binding, time_start, time_end, bbox
|
||||
id, geo_type, draw_geometry, binding, time_start, time_end, bbox, project_id
|
||||
) VALUES (
|
||||
$1, $2, $3, $4, $5, ST_MakeEnvelope($6::float8, $7::float8, $8::float8, $9::float8, 4326)
|
||||
COALESCE($7::uuid, uuidv7()), $1, $2, $3, $4, $5, ST_MakeEnvelope($8::float8, $9::float8, $10::float8, $11::float8, 4326), $6
|
||||
)
|
||||
RETURNING id, geo_type, draw_geometry, binding, time_start, time_end,
|
||||
RETURNING id, geo_type, draw_geometry, binding, time_start, time_end, project_id,
|
||||
ST_XMin(bbox)::float8 as min_lng, ST_YMin(bbox)::float8 as min_lat, ST_XMax(bbox)::float8 as max_lng, ST_YMax(bbox)::float8 as max_lat,
|
||||
is_deleted, created_at, updated_at
|
||||
`
|
||||
@@ -72,6 +84,8 @@ type CreateGeometryParams struct {
|
||||
Binding []byte `json:"binding"`
|
||||
TimeStart pgtype.Int4 `json:"time_start"`
|
||||
TimeEnd pgtype.Int4 `json:"time_end"`
|
||||
ProjectID pgtype.UUID `json:"project_id"`
|
||||
ID pgtype.UUID `json:"id"`
|
||||
MinLng float64 `json:"min_lng"`
|
||||
MinLat float64 `json:"min_lat"`
|
||||
MaxLng float64 `json:"max_lng"`
|
||||
@@ -85,6 +99,7 @@ type CreateGeometryRow struct {
|
||||
Binding []byte `json:"binding"`
|
||||
TimeStart pgtype.Int4 `json:"time_start"`
|
||||
TimeEnd pgtype.Int4 `json:"time_end"`
|
||||
ProjectID pgtype.UUID `json:"project_id"`
|
||||
MinLng float64 `json:"min_lng"`
|
||||
MinLat float64 `json:"min_lat"`
|
||||
MaxLng float64 `json:"max_lng"`
|
||||
@@ -101,6 +116,8 @@ func (q *Queries) CreateGeometry(ctx context.Context, arg CreateGeometryParams)
|
||||
arg.Binding,
|
||||
arg.TimeStart,
|
||||
arg.TimeEnd,
|
||||
arg.ProjectID,
|
||||
arg.ID,
|
||||
arg.MinLng,
|
||||
arg.MinLat,
|
||||
arg.MaxLng,
|
||||
@@ -114,6 +131,7 @@ func (q *Queries) CreateGeometry(ctx context.Context, arg CreateGeometryParams)
|
||||
&i.Binding,
|
||||
&i.TimeStart,
|
||||
&i.TimeEnd,
|
||||
&i.ProjectID,
|
||||
&i.MinLng,
|
||||
&i.MinLat,
|
||||
&i.MaxLng,
|
||||
@@ -125,6 +143,42 @@ func (q *Queries) CreateGeometry(ctx context.Context, arg CreateGeometryParams)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const deleteEntityGeometriesByProjectID = `-- name: DeleteEntityGeometriesByProjectID :exec
|
||||
DELETE FROM entity_geometries
|
||||
WHERE project_id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) DeleteEntityGeometriesByProjectID(ctx context.Context, projectID pgtype.UUID) error {
|
||||
_, err := q.db.Exec(ctx, deleteEntityGeometriesByProjectID, projectID)
|
||||
return err
|
||||
}
|
||||
|
||||
const deleteEntityGeometry = `-- name: DeleteEntityGeometry :exec
|
||||
DELETE FROM entity_geometries
|
||||
WHERE entity_id = $1 AND geometry_id = $2
|
||||
`
|
||||
|
||||
type DeleteEntityGeometryParams struct {
|
||||
EntityID pgtype.UUID `json:"entity_id"`
|
||||
GeometryID pgtype.UUID `json:"geometry_id"`
|
||||
}
|
||||
|
||||
func (q *Queries) DeleteEntityGeometry(ctx context.Context, arg DeleteEntityGeometryParams) error {
|
||||
_, err := q.db.Exec(ctx, deleteEntityGeometry, arg.EntityID, arg.GeometryID)
|
||||
return err
|
||||
}
|
||||
|
||||
const deleteGeometriesByIDs = `-- name: DeleteGeometriesByIDs :exec
|
||||
UPDATE geometries
|
||||
SET is_deleted = true
|
||||
WHERE id = ANY($1::uuid[])
|
||||
`
|
||||
|
||||
func (q *Queries) DeleteGeometriesByIDs(ctx context.Context, dollar_1 []pgtype.UUID) error {
|
||||
_, err := q.db.Exec(ctx, deleteGeometriesByIDs, dollar_1)
|
||||
return err
|
||||
}
|
||||
|
||||
const deleteGeometry = `-- name: DeleteGeometry :exec
|
||||
UPDATE geometries
|
||||
SET
|
||||
@@ -139,7 +193,7 @@ func (q *Queries) DeleteGeometry(ctx context.Context, id pgtype.UUID) error {
|
||||
|
||||
const getGeometriesByIDs = `-- name: GetGeometriesByIDs :many
|
||||
SELECT
|
||||
id, geo_type, draw_geometry, binding, time_start, time_end,
|
||||
id, geo_type, draw_geometry, binding, time_start, time_end, project_id,
|
||||
ST_XMin(bbox)::float8 as min_lng,
|
||||
ST_YMin(bbox)::float8 as min_lat,
|
||||
ST_XMax(bbox)::float8 as max_lng,
|
||||
@@ -156,6 +210,7 @@ type GetGeometriesByIDsRow struct {
|
||||
Binding []byte `json:"binding"`
|
||||
TimeStart pgtype.Int4 `json:"time_start"`
|
||||
TimeEnd pgtype.Int4 `json:"time_end"`
|
||||
ProjectID pgtype.UUID `json:"project_id"`
|
||||
MinLng float64 `json:"min_lng"`
|
||||
MinLat float64 `json:"min_lat"`
|
||||
MaxLng float64 `json:"max_lng"`
|
||||
@@ -181,6 +236,71 @@ func (q *Queries) GetGeometriesByIDs(ctx context.Context, dollar_1 []pgtype.UUID
|
||||
&i.Binding,
|
||||
&i.TimeStart,
|
||||
&i.TimeEnd,
|
||||
&i.ProjectID,
|
||||
&i.MinLng,
|
||||
&i.MinLat,
|
||||
&i.MaxLng,
|
||||
&i.MaxLat,
|
||||
&i.IsDeleted,
|
||||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const getGeometriesByProjectId = `-- name: GetGeometriesByProjectId :many
|
||||
SELECT
|
||||
id, geo_type, draw_geometry, binding, time_start, time_end, project_id,
|
||||
ST_XMin(bbox)::float8 as min_lng,
|
||||
ST_YMin(bbox)::float8 as min_lat,
|
||||
ST_XMax(bbox)::float8 as max_lng,
|
||||
ST_YMax(bbox)::float8 as max_lat,
|
||||
is_deleted, created_at, updated_at
|
||||
FROM geometries
|
||||
WHERE project_id = $1 AND is_deleted = false
|
||||
`
|
||||
|
||||
type GetGeometriesByProjectIdRow struct {
|
||||
ID pgtype.UUID `json:"id"`
|
||||
GeoType int16 `json:"geo_type"`
|
||||
DrawGeometry json.RawMessage `json:"draw_geometry"`
|
||||
Binding []byte `json:"binding"`
|
||||
TimeStart pgtype.Int4 `json:"time_start"`
|
||||
TimeEnd pgtype.Int4 `json:"time_end"`
|
||||
ProjectID pgtype.UUID `json:"project_id"`
|
||||
MinLng float64 `json:"min_lng"`
|
||||
MinLat float64 `json:"min_lat"`
|
||||
MaxLng float64 `json:"max_lng"`
|
||||
MaxLat float64 `json:"max_lat"`
|
||||
IsDeleted bool `json:"is_deleted"`
|
||||
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
||||
}
|
||||
|
||||
func (q *Queries) GetGeometriesByProjectId(ctx context.Context, projectID pgtype.UUID) ([]GetGeometriesByProjectIdRow, error) {
|
||||
rows, err := q.db.Query(ctx, getGeometriesByProjectId, projectID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
items := []GetGeometriesByProjectIdRow{}
|
||||
for rows.Next() {
|
||||
var i GetGeometriesByProjectIdRow
|
||||
if err := rows.Scan(
|
||||
&i.ID,
|
||||
&i.GeoType,
|
||||
&i.DrawGeometry,
|
||||
&i.Binding,
|
||||
&i.TimeStart,
|
||||
&i.TimeEnd,
|
||||
&i.ProjectID,
|
||||
&i.MinLng,
|
||||
&i.MinLat,
|
||||
&i.MaxLng,
|
||||
@@ -200,7 +320,7 @@ func (q *Queries) GetGeometriesByIDs(ctx context.Context, dollar_1 []pgtype.UUID
|
||||
}
|
||||
|
||||
const getGeometryById = `-- name: GetGeometryById :one
|
||||
SELECT id, geo_type, draw_geometry, binding, time_start, time_end,
|
||||
SELECT id, geo_type, draw_geometry, binding, time_start, time_end, project_id,
|
||||
ST_XMin(bbox)::float8 as min_lng, ST_YMin(bbox)::float8 as min_lat, ST_XMax(bbox)::float8 as max_lng, ST_YMax(bbox)::float8 as max_lat,
|
||||
is_deleted, created_at, updated_at
|
||||
FROM geometries
|
||||
@@ -214,6 +334,7 @@ type GetGeometryByIdRow struct {
|
||||
Binding []byte `json:"binding"`
|
||||
TimeStart pgtype.Int4 `json:"time_start"`
|
||||
TimeEnd pgtype.Int4 `json:"time_end"`
|
||||
ProjectID pgtype.UUID `json:"project_id"`
|
||||
MinLng float64 `json:"min_lng"`
|
||||
MinLat float64 `json:"min_lat"`
|
||||
MaxLng float64 `json:"max_lng"`
|
||||
@@ -233,6 +354,7 @@ func (q *Queries) GetGeometryById(ctx context.Context, id pgtype.UUID) (GetGeome
|
||||
&i.Binding,
|
||||
&i.TimeStart,
|
||||
&i.TimeEnd,
|
||||
&i.ProjectID,
|
||||
&i.MinLng,
|
||||
&i.MinLat,
|
||||
&i.MaxLng,
|
||||
@@ -246,7 +368,7 @@ func (q *Queries) GetGeometryById(ctx context.Context, id pgtype.UUID) (GetGeome
|
||||
|
||||
const searchGeometries = `-- name: SearchGeometries :many
|
||||
SELECT
|
||||
g.id, g.geo_type, g.draw_geometry, g.binding, g.time_start, g.time_end,
|
||||
g.id, g.geo_type, g.draw_geometry, g.binding, g.time_start, g.time_end, g.project_id,
|
||||
ST_XMin(g.bbox)::float8 as min_lng,
|
||||
ST_YMin(g.bbox)::float8 as min_lat,
|
||||
ST_XMax(g.bbox)::float8 as max_lng,
|
||||
@@ -254,36 +376,38 @@ SELECT
|
||||
g.is_deleted, g.created_at, g.updated_at
|
||||
FROM geometries g
|
||||
WHERE g.is_deleted = false
|
||||
AND ($1::uuid IS NULL OR g.project_id = $1::uuid)
|
||||
AND (
|
||||
$1::float8 IS NULL OR
|
||||
$2::float8 IS NULL OR
|
||||
$3::float8 IS NULL OR
|
||||
$4::float8 IS NULL OR
|
||||
$5::float8 IS NULL OR
|
||||
g.bbox && ST_MakeEnvelope(
|
||||
$1::float8,
|
||||
$2::float8,
|
||||
$3::float8,
|
||||
$4::float8,
|
||||
$5::float8,
|
||||
4326
|
||||
)
|
||||
)
|
||||
AND (
|
||||
$5::int IS NULL OR
|
||||
(g.time_start <= $5::int AND g.time_end >= $5::int)
|
||||
$6::int IS NULL OR
|
||||
(g.time_start <= $6::int AND g.time_end >= $6::int)
|
||||
)
|
||||
AND (
|
||||
$6::uuid IS NULL OR
|
||||
$7::uuid IS NULL OR
|
||||
EXISTS (
|
||||
SELECT 1
|
||||
FROM entity_geometries eg
|
||||
WHERE eg.geometry_id = g.id
|
||||
AND eg.entity_id = $6::uuid
|
||||
AND eg.entity_id = $7::uuid
|
||||
)
|
||||
)
|
||||
ORDER BY g.id DESC
|
||||
`
|
||||
|
||||
type SearchGeometriesParams struct {
|
||||
ProjectID pgtype.UUID `json:"project_id"`
|
||||
SearchMinLng pgtype.Float8 `json:"search_min_lng"`
|
||||
SearchMinLat pgtype.Float8 `json:"search_min_lat"`
|
||||
SearchMaxLng pgtype.Float8 `json:"search_max_lng"`
|
||||
@@ -299,6 +423,7 @@ type SearchGeometriesRow struct {
|
||||
Binding []byte `json:"binding"`
|
||||
TimeStart pgtype.Int4 `json:"time_start"`
|
||||
TimeEnd pgtype.Int4 `json:"time_end"`
|
||||
ProjectID pgtype.UUID `json:"project_id"`
|
||||
MinLng float64 `json:"min_lng"`
|
||||
MinLat float64 `json:"min_lat"`
|
||||
MaxLng float64 `json:"max_lng"`
|
||||
@@ -310,6 +435,7 @@ type SearchGeometriesRow struct {
|
||||
|
||||
func (q *Queries) SearchGeometries(ctx context.Context, arg SearchGeometriesParams) ([]SearchGeometriesRow, error) {
|
||||
rows, err := q.db.Query(ctx, searchGeometries,
|
||||
arg.ProjectID,
|
||||
arg.SearchMinLng,
|
||||
arg.SearchMinLat,
|
||||
arg.SearchMaxLng,
|
||||
@@ -331,6 +457,7 @@ func (q *Queries) SearchGeometries(ctx context.Context, arg SearchGeometriesPara
|
||||
&i.Binding,
|
||||
&i.TimeStart,
|
||||
&i.TimeEnd,
|
||||
&i.ProjectID,
|
||||
&i.MinLng,
|
||||
&i.MinLat,
|
||||
&i.MaxLng,
|
||||
@@ -357,14 +484,15 @@ SET
|
||||
binding = COALESCE($3, binding),
|
||||
time_start = COALESCE($4, time_start),
|
||||
time_end = COALESCE($5, time_end),
|
||||
project_id = COALESCE($6, project_id),
|
||||
bbox = CASE
|
||||
WHEN $6::boolean = true THEN
|
||||
ST_MakeEnvelope($7::float8, $8::float8, $9::float8, $10::float8, 4326)
|
||||
WHEN $7::boolean = true THEN
|
||||
ST_MakeEnvelope($8::float8, $9::float8, $10::float8, $11::float8, 4326)
|
||||
ELSE bbox
|
||||
END,
|
||||
updated_at = now()
|
||||
WHERE id = $11 AND is_deleted = false
|
||||
RETURNING id, geo_type, draw_geometry, binding, time_start, time_end,
|
||||
WHERE id = $12 AND is_deleted = false
|
||||
RETURNING id, geo_type, draw_geometry, binding, time_start, time_end, project_id,
|
||||
ST_XMin(bbox)::float8 as min_lng, ST_YMin(bbox)::float8 as min_lat, ST_XMax(bbox)::float8 as max_lng, ST_YMax(bbox)::float8 as max_lat,
|
||||
is_deleted, created_at, updated_at
|
||||
`
|
||||
@@ -375,6 +503,7 @@ type UpdateGeometryParams struct {
|
||||
Binding []byte `json:"binding"`
|
||||
TimeStart pgtype.Int4 `json:"time_start"`
|
||||
TimeEnd pgtype.Int4 `json:"time_end"`
|
||||
ProjectID pgtype.UUID `json:"project_id"`
|
||||
UpdateBbox pgtype.Bool `json:"update_bbox"`
|
||||
MinLng pgtype.Float8 `json:"min_lng"`
|
||||
MinLat pgtype.Float8 `json:"min_lat"`
|
||||
@@ -390,6 +519,7 @@ type UpdateGeometryRow struct {
|
||||
Binding []byte `json:"binding"`
|
||||
TimeStart pgtype.Int4 `json:"time_start"`
|
||||
TimeEnd pgtype.Int4 `json:"time_end"`
|
||||
ProjectID pgtype.UUID `json:"project_id"`
|
||||
MinLng float64 `json:"min_lng"`
|
||||
MinLat float64 `json:"min_lat"`
|
||||
MaxLng float64 `json:"max_lng"`
|
||||
@@ -406,6 +536,7 @@ func (q *Queries) UpdateGeometry(ctx context.Context, arg UpdateGeometryParams)
|
||||
arg.Binding,
|
||||
arg.TimeStart,
|
||||
arg.TimeEnd,
|
||||
arg.ProjectID,
|
||||
arg.UpdateBbox,
|
||||
arg.MinLng,
|
||||
arg.MinLat,
|
||||
@@ -421,6 +552,7 @@ func (q *Queries) UpdateGeometry(ctx context.Context, arg UpdateGeometryParams)
|
||||
&i.Binding,
|
||||
&i.TimeStart,
|
||||
&i.TimeEnd,
|
||||
&i.ProjectID,
|
||||
&i.MinLng,
|
||||
&i.MinLat,
|
||||
&i.MaxLng,
|
||||
|
||||
@@ -22,23 +22,27 @@ type Commit struct {
|
||||
}
|
||||
|
||||
type Entity struct {
|
||||
ID pgtype.UUID `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Description pgtype.Text `json:"description"`
|
||||
ThumbnailUrl pgtype.Text `json:"thumbnail_url"`
|
||||
IsDeleted bool `json:"is_deleted"`
|
||||
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
||||
ID pgtype.UUID `json:"id"`
|
||||
ProjectID pgtype.UUID `json:"project_id"`
|
||||
Name string `json:"name"`
|
||||
Slug pgtype.Text `json:"slug"`
|
||||
Description pgtype.Text `json:"description"`
|
||||
Status pgtype.Int2 `json:"status"`
|
||||
IsDeleted bool `json:"is_deleted"`
|
||||
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
||||
}
|
||||
|
||||
type EntityGeometry struct {
|
||||
EntityID pgtype.UUID `json:"entity_id"`
|
||||
GeometryID pgtype.UUID `json:"geometry_id"`
|
||||
ProjectID pgtype.UUID `json:"project_id"`
|
||||
}
|
||||
|
||||
type EntityWiki struct {
|
||||
EntityID pgtype.UUID `json:"entity_id"`
|
||||
WikiID pgtype.UUID `json:"wiki_id"`
|
||||
EntityID pgtype.UUID `json:"entity_id"`
|
||||
WikiID pgtype.UUID `json:"wiki_id"`
|
||||
ProjectID pgtype.UUID `json:"project_id"`
|
||||
}
|
||||
|
||||
type Geometry struct {
|
||||
@@ -49,6 +53,7 @@ type Geometry struct {
|
||||
TimeStart pgtype.Int4 `json:"time_start"`
|
||||
TimeEnd pgtype.Int4 `json:"time_end"`
|
||||
Bbox interface{} `json:"bbox"`
|
||||
ProjectID pgtype.UUID `json:"project_id"`
|
||||
IsDeleted bool `json:"is_deleted"`
|
||||
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
||||
@@ -161,8 +166,9 @@ type VerificationMedia struct {
|
||||
|
||||
type Wiki struct {
|
||||
ID pgtype.UUID `json:"id"`
|
||||
ProjectID pgtype.UUID `json:"project_id"`
|
||||
Title pgtype.Text `json:"title"`
|
||||
Content pgtype.Text `json:"content"`
|
||||
Content []byte `json:"content"`
|
||||
IsDeleted bool `json:"is_deleted"`
|
||||
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
||||
|
||||
@@ -136,7 +136,7 @@ SELECT
|
||||
'avatar_url', up.avatar_url
|
||||
)::json AS user,
|
||||
'[]'::json AS commits,
|
||||
'{}'::uuid[] AS submission_ids,
|
||||
'[]'::json AS submissions,
|
||||
'[]'::json AS members
|
||||
FROM inserted_project p
|
||||
JOIN users u ON p.user_id = u.id
|
||||
@@ -163,7 +163,7 @@ type CreateProjectRow struct {
|
||||
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
||||
User []byte `json:"user"`
|
||||
Commits []byte `json:"commits"`
|
||||
SubmissionIds []pgtype.UUID `json:"submission_ids"`
|
||||
Submissions []byte `json:"submissions"`
|
||||
Members []byte `json:"members"`
|
||||
}
|
||||
|
||||
@@ -188,7 +188,7 @@ func (q *Queries) CreateProject(ctx context.Context, arg CreateProjectParams) (C
|
||||
&i.UpdatedAt,
|
||||
&i.User,
|
||||
&i.Commits,
|
||||
&i.SubmissionIds,
|
||||
&i.Submissions,
|
||||
&i.Members,
|
||||
)
|
||||
return i, err
|
||||
@@ -215,9 +215,9 @@ SELECT
|
||||
'[]'
|
||||
)::json AS commits,
|
||||
COALESCE(
|
||||
(SELECT array_agg(id) FROM submissions WHERE project_id = p.id),
|
||||
'{}'
|
||||
)::uuid[] AS submission_ids,
|
||||
(SELECT json_agg(json_build_object('id', s.id, 'status', s.status)) FROM submissions s WHERE s.project_id = p.id),
|
||||
'[]'
|
||||
)::json AS submissions,
|
||||
json_build_object(
|
||||
'id', u.id,
|
||||
'email', u.email,
|
||||
@@ -254,7 +254,7 @@ type GetProjectByIdRow struct {
|
||||
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
||||
Commits []byte `json:"commits"`
|
||||
SubmissionIds []pgtype.UUID `json:"submission_ids"`
|
||||
Submissions []byte `json:"submissions"`
|
||||
User []byte `json:"user"`
|
||||
Members []byte `json:"members"`
|
||||
}
|
||||
@@ -274,7 +274,7 @@ func (q *Queries) GetProjectById(ctx context.Context, id pgtype.UUID) (GetProjec
|
||||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
&i.Commits,
|
||||
&i.SubmissionIds,
|
||||
&i.Submissions,
|
||||
&i.User,
|
||||
&i.Members,
|
||||
)
|
||||
@@ -289,7 +289,10 @@ SELECT
|
||||
FROM commits c WHERE c.project_id = p.id AND c.is_deleted = false),
|
||||
'[]'
|
||||
)::json AS commits,
|
||||
COALESCE((SELECT array_agg(id) FROM submissions WHERE project_id = p.id), '{}')::uuid[] AS submission_ids,
|
||||
COALESCE(
|
||||
(SELECT json_agg(json_build_object('id', s.id, 'status', s.status)) FROM submissions s WHERE s.project_id = p.id),
|
||||
'[]'
|
||||
)::json AS submissions,
|
||||
json_build_object(
|
||||
'id', u.id,
|
||||
'email', u.email,
|
||||
@@ -326,7 +329,7 @@ type GetProjectsByIDsRow struct {
|
||||
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
||||
Commits []byte `json:"commits"`
|
||||
SubmissionIds []pgtype.UUID `json:"submission_ids"`
|
||||
Submissions []byte `json:"submissions"`
|
||||
User []byte `json:"user"`
|
||||
Members []byte `json:"members"`
|
||||
}
|
||||
@@ -352,7 +355,7 @@ func (q *Queries) GetProjectsByIDs(ctx context.Context, dollar_1 []pgtype.UUID)
|
||||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
&i.Commits,
|
||||
&i.SubmissionIds,
|
||||
&i.Submissions,
|
||||
&i.User,
|
||||
&i.Members,
|
||||
); err != nil {
|
||||
@@ -375,9 +378,9 @@ SELECT
|
||||
'[]'
|
||||
)::json AS commits,
|
||||
COALESCE(
|
||||
(SELECT array_agg(id) FROM submissions WHERE project_id = p.id),
|
||||
'{}'
|
||||
)::uuid[] AS submission_ids,
|
||||
(SELECT json_agg(json_build_object('id', s.id, 'status', s.status)) FROM submissions s WHERE s.project_id = p.id),
|
||||
'[]'
|
||||
)::json AS submissions,
|
||||
json_build_object(
|
||||
'id', u.id,
|
||||
'email', u.email,
|
||||
@@ -424,7 +427,7 @@ type GetProjectsByUserIdRow struct {
|
||||
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
||||
Commits []byte `json:"commits"`
|
||||
SubmissionIds []pgtype.UUID `json:"submission_ids"`
|
||||
Submissions []byte `json:"submissions"`
|
||||
User []byte `json:"user"`
|
||||
Members []byte `json:"members"`
|
||||
}
|
||||
@@ -450,7 +453,7 @@ func (q *Queries) GetProjectsByUserId(ctx context.Context, arg GetProjectsByUser
|
||||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
&i.Commits,
|
||||
&i.SubmissionIds,
|
||||
&i.Submissions,
|
||||
&i.User,
|
||||
&i.Members,
|
||||
); err != nil {
|
||||
@@ -488,9 +491,9 @@ SELECT
|
||||
'[]'
|
||||
)::json AS commits,
|
||||
COALESCE(
|
||||
(SELECT array_agg(id) FROM submissions WHERE project_id = p.id),
|
||||
'{}'
|
||||
)::uuid[] AS submission_ids,
|
||||
(SELECT json_agg(json_build_object('id', s.id, 'status', s.status)) FROM submissions s WHERE s.project_id = p.id),
|
||||
'[]'
|
||||
)::json AS submissions,
|
||||
json_build_object(
|
||||
'id', u.id,
|
||||
'email', u.email,
|
||||
@@ -561,7 +564,7 @@ type SearchProjectsRow struct {
|
||||
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
||||
Commits []byte `json:"commits"`
|
||||
SubmissionIds []pgtype.UUID `json:"submission_ids"`
|
||||
Submissions []byte `json:"submissions"`
|
||||
User []byte `json:"user"`
|
||||
Members []byte `json:"members"`
|
||||
}
|
||||
@@ -597,7 +600,7 @@ func (q *Queries) SearchProjects(ctx context.Context, arg SearchProjectsParams)
|
||||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
&i.Commits,
|
||||
&i.SubmissionIds,
|
||||
&i.Submissions,
|
||||
&i.User,
|
||||
&i.Members,
|
||||
); err != nil {
|
||||
@@ -654,7 +657,10 @@ RETURNING
|
||||
FROM commits c WHERE c.project_id = projects.id AND c.is_deleted = false),
|
||||
'[]'
|
||||
)::json AS commits,
|
||||
COALESCE((SELECT array_agg(id) FROM submissions WHERE project_id = projects.id), '{}')::uuid[] AS submission_ids,
|
||||
COALESCE(
|
||||
(SELECT json_agg(json_build_object('id', s.id, 'status', s.status)) FROM submissions s WHERE s.project_id = projects.id),
|
||||
'[]'
|
||||
)::json AS submissions,
|
||||
COALESCE(
|
||||
(SELECT json_agg(json_build_object(
|
||||
'user_id', pm.user_id, 'role', pm.role,
|
||||
@@ -690,7 +696,7 @@ type UpdateProjectRow struct {
|
||||
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
||||
User []byte `json:"user"`
|
||||
Commits []byte `json:"commits"`
|
||||
SubmissionIds []pgtype.UUID `json:"submission_ids"`
|
||||
Submissions []byte `json:"submissions"`
|
||||
Members []byte `json:"members"`
|
||||
}
|
||||
|
||||
@@ -717,7 +723,7 @@ func (q *Queries) UpdateProject(ctx context.Context, arg UpdateProjectParams) (U
|
||||
&i.UpdatedAt,
|
||||
&i.User,
|
||||
&i.Commits,
|
||||
&i.SubmissionIds,
|
||||
&i.Submissions,
|
||||
&i.Members,
|
||||
)
|
||||
return i, err
|
||||
|
||||
@@ -37,42 +37,62 @@ func (q *Queries) BulkDeleteEntityWikisByEntityId(ctx context.Context, entityID
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const bulkDeleteEntityWikisByWikiID = `-- name: BulkDeleteEntityWikisByWikiID :exec
|
||||
DELETE FROM entity_wikis
|
||||
WHERE wiki_id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) BulkDeleteEntityWikisByWikiID(ctx context.Context, wikiID pgtype.UUID) error {
|
||||
_, err := q.db.Exec(ctx, bulkDeleteEntityWikisByWikiID, wikiID)
|
||||
return err
|
||||
}
|
||||
|
||||
const createEntityWikis = `-- name: CreateEntityWikis :exec
|
||||
INSERT INTO entity_wikis (
|
||||
entity_id, wiki_id
|
||||
entity_id, wiki_id, project_id
|
||||
)
|
||||
SELECT $1, unnest($2::uuid[])
|
||||
SELECT $1, unnest($3::uuid[]), $2
|
||||
ON CONFLICT DO NOTHING
|
||||
`
|
||||
|
||||
type CreateEntityWikisParams struct {
|
||||
EntityID pgtype.UUID `json:"entity_id"`
|
||||
WikiIds []pgtype.UUID `json:"wiki_ids"`
|
||||
EntityID pgtype.UUID `json:"entity_id"`
|
||||
ProjectID pgtype.UUID `json:"project_id"`
|
||||
WikiIds []pgtype.UUID `json:"wiki_ids"`
|
||||
}
|
||||
|
||||
func (q *Queries) CreateEntityWikis(ctx context.Context, arg CreateEntityWikisParams) error {
|
||||
_, err := q.db.Exec(ctx, createEntityWikis, arg.EntityID, arg.WikiIds)
|
||||
_, err := q.db.Exec(ctx, createEntityWikis, arg.EntityID, arg.ProjectID, arg.WikiIds)
|
||||
return err
|
||||
}
|
||||
|
||||
const createWiki = `-- name: CreateWiki :one
|
||||
INSERT INTO wikis (
|
||||
title, content
|
||||
id, title, content, project_id
|
||||
) VALUES (
|
||||
$1, $2
|
||||
COALESCE($4::uuid, uuidv7()), $1, $2, $3
|
||||
)
|
||||
RETURNING id, title, content, is_deleted, created_at, updated_at
|
||||
RETURNING id, project_id, title, content, is_deleted, created_at, updated_at
|
||||
`
|
||||
|
||||
type CreateWikiParams struct {
|
||||
Title pgtype.Text `json:"title"`
|
||||
Content pgtype.Text `json:"content"`
|
||||
Title pgtype.Text `json:"title"`
|
||||
Content []byte `json:"content"`
|
||||
ProjectID pgtype.UUID `json:"project_id"`
|
||||
ID pgtype.UUID `json:"id"`
|
||||
}
|
||||
|
||||
func (q *Queries) CreateWiki(ctx context.Context, arg CreateWikiParams) (Wiki, error) {
|
||||
row := q.db.QueryRow(ctx, createWiki, arg.Title, arg.Content)
|
||||
row := q.db.QueryRow(ctx, createWiki,
|
||||
arg.Title,
|
||||
arg.Content,
|
||||
arg.ProjectID,
|
||||
arg.ID,
|
||||
)
|
||||
var i Wiki
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.ProjectID,
|
||||
&i.Title,
|
||||
&i.Content,
|
||||
&i.IsDeleted,
|
||||
@@ -82,6 +102,31 @@ func (q *Queries) CreateWiki(ctx context.Context, arg CreateWikiParams) (Wiki, e
|
||||
return i, err
|
||||
}
|
||||
|
||||
const deleteEntityWiki = `-- name: DeleteEntityWiki :exec
|
||||
DELETE FROM entity_wikis
|
||||
WHERE entity_id = $1 AND wiki_id = $2
|
||||
`
|
||||
|
||||
type DeleteEntityWikiParams struct {
|
||||
EntityID pgtype.UUID `json:"entity_id"`
|
||||
WikiID pgtype.UUID `json:"wiki_id"`
|
||||
}
|
||||
|
||||
func (q *Queries) DeleteEntityWiki(ctx context.Context, arg DeleteEntityWikiParams) error {
|
||||
_, err := q.db.Exec(ctx, deleteEntityWiki, arg.EntityID, arg.WikiID)
|
||||
return err
|
||||
}
|
||||
|
||||
const deleteEntityWikisByProjectID = `-- name: DeleteEntityWikisByProjectID :exec
|
||||
DELETE FROM entity_wikis
|
||||
WHERE project_id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) DeleteEntityWikisByProjectID(ctx context.Context, projectID pgtype.UUID) error {
|
||||
_, err := q.db.Exec(ctx, deleteEntityWikisByProjectID, projectID)
|
||||
return err
|
||||
}
|
||||
|
||||
const deleteWiki = `-- name: DeleteWiki :exec
|
||||
UPDATE wikis
|
||||
SET
|
||||
@@ -94,8 +139,19 @@ func (q *Queries) DeleteWiki(ctx context.Context, id pgtype.UUID) error {
|
||||
return err
|
||||
}
|
||||
|
||||
const deleteWikisByIDs = `-- name: DeleteWikisByIDs :exec
|
||||
UPDATE wikis
|
||||
SET is_deleted = true
|
||||
WHERE id = ANY($1::uuid[])
|
||||
`
|
||||
|
||||
func (q *Queries) DeleteWikisByIDs(ctx context.Context, dollar_1 []pgtype.UUID) error {
|
||||
_, err := q.db.Exec(ctx, deleteWikisByIDs, dollar_1)
|
||||
return err
|
||||
}
|
||||
|
||||
const getWikiById = `-- name: GetWikiById :one
|
||||
SELECT id, title, content, is_deleted, created_at, updated_at
|
||||
SELECT id, project_id, title, content, is_deleted, created_at, updated_at
|
||||
FROM wikis
|
||||
WHERE id = $1 AND is_deleted = false
|
||||
`
|
||||
@@ -105,6 +161,7 @@ func (q *Queries) GetWikiById(ctx context.Context, id pgtype.UUID) (Wiki, error)
|
||||
var i Wiki
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.ProjectID,
|
||||
&i.Title,
|
||||
&i.Content,
|
||||
&i.IsDeleted,
|
||||
@@ -115,7 +172,7 @@ func (q *Queries) GetWikiById(ctx context.Context, id pgtype.UUID) (Wiki, error)
|
||||
}
|
||||
|
||||
const getWikisByIDs = `-- name: GetWikisByIDs :many
|
||||
SELECT id, title, content, is_deleted, created_at, updated_at FROM wikis WHERE id = ANY($1::uuid[]) AND is_deleted = false
|
||||
SELECT id, project_id, title, content, is_deleted, created_at, updated_at FROM wikis WHERE id = ANY($1::uuid[]) AND is_deleted = false
|
||||
`
|
||||
|
||||
func (q *Queries) GetWikisByIDs(ctx context.Context, dollar_1 []pgtype.UUID) ([]Wiki, error) {
|
||||
@@ -129,6 +186,41 @@ func (q *Queries) GetWikisByIDs(ctx context.Context, dollar_1 []pgtype.UUID) ([]
|
||||
var i Wiki
|
||||
if err := rows.Scan(
|
||||
&i.ID,
|
||||
&i.ProjectID,
|
||||
&i.Title,
|
||||
&i.Content,
|
||||
&i.IsDeleted,
|
||||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const getWikisByProjectId = `-- name: GetWikisByProjectId :many
|
||||
SELECT id, project_id, title, content, is_deleted, created_at, updated_at
|
||||
FROM wikis
|
||||
WHERE project_id = $1 AND is_deleted = false
|
||||
`
|
||||
|
||||
func (q *Queries) GetWikisByProjectId(ctx context.Context, projectID pgtype.UUID) ([]Wiki, error) {
|
||||
rows, err := q.db.Query(ctx, getWikisByProjectId, projectID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
items := []Wiki{}
|
||||
for rows.Next() {
|
||||
var i Wiki
|
||||
if err := rows.Scan(
|
||||
&i.ID,
|
||||
&i.ProjectID,
|
||||
&i.Title,
|
||||
&i.Content,
|
||||
&i.IsDeleted,
|
||||
@@ -146,26 +238,28 @@ func (q *Queries) GetWikisByIDs(ctx context.Context, dollar_1 []pgtype.UUID) ([]
|
||||
}
|
||||
|
||||
const searchWikis = `-- name: SearchWikis :many
|
||||
SELECT w.id, w.title, w.content, w.is_deleted, w.created_at, w.updated_at
|
||||
SELECT w.id, w.project_id, w.title, w.content, w.is_deleted, w.created_at, w.updated_at
|
||||
FROM wikis w
|
||||
WHERE w.is_deleted = false
|
||||
AND w.title ILIKE '%' || $1::text || '%'
|
||||
AND ($1::uuid IS NULL OR w.project_id = $1::uuid)
|
||||
AND w.title ILIKE '%' || $2::text || '%'
|
||||
AND (
|
||||
$2::uuid IS NULL OR
|
||||
$3::uuid IS NULL OR
|
||||
EXISTS (
|
||||
SELECT 1
|
||||
FROM entity_wikis ew
|
||||
WHERE ew.wiki_id = w.id
|
||||
AND ew.entity_id = $2::uuid
|
||||
AND ew.entity_id = $3::uuid
|
||||
)
|
||||
)
|
||||
AND ($3::uuid IS NULL OR w.id < $3::uuid)
|
||||
AND ($4::uuid IS NULL OR w.id < $4::uuid)
|
||||
|
||||
ORDER BY w.id DESC
|
||||
LIMIT $4
|
||||
LIMIT $5
|
||||
`
|
||||
|
||||
type SearchWikisParams struct {
|
||||
ProjectID pgtype.UUID `json:"project_id"`
|
||||
Title string `json:"title"`
|
||||
EntityID pgtype.UUID `json:"entity_id"`
|
||||
CursorID pgtype.UUID `json:"cursor_id"`
|
||||
@@ -174,6 +268,7 @@ type SearchWikisParams struct {
|
||||
|
||||
func (q *Queries) SearchWikis(ctx context.Context, arg SearchWikisParams) ([]Wiki, error) {
|
||||
rows, err := q.db.Query(ctx, searchWikis,
|
||||
arg.ProjectID,
|
||||
arg.Title,
|
||||
arg.EntityID,
|
||||
arg.CursorID,
|
||||
@@ -188,6 +283,7 @@ func (q *Queries) SearchWikis(ctx context.Context, arg SearchWikisParams) ([]Wik
|
||||
var i Wiki
|
||||
if err := rows.Scan(
|
||||
&i.ID,
|
||||
&i.ProjectID,
|
||||
&i.Title,
|
||||
&i.Content,
|
||||
&i.IsDeleted,
|
||||
@@ -208,22 +304,30 @@ const updateWiki = `-- name: UpdateWiki :one
|
||||
UPDATE wikis
|
||||
SET
|
||||
title = COALESCE($1, title),
|
||||
content = COALESCE($2, content)
|
||||
WHERE id = $3 AND is_deleted = false
|
||||
RETURNING id, title, content, is_deleted, created_at, updated_at
|
||||
content = COALESCE($2, content),
|
||||
project_id = COALESCE($3, project_id)
|
||||
WHERE id = $4 AND is_deleted = false
|
||||
RETURNING id, project_id, title, content, is_deleted, created_at, updated_at
|
||||
`
|
||||
|
||||
type UpdateWikiParams struct {
|
||||
Title pgtype.Text `json:"title"`
|
||||
Content pgtype.Text `json:"content"`
|
||||
ID pgtype.UUID `json:"id"`
|
||||
Title pgtype.Text `json:"title"`
|
||||
Content []byte `json:"content"`
|
||||
ProjectID pgtype.UUID `json:"project_id"`
|
||||
ID pgtype.UUID `json:"id"`
|
||||
}
|
||||
|
||||
func (q *Queries) UpdateWiki(ctx context.Context, arg UpdateWikiParams) (Wiki, error) {
|
||||
row := q.db.QueryRow(ctx, updateWiki, arg.Title, arg.Content, arg.ID)
|
||||
row := q.db.QueryRow(ctx, updateWiki,
|
||||
arg.Title,
|
||||
arg.Content,
|
||||
arg.ProjectID,
|
||||
arg.ID,
|
||||
)
|
||||
var i Wiki
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.ProjectID,
|
||||
&i.Title,
|
||||
&i.Content,
|
||||
&i.IsDeleted,
|
||||
|
||||
@@ -8,8 +8,10 @@ import (
|
||||
type EntityEntity struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Slug string `json:"slug"`
|
||||
Description string `json:"description"`
|
||||
ThumbnailUrl string `json:"thumbnail_url"`
|
||||
ProjectID string `json:"project_id"`
|
||||
Status *int16 `json:"status"`
|
||||
IsDeleted bool `json:"is_deleted"`
|
||||
CreatedAt *time.Time `json:"created_at"`
|
||||
UpdatedAt *time.Time `json:"updated_at"`
|
||||
@@ -22,8 +24,10 @@ func (e *EntityEntity) ToResponse() *response.EntityResponse {
|
||||
return &response.EntityResponse{
|
||||
ID: e.ID,
|
||||
Name: e.Name,
|
||||
Slug: e.Slug,
|
||||
Description: e.Description,
|
||||
ThumbnailUrl: e.ThumbnailUrl,
|
||||
ProjectID: e.ProjectID,
|
||||
Status: e.Status,
|
||||
IsDeleted: e.IsDeleted,
|
||||
CreatedAt: e.CreatedAt,
|
||||
UpdatedAt: e.UpdatedAt,
|
||||
|
||||
@@ -15,6 +15,7 @@ type GeometryEntity struct {
|
||||
TimeStart int32 `json:"time_start"`
|
||||
TimeEnd int32 `json:"time_end"`
|
||||
Bbox *response.Bbox `json:"bbox"`
|
||||
ProjectID string `json:"project_id"`
|
||||
IsDeleted bool `json:"is_deleted"`
|
||||
CreatedAt *time.Time `json:"created_at"`
|
||||
UpdatedAt *time.Time `json:"updated_at"`
|
||||
@@ -32,6 +33,7 @@ func (g *GeometryEntity) ToResponse() *response.GeometryResponse {
|
||||
TimeStart: g.TimeStart,
|
||||
TimeEnd: g.TimeEnd,
|
||||
Bbox: g.Bbox,
|
||||
ProjectID: g.ProjectID,
|
||||
IsDeleted: g.IsDeleted,
|
||||
CreatedAt: g.CreatedAt,
|
||||
UpdatedAt: g.UpdatedAt,
|
||||
|
||||
@@ -19,6 +19,11 @@ type MemberSimple struct {
|
||||
AvatarUrl string `json:"avatar_url"`
|
||||
}
|
||||
|
||||
type SubmissionSimple struct {
|
||||
ID string `json:"id"`
|
||||
Status constants.StatusType `json:"status"`
|
||||
}
|
||||
|
||||
type ProjectEntity struct {
|
||||
ID string `json:"id"`
|
||||
Title string `json:"title"`
|
||||
@@ -32,7 +37,7 @@ type ProjectEntity struct {
|
||||
UpdatedAt *time.Time `json:"updated_at"`
|
||||
User *UserSimpleEntity `json:"user"`
|
||||
Commits []CommitSimple `json:"commits"`
|
||||
SubmissionIds []string `json:"submission_ids"`
|
||||
Submissions []SubmissionSimple `json:"submissions"`
|
||||
Members []MemberSimple `json:"members"`
|
||||
}
|
||||
|
||||
@@ -60,6 +65,14 @@ func (p *ProjectEntity) ParseMembers(data []byte) error {
|
||||
return json.Unmarshal(data, &p.Members)
|
||||
}
|
||||
|
||||
func (p *ProjectEntity) ParseSubmissions(data []byte) error {
|
||||
if len(data) == 0 || string(data) == "null" || string(data) == "[]" {
|
||||
p.Submissions = []SubmissionSimple{}
|
||||
return nil
|
||||
}
|
||||
return json.Unmarshal(data, &p.Submissions)
|
||||
}
|
||||
|
||||
func (p *ProjectEntity) ToResponse() *response.ProjectResponse {
|
||||
if p == nil {
|
||||
return nil
|
||||
@@ -77,6 +90,14 @@ func (p *ProjectEntity) ToResponse() *response.ProjectResponse {
|
||||
})
|
||||
}
|
||||
|
||||
submissions := make([]response.SubmissionSimpleResponse, 0, len(p.Submissions))
|
||||
for _, s := range p.Submissions {
|
||||
submissions = append(submissions, response.SubmissionSimpleResponse{
|
||||
ID: s.ID,
|
||||
Status: s.Status.String(),
|
||||
})
|
||||
}
|
||||
|
||||
members := make([]response.MemberSimpleResponse, 0, len(p.Members))
|
||||
for _, m := range p.Members {
|
||||
members = append(members, response.MemberSimpleResponse{
|
||||
@@ -100,7 +121,7 @@ func (p *ProjectEntity) ToResponse() *response.ProjectResponse {
|
||||
UpdatedAt: p.UpdatedAt,
|
||||
User: userResponse,
|
||||
Commits: commits,
|
||||
SubmissionIds: p.SubmissionIds,
|
||||
Submissions: submissions,
|
||||
Members: members,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"history-api/internal/dtos/response"
|
||||
"time"
|
||||
)
|
||||
|
||||
type WikiEntity struct {
|
||||
ID string `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Content string `json:"content"`
|
||||
IsDeleted bool `json:"is_deleted"`
|
||||
CreatedAt *time.Time `json:"created_at"`
|
||||
UpdatedAt *time.Time `json:"updated_at"`
|
||||
ID string `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Content json.RawMessage `json:"content"`
|
||||
ProjectID string `json:"project_id"`
|
||||
IsDeleted bool `json:"is_deleted"`
|
||||
CreatedAt *time.Time `json:"created_at"`
|
||||
UpdatedAt *time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
func (w *WikiEntity) ToResponse() *response.WikiResponse {
|
||||
@@ -22,6 +24,7 @@ func (w *WikiEntity) ToResponse() *response.WikiResponse {
|
||||
ID: w.ID,
|
||||
Title: w.Title,
|
||||
Content: w.Content,
|
||||
ProjectID: w.ProjectID,
|
||||
IsDeleted: w.IsDeleted,
|
||||
CreatedAt: w.CreatedAt,
|
||||
UpdatedAt: w.UpdatedAt,
|
||||
|
||||
@@ -20,6 +20,7 @@ type CommitRepository interface {
|
||||
GetByID(ctx context.Context, id pgtype.UUID) (*models.CommitEntity, error)
|
||||
GetByProjectID(ctx context.Context, projectID pgtype.UUID) ([]*models.CommitEntity, error)
|
||||
Search(ctx context.Context, params sqlc.SearchCommitsParams) ([]*models.CommitEntity, error)
|
||||
UpdateSnapshot(ctx context.Context, id pgtype.UUID, snapshot json.RawMessage) (*models.CommitEntity, error)
|
||||
WithTx(tx pgx.Tx) CommitRepository
|
||||
}
|
||||
|
||||
@@ -228,3 +229,25 @@ func (r *commitRepository) Search(ctx context.Context, params sqlc.SearchCommits
|
||||
|
||||
return commits, nil
|
||||
}
|
||||
|
||||
func (r *commitRepository) UpdateSnapshot(ctx context.Context, id pgtype.UUID, snapshot json.RawMessage) (*models.CommitEntity, error) {
|
||||
row, err := r.q.UpdateCommitSnapshot(ctx, sqlc.UpdateCommitSnapshotParams{
|
||||
ID: id,
|
||||
SnapshotJson: snapshot,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
r.c.Del(ctx, fmt.Sprintf("commit:id:%s", convert.UUIDToString(id)))
|
||||
|
||||
return &models.CommitEntity{
|
||||
ID: convert.UUIDToString(row.ID),
|
||||
ProjectID: convert.UUIDToString(row.ProjectID),
|
||||
SnapshotJson: row.SnapshotJson,
|
||||
SnapshotHash: convert.TextToString(row.SnapshotHash),
|
||||
UserID: convert.UUIDToString(row.UserID),
|
||||
EditSummary: convert.TextToString(row.EditSummary),
|
||||
IsDeleted: row.IsDeleted,
|
||||
CreatedAt: convert.TimeToPtr(row.CreatedAt),
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -23,6 +23,8 @@ type EntityRepository interface {
|
||||
Create(ctx context.Context, params sqlc.CreateEntityParams) (*models.EntityEntity, error)
|
||||
Update(ctx context.Context, params sqlc.UpdateEntityParams) (*models.EntityEntity, error)
|
||||
Delete(ctx context.Context, id pgtype.UUID) error
|
||||
DeleteByIDs(ctx context.Context, ids []pgtype.UUID) error
|
||||
GetByProjectID(ctx context.Context, projectID pgtype.UUID) ([]*models.EntityEntity, error)
|
||||
WithTx(tx pgx.Tx) EntityRepository
|
||||
}
|
||||
|
||||
@@ -83,8 +85,10 @@ func (r *entityRepository) getByIDsWithFallback(ctx context.Context, ids []strin
|
||||
item := models.EntityEntity{
|
||||
ID: convert.UUIDToString(row.ID),
|
||||
Name: row.Name,
|
||||
Slug: convert.TextToString(row.Slug),
|
||||
Description: convert.TextToString(row.Description),
|
||||
ThumbnailUrl: convert.TextToString(row.ThumbnailUrl),
|
||||
ProjectID: convert.UUIDToString(row.ProjectID),
|
||||
Status: convert.Int2ToInt16Ptr(row.Status),
|
||||
IsDeleted: row.IsDeleted,
|
||||
CreatedAt: convert.TimeToPtr(row.CreatedAt),
|
||||
UpdatedAt: convert.TimeToPtr(row.UpdatedAt),
|
||||
@@ -136,8 +140,10 @@ func (r *entityRepository) GetByID(ctx context.Context, id pgtype.UUID) (*models
|
||||
entity = models.EntityEntity{
|
||||
ID: convert.UUIDToString(row.ID),
|
||||
Name: row.Name,
|
||||
Slug: convert.TextToString(row.Slug),
|
||||
Description: convert.TextToString(row.Description),
|
||||
ThumbnailUrl: convert.TextToString(row.ThumbnailUrl),
|
||||
ProjectID: convert.UUIDToString(row.ProjectID),
|
||||
Status: convert.Int2ToInt16Ptr(row.Status),
|
||||
IsDeleted: row.IsDeleted,
|
||||
CreatedAt: convert.TimeToPtr(row.CreatedAt),
|
||||
UpdatedAt: convert.TimeToPtr(row.UpdatedAt),
|
||||
@@ -166,8 +172,10 @@ func (r *entityRepository) Search(ctx context.Context, params sqlc.SearchEntitie
|
||||
entity := &models.EntityEntity{
|
||||
ID: convert.UUIDToString(row.ID),
|
||||
Name: row.Name,
|
||||
Slug: convert.TextToString(row.Slug),
|
||||
Description: convert.TextToString(row.Description),
|
||||
ThumbnailUrl: convert.TextToString(row.ThumbnailUrl),
|
||||
ProjectID: convert.UUIDToString(row.ProjectID),
|
||||
Status: convert.Int2ToInt16Ptr(row.Status),
|
||||
IsDeleted: row.IsDeleted,
|
||||
CreatedAt: convert.TimeToPtr(row.CreatedAt),
|
||||
UpdatedAt: convert.TimeToPtr(row.UpdatedAt),
|
||||
@@ -180,6 +188,7 @@ func (r *entityRepository) Search(ctx context.Context, params sqlc.SearchEntitie
|
||||
if len(entityToCache) > 0 {
|
||||
_ = r.c.MSet(ctx, entityToCache, constants.NormalCacheDuration)
|
||||
}
|
||||
|
||||
if len(ids) > 0 {
|
||||
_ = r.c.Set(ctx, queryKey, ids, constants.ListCacheDuration)
|
||||
}
|
||||
@@ -196,15 +205,15 @@ func (r *entityRepository) Create(ctx context.Context, params sqlc.CreateEntityP
|
||||
entity := models.EntityEntity{
|
||||
ID: convert.UUIDToString(row.ID),
|
||||
Name: row.Name,
|
||||
Slug: convert.TextToString(row.Slug),
|
||||
Description: convert.TextToString(row.Description),
|
||||
ThumbnailUrl: convert.TextToString(row.ThumbnailUrl),
|
||||
ProjectID: convert.UUIDToString(row.ProjectID),
|
||||
Status: convert.Int2ToInt16Ptr(row.Status),
|
||||
IsDeleted: row.IsDeleted,
|
||||
CreatedAt: convert.TimeToPtr(row.CreatedAt),
|
||||
UpdatedAt: convert.TimeToPtr(row.UpdatedAt),
|
||||
}
|
||||
go func() {
|
||||
_ = r.c.DelByPattern(context.Background(), "entity:search*")
|
||||
}()
|
||||
|
||||
return &entity, nil
|
||||
}
|
||||
|
||||
@@ -216,8 +225,10 @@ func (r *entityRepository) Update(ctx context.Context, params sqlc.UpdateEntityP
|
||||
entity := models.EntityEntity{
|
||||
ID: convert.UUIDToString(row.ID),
|
||||
Name: row.Name,
|
||||
Slug: convert.TextToString(row.Slug),
|
||||
Description: convert.TextToString(row.Description),
|
||||
ThumbnailUrl: convert.TextToString(row.ThumbnailUrl),
|
||||
ProjectID: convert.UUIDToString(row.ProjectID),
|
||||
Status: convert.Int2ToInt16Ptr(row.Status),
|
||||
IsDeleted: row.IsDeleted,
|
||||
CreatedAt: convert.TimeToPtr(row.CreatedAt),
|
||||
UpdatedAt: convert.TimeToPtr(row.UpdatedAt),
|
||||
@@ -234,3 +245,61 @@ func (r *entityRepository) Delete(ctx context.Context, id pgtype.UUID) error {
|
||||
_ = r.c.Del(ctx, fmt.Sprintf("entity:id:%s", convert.UUIDToString(id)))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *entityRepository) GetByProjectID(ctx context.Context, projectID pgtype.UUID) ([]*models.EntityEntity, error) {
|
||||
cacheKey := fmt.Sprintf("entity:project:%s", convert.UUIDToString(projectID))
|
||||
var cachedIDs []string
|
||||
if err := r.c.Get(ctx, cacheKey, &cachedIDs); err == nil && len(cachedIDs) > 0 {
|
||||
return r.getByIDsWithFallback(ctx, cachedIDs)
|
||||
}
|
||||
|
||||
rows, err := r.q.GetEntitiesByProjectId(ctx, projectID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var entities []*models.EntityEntity
|
||||
var ids []string
|
||||
entityToCache := make(map[string]any)
|
||||
|
||||
for _, row := range rows {
|
||||
entity := &models.EntityEntity{
|
||||
ID: convert.UUIDToString(row.ID),
|
||||
Name: row.Name,
|
||||
Slug: convert.TextToString(row.Slug),
|
||||
Description: convert.TextToString(row.Description),
|
||||
ProjectID: convert.UUIDToString(row.ProjectID),
|
||||
Status: convert.Int2ToInt16Ptr(row.Status),
|
||||
IsDeleted: row.IsDeleted,
|
||||
CreatedAt: convert.TimeToPtr(row.CreatedAt),
|
||||
UpdatedAt: convert.TimeToPtr(row.UpdatedAt),
|
||||
}
|
||||
ids = append(ids, entity.ID)
|
||||
entities = append(entities, entity)
|
||||
entityToCache[fmt.Sprintf("entity:id:%s", entity.ID)] = entity
|
||||
}
|
||||
|
||||
if len(entityToCache) > 0 {
|
||||
_ = r.c.MSet(ctx, entityToCache, constants.NormalCacheDuration)
|
||||
}
|
||||
if len(ids) > 0 {
|
||||
_ = r.c.Set(ctx, cacheKey, ids, constants.ListCacheDuration)
|
||||
}
|
||||
|
||||
return entities, nil
|
||||
}
|
||||
|
||||
func (r *entityRepository) DeleteByIDs(ctx context.Context, ids []pgtype.UUID) error {
|
||||
err := r.q.DeleteEntitiesByIDs(ctx, ids)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(ids) > 0 {
|
||||
keys := make([]string, len(ids))
|
||||
for i, id := range ids {
|
||||
keys[i] = fmt.Sprintf("entity:id:%s", convert.UUIDToString(id))
|
||||
}
|
||||
_ = r.c.Del(ctx, keys...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -26,6 +26,11 @@ type GeometryRepository interface {
|
||||
Delete(ctx context.Context, id pgtype.UUID) error
|
||||
CreateEntityGeometries(ctx context.Context, params sqlc.CreateEntityGeometriesParams) error
|
||||
BulkDeleteEntityGeometriesByEntityId(ctx context.Context, entityId pgtype.UUID) error
|
||||
GetByProjectID(ctx context.Context, projectID pgtype.UUID) ([]*models.GeometryEntity, error)
|
||||
DeleteByIDs(ctx context.Context, ids []pgtype.UUID) error
|
||||
BulkDeleteEntityGeometriesByGeometryID(ctx context.Context, geometryID pgtype.UUID) error
|
||||
DeleteEntityGeometry(ctx context.Context, entityID pgtype.UUID, geometryID pgtype.UUID) error
|
||||
DeleteEntityGeometriesByProjectID(ctx context.Context, projectID pgtype.UUID) error
|
||||
WithTx(tx pgx.Tx) GeometryRepository
|
||||
}
|
||||
|
||||
@@ -96,6 +101,7 @@ func (r *geometryRepository) getByIDsWithFallback(ctx context.Context, ids []str
|
||||
MaxLng: row.MaxLng,
|
||||
MaxLat: row.MaxLat,
|
||||
},
|
||||
ProjectID: convert.UUIDToString(row.ProjectID),
|
||||
IsDeleted: row.IsDeleted,
|
||||
CreatedAt: convert.TimeToPtr(row.CreatedAt),
|
||||
UpdatedAt: convert.TimeToPtr(row.UpdatedAt),
|
||||
@@ -157,6 +163,7 @@ func (r *geometryRepository) GetByID(ctx context.Context, id pgtype.UUID) (*mode
|
||||
MaxLng: row.MaxLng,
|
||||
MaxLat: row.MaxLat,
|
||||
},
|
||||
ProjectID: convert.UUIDToString(row.ProjectID),
|
||||
IsDeleted: row.IsDeleted,
|
||||
CreatedAt: convert.TimeToPtr(row.CreatedAt),
|
||||
UpdatedAt: convert.TimeToPtr(row.UpdatedAt),
|
||||
@@ -195,6 +202,7 @@ func (r *geometryRepository) Search(ctx context.Context, params sqlc.SearchGeome
|
||||
MaxLng: row.MaxLng,
|
||||
MaxLat: row.MaxLat,
|
||||
},
|
||||
ProjectID: convert.UUIDToString(row.ProjectID),
|
||||
IsDeleted: row.IsDeleted,
|
||||
CreatedAt: convert.TimeToPtr(row.CreatedAt),
|
||||
UpdatedAt: convert.TimeToPtr(row.UpdatedAt),
|
||||
@@ -233,15 +241,12 @@ func (r *geometryRepository) Create(ctx context.Context, params sqlc.CreateGeome
|
||||
MaxLng: row.MaxLng,
|
||||
MaxLat: row.MaxLat,
|
||||
},
|
||||
ProjectID: convert.UUIDToString(row.ProjectID),
|
||||
IsDeleted: row.IsDeleted,
|
||||
CreatedAt: convert.TimeToPtr(row.CreatedAt),
|
||||
UpdatedAt: convert.TimeToPtr(row.UpdatedAt),
|
||||
}
|
||||
|
||||
go func() {
|
||||
_ = r.c.DelByPattern(context.Background(), "geometry:search*")
|
||||
}()
|
||||
|
||||
return &geometry, nil
|
||||
}
|
||||
|
||||
@@ -263,6 +268,7 @@ func (r *geometryRepository) Update(ctx context.Context, params sqlc.UpdateGeome
|
||||
MaxLng: row.MaxLng,
|
||||
MaxLat: row.MaxLat,
|
||||
},
|
||||
ProjectID: convert.UUIDToString(row.ProjectID),
|
||||
IsDeleted: row.IsDeleted,
|
||||
CreatedAt: convert.TimeToPtr(row.CreatedAt),
|
||||
UpdatedAt: convert.TimeToPtr(row.UpdatedAt),
|
||||
@@ -281,26 +287,93 @@ func (r *geometryRepository) Delete(ctx context.Context, id pgtype.UUID) error {
|
||||
}
|
||||
|
||||
func (r *geometryRepository) CreateEntityGeometries(ctx context.Context, params sqlc.CreateEntityGeometriesParams) error {
|
||||
err := r.q.CreateEntityGeometries(ctx, params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return err
|
||||
return r.q.CreateEntityGeometries(ctx, params)
|
||||
}
|
||||
|
||||
func (r *geometryRepository) DeleteEntityGeometriesByProjectID(ctx context.Context, projectID pgtype.UUID) error {
|
||||
return r.q.DeleteEntityGeometriesByProjectID(ctx, projectID)
|
||||
}
|
||||
|
||||
func (r *geometryRepository) BulkDeleteEntityGeometriesByEntityId(ctx context.Context, entityId pgtype.UUID) error {
|
||||
geometryIDs, err := r.q.BulkDeleteEntityGeometriesByEntityId(ctx, entityId)
|
||||
_, err := r.q.BulkDeleteEntityGeometriesByEntityId(ctx, entityId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(geometryIDs) > 0 {
|
||||
keys := make([]string, len(geometryIDs))
|
||||
for i, id := range geometryIDs {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *geometryRepository) GetByProjectID(ctx context.Context, projectID pgtype.UUID) ([]*models.GeometryEntity, error) {
|
||||
cacheKey := fmt.Sprintf("geometry:project:%s", convert.UUIDToString(projectID))
|
||||
var cachedIDs []string
|
||||
if err := r.c.Get(ctx, cacheKey, &cachedIDs); err == nil && len(cachedIDs) > 0 {
|
||||
return r.getByIDsWithFallback(ctx, cachedIDs)
|
||||
}
|
||||
|
||||
rows, err := r.q.GetGeometriesByProjectId(ctx, projectID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var geometries []*models.GeometryEntity
|
||||
var ids []string
|
||||
geometryToCache := make(map[string]any)
|
||||
|
||||
for _, row := range rows {
|
||||
geometry := &models.GeometryEntity{
|
||||
ID: convert.UUIDToString(row.ID),
|
||||
GeoType: constants.ParseGeoType(row.GeoType),
|
||||
DrawGeometry: row.DrawGeometry,
|
||||
Binding: row.Binding,
|
||||
TimeStart: convert.Int4ToInt32(row.TimeStart),
|
||||
TimeEnd: convert.Int4ToInt32(row.TimeEnd),
|
||||
Bbox: &response.Bbox{
|
||||
MinLng: row.MinLng,
|
||||
MinLat: row.MinLat,
|
||||
MaxLng: row.MaxLng,
|
||||
MaxLat: row.MaxLat,
|
||||
},
|
||||
ProjectID: convert.UUIDToString(row.ProjectID),
|
||||
IsDeleted: row.IsDeleted,
|
||||
CreatedAt: convert.TimeToPtr(row.CreatedAt),
|
||||
UpdatedAt: convert.TimeToPtr(row.UpdatedAt),
|
||||
}
|
||||
ids = append(ids, geometry.ID)
|
||||
geometries = append(geometries, geometry)
|
||||
geometryToCache[fmt.Sprintf("geometry:id:%s", geometry.ID)] = geometry
|
||||
}
|
||||
|
||||
if len(geometryToCache) > 0 {
|
||||
_ = r.c.MSet(ctx, geometryToCache, constants.NormalCacheDuration)
|
||||
}
|
||||
if len(ids) > 0 {
|
||||
_ = r.c.Set(ctx, cacheKey, ids, constants.ListCacheDuration)
|
||||
}
|
||||
|
||||
return geometries, nil
|
||||
}
|
||||
|
||||
func (r *geometryRepository) DeleteByIDs(ctx context.Context, ids []pgtype.UUID) error {
|
||||
err := r.q.DeleteGeometriesByIDs(ctx, ids)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(ids) > 0 {
|
||||
keys := make([]string, len(ids))
|
||||
for i, id := range ids {
|
||||
keys[i] = fmt.Sprintf("geometry:id:%s", convert.UUIDToString(id))
|
||||
}
|
||||
go func() {
|
||||
_ = r.c.Del(context.Background(), keys...)
|
||||
}()
|
||||
_ = r.c.Del(ctx, keys...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *geometryRepository) BulkDeleteEntityGeometriesByGeometryID(ctx context.Context, geometryID pgtype.UUID) error {
|
||||
return r.q.BulkDeleteEntityGeometriesByGeometryID(ctx, geometryID)
|
||||
}
|
||||
|
||||
func (r *geometryRepository) DeleteEntityGeometry(ctx context.Context, entityID pgtype.UUID, geometryID pgtype.UUID) error {
|
||||
return r.q.DeleteEntityGeometry(ctx, sqlc.DeleteEntityGeometryParams{
|
||||
EntityID: entityID,
|
||||
GeometryID: geometryID,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -98,10 +98,10 @@ func (r *projectRepository) getByIDsWithFallback(ctx context.Context, ids []stri
|
||||
UserID: convert.UUIDToString(row.UserID),
|
||||
CreatedAt: convert.TimeToPtr(row.CreatedAt),
|
||||
UpdatedAt: convert.TimeToPtr(row.UpdatedAt),
|
||||
SubmissionIds: convert.ListUUIDToString(row.SubmissionIds),
|
||||
}
|
||||
_ = item.ParseUser(row.User)
|
||||
_ = item.ParseCommits(row.Commits)
|
||||
_ = item.ParseSubmissions(row.Submissions)
|
||||
_ = item.ParseMembers(row.Members)
|
||||
dbMap[item.ID] = &item
|
||||
}
|
||||
@@ -158,10 +158,10 @@ func (r *projectRepository) GetByID(ctx context.Context, id pgtype.UUID) (*model
|
||||
UserID: convert.UUIDToString(row.UserID),
|
||||
CreatedAt: convert.TimeToPtr(row.CreatedAt),
|
||||
UpdatedAt: convert.TimeToPtr(row.UpdatedAt),
|
||||
SubmissionIds: convert.ListUUIDToString(row.SubmissionIds),
|
||||
}
|
||||
_ = project.ParseUser(row.User)
|
||||
_ = project.ParseCommits(row.Commits)
|
||||
_ = project.ParseSubmissions(row.Submissions)
|
||||
_ = project.ParseMembers(row.Members)
|
||||
|
||||
_ = r.c.Set(ctx, cacheId, project, constants.NormalCacheDuration)
|
||||
@@ -197,10 +197,10 @@ func (r *projectRepository) GetByUserID(ctx context.Context, params sqlc.GetProj
|
||||
UserID: convert.UUIDToString(row.UserID),
|
||||
CreatedAt: convert.TimeToPtr(row.CreatedAt),
|
||||
UpdatedAt: convert.TimeToPtr(row.UpdatedAt),
|
||||
SubmissionIds: convert.ListUUIDToString(row.SubmissionIds),
|
||||
}
|
||||
_ = project.ParseUser(row.User)
|
||||
_ = project.ParseCommits(row.Commits)
|
||||
_ = project.ParseSubmissions(row.Submissions)
|
||||
_ = project.ParseMembers(row.Members)
|
||||
|
||||
ids = append(ids, project.ID)
|
||||
@@ -245,10 +245,10 @@ func (r *projectRepository) Search(ctx context.Context, params sqlc.SearchProjec
|
||||
UserID: convert.UUIDToString(row.UserID),
|
||||
CreatedAt: convert.TimeToPtr(row.CreatedAt),
|
||||
UpdatedAt: convert.TimeToPtr(row.UpdatedAt),
|
||||
SubmissionIds: convert.ListUUIDToString(row.SubmissionIds),
|
||||
}
|
||||
_ = project.ParseUser(row.User)
|
||||
_ = project.ParseCommits(row.Commits)
|
||||
_ = project.ParseSubmissions(row.Submissions)
|
||||
_ = project.ParseMembers(row.Members)
|
||||
|
||||
ids = append(ids, project.ID)
|
||||
@@ -299,10 +299,10 @@ func (r *projectRepository) Create(ctx context.Context, params sqlc.CreateProjec
|
||||
UserID: convert.UUIDToString(row.UserID),
|
||||
CreatedAt: convert.TimeToPtr(row.CreatedAt),
|
||||
UpdatedAt: convert.TimeToPtr(row.UpdatedAt),
|
||||
SubmissionIds: convert.ListUUIDToString(row.SubmissionIds),
|
||||
}
|
||||
_ = project.ParseUser(row.User)
|
||||
_ = project.ParseCommits(row.Commits)
|
||||
_ = project.ParseSubmissions(row.Submissions)
|
||||
_ = project.ParseMembers(row.Members)
|
||||
|
||||
go func() {
|
||||
@@ -330,10 +330,10 @@ func (r *projectRepository) Update(ctx context.Context, params sqlc.UpdateProjec
|
||||
UserID: convert.UUIDToString(row.UserID),
|
||||
CreatedAt: convert.TimeToPtr(row.CreatedAt),
|
||||
UpdatedAt: convert.TimeToPtr(row.UpdatedAt),
|
||||
SubmissionIds: convert.ListUUIDToString(row.SubmissionIds),
|
||||
}
|
||||
_ = project.ParseUser(row.User)
|
||||
_ = project.ParseCommits(row.Commits)
|
||||
_ = project.ParseSubmissions(row.Submissions)
|
||||
_ = project.ParseMembers(row.Members)
|
||||
|
||||
_ = r.c.Del(ctx, fmt.Sprintf("project:id:%s", project.ID))
|
||||
|
||||
@@ -25,6 +25,11 @@ type WikiRepository interface {
|
||||
Delete(ctx context.Context, id pgtype.UUID) error
|
||||
CreateEntityWikis(ctx context.Context, params sqlc.CreateEntityWikisParams) error
|
||||
BulkDeleteEntityWikisByEntityId(ctx context.Context, entityId pgtype.UUID) error
|
||||
GetByProjectID(ctx context.Context, projectID pgtype.UUID) ([]*models.WikiEntity, error)
|
||||
DeleteByIDs(ctx context.Context, ids []pgtype.UUID) error
|
||||
BulkDeleteEntityWikisByWikiID(ctx context.Context, wikiID pgtype.UUID) error
|
||||
DeleteEntityWiki(ctx context.Context, entityID pgtype.UUID, wikiID pgtype.UUID) error
|
||||
DeleteEntityWikisByProjectID(ctx context.Context, projectID pgtype.UUID) error
|
||||
WithTx(tx pgx.Tx) WikiRepository
|
||||
}
|
||||
|
||||
@@ -85,8 +90,9 @@ func (r *wikiRepository) getByIDsWithFallback(ctx context.Context, ids []string)
|
||||
item := models.WikiEntity{
|
||||
ID: convert.UUIDToString(row.ID),
|
||||
Title: convert.TextToString(row.Title),
|
||||
Content: convert.TextToString(row.Content),
|
||||
Content: json.RawMessage(row.Content),
|
||||
IsDeleted: row.IsDeleted,
|
||||
ProjectID: convert.UUIDToString(row.ProjectID),
|
||||
CreatedAt: convert.TimeToPtr(row.CreatedAt),
|
||||
UpdatedAt: convert.TimeToPtr(row.UpdatedAt),
|
||||
}
|
||||
@@ -137,7 +143,7 @@ func (r *wikiRepository) GetByID(ctx context.Context, id pgtype.UUID) (*models.W
|
||||
wiki = models.WikiEntity{
|
||||
ID: convert.UUIDToString(row.ID),
|
||||
Title: convert.TextToString(row.Title),
|
||||
Content: convert.TextToString(row.Content),
|
||||
Content: json.RawMessage(row.Content),
|
||||
IsDeleted: row.IsDeleted,
|
||||
CreatedAt: convert.TimeToPtr(row.CreatedAt),
|
||||
UpdatedAt: convert.TimeToPtr(row.UpdatedAt),
|
||||
@@ -166,7 +172,7 @@ func (r *wikiRepository) Search(ctx context.Context, params sqlc.SearchWikisPara
|
||||
wiki := &models.WikiEntity{
|
||||
ID: convert.UUIDToString(row.ID),
|
||||
Title: convert.TextToString(row.Title),
|
||||
Content: convert.TextToString(row.Content),
|
||||
Content: json.RawMessage(row.Content),
|
||||
IsDeleted: row.IsDeleted,
|
||||
CreatedAt: convert.TimeToPtr(row.CreatedAt),
|
||||
UpdatedAt: convert.TimeToPtr(row.UpdatedAt),
|
||||
@@ -195,16 +201,12 @@ func (r *wikiRepository) Create(ctx context.Context, params sqlc.CreateWikiParam
|
||||
wiki := models.WikiEntity{
|
||||
ID: convert.UUIDToString(row.ID),
|
||||
Title: convert.TextToString(row.Title),
|
||||
Content: convert.TextToString(row.Content),
|
||||
Content: json.RawMessage(row.Content),
|
||||
IsDeleted: row.IsDeleted,
|
||||
CreatedAt: convert.TimeToPtr(row.CreatedAt),
|
||||
UpdatedAt: convert.TimeToPtr(row.UpdatedAt),
|
||||
}
|
||||
|
||||
go func() {
|
||||
_ = r.c.DelByPattern(context.Background(), "wiki:search*")
|
||||
}()
|
||||
|
||||
return &wiki, nil
|
||||
}
|
||||
|
||||
@@ -216,7 +218,7 @@ func (r *wikiRepository) Update(ctx context.Context, params sqlc.UpdateWikiParam
|
||||
wiki := models.WikiEntity{
|
||||
ID: convert.UUIDToString(row.ID),
|
||||
Title: convert.TextToString(row.Title),
|
||||
Content: convert.TextToString(row.Content),
|
||||
Content: json.RawMessage(row.Content),
|
||||
IsDeleted: row.IsDeleted,
|
||||
CreatedAt: convert.TimeToPtr(row.CreatedAt),
|
||||
UpdatedAt: convert.TimeToPtr(row.UpdatedAt),
|
||||
@@ -235,26 +237,84 @@ func (r *wikiRepository) Delete(ctx context.Context, id pgtype.UUID) error {
|
||||
}
|
||||
|
||||
func (r *wikiRepository) CreateEntityWikis(ctx context.Context, params sqlc.CreateEntityWikisParams) error {
|
||||
err := r.q.CreateEntityWikis(ctx, params)
|
||||
return r.q.CreateEntityWikis(ctx, params)
|
||||
}
|
||||
|
||||
func (r *wikiRepository) DeleteEntityWikisByProjectID(ctx context.Context, projectID pgtype.UUID) error {
|
||||
return r.q.DeleteEntityWikisByProjectID(ctx, projectID)
|
||||
}
|
||||
|
||||
func (r *wikiRepository) BulkDeleteEntityWikisByEntityId(ctx context.Context, entityId pgtype.UUID) error {
|
||||
_, err := r.q.BulkDeleteEntityWikisByEntityId(ctx, entityId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *wikiRepository) BulkDeleteEntityWikisByEntityId(ctx context.Context, entityId pgtype.UUID) error {
|
||||
wikiIDs, err := r.q.BulkDeleteEntityWikisByEntityId(ctx, entityId)
|
||||
func (r *wikiRepository) GetByProjectID(ctx context.Context, projectID pgtype.UUID) ([]*models.WikiEntity, error) {
|
||||
cacheKey := fmt.Sprintf("wiki:project:%s", convert.UUIDToString(projectID))
|
||||
var cachedIDs []string
|
||||
if err := r.c.Get(ctx, cacheKey, &cachedIDs); err == nil && len(cachedIDs) > 0 {
|
||||
return r.getByIDsWithFallback(ctx, cachedIDs)
|
||||
}
|
||||
|
||||
rows, err := r.q.GetWikisByProjectId(ctx, projectID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var wikis []*models.WikiEntity
|
||||
var ids []string
|
||||
wikiToCache := make(map[string]any)
|
||||
|
||||
for _, row := range rows {
|
||||
wiki := &models.WikiEntity{
|
||||
ID: convert.UUIDToString(row.ID),
|
||||
Title: convert.TextToString(row.Title),
|
||||
Content: json.RawMessage(row.Content),
|
||||
IsDeleted: row.IsDeleted,
|
||||
ProjectID: convert.UUIDToString(row.ProjectID),
|
||||
CreatedAt: convert.TimeToPtr(row.CreatedAt),
|
||||
UpdatedAt: convert.TimeToPtr(row.UpdatedAt),
|
||||
}
|
||||
ids = append(ids, wiki.ID)
|
||||
wikis = append(wikis, wiki)
|
||||
wikiToCache[fmt.Sprintf("wiki:id:%s", wiki.ID)] = wiki
|
||||
}
|
||||
|
||||
if len(wikiToCache) > 0 {
|
||||
_ = r.c.MSet(ctx, wikiToCache, constants.NormalCacheDuration)
|
||||
}
|
||||
if len(ids) > 0 {
|
||||
_ = r.c.Set(ctx, cacheKey, ids, constants.ListCacheDuration)
|
||||
}
|
||||
|
||||
return wikis, nil
|
||||
}
|
||||
|
||||
func (r *wikiRepository) DeleteByIDs(ctx context.Context, ids []pgtype.UUID) error {
|
||||
err := r.q.DeleteWikisByIDs(ctx, ids)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(wikiIDs) > 0 {
|
||||
keys := make([]string, len(wikiIDs))
|
||||
for i, id := range wikiIDs {
|
||||
if len(ids) > 0 {
|
||||
keys := make([]string, len(ids))
|
||||
for i, id := range ids {
|
||||
keys[i] = fmt.Sprintf("wiki:id:%s", convert.UUIDToString(id))
|
||||
}
|
||||
go func() {
|
||||
_ = r.c.Del(context.Background(), keys...)
|
||||
}()
|
||||
_ = r.c.Del(ctx, keys...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *wikiRepository) BulkDeleteEntityWikisByWikiID(ctx context.Context, wikiID pgtype.UUID) error {
|
||||
return r.q.BulkDeleteEntityWikisByWikiID(ctx, wikiID)
|
||||
}
|
||||
|
||||
func (r *wikiRepository) DeleteEntityWiki(ctx context.Context, entityID pgtype.UUID, wikiID pgtype.UUID) error {
|
||||
return r.q.DeleteEntityWiki(ctx, sqlc.DeleteEntityWikiParams{
|
||||
EntityID: entityID,
|
||||
WikiID: wikiID,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package services
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"history-api/internal/dtos/request"
|
||||
"history-api/internal/dtos/response"
|
||||
"history-api/internal/gen/sqlc"
|
||||
@@ -63,6 +64,12 @@ func (s *commitService) checkWritePermission(ctx context.Context, userID string,
|
||||
return fiber.NewError(fiber.StatusForbidden, "You do not have permission to write to this project")
|
||||
}
|
||||
|
||||
for _, s := range project.Submissions {
|
||||
if s.Status == constants.StatusTypePending {
|
||||
return fiber.NewError(fiber.StatusConflict, "Cannot create commit while there is a pending submission")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -90,9 +97,14 @@ func (s *commitService) CreateCommit(ctx context.Context, userID string, project
|
||||
return nil, fiber.NewError(fiber.StatusBadRequest, "Invalid user ID")
|
||||
}
|
||||
|
||||
snapshotJSON, err := json.Marshal(dto.SnapshotJson)
|
||||
if err != nil {
|
||||
return nil, fiber.NewError(fiber.StatusBadRequest, "Invalid snapshot JSON")
|
||||
}
|
||||
|
||||
commit, err := cRepoTx.Create(ctx, sqlc.CreateCommitParams{
|
||||
ProjectID: projectUUID,
|
||||
SnapshotJson: dto.SnapshotJson,
|
||||
SnapshotJson: snapshotJSON,
|
||||
UserID: userUUID,
|
||||
EditSummary: convert.StringToText(dto.EditSummary),
|
||||
})
|
||||
|
||||
@@ -59,6 +59,13 @@ func (s *entityService) SearchEntities(ctx context.Context, req *request.SearchE
|
||||
params.Name = req.Name
|
||||
}
|
||||
|
||||
if req.ProjectID != nil {
|
||||
projectID, err := convert.StringToUUID(*req.ProjectID)
|
||||
if err == nil {
|
||||
params.ProjectID = projectID
|
||||
}
|
||||
}
|
||||
|
||||
entities, err := s.entityRepo.Search(ctx, params)
|
||||
if err != nil {
|
||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to search entities")
|
||||
|
||||
@@ -2,6 +2,7 @@ package services
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"history-api/internal/dtos/request"
|
||||
"history-api/internal/dtos/response"
|
||||
@@ -32,6 +33,9 @@ type submissionService struct {
|
||||
projectRepo repositories.ProjectRepository
|
||||
commitRepo repositories.CommitRepository
|
||||
userRepo repositories.UserRepository
|
||||
wikiRepo repositories.WikiRepository
|
||||
geometryRepo repositories.GeometryRepository
|
||||
entityRepo repositories.EntityRepository
|
||||
db *pgxpool.Pool
|
||||
c cache.Cache
|
||||
}
|
||||
@@ -41,6 +45,9 @@ func NewSubmissionService(
|
||||
projectRepo repositories.ProjectRepository,
|
||||
commitRepo repositories.CommitRepository,
|
||||
userRepo repositories.UserRepository,
|
||||
wikiRepo repositories.WikiRepository,
|
||||
geometryRepo repositories.GeometryRepository,
|
||||
entityRepo repositories.EntityRepository,
|
||||
db *pgxpool.Pool,
|
||||
c cache.Cache,
|
||||
) SubmissionService {
|
||||
@@ -49,6 +56,9 @@ func NewSubmissionService(
|
||||
projectRepo: projectRepo,
|
||||
commitRepo: commitRepo,
|
||||
userRepo: userRepo,
|
||||
wikiRepo: wikiRepo,
|
||||
geometryRepo: geometryRepo,
|
||||
entityRepo: entityRepo,
|
||||
db: db,
|
||||
c: c,
|
||||
}
|
||||
@@ -78,6 +88,17 @@ func (s *submissionService) CreateSubmission(ctx context.Context, userID string,
|
||||
return nil, fiber.NewError(fiber.StatusBadRequest, "Commit does not belong to project")
|
||||
}
|
||||
|
||||
project, err := s.projectRepo.GetByID(ctx, projectUUID)
|
||||
if err != nil {
|
||||
return nil, fiber.NewError(fiber.StatusNotFound, "Project not found")
|
||||
}
|
||||
|
||||
for _, sub := range project.Submissions {
|
||||
if sub.Status == constants.StatusTypePending {
|
||||
return nil, fiber.NewError(fiber.StatusConflict, "There is already a pending submission for this project")
|
||||
}
|
||||
}
|
||||
|
||||
arg := sqlc.CreateSubmissionParams{
|
||||
ProjectID: projectUUID,
|
||||
CommitID: commitUUID,
|
||||
@@ -95,6 +116,18 @@ func (s *submissionService) CreateSubmission(ctx context.Context, userID string,
|
||||
}
|
||||
|
||||
func (s *submissionService) UpdateSubmissionStatus(ctx context.Context, reviewerID string, submissionID string, dto *request.UpdateSubmissionStatusDto) (*response.SubmissionResponse, *fiber.Error) {
|
||||
tx, err := s.db.Begin(ctx)
|
||||
if err != nil {
|
||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to start transaction")
|
||||
}
|
||||
defer tx.Rollback(ctx)
|
||||
|
||||
submissionRepo := s.submissionRepo.WithTx(tx)
|
||||
commitRepo := s.commitRepo.WithTx(tx)
|
||||
entityRepo := s.entityRepo.WithTx(tx)
|
||||
geometryRepo := s.geometryRepo.WithTx(tx)
|
||||
wikiRepo := s.wikiRepo.WithTx(tx)
|
||||
|
||||
submissionUUID, err := convert.StringToUUID(submissionID)
|
||||
if err != nil {
|
||||
return nil, fiber.NewError(fiber.StatusBadRequest, "Invalid submission ID")
|
||||
@@ -119,6 +152,404 @@ func (s *submissionService) UpdateSubmissionStatus(ctx context.Context, reviewer
|
||||
return nil, fiber.NewError(fiber.StatusBadRequest, "Submission already processed")
|
||||
}
|
||||
|
||||
commitUUID, err := convert.StringToUUID(submission.CommitID)
|
||||
if err != nil {
|
||||
return nil, fiber.NewError(fiber.StatusBadRequest, "Invalid commit ID")
|
||||
}
|
||||
|
||||
commit, err := s.commitRepo.GetByID(ctx, commitUUID)
|
||||
if err != nil {
|
||||
return nil, fiber.NewError(fiber.StatusNotFound, "Commit not found")
|
||||
}
|
||||
|
||||
if commit.ProjectID != submission.ProjectID {
|
||||
return nil, fiber.NewError(fiber.StatusBadRequest, "Commit does not belong to project")
|
||||
}
|
||||
|
||||
if status == constants.StatusTypeApproved {
|
||||
var snapshotData request.CommitSnapshot
|
||||
err = json.Unmarshal(commit.SnapshotJson, &snapshotData)
|
||||
if err != nil {
|
||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to parse commit snapshot")
|
||||
}
|
||||
|
||||
projectUUID, err := convert.StringToUUID(commit.ProjectID)
|
||||
if err != nil {
|
||||
return nil, fiber.NewError(fiber.StatusBadRequest, "Invalid project ID")
|
||||
}
|
||||
currentEntity, err := s.entityRepo.GetByProjectID(ctx, projectUUID)
|
||||
if err != nil {
|
||||
return nil, fiber.NewError(fiber.StatusNotFound, "Entity not found")
|
||||
}
|
||||
|
||||
currentGeometry, err := s.geometryRepo.GetByProjectID(ctx, projectUUID)
|
||||
if err != nil {
|
||||
return nil, fiber.NewError(fiber.StatusNotFound, "Geometry not found")
|
||||
}
|
||||
|
||||
currentWiki, err := s.wikiRepo.GetByProjectID(ctx, projectUUID)
|
||||
if err != nil {
|
||||
return nil, fiber.NewError(fiber.StatusNotFound, "Wiki not found")
|
||||
}
|
||||
|
||||
persistItemIDs := make(map[string]struct{})
|
||||
for _, item := range snapshotData.Entities {
|
||||
persistItemIDs[item.ID] = struct{}{}
|
||||
}
|
||||
for _, item := range snapshotData.Geometries {
|
||||
persistItemIDs[item.ID] = struct{}{}
|
||||
}
|
||||
for _, item := range snapshotData.Wikis {
|
||||
persistItemIDs[item.ID] = struct{}{}
|
||||
}
|
||||
|
||||
persistCurrentItemIDs := make(map[string]struct{})
|
||||
for _, item := range currentEntity {
|
||||
persistCurrentItemIDs[item.ID] = struct{}{}
|
||||
}
|
||||
for _, item := range currentGeometry {
|
||||
persistCurrentItemIDs[item.ID] = struct{}{}
|
||||
}
|
||||
for _, item := range currentWiki {
|
||||
persistCurrentItemIDs[item.ID] = struct{}{}
|
||||
}
|
||||
|
||||
listDeleteEntities := make([]pgtype.UUID, 0)
|
||||
for _, e := range currentEntity {
|
||||
if _, ok := persistItemIDs[e.ID]; !ok {
|
||||
itemUUID, err := convert.StringToUUID(e.ID)
|
||||
if err != nil {
|
||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Invalid entity ID")
|
||||
}
|
||||
listDeleteEntities = append(listDeleteEntities, itemUUID)
|
||||
delete(persistCurrentItemIDs, e.ID)
|
||||
}
|
||||
}
|
||||
|
||||
listDeleteGeometries := make([]pgtype.UUID, 0)
|
||||
for _, g := range currentGeometry {
|
||||
if _, ok := persistItemIDs[g.ID]; !ok {
|
||||
itemUUID, err := convert.StringToUUID(g.ID)
|
||||
if err != nil {
|
||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Invalid geometry ID")
|
||||
}
|
||||
listDeleteGeometries = append(listDeleteGeometries, itemUUID)
|
||||
delete(persistCurrentItemIDs, g.ID)
|
||||
}
|
||||
}
|
||||
|
||||
listDeleteWikis := make([]pgtype.UUID, 0)
|
||||
for _, w := range currentWiki {
|
||||
if _, ok := persistItemIDs[w.ID]; !ok {
|
||||
itemUUID, err := convert.StringToUUID(w.ID)
|
||||
if err != nil {
|
||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Invalid wiki ID")
|
||||
}
|
||||
listDeleteWikis = append(listDeleteWikis, itemUUID)
|
||||
delete(persistCurrentItemIDs, w.ID)
|
||||
}
|
||||
}
|
||||
|
||||
if len(listDeleteEntities) > 0 {
|
||||
if err = entityRepo.DeleteByIDs(ctx, listDeleteEntities); err != nil {
|
||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to delete entities")
|
||||
}
|
||||
}
|
||||
|
||||
if len(listDeleteGeometries) > 0 {
|
||||
if err = geometryRepo.DeleteByIDs(ctx, listDeleteGeometries); err != nil {
|
||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to delete geometries")
|
||||
}
|
||||
}
|
||||
|
||||
if len(listDeleteWikis) > 0 {
|
||||
if err = wikiRepo.DeleteByIDs(ctx, listDeleteWikis); err != nil {
|
||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to delete wikis")
|
||||
}
|
||||
}
|
||||
|
||||
refEntityIDs := []string{}
|
||||
for _, e := range snapshotData.Entities {
|
||||
if e.Source == "ref" {
|
||||
refEntityIDs = append(refEntityIDs, e.ID)
|
||||
}
|
||||
}
|
||||
refEntities, _ := s.entityRepo.GetByIDs(ctx, refEntityIDs)
|
||||
refEntityMap := make(map[string]bool)
|
||||
for _, e := range refEntities {
|
||||
refEntityMap[e.ID] = true
|
||||
}
|
||||
|
||||
newEntities := make([]*request.EntitySnapshot, 0, len(snapshotData.Entities))
|
||||
for i, entity := range snapshotData.Entities {
|
||||
if entity.Operation == "delete" {
|
||||
continue
|
||||
}
|
||||
|
||||
entityUUID, err := convert.StringToUUID(entity.ID)
|
||||
if err != nil {
|
||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Invalid entity ID")
|
||||
}
|
||||
|
||||
if _, ok := persistCurrentItemIDs[entity.ID]; ok {
|
||||
_, err := entityRepo.Update(ctx, sqlc.UpdateEntityParams{
|
||||
Name: convert.StringToText(entity.Name),
|
||||
Description: convert.StringToText(entity.Description),
|
||||
Slug: convert.PtrToText(entity.Slug),
|
||||
Status: convert.PtrToInt2(entity.Status),
|
||||
ID: entityUUID,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to update entity: "+entity.ID)
|
||||
}
|
||||
|
||||
newEntities = append(newEntities, snapshotData.Entities[i])
|
||||
|
||||
} else if entity.Source == "inline" {
|
||||
_, err := entityRepo.Create(ctx, sqlc.CreateEntityParams{
|
||||
ID: entityUUID,
|
||||
Name: entity.Name,
|
||||
Description: convert.StringToText(entity.Description),
|
||||
ProjectID: projectUUID,
|
||||
Slug: convert.PtrToText(entity.Slug),
|
||||
Status: convert.PtrToInt2(entity.Status),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to create entity: "+entity.ID)
|
||||
}
|
||||
|
||||
newEntities = append(newEntities, snapshotData.Entities[i])
|
||||
|
||||
} else if entity.Source == "ref" {
|
||||
if !refEntityMap[entity.ID] {
|
||||
continue
|
||||
}
|
||||
newEntities = append(newEntities, snapshotData.Entities[i])
|
||||
}
|
||||
}
|
||||
snapshotData.Entities = newEntities
|
||||
|
||||
refGeometryIDs := []string{}
|
||||
for _, g := range snapshotData.Geometries {
|
||||
if g.Source == "ref" {
|
||||
refGeometryIDs = append(refGeometryIDs, g.ID)
|
||||
}
|
||||
}
|
||||
refGeometries, _ := s.geometryRepo.GetByIDs(ctx, refGeometryIDs)
|
||||
refGeometryMap := make(map[string]bool)
|
||||
for _, g := range refGeometries {
|
||||
refGeometryMap[g.ID] = true
|
||||
}
|
||||
|
||||
newGeometries := make([]*request.GeometrySnapshot, 0, len(snapshotData.Geometries))
|
||||
for i, geo := range snapshotData.Geometries {
|
||||
if geo.Operation == "delete" {
|
||||
continue
|
||||
}
|
||||
|
||||
geometryUUID, err := convert.StringToUUID(geo.ID)
|
||||
if err != nil {
|
||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Invalid geometry ID")
|
||||
}
|
||||
|
||||
binding, _ := json.Marshal(geo.Binding)
|
||||
|
||||
if _, ok := persistCurrentItemIDs[geo.ID]; ok {
|
||||
params := sqlc.UpdateGeometryParams{
|
||||
ID: geometryUUID,
|
||||
GeoType: pgtype.Int2{Int16: constants.ParseGeoTypeText(geo.Type).Int16(), Valid: true},
|
||||
DrawGeometry: geo.DrawGeometry,
|
||||
Binding: binding,
|
||||
TimeStart: convert.PtrFloat64ToInt4(geo.TimeStart),
|
||||
TimeEnd: convert.PtrFloat64ToInt4(geo.TimeEnd),
|
||||
ProjectID: projectUUID,
|
||||
}
|
||||
|
||||
if geo.BBox != nil {
|
||||
params.UpdateBbox = pgtype.Bool{Bool: true, Valid: true}
|
||||
params.MinLng = pgtype.Float8{Float64: geo.BBox.MinLng, Valid: true}
|
||||
params.MinLat = pgtype.Float8{Float64: geo.BBox.MinLat, Valid: true}
|
||||
params.MaxLng = pgtype.Float8{Float64: geo.BBox.MaxLng, Valid: true}
|
||||
params.MaxLat = pgtype.Float8{Float64: geo.BBox.MaxLat, Valid: true}
|
||||
}
|
||||
|
||||
_, err := geometryRepo.Update(ctx, params)
|
||||
if err != nil {
|
||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to update geometry: "+geo.ID)
|
||||
}
|
||||
newGeometries = append(newGeometries, snapshotData.Geometries[i])
|
||||
|
||||
} else if geo.Source == "inline" {
|
||||
params := sqlc.CreateGeometryParams{
|
||||
ID: geometryUUID,
|
||||
GeoType: constants.ParseGeoTypeText(geo.Type).Int16(),
|
||||
DrawGeometry: geo.DrawGeometry,
|
||||
Binding: binding,
|
||||
TimeStart: convert.PtrFloat64ToInt4(geo.TimeStart),
|
||||
TimeEnd: convert.PtrFloat64ToInt4(geo.TimeEnd),
|
||||
ProjectID: projectUUID,
|
||||
}
|
||||
if geo.BBox != nil {
|
||||
params.MinLng = geo.BBox.MinLng
|
||||
params.MinLat = geo.BBox.MinLat
|
||||
params.MaxLng = geo.BBox.MaxLng
|
||||
params.MaxLat = geo.BBox.MaxLat
|
||||
}
|
||||
|
||||
_, err := geometryRepo.Create(ctx, params)
|
||||
if err != nil {
|
||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to create geometry: "+geo.ID)
|
||||
}
|
||||
newGeometries = append(newGeometries, snapshotData.Geometries[i])
|
||||
|
||||
} else if geo.Source == "ref" {
|
||||
if !refGeometryMap[geo.ID] {
|
||||
continue
|
||||
}
|
||||
newGeometries = append(newGeometries, snapshotData.Geometries[i])
|
||||
}
|
||||
}
|
||||
snapshotData.Geometries = newGeometries
|
||||
|
||||
refWikiIDs := []string{}
|
||||
for _, w := range snapshotData.Wikis {
|
||||
if w.Source == "ref" {
|
||||
refWikiIDs = append(refWikiIDs, w.ID)
|
||||
}
|
||||
}
|
||||
refWikis, _ := s.wikiRepo.GetByIDs(ctx, refWikiIDs)
|
||||
refWikiMap := make(map[string]bool)
|
||||
for _, w := range refWikis {
|
||||
refWikiMap[w.ID] = true
|
||||
}
|
||||
|
||||
newWikis := make([]*request.WikiSnapshot, 0, len(snapshotData.Wikis))
|
||||
for i, wiki := range snapshotData.Wikis {
|
||||
if wiki.Operation == "delete" {
|
||||
continue
|
||||
}
|
||||
|
||||
wikiUUID, err := convert.StringToUUID(wiki.ID)
|
||||
if err != nil {
|
||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Invalid wiki ID")
|
||||
}
|
||||
|
||||
if _, ok := persistCurrentItemIDs[wiki.ID]; ok {
|
||||
_, err := wikiRepo.Update(ctx, sqlc.UpdateWikiParams{
|
||||
ID: wikiUUID,
|
||||
Title: convert.StringToText(wiki.Title),
|
||||
Content: wiki.Doc,
|
||||
ProjectID: projectUUID,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to update wiki: "+wiki.ID)
|
||||
}
|
||||
newWikis = append(newWikis, snapshotData.Wikis[i])
|
||||
|
||||
} else if wiki.Source == "inline" {
|
||||
_, err := wikiRepo.Create(ctx, sqlc.CreateWikiParams{
|
||||
ID: wikiUUID,
|
||||
Title: convert.StringToText(wiki.Title),
|
||||
Content: wiki.Doc,
|
||||
ProjectID: projectUUID,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to create wiki: "+wiki.ID)
|
||||
}
|
||||
newWikis = append(newWikis, snapshotData.Wikis[i])
|
||||
|
||||
} else if wiki.Source == "ref" {
|
||||
if !refWikiMap[wiki.ID] {
|
||||
continue
|
||||
}
|
||||
newWikis = append(newWikis, snapshotData.Wikis[i])
|
||||
}
|
||||
}
|
||||
snapshotData.Wikis = newWikis
|
||||
|
||||
err = geometryRepo.DeleteEntityGeometriesByProjectID(ctx, projectUUID)
|
||||
if err != nil {
|
||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to delete geometry entity: "+err.Error())
|
||||
}
|
||||
err = wikiRepo.DeleteEntityWikisByProjectID(ctx, projectUUID)
|
||||
if err != nil {
|
||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to delete wiki entity: "+err.Error())
|
||||
}
|
||||
|
||||
validEntities := make(map[string]bool)
|
||||
for _, e := range snapshotData.Entities {
|
||||
validEntities[e.ID] = true
|
||||
}
|
||||
validGeometries := make(map[string]bool)
|
||||
for _, g := range snapshotData.Geometries {
|
||||
validGeometries[g.ID] = true
|
||||
}
|
||||
validWikis := make(map[string]bool)
|
||||
for _, w := range snapshotData.Wikis {
|
||||
validWikis[w.ID] = true
|
||||
}
|
||||
|
||||
if len(snapshotData.GeometryEntity) > 0 {
|
||||
geomLinks := make(map[string][]pgtype.UUID)
|
||||
for _, link := range snapshotData.GeometryEntity {
|
||||
if !validEntities[link.EntityID] || !validGeometries[link.GeometryID] {
|
||||
continue
|
||||
}
|
||||
gID, _ := convert.StringToUUID(link.GeometryID)
|
||||
geomLinks[link.EntityID] = append(geomLinks[link.EntityID], gID)
|
||||
}
|
||||
|
||||
for eIDStr, gIDs := range geomLinks {
|
||||
eID, _ := convert.StringToUUID(eIDStr)
|
||||
err = geometryRepo.CreateEntityGeometries(ctx, sqlc.CreateEntityGeometriesParams{
|
||||
EntityID: eID,
|
||||
GeometryIds: gIDs,
|
||||
ProjectID: projectUUID,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to create geometry entity: "+err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(snapshotData.EntityWiki) > 0 {
|
||||
wikiLinks := make(map[string][]pgtype.UUID)
|
||||
for _, link := range snapshotData.EntityWiki {
|
||||
if link.Operation == "delete" || (link.IsDeleted != nil && *link.IsDeleted == 1) {
|
||||
continue
|
||||
}
|
||||
if !validEntities[link.EntityID] || !validWikis[link.WikiID] {
|
||||
continue
|
||||
}
|
||||
wID, _ := convert.StringToUUID(link.WikiID)
|
||||
wikiLinks[link.EntityID] = append(wikiLinks[link.EntityID], wID)
|
||||
}
|
||||
|
||||
for eIDStr, wIDs := range wikiLinks {
|
||||
eID, _ := convert.StringToUUID(eIDStr)
|
||||
err = wikiRepo.CreateEntityWikis(ctx, sqlc.CreateEntityWikisParams{
|
||||
EntityID: eID,
|
||||
WikiIds: wIDs,
|
||||
ProjectID: projectUUID,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to create wiki entity: "+err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
newSnapshot, err := json.Marshal(snapshotData)
|
||||
if err != nil {
|
||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to marshal snapshot")
|
||||
}
|
||||
_, err = commitRepo.UpdateSnapshot(ctx, commitUUID, newSnapshot)
|
||||
if err != nil {
|
||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to update snapshot: "+err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
arg := sqlc.UpdateSubmissionParams{
|
||||
ID: submissionUUID,
|
||||
Status: pgtype.Int2{Int16: status.Int16(), Valid: true},
|
||||
@@ -126,11 +557,25 @@ func (s *submissionService) UpdateSubmissionStatus(ctx context.Context, reviewer
|
||||
ReviewNote: convert.StringToText(dto.ReviewNote),
|
||||
}
|
||||
|
||||
updatedSubmission, err := s.submissionRepo.Update(ctx, arg)
|
||||
updatedSubmission, err := submissionRepo.Update(ctx, arg)
|
||||
|
||||
if err != nil {
|
||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to update submission status")
|
||||
}
|
||||
|
||||
err = tx.Commit(ctx)
|
||||
if err != nil {
|
||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to commit transaction")
|
||||
}
|
||||
|
||||
if status == constants.StatusTypeApproved {
|
||||
go func() {
|
||||
bgCtx := context.Background()
|
||||
_ = s.c.DelByPattern(bgCtx, "entity:search*")
|
||||
_ = s.c.DelByPattern(bgCtx, "geometry:search*")
|
||||
_ = s.c.DelByPattern(bgCtx, "wiki:search*")
|
||||
}()
|
||||
}
|
||||
_ = s.c.Del(ctx, fmt.Sprintf("project:id:%s", submission.ProjectID))
|
||||
|
||||
return updatedSubmission.ToResponse(), nil
|
||||
|
||||
@@ -58,6 +58,7 @@ func (s *wikiService) SearchWikis(ctx context.Context, req *request.SearchWikiDt
|
||||
if req.Title != "" {
|
||||
params.Title = req.Title
|
||||
}
|
||||
|
||||
if req.EntityID != "" {
|
||||
entityId, err := convert.StringToUUID(req.EntityID)
|
||||
if err == nil {
|
||||
@@ -65,6 +66,13 @@ func (s *wikiService) SearchWikis(ctx context.Context, req *request.SearchWikiDt
|
||||
}
|
||||
}
|
||||
|
||||
if req.ProjectID != nil {
|
||||
projectID, err := convert.StringToUUID(*req.ProjectID)
|
||||
if err == nil {
|
||||
params.ProjectID = projectID
|
||||
}
|
||||
}
|
||||
|
||||
wikis, err := s.wikiRepo.Search(ctx, params)
|
||||
if err != nil {
|
||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to search wikis")
|
||||
|
||||
Reference in New Issue
Block a user