Skip to content

Commit

Permalink
Update CompatibilityDate in JSON Schema to contain a list of known da…
Browse files Browse the repository at this point in the history
…tes (#1432)

### What
This PR updates the MBS JSON Schema so that its definition of
CompatibilityDate contains a list of known compatibility dates. The type
still allows any date as well.

This change ensures that every time a new CompatibilityDate is added,
the JSON Schema changes, which automatically creates a PR to the CLI
repo, so they know a new date has been added, so that they can evaluate
and respond to that.

### How

The code that maps OpenDD `Flag`s to `CompatibilityDate`s was moved from
MBS to the `compatibility` crate, and then used during JSON Schema
formation to generate the JSON Schema enum list of dates.

V3_GIT_ORIGIN_REV_ID: e67dad2aa10e5e74613aa1f80c3972753bc9a576
  • Loading branch information
daniel-chambers authored and hasura-bot committed Dec 9, 2024
1 parent 4d514b7 commit 4df58b5
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 15 deletions.
1 change: 1 addition & 0 deletions v3/Cargo.lock

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

1 change: 1 addition & 0 deletions v3/crates/compatibility/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ schemars = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
serde_path_to_error = { workspace = true }
strum = { workspace = true }
thiserror = { workspace = true }

[package.metadata.cargo-machete]
Expand Down
98 changes: 96 additions & 2 deletions v3/crates/compatibility/src/compatibility_date.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
use std::collections::BTreeSet;

use chrono::NaiveDate;
use open_dds::flags::Flag;
use strum::IntoEnumIterator;

const DATE_FORMAT: &str = "%Y-%m-%d";

#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
/// The date to use for determining the default metadata semantics and Hasura behavior.
pub struct CompatibilityDate(pub NaiveDate);

Expand Down Expand Up @@ -43,11 +47,101 @@ impl schemars::JsonSchema for CompatibilityDate {
}

fn json_schema(_gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
schemars::schema::SchemaObject {
let any_date_schema = schemars::schema::SchemaObject {
metadata: Some(Box::new(schemars::schema::Metadata {
description: Some("Any date".to_owned()),
..Default::default()
})),
instance_type: Some(schemars::schema::InstanceType::String.into()),
format: Some("date".to_string()),
..Default::default()
}
.into();

let known_compatibility_dates = Flag::iter()
.filter_map(get_compatibility_date_for_flag)
.collect::<BTreeSet<CompatibilityDate>>();

let known_compatibility_dates_schema = schemars::schema::SchemaObject {
metadata: Some(Box::new(schemars::schema::Metadata {
description: Some("Known compatibility dates".to_owned()),
..Default::default()
})),
instance_type: Some(schemars::schema::InstanceType::String.into()),
enum_values: Some(
known_compatibility_dates
.into_iter()
.map(|date| serde_json::Value::String(date.to_string()))
.collect(),
),
..Default::default()
}
.into();

schemars::schema::SchemaObject {
metadata: Some(Box::new(schemars::schema::Metadata {
id: Some(format!(
"https://hasura.io/jsonschemas/metadata/{}",
Self::schema_name()
)),
title: Some(Self::schema_name()),
description: Some("Any backwards incompatible changes made to Hasura DDN after this date won't impact the metadata".to_owned()),
..Default::default()
})),
subschemas: Some(Box::new(schemars::schema::SubschemaValidation {
any_of: Some(vec![
known_compatibility_dates_schema,
any_date_schema,
]),
..Default::default()
})),
..Default::default()
}
.into()
}
}

pub const OLDEST_COMPATIBILITY_DATE: CompatibilityDate = new_compatibility_date(2023, 10, 9);

pub const fn new_compatibility_date(year: i32, month: u32, day: u32) -> CompatibilityDate {
CompatibilityDate(match NaiveDate::from_ymd_opt(year, month, day) {
// Need to match instead of unwrap because unwrap is still unstable as const
Some(date) => date,
None => panic!("Invalid date"),
})
}

// Adding a flag? Don't forget to add it to the docs: https://hasura.io/docs/3.0/supergraph-modeling/compatibility-config/
pub fn get_compatibility_date_for_flag(flag: Flag) -> Option<CompatibilityDate> {
match flag {
Flag::RequireGraphqlConfig => Some(new_compatibility_date(2024, 6, 30)),
Flag::BypassRelationComparisonsNdcCapability => Some(new_compatibility_date(2024, 9, 3)),
Flag::RequireNestedArrayFilteringCapability => Some(new_compatibility_date(2024, 9, 18)),
Flag::DisallowScalarTypeNamesConflictingWithInbuiltTypes
| Flag::PropagateBooleanExpressionDeprecationStatus => {
Some(new_compatibility_date(2024, 9, 26))
}
Flag::RequireUniqueCommandGraphqlNames => Some(new_compatibility_date(2024, 10, 7)),
Flag::AllowPartialSupergraph => None, // This is not triggered by compatibility date, instead it is set by the build settings (ie. using a /partial endpoint)
Flag::JsonSessionVariables => Some(new_compatibility_date(2024, 10, 16)),
Flag::DisallowArrayFieldComparedWithScalarBooleanType => {
Some(new_compatibility_date(2024, 10, 31))
}
Flag::AllowBooleanExpressionFieldsWithoutGraphql => {
Some(new_compatibility_date(2024, 11, 13))
}
Flag::RequireValidNdcV01Version | Flag::RequireUniqueModelGraphqlNames => {
Some(new_compatibility_date(2024, 11, 15))
}
Flag::DisallowObjectBooleanExpressionType => Some(new_compatibility_date(2024, 11, 18)),
Flag::LogicalOperatorsInScalarBooleanExpressions => {
Some(new_compatibility_date(2024, 11, 26))
}
Flag::DisallowDuplicateNamesInBooleanExpressions => {
Some(new_compatibility_date(2024, 12, 5))
}
Flag::DisallowMultipleInputObjectFieldsInGraphqlOrderBy => {
Some(new_compatibility_date(2024, 12, 10))
}
}
}
9 changes: 0 additions & 9 deletions v3/crates/compatibility/src/config.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use super::compatibility_date::CompatibilityDate;
use chrono::NaiveDate;

#[derive(Clone, Debug, PartialEq, serde::Serialize, opendds_derive::OpenDd)]
#[serde(rename_all = "camelCase")]
Expand All @@ -23,14 +22,6 @@ pub struct CompatibilityConfigV2 {
// TODO: add flags.
}

pub const fn new_compatibility_date(year: i32, month: u32, day: u32) -> CompatibilityDate {
CompatibilityDate(match NaiveDate::from_ymd_opt(year, month, day) {
// Need to match instead of unwrap because unwrap is still unstable as const
Some(date) => date,
None => panic!("Invalid date"),
})
}

#[derive(Debug, PartialEq, thiserror::Error)]
pub enum CompatibilityError {
#[error("no compatibility config found")]
Expand Down
9 changes: 5 additions & 4 deletions v3/crates/compatibility/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
mod compatibility_date;
pub use compatibility_date::CompatibilityDate;
pub use compatibility_date::{
get_compatibility_date_for_flag, new_compatibility_date, CompatibilityDate,
OLDEST_COMPATIBILITY_DATE,
};

mod config;
pub use config::{
new_compatibility_date, CompatibilityConfigV1, CompatibilityConfigV2, CompatibilityError,
};
pub use config::{CompatibilityConfigV1, CompatibilityConfigV2, CompatibilityError};

0 comments on commit 4df58b5

Please sign in to comment.