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 = "Joseph R. Quinn")]
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 /// Import schema from Prisma or Diesel
41 Import(ImportArgs),
42
43 /// Display version information
44 Version,
45}
46
47// =============================================================================
48// Init Command
49// =============================================================================
50
51/// Arguments for the `init` command
52#[derive(Args, Debug)]
53pub struct InitArgs {
54 /// Path to initialize the project (defaults to current directory)
55 #[arg(default_value = ".")]
56 pub path: PathBuf,
57
58 /// Database provider to use
59 #[arg(short, long, default_value = "postgresql")]
60 pub provider: DatabaseProvider,
61
62 /// Database connection URL
63 #[arg(short, long)]
64 pub url: Option<String>,
65
66 /// Skip generating example schema
67 #[arg(long)]
68 pub no_example: bool,
69
70 /// Accept all defaults without prompting
71 #[arg(short, long)]
72 pub yes: bool,
73}
74
75/// Supported database providers
76#[derive(ValueEnum, Debug, Clone, Copy, Default)]
77pub enum DatabaseProvider {
78 #[default]
79 Postgresql,
80 Mysql,
81 Sqlite,
82}
83
84impl std::fmt::Display for DatabaseProvider {
85 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
86 match self {
87 DatabaseProvider::Postgresql => write!(f, "postgresql"),
88 DatabaseProvider::Mysql => write!(f, "mysql"),
89 DatabaseProvider::Sqlite => write!(f, "sqlite"),
90 }
91 }
92}
93
94// =============================================================================
95// Generate Command
96// =============================================================================
97
98/// Arguments for the `generate` command
99#[derive(Args, Debug)]
100pub struct GenerateArgs {
101 /// Path to schema file
102 #[arg(short, long)]
103 pub schema: Option<PathBuf>,
104
105 /// Output directory for generated code
106 #[arg(short, long)]
107 pub output: Option<PathBuf>,
108
109 /// Features to generate (e.g., serde, graphql)
110 #[arg(short, long, value_delimiter = ',')]
111 pub features: Vec<String>,
112
113 /// Watch for schema changes and regenerate (not yet implemented — runs once)
114 #[arg(short, long)]
115 pub watch: bool,
116}
117
118// =============================================================================
119// Validate Command
120// =============================================================================
121
122/// Arguments for the `validate` command
123#[derive(Args, Debug)]
124pub struct ValidateArgs {
125 /// Path to schema file
126 #[arg(short, long)]
127 pub schema: Option<PathBuf>,
128}
129
130// =============================================================================
131// Format Command
132// =============================================================================
133
134/// Arguments for the `format` command.
135///
136/// Formatting is syntactic-only and per-file: it does not validate
137/// relations or types. Use `prax validate` to type-check.
138#[derive(Args, Debug)]
139pub struct FormatArgs {
140 /// Path to schema file
141 #[arg(short, long)]
142 pub schema: Option<PathBuf>,
143
144 /// Check formatting without writing changes (does not validate)
145 #[arg(short, long)]
146 pub check: bool,
147}
148
149// =============================================================================
150// Migrate Command
151// =============================================================================
152
153/// Arguments for the `migrate` command
154#[derive(Args, Debug)]
155pub struct MigrateArgs {
156 #[command(subcommand)]
157 pub command: MigrateSubcommand,
158}
159
160/// Migrate subcommands
161#[derive(Subcommand, Debug)]
162pub enum MigrateSubcommand {
163 /// Create and apply migrations during development
164 Dev(MigrateDevArgs),
165
166 /// Deploy pending migrations to production
167 Deploy,
168
169 /// Reset database and re-apply all migrations
170 Reset(MigrateResetArgs),
171
172 /// Show migration status
173 Status,
174
175 /// Resolve migration issues
176 Resolve(MigrateResolveArgs),
177
178 /// Generate migration diff without applying
179 Diff(MigrateDiffArgs),
180
181 /// Rollback the last applied migration
182 Rollback(MigrateRollbackArgs),
183
184 /// View migration history
185 History(MigrateHistoryArgs),
186}
187
188/// Arguments for `migrate dev`
189#[derive(Args, Debug)]
190pub struct MigrateDevArgs {
191 /// Name for the migration
192 #[arg(short, long)]
193 pub name: Option<String>,
194
195 /// Create migration without applying
196 #[arg(long)]
197 pub create_only: bool,
198
199 /// Skip seed after migration
200 #[arg(long)]
201 pub skip_seed: bool,
202
203 /// Path to schema file
204 #[arg(short, long)]
205 pub schema: Option<PathBuf>,
206
207 /// Emit destructive statements (DROP TABLE/COLUMN/TYPE). Default is
208 /// additive-only: drops are omitted so a stale schema never silently
209 /// destroys data.
210 #[arg(long)]
211 pub allow_destructive: bool,
212}
213
214/// Arguments for `migrate reset`
215#[derive(Args, Debug)]
216pub struct MigrateResetArgs {
217 /// Skip confirmation prompt
218 #[arg(short, long)]
219 pub force: bool,
220
221 /// Run seed after reset
222 #[arg(long)]
223 pub seed: bool,
224
225 /// Skip applying migrations (just reset)
226 #[arg(long)]
227 pub skip_migrations: bool,
228}
229
230/// Arguments for `migrate resolve`
231#[derive(Args, Debug)]
232pub struct MigrateResolveArgs {
233 /// Name of the migration to resolve
234 pub migration: String,
235
236 /// Mark migration as applied
237 #[arg(long)]
238 pub applied: bool,
239
240 /// Mark migration as rolled back
241 #[arg(long)]
242 pub rolled_back: bool,
243}
244
245/// Arguments for `migrate diff`
246#[derive(Args, Debug)]
247pub struct MigrateDiffArgs {
248 /// Path to schema file
249 #[arg(short, long)]
250 pub schema: Option<PathBuf>,
251
252 /// Output path for generated SQL
253 #[arg(short, long)]
254 pub output: Option<PathBuf>,
255
256 /// Compare against a specific migration
257 #[arg(long)]
258 pub from_migration: Option<String>,
259
260 /// Emit destructive statements (DROP TABLE/COLUMN/TYPE). Default is
261 /// additive-only: drops are omitted.
262 #[arg(long)]
263 pub allow_destructive: bool,
264}
265
266/// Arguments for `migrate rollback`
267#[derive(Args, Debug)]
268pub struct MigrateRollbackArgs {
269 /// Reason for rollback
270 #[arg(long)]
271 pub reason: Option<String>,
272
273 /// User performing the rollback
274 #[arg(long)]
275 pub user: Option<String>,
276
277 /// Rollback to a specific migration
278 #[arg(long)]
279 pub to: Option<String>,
280}
281
282/// Arguments for `migrate history`
283#[derive(Args, Debug)]
284pub struct MigrateHistoryArgs {
285 /// Show history for a specific migration
286 #[arg(long)]
287 pub migration: Option<String>,
288}
289
290// =============================================================================
291// Db Command
292// =============================================================================
293
294/// Arguments for the `db` command
295#[derive(Args, Debug)]
296pub struct DbArgs {
297 #[command(subcommand)]
298 pub command: DbSubcommand,
299}
300
301/// Db subcommands
302#[derive(Subcommand, Debug)]
303pub enum DbSubcommand {
304 /// Push schema to database without migrations
305 Push(DbPushArgs),
306
307 /// Introspect database and generate schema
308 Pull(DbPullArgs),
309
310 /// Seed database with initial data
311 Seed(DbSeedArgs),
312
313 /// Execute raw SQL
314 Execute(DbExecuteArgs),
315}
316
317/// Arguments for `db push`
318#[derive(Args, Debug)]
319pub struct DbPushArgs {
320 /// Path to schema file
321 #[arg(short, long)]
322 pub schema: Option<PathBuf>,
323
324 /// Accept data loss from destructive changes
325 #[arg(long)]
326 pub accept_data_loss: bool,
327
328 /// Skip confirmation prompts
329 #[arg(short, long)]
330 pub force: bool,
331
332 /// Reset database before push
333 #[arg(long)]
334 pub reset: bool,
335}
336
337/// Arguments for `db pull`
338#[derive(Args, Debug)]
339pub struct DbPullArgs {
340 /// Output path for generated schema
341 #[arg(short, long)]
342 pub output: Option<PathBuf>,
343
344 /// Overwrite existing schema without prompting
345 #[arg(short, long)]
346 pub force: bool,
347
348 /// Include views in introspection
349 #[arg(long)]
350 pub include_views: bool,
351
352 /// Include materialized views in introspection
353 #[arg(long)]
354 pub include_materialized_views: bool,
355
356 /// Schema/namespace to introspect (default: public for PostgreSQL, dbo for MSSQL)
357 #[arg(long)]
358 pub schema: Option<String>,
359
360 /// Filter tables by pattern (glob-style, e.g., "user*")
361 #[arg(long)]
362 pub tables: Option<String>,
363
364 /// Exclude tables by pattern (glob-style, e.g., "_prisma*")
365 #[arg(long)]
366 pub exclude: Option<String>,
367
368 /// Print schema to stdout instead of writing to file
369 #[arg(long)]
370 pub print: bool,
371
372 /// Output format
373 #[arg(long, default_value = "prax")]
374 pub format: OutputFormat,
375
376 /// Number of documents to sample for MongoDB schema inference
377 #[arg(long, default_value = "100")]
378 pub sample_size: usize,
379
380 /// Include column comments in schema
381 #[arg(long)]
382 pub comments: bool,
383}
384
385/// Output format for schema introspection
386#[derive(ValueEnum, Debug, Clone, Copy, Default)]
387pub enum OutputFormat {
388 /// Prax schema format (.prax)
389 #[default]
390 Prax,
391 /// JSON format
392 Json,
393 /// SQL DDL format
394 Sql,
395}
396
397/// Arguments for `db seed`
398#[derive(Args, Debug)]
399pub struct DbSeedArgs {
400 /// Path to seed file
401 #[arg(short, long)]
402 pub seed_file: Option<PathBuf>,
403
404 /// Reset database before seeding
405 #[arg(long)]
406 pub reset: bool,
407
408 /// Environment to run seed for (development, staging, production)
409 #[arg(short, long, default_value = "development")]
410 pub environment: String,
411
412 /// Force seeding even if environment config says not to
413 #[arg(short, long)]
414 pub force: bool,
415}
416
417/// Arguments for `db execute`
418#[derive(Args, Debug)]
419pub struct DbExecuteArgs {
420 /// SQL to execute
421 #[arg(short, long)]
422 pub sql: Option<String>,
423
424 /// Path to SQL file
425 #[arg(short, long)]
426 pub file: Option<PathBuf>,
427
428 /// Read SQL from stdin
429 #[arg(long)]
430 pub stdin: bool,
431
432 /// Skip confirmation prompt
433 #[arg(short = 'y', long)]
434 pub force: bool,
435}
436
437// =============================================================================
438// Import Command
439// =============================================================================
440
441/// Arguments for the `import` command
442#[derive(Args, Debug)]
443pub struct ImportArgs {
444 /// Source ORM to import from
445 #[arg(long, value_enum)]
446 pub from: ImportSource,
447
448 /// Input schema file path
449 #[arg(short, long)]
450 pub input: PathBuf,
451
452 /// Output Prax schema file path
453 #[arg(short, long)]
454 pub output: Option<PathBuf>,
455
456 /// Database provider for the imported schema
457 #[arg(short = 'P', long)]
458 pub provider: Option<DatabaseProvider>,
459
460 /// Database connection URL for the imported schema
461 #[arg(short, long)]
462 pub url: Option<String>,
463
464 /// Print to stdout instead of writing to file
465 #[arg(long)]
466 pub print: bool,
467
468 /// Overwrite existing output file without prompting
469 #[arg(short, long)]
470 pub force: bool,
471}
472
473/// Source ORM for import
474#[derive(ValueEnum, Debug, Clone, Copy, PartialEq, Eq)]
475pub enum ImportSource {
476 /// Prisma schema (.prisma files)
477 Prisma,
478 /// Diesel schema (schema.rs files with table! macros)
479 Diesel,
480 /// SeaORM entity (entity files with DeriveEntityModel)
481 SeaOrm,
482}