Skip to content

Commit b9c4044

Browse files
authored
Query multiple beamline configurations (#72)
Add new graphql query for accessing multiple beamline configurations.
1 parent fe72e0a commit b9c4044

File tree

8 files changed

+518
-31
lines changed

8 files changed

+518
-31
lines changed

.sqlx/query-02d6faf0ffd8fb96031f7a8e824de4e4552ea72176c5e885cea3e517316e7774.json

Lines changed: 56 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ assert_matches = "1.5.0"
3737
async-std = { version = "1.13.0", features = ["attributes"], default-features = false }
3838
httpmock = { version = "0.7.0", default-features = false }
3939
rstest = "0.24.0"
40-
serde_json = "1.0.138"
40+
serde_json = { version = "1.0.138", features = ["preserve_order"] }
4141
tempfile = "3.16.0"
4242

4343
[build-dependencies]

README.md

Lines changed: 87 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -83,9 +83,9 @@ echo '{
8383
</details>
8484

8585
### Queries (read-only)
86-
There are two read only queries, one to get the visit directory for a given
87-
visit and beamline and one to get the current configuration for a given
88-
beamline.
86+
There are three read only queries, one to get the visit directory for a given
87+
visit and beamline, one to get the current configuration for a given
88+
beamline and one to get the current configuration(s) for one or more beamline.
8989

9090
#### paths
9191
Get the visit directory for a beamline and visit
@@ -119,7 +119,9 @@ Get the current configuration values for the given beamline
119119
visitTemplate
120120
scanTemplate
121121
detectorTemplate
122-
latestScanNumber
122+
dbScanNumber
123+
fileScanNumber
124+
trackerFileExtension
123125
}
124126
}
125127
```
@@ -131,11 +133,91 @@ Get the current configuration values for the given beamline
131133
"visitTemplate": "/data/{instrument}/data/{year}/{visit}",
132134
"scanTemplate": "{subdirectory}/{instrument}-{scan_number}",
133135
"detectorTemplate": "{subdirectory}/{instrument}-{scan_number}-{detector}",
134-
"latestScanNumber": 20839
136+
"dbScanNumber": 0,
137+
"fileScanNumber": null,
138+
"trackerFileExtension": null
135139
}
136140
}
137141
```
138142

143+
#### configurations
144+
Get the current configuration values for one or more beamlines specified as a list.
145+
Providing no beamlines returns all current configurations.
146+
147+
##### Query
148+
```graphql
149+
{
150+
configurations(beamlineFilters: ["i22", "i11"]) {
151+
beamline
152+
visitTemplate
153+
scanTemplate
154+
detectorTemplate
155+
dbScanNumber
156+
fileScanNumber
157+
trackerFileExtension
158+
}
159+
}
160+
```
161+
162+
##### Response
163+
```json
164+
{
165+
"configurations": [
166+
{
167+
"beamline": "i11",
168+
"visitTemplate": "/tmp/{instrument}/data/{year}/{visit}",
169+
"scanTemplate": "{subdirectory}/{instrument}-{scan_number}",
170+
"detectorTemplate": "{subdirectory}/{instrument}-{scan_number}-{detector}",
171+
"dbScanNumber": 0,
172+
"fileScanNumber": null,
173+
"trackerFileExtension": null
174+
},
175+
{
176+
"beamline": "i22",
177+
"visitTemplate": "/tmp/{instrument}/data/{year}/{visit}",
178+
"scanTemplate": "{subdirectory}/{instrument}-{scan_number}",
179+
"detectorTemplate": "{subdirectory}/{instrument}-{scan_number}-{detector}",
180+
"dbScanNumber": 0,
181+
"fileScanNumber": null,
182+
"trackerFileExtension": null
183+
}
184+
]
185+
}
186+
```
187+
188+
##### Query
189+
```graphql
190+
{
191+
configurations {
192+
beamline
193+
visitTemplate
194+
scanTemplate
195+
detectorTemplate
196+
dbScanNumber
197+
fileScanNumber
198+
trackerFileExtension
199+
}
200+
}
201+
```
202+
203+
##### Response
204+
```json
205+
{
206+
"configurations": [
207+
{
208+
"beamline": "i11",
209+
"visitTemplate": "/tmp/{instrument}/data/{year}/{visit}",
210+
"scanTemplate": "{subdirectory}/{instrument}-{scan_number}",
211+
"detectorTemplate": "{subdirectory}/{instrument}-{scan_number}-{detector}",
212+
"dbScanNumber": 0,
213+
"fileScanNumber": null,
214+
"trackerFileExtension": null
215+
},
216+
...
217+
]
218+
}
219+
```
220+
139221
## Mutations (read-write)
140222

141223
#### scan

src/db_service.rs

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,32 @@ impl SqliteScanPathService {
297297
.ok_or(ConfigurationError::MissingBeamline(beamline.into()))
298298
}
299299

300+
pub async fn configurations(
301+
&self,
302+
filters: Vec<String>,
303+
) -> Result<Vec<BeamlineConfiguration>, ConfigurationError> {
304+
let mut q = QueryBuilder::new("SELECT * FROM beamline WHERE name in (");
305+
let mut beamlines = q.separated(", ");
306+
for filter in filters {
307+
beamlines.push_bind(filter);
308+
}
309+
q.push(")");
310+
311+
let query = q.build_query_as();
312+
Ok(query.fetch_all(&self.pool).await?)
313+
}
314+
315+
pub async fn all_configurations(
316+
&self,
317+
) -> Result<Vec<BeamlineConfiguration>, ConfigurationError> {
318+
Ok(query_as!(DbBeamlineConfig, "SELECT * FROM beamline")
319+
.fetch_all(&self.pool)
320+
.await?
321+
.into_iter()
322+
.map(BeamlineConfiguration::from)
323+
.collect())
324+
}
325+
300326
pub async fn next_scan_configuration(
301327
&self,
302328
beamline: &str,
@@ -575,6 +601,137 @@ mod db_tests {
575601
assert_eq!(ext, "ext");
576602
}
577603

604+
#[rstest]
605+
#[test]
606+
async fn configurations() {
607+
let db = SqliteScanPathService::memory().await;
608+
ok!(update("i22")
609+
.with_scan_number(122)
610+
.with_extension("ext")
611+
.insert_new(&db));
612+
ok!(update("i11")
613+
.with_scan_number(111)
614+
.with_extension("ext")
615+
.insert_new(&db));
616+
617+
let confs = ok!(db.configurations(vec![
618+
"i22".to_string(),
619+
"i11".to_string(),
620+
"i03".to_string()
621+
]));
622+
// i03 has not been configured so it will not fetch it.
623+
assert_eq!(confs.len(), 2);
624+
625+
for conf in confs.iter() {
626+
match conf.name() {
627+
"i22" => {
628+
assert_eq!(conf.name(), "i22");
629+
assert_eq!(conf.scan_number(), 122);
630+
assert_eq!(
631+
conf.visit().unwrap().to_string(),
632+
"/tmp/{instrument}/data/{year}/{visit}"
633+
);
634+
assert_eq!(
635+
conf.scan().unwrap().to_string(),
636+
"{subdirectory}/{instrument}-{scan_number}"
637+
);
638+
assert_eq!(
639+
conf.detector().unwrap().to_string(),
640+
"{subdirectory}/{instrument}-{scan_number}-{detector}"
641+
);
642+
let Some(ext) = &conf.tracker_file_extension else {
643+
panic!("Missing extension");
644+
};
645+
assert_eq!(ext, "ext");
646+
}
647+
"i11" => {
648+
assert_eq!(conf.name(), "i11");
649+
assert_eq!(conf.scan_number(), 111);
650+
assert_eq!(
651+
conf.visit().unwrap().to_string(),
652+
"/tmp/{instrument}/data/{year}/{visit}"
653+
);
654+
assert_eq!(
655+
conf.scan().unwrap().to_string(),
656+
"{subdirectory}/{instrument}-{scan_number}"
657+
);
658+
assert_eq!(
659+
conf.detector().unwrap().to_string(),
660+
"{subdirectory}/{instrument}-{scan_number}-{detector}"
661+
);
662+
let Some(ext) = &conf.tracker_file_extension else {
663+
panic!("Missing extension");
664+
};
665+
assert_eq!(ext, "ext");
666+
}
667+
other => panic!("Unexpected beamline name: {other}"),
668+
}
669+
}
670+
}
671+
672+
#[rstest]
673+
#[test]
674+
async fn all_configurations() {
675+
let db = SqliteScanPathService::memory().await;
676+
ok!(update("i22")
677+
.with_scan_number(122)
678+
.with_extension("ext")
679+
.insert_new(&db));
680+
ok!(update("i11")
681+
.with_scan_number(111)
682+
.with_extension("ext")
683+
.insert_new(&db));
684+
685+
let confs = ok!(db.all_configurations());
686+
assert_eq!(confs.len(), 2);
687+
688+
for conf in confs.iter() {
689+
match conf.name() {
690+
"i22" => {
691+
assert_eq!(conf.name(), "i22");
692+
assert_eq!(conf.scan_number(), 122);
693+
assert_eq!(
694+
conf.visit().unwrap().to_string(),
695+
"/tmp/{instrument}/data/{year}/{visit}"
696+
);
697+
assert_eq!(
698+
conf.scan().unwrap().to_string(),
699+
"{subdirectory}/{instrument}-{scan_number}"
700+
);
701+
assert_eq!(
702+
conf.detector().unwrap().to_string(),
703+
"{subdirectory}/{instrument}-{scan_number}-{detector}"
704+
);
705+
let Some(ext) = &conf.tracker_file_extension else {
706+
panic!("Missing extension");
707+
};
708+
assert_eq!(ext, "ext");
709+
}
710+
"i11" => {
711+
assert_eq!(conf.name(), "i11");
712+
assert_eq!(conf.scan_number(), 111);
713+
assert_eq!(
714+
conf.visit().unwrap().to_string(),
715+
"/tmp/{instrument}/data/{year}/{visit}"
716+
);
717+
assert_eq!(
718+
conf.scan().unwrap().to_string(),
719+
"{subdirectory}/{instrument}-{scan_number}"
720+
);
721+
assert_eq!(
722+
conf.detector().unwrap().to_string(),
723+
"{subdirectory}/{instrument}-{scan_number}-{detector}"
724+
);
725+
let Some(ext) = &conf.tracker_file_extension else {
726+
panic!("Missing extension");
727+
};
728+
assert_eq!(ext, "ext");
729+
}
730+
other => panic!("Unexpected beamline name: {other}"),
731+
}
732+
}
733+
}
734+
578735
type Update = BeamlineConfigurationUpdate;
579736

580737
#[rstest]

0 commit comments

Comments
 (0)