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

geo-engine / geoengine / 4493843834

pending completion
4493843834

push

github

GitHub
Merge #764

325 of 325 new or added lines in 3 files covered. (100.0%)

92759 of 106267 relevant lines covered (87.29%)

74024.0 hits per line

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

77.52
/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::PostgresDb;
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
    util::user_input::Validated,
25
};
26
use async_trait::async_trait;
27
use bb8_postgres::tokio_postgres::{
28
    tls::{MakeTlsConnect, TlsConnect},
29
    Socket,
30
};
31

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

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

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

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

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

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

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

104
        let collection_id =
6✔
105
            Uuid::from_str(&collection.0).map_err(|_| crate::error::Error::IdStringMustBeUuid {
6✔
106
                found: collection.0.clone(),
×
107
            })?;
6✔
108

109
        let mut conn = self.conn_pool.get().await?;
6✔
110

111
        let layer = layer.user_input;
6✔
112

6✔
113
        let layer_id = Uuid::new_v4();
6✔
114
        let symbology = serde_json::to_value(&layer.symbology).context(crate::error::SerdeJson)?;
6✔
115

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

118
        let trans = conn.build_transaction().start().await?;
6✔
119

120
        let stmt = trans
6✔
121
            .prepare(
6✔
122
                "
6✔
123
            INSERT INTO layers (id, name, description, workflow, symbology, properties, metadata)
6✔
124
            VALUES ($1, $2, $3, $4, $5, $6, $7);",
6✔
125
            )
6✔
126
            .await?;
4✔
127

128
        trans
129
            .execute(
130
                &stmt,
6✔
131
                &[
6✔
132
                    &layer_id,
6✔
133
                    &layer.name,
6✔
134
                    &layer.description,
6✔
135
                    &serde_json::to_value(&layer.workflow).context(crate::error::SerdeJson)?,
6✔
136
                    &symbology,
6✔
137
                    &layer.properties,
6✔
138
                    &metadata,
6✔
139
                ],
140
            )
141
            .await?;
5✔
142

143
        let stmt = trans
6✔
144
            .prepare(
6✔
145
                "
6✔
146
        INSERT INTO collection_layers (collection, layer)
6✔
147
        VALUES ($1, $2) ON CONFLICT DO NOTHING;",
6✔
148
            )
6✔
149
            .await?;
4✔
150

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

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

164
        trans
6✔
165
            .execute(
6✔
166
                &stmt,
6✔
167
                &[
6✔
168
                    &RoleId::from(self.session.user.id),
6✔
169
                    &Permission::Owner,
6✔
170
                    &layer_id,
6✔
171
                ],
6✔
172
            )
6✔
173
            .await?;
4✔
174

175
        trans.commit().await?;
6✔
176

177
        Ok(LayerId(layer_id.to_string()))
6✔
178
    }
12✔
179

180
    async fn add_layer_with_id(
×
181
        &self,
×
182
        id: &LayerId,
×
183
        layer: Validated<AddLayer>,
×
184
        collection: &LayerCollectionId,
×
185
    ) -> Result<()> {
×
186
        ensure!(
×
187
            self.has_permission(collection.clone(), Permission::Owner)
×
188
                .await?,
×
189
            error::PermissionDenied
×
190
        );
191

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

197
        let collection_id =
×
198
            Uuid::from_str(&collection.0).map_err(|_| crate::error::Error::IdStringMustBeUuid {
×
199
                found: collection.0.clone(),
×
200
            })?;
×
201

202
        let mut conn = self.conn_pool.get().await?;
×
203

204
        let layer = layer.user_input;
×
205

206
        let symbology = serde_json::to_value(&layer.symbology).context(crate::error::SerdeJson)?;
×
207

208
        let trans = conn.build_transaction().start().await?;
×
209

210
        let stmt = trans
×
211
            .prepare(
×
212
                "
×
213
            INSERT INTO layers (id, name, description, workflow, symbology)
×
214
            VALUES ($1, $2, $3, $4, $5);",
×
215
            )
×
216
            .await?;
×
217

218
        trans
219
            .execute(
220
                &stmt,
×
221
                &[
×
222
                    &layer_id,
×
223
                    &layer.name,
×
224
                    &layer.description,
×
225
                    &serde_json::to_value(&layer.workflow).context(crate::error::SerdeJson)?,
×
226
                    &symbology,
×
227
                ],
228
            )
229
            .await?;
×
230

231
        let stmt = trans
×
232
            .prepare(
×
233
                "
×
234
            INSERT INTO collection_layers (collection, layer)
×
235
            VALUES ($1, $2) ON CONFLICT DO NOTHING;",
×
236
            )
×
237
            .await?;
×
238

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

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

249
        trans
×
250
            .execute(
×
251
                &stmt,
×
252
                &[
×
253
                    &RoleId::from(self.session.user.id),
×
254
                    &Permission::Owner,
×
255
                    &layer_id,
×
256
                ],
×
257
            )
×
258
            .await?;
×
259

260
        trans.commit().await?;
×
261

262
        Ok(())
×
263
    }
×
264

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

276
        let layer_id =
1✔
277
            Uuid::from_str(&layer.0).map_err(|_| crate::error::Error::IdStringMustBeUuid {
2✔
278
                found: layer.0.clone(),
1✔
279
            })?;
2✔
280

281
        let collection_id =
1✔
282
            Uuid::from_str(&collection.0).map_err(|_| crate::error::Error::IdStringMustBeUuid {
1✔
283
                found: collection.0.clone(),
×
284
            })?;
1✔
285

286
        let conn = self.conn_pool.get().await?;
1✔
287

288
        let stmt = conn
1✔
289
            .prepare(
1✔
290
                "
1✔
291
            INSERT INTO collection_layers (collection, layer)
1✔
292
            VALUES ($1, $2) ON CONFLICT DO NOTHING;",
1✔
293
            )
1✔
294
            .await?;
1✔
295

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

298
        Ok(())
1✔
299
    }
4✔
300

301
    async fn add_layer_collection(
12✔
302
        &self,
12✔
303
        collection: Validated<AddLayerCollection>,
12✔
304
        parent: &LayerCollectionId,
12✔
305
    ) -> Result<LayerCollectionId> {
12✔
306
        ensure!(
12✔
307
            self.has_permission(parent.clone(), Permission::Owner)
12✔
308
                .await?,
47✔
309
            error::PermissionDenied
2✔
310
        );
311

312
        let parent =
10✔
313
            Uuid::from_str(&parent.0).map_err(|_| crate::error::Error::IdStringMustBeUuid {
10✔
314
                found: parent.0.clone(),
×
315
            })?;
10✔
316

317
        let mut conn = self.conn_pool.get().await?;
10✔
318

319
        let collection = collection.user_input;
10✔
320

10✔
321
        let collection_id = Uuid::new_v4();
10✔
322

323
        let trans = conn.build_transaction().start().await?;
10✔
324

325
        let stmt = trans
10✔
326
            .prepare(
10✔
327
                "
10✔
328
            INSERT INTO layer_collections (id, name, description, properties)
10✔
329
            VALUES ($1, $2, $3, $4);",
10✔
330
            )
10✔
331
            .await?;
23✔
332

333
        trans
10✔
334
            .execute(
10✔
335
                &stmt,
10✔
336
                &[
10✔
337
                    &collection_id,
10✔
338
                    &collection.name,
10✔
339
                    &collection.description,
10✔
340
                    &collection.properties,
10✔
341
                ],
10✔
342
            )
10✔
343
            .await?;
7✔
344

345
        let stmt = trans
10✔
346
            .prepare(
10✔
347
                "
10✔
348
            INSERT INTO collection_children (parent, child)
10✔
349
            VALUES ($1, $2) ON CONFLICT DO NOTHING;",
10✔
350
            )
10✔
351
            .await?;
7✔
352

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

355
        let stmt = trans
10✔
356
            .prepare(
10✔
357
                "
10✔
358
            INSERT INTO permissions (role_id, permission, layer_collection_id)
10✔
359
            VALUES ($1, $2, $3) ON CONFLICT DO NOTHING;",
10✔
360
            )
10✔
361
            .await?;
8✔
362

363
        trans
10✔
364
            .execute(
10✔
365
                &stmt,
10✔
366
                &[
10✔
367
                    &RoleId::from(self.session.user.id),
10✔
368
                    &Permission::Owner,
10✔
369
                    &collection_id,
10✔
370
                ],
10✔
371
            )
10✔
372
            .await?;
8✔
373

374
        trans.commit().await?;
10✔
375

376
        Ok(LayerCollectionId(collection_id.to_string()))
10✔
377
    }
24✔
378

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

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

396
        let parent =
×
397
            Uuid::from_str(&parent.0).map_err(|_| crate::error::Error::IdStringMustBeUuid {
×
398
                found: parent.0.clone(),
×
399
            })?;
×
400

401
        let mut conn = self.conn_pool.get().await?;
×
402

403
        let collection = collection.user_input;
×
404

405
        let trans = conn.build_transaction().start().await?;
×
406

407
        let stmt = trans
×
408
            .prepare(
×
409
                "
×
410
            INSERT INTO layer_collections (id, name, description)
×
411
            VALUES ($1, $2, $3);",
×
412
            )
×
413
            .await?;
×
414

415
        trans
×
416
            .execute(
×
417
                &stmt,
×
418
                &[&collection_id, &collection.name, &collection.description],
×
419
            )
×
420
            .await?;
×
421

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

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

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

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

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

453
        Ok(())
×
454
    }
×
455

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

663
        let options = options.user_input;
12✔
664

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

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

679
        let name: String = row.get(0);
12✔
680
        let description: String = row.get(1);
12✔
681
        let properties: Vec<Property> = row.get(2);
12✔
682

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

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

729
        let items = rows
12✔
730
            .into_iter()
12✔
731
            .map(|row| {
15✔
732
                let is_layer: bool = row.get(4);
15✔
733

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

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

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

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

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

788
        let conn = self.conn_pool.get().await?;
2✔
789

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

805
        let row = conn
2✔
806
            .query_one(&stmt, &[&layer_id])
2✔
807
            .await
1✔
808
            .map_err(|_error| LayerDbError::NoLayerForGivenId { id: id.clone() })?;
2✔
809

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

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

839
        let conn = self.conn_pool.get().await?;
1✔
840

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

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

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

875
        let options = options.user_input;
1✔
876

877
        let stmt = conn
1✔
878
            .prepare(
1✔
879
                "
1✔
880
            SELECT 
1✔
881
                id, 
1✔
882
                name,
1✔
883
                type_name
1✔
884
            FROM 
1✔
885
                layer_providers
1✔
886
            ORDER BY name ASC
1✔
887
            LIMIT $1 
1✔
888
            OFFSET $2;",
1✔
889
            )
1✔
890
            .await?;
1✔
891

892
        let rows = conn
1✔
893
            .query(
1✔
894
                &stmt,
1✔
895
                &[&i64::from(options.limit), &i64::from(options.offset)],
1✔
896
            )
1✔
897
            .await?;
1✔
898

899
        Ok(rows
1✔
900
            .iter()
1✔
901
            .map(|row| LayerProviderListing {
1✔
902
                id: row.get(0),
1✔
903
                name: row.get(1),
1✔
904
                description: row.get(2),
1✔
905
            })
1✔
906
            .collect())
1✔
907
    }
2✔
908

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

913
        let stmt = conn
1✔
914
            .prepare(
1✔
915
                "
1✔
916
               SELECT 
1✔
917
                   definition
1✔
918
               FROM 
1✔
919
                   layer_providers
1✔
920
               WHERE
1✔
921
                   id = $1",
1✔
922
            )
1✔
923
            .await?;
×
924

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

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

929
        definition.initialize().await
1✔
930
    }
2✔
931
}
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