Skip to content

Commit

Permalink
new: Add serde support to schema. (#134)
Browse files Browse the repository at this point in the history
  • Loading branch information
milesj authored Aug 5, 2024
1 parent b91928d commit b8216f1
Show file tree
Hide file tree
Showing 16 changed files with 122 additions and 2 deletions.
5 changes: 3 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@
- Removed generics from `SchemaGenerator` and `SchemaRenderer`.

```rust
# Before
// Before
fn render(
&mut self,
schemas: &'gen IndexMap<String, Schema>,
references: &'gen HashSet<String>,
) -> RenderResult;

# After
// After
fn render(&mut self, schemas: IndexMap<String, Schema>) -> RenderResult;
```

Expand All @@ -35,6 +35,7 @@ fn render(&mut self, schemas: IndexMap<String, Schema>) -> RenderResult;
- Added a `env` Cargo feature for toggling environment variable functionality. Enabled by default.
- Added a `extends` Cargo feature for config extending functionality. Enabled by default.
- Added a `validate` Cargo feature for toggling validation functionality. Enabled by default.
- Added a `schema_serde` Cargo feature for allowing the `Schema` to be serialized.
- Reworked how parser and validator errors are rendered in the terminal.

#### ⚙️ Internal
Expand Down
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: 2 additions & 0 deletions crates/schematic/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ config = [
"schematic_macros/config",
]
schema = ["dep:indexmap", "schematic_macros/schema"]
schema_serde = ["schema", "schematic_types/serde"]
tracing = ["schematic_macros/tracing"]

# Features
Expand Down Expand Up @@ -102,6 +103,7 @@ schematic = { path = ".", features = [
"extends",
"json",
"schema",
"schema_serde",
"toml",
"renderer_json_schema",
"renderer_template",
Expand Down
3 changes: 3 additions & 0 deletions crates/types/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ rust_decimal = { workspace = true, optional = true }
relative-path = { workspace = true, optional = true }
url = { workspace = true, optional = true }
semver = { workspace = true, optional = true }
serde = { workspace = true, optional = true }
serde_json = { workspace = true, optional = true }
serde_yaml = { workspace = true, optional = true }
toml = { workspace = true, optional = true }
Expand All @@ -27,6 +28,7 @@ schematic_types = { path = ".", features = [
"relative_path",
"rust_decimal",
"semver",
"serde",
"serde_json",
"serde_toml",
"serde_yaml",
Expand All @@ -41,6 +43,7 @@ regex = ["dep:regex"]
relative_path = ["dep:relative-path"]
rust_decimal = ["dep:rust_decimal"]
semver = ["dep:semver"]
serde = ["dep:serde"]
serde_json = ["dep:serde_json"]
serde_toml = ["dep:toml"]
serde_yaml = ["dep:serde_yaml"]
Expand Down
13 changes: 13 additions & 0 deletions crates/types/src/arrays.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,26 @@ use crate::*;
use std::collections::{BTreeSet, HashSet};

#[derive(Clone, Debug, Default, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct ArrayType {
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub contains: Option<bool>,

pub items_type: Box<Schema>,

#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub max_contains: Option<usize>,

#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub max_length: Option<usize>,

#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub min_contains: Option<usize>,

#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub min_length: Option<usize>,

#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub unique: Option<bool>,
}

Expand Down
2 changes: 2 additions & 0 deletions crates/types/src/bools.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use crate::*;

#[derive(Clone, Debug, Default, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct BooleanType {
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub default: Option<LiteralValue>,
}

Expand Down
5 changes: 5 additions & 0 deletions crates/types/src/enums.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,14 @@ use crate::*;
pub use indexmap::IndexMap;

#[derive(Clone, Debug, Default, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct EnumType {
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub default_index: Option<usize>,

pub values: Vec<LiteralValue>,

#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub variants: Option<IndexMap<String, Box<SchemaField>>>,
}

Expand Down
5 changes: 5 additions & 0 deletions crates/types/src/literals.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "serde", serde(tag = "type", content = "value"))]
pub enum LiteralValue {
Bool(bool),
F32(f32),
Expand All @@ -9,8 +11,11 @@ pub enum LiteralValue {
}

#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct LiteralType {
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub format: Option<String>,

pub value: LiteralValue,
}

Expand Down
38 changes: 38 additions & 0 deletions crates/types/src/numbers.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::*;

#[derive(Clone, Debug, Default, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub enum IntegerKind {
Isize,
I8,
Expand All @@ -27,15 +28,32 @@ impl IntegerKind {
}

#[derive(Clone, Debug, Default, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct IntegerType {
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub default: Option<LiteralValue>,

#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub enum_values: Option<Vec<isize>>,

#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub format: Option<String>,

pub kind: IntegerKind,

#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub max: Option<isize>,

#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub max_exclusive: Option<isize>,

#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub min: Option<isize>,

#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub min_exclusive: Option<isize>,

#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub multiple_of: Option<isize>,
}

Expand Down Expand Up @@ -96,23 +114,43 @@ impl_int!(i64, IntegerKind::I64);
impl_int!(i128, IntegerKind::I128);

#[derive(Clone, Debug, Default, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub enum FloatKind {
#[default]
F32,
F64,
}

#[derive(Clone, Debug, Default, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct FloatType {
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub default: Option<LiteralValue>,

#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub enum_values: Option<Vec<f64>>,

#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub format: Option<String>,

pub kind: FloatKind,

#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub max: Option<f64>,

#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub max_exclusive: Option<f64>,

#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub min: Option<f64>,

#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub min_exclusive: Option<f64>,

#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub multiple_of: Option<f64>,

#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub name: Option<String>,
}

Expand Down
8 changes: 8 additions & 0 deletions crates/types/src/objects.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,19 @@ use crate::*;
use std::collections::{BTreeMap, HashMap};

#[derive(Clone, Debug, Default, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct ObjectType {
pub key_type: Box<Schema>,

#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub max_length: Option<usize>,

#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub min_length: Option<usize>,

#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub required: Option<Vec<String>>,

pub value_type: Box<Schema>,
}

Expand Down
17 changes: 17 additions & 0 deletions crates/types/src/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,20 @@ use std::ops::{Deref, DerefMut};

/// Describes the metadata and shape of a type.
#[derive(Clone, Debug, Default, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct Schema {
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub deprecated: Option<String>,

#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub description: Option<String>,

#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub name: Option<String>,

#[cfg_attr(feature = "serde", serde(skip_serializing))]
pub nullable: bool,

pub ty: SchemaType,
}

Expand Down Expand Up @@ -172,11 +181,19 @@ impl From<Schema> for SchemaType {

/// Describes the metadata and shape of a field within a struct or enum.
#[derive(Clone, Debug, Default, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct SchemaField {
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub comment: Option<String>,

pub schema: Schema,

#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub deprecated: Option<String>,

#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub env_var: Option<String>,

pub hidden: bool,
pub nullable: bool,
pub optional: bool,
Expand Down
2 changes: 2 additions & 0 deletions crates/types/src/schema_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ use crate::unions::*;

/// All possible types within a schema.
#[derive(Clone, Debug, Default, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "serde", serde(tag = "type", content = "value"))]
pub enum SchemaType {
Null,
#[default]
Expand Down
12 changes: 12 additions & 0 deletions crates/types/src/strings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,24 @@ use std::path::{Path, PathBuf};
use std::time::{Duration, SystemTime};

#[derive(Clone, Debug, Default, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct StringType {
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub default: Option<LiteralValue>,

#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub enum_values: Option<Vec<String>>,

#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub format: Option<String>,

#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub max_length: Option<usize>,

#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub min_length: Option<usize>,

#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub pattern: Option<String>,
}

Expand Down
4 changes: 4 additions & 0 deletions crates/types/src/structs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,15 @@ use crate::schema::SchemaField;
use std::collections::BTreeMap;

#[derive(Clone, Debug, Default, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct StructType {
pub fields: BTreeMap<String, Box<SchemaField>>,

// The type is a partial nested config, like `PartialConfig`.
// This doesn't mean it's been partialized.
pub partial: bool,

#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub required: Option<Vec<String>>,
}

Expand Down
1 change: 1 addition & 0 deletions crates/types/src/tuples.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::*;

#[derive(Clone, Debug, Default, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct TupleType {
pub items_types: Vec<Box<Schema>>,
}
Expand Down
6 changes: 6 additions & 0 deletions crates/types/src/unions.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
use crate::*;

#[derive(Clone, Debug, Default, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub enum UnionOperator {
#[default]
AnyOf,
OneOf,
}

#[derive(Clone, Debug, Default, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct UnionType {
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub default_index: Option<usize>,

pub partial: bool,

pub operator: UnionOperator,

pub variants_types: Vec<Box<Schema>>,
}

Expand Down

0 comments on commit b8216f1

Please sign in to comment.