• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

geo-engine / geoengine / 5740825225

02 Aug 2023 03:32PM UTC coverage: 88.958% (+0.05%) from 88.913%
5740825225

push

github

web-flow
Merge pull request #844 from geo-engine/pg-symbology-mapping

Pg symbology mapping

610 of 610 new or added lines in 10 files covered. (100.0%)

106476 of 119693 relevant lines covered (88.96%)

60487.94 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

76.21
/services/src/pro/layers/postgres_layer_db.rs
1
use crate::api::model::datatypes::{DataProviderId, LayerId};
2

3
use crate::error;
4
use crate::layers::layer::Property;
5
use crate::pro::contexts::ProPostgresDb;
6
use crate::pro::permissions::{Permission, PermissionDb, RoleId};
7

8
use crate::{
9
    error::Result,
10
    layers::{
11
        external::{DataProvider, DataProviderDefinition},
12
        layer::{
13
            AddLayer, AddLayerCollection, CollectionItem, Layer, LayerCollection,
14
            LayerCollectionListOptions, LayerCollectionListing, LayerListing,
15
            ProviderLayerCollectionId, ProviderLayerId,
16
        },
17
        listing::{LayerCollectionId, LayerCollectionProvider},
18
        storage::{
19
            LayerDb, LayerProviderDb, LayerProviderListing, LayerProviderListingOptions,
20
            INTERNAL_LAYER_DB_ROOT_COLLECTION_ID, INTERNAL_PROVIDER_ID,
21
        },
22
        LayerDbError,
23
    },
24
};
25
use async_trait::async_trait;
26
use bb8_postgres::tokio_postgres::{
27
    tls::{MakeTlsConnect, TlsConnect},
28
    Socket,
29
};
30

31
use snafu::{ensure, ResultExt};
32
use std::str::FromStr;
33
use uuid::Uuid;
34

35
/// delete all collections without parent collection
36
async fn _remove_collections_without_parent_collection(
3✔
37
    transaction: &tokio_postgres::Transaction<'_>,
3✔
38
) -> Result<()> {
3✔
39
    // HINT: a recursive delete statement seems reasonable, but hard to implement in postgres
40
    //       because you have a graph with potential loops
41

42
    let remove_layer_collections_without_parents_stmt = transaction
3✔
43
        .prepare(
3✔
44
            "DELETE FROM layer_collections
3✔
45
                 WHERE  id <> $1 -- do not delete root collection
3✔
46
                 AND    id NOT IN (
3✔
47
                    SELECT child FROM collection_children
3✔
48
                 );",
3✔
49
        )
3✔
50
        .await?;
3✔
51
    while 0 < transaction
5✔
52
        .execute(
5✔
53
            &remove_layer_collections_without_parents_stmt,
5✔
54
            &[&INTERNAL_LAYER_DB_ROOT_COLLECTION_ID],
5✔
55
        )
5✔
56
        .await?
5✔
57
    {
2✔
58
        // whenever one collection is deleted, we have to check again if there are more
2✔
59
        // collections without parents
2✔
60
    }
2✔
61

62
    Ok(())
3✔
63
}
3✔
64

65
/// delete all layers without parent collection
66
async fn _remove_layers_without_parent_collection(
5✔
67
    transaction: &tokio_postgres::Transaction<'_>,
5✔
68
) -> Result<()> {
5✔
69
    let remove_layers_without_parents_stmt = transaction
5✔
70
        .prepare(
5✔
71
            "DELETE FROM layers
5✔
72
                 WHERE id NOT IN (
5✔
73
                    SELECT layer FROM collection_layers
5✔
74
                 );",
5✔
75
        )
5✔
76
        .await?;
5✔
77
    transaction
5✔
78
        .execute(&remove_layers_without_parents_stmt, &[])
5✔
79
        .await?;
5✔
80

81
    Ok(())
5✔
82
}
5✔
83

84
#[async_trait]
85
impl<Tls> LayerDb for ProPostgresDb<Tls>
86
where
87
    Tls: MakeTlsConnect<Socket> + Clone + Send + Sync + 'static,
88
    <Tls as MakeTlsConnect<Socket>>::Stream: Send + Sync,
89
    <Tls as MakeTlsConnect<Socket>>::TlsConnect: Send,
90
    <<Tls as MakeTlsConnect<Socket>>::TlsConnect as TlsConnect<Socket>>::Future: Send,
91
{
92
    async fn add_layer(&self, layer: AddLayer, collection: &LayerCollectionId) -> Result<LayerId> {
6✔
93
        ensure!(
6✔
94
            self.has_permission(collection.clone(), Permission::Owner)
6✔
95
                .await?,
11✔
96
            error::PermissionDenied
×
97
        );
98

99
        let collection_id =
6✔
100
            Uuid::from_str(&collection.0).map_err(|_| crate::error::Error::IdStringMustBeUuid {
6✔
101
                found: collection.0.clone(),
×
102
            })?;
6✔
103

104
        let mut conn = self.conn_pool.get().await?;
6✔
105

106
        let layer = layer;
6✔
107

6✔
108
        let layer_id = Uuid::new_v4();
6✔
109

110
        let metadata = serde_json::to_value(&layer.metadata).context(crate::error::SerdeJson)?;
6✔
111

112
        let trans = conn.build_transaction().start().await?;
6✔
113

114
        let stmt = trans
6✔
115
            .prepare(
6✔
116
                "
6✔
117
            INSERT INTO layers (id, name, description, workflow, symbology, properties, metadata)
6✔
118
            VALUES ($1, $2, $3, $4, $5, $6, $7);",
6✔
119
            )
6✔
120
            .await?;
52✔
121

122
        trans
123
            .execute(
124
                &stmt,
6✔
125
                &[
6✔
126
                    &layer_id,
6✔
127
                    &layer.name,
6✔
128
                    &layer.description,
6✔
129
                    &serde_json::to_value(&layer.workflow).context(crate::error::SerdeJson)?,
6✔
130
                    &layer.symbology,
6✔
131
                    &layer.properties,
6✔
132
                    &metadata,
6✔
133
                ],
134
            )
135
            .await?;
3✔
136

137
        let stmt = trans
6✔
138
            .prepare(
6✔
139
                "
6✔
140
        INSERT INTO collection_layers (collection, layer)
6✔
141
        VALUES ($1, $2) ON CONFLICT DO NOTHING;",
6✔
142
            )
6✔
143
            .await?;
3✔
144

145
        trans.execute(&stmt, &[&collection_id, &layer_id]).await?;
6✔
146

147
        // TODO: `ON CONFLICT DO NOTHING` means, we do not get an error if the permission already exists.
148
        //       Do we want that, or should we report an error and let the caller decide whether to ignore it?
149
        //       We should decide that and adjust all places where `ON CONFILCT DO NOTHING` is used.
150
        let stmt = trans
6✔
151
            .prepare(
6✔
152
                "
6✔
153
        INSERT INTO permissions (role_id, permission, layer_id)
6✔
154
        VALUES ($1, $2, $3) ON CONFLICT DO NOTHING;",
6✔
155
            )
6✔
156
            .await?;
3✔
157

158
        trans
6✔
159
            .execute(
6✔
160
                &stmt,
6✔
161
                &[
6✔
162
                    &RoleId::from(self.session.user.id),
6✔
163
                    &Permission::Owner,
6✔
164
                    &layer_id,
6✔
165
                ],
6✔
166
            )
6✔
167
            .await?;
3✔
168

169
        trans.commit().await?;
6✔
170

171
        Ok(LayerId(layer_id.to_string()))
6✔
172
    }
12✔
173

174
    async fn add_layer_with_id(
×
175
        &self,
×
176
        id: &LayerId,
×
177
        layer: AddLayer,
×
178
        collection: &LayerCollectionId,
×
179
    ) -> Result<()> {
×
180
        ensure!(
×
181
            self.has_permission(collection.clone(), Permission::Owner)
×
182
                .await?,
×
183
            error::PermissionDenied
×
184
        );
185

186
        let layer_id =
×
187
            Uuid::from_str(&id.0).map_err(|_| crate::error::Error::IdStringMustBeUuid {
×
188
                found: collection.0.clone(),
×
189
            })?;
×
190

191
        let collection_id =
×
192
            Uuid::from_str(&collection.0).map_err(|_| crate::error::Error::IdStringMustBeUuid {
×
193
                found: collection.0.clone(),
×
194
            })?;
×
195

196
        let mut conn = self.conn_pool.get().await?;
×
197

198
        let layer = layer;
×
199

200
        let metadata = serde_json::to_value(&layer.metadata).context(crate::error::SerdeJson)?;
×
201

202
        let trans = conn.build_transaction().start().await?;
×
203

204
        let stmt = trans
×
205
            .prepare(
×
206
                "
×
207
            INSERT INTO layers (id, name, description, workflow, symbology, properties, metadata)
×
208
            VALUES ($1, $2, $3, $4, $5, $6, $7);",
×
209
            )
×
210
            .await?;
×
211

212
        trans
213
            .execute(
214
                &stmt,
×
215
                &[
×
216
                    &layer_id,
×
217
                    &layer.name,
×
218
                    &layer.description,
×
219
                    &serde_json::to_value(&layer.workflow).context(crate::error::SerdeJson)?,
×
220
                    &layer.symbology,
×
221
                    &layer.properties,
×
222
                    &metadata,
×
223
                ],
224
            )
225
            .await?;
×
226

227
        let stmt = trans
×
228
            .prepare(
×
229
                "
×
230
            INSERT INTO collection_layers (collection, layer)
×
231
            VALUES ($1, $2) ON CONFLICT DO NOTHING;",
×
232
            )
×
233
            .await?;
×
234

235
        trans.execute(&stmt, &[&collection_id, &layer_id]).await?;
×
236

237
        let stmt = trans
×
238
            .prepare(
×
239
                "
×
240
            INSERT INTO permissions (role_id, permission, layer_id)
×
241
            VALUES ($1, $2, $3) ON CONFLICT DO NOTHING;",
×
242
            )
×
243
            .await?;
×
244

245
        trans
×
246
            .execute(
×
247
                &stmt,
×
248
                &[
×
249
                    &RoleId::from(self.session.user.id),
×
250
                    &Permission::Owner,
×
251
                    &layer_id,
×
252
                ],
×
253
            )
×
254
            .await?;
×
255

256
        trans.commit().await?;
×
257

258
        Ok(())
×
259
    }
×
260

261
    async fn add_layer_to_collection(
2✔
262
        &self,
2✔
263
        layer: &LayerId,
2✔
264
        collection: &LayerCollectionId,
2✔
265
    ) -> Result<()> {
2✔
266
        ensure!(
2✔
267
            self.has_permission(collection.clone(), Permission::Owner)
2✔
268
                .await?,
6✔
269
            error::PermissionDenied
×
270
        );
271

272
        let layer_id =
1✔
273
            Uuid::from_str(&layer.0).map_err(|_| crate::error::Error::IdStringMustBeUuid {
2✔
274
                found: layer.0.clone(),
1✔
275
            })?;
2✔
276

277
        let collection_id =
1✔
278
            Uuid::from_str(&collection.0).map_err(|_| crate::error::Error::IdStringMustBeUuid {
1✔
279
                found: collection.0.clone(),
×
280
            })?;
1✔
281

282
        let conn = self.conn_pool.get().await?;
1✔
283

284
        let stmt = conn
1✔
285
            .prepare(
1✔
286
                "
1✔
287
            INSERT INTO collection_layers (collection, layer)
1✔
288
            VALUES ($1, $2) ON CONFLICT DO NOTHING;",
1✔
289
            )
1✔
290
            .await?;
1✔
291

292
        conn.execute(&stmt, &[&collection_id, &layer_id]).await?;
1✔
293

294
        Ok(())
1✔
295
    }
4✔
296

297
    async fn add_layer_collection(
12✔
298
        &self,
12✔
299
        collection: AddLayerCollection,
12✔
300
        parent: &LayerCollectionId,
12✔
301
    ) -> Result<LayerCollectionId> {
12✔
302
        ensure!(
12✔
303
            self.has_permission(parent.clone(), Permission::Owner)
12✔
304
                .await?,
25✔
305
            error::PermissionDenied
2✔
306
        );
307

308
        let parent =
10✔
309
            Uuid::from_str(&parent.0).map_err(|_| crate::error::Error::IdStringMustBeUuid {
10✔
310
                found: parent.0.clone(),
×
311
            })?;
10✔
312

313
        let mut conn = self.conn_pool.get().await?;
10✔
314

315
        let collection = collection;
10✔
316

10✔
317
        let collection_id = Uuid::new_v4();
10✔
318

319
        let trans = conn.build_transaction().start().await?;
10✔
320

321
        let stmt = trans
10✔
322
            .prepare(
10✔
323
                "
10✔
324
            INSERT INTO layer_collections (id, name, description, properties)
10✔
325
            VALUES ($1, $2, $3, $4);",
10✔
326
            )
10✔
327
            .await?;
9✔
328

329
        trans
10✔
330
            .execute(
10✔
331
                &stmt,
10✔
332
                &[
10✔
333
                    &collection_id,
10✔
334
                    &collection.name,
10✔
335
                    &collection.description,
10✔
336
                    &collection.properties,
10✔
337
                ],
10✔
338
            )
10✔
339
            .await?;
5✔
340

341
        let stmt = trans
10✔
342
            .prepare(
10✔
343
                "
10✔
344
            INSERT INTO collection_children (parent, child)
10✔
345
            VALUES ($1, $2) ON CONFLICT DO NOTHING;",
10✔
346
            )
10✔
347
            .await?;
5✔
348

349
        trans.execute(&stmt, &[&parent, &collection_id]).await?;
10✔
350

351
        let stmt = trans
10✔
352
            .prepare(
10✔
353
                "
10✔
354
            INSERT INTO permissions (role_id, permission, layer_collection_id)
10✔
355
            VALUES ($1, $2, $3) ON CONFLICT DO NOTHING;",
10✔
356
            )
10✔
357
            .await?;
5✔
358

359
        trans
10✔
360
            .execute(
10✔
361
                &stmt,
10✔
362
                &[
10✔
363
                    &RoleId::from(self.session.user.id),
10✔
364
                    &Permission::Owner,
10✔
365
                    &collection_id,
10✔
366
                ],
10✔
367
            )
10✔
368
            .await?;
5✔
369

370
        trans.commit().await?;
10✔
371

372
        Ok(LayerCollectionId(collection_id.to_string()))
10✔
373
    }
24✔
374

375
    async fn add_layer_collection_with_id(
×
376
        &self,
×
377
        id: &LayerCollectionId,
×
378
        collection: AddLayerCollection,
×
379
        parent: &LayerCollectionId,
×
380
    ) -> Result<()> {
×
381
        ensure!(
×
382
            self.has_permission(parent.clone(), Permission::Owner)
×
383
                .await?,
×
384
            error::PermissionDenied
×
385
        );
386

387
        let collection_id =
×
388
            Uuid::from_str(&id.0).map_err(|_| crate::error::Error::IdStringMustBeUuid {
×
389
                found: id.0.clone(),
×
390
            })?;
×
391

392
        let parent =
×
393
            Uuid::from_str(&parent.0).map_err(|_| crate::error::Error::IdStringMustBeUuid {
×
394
                found: parent.0.clone(),
×
395
            })?;
×
396

397
        let mut conn = self.conn_pool.get().await?;
×
398

399
        let trans = conn.build_transaction().start().await?;
×
400

401
        let stmt = trans
×
402
            .prepare(
×
403
                "
×
404
            INSERT INTO layer_collections (id, name, description, properties)
×
405
            VALUES ($1, $2, $3, $4);",
×
406
            )
×
407
            .await?;
×
408

409
        trans
×
410
            .execute(
×
411
                &stmt,
×
412
                &[
×
413
                    &collection_id,
×
414
                    &collection.name,
×
415
                    &collection.description,
×
416
                    &collection.properties,
×
417
                ],
×
418
            )
×
419
            .await?;
×
420

421
        let stmt = trans
×
422
            .prepare(
×
423
                "
×
424
            INSERT INTO collection_children (parent, child)
×
425
            VALUES ($1, $2) ON CONFLICT DO NOTHING;",
×
426
            )
×
427
            .await?;
×
428

429
        trans.execute(&stmt, &[&parent, &collection_id]).await?;
×
430

431
        let stmt = trans
×
432
            .prepare(
×
433
                "
×
434
            INSERT INTO permissions (role_id, permission, layer_collection_id)
×
435
            VALUES ($1, $2, $3) ON CONFLICT DO NOTHING;",
×
436
            )
×
437
            .await?;
×
438

439
        trans
×
440
            .execute(
×
441
                &stmt,
×
442
                &[
×
443
                    &RoleId::from(self.session.user.id),
×
444
                    &Permission::Owner,
×
445
                    &collection_id,
×
446
                ],
×
447
            )
×
448
            .await?;
×
449

450
        trans.commit().await?;
×
451

452
        Ok(())
×
453
    }
×
454

455
    async fn add_collection_to_parent(
1✔
456
        &self,
1✔
457
        collection: &LayerCollectionId,
1✔
458
        parent: &LayerCollectionId,
1✔
459
    ) -> Result<()> {
1✔
460
        ensure!(
1✔
461
            self.has_permission(collection.clone(), Permission::Owner)
1✔
462
                .await?,
3✔
463
            error::PermissionDenied
×
464
        );
465

466
        let collection =
1✔
467
            Uuid::from_str(&collection.0).map_err(|_| crate::error::Error::IdStringMustBeUuid {
1✔
468
                found: collection.0.clone(),
×
469
            })?;
1✔
470

471
        let parent =
1✔
472
            Uuid::from_str(&parent.0).map_err(|_| crate::error::Error::IdStringMustBeUuid {
1✔
473
                found: parent.0.clone(),
×
474
            })?;
1✔
475

476
        let conn = self.conn_pool.get().await?;
1✔
477

478
        let stmt = conn
1✔
479
            .prepare(
1✔
480
                "
1✔
481
            INSERT INTO collection_children (parent, child)
1✔
482
            VALUES ($1, $2) ON CONFLICT DO NOTHING;",
1✔
483
            )
1✔
484
            .await?;
1✔
485

486
        conn.execute(&stmt, &[&parent, &collection]).await?;
1✔
487

488
        Ok(())
1✔
489
    }
2✔
490

491
    async fn remove_layer_collection(&self, collection: &LayerCollectionId) -> Result<()> {
3✔
492
        ensure!(
3✔
493
            self.has_permission(collection.clone(), Permission::Owner)
3✔
494
                .await?,
9✔
495
            error::PermissionDenied
×
496
        );
497

498
        let collection =
3✔
499
            Uuid::from_str(&collection.0).map_err(|_| crate::error::Error::IdStringMustBeUuid {
3✔
500
                found: collection.0.clone(),
×
501
            })?;
3✔
502

503
        if collection == INTERNAL_LAYER_DB_ROOT_COLLECTION_ID {
3✔
504
            return Err(LayerDbError::CannotRemoveRootCollection.into());
1✔
505
        }
2✔
506

507
        let mut conn = self.conn_pool.get().await?;
2✔
508
        let transaction = conn.transaction().await?;
2✔
509

510
        // delete the collection!
511
        // on delete cascade removes all entries from `collection_children` and `collection_layers`
512

513
        let remove_layer_collection_stmt = transaction
2✔
514
            .prepare(
2✔
515
                "DELETE FROM layer_collections
2✔
516
                 WHERE id = $1;",
2✔
517
            )
2✔
518
            .await?;
2✔
519
        transaction
2✔
520
            .execute(&remove_layer_collection_stmt, &[&collection])
2✔
521
            .await?;
2✔
522

523
        _remove_collections_without_parent_collection(&transaction).await?;
4✔
524

525
        _remove_layers_without_parent_collection(&transaction).await?;
4✔
526

527
        transaction.commit().await.map_err(Into::into)
2✔
528
    }
6✔
529

530
    async fn remove_layer_from_collection(
2✔
531
        &self,
2✔
532
        layer: &LayerId,
2✔
533
        collection: &LayerCollectionId,
2✔
534
    ) -> Result<()> {
2✔
535
        ensure!(
2✔
536
            self.has_permission(layer.clone(), Permission::Owner)
2✔
537
                .await?,
6✔
538
            error::PermissionDenied
×
539
        );
540

541
        let collection_uuid =
2✔
542
            Uuid::from_str(&collection.0).map_err(|_| crate::error::Error::IdStringMustBeUuid {
2✔
543
                found: collection.0.clone(),
×
544
            })?;
2✔
545

546
        let layer_uuid =
2✔
547
            Uuid::from_str(&layer.0).map_err(|_| crate::error::Error::IdStringMustBeUuid {
2✔
548
                found: layer.0.clone(),
×
549
            })?;
2✔
550

551
        let mut conn = self.conn_pool.get().await?;
2✔
552
        let transaction = conn.transaction().await?;
2✔
553

554
        let remove_layer_collection_stmt = transaction
2✔
555
            .prepare(
2✔
556
                "DELETE FROM collection_layers
2✔
557
                 WHERE collection = $1
2✔
558
                 AND layer = $2;",
2✔
559
            )
2✔
560
            .await?;
2✔
561
        let num_results = transaction
2✔
562
            .execute(
2✔
563
                &remove_layer_collection_stmt,
2✔
564
                &[&collection_uuid, &layer_uuid],
2✔
565
            )
2✔
566
            .await?;
2✔
567

568
        if num_results == 0 {
2✔
569
            return Err(LayerDbError::NoLayerForGivenIdInCollection {
×
570
                layer: layer.clone(),
×
571
                collection: collection.clone(),
×
572
            }
×
573
            .into());
×
574
        }
2✔
575

2✔
576
        _remove_layers_without_parent_collection(&transaction).await?;
4✔
577

578
        transaction.commit().await.map_err(Into::into)
2✔
579
    }
4✔
580

581
    async fn remove_layer_collection_from_parent(
1✔
582
        &self,
1✔
583
        collection: &LayerCollectionId,
1✔
584
        parent: &LayerCollectionId,
1✔
585
    ) -> Result<()> {
1✔
586
        ensure!(
1✔
587
            self.has_permission(collection.clone(), Permission::Owner)
1✔
588
                .await?,
3✔
589
            error::PermissionDenied
×
590
        );
591

592
        let collection_uuid =
1✔
593
            Uuid::from_str(&collection.0).map_err(|_| crate::error::Error::IdStringMustBeUuid {
1✔
594
                found: collection.0.clone(),
×
595
            })?;
1✔
596

597
        let parent_collection_uuid =
1✔
598
            Uuid::from_str(&parent.0).map_err(|_| crate::error::Error::IdStringMustBeUuid {
1✔
599
                found: parent.0.clone(),
×
600
            })?;
1✔
601

602
        let mut conn = self.conn_pool.get().await?;
1✔
603
        let transaction = conn.transaction().await?;
1✔
604

605
        let remove_layer_collection_stmt = transaction
1✔
606
            .prepare(
1✔
607
                "DELETE FROM collection_children
1✔
608
                 WHERE child = $1
1✔
609
                 AND parent = $2;",
1✔
610
            )
1✔
611
            .await?;
1✔
612
        let num_results = transaction
1✔
613
            .execute(
1✔
614
                &remove_layer_collection_stmt,
1✔
615
                &[&collection_uuid, &parent_collection_uuid],
1✔
616
            )
1✔
617
            .await?;
1✔
618

619
        if num_results == 0 {
1✔
620
            return Err(LayerDbError::NoCollectionForGivenIdInCollection {
×
621
                collection: collection.clone(),
×
622
                parent: parent.clone(),
×
623
            }
×
624
            .into());
×
625
        }
1✔
626

1✔
627
        _remove_collections_without_parent_collection(&transaction).await?;
4✔
628

629
        _remove_layers_without_parent_collection(&transaction).await?;
2✔
630

631
        transaction.commit().await.map_err(Into::into)
1✔
632
    }
2✔
633
}
634

635
#[async_trait]
636
impl<Tls> LayerCollectionProvider for ProPostgresDb<Tls>
637
where
638
    Tls: MakeTlsConnect<Socket> + Clone + Send + Sync + 'static,
639
    <Tls as MakeTlsConnect<Socket>>::Stream: Send + Sync,
640
    <Tls as MakeTlsConnect<Socket>>::TlsConnect: Send,
641
    <<Tls as MakeTlsConnect<Socket>>::TlsConnect as TlsConnect<Socket>>::Future: Send,
642
{
643
    #[allow(clippy::too_many_lines)]
644
    async fn load_layer_collection(
15✔
645
        &self,
15✔
646
        collection_id: &LayerCollectionId,
15✔
647
        options: LayerCollectionListOptions,
15✔
648
    ) -> Result<LayerCollection> {
15✔
649
        ensure!(
15✔
650
            self.has_permission(collection_id.clone(), Permission::Read)
15✔
651
                .await?,
39✔
652
            error::PermissionDenied
3✔
653
        );
654
        let collection = Uuid::from_str(&collection_id.0).map_err(|_| {
12✔
655
            crate::error::Error::IdStringMustBeUuid {
×
656
                found: collection_id.0.clone(),
×
657
            }
×
658
        })?;
12✔
659

660
        let conn = self.conn_pool.get().await?;
12✔
661

662
        let stmt = conn
12✔
663
            .prepare(
12✔
664
                "
12✔
665
        SELECT DISTINCT name, description, properties
12✔
666
        FROM user_permitted_layer_collections p 
12✔
667
            JOIN layer_collections c ON (p.layer_collection_id = c.id) 
12✔
668
        WHERE p.user_id = $1 AND layer_collection_id = $2;",
12✔
669
            )
12✔
670
            .await?;
11✔
671

672
        let row = conn
12✔
673
            .query_one(&stmt, &[&self.session.user.id, &collection])
12✔
674
            .await?;
11✔
675

676
        let name: String = row.get(0);
12✔
677
        let description: String = row.get(1);
12✔
678
        let properties: Vec<Property> = row.get(2);
12✔
679

680
        let stmt = conn
12✔
681
            .prepare(
12✔
682
                "
12✔
683
        SELECT DISTINCT id, name, description, properties, is_layer
12✔
684
        FROM (
12✔
685
            SELECT 
12✔
686
                concat(id, '') AS id, 
12✔
687
                name, 
12✔
688
                description, 
12✔
689
                properties, 
12✔
690
                FALSE AS is_layer
12✔
691
            FROM user_permitted_layer_collections u 
12✔
692
                JOIN layer_collections lc ON (u.layer_collection_id = lc.id)
12✔
693
                JOIN collection_children cc ON (layer_collection_id = cc.child)
12✔
694
            WHERE u.user_id = $4 AND cc.parent = $1
12✔
695
        ) u UNION (
12✔
696
            SELECT 
12✔
697
                concat(id, '') AS id, 
12✔
698
                name, 
12✔
699
                description, 
12✔
700
                properties, 
12✔
701
                TRUE AS is_layer
12✔
702
            FROM user_permitted_layers ul
12✔
703
                JOIN layers uc ON (ul.layer_id = uc.id) 
12✔
704
                JOIN collection_layers cl ON (layer_id = cl.layer)
12✔
705
            WHERE ul.user_id = $4 AND cl.collection = $1
12✔
706
        )
12✔
707
        ORDER BY is_layer ASC, name ASC
12✔
708
        LIMIT $2 
12✔
709
        OFFSET $3;            
12✔
710
        ",
12✔
711
            )
12✔
712
            .await?;
11✔
713

714
        let rows = conn
12✔
715
            .query(
12✔
716
                &stmt,
12✔
717
                &[
12✔
718
                    &collection,
12✔
719
                    &i64::from(options.limit),
12✔
720
                    &i64::from(options.offset),
12✔
721
                    &self.session.user.id,
12✔
722
                ],
12✔
723
            )
12✔
724
            .await?;
11✔
725

726
        let items = rows
12✔
727
            .into_iter()
12✔
728
            .map(|row| {
15✔
729
                let is_layer: bool = row.get(4);
15✔
730

15✔
731
                if is_layer {
15✔
732
                    Ok(CollectionItem::Layer(LayerListing {
5✔
733
                        id: ProviderLayerId {
5✔
734
                            provider_id: INTERNAL_PROVIDER_ID,
5✔
735
                            layer_id: LayerId(row.get(0)),
5✔
736
                        },
5✔
737
                        name: row.get(1),
5✔
738
                        description: row.get(2),
5✔
739
                        properties: row.get(3),
5✔
740
                    }))
5✔
741
                } else {
742
                    Ok(CollectionItem::Collection(LayerCollectionListing {
10✔
743
                        id: ProviderLayerCollectionId {
10✔
744
                            provider_id: INTERNAL_PROVIDER_ID,
10✔
745
                            collection_id: LayerCollectionId(row.get(0)),
10✔
746
                        },
10✔
747
                        name: row.get(1),
10✔
748
                        description: row.get(2),
10✔
749
                        properties: row.get(3),
10✔
750
                    }))
10✔
751
                }
752
            })
15✔
753
            .collect::<Result<Vec<CollectionItem>>>()?;
12✔
754

755
        Ok(LayerCollection {
12✔
756
            id: ProviderLayerCollectionId {
12✔
757
                provider_id: INTERNAL_PROVIDER_ID,
12✔
758
                collection_id: collection_id.clone(),
12✔
759
            },
12✔
760
            name,
12✔
761
            description,
12✔
762
            items,
12✔
763
            entry_label: None,
12✔
764
            properties,
12✔
765
        })
12✔
766
    }
30✔
767

768
    async fn get_root_layer_collection_id(&self) -> Result<LayerCollectionId> {
6✔
769
        Ok(LayerCollectionId(
6✔
770
            INTERNAL_LAYER_DB_ROOT_COLLECTION_ID.to_string(),
6✔
771
        ))
6✔
772
    }
6✔
773

774
    async fn load_layer(&self, id: &LayerId) -> Result<Layer> {
5✔
775
        ensure!(
5✔
776
            self.has_permission(id.clone(), Permission::Read).await?,
15✔
777
            error::PermissionDenied
3✔
778
        );
779

780
        let layer_id =
2✔
781
            Uuid::from_str(&id.0).map_err(|_| crate::error::Error::IdStringMustBeUuid {
2✔
782
                found: id.0.clone(),
×
783
            })?;
2✔
784

785
        let conn = self.conn_pool.get().await?;
2✔
786

787
        let stmt = conn
2✔
788
            .prepare(
2✔
789
                "
2✔
790
            SELECT 
2✔
791
                name,
2✔
792
                description,
2✔
793
                workflow,
2✔
794
                symbology,
2✔
795
                properties,
2✔
796
                metadata
2✔
797
            FROM layers l
2✔
798
            WHERE l.id = $1;",
2✔
799
            )
2✔
800
            .await?;
2✔
801

802
        let row = conn
2✔
803
            .query_one(&stmt, &[&layer_id])
2✔
804
            .await
3✔
805
            .map_err(|_error| LayerDbError::NoLayerForGivenId { id: id.clone() })?;
2✔
806

807
        Ok(Layer {
808
            id: ProviderLayerId {
2✔
809
                provider_id: INTERNAL_PROVIDER_ID,
2✔
810
                layer_id: id.clone(),
2✔
811
            },
2✔
812
            name: row.get(0),
2✔
813
            description: row.get(1),
2✔
814
            workflow: serde_json::from_value(row.get(2)).context(crate::error::SerdeJson)?,
2✔
815
            symbology: row.get(3),
2✔
816
            properties: row.get(4),
2✔
817
            metadata: serde_json::from_value(row.get(5)).context(crate::error::SerdeJson)?,
2✔
818
        })
819
    }
10✔
820
}
821

822
#[async_trait]
823
impl<Tls> LayerProviderDb for ProPostgresDb<Tls>
824
where
825
    Tls: MakeTlsConnect<Socket> + Clone + Send + Sync + 'static,
826
    <Tls as MakeTlsConnect<Socket>>::Stream: Send + Sync,
827
    <Tls as MakeTlsConnect<Socket>>::TlsConnect: Send,
828
    <<Tls as MakeTlsConnect<Socket>>::TlsConnect as TlsConnect<Socket>>::Future: Send,
829
{
830
    async fn add_layer_provider(
1✔
831
        &self,
1✔
832
        provider: Box<dyn DataProviderDefinition>,
1✔
833
    ) -> Result<DataProviderId> {
1✔
834
        ensure!(self.session.is_admin(), error::PermissionDenied);
1✔
835

836
        let conn = self.conn_pool.get().await?;
1✔
837

838
        let stmt = conn
1✔
839
            .prepare(
1✔
840
                "
1✔
841
              INSERT INTO layer_providers (
1✔
842
                  id, 
1✔
843
                  type_name, 
1✔
844
                  name,
1✔
845
                  definition
1✔
846
              )
1✔
847
              VALUES ($1, $2, $3, $4)",
1✔
848
            )
1✔
849
            .await?;
×
850

851
        let id = provider.id();
1✔
852
        conn.execute(
1✔
853
            &stmt,
1✔
854
            &[
1✔
855
                &id,
1✔
856
                &provider.type_name(),
1✔
857
                &provider.name(),
1✔
858
                &serde_json::to_value(provider)?,
1✔
859
            ],
860
        )
861
        .await?;
1✔
862
        Ok(id)
1✔
863
    }
2✔
864

865
    async fn list_layer_providers(
1✔
866
        &self,
1✔
867
        options: LayerProviderListingOptions,
1✔
868
    ) -> Result<Vec<LayerProviderListing>> {
1✔
869
        // TODO: permission
870
        let conn = self.conn_pool.get().await?;
1✔
871

872
        let stmt = conn
1✔
873
            .prepare(
1✔
874
                "
1✔
875
            SELECT 
1✔
876
                id, 
1✔
877
                name,
1✔
878
                type_name
1✔
879
            FROM 
1✔
880
                layer_providers
1✔
881
            ORDER BY name ASC
1✔
882
            LIMIT $1 
1✔
883
            OFFSET $2;",
1✔
884
            )
1✔
885
            .await?;
×
886

887
        let rows = conn
1✔
888
            .query(
1✔
889
                &stmt,
1✔
890
                &[&i64::from(options.limit), &i64::from(options.offset)],
1✔
891
            )
1✔
892
            .await?;
×
893

894
        Ok(rows
1✔
895
            .iter()
1✔
896
            .map(|row| LayerProviderListing {
1✔
897
                id: row.get(0),
1✔
898
                name: row.get(1),
1✔
899
                description: row.get(2),
1✔
900
            })
1✔
901
            .collect())
1✔
902
    }
2✔
903

904
    async fn load_layer_provider(&self, id: DataProviderId) -> Result<Box<dyn DataProvider>> {
1✔
905
        // TODO: permissions
906
        let conn = self.conn_pool.get().await?;
1✔
907

908
        let stmt = conn
1✔
909
            .prepare(
1✔
910
                "
1✔
911
               SELECT 
1✔
912
                   definition
1✔
913
               FROM 
1✔
914
                   layer_providers
1✔
915
               WHERE
1✔
916
                   id = $1",
1✔
917
            )
1✔
918
            .await?;
×
919

920
        let row = conn.query_one(&stmt, &[&id]).await?;
1✔
921

922
        let definition = serde_json::from_value::<Box<dyn DataProviderDefinition>>(row.get(0))?;
1✔
923

924
        definition.initialize().await
1✔
925
    }
2✔
926
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc