Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

4791 add report versioning #5533

Merged
merged 38 commits into from
Dec 19, 2024
Merged

4791 add report versioning #5533

merged 38 commits into from
Dec 19, 2024

Conversation

fergie-nz
Copy link
Contributor

Fixes #4791

πŸ‘©πŸ»β€πŸ’» What does this PR do?

Two parts:

  • Adds only upsert if the report to be upserted is a later version than the existing report of the same code (or if is_custom && is later version than an existing custom report)
  • Adds filter for only the latest version of any report which is compatible with the app version

There is a unique case which could casue issues where if a db has a report version later than the app version, you wouldn't be able to upload older report versions. But I don't think we need to worry about that.

πŸ’Œ Any notes for the reviewer?

You can test this report with this database which includes a number of report versions and is_custom combinations:

central_test.sqlite.zip

πŸ§ͺ Testing

  • Go to reports
  • See only latest versions displayed

πŸ“ƒ Documentation

  • No documentation required: no user facing changes or a bug fix which isn't a change in behaviour

@github-actions github-actions bot added this to the V2.4.0-RC4 milestone Nov 22, 2024
@github-actions github-actions bot added enhancement New feature or request Priority: Must Have The product will not work without this Team Ruru πŸ¦‰ Roxy, Ferg, Noel feature: reports labels Nov 22, 2024
Copy link

github-actions bot commented Nov 22, 2024

Bundle size difference

Comparing this PR to main

Old size New size Diff
4.98 MB 4.98 MB 0 B (0.00%)

@andreievg andreievg self-assigned this Nov 25, 2024
version: report.version,
code: report.code,
})?;
};
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm not very happy with logic here, do you mind doing a self review of the changes and existing logic in this file and seeing how it can/should be simplified ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi Andrei,

I was wondering about just upserting all reports regardless of if they were older versions than the one existing on the server.
Is this what you're thinking? Or are you thinking refactoring but keeping the current logic?

return 0;
};

export const useLatestReportList = ({
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Front end should be report version agnostic, this should be back end logic

@fergie-nz fergie-nz requested a review from andreievg November 27, 2024 00:59
@roxy-dao roxy-dao removed this from the V2.4.0-RC4 milestone Nov 27, 2024
Comment on lines -113 to -125
pub fn find_one_by_code_and_version(
&self,
code: &str,
version: &str,
) -> Result<Option<ReportRow>, RepositoryError> {
let result = report_dsl::report
.filter(report_dsl::code.eq(code))
.filter(report_dsl::version.eq(version))
.first(self.connection.lock().connection())
.optional()?;
Ok(result)
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removing as not anymore

Comment on lines +59 to +93
pub fn mock_report_g() -> ReportRow {
inline_init(|r: &mut ReportRow| {
r.id = "mock_report_g".to_string();
r.version = "2.3.0".to_string();
r.is_custom = true;
r.code = "report_with_custom_option".to_string();
})
}

pub fn mock_report_h() -> ReportRow {
inline_init(|r: &mut ReportRow| {
r.id = "mock_report_h".to_string();
r.version = "2.3.1".to_string();
r.is_custom = false;
r.code = "report_with_custom_option".to_string();
})
}

pub fn mock_report_i() -> ReportRow {
inline_init(|r: &mut ReportRow| {
r.id = "mock_report_i".to_string();
r.version = "2.8.2".to_string();
r.is_custom = true;
r.code = "report_with_custom_option".to_string();
})
}

pub fn mock_report_j() -> ReportRow {
inline_init(|r: &mut ReportRow| {
r.id = "mock_report_j".to_string();
r.version = "3.0.1".to_string();
r.is_custom = false;
r.code = "report_with_custom_option".to_string();
})
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added extra cases to test for prioritising is_custom reports

Comment on lines 337 to 340
let reports_to_show_meta_data = report_filter_method(
repo.query_meta_data(Some(filter.clone()), None)?,
app_version,
);
Copy link
Contributor Author

@fergie-nz fergie-nz Nov 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added querying all for metadata first with a sub selection of code, version, id, and is_custom. I thought this would help if our report list gets long and we aren't wanting to query all reports and filter out later.

Later we can collect the ids, and query all report data.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added querying all for metadata first with a sub selection of code, version, id, and is_custom. I thought this would help if our report list gets long and we aren't wanting to query all reports and filter out later.

That's awesome, thank you

Ok(reports)
}

fn report_filter_method(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a feeling this logic could be more concise. However, after taking some time to think about it, I figure it is not worth spending time on now given we are only passing around report_meta_data

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is great, really easy to read and performant, thank you. There is a lot to like about this, abstraction for readability, the reports_of_code and custom_reports_of_code` reduces the cognitive load (one step at a time)

The only improvement I can think of, the query_meta_data could return a domain object, with a little bit of mapping after .load, to get the version number (from_str) and store it into that domain object (reduce mapping in compare_major_minor and in find_latest_report)

};

use crate::{
diesel_macros::{apply_equal_filter, apply_sort_no_case},
schema_from_row, FormSchema, FormSchemaRow,
};
use crate::{EqualFilter, Pagination, Sort, StringFilter};
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have removed pagination as we won't use it for these queries.

@roxy-dao roxy-dao modified the milestones: V2.4.0-RC5, V2.4.0-RC6, v2.5.0 Nov 28, 2024
@roxy-dao roxy-dao changed the base branch from v2.4.0 to develop November 28, 2024 22:46
Copy link
Collaborator

@andreievg andreievg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking very good, a joy to review. At some point we need to document this a bit more, wondering if it should be done inline in code, or as a separate .md file

server/service/src/report/report_service.rs Outdated Show resolved Hide resolved
let filter = filter
.unwrap_or_default()
.r#type(ReportType::OmSupply.equal_to());
Ok(repo.query(pagination, Some(filter.clone()), sort)?)

let reports_to_show_meta_data = report_filter_method(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's better to return report_ids to show (that feels a bit more clear to me), maybe it's personal preference, how does it sound to you ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes I like that too - will amend

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment on lines 337 to 340
let reports_to_show_meta_data = report_filter_method(
repo.query_meta_data(Some(filter.clone()), None)?,
app_version,
);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added querying all for metadata first with a sub selection of code, version, id, and is_custom. I thought this would help if our report list gets long and we aren't wanting to query all reports and filter out later.

That's awesome, thank you

}
}
}
Ok(query
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's so good !

Ok(reports)
}

fn report_filter_method(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is great, really easy to read and performant, thank you. There is a lot to like about this, abstraction for readability, the reports_of_code and custom_reports_of_code` reduces the cognitive load (one step at a time)

The only improvement I can think of, the query_meta_data could return a domain object, with a little bit of mapping after .load, to get the version number (from_str) and store it into that domain object (reduce mapping in compare_major_minor and in find_latest_report)

@fergie-nz
Copy link
Contributor Author

Looking very good, a joy to review. At some point we need to document this a bit more, wondering if it should be done inline in code, or as a separate .md file

Cheers!

I am thinking in report .md file might be good? It documents a lot of other report editing how-tos, which would be accompanied by report version changes.

@fergie-nz
Copy link
Contributor Author

Have added better explanation in .md file, and added from_domain mapping to remove need for version mapping in meta data.

@fergie-nz fergie-nz requested a review from andreievg December 17, 2024 01:23
@@ -93,6 +93,26 @@ impl Default for ReportRow {
}
}

#[derive(Clone, Insertable, Queryable, Debug, PartialEq, Eq, AsChangeset, Selectable)]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can default here so you don't need to impl default (:

.map(|r| r.id)
.collect(),
));
let filter = ReportFilter::new().id(EqualFilter::equal_any(reports_to_show_meta_data));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this variable name doesn't make that much sense now

let mut report = reports
.clone()
.into_iter()
.filter(|r| r.id == result.clone().into_iter().next().unwrap())
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

result.first/pop().unwrap()

@@ -21,6 +22,25 @@ pub struct Report {
pub argument_schema: Option<FormSchema>,
}

#[derive(Debug, Clone, PartialEq)]
pub struct ReportMetaData {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

our domain object are composites atm, we don't really copy them (a bit less mapping and less to change when new fields are added)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So should just have Version as another key (of type Version)

.filter(|r| {
compare_major_minor(Version::from_str(&r.version), &app_version) != Ordering::Greater
})
.filter(|r| compare_major_minor(r.version.clone(), &app_version) != Ordering::Greater)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why clone ?

Copy link
Collaborator

@andreievg andreievg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks great thanks

@fergie-nz fergie-nz merged commit 84f56eb into develop Dec 19, 2024
2 checks passed
@fergie-nz fergie-nz deleted the 4791-add-report-versioning branch December 19, 2024 03:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request feature: reports Priority: Must Have The product will not work without this Team Ruru πŸ¦‰ Roxy, Ferg, Noel
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Reports-versioning: Select the right version of a report to include
3 participants