Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
59308e4
Add db query to fetch all beamline configurations
abbiemery Jan 24, 2025
9d3c923
Add graphql query to get collection of all current beamline configura…
abbiemery Jan 24, 2025
98b95c0
Add configurations query to select multiple bl configs
abbiemery Jan 28, 2025
86dc329
Add configurations gql query to get selection of bl configurations
abbiemery Jan 28, 2025
39b9305
Combine conigurations and all_configurations into a single graphql query
abbiemery Jan 28, 2025
91a3d83
Add templating for super admin access
abbiemery Jan 28, 2025
712bc53
Fix local linting
abbiemery Jan 28, 2025
3fd4981
Add ConfigurationError as test import
abbiemery Jan 28, 2025
e5d0c22
Add sqlx query for offline
abbiemery Jan 28, 2025
bff480b
Update service_schema
abbiemery Jan 30, 2025
3e990b9
Change auth to check admin and check beamline admin
abbiemery Jan 31, 2025
52b03fc
Return old match so it can be changed in another pr
abbiemery Feb 4, 2025
60ccbe1
Make configurations query once and filter
abbiemery Feb 4, 2025
798e7f7
Fix match
abbiemery Feb 5, 2025
d375ce7
Remove unneccesary binding
abbiemery Feb 5, 2025
3bb0c40
Regenerate schema
abbiemery Feb 5, 2025
9f32363
Remove old cfg_attr
abbiemery Feb 5, 2025
928b114
Placate Clippy
abbiemery Feb 5, 2025
045ec02
Use more useful naming for beamline filters
abbiemery Feb 5, 2025
2f05f42
Refactor to utilise BeamlineConfiguration method
abbiemery Feb 5, 2025
fe033f6
Remove type
abbiemery Feb 5, 2025
12aaadc
Simplify gql configurations query
abbiemery Feb 5, 2025
6073e5c
Add docstring to CurrentConfiguration
abbiemery Feb 5, 2025
bee1435
Update service schema
abbiemery Feb 5, 2025
11dd996
Add initial test for db configurations
abbiemery Feb 10, 2025
f6c9cb4
Add all_configurations test to db
abbiemery Feb 11, 2025
ee61c9e
Add beamline to configuration graphql test
abbiemery Feb 11, 2025
6a2e0f9
Add configuration tests to graphql
abbiemery Feb 11, 2025
a543c39
remove erroneous year from visit template in gql test
abbiemery Feb 11, 2025
8a22737
Fix incorrect config in qgl test
abbiemery Feb 11, 2025
4337f02
Preserve order in serde_json
abbiemery Feb 11, 2025
fb407c1
Remove unneccessary pub
abbiemery Feb 11, 2025
80cfba2
Update src/db_service.rs
abbiemery Feb 11, 2025
58ca416
Update src/db_service.rs test match
abbiemery Feb 11, 2025
cbc639a
Fix indentation in gql tests
abbiemery Feb 11, 2025
aabbd89
Update README with new gql API changes
abbiemery Feb 11, 2025
6d64582
Add test for super admin check
abbiemery Feb 11, 2025
4e2e4f2
Add denied super admin check
abbiemery Feb 11, 2025
1bd9e33
Add unauthorised super admin check test
abbiemery Feb 11, 2025
52f4b2c
Rename check admin tests to match api methods
abbiemery Feb 11, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ assert_matches = "1.5.0"
async-std = { version = "1.13.0", features = ["attributes"], default-features = false }
httpmock = { version = "0.7.0", default-features = false }
rstest = "0.24.0"
serde_json = "1.0.138"
serde_json = { version = "1.0.138", features = ["preserve_order"] }
tempfile = "3.16.0"

[build-dependencies]
Expand Down
92 changes: 87 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,9 @@ echo '{
</details>

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

#### paths
Get the visit directory for a beamline and visit
Expand Down Expand Up @@ -119,7 +119,9 @@ Get the current configuration values for the given beamline
visitTemplate
scanTemplate
detectorTemplate
latestScanNumber
dbScanNumber
fileScanNumber
trackerFileExtension
Comment thread
abbiemery marked this conversation as resolved.
}
}
```
Expand All @@ -131,11 +133,91 @@ Get the current configuration values for the given beamline
"visitTemplate": "/data/{instrument}/data/{year}/{visit}",
"scanTemplate": "{subdirectory}/{instrument}-{scan_number}",
"detectorTemplate": "{subdirectory}/{instrument}-{scan_number}-{detector}",
"latestScanNumber": 20839
"dbScanNumber": 0,
"fileScanNumber": null,
"trackerFileExtension": null
}
}
```

#### configurations
Get the current configuration values for one or more beamlines specified as a list.
Providing no beamlines returns all current configurations.

##### Query
```graphql
{
configurations(beamlineFilters: ["i22", "i11"]) {
beamline
visitTemplate
scanTemplate
detectorTemplate
dbScanNumber
fileScanNumber
trackerFileExtension
}
}
```

##### Response
```json
{
"configurations": [
{
"beamline": "i11",
"visitTemplate": "/tmp/{instrument}/data/{year}/{visit}",
"scanTemplate": "{subdirectory}/{instrument}-{scan_number}",
"detectorTemplate": "{subdirectory}/{instrument}-{scan_number}-{detector}",
"dbScanNumber": 0,
"fileScanNumber": null,
"trackerFileExtension": null
},
{
"beamline": "i22",
"visitTemplate": "/tmp/{instrument}/data/{year}/{visit}",
"scanTemplate": "{subdirectory}/{instrument}-{scan_number}",
"detectorTemplate": "{subdirectory}/{instrument}-{scan_number}-{detector}",
"dbScanNumber": 0,
"fileScanNumber": null,
"trackerFileExtension": null
}
]
}
```

##### Query
```graphql
{
configurations {
beamline
visitTemplate
scanTemplate
detectorTemplate
dbScanNumber
fileScanNumber
trackerFileExtension
}
}
```

##### Response
```json
{
"configurations": [
{
"beamline": "i11",
"visitTemplate": "/tmp/{instrument}/data/{year}/{visit}",
"scanTemplate": "{subdirectory}/{instrument}-{scan_number}",
"detectorTemplate": "{subdirectory}/{instrument}-{scan_number}-{detector}",
"dbScanNumber": 0,
"fileScanNumber": null,
"trackerFileExtension": null
},
...
]
}
```

## Mutations (read-write)

#### scan
Expand Down
157 changes: 157 additions & 0 deletions src/db_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,32 @@ impl SqliteScanPathService {
.ok_or(ConfigurationError::MissingBeamline(beamline.into()))
}

pub async fn configurations(
&self,
filters: Vec<String>,
) -> Result<Vec<BeamlineConfiguration>, ConfigurationError> {
let mut q = QueryBuilder::new("SELECT * FROM beamline WHERE name in (");
let mut beamlines = q.separated(", ");
for filter in filters {
beamlines.push_bind(filter);
}
q.push(")");

let query = q.build_query_as();
Ok(query.fetch_all(&self.pool).await?)
}

pub async fn all_configurations(
&self,
) -> Result<Vec<BeamlineConfiguration>, ConfigurationError> {
Ok(query_as!(DbBeamlineConfig, "SELECT * FROM beamline")
.fetch_all(&self.pool)
.await?
.into_iter()
.map(BeamlineConfiguration::from)
.collect())
}

pub async fn next_scan_configuration(
&self,
beamline: &str,
Expand Down Expand Up @@ -575,6 +601,137 @@ mod db_tests {
assert_eq!(ext, "ext");
}

#[rstest]
#[test]
async fn configurations() {
let db = SqliteScanPathService::memory().await;
ok!(update("i22")
.with_scan_number(122)
.with_extension("ext")
.insert_new(&db));
ok!(update("i11")
.with_scan_number(111)
.with_extension("ext")
.insert_new(&db));

let confs = ok!(db.configurations(vec![
"i22".to_string(),
"i11".to_string(),
"i03".to_string()
]));
// i03 has not been configured so it will not fetch it.
assert_eq!(confs.len(), 2);

for conf in confs.iter() {
match conf.name() {
"i22" => {
Comment thread
abbiemery marked this conversation as resolved.
assert_eq!(conf.name(), "i22");
assert_eq!(conf.scan_number(), 122);
assert_eq!(
conf.visit().unwrap().to_string(),
"/tmp/{instrument}/data/{year}/{visit}"
);
assert_eq!(
conf.scan().unwrap().to_string(),
"{subdirectory}/{instrument}-{scan_number}"
);
assert_eq!(
conf.detector().unwrap().to_string(),
"{subdirectory}/{instrument}-{scan_number}-{detector}"
);
let Some(ext) = &conf.tracker_file_extension else {
panic!("Missing extension");
};
assert_eq!(ext, "ext");
}
"i11" => {
assert_eq!(conf.name(), "i11");
assert_eq!(conf.scan_number(), 111);
assert_eq!(
conf.visit().unwrap().to_string(),
"/tmp/{instrument}/data/{year}/{visit}"
);
assert_eq!(
conf.scan().unwrap().to_string(),
"{subdirectory}/{instrument}-{scan_number}"
);
assert_eq!(
conf.detector().unwrap().to_string(),
"{subdirectory}/{instrument}-{scan_number}-{detector}"
);
let Some(ext) = &conf.tracker_file_extension else {
panic!("Missing extension");
};
assert_eq!(ext, "ext");
}
other => panic!("Unexpected beamline name: {other}"),
}
}
}

#[rstest]
#[test]
async fn all_configurations() {
let db = SqliteScanPathService::memory().await;
ok!(update("i22")
.with_scan_number(122)
.with_extension("ext")
.insert_new(&db));
ok!(update("i11")
.with_scan_number(111)
.with_extension("ext")
.insert_new(&db));

let confs = ok!(db.all_configurations());
assert_eq!(confs.len(), 2);

for conf in confs.iter() {
match conf.name() {
"i22" => {
assert_eq!(conf.name(), "i22");
assert_eq!(conf.scan_number(), 122);
assert_eq!(
conf.visit().unwrap().to_string(),
"/tmp/{instrument}/data/{year}/{visit}"
);
assert_eq!(
conf.scan().unwrap().to_string(),
"{subdirectory}/{instrument}-{scan_number}"
);
assert_eq!(
conf.detector().unwrap().to_string(),
"{subdirectory}/{instrument}-{scan_number}-{detector}"
);
let Some(ext) = &conf.tracker_file_extension else {
panic!("Missing extension");
};
assert_eq!(ext, "ext");
}
"i11" => {
assert_eq!(conf.name(), "i11");
assert_eq!(conf.scan_number(), 111);
assert_eq!(
conf.visit().unwrap().to_string(),
"/tmp/{instrument}/data/{year}/{visit}"
);
assert_eq!(
conf.scan().unwrap().to_string(),
"{subdirectory}/{instrument}-{scan_number}"
);
assert_eq!(
conf.detector().unwrap().to_string(),
"{subdirectory}/{instrument}-{scan_number}-{detector}"
);
let Some(ext) = &conf.tracker_file_extension else {
panic!("Missing extension");
};
assert_eq!(ext, "ext");
}
other => panic!("Unexpected beamline name: {other}"),
}
}
}

type Update = BeamlineConfigurationUpdate;

#[rstest]
Expand Down
Loading