prax_cli/
cli.rs

1//! CLI argument definitions using clap.
2
3use clap::{Args, Parser, Subcommand, ValueEnum};
4use std::path::PathBuf;
5
6/// Prax CLI - A modern ORM for Rust
7#[derive(Parser, Debug)]
8#[command(name = "prax")]
9#[command(author = "Pegasus Heavy Industries LLC")]
10#[command(version)]
11#[command(about = "Prax CLI - A modern ORM for Rust", long_about = None)]
12#[command(propagate_version = true)]
13pub struct Cli {
14    /// Subcommand to execute
15    #[command(subcommand)]
16    pub command: Command,
17}
18
19/// Available CLI commands
20#[derive(Subcommand, Debug)]
21pub enum Command {
22    /// Initialize a new Prax project
23    Init(InitArgs),
24
25    /// Generate Rust client code from schema
26    Generate(GenerateArgs),
27
28    /// Schema validation and formatting
29    Validate(ValidateArgs),
30
31    /// Format schema file
32    Format(FormatArgs),
33
34    /// Database migration commands
35    Migrate(MigrateArgs),
36
37    /// Direct database operations
38    Db(DbArgs),
39
40    /// Display version information
41    Version,
42}
43
44// =============================================================================
45// Init Command
46// =============================================================================
47
48/// Arguments for the `init` command
49#[derive(Args, Debug)]
50pub struct InitArgs {
51    /// Path to initialize the project (defaults to current directory)
52    #[arg(default_value = ".")]
53    pub path: PathBuf,
54
55    /// Database provider to use
56    #[arg(short, long, default_value = "postgresql")]
57    pub provider: DatabaseProvider,
58
59    /// Database connection URL
60    #[arg(short, long)]
61    pub url: Option<String>,
62
63    /// Skip generating example schema
64    #[arg(long)]
65    pub no_example: bool,
66
67    /// Accept all defaults without prompting
68    #[arg(short, long)]
69    pub yes: bool,
70}
71
72/// Supported database providers
73#[derive(ValueEnum, Debug, Clone, Copy, Default)]
74pub enum DatabaseProvider {
75    #[default]
76    Postgresql,
77    Mysql,
78    Sqlite,
79}
80
81impl std::fmt::Display for DatabaseProvider {
82    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
83        match self {
84            DatabaseProvider::Postgresql => write!(f, "postgresql"),
85            DatabaseProvider::Mysql => write!(f, "mysql"),
86            DatabaseProvider::Sqlite => write!(f, "sqlite"),
87        }
88    }
89}
90
91// =============================================================================
92// Generate Command
93// =============================================================================
94
95/// Arguments for the `generate` command
96#[derive(Args, Debug)]
97pub struct GenerateArgs {
98    /// Path to schema file
99    #[arg(short, long)]
100    pub schema: Option<PathBuf>,
101
102    /// Output directory for generated code
103    #[arg(short, long)]
104    pub output: Option<PathBuf>,
105
106    /// Features to generate (e.g., serde, graphql)
107    #[arg(short, long, value_delimiter = ',')]
108    pub features: Vec<String>,
109
110    /// Watch for schema changes and regenerate
111    #[arg(short, long)]
112    pub watch: bool,
113}
114
115// =============================================================================
116// Validate Command
117// =============================================================================
118
119/// Arguments for the `validate` command
120#[derive(Args, Debug)]
121pub struct ValidateArgs {
122    /// Path to schema file
123    #[arg(short, long)]
124    pub schema: Option<PathBuf>,
125}
126
127// =============================================================================
128// Format Command
129// =============================================================================
130
131/// Arguments for the `format` command
132#[derive(Args, Debug)]
133pub struct FormatArgs {
134    /// Path to schema file
135    #[arg(short, long)]
136    pub schema: Option<PathBuf>,
137
138    /// Check formatting without writing changes
139    #[arg(short, long)]
140    pub check: bool,
141}
142
143// =============================================================================
144// Migrate Command
145// =============================================================================
146
147/// Arguments for the `migrate` command
148#[derive(Args, Debug)]
149pub struct MigrateArgs {
150    #[command(subcommand)]
151    pub command: MigrateSubcommand,
152}
153
154/// Migrate subcommands
155#[derive(Subcommand, Debug)]
156pub enum MigrateSubcommand {
157    /// Create and apply migrations during development
158    Dev(MigrateDevArgs),
159
160    /// Deploy pending migrations to production
161    Deploy,
162
163    /// Reset database and re-apply all migrations
164    Reset(MigrateResetArgs),
165
166    /// Show migration status
167    Status,
168
169    /// Resolve migration issues
170    Resolve(MigrateResolveArgs),
171
172    /// Generate migration diff without applying
173    Diff(MigrateDiffArgs),
174}
175
176/// Arguments for `migrate dev`
177#[derive(Args, Debug)]
178pub struct MigrateDevArgs {
179    /// Name for the migration
180    #[arg(short, long)]
181    pub name: Option<String>,
182
183    /// Create migration without applying
184    #[arg(long)]
185    pub create_only: bool,
186
187    /// Skip seed after migration
188    #[arg(long)]
189    pub skip_seed: bool,
190
191    /// Path to schema file
192    #[arg(short, long)]
193    pub schema: Option<PathBuf>,
194}
195
196/// Arguments for `migrate reset`
197#[derive(Args, Debug)]
198pub struct MigrateResetArgs {
199    /// Skip confirmation prompt
200    #[arg(short, long)]
201    pub force: bool,
202
203    /// Run seed after reset
204    #[arg(long)]
205    pub seed: bool,
206
207    /// Skip applying migrations (just reset)
208    #[arg(long)]
209    pub skip_migrations: bool,
210}
211
212/// Arguments for `migrate resolve`
213#[derive(Args, Debug)]
214pub struct MigrateResolveArgs {
215    /// Name of the migration to resolve
216    pub migration: String,
217
218    /// Mark migration as applied
219    #[arg(long)]
220    pub applied: bool,
221
222    /// Mark migration as rolled back
223    #[arg(long)]
224    pub rolled_back: bool,
225}
226
227/// Arguments for `migrate diff`
228#[derive(Args, Debug)]
229pub struct MigrateDiffArgs {
230    /// Path to schema file
231    #[arg(short, long)]
232    pub schema: Option<PathBuf>,
233
234    /// Output path for generated SQL
235    #[arg(short, long)]
236    pub output: Option<PathBuf>,
237
238    /// Compare against a specific migration
239    #[arg(long)]
240    pub from_migration: Option<String>,
241}
242
243// =============================================================================
244// Db Command
245// =============================================================================
246
247/// Arguments for the `db` command
248#[derive(Args, Debug)]
249pub struct DbArgs {
250    #[command(subcommand)]
251    pub command: DbSubcommand,
252}
253
254/// Db subcommands
255#[derive(Subcommand, Debug)]
256pub enum DbSubcommand {
257    /// Push schema to database without migrations
258    Push(DbPushArgs),
259
260    /// Introspect database and generate schema
261    Pull(DbPullArgs),
262
263    /// Seed database with initial data
264    Seed(DbSeedArgs),
265
266    /// Execute raw SQL
267    Execute(DbExecuteArgs),
268}
269
270/// Arguments for `db push`
271#[derive(Args, Debug)]
272pub struct DbPushArgs {
273    /// Path to schema file
274    #[arg(short, long)]
275    pub schema: Option<PathBuf>,
276
277    /// Accept data loss from destructive changes
278    #[arg(long)]
279    pub accept_data_loss: bool,
280
281    /// Skip confirmation prompts
282    #[arg(short, long)]
283    pub force: bool,
284
285    /// Reset database before push
286    #[arg(long)]
287    pub reset: bool,
288}
289
290/// Arguments for `db pull`
291#[derive(Args, Debug)]
292pub struct DbPullArgs {
293    /// Output path for generated schema
294    #[arg(short, long)]
295    pub output: Option<PathBuf>,
296
297    /// Overwrite existing schema without prompting
298    #[arg(short, long)]
299    pub force: bool,
300
301    /// Include views in introspection
302    #[arg(long)]
303    pub include_views: bool,
304}
305
306/// Arguments for `db seed`
307#[derive(Args, Debug)]
308pub struct DbSeedArgs {
309    /// Path to seed file
310    #[arg(short, long)]
311    pub seed_file: Option<PathBuf>,
312
313    /// Reset database before seeding
314    #[arg(long)]
315    pub reset: bool,
316
317    /// Environment to run seed for (development, staging, production)
318    #[arg(short, long, default_value = "development")]
319    pub environment: String,
320
321    /// Force seeding even if environment config says not to
322    #[arg(short, long)]
323    pub force: bool,
324}
325
326/// Arguments for `db execute`
327#[derive(Args, Debug)]
328pub struct DbExecuteArgs {
329    /// SQL to execute
330    #[arg(short, long)]
331    pub sql: Option<String>,
332
333    /// Path to SQL file
334    #[arg(short, long)]
335    pub file: Option<PathBuf>,
336
337    /// Read SQL from stdin
338    #[arg(long)]
339    pub stdin: bool,
340
341    /// Skip confirmation prompt
342    #[arg(short = 'y', long)]
343    pub force: bool,
344}