You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
+
5
+
## Overview
6
+
7
+
Vespertide is a Rust workspace for defining database schemas in JSON/YAML and generating migration plans and SQL from model diffs. It enables declarative schema management by comparing the current model state against a baseline reconstructed from applied migrations.
8
+
9
+
## Build and Test Commands
10
+
11
+
```bash
12
+
# Build the entire workspace
13
+
cargo build
14
+
15
+
# Run all tests
16
+
cargo test
17
+
18
+
# Run tests for a specific crate
19
+
cargo test -p vespertide-core
20
+
cargo test -p vespertide-planner
21
+
22
+
# Format code
23
+
cargo fmt
24
+
25
+
# Lint (important: use all targets and features)
26
+
cargo clippy --all-targets --all-features
27
+
28
+
# Regenerate JSON schemas
29
+
cargo run -p vespertide-schema-gen -- --out schemas
30
+
31
+
# Run CLI commands (use -p vespertide-cli)
32
+
cargo run -p vespertide-cli -- init
33
+
cargo run -p vespertide-cli -- new user
34
+
cargo run -p vespertide-cli -- diff
35
+
cargo run -p vespertide-cli -- sql
36
+
cargo run -p vespertide-cli -- revision -m "message"
37
+
cargo run -p vespertide-cli -- status
38
+
cargo run -p vespertide-cli -- log
39
+
```
40
+
41
+
## Architecture
42
+
43
+
### Core Data Flow
44
+
45
+
1.**Schema Definition**: Users define tables in JSON files (`TableDef`) in the `models/` directory
46
+
2.**Baseline Reconstruction**: Applied migrations are replayed to rebuild the baseline schema
47
+
3.**Diffing**: Current models are compared against the baseline to compute changes
48
+
4.**Planning**: Changes are converted into a `MigrationPlan` with versioned actions
49
+
5.**SQL Generation**: Migration actions are translated into PostgreSQL SQL statements
50
+
51
+
### Crate Responsibilities
52
+
53
+
-**vespertide-core**: Data structures (`TableDef`, `ColumnDef`, `MigrationAction`, `MigrationPlan`, constraints, indexes)
54
+
-**vespertide-planner**:
55
+
-`schema_from_plans()`: Replays applied migrations to reconstruct baseline schema
56
+
-`diff_schemas()`: Compares two schemas and generates migration actions
57
+
-`plan_next_migration()`: Combines baseline reconstruction + diffing to create the next migration
58
+
-`apply_action()`: Applies a single migration action to a schema (used during replay)
59
+
-`validate_*()`: Validates schemas and migration plans
60
+
-**vespertide-query**: Converts `MigrationAction` → PostgreSQL SQL with bind parameters
61
+
-**vespertide-config**: Manages `vespertide.json` (models/migrations directories, naming case preferences)
-**vespertide-exporter**: Exports schemas to other formats (e.g., SeaORM entities)
64
+
-**vespertide-schema-gen**: Generates JSON Schema files for validation
65
+
-**vespertide-macro**: Placeholder for future runtime migration executor
66
+
67
+
### Key Architectural Patterns
68
+
69
+
**Migration Replay Pattern**: The planner doesn't store a "current database state" - it reconstructs it by replaying all applied migrations in order. This ensures the baseline is always derivable from the migration history.
70
+
71
+
**Declarative Diffing**: Users declare the desired end state in model files. The diff engine compares this against the reconstructed baseline to compute necessary changes.
72
+
73
+
**Action-Based Migrations**: All changes are expressed as typed `MigrationAction` enums (CreateTable, AddColumn, ModifyColumnType, etc.) rather than raw SQL. SQL generation happens in a separate layer.
74
+
75
+
## Important Implementation Details
76
+
77
+
### ColumnDef Structure
78
+
When creating `ColumnDef` instances in tests or code, you must initialize ALL fields including the newer inline constraint fields:
79
+
80
+
```rust
81
+
ColumnDef {
82
+
name:"id".into(),
83
+
r#type:ColumnType::Integer,
84
+
nullable:false,
85
+
default:None,
86
+
comment:None,
87
+
primary_key:None, // Inline PK declaration
88
+
unique:None, // Inline unique constraint
89
+
index:None, // Inline index creation
90
+
foreign_key:None, // Inline FK definition
91
+
}
92
+
```
93
+
94
+
These inline fields (added recently) allow constraints to be defined directly on columns in addition to table-level `TableConstraint` definitions.
95
+
96
+
### Foreign Key Definition
97
+
Foreign keys can be defined inline on columns via the `foreign_key` field:
98
+
99
+
```rust
100
+
pubstructForeignKeyDef {
101
+
pubref_table:TableName,
102
+
pubref_columns:Vec<ColumnName>,
103
+
pubon_delete:Option<ReferenceAction>,
104
+
pubon_update:Option<ReferenceAction>,
105
+
}
106
+
```
107
+
108
+
### Migration Plan Validation
109
+
- Non-nullable columns added to existing tables require either a `default` value or a `fill_with` backfill expression
110
+
- Schemas are validated for constraint consistency before diffing
111
+
- The planner validates that column/table names follow the configured naming case
112
+
113
+
### SQL Generation Target
114
+
All SQL generation currently targets **PostgreSQL only**. When modifying the query builder, ensure PostgreSQL compatibility.
115
+
116
+
### JSON Schema Generation
117
+
The `vespertide-schema-gen` crate uses `schemars` to generate JSON Schemas from the Rust types. After modifying core data structures, regenerate schemas with:
118
+
```bash
119
+
cargo run -p vespertide-schema-gen -- --out schemas
120
+
```
121
+
122
+
Schema base URL can be overridden via `VESP_SCHEMA_BASE_URL` environment variable.
123
+
124
+
## Testing Patterns
125
+
126
+
- Tests use helper functions like `col()` and `table()` to reduce boilerplate
127
+
- Use `rstest` for parameterized tests (common in planner/query crates)
128
+
- Use `serial_test::serial` for tests that modify the filesystem or working directory
129
+
- Snapshot testing with `insta` is used in the exporter crate
130
+
131
+
## Limitations
132
+
133
+
- YAML loading is not implemented (templates can be generated but not parsed)
134
+
- Runtime migration executor (`run_migrations`) in `vespertide-macro` is not implemented
0 commit comments