Skip to content

Commit 1ab86ce

Browse files
authored
Merge pull request #2619 from msupply-foundation/2618-Sync-and-expose-custom-data-on-Name
2618 sync and expose custom data on name
2 parents 4898e57 + 9d85ad1 commit 1ab86ce

File tree

9 files changed

+107
-7
lines changed

9 files changed

+107
-7
lines changed

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "open-msupply",
33
"//": "Main version for the app, should be in semantic version format (any release candidate or test build should be separated by '-' i.e. 1.1.1-rc1 or 1.1.1-test",
4-
"version": "1.5.00",
4+
"version": "1.5.04",
55
"private": true,
66
"scripts": {
77
"start": "cd ./server && cargo run & cd ./client && yarn start-local",

server/graphql/types/src/types/name.rs

+15-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@ use chrono::{DateTime, NaiveDate, Utc};
33
use dataloader::DataLoader;
44
use repository::{Gender, Name, NameRow, NameType};
55

6-
use graphql_core::{loader::StoreByIdLoader, simple_generic_errors::NodeError, ContextExt};
6+
use graphql_core::{
7+
loader::StoreByIdLoader, simple_generic_errors::NodeError,
8+
standard_graphql_error::StandardGraphqlError, ContextExt,
9+
};
710
use serde::Serialize;
811

912
use super::StoreNode;
@@ -228,6 +231,12 @@ impl NameNode {
228231
pub async fn date_of_birth(&self) -> Option<NaiveDate> {
229232
self.row().date_of_birth
230233
}
234+
235+
pub async fn custom_data(&self) -> Result<Option<serde_json::Value>> {
236+
self.name
237+
.custom_data()
238+
.map_err(|err| StandardGraphqlError::from_error(&err))
239+
}
231240
}
232241

233242
#[derive(Union)]
@@ -304,6 +313,7 @@ mod test {
304313
.unwrap(),
305314
);
306315
r.date_of_birth = Some(NaiveDate::from_ymd_opt(1995, 05, 15).unwrap());
316+
r.custom_data_string = Some(r#"{"check": "check"}"#.to_string());
307317
}),
308318
name_store_join_row: None,
309319
store_row: None,
@@ -333,6 +343,9 @@ mod test {
333343
"address2": "address2",
334344
"createdDatetime": "2022-05-18T12:07:12+00:00",
335345
"dateOfBirth": "1995-05-15",
346+
"customData": {
347+
"check": "check"
348+
}
336349
}
337350
}
338351
);
@@ -359,6 +372,7 @@ mod test {
359372
createdDatetime
360373
isOnHold
361374
dateOfBirth
375+
customData
362376
}
363377
}
364378
"#;

server/repository/src/db_diesel/name.rs

+8
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,14 @@ impl Name {
234234
store_row,
235235
}
236236
}
237+
238+
pub fn custom_data(&self) -> Result<Option<serde_json::Value>, serde_json::Error> {
239+
self.name_row
240+
.custom_data_string
241+
.as_ref()
242+
.map(|custom_data_string| serde_json::from_str(&custom_data_string))
243+
.transpose()
244+
}
237245
}
238246

239247
// name_store_join_dsl::name_id.eq(name_dsl::id)

server/repository/src/db_diesel/name_row.rs

+9
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ table! {
3838
is_deceased -> Bool,
3939
national_health_number -> Nullable<Text>,
4040
date_of_death -> Nullable<Date>,
41+
custom_data -> Nullable<Text>,
4142
}
4243
}
4344

@@ -100,6 +101,12 @@ impl Default for NameType {
100101
}
101102
}
102103

104+
impl NameType {
105+
pub fn is_facility_or_store(&self) -> bool {
106+
*self == NameType::Facility || *self == NameType::Store
107+
}
108+
}
109+
103110
#[derive(Clone, Queryable, Insertable, Debug, PartialEq, Eq, AsChangeset, Default)]
104111
#[changeset_options(treat_none_as_null = "true")]
105112
#[table_name = "name"]
@@ -141,6 +148,8 @@ pub struct NameRow {
141148
pub is_deceased: bool,
142149
pub national_health_number: Option<String>,
143150
pub date_of_death: Option<NaiveDate>,
151+
#[column_name = "custom_data"]
152+
pub custom_data_string: Option<String>,
144153
}
145154

146155
pub struct NameRowRepository<'a> {

server/repository/src/migrations/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ mod v1_02_01;
1414
mod v1_03_00;
1515
mod v1_04_00;
1616
mod v1_05_00;
17+
mod v1_05_04;
1718
mod version;
1819

1920
pub(crate) use self::types::*;
@@ -85,6 +86,7 @@ pub fn migrate(
8586
Box::new(v1_03_00::V1_03_00),
8687
Box::new(v1_04_00::V1_04_00),
8788
Box::new(v1_05_00::V1_05_00),
89+
Box::new(v1_05_04::V1_05_04),
8890
];
8991

9092
// Historic diesel migrations
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
use super::{sql, version::Version, Migration};
2+
3+
use crate::StorageConnection;
4+
5+
pub(crate) struct V1_05_04;
6+
7+
impl Migration for V1_05_04 {
8+
fn version(&self) -> Version {
9+
Version::from_str("1.5.04")
10+
}
11+
12+
fn migrate(&self, connection: &StorageConnection) -> anyhow::Result<()> {
13+
// Update integartion_datetime on facility/store type name records in sync_buffer
14+
// when server start, or on next sync these will be re-integrated
15+
sql!(
16+
connection,
17+
r#"
18+
ALTER TABLE name ADD COLUMN custom_data TEXT DEFAULT NULL;
19+
UPDATE sync_buffer SET integration_datetime = NULL
20+
WHERE record_id IN (SELECT id FROM name where name."type" IN ('FACILITY', 'STORE'));
21+
"#
22+
)?;
23+
24+
Ok(())
25+
}
26+
}
27+
28+
#[cfg(test)]
29+
#[actix_rt::test]
30+
async fn migration_1_05_04() {
31+
use crate::migrations::*;
32+
use crate::test_db::*;
33+
34+
let version = V1_05_04.version();
35+
36+
// This test allows checking sql syntax
37+
let SetupResult { connection, .. } = setup_test(SetupOption {
38+
db_name: &format!("migration_{version}"),
39+
version: Some(version.clone()),
40+
..Default::default()
41+
})
42+
.await;
43+
44+
assert_eq!(get_database_version(&connection), version);
45+
}

server/service/src/programs/patient/patient_updated.rs

+1
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ pub fn update_patient_row(
128128
is_deceased: patient.is_deceased.unwrap_or(false),
129129
date_of_death,
130130
national_health_number: code_2,
131+
custom_data_string: None,
131132
};
132133

133134
if is_sync_update {

server/service/src/sync/test/test_data/name.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ fn name_1() -> TestSyncPullRecord {
144144
.unwrap(),
145145
),
146146
date_of_death: None,
147+
custom_data_string: None,
147148
}),
148149
)
149150
}
@@ -277,6 +278,7 @@ fn name_2() -> TestSyncPullRecord {
277278
is_deceased: false,
278279
national_health_number: None,
279280
date_of_death: None,
281+
custom_data_string: None,
280282
}),
281283
)
282284
}
@@ -368,7 +370,7 @@ const NAME_3: (&'static str, &'static str) = (
368370
"license_number": "",
369371
"license_expiry": "0000-00-00",
370372
"has_current_license": false,
371-
"custom_data": null,
373+
"custom_data": {"check":"check"},
372374
"maximum_credit": 0,
373375
"nationality_ID": "",
374376
"created_date": "0000-00-00",
@@ -410,6 +412,7 @@ fn name_3() -> TestSyncPullRecord {
410412
is_deceased: false,
411413
national_health_number: Some("NHN002".to_string()),
412414
date_of_death: None,
415+
custom_data_string: Some(r#"{"check":"check"}"#.to_string()),
413416
}),
414417
)
415418
}
@@ -549,6 +552,7 @@ fn name_4() -> TestSyncPullRecord {
549552
is_deceased: true,
550553
national_health_number: Some("NHN003".to_string()),
551554
date_of_death: None,
555+
custom_data_string: None,
552556
}),
553557
)
554558
}
@@ -591,6 +595,7 @@ fn name_push_record_1() -> TestSyncPushRecord {
591595
),
592596
gender: Some(Gender::Female),
593597
date_of_death: None,
598+
custom_data: None
594599
}),
595600
}
596601
}
@@ -633,6 +638,7 @@ fn name_push_record_2() -> TestSyncPushRecord {
633638
),
634639
gender: Some(Gender::Female),
635640
date_of_death: None,
641+
custom_data: None
636642
}),
637643
}
638644
}

server/service/src/sync/translations/name.rs

+19-4
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use crate::sync::{
55
zero_date_as_option,
66
},
77
};
8+
use anyhow::Context;
89
use chrono::{NaiveDate, NaiveDateTime};
910
use repository::{
1011
ChangelogRow, ChangelogTableName, Gender, NameRow, NameRowRepository, NameType,
@@ -131,6 +132,7 @@ pub struct LegacyNameRow {
131132
#[serde(deserialize_with = "zero_date_as_option")]
132133
#[serde(serialize_with = "date_option_to_isostring")]
133134
pub date_of_death: Option<NaiveDate>,
135+
pub custom_data: Option<serde_json::Value>,
134136
}
135137

136138
const LEGACY_TABLE_NAME: &'static str = LegacyTableName::NAME;
@@ -165,7 +167,7 @@ impl SyncTranslation for NameTranslation {
165167
id,
166168
name,
167169
code,
168-
r#type,
170+
r#type: legacy_type,
169171
is_customer,
170172
is_supplier,
171173
supplying_store_id,
@@ -190,16 +192,25 @@ impl SyncTranslation for NameTranslation {
190192
created_datetime,
191193
gender,
192194
date_of_death,
195+
custom_data,
193196
} = serde_json::from_str::<LegacyNameRow>(&sync_record.data)?;
194197

198+
// Custom data for facility or name only (for others, say patient, don't need to have extra overhead or push translation back to json)
199+
let r#type = legacy_type.to_name_type();
200+
let custom_data_string = r#type
201+
.is_facility_or_store()
202+
.then(|| custom_data.as_ref().map(serde_json::to_string))
203+
.flatten()
204+
.transpose()
205+
.context("Error serialising custom data to string")?;
206+
195207
let result = NameRow {
196208
id,
197209
name,
198-
r#type: r#type.to_name_type(),
210+
r#type,
199211
code,
200212
is_customer,
201213
is_supplier,
202-
203214
supplying_store_id,
204215
first_name,
205216
last_name,
@@ -217,7 +228,7 @@ impl SyncTranslation for NameTranslation {
217228
on_hold,
218229
is_deceased,
219230
national_health_number,
220-
gender: gender.or(if r#type == LegacyNameType::Patient {
231+
gender: gender.or(if legacy_type == LegacyNameType::Patient {
221232
if female {
222233
Some(Gender::Female)
223234
} else {
@@ -229,6 +240,7 @@ impl SyncTranslation for NameTranslation {
229240
created_datetime: created_datetime
230241
.or(created_date.map(|date| date.and_hms_opt(0, 0, 0).unwrap())),
231242
date_of_death,
243+
custom_data_string,
232244
};
233245

234246
Ok(Some(IntegrationRecords::from_upsert(
@@ -284,6 +296,8 @@ impl SyncTranslation for NameTranslation {
284296
is_deceased,
285297
date_of_death,
286298
national_health_number,
299+
// See comment in pull translation
300+
custom_data_string: _,
287301
} = NameRowRepository::new(connection)
288302
.find_one_by_id(&changelog.record_id)?
289303
.ok_or(anyhow::Error::msg(format!(
@@ -326,6 +340,7 @@ impl SyncTranslation for NameTranslation {
326340
created_datetime,
327341
gender,
328342
date_of_death,
343+
custom_data: None,
329344
};
330345

331346
Ok(Some(vec![RemoteSyncRecordV5::new_upsert(

0 commit comments

Comments
 (0)