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

Merge version and version_sort columns #2344

Closed
Tracked by #2341
david-crespo opened this issue Feb 9, 2023 · 0 comments · Fixed by #2346
Closed
Tracked by #2341

Merge version and version_sort columns #2344

david-crespo opened this issue Feb 9, 2023 · 0 comments · Fixed by #2346

Comments

@david-crespo
Copy link
Contributor

david-crespo commented Feb 9, 2023

Semver version strings do not sort well lexicographically. In #2100 I hacked in DB sorting of system updates by version by adding a second column to sort by, version_sort:

-- Unique semver version
version STRING(64) NOT NULL, -- TODO: length
-- version string with maj/min/patch 0-padded to be string sortable
version_sort STRING(64) NOT NULL -- TODO: length

-- The version of the system update this component's software came from.
-- This may need to be nullable if we are registering components before we
-- know about system versions at all
system_version STRING(64) NOT NULL, -- TODO: length
-- version string with maj/min/patch 0-padded to be string sortable
system_version_sort STRING(64) NOT NULL, -- TODO: length

which uses left zero padding to make the versions sort almost correctly. (Technically, build and prerelease meta are not supposed to be sorted lexicographically, but we have decided to tolerate being wrong in this way for now.)

pub fn to_sortable_string(self) -> Result<String, external::Error> {
let v = &self.0 .0;
if v.major > MAX_VERSION_NUM
|| v.minor > MAX_VERSION_NUM
|| v.patch > MAX_VERSION_NUM
{
return Err(external::Error::InvalidValue {
label: "version".to_string(),
message: format!("Major, minor, and patch version must be less than {MAX_VERSION_NUM}"),
});
}
let mut result =
format!("{:0>8}.{:0>8}.{:0>8}", v.major, v.minor, v.patch);

However! These do not actually need to be two columns. I only did it that way because I didn't feel like figuring out how to deserialize the zero-padded version string back into a Semver::Version (built-in parse chokes on the zeros). The change that's required here is to update our ToSql for SemverVersion to do the zero-padding and the FromSql to remove the zero-padding before passing it to Semver::Version's parse.

impl<DB> ToSql<sql_types::Text, DB> for SemverVersion
where
DB: Backend<BindCollector = RawBytesBindCollector<DB>>,
String: ToSql<sql_types::Text, DB>,
{
fn to_sql<'a>(
&'a self,
out: &mut serialize::Output<'a, '_, DB>,
) -> serialize::Result {
(self.0).0.to_string().to_sql(&mut out.reborrow())
}
}
impl<DB> FromSql<sql_types::Text, DB> for SemverVersion
where
DB: Backend,
String: FromSql<sql_types::Text, DB>,
{
fn from_sql(raw: RawValue<DB>) -> deserialize::Result<Self> {
String::from_sql(raw)?
.parse()
.map(|s| SemverVersion(external::SemverVersion(s)))
.map_err(|e| e.into())
}
}

That way, we do not have to generate a sortable string manually in the constructor.

impl SystemUpdate {
/// Can fail if version numbers are too high.
pub fn new(
version: external::SemverVersion,
) -> Result<Self, external::Error> {
let db_version = SemverVersion(version);
Ok(Self {
identity: SystemUpdateIdentity::new(Uuid::new_v4()),
version: db_version.clone(),
version_sort: db_version.to_sortable_string()?,
})
}
}

@david-crespo david-crespo changed the title Merge version and version_sort Merge version and version_sort columns Feb 9, 2023
david-crespo added a commit that referenced this issue Feb 10, 2023
Closes #2344. Followup to #2100. Rather than manually adding a sortable
`version_sort` column alongside the `version` column, make
`SemverVersion` itself automatically sortable by serializing it to the
DB in sortable form (with zero padding on the numbers). On
deserialization, we remove the padding before trying to parse it.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant