Skip to content

Commit c98bebd

Browse files
authored
Merge pull request #51 from dev-five-git/add-config-schema
Add config schema
2 parents fe14d74 + 0193ce7 commit c98bebd

8 files changed

Lines changed: 168 additions & 32 deletions

File tree

Cargo.lock

Lines changed: 12 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/vespertide-config/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ description = "Manages models/migrations directories and naming-case preferences
1111
[dependencies]
1212
serde = { version = "1", features = ["derive"] }
1313
clap = { version = "4", features = ["derive"] }
14+
schemars = "1.1"
1415

1516
[dev-dependencies]
1617
serde_json = "1"

crates/vespertide-config/src/config.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use std::path::{Path, PathBuf};
22

3+
use schemars::JsonSchema;
34
use serde::{Deserialize, Serialize};
45

56
use crate::file_format::FileFormat;
@@ -11,7 +12,7 @@ pub fn default_migration_filename_pattern() -> String {
1112
}
1213

1314
/// SeaORM-specific export configuration.
14-
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
15+
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
1516
#[serde(rename_all = "camelCase")]
1617
pub struct SeaOrmConfig {
1718
/// Additional derive macros to add to generated enum types.
@@ -49,7 +50,7 @@ impl SeaOrmConfig {
4950
}
5051

5152
/// Top-level vespertide configuration.
52-
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
53+
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
5354
#[serde(rename_all = "camelCase")]
5455
pub struct VespertideConfig {
5556
pub models_dir: PathBuf,

crates/vespertide-config/src/file_format.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
use clap::ValueEnum;
2+
use schemars::JsonSchema;
23
use serde::{Deserialize, Serialize};
34

45
/// Supported file formats for generated artifacts.
5-
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, ValueEnum)]
6+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, ValueEnum, JsonSchema)]
67
#[serde(rename_all = "lowercase")]
78
#[derive(Default)]
89
pub enum FileFormat {

crates/vespertide-config/src/name_case.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1+
use schemars::JsonSchema;
12
use serde::{Deserialize, Serialize};
23

34
/// Supported naming cases.
4-
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
5+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
56
#[serde(rename_all = "snake_case")]
67
pub enum NameCase {
78
Snake,
Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,24 @@
1-
[package]
2-
name = "vespertide-schema-gen"
3-
version = "0.1.0"
4-
edition.workspace = true
5-
license.workspace = true
6-
repository.workspace = true
7-
homepage.workspace = true
8-
documentation.workspace = true
9-
description = "Emits JSON Schemas for vespertide models and migrations"
10-
publish = false
11-
1+
[package]
2+
name = "vespertide-schema-gen"
3+
version = "0.1.0"
4+
edition.workspace = true
5+
license.workspace = true
6+
repository.workspace = true
7+
homepage.workspace = true
8+
documentation.workspace = true
9+
description = "Emits JSON Schemas for vespertide models and migrations"
10+
publish = false
11+
1212
[dependencies]
1313
anyhow = "1"
1414
clap = { version = "4", features = ["derive"] }
1515
schemars = "1.1"
1616
serde_json = "1"
1717
vespertide-core = { workspace = true }
18-
19-
[dev-dependencies]
20-
tempfile = "3"
21-
assert_cmd = "2"
22-
predicates = "3"
23-
18+
vespertide-config = { workspace = true }
19+
20+
[dev-dependencies]
21+
tempfile = "3"
22+
assert_cmd = "2"
23+
predicates = "3"
24+

crates/vespertide-schema-gen/src/main.rs

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use std::path::PathBuf;
44
use anyhow::{Context, Result};
55
use clap::Parser;
66
use schemars::schema_for;
7+
use vespertide_config::VespertideConfig;
78
use vespertide_core::{MigrationPlan, TableDef};
89

910
#[derive(Debug, Parser)]
@@ -29,9 +30,11 @@ fn run(out: PathBuf) -> Result<()> {
2930

3031
let model_schema = schema_for!(TableDef);
3132
let migration_schema = schema_for!(MigrationPlan);
33+
let config_schema = schema_for!(VespertideConfig);
3234

3335
let model_path = out.join("model.schema.json");
3436
let migration_path = out.join("migration.schema.json");
37+
let config_path = out.join("config.schema.json");
3538

3639
fs::write(
3740
&model_path,
@@ -45,9 +48,16 @@ fn run(out: PathBuf) -> Result<()> {
4548
)
4649
.with_context(|| format!("write {}", migration_path.display()))?;
4750

51+
fs::write(
52+
&config_path,
53+
serde_json::to_string_pretty(&config_schema).context("serialize config schema")?,
54+
)
55+
.with_context(|| format!("write {}", config_path.display()))?;
56+
4857
println!("Wrote schemas:");
4958
println!(" {}", model_path.display());
5059
println!(" {}", migration_path.display());
60+
println!(" {}", config_path.display());
5161
Ok(())
5262
}
5363

@@ -98,24 +108,28 @@ mod tests {
98108
}
99109

100110
#[test]
101-
fn run_generates_both_schema_files() {
111+
fn run_generates_all_schema_files() {
102112
let temp_dir = TempDir::new().unwrap();
103113
let out = temp_dir.path();
104114

105115
run(out.to_path_buf()).unwrap();
106116

107117
let model_path = out.join("model.schema.json");
108118
let migration_path = out.join("migration.schema.json");
119+
let config_path = out.join("config.schema.json");
109120

110121
assert!(model_path.exists());
111122
assert!(migration_path.exists());
123+
assert!(config_path.exists());
112124

113125
// Verify files are valid JSON
114126
let model_content = fs::read_to_string(&model_path).unwrap();
115127
let migration_content = fs::read_to_string(&migration_path).unwrap();
128+
let config_content = fs::read_to_string(&config_path).unwrap();
116129

117130
serde_json::from_str::<serde_json::Value>(&model_content).unwrap();
118131
serde_json::from_str::<serde_json::Value>(&migration_content).unwrap();
132+
serde_json::from_str::<serde_json::Value>(&config_content).unwrap();
119133
}
120134

121135
#[test]
@@ -132,7 +146,25 @@ mod tests {
132146

133147
let model_path = out.join("model.schema.json");
134148
let migration_path = out.join("migration.schema.json");
149+
let config_path = out.join("config.schema.json");
135150
assert!(model_path.exists());
136151
assert!(migration_path.exists());
152+
assert!(config_path.exists());
153+
}
154+
155+
#[test]
156+
fn run_generates_config_schema_file() {
157+
let temp_dir = TempDir::new().unwrap();
158+
let out = temp_dir.path();
159+
160+
run(out.to_path_buf()).unwrap();
161+
162+
let config_path = out.join("config.schema.json");
163+
assert!(config_path.exists());
164+
165+
let content = fs::read_to_string(&config_path).unwrap();
166+
assert!(content.contains("VespertideConfig"));
167+
assert!(content.contains("modelsDir"));
168+
assert!(content.contains("migrationsDir"));
137169
}
138170
}

schemas/config.schema.json

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
{
2+
"$schema": "https://json-schema.org/draft/2020-12/schema",
3+
"title": "VespertideConfig",
4+
"description": "Top-level vespertide configuration.",
5+
"type": "object",
6+
"properties": {
7+
"columnNamingCase": {
8+
"$ref": "#/$defs/NameCase"
9+
},
10+
"migrationFilenamePattern": {
11+
"type": "string",
12+
"default": "%04v_%m"
13+
},
14+
"migrationFormat": {
15+
"$ref": "#/$defs/FileFormat",
16+
"default": "json"
17+
},
18+
"migrationsDir": {
19+
"type": "string"
20+
},
21+
"modelExportDir": {
22+
"description": "Output directory for generated ORM models.",
23+
"type": "string",
24+
"default": "src/models"
25+
},
26+
"modelFormat": {
27+
"$ref": "#/$defs/FileFormat",
28+
"default": "json"
29+
},
30+
"modelsDir": {
31+
"type": "string"
32+
},
33+
"seaorm": {
34+
"description": "SeaORM-specific export configuration.",
35+
"$ref": "#/$defs/SeaOrmConfig",
36+
"default": {
37+
"extraEnumDerives": [
38+
"vespera::Schema"
39+
],
40+
"extraModelDerives": []
41+
}
42+
},
43+
"tableNamingCase": {
44+
"$ref": "#/$defs/NameCase"
45+
}
46+
},
47+
"required": [
48+
"modelsDir",
49+
"migrationsDir",
50+
"tableNamingCase",
51+
"columnNamingCase"
52+
],
53+
"$defs": {
54+
"FileFormat": {
55+
"description": "Supported file formats for generated artifacts.",
56+
"type": "string",
57+
"enum": [
58+
"json",
59+
"yaml",
60+
"yml"
61+
]
62+
},
63+
"NameCase": {
64+
"description": "Supported naming cases.",
65+
"type": "string",
66+
"enum": [
67+
"snake",
68+
"camel",
69+
"pascal"
70+
]
71+
},
72+
"SeaOrmConfig": {
73+
"description": "SeaORM-specific export configuration.",
74+
"type": "object",
75+
"properties": {
76+
"extraEnumDerives": {
77+
"description": "Additional derive macros to add to generated enum types.\nDefault: `[\"vespera::Schema\"]`",
78+
"type": "array",
79+
"default": [
80+
"vespera::Schema"
81+
],
82+
"items": {
83+
"type": "string"
84+
}
85+
},
86+
"extraModelDerives": {
87+
"description": "Additional derive macros to add to generated entity model types.",
88+
"type": "array",
89+
"default": [],
90+
"items": {
91+
"type": "string"
92+
}
93+
}
94+
}
95+
}
96+
}
97+
}

0 commit comments

Comments
 (0)