haste_repository/pg/
sequence.rs1use haste_fhir_model::r4::{
2 generated::resources::{Resource, ResourceType},
3 generated::terminology::IssueType,
4 sqlx::FHIRJson,
5};
6use haste_fhir_operation_error::OperationOutcomeError;
7use haste_jwt::{ProjectId, ResourceId, TenantId};
8use sqlx::PgConnection;
9
10use crate::{
11 pg::{PGConnection, StoreError},
12 sequence::{ResourcePollingValue, ResourceSequential},
13 types::FHIRMethod,
14};
15
16async fn get_sequence_helper(
18 executor: &mut PgConnection,
19 tenant_id: &TenantId,
20 cur_sequence: u64,
21 count: Option<u64>,
22) -> Result<Vec<ResourcePollingValue>, OperationOutcomeError> {
23 let safe_sequence_row = sqlx::query_as::<_, (Option<i64>,)>(
24 "SELECT max_safe_seq('resources_sequence_seq') as max_safe_seq",
25 )
26 .fetch_one(&mut *executor)
27 .await
28 .map_err(StoreError::from)?;
29
30 let safe_sequence = safe_sequence_row.0.unwrap_or(0);
31
32 let result = sqlx::query_as::<
33 _,
34 (
35 String,
36 TenantId,
37 ProjectId,
38 String,
39 String,
40 FHIRMethod,
41 i64,
42 FHIRJson<Resource>,
43 ),
44 >(
45 r"
46 SELECT id, tenant, project, version_id, resource_type, fhir_method, sequence, resource
47 FROM resources
48 WHERE tenant = $1 AND sequence > $2 AND sequence <= $3
49 ORDER BY sequence
50 LIMIT $4
51 ",
52 )
53 .bind(tenant_id.as_ref())
54 .bind(cur_sequence.cast_signed())
55 .bind(safe_sequence)
56 .bind(count.unwrap_or(100).cast_signed())
57 .fetch_all(executor)
58 .await
59 .map_err(StoreError::from)?;
60
61 result
62 .into_iter()
63 .map(
64 |(
65 id,
66 tenant,
67 project,
68 version_id,
69 resource_type_str,
70 fhir_method,
71 sequence,
72 resource,
73 )| {
74 let resource_type = ResourceType::try_from(resource_type_str).map_err(|_| {
75 OperationOutcomeError::error(
76 IssueType::structure(),
77 "Invalid resource type encountered during sequence polling.".to_string(),
78 )
79 })?;
80
81 Ok::<ResourcePollingValue, OperationOutcomeError>(ResourcePollingValue {
82 id: ResourceId::new(id),
83 tenant,
84 project,
85 version_id,
86 resource_type,
87 fhir_method,
88 sequence,
89 resource,
90 })
91 },
92 )
93 .collect()
94}
95
96impl ResourceSequential for PGConnection {
98 async fn get_sequence(
99 &self,
100 tenant_id: &TenantId,
101 sequence_id: u64,
102 count: Option<u64>,
103 ) -> Result<Vec<ResourcePollingValue>, OperationOutcomeError> {
104 match self {
105 PGConnection::Pool(pool, _) => {
106 let mut conn = pool.acquire().await.map_err(StoreError::from)?;
109 get_sequence_helper(&mut conn, tenant_id, sequence_id, count).await
110 }
111 PGConnection::Transaction(tx, _) => {
112 let mut conn = tx.lock().await;
113 get_sequence_helper(&mut conn, tenant_id, sequence_id, count).await
115 }
116 }
117 }
118}