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:
@@ -105,7 +105,10 @@ func (s *FiberServer) SetupServer(
|
||||
wikiService := services.NewWikiService(wikiRepo)
|
||||
projectService := services.NewProjectService(projectRepo)
|
||||
commitService := services.NewCommitService(poolPg, commitRepo, projectRepo)
|
||||
submissionService := services.NewSubmissionService(submissionRepo, projectRepo, commitRepo, userRepo, poolPg, redis)
|
||||
submissionService := services.NewSubmissionService(
|
||||
submissionRepo, projectRepo, commitRepo,
|
||||
userRepo, wikiRepo, geometryRepo, entityRepo, poolPg, redis,
|
||||
)
|
||||
|
||||
// controller setup
|
||||
authController := controllers.NewAuthController(authService, oauth)
|
||||
|
||||
355
commit_snapshot.md
Normal file
355
commit_snapshot.md
Normal file
@@ -0,0 +1,355 @@
|
||||
# Commit Snapshot (`commits.snapshot_json`) - Chuẩn Hiện Tại (FrontEndAdmin)
|
||||
|
||||
Tài liệu này mô tả **commit snapshot** được `FrontEndAdmin` tạo ra khi bấm **Commit** trong `/editor`, và được lưu vào `BackEndGo.commits.snapshot_json` (JSONB).
|
||||
|
||||
Nguồn tham chiếu trong code:
|
||||
|
||||
- Type snapshot: `FrontEndAdmin/src/uhm/types/sections.ts` (`EditorSnapshot`)
|
||||
- Build snapshot: `FrontEndAdmin/src/uhm/lib/editor/snapshot/editorSnapshot.ts` (`buildEditorSnapshot`)
|
||||
|
||||
## 1) Tổng Quan Schema
|
||||
|
||||
Snapshot hiện tại:
|
||||
|
||||
- Không có `schema_version`.
|
||||
- Không lưu `section` (entity trong DB là `projects`; project được xác định bằng context record `commits.project_id`).
|
||||
- Không dùng `ref:{id}` nữa: **`id` là canonical**, `source:"ref"` nghĩa là tham chiếu theo `id`.
|
||||
|
||||
```ts
|
||||
export type CommitSnapshot = {
|
||||
editor_feature_collection?: FeatureCollection;
|
||||
|
||||
entities?: EntitySnapshot[];
|
||||
geometries?: GeometrySnapshot[];
|
||||
wikis?: WikiSnapshot[];
|
||||
|
||||
geometry_entity?: GeometryEntitySnapshot[]; // geometry ↔ entity (many-to-many)
|
||||
entity_wiki?: EntityWikiLinkSnapshot[]; // entity ↔ wiki
|
||||
};
|
||||
```
|
||||
|
||||
## 1.1 Type đầy đủ (TypeScript)
|
||||
|
||||
Đây là bản type "đúng để BEGo implement chuyển đổi snapshot → DB". FE có thể gửi thêm field legacy (xem mục 6), nhưng BE nên normalize theo các type dưới đây.
|
||||
|
||||
```ts
|
||||
// ---- GeoJSON ----
|
||||
|
||||
export type Geometry =
|
||||
| { type: "Point"; coordinates: [number, number] }
|
||||
| { type: "MultiPoint"; coordinates: [number, number][] }
|
||||
| { type: "LineString"; coordinates: [number, number][] }
|
||||
| { type: "MultiLineString"; coordinates: [number, number][][] }
|
||||
| { type: "Polygon"; coordinates: [number, number][][] }
|
||||
| { type: "MultiPolygon"; coordinates: [number, number][][][] };
|
||||
|
||||
export type FeatureId = string | number; // FE hiện dùng UUIDv7 string
|
||||
|
||||
export type FeatureProperties = {
|
||||
id: FeatureId;
|
||||
type?: string | null;
|
||||
geometry_preset?: string | null;
|
||||
time_start?: number | null;
|
||||
time_end?: number | null;
|
||||
binding?: string[]; // entity ids used as "binding filter"
|
||||
|
||||
// Legacy UI fields. FE persist snapshot hiện tại KHONG gửi các field này,
|
||||
// nhưng BE nên ignore nếu gặp trong snapshot cũ:
|
||||
entity_id?: string | null;
|
||||
entity_ids?: string[];
|
||||
entity_name?: string | null;
|
||||
entity_names?: string[];
|
||||
entity_type_id?: string | null;
|
||||
};
|
||||
|
||||
export type Feature = {
|
||||
type: "Feature";
|
||||
properties: FeatureProperties;
|
||||
geometry: Geometry;
|
||||
};
|
||||
|
||||
export type FeatureCollection = {
|
||||
type: "FeatureCollection";
|
||||
features: Feature[];
|
||||
};
|
||||
|
||||
// ---- Snapshot rows ----
|
||||
|
||||
export type SnapshotSource = "inline" | "ref";
|
||||
|
||||
export type EntitySnapshotOperation = "create" | "update" | "delete" | "reference";
|
||||
export type GeometrySnapshotOperation = "create" | "update" | "delete" | "reference";
|
||||
export type WikiSnapshotOperation = "create" | "update" | "delete" | "reference";
|
||||
|
||||
export type EntitySnapshot = {
|
||||
id: string; // UUIDv7 string (canonical)
|
||||
source: SnapshotSource;
|
||||
operation?: EntitySnapshotOperation;
|
||||
name?: string;
|
||||
slug?: string | null;
|
||||
description?: string | null;
|
||||
type_id?: string | null;
|
||||
status?: number | null;
|
||||
base_updated_at?: string;
|
||||
base_hash?: string;
|
||||
};
|
||||
|
||||
export type GeometrySnapshot = {
|
||||
id: string; // UUIDv7 string (canonical)
|
||||
source: SnapshotSource;
|
||||
operation?: GeometrySnapshotOperation;
|
||||
|
||||
// Present when source:"inline" (draft features)
|
||||
type?: string | null;
|
||||
draw_geometry?: Geometry;
|
||||
binding?: string[];
|
||||
time_start?: number | null;
|
||||
time_end?: number | null;
|
||||
bbox?: {
|
||||
min_lng: number;
|
||||
min_lat: number;
|
||||
max_lng: number;
|
||||
max_lat: number;
|
||||
} | null;
|
||||
|
||||
base_updated_at?: string;
|
||||
base_hash?: string;
|
||||
};
|
||||
|
||||
export type WikiSnapshot = {
|
||||
id: string; // UUIDv7 string (canonical)
|
||||
source: SnapshotSource;
|
||||
operation?: WikiSnapshotOperation;
|
||||
title: string;
|
||||
doc: unknown; // tiptap JSON (inline) hoặc null (ref)
|
||||
updated_at?: string;
|
||||
};
|
||||
|
||||
// ---- Join tables ----
|
||||
|
||||
export type GeometryEntitySnapshot = {
|
||||
geometry_id: string;
|
||||
entity_id: string;
|
||||
base_links_hash?: string;
|
||||
};
|
||||
|
||||
export type EntityWikiLinkSnapshot = {
|
||||
entity_id: string;
|
||||
wiki_id: string;
|
||||
// If missing, BE should treat as "reference" (active link) for backwards-compat.
|
||||
operation?: "reference" | "delete";
|
||||
};
|
||||
|
||||
// ---- Root ----
|
||||
|
||||
export type CommitSnapshot = {
|
||||
editor_feature_collection?: FeatureCollection;
|
||||
entities?: EntitySnapshot[];
|
||||
geometries?: GeometrySnapshot[];
|
||||
wikis?: WikiSnapshot[];
|
||||
geometry_entity?: GeometryEntitySnapshot[];
|
||||
entity_wiki?: EntityWikiLinkSnapshot[];
|
||||
};
|
||||
```
|
||||
|
||||
## 2) Quy Ước `source` và `operation`
|
||||
|
||||
### 2.1 `source` (bắt buộc)
|
||||
|
||||
`source` bắt buộc là một trong:
|
||||
|
||||
- `inline`: dữ liệu được embed trong snapshot_json.
|
||||
- `ref`: dữ liệu là tham chiếu (theo `id`), cần fetch bên ngoài nếu muốn đầy đủ.
|
||||
|
||||
FE hiện tại luôn ghi `source` cho `entities[]`, `geometries[]`, `wikis[]`.
|
||||
|
||||
### 2.2 `operation` (tùy chọn)
|
||||
|
||||
`operation` là tùy chọn. Khi **không có** `operation` thì hiểu là:
|
||||
|
||||
- row được đưa vào snapshot như **project context** (hoặc không đổi trong commit này),
|
||||
- commit này không sửa record, và cũng không cần đánh dấu là `"reference"` để làm “đầu mối nối”.
|
||||
|
||||
`operation` có thể xuất hiện ở:
|
||||
|
||||
- `entities[].operation`: `create` | `update` | `delete` | `reference`
|
||||
- `geometries[].operation`: `create` | `update` | `delete` | `reference`
|
||||
- `wikis[].operation`: `create` | `update` | `delete` | `reference`
|
||||
|
||||
`geometry_entity[]` không có `operation` (join table state).
|
||||
|
||||
`entity_wiki[]` dùng `operation:"reference"|"delete"` để biểu diễn link/unlink **trong snapshot** (không phải delete trong DB).
|
||||
|
||||
## 3) Ý Nghĩa Từng Phần
|
||||
|
||||
### 3.1 `editor_feature_collection`
|
||||
|
||||
GeoJSON `FeatureCollection` là nguồn để:
|
||||
|
||||
- render map trong editor,
|
||||
- làm cơ sở build `geometries[]` và join table `geometry_entity[]`.
|
||||
|
||||
Lưu ý quan trọng:
|
||||
|
||||
- Snapshot persist **không lưu** các field entity denormalize trên `feature.properties`:
|
||||
`entity_id/entity_ids/entity_name/entity_names/entity_type_id`.
|
||||
- Quan hệ geometry ↔ entity nằm ở `geometry_entity[]`.
|
||||
- Khi load commit vào editor, FE có thể rehydrate `entity_ids/entity_id` lên features từ `geometry_entity[]` để UI hoạt động, nhưng đó không phải dữ liệu persist.
|
||||
|
||||
### 3.2 `entities[]`
|
||||
|
||||
`entities[]` là danh sách entity liên quan tới project/commit. Mỗi row có `source` và có thể có/không có `operation`.
|
||||
|
||||
FE build `entities[]` từ:
|
||||
|
||||
1. Pending entities tạo mới trong editor:
|
||||
`source:"inline"`, `operation:"create"`.
|
||||
|
||||
2. Entity được user “pin” vào project từ search (không gắn geometry, không link wiki):
|
||||
`source:"ref"`, không có `operation`.
|
||||
|
||||
3. Entities xuất hiện trong `geometry_entity[]`:
|
||||
`source:"ref"`, `operation:"reference"`.
|
||||
|
||||
4. Entities xuất hiện trong `entity_wiki[]`:
|
||||
`source:"ref"`, `operation:"reference"`.
|
||||
|
||||
### 3.3 `geometries[]`
|
||||
|
||||
Mỗi `Feature` trong `editor_feature_collection.features[]` sinh 1 `GeometrySnapshot` row:
|
||||
|
||||
- `id = String(feature.properties.id)`
|
||||
- `source:"inline"`
|
||||
- `draw_geometry = feature.geometry`
|
||||
- kèm `type`, `binding`, `time_start/time_end`, `bbox` (nếu tính được)
|
||||
|
||||
`operation` cho geometry:
|
||||
|
||||
- `create`: feature mới
|
||||
- `update`: feature thay đổi
|
||||
- (không có `operation`): feature không đổi (không delta trong commit)
|
||||
|
||||
Nếu feature bị xoá khỏi draft, FE thêm 1 delete row:
|
||||
|
||||
```json
|
||||
{ "id": "g_1", "source": "ref", "operation": "delete" }
|
||||
```
|
||||
|
||||
Lưu ý: geometry `operation:"delete"` **không xuất hiện trên map**, vì map render theo `editor_feature_collection.features[]`.
|
||||
|
||||
Gợi ý cho BE khi apply vào DB:
|
||||
|
||||
- Có thể coi `editor_feature_collection` là state hiện tại để render/map.
|
||||
- `geometries[]` là "rows + deltas": sẽ có 1 row cho mỗi feature đang tồn tại trong draft (có/không có `operation`), và có thể có thêm các row `operation:"delete"` để xoá geometry khỏi project state.
|
||||
|
||||
### 3.4 `geometry_entity[]` (join table Geometry ↔ Entity)
|
||||
|
||||
Join table many-to-many giữa geometry và entity. Mỗi cặp geometry↔entity là một row:
|
||||
|
||||
```ts
|
||||
{ geometry_id: string; entity_id: string }
|
||||
```
|
||||
|
||||
### 3.5 `wikis[]`
|
||||
|
||||
Danh sách wiki của project tại thời điểm commit:
|
||||
|
||||
- Wiki tạo mới: `source:"inline"`, `operation:"create"`, `doc` là tiptap JSON.
|
||||
- Wiki sửa: `source:"inline"`, `operation:"update"`, `doc` là tiptap JSON.
|
||||
- Wiki không đổi: thường không có `operation`.
|
||||
- Wiki add từ search (wiki đã có trong DB): `source:"ref"`, `operation:"reference"`, `doc` có thể là `null`.
|
||||
|
||||
### 3.6 `entity_wiki[]` (join table Entity ↔ Wiki)
|
||||
|
||||
```ts
|
||||
export type EntityWikiLinkSnapshot = {
|
||||
entity_id: string;
|
||||
wiki_id: string;
|
||||
operation?: "reference" | "delete";
|
||||
};
|
||||
```
|
||||
|
||||
Toggle link trong UI:
|
||||
|
||||
- Tick checkbox: `{ operation: "reference" }`
|
||||
- Untick checkbox: `{ operation: "delete" }`
|
||||
|
||||
## 4) Ví Dụ JSON (rút gọn)
|
||||
|
||||
```json
|
||||
{
|
||||
"editor_feature_collection": {
|
||||
"type": "FeatureCollection",
|
||||
"features": [
|
||||
{
|
||||
"type": "Feature",
|
||||
"properties": {
|
||||
"id": "g_1",
|
||||
"type": "city",
|
||||
"time_start": 1200,
|
||||
"time_end": 1300,
|
||||
"binding": []
|
||||
},
|
||||
"geometry": { "type": "Point", "coordinates": [105.8, 21.0] }
|
||||
}
|
||||
]
|
||||
},
|
||||
"entities": [
|
||||
{ "id": "e_2", "source": "ref", "name": "Pinned Entity" },
|
||||
{ "id": "e_1", "source": "ref", "operation": "reference", "name": "Ha Noi", "type_id": "city", "status": 1 }
|
||||
],
|
||||
"geometries": [
|
||||
{
|
||||
"id": "g_1",
|
||||
"source": "inline",
|
||||
"operation": "update",
|
||||
"type": "city",
|
||||
"draw_geometry": { "type": "Point", "coordinates": [105.8, 21.0] },
|
||||
"binding": [],
|
||||
"time_start": 1200,
|
||||
"time_end": 1300,
|
||||
"bbox": { "min_lng": 105.8, "min_lat": 21.0, "max_lng": 105.8, "max_lat": 21.0 }
|
||||
}
|
||||
],
|
||||
"geometry_entity": [
|
||||
{ "geometry_id": "g_1", "entity_id": "e_1" }
|
||||
],
|
||||
"wikis": [
|
||||
{
|
||||
"id": "w_inline_1",
|
||||
"source": "inline",
|
||||
"operation": "create",
|
||||
"title": "Overview",
|
||||
"doc": { "type": "doc", "content": [{ "type": "paragraph" }] }
|
||||
},
|
||||
{
|
||||
"id": "019d...wiki_from_db",
|
||||
"source": "ref",
|
||||
"operation": "reference",
|
||||
"title": "Existing Wiki (DB)",
|
||||
"doc": null
|
||||
}
|
||||
],
|
||||
"entity_wiki": [
|
||||
{ "entity_id": "e_1", "wiki_id": "w_inline_1", "operation": "reference" }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## 5) Notes Cho BackEnd (Normalize + Compat)
|
||||
|
||||
BE nên normalize trước khi convert snapshot → DB:
|
||||
|
||||
- Ignore toàn bộ field entity denormalize trên `feature.properties` (nếu có): `entity_id/entity_ids/entity_name/entity_names/entity_type_id`. Quan hệ geometry↔entity lấy từ `geometry_entity[]`.
|
||||
- `entity_wiki[].operation`:
|
||||
- `"reference"`: link active
|
||||
- `"delete"`: link removed trong snapshot
|
||||
- missing: treat as `"reference"` (compat)
|
||||
|
||||
## 6) Legacy Compatibility (nếu gặp snapshot cũ)
|
||||
|
||||
FE đã từng gửi các field legacy; BE có thể gặp nếu đang xử lý commit cũ:
|
||||
|
||||
- `entity_wikis` (plural) thay vì `entity_wiki` (singular): treat như nhau.
|
||||
- `ref:{id}` trong `entities/geometries/wikis`: ignore (id canonical).
|
||||
- `is_deleted` trong join table entity↔wiki: map sang `operation:"delete"` khi `is_deleted==1`, ngược lại `"reference"`.
|
||||
@@ -23,3 +23,6 @@ ON projects (project_status, updated_at DESC);
|
||||
|
||||
CREATE INDEX idx_projects_title_trgm
|
||||
ON projects USING GIN (title gin_trgm_ops);
|
||||
|
||||
|
||||
|
||||
@@ -1,17 +1,21 @@
|
||||
|
||||
CREATE TABLE IF NOT EXISTS entities (
|
||||
id UUID PRIMARY KEY DEFAULT uuidv7(),
|
||||
project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
|
||||
name TEXT NOT NULL,
|
||||
slug TEXT,
|
||||
description TEXT,
|
||||
thumbnail_url TEXT,
|
||||
status SMALLINT,
|
||||
is_deleted BOOLEAN NOT NULL DEFAULT false,
|
||||
created_at TIMESTAMPTZ DEFAULT now(),
|
||||
updated_at TIMESTAMPTZ DEFAULT now()
|
||||
);
|
||||
|
||||
|
||||
CREATE INDEX idx_entities_name_search
|
||||
ON entities USING GIN (name gin_trgm_ops);
|
||||
|
||||
CREATE INDEX idx_entities_project_id ON entities(project_id);
|
||||
|
||||
CREATE INDEX idx_entities_created_active
|
||||
ON entities(created_at DESC)
|
||||
WHERE is_deleted = false;
|
||||
@@ -2,8 +2,9 @@ CREATE EXTENSION IF NOT EXISTS pg_trgm;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS wikis (
|
||||
id UUID PRIMARY KEY DEFAULT uuidv7(),
|
||||
project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
|
||||
title TEXT,
|
||||
content TEXT,
|
||||
content JSONB,
|
||||
is_deleted BOOLEAN NOT NULL DEFAULT false,
|
||||
created_at TIMESTAMPTZ DEFAULT now(),
|
||||
updated_at TIMESTAMPTZ DEFAULT now()
|
||||
@@ -13,9 +14,12 @@ CREATE TABLE IF NOT EXISTS wikis (
|
||||
CREATE TABLE IF NOT EXISTS entity_wikis (
|
||||
entity_id UUID REFERENCES entities(id) ON DELETE CASCADE,
|
||||
wiki_id UUID REFERENCES wikis(id) ON DELETE CASCADE,
|
||||
project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
|
||||
PRIMARY KEY (entity_id, wiki_id)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_entity_wikis_project_id ON entity_wikis(project_id);
|
||||
|
||||
CREATE INDEX idx_entity_wikis_wiki_id
|
||||
ON entity_wikis(wiki_id);
|
||||
|
||||
@@ -27,6 +31,8 @@ CREATE INDEX idx_wikis_title_search
|
||||
ON wikis USING GIN (title gin_trgm_ops)
|
||||
WHERE is_deleted = false;
|
||||
|
||||
CREATE INDEX idx_wikis_project_id ON wikis(project_id);
|
||||
|
||||
CREATE TRIGGER trigger_wikis_updated_at
|
||||
BEFORE UPDATE ON wikis
|
||||
FOR EACH ROW
|
||||
@@ -4,6 +4,7 @@ CREATE EXTENSION IF NOT EXISTS postgis;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS geometries (
|
||||
id UUID PRIMARY KEY DEFAULT uuidv7(),
|
||||
project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
|
||||
geo_type SMALLINT NOT NULL DEFAULT 1,
|
||||
draw_geometry JSONB NOT NULL,
|
||||
binding JSONB,
|
||||
@@ -18,15 +19,12 @@ CREATE TABLE IF NOT EXISTS geometries (
|
||||
CREATE TABLE IF NOT EXISTS entity_geometries (
|
||||
entity_id UUID REFERENCES entities(id) ON DELETE CASCADE,
|
||||
geometry_id UUID REFERENCES geometries(id) ON DELETE CASCADE,
|
||||
project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
|
||||
PRIMARY KEY (entity_id, geometry_id)
|
||||
);
|
||||
|
||||
DROP INDEX IF EXISTS idx_geom_draw_geometry;
|
||||
DROP INDEX IF EXISTS idx_geom_bbox;
|
||||
DROP INDEX IF EXISTS idx_geom_time_range;
|
||||
DROP INDEX IF EXISTS idx_entity_geometries_geometry;
|
||||
DROP INDEX IF EXISTS idx_geom_binding;
|
||||
DROP INDEX IF EXISTS idx_geom_updated_at;
|
||||
CREATE INDEX idx_entity_geometries_project_id ON entity_geometries(project_id);
|
||||
|
||||
|
||||
CREATE INDEX idx_geom_draw_geometry
|
||||
ON geometries USING GIN (draw_geometry);
|
||||
@@ -49,6 +47,8 @@ CREATE INDEX idx_geom_updated_at
|
||||
ON geometries (updated_at DESC)
|
||||
WHERE is_deleted = false;
|
||||
|
||||
CREATE INDEX idx_geometries_project_id ON geometries(project_id);
|
||||
|
||||
DROP TRIGGER IF EXISTS trigger_geometries_updated_at ON geometries;
|
||||
CREATE TRIGGER trigger_geometries_updated_at
|
||||
BEFORE UPDATE ON geometries
|
||||
@@ -34,3 +34,9 @@ LIMIT sqlc.arg('limit');
|
||||
|
||||
-- name: GetCommitsByIDs :many
|
||||
SELECT * FROM commits WHERE id = ANY($1::uuid[]) AND is_deleted = false;
|
||||
|
||||
-- name: UpdateCommitSnapshot :one
|
||||
UPDATE commits
|
||||
SET snapshot_json = $2
|
||||
WHERE id = $1
|
||||
RETURNING *;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
-- name: CreateEntity :one
|
||||
INSERT INTO entities (
|
||||
name, description, thumbnail_url
|
||||
id, name, slug, description, project_id, status
|
||||
) VALUES (
|
||||
$1, $2, $3
|
||||
COALESCE(sqlc.narg('id')::uuid, uuidv7()), $1, $2, $3, $4, $5
|
||||
)
|
||||
RETURNING *;
|
||||
|
||||
@@ -17,8 +17,10 @@ WHERE id = $1 AND is_deleted = false;
|
||||
UPDATE entities
|
||||
SET
|
||||
name = COALESCE(sqlc.narg('name'), name),
|
||||
slug = COALESCE(sqlc.narg('slug'), slug),
|
||||
description = COALESCE(sqlc.narg('description'), description),
|
||||
thumbnail_url = COALESCE(sqlc.narg('thumbnail_url'), thumbnail_url)
|
||||
project_id = COALESCE(sqlc.narg('project_id'), project_id),
|
||||
status = COALESCE(sqlc.narg('status'), status)
|
||||
WHERE id = sqlc.arg('id') AND is_deleted = false
|
||||
RETURNING *;
|
||||
|
||||
@@ -34,6 +36,7 @@ WHERE id = $1;
|
||||
SELECT *
|
||||
FROM entities
|
||||
WHERE is_deleted = false
|
||||
AND (sqlc.narg('project_id')::uuid IS NULL OR project_id = sqlc.narg('project_id')::uuid)
|
||||
AND name ILIKE '%' || sqlc.arg('name')::text || '%'
|
||||
AND (sqlc.narg('cursor_id')::uuid IS NULL OR id < sqlc.narg('cursor_id')::uuid)
|
||||
ORDER BY id DESC
|
||||
@@ -41,3 +44,13 @@ LIMIT sqlc.arg('limit_count');
|
||||
|
||||
-- name: GetEntitiesByIDs :many
|
||||
SELECT * FROM entities WHERE id = ANY($1::uuid[]) AND is_deleted = false;
|
||||
|
||||
-- name: GetEntitiesByProjectId :many
|
||||
SELECT *
|
||||
FROM entities
|
||||
WHERE project_id = $1 AND is_deleted = false;
|
||||
|
||||
-- name: DeleteEntitiesByIDs :exec
|
||||
UPDATE entities
|
||||
SET is_deleted = true
|
||||
WHERE id = ANY($1::uuid[]);
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
-- 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(sqlc.arg('min_lng')::float8, sqlc.arg('min_lat')::float8, sqlc.arg('max_lng')::float8, sqlc.arg('max_lat')::float8, 4326)
|
||||
COALESCE(sqlc.narg('id')::uuid, uuidv7()), $1, $2, $3, $4, $5, ST_MakeEnvelope(sqlc.arg('min_lng')::float8, sqlc.arg('min_lat')::float8, sqlc.arg('max_lng')::float8, sqlc.arg('max_lat')::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;
|
||||
|
||||
-- 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
|
||||
@@ -23,6 +23,7 @@ SET
|
||||
binding = COALESCE(sqlc.narg('binding'), binding),
|
||||
time_start = COALESCE(sqlc.narg('time_start'), time_start),
|
||||
time_end = COALESCE(sqlc.narg('time_end'), time_end),
|
||||
project_id = COALESCE(sqlc.narg('project_id'), project_id),
|
||||
bbox = CASE
|
||||
WHEN sqlc.narg('update_bbox')::boolean = true THEN
|
||||
ST_MakeEnvelope(sqlc.narg('min_lng')::float8, sqlc.narg('min_lat')::float8, sqlc.narg('max_lng')::float8, sqlc.narg('max_lat')::float8, 4326)
|
||||
@@ -30,7 +31,7 @@ SET
|
||||
END,
|
||||
updated_at = now()
|
||||
WHERE id = sqlc.arg('id') AND is_deleted = false
|
||||
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;
|
||||
|
||||
@@ -42,7 +43,7 @@ WHERE id = $1;
|
||||
|
||||
-- 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,
|
||||
@@ -50,6 +51,7 @@ SELECT
|
||||
g.is_deleted, g.created_at, g.updated_at
|
||||
FROM geometries g
|
||||
WHERE g.is_deleted = false
|
||||
AND (sqlc.narg('project_id')::uuid IS NULL OR g.project_id = sqlc.narg('project_id')::uuid)
|
||||
AND (
|
||||
sqlc.narg('search_min_lng')::float8 IS NULL OR
|
||||
sqlc.narg('search_min_lat')::float8 IS NULL OR
|
||||
@@ -85,13 +87,18 @@ RETURNING geometry_id;
|
||||
|
||||
-- name: CreateEntityGeometries :exec
|
||||
INSERT INTO entity_geometries (
|
||||
entity_id, geometry_id
|
||||
entity_id, geometry_id, project_id
|
||||
)
|
||||
SELECT $1, unnest(@geometry_ids::uuid[]);
|
||||
SELECT $1, unnest(@geometry_ids::uuid[]), $2
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
-- name: DeleteEntityGeometriesByProjectID :exec
|
||||
DELETE FROM entity_geometries
|
||||
WHERE project_id = $1;
|
||||
|
||||
-- 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,
|
||||
@@ -99,3 +106,27 @@ SELECT
|
||||
is_deleted, created_at, updated_at
|
||||
FROM geometries
|
||||
WHERE id = ANY($1::uuid[]) AND is_deleted = false;
|
||||
|
||||
-- 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;
|
||||
|
||||
-- name: DeleteGeometriesByIDs :exec
|
||||
UPDATE geometries
|
||||
SET is_deleted = true
|
||||
WHERE id = ANY($1::uuid[]);
|
||||
|
||||
-- name: BulkDeleteEntityGeometriesByGeometryID :exec
|
||||
DELETE FROM entity_geometries
|
||||
WHERE geometry_id = $1;
|
||||
|
||||
-- name: DeleteEntityGeometry :exec
|
||||
DELETE FROM entity_geometries
|
||||
WHERE entity_id = $1 AND geometry_id = $2;
|
||||
|
||||
@@ -17,7 +17,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
|
||||
@@ -32,9 +32,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,
|
||||
@@ -85,7 +85,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,
|
||||
@@ -113,9 +116,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,
|
||||
@@ -187,9 +190,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,
|
||||
@@ -225,7 +228,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,
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
-- name: CreateWiki :one
|
||||
INSERT INTO wikis (
|
||||
title, content
|
||||
id, title, content, project_id
|
||||
) VALUES (
|
||||
$1, $2
|
||||
COALESCE(sqlc.narg('id')::uuid, uuidv7()), $1, $2, $3
|
||||
)
|
||||
RETURNING *;
|
||||
|
||||
@@ -15,7 +15,8 @@ WHERE id = $1 AND is_deleted = false;
|
||||
UPDATE wikis
|
||||
SET
|
||||
title = COALESCE(sqlc.narg('title'), title),
|
||||
content = COALESCE(sqlc.narg('content'), content)
|
||||
content = COALESCE(sqlc.narg('content'), content),
|
||||
project_id = COALESCE(sqlc.narg('project_id'), project_id)
|
||||
WHERE id = sqlc.arg('id') AND is_deleted = false
|
||||
RETURNING *;
|
||||
|
||||
@@ -25,10 +26,12 @@ SET
|
||||
is_deleted = true
|
||||
WHERE id = $1;
|
||||
|
||||
|
||||
-- name: SearchWikis :many
|
||||
SELECT w.*
|
||||
FROM wikis w
|
||||
WHERE w.is_deleted = false
|
||||
AND (sqlc.narg('project_id')::uuid IS NULL OR w.project_id = sqlc.narg('project_id')::uuid)
|
||||
AND w.title ILIKE '%' || sqlc.arg('title')::text || '%'
|
||||
AND (
|
||||
sqlc.narg('entity_id')::uuid IS NULL OR
|
||||
@@ -51,10 +54,33 @@ RETURNING wiki_id;
|
||||
|
||||
-- name: CreateEntityWikis :exec
|
||||
INSERT INTO entity_wikis (
|
||||
entity_id, wiki_id
|
||||
entity_id, wiki_id, project_id
|
||||
)
|
||||
SELECT $1, unnest(@wiki_ids::uuid[]);
|
||||
SELECT $1, unnest(@wiki_ids::uuid[]), $2
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
-- name: DeleteEntityWikisByProjectID :exec
|
||||
DELETE FROM entity_wikis
|
||||
WHERE project_id = $1;
|
||||
|
||||
|
||||
-- name: GetWikisByIDs :many
|
||||
SELECT * FROM wikis WHERE id = ANY($1::uuid[]) AND is_deleted = false;
|
||||
|
||||
-- name: GetWikisByProjectId :many
|
||||
SELECT *
|
||||
FROM wikis
|
||||
WHERE project_id = $1 AND is_deleted = false;
|
||||
|
||||
-- name: DeleteWikisByIDs :exec
|
||||
UPDATE wikis
|
||||
SET is_deleted = true
|
||||
WHERE id = ANY($1::uuid[]);
|
||||
|
||||
-- name: BulkDeleteEntityWikisByWikiID :exec
|
||||
DELETE FROM entity_wikis
|
||||
WHERE wiki_id = $1;
|
||||
|
||||
-- name: DeleteEntityWiki :exec
|
||||
DELETE FROM entity_wikis
|
||||
WHERE entity_id = $1 AND wiki_id = $2;
|
||||
|
||||
@@ -70,51 +70,6 @@ CREATE TABLE IF NOT EXISTS verification_medias (
|
||||
PRIMARY KEY (verification_id, media_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS entities (
|
||||
id UUID PRIMARY KEY DEFAULT uuidv7(),
|
||||
name TEXT NOT NULL,
|
||||
description TEXT,
|
||||
thumbnail_url TEXT,
|
||||
is_deleted BOOLEAN NOT NULL DEFAULT false,
|
||||
created_at TIMESTAMPTZ DEFAULT now(),
|
||||
updated_at TIMESTAMPTZ DEFAULT now()
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS wikis (
|
||||
id UUID PRIMARY KEY DEFAULT uuidv7(),
|
||||
title TEXT,
|
||||
content TEXT,
|
||||
is_deleted BOOLEAN NOT NULL DEFAULT false,
|
||||
created_at TIMESTAMPTZ DEFAULT now(),
|
||||
updated_at TIMESTAMPTZ DEFAULT now()
|
||||
);
|
||||
|
||||
|
||||
CREATE TABLE IF NOT EXISTS entity_wikis (
|
||||
entity_id UUID REFERENCES entities(id) ON DELETE CASCADE,
|
||||
wiki_id UUID REFERENCES wikis(id) ON DELETE CASCADE,
|
||||
PRIMARY KEY (entity_id, wiki_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS geometries (
|
||||
id UUID PRIMARY KEY DEFAULT uuidv7(),
|
||||
geo_type SMALLINT NOT NULL DEFAULT 1,
|
||||
draw_geometry JSONB NOT NULL,
|
||||
binding JSONB,
|
||||
time_start INT,
|
||||
time_end INT,
|
||||
bbox GEOMETRY(Polygon, 4326),
|
||||
is_deleted BOOLEAN NOT NULL DEFAULT false,
|
||||
created_at TIMESTAMPTZ DEFAULT now(),
|
||||
updated_at TIMESTAMPTZ DEFAULT now()
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS entity_geometries (
|
||||
entity_id UUID REFERENCES entities(id) ON DELETE CASCADE,
|
||||
geometry_id UUID REFERENCES geometries(id) ON DELETE CASCADE,
|
||||
PRIMARY KEY (entity_id, geometry_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS projects (
|
||||
id UUID PRIMARY KEY DEFAULT uuidv7(),
|
||||
title TEXT NOT NULL,
|
||||
@@ -128,6 +83,60 @@ CREATE TABLE IF NOT EXISTS projects (
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS entities (
|
||||
id UUID PRIMARY KEY DEFAULT uuidv7(),
|
||||
project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
|
||||
name TEXT NOT NULL,
|
||||
slug TEXT,
|
||||
description TEXT,
|
||||
status SMALLINT,
|
||||
is_deleted BOOLEAN NOT NULL DEFAULT false,
|
||||
created_at TIMESTAMPTZ DEFAULT now(),
|
||||
updated_at TIMESTAMPTZ DEFAULT now()
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS wikis (
|
||||
id UUID PRIMARY KEY DEFAULT uuidv7(),
|
||||
project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
|
||||
title TEXT,
|
||||
content JSONB,
|
||||
is_deleted BOOLEAN NOT NULL DEFAULT false,
|
||||
created_at TIMESTAMPTZ DEFAULT now(),
|
||||
updated_at TIMESTAMPTZ DEFAULT now()
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS entity_wikis (
|
||||
entity_id UUID REFERENCES entities(id) ON DELETE CASCADE,
|
||||
wiki_id UUID REFERENCES wikis(id) ON DELETE CASCADE,
|
||||
project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
|
||||
PRIMARY KEY (entity_id, wiki_id)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_entity_wikis_project_id ON entity_wikis(project_id);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS geometries (
|
||||
id UUID PRIMARY KEY DEFAULT uuidv7(),
|
||||
geo_type SMALLINT NOT NULL DEFAULT 1,
|
||||
draw_geometry JSONB NOT NULL,
|
||||
binding JSONB,
|
||||
time_start INT,
|
||||
time_end INT,
|
||||
bbox GEOMETRY(Polygon, 4326),
|
||||
project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
|
||||
is_deleted BOOLEAN NOT NULL DEFAULT false,
|
||||
created_at TIMESTAMPTZ DEFAULT now(),
|
||||
updated_at TIMESTAMPTZ DEFAULT now()
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS entity_geometries (
|
||||
entity_id UUID REFERENCES entities(id) ON DELETE CASCADE,
|
||||
geometry_id UUID REFERENCES geometries(id) ON DELETE CASCADE,
|
||||
project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
|
||||
PRIMARY KEY (entity_id, geometry_id)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_entity_geometries_project_id ON entity_geometries(project_id);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS commits (
|
||||
id UUID PRIMARY KEY DEFAULT uuidv7(),
|
||||
project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
|
||||
|
||||
373
docs/docs.go
373
docs/docs.go
@@ -430,6 +430,11 @@ const docTemplate = `{
|
||||
"type": "string",
|
||||
"name": "name",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"name": "project_id",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
@@ -537,6 +542,11 @@ const docTemplate = `{
|
||||
"in": "query",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"name": "project_id",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"name": "time",
|
||||
@@ -3418,6 +3428,11 @@ const docTemplate = `{
|
||||
"name": "limit",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"name": "project_id",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"maxLength": 1000,
|
||||
"type": "string",
|
||||
@@ -3500,6 +3515,29 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"history-api_internal_dtos_request.BBox": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"max_lat",
|
||||
"max_lng",
|
||||
"min_lat",
|
||||
"min_lng"
|
||||
],
|
||||
"properties": {
|
||||
"max_lat": {
|
||||
"type": "number"
|
||||
},
|
||||
"max_lng": {
|
||||
"type": "number"
|
||||
},
|
||||
"min_lat": {
|
||||
"type": "number"
|
||||
},
|
||||
"min_lng": {
|
||||
"type": "number"
|
||||
}
|
||||
}
|
||||
},
|
||||
"history-api_internal_dtos_request.ChangeOwnerDto": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
@@ -3544,6 +3582,50 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"history-api_internal_dtos_request.CommitSnapshot": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"editor_feature_collection": {
|
||||
"$ref": "#/definitions/history-api_internal_dtos_request.FeatureCollection"
|
||||
},
|
||||
"entities": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/history-api_internal_dtos_request.EntitySnapshot"
|
||||
}
|
||||
},
|
||||
"entity_wiki": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/history-api_internal_dtos_request.EntityWikiLinkSnapshot"
|
||||
}
|
||||
},
|
||||
"entity_wikis": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/history-api_internal_dtos_request.EntityWikiLinkSnapshot"
|
||||
}
|
||||
},
|
||||
"geometries": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/history-api_internal_dtos_request.GeometrySnapshot"
|
||||
}
|
||||
},
|
||||
"geometry_entity": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/history-api_internal_dtos_request.GeometryEntitySnapshot"
|
||||
}
|
||||
},
|
||||
"wikis": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/history-api_internal_dtos_request.WikiSnapshot"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"history-api_internal_dtos_request.CreateCommitDto": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
@@ -3556,10 +3638,7 @@ const docTemplate = `{
|
||||
"maxLength": 500
|
||||
},
|
||||
"snapshot_json": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "integer"
|
||||
}
|
||||
"$ref": "#/definitions/history-api_internal_dtos_request.CommitSnapshot"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -3688,6 +3767,176 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"history-api_internal_dtos_request.EntitySnapshot": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"id"
|
||||
],
|
||||
"properties": {
|
||||
"base_hash": {
|
||||
"type": "string"
|
||||
},
|
||||
"base_updated_at": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"operation": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"create",
|
||||
"update",
|
||||
"delete",
|
||||
"reference"
|
||||
]
|
||||
},
|
||||
"slug": {
|
||||
"type": "string"
|
||||
},
|
||||
"source": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"inline",
|
||||
"ref"
|
||||
]
|
||||
},
|
||||
"status": {
|
||||
"type": "integer",
|
||||
"enum": [
|
||||
0,
|
||||
1
|
||||
]
|
||||
},
|
||||
"type_id": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"history-api_internal_dtos_request.EntityWikiLinkSnapshot": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"entity_id",
|
||||
"wiki_id"
|
||||
],
|
||||
"properties": {
|
||||
"entity_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"is_deleted": {
|
||||
"description": "Legacy / Compatibility",
|
||||
"type": "integer",
|
||||
"enum": [
|
||||
0,
|
||||
1
|
||||
]
|
||||
},
|
||||
"operation": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"reference",
|
||||
"delete"
|
||||
]
|
||||
},
|
||||
"wiki_id": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"history-api_internal_dtos_request.Feature": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"geometry",
|
||||
"properties",
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"geometry": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"$ref": "#/definitions/history-api_internal_dtos_request.FeatureProperties"
|
||||
},
|
||||
"type": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"history-api_internal_dtos_request.FeatureCollection": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"features",
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"features": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/history-api_internal_dtos_request.Feature"
|
||||
}
|
||||
},
|
||||
"type": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"history-api_internal_dtos_request.FeatureProperties": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"id"
|
||||
],
|
||||
"properties": {
|
||||
"binding": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"entity_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"entity_ids": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"entity_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"entity_names": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"entity_type_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"geometry_preset": {
|
||||
"type": "string"
|
||||
},
|
||||
"id": {},
|
||||
"time_end": {
|
||||
"type": "number"
|
||||
},
|
||||
"time_start": {
|
||||
"type": "number"
|
||||
},
|
||||
"type": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"history-api_internal_dtos_request.ForgotPasswordDto": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
@@ -3711,6 +3960,82 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"history-api_internal_dtos_request.GeometryEntitySnapshot": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"entity_id",
|
||||
"geometry_id"
|
||||
],
|
||||
"properties": {
|
||||
"base_links_hash": {
|
||||
"type": "string"
|
||||
},
|
||||
"entity_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"geometry_id": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"history-api_internal_dtos_request.GeometrySnapshot": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"id",
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"base_hash": {
|
||||
"type": "string"
|
||||
},
|
||||
"base_updated_at": {
|
||||
"type": "string"
|
||||
},
|
||||
"bbox": {
|
||||
"$ref": "#/definitions/history-api_internal_dtos_request.BBox"
|
||||
},
|
||||
"binding": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"draw_geometry": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"operation": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"create",
|
||||
"update",
|
||||
"delete",
|
||||
"reference"
|
||||
]
|
||||
},
|
||||
"source": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"inline",
|
||||
"ref"
|
||||
]
|
||||
},
|
||||
"time_end": {
|
||||
"type": "number"
|
||||
},
|
||||
"time_start": {
|
||||
"type": "number"
|
||||
},
|
||||
"type": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"history-api_internal_dtos_request.MediaBulkDeleteDto": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
@@ -3934,6 +4259,46 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"history-api_internal_dtos_request.WikiSnapshot": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"id",
|
||||
"title"
|
||||
],
|
||||
"properties": {
|
||||
"doc": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"operation": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"create",
|
||||
"update",
|
||||
"delete",
|
||||
"reference"
|
||||
]
|
||||
},
|
||||
"source": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"inline",
|
||||
"ref"
|
||||
]
|
||||
},
|
||||
"title": {
|
||||
"type": "string"
|
||||
},
|
||||
"updated_at": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"history-api_internal_dtos_response.CommonResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
||||
@@ -423,6 +423,11 @@
|
||||
"type": "string",
|
||||
"name": "name",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"name": "project_id",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
@@ -530,6 +535,11 @@
|
||||
"in": "query",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"name": "project_id",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"name": "time",
|
||||
@@ -3411,6 +3421,11 @@
|
||||
"name": "limit",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"name": "project_id",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"maxLength": 1000,
|
||||
"type": "string",
|
||||
@@ -3493,6 +3508,29 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"history-api_internal_dtos_request.BBox": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"max_lat",
|
||||
"max_lng",
|
||||
"min_lat",
|
||||
"min_lng"
|
||||
],
|
||||
"properties": {
|
||||
"max_lat": {
|
||||
"type": "number"
|
||||
},
|
||||
"max_lng": {
|
||||
"type": "number"
|
||||
},
|
||||
"min_lat": {
|
||||
"type": "number"
|
||||
},
|
||||
"min_lng": {
|
||||
"type": "number"
|
||||
}
|
||||
}
|
||||
},
|
||||
"history-api_internal_dtos_request.ChangeOwnerDto": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
@@ -3537,6 +3575,50 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"history-api_internal_dtos_request.CommitSnapshot": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"editor_feature_collection": {
|
||||
"$ref": "#/definitions/history-api_internal_dtos_request.FeatureCollection"
|
||||
},
|
||||
"entities": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/history-api_internal_dtos_request.EntitySnapshot"
|
||||
}
|
||||
},
|
||||
"entity_wiki": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/history-api_internal_dtos_request.EntityWikiLinkSnapshot"
|
||||
}
|
||||
},
|
||||
"entity_wikis": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/history-api_internal_dtos_request.EntityWikiLinkSnapshot"
|
||||
}
|
||||
},
|
||||
"geometries": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/history-api_internal_dtos_request.GeometrySnapshot"
|
||||
}
|
||||
},
|
||||
"geometry_entity": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/history-api_internal_dtos_request.GeometryEntitySnapshot"
|
||||
}
|
||||
},
|
||||
"wikis": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/history-api_internal_dtos_request.WikiSnapshot"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"history-api_internal_dtos_request.CreateCommitDto": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
@@ -3549,10 +3631,7 @@
|
||||
"maxLength": 500
|
||||
},
|
||||
"snapshot_json": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "integer"
|
||||
}
|
||||
"$ref": "#/definitions/history-api_internal_dtos_request.CommitSnapshot"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -3681,6 +3760,176 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"history-api_internal_dtos_request.EntitySnapshot": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"id"
|
||||
],
|
||||
"properties": {
|
||||
"base_hash": {
|
||||
"type": "string"
|
||||
},
|
||||
"base_updated_at": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"operation": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"create",
|
||||
"update",
|
||||
"delete",
|
||||
"reference"
|
||||
]
|
||||
},
|
||||
"slug": {
|
||||
"type": "string"
|
||||
},
|
||||
"source": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"inline",
|
||||
"ref"
|
||||
]
|
||||
},
|
||||
"status": {
|
||||
"type": "integer",
|
||||
"enum": [
|
||||
0,
|
||||
1
|
||||
]
|
||||
},
|
||||
"type_id": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"history-api_internal_dtos_request.EntityWikiLinkSnapshot": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"entity_id",
|
||||
"wiki_id"
|
||||
],
|
||||
"properties": {
|
||||
"entity_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"is_deleted": {
|
||||
"description": "Legacy / Compatibility",
|
||||
"type": "integer",
|
||||
"enum": [
|
||||
0,
|
||||
1
|
||||
]
|
||||
},
|
||||
"operation": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"reference",
|
||||
"delete"
|
||||
]
|
||||
},
|
||||
"wiki_id": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"history-api_internal_dtos_request.Feature": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"geometry",
|
||||
"properties",
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"geometry": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"$ref": "#/definitions/history-api_internal_dtos_request.FeatureProperties"
|
||||
},
|
||||
"type": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"history-api_internal_dtos_request.FeatureCollection": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"features",
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"features": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/history-api_internal_dtos_request.Feature"
|
||||
}
|
||||
},
|
||||
"type": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"history-api_internal_dtos_request.FeatureProperties": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"id"
|
||||
],
|
||||
"properties": {
|
||||
"binding": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"entity_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"entity_ids": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"entity_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"entity_names": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"entity_type_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"geometry_preset": {
|
||||
"type": "string"
|
||||
},
|
||||
"id": {},
|
||||
"time_end": {
|
||||
"type": "number"
|
||||
},
|
||||
"time_start": {
|
||||
"type": "number"
|
||||
},
|
||||
"type": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"history-api_internal_dtos_request.ForgotPasswordDto": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
@@ -3704,6 +3953,82 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"history-api_internal_dtos_request.GeometryEntitySnapshot": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"entity_id",
|
||||
"geometry_id"
|
||||
],
|
||||
"properties": {
|
||||
"base_links_hash": {
|
||||
"type": "string"
|
||||
},
|
||||
"entity_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"geometry_id": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"history-api_internal_dtos_request.GeometrySnapshot": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"id",
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"base_hash": {
|
||||
"type": "string"
|
||||
},
|
||||
"base_updated_at": {
|
||||
"type": "string"
|
||||
},
|
||||
"bbox": {
|
||||
"$ref": "#/definitions/history-api_internal_dtos_request.BBox"
|
||||
},
|
||||
"binding": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"draw_geometry": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"operation": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"create",
|
||||
"update",
|
||||
"delete",
|
||||
"reference"
|
||||
]
|
||||
},
|
||||
"source": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"inline",
|
||||
"ref"
|
||||
]
|
||||
},
|
||||
"time_end": {
|
||||
"type": "number"
|
||||
},
|
||||
"time_start": {
|
||||
"type": "number"
|
||||
},
|
||||
"type": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"history-api_internal_dtos_request.MediaBulkDeleteDto": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
@@ -3927,6 +4252,46 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"history-api_internal_dtos_request.WikiSnapshot": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"id",
|
||||
"title"
|
||||
],
|
||||
"properties": {
|
||||
"doc": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"operation": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"create",
|
||||
"update",
|
||||
"delete",
|
||||
"reference"
|
||||
]
|
||||
},
|
||||
"source": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"inline",
|
||||
"ref"
|
||||
]
|
||||
},
|
||||
"title": {
|
||||
"type": "string"
|
||||
},
|
||||
"updated_at": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"history-api_internal_dtos_response.CommonResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
||||
@@ -13,6 +13,22 @@ definitions:
|
||||
- role
|
||||
- user_id
|
||||
type: object
|
||||
history-api_internal_dtos_request.BBox:
|
||||
properties:
|
||||
max_lat:
|
||||
type: number
|
||||
max_lng:
|
||||
type: number
|
||||
min_lat:
|
||||
type: number
|
||||
min_lng:
|
||||
type: number
|
||||
required:
|
||||
- max_lat
|
||||
- max_lng
|
||||
- min_lat
|
||||
- min_lng
|
||||
type: object
|
||||
history-api_internal_dtos_request.ChangeOwnerDto:
|
||||
properties:
|
||||
new_owner_id:
|
||||
@@ -43,15 +59,42 @@ definitions:
|
||||
required:
|
||||
- role_ids
|
||||
type: object
|
||||
history-api_internal_dtos_request.CommitSnapshot:
|
||||
properties:
|
||||
editor_feature_collection:
|
||||
$ref: '#/definitions/history-api_internal_dtos_request.FeatureCollection'
|
||||
entities:
|
||||
items:
|
||||
$ref: '#/definitions/history-api_internal_dtos_request.EntitySnapshot'
|
||||
type: array
|
||||
entity_wiki:
|
||||
items:
|
||||
$ref: '#/definitions/history-api_internal_dtos_request.EntityWikiLinkSnapshot'
|
||||
type: array
|
||||
entity_wikis:
|
||||
items:
|
||||
$ref: '#/definitions/history-api_internal_dtos_request.EntityWikiLinkSnapshot'
|
||||
type: array
|
||||
geometries:
|
||||
items:
|
||||
$ref: '#/definitions/history-api_internal_dtos_request.GeometrySnapshot'
|
||||
type: array
|
||||
geometry_entity:
|
||||
items:
|
||||
$ref: '#/definitions/history-api_internal_dtos_request.GeometryEntitySnapshot'
|
||||
type: array
|
||||
wikis:
|
||||
items:
|
||||
$ref: '#/definitions/history-api_internal_dtos_request.WikiSnapshot'
|
||||
type: array
|
||||
type: object
|
||||
history-api_internal_dtos_request.CreateCommitDto:
|
||||
properties:
|
||||
edit_summary:
|
||||
maxLength: 500
|
||||
type: string
|
||||
snapshot_json:
|
||||
items:
|
||||
type: integer
|
||||
type: array
|
||||
$ref: '#/definitions/history-api_internal_dtos_request.CommitSnapshot'
|
||||
required:
|
||||
- edit_summary
|
||||
- snapshot_json
|
||||
@@ -143,6 +186,122 @@ definitions:
|
||||
- content
|
||||
- verify_type
|
||||
type: object
|
||||
history-api_internal_dtos_request.EntitySnapshot:
|
||||
properties:
|
||||
base_hash:
|
||||
type: string
|
||||
base_updated_at:
|
||||
type: string
|
||||
description:
|
||||
type: string
|
||||
id:
|
||||
type: string
|
||||
name:
|
||||
type: string
|
||||
operation:
|
||||
enum:
|
||||
- create
|
||||
- update
|
||||
- delete
|
||||
- reference
|
||||
type: string
|
||||
slug:
|
||||
type: string
|
||||
source:
|
||||
enum:
|
||||
- inline
|
||||
- ref
|
||||
type: string
|
||||
status:
|
||||
enum:
|
||||
- 0
|
||||
- 1
|
||||
type: integer
|
||||
type_id:
|
||||
type: string
|
||||
required:
|
||||
- id
|
||||
type: object
|
||||
history-api_internal_dtos_request.EntityWikiLinkSnapshot:
|
||||
properties:
|
||||
entity_id:
|
||||
type: string
|
||||
is_deleted:
|
||||
description: Legacy / Compatibility
|
||||
enum:
|
||||
- 0
|
||||
- 1
|
||||
type: integer
|
||||
operation:
|
||||
enum:
|
||||
- reference
|
||||
- delete
|
||||
type: string
|
||||
wiki_id:
|
||||
type: string
|
||||
required:
|
||||
- entity_id
|
||||
- wiki_id
|
||||
type: object
|
||||
history-api_internal_dtos_request.Feature:
|
||||
properties:
|
||||
geometry:
|
||||
items:
|
||||
type: integer
|
||||
type: array
|
||||
properties:
|
||||
$ref: '#/definitions/history-api_internal_dtos_request.FeatureProperties'
|
||||
type:
|
||||
type: string
|
||||
required:
|
||||
- geometry
|
||||
- properties
|
||||
- type
|
||||
type: object
|
||||
history-api_internal_dtos_request.FeatureCollection:
|
||||
properties:
|
||||
features:
|
||||
items:
|
||||
$ref: '#/definitions/history-api_internal_dtos_request.Feature'
|
||||
type: array
|
||||
type:
|
||||
type: string
|
||||
required:
|
||||
- features
|
||||
- type
|
||||
type: object
|
||||
history-api_internal_dtos_request.FeatureProperties:
|
||||
properties:
|
||||
binding:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
entity_id:
|
||||
type: string
|
||||
entity_ids:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
entity_name:
|
||||
type: string
|
||||
entity_names:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
entity_type_id:
|
||||
type: string
|
||||
geometry_preset:
|
||||
type: string
|
||||
id: {}
|
||||
time_end:
|
||||
type: number
|
||||
time_start:
|
||||
type: number
|
||||
type:
|
||||
type: string
|
||||
required:
|
||||
- id
|
||||
type: object
|
||||
history-api_internal_dtos_request.ForgotPasswordDto:
|
||||
properties:
|
||||
email:
|
||||
@@ -160,6 +319,58 @@ definitions:
|
||||
- new_password
|
||||
- token_id
|
||||
type: object
|
||||
history-api_internal_dtos_request.GeometryEntitySnapshot:
|
||||
properties:
|
||||
base_links_hash:
|
||||
type: string
|
||||
entity_id:
|
||||
type: string
|
||||
geometry_id:
|
||||
type: string
|
||||
required:
|
||||
- entity_id
|
||||
- geometry_id
|
||||
type: object
|
||||
history-api_internal_dtos_request.GeometrySnapshot:
|
||||
properties:
|
||||
base_hash:
|
||||
type: string
|
||||
base_updated_at:
|
||||
type: string
|
||||
bbox:
|
||||
$ref: '#/definitions/history-api_internal_dtos_request.BBox'
|
||||
binding:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
draw_geometry:
|
||||
items:
|
||||
type: integer
|
||||
type: array
|
||||
id:
|
||||
type: string
|
||||
operation:
|
||||
enum:
|
||||
- create
|
||||
- update
|
||||
- delete
|
||||
- reference
|
||||
type: string
|
||||
source:
|
||||
enum:
|
||||
- inline
|
||||
- ref
|
||||
type: string
|
||||
time_end:
|
||||
type: number
|
||||
time_start:
|
||||
type: number
|
||||
type:
|
||||
type: string
|
||||
required:
|
||||
- id
|
||||
- type
|
||||
type: object
|
||||
history-api_internal_dtos_request.MediaBulkDeleteDto:
|
||||
properties:
|
||||
media_ids:
|
||||
@@ -316,6 +527,34 @@ definitions:
|
||||
- token
|
||||
- token_type
|
||||
type: object
|
||||
history-api_internal_dtos_request.WikiSnapshot:
|
||||
properties:
|
||||
doc:
|
||||
items:
|
||||
type: integer
|
||||
type: array
|
||||
id:
|
||||
type: string
|
||||
operation:
|
||||
enum:
|
||||
- create
|
||||
- update
|
||||
- delete
|
||||
- reference
|
||||
type: string
|
||||
source:
|
||||
enum:
|
||||
- inline
|
||||
- ref
|
||||
type: string
|
||||
title:
|
||||
type: string
|
||||
updated_at:
|
||||
type: string
|
||||
required:
|
||||
- id
|
||||
- title
|
||||
type: object
|
||||
history-api_internal_dtos_response.CommonResponse:
|
||||
properties:
|
||||
data: {}
|
||||
@@ -636,6 +875,9 @@ paths:
|
||||
maxLength: 255
|
||||
name: name
|
||||
type: string
|
||||
- in: query
|
||||
name: project_id
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
@@ -708,6 +950,9 @@ paths:
|
||||
name: min_lng
|
||||
required: true
|
||||
type: number
|
||||
- in: query
|
||||
name: project_id
|
||||
type: string
|
||||
- in: query
|
||||
name: time
|
||||
type: integer
|
||||
@@ -2565,6 +2810,9 @@ paths:
|
||||
minimum: 1
|
||||
name: limit
|
||||
type: integer
|
||||
- in: query
|
||||
name: project_id
|
||||
type: string
|
||||
- in: query
|
||||
maxLength: 1000
|
||||
name: title
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -101,6 +101,16 @@ func TextToPtr(v pgtype.Text) *string {
|
||||
return &v.String
|
||||
}
|
||||
|
||||
func PtrToInt4(i *int32) pgtype.Int4 {
|
||||
if i == nil {
|
||||
return pgtype.Int4{Valid: false}
|
||||
}
|
||||
return pgtype.Int4{
|
||||
Int32: *i,
|
||||
Valid: true,
|
||||
}
|
||||
}
|
||||
|
||||
func Int4ToPtr(v pgtype.Int4) *int32 {
|
||||
if !v.Valid {
|
||||
return nil
|
||||
@@ -114,3 +124,31 @@ func Int4ToInt32(v pgtype.Int4) int32 {
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func PtrToInt2(v *int) pgtype.Int2 {
|
||||
if v == nil {
|
||||
return pgtype.Int2{Valid: false}
|
||||
}
|
||||
return pgtype.Int2{
|
||||
Int16: int16(*v),
|
||||
Valid: true,
|
||||
}
|
||||
}
|
||||
|
||||
func Int2ToInt16Ptr(v pgtype.Int2) *int16 {
|
||||
if !v.Valid {
|
||||
return nil
|
||||
}
|
||||
int16Val := v.Int16
|
||||
return &int16Val
|
||||
}
|
||||
|
||||
func PtrFloat64ToInt4(v *float64) pgtype.Int4 {
|
||||
if v == nil {
|
||||
return pgtype.Int4{Valid: false}
|
||||
}
|
||||
return pgtype.Int4{
|
||||
Int32: int32(*v),
|
||||
Valid: true,
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user