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#[derive(Args, Debug)]
136pub struct FormatArgs {
137 /// Path to schema file
138 #[arg(short, long)]
139 pub schema: Option<PathBuf>,
140
141 /// Check formatting without writing changes
142 #[arg(short, long)]
143 pub check: bool,
144}
145
146// =============================================================================
147// Migrate Command
148// =============================================================================
149
150/// Arguments for the `migrate` command
151#[derive(Args, Debug)]
152pub struct MigrateArgs {
153 #[command(subcommand)]
154 pub command: MigrateSubcommand,
155}
156
157/// Migrate subcommands
158#[derive(Subcommand, Debug)]
159pub enum MigrateSubcommand {
160 /// Create and apply migrations during development
161 Dev(MigrateDevArgs),
162
163 /// Deploy pending migrations to production
164 Deploy,
165
166 /// Reset database and re-apply all migrations
167 Reset(MigrateResetArgs),
168
169 /// Show migration status
170 Status,
171
172 /// Resolve migration issues
173 Resolve(MigrateResolveArgs),
174
175 /// Generate migration diff without applying
176 Diff(MigrateDiffArgs),
177
178 /// Rollback the last applied migration
179 Rollback(MigrateRollbackArgs),
180
181 /// View migration history
182 History(MigrateHistoryArgs),
183}
184
185/// Arguments for `migrate dev`
186#[derive(Args, Debug)]
187pub struct MigrateDevArgs {
188 /// Name for the migration
189 #[arg(short, long)]
190 pub name: Option<String>,
191
192 /// Create migration without applying
193 #[arg(long)]
194 pub create_only: bool,
195
196 /// Skip seed after migration
197 #[arg(long)]
198 pub skip_seed: bool,
199
200 /// Path to schema file
201 #[arg(short, long)]
202 pub schema: Option<PathBuf>,
203
204 /// Emit destructive statements (DROP TABLE/COLUMN/TYPE). Default is
205 /// additive-only: drops are omitted so a stale schema never silently
206 /// destroys data.
207 #[arg(long)]
208 pub allow_destructive: bool,
209}
210
211/// Arguments for `migrate reset`
212#[derive(Args, Debug)]
213pub struct MigrateResetArgs {
214 /// Skip confirmation prompt
215 #[arg(short, long)]
216 pub force: bool,
217
218 /// Run seed after reset
219 #[arg(long)]
220 pub seed: bool,
221
222 /// Skip applying migrations (just reset)
223 #[arg(long)]
224 pub skip_migrations: bool,
225}
226
227/// Arguments for `migrate resolve`
228#[derive(Args, Debug)]
229pub struct MigrateResolveArgs {
230 /// Name of the migration to resolve
231 pub migration: String,
232
233 /// Mark migration as applied
234 #[arg(long)]
235 pub applied: bool,
236
237 /// Mark migration as rolled back
238 #[arg(long)]
239 pub rolled_back: bool,
240}
241
242/// Arguments for `migrate diff`
243#[derive(Args, Debug)]
244pub struct MigrateDiffArgs {
245 /// Path to schema file
246 #[arg(short, long)]
247 pub schema: Option<PathBuf>,
248
249 /// Output path for generated SQL
250 #[arg(short, long)]
251 pub output: Option<PathBuf>,
252
253 /// Compare against a specific migration
254 #[arg(long)]
255 pub from_migration: Option<String>,
256
257 /// Emit destructive statements (DROP TABLE/COLUMN/TYPE). Default is
258 /// additive-only: drops are omitted.
259 #[arg(long)]
260 pub allow_destructive: bool,
261}
262
263/// Arguments for `migrate rollback`
264#[derive(Args, Debug)]
265pub struct MigrateRollbackArgs {
266 /// Reason for rollback
267 #[arg(long)]
268 pub reason: Option<String>,
269
270 /// User performing the rollback
271 #[arg(long)]
272 pub user: Option<String>,
273
274 /// Rollback to a specific migration
275 #[arg(long)]
276 pub to: Option<String>,
277}
278
279/// Arguments for `migrate history`
280#[derive(Args, Debug)]
281pub struct MigrateHistoryArgs {
282 /// Show history for a specific migration
283 #[arg(long)]
284 pub migration: Option<String>,
285}
286
287// =============================================================================
288// Db Command
289// =============================================================================
290
291/// Arguments for the `db` command
292#[derive(Args, Debug)]
293pub struct DbArgs {
294 #[command(subcommand)]
295 pub command: DbSubcommand,
296}
297
298/// Db subcommands
299#[derive(Subcommand, Debug)]
300pub enum DbSubcommand {
301 /// Push schema to database without migrations
302 Push(DbPushArgs),
303
304 /// Introspect database and generate schema
305 Pull(DbPullArgs),
306
307 /// Seed database with initial data
308 Seed(DbSeedArgs),
309
310 /// Execute raw SQL
311 Execute(DbExecuteArgs),
312}
313
314/// Arguments for `db push`
315#[derive(Args, Debug)]
316pub struct DbPushArgs {
317 /// Path to schema file
318 #[arg(short, long)]
319 pub schema: Option<PathBuf>,
320
321 /// Accept data loss from destructive changes
322 #[arg(long)]
323 pub accept_data_loss: bool,
324
325 /// Skip confirmation prompts
326 #[arg(short, long)]
327 pub force: bool,
328
329 /// Reset database before push
330 #[arg(long)]
331 pub reset: bool,
332}
333
334/// Arguments for `db pull`
335#[derive(Args, Debug)]
336pub struct DbPullArgs {
337 /// Output path for generated schema
338 #[arg(short, long)]
339 pub output: Option<PathBuf>,
340
341 /// Overwrite existing schema without prompting
342 #[arg(short, long)]
343 pub force: bool,
344
345 /// Include views in introspection
346 #[arg(long)]
347 pub include_views: bool,
348
349 /// Include materialized views in introspection
350 #[arg(long)]
351 pub include_materialized_views: bool,
352
353 /// Schema/namespace to introspect (default: public for PostgreSQL, dbo for MSSQL)
354 #[arg(long)]
355 pub schema: Option<String>,
356
357 /// Filter tables by pattern (glob-style, e.g., "user*")
358 #[arg(long)]
359 pub tables: Option<String>,
360
361 /// Exclude tables by pattern (glob-style, e.g., "_prisma*")
362 #[arg(long)]
363 pub exclude: Option<String>,
364
365 /// Print schema to stdout instead of writing to file
366 #[arg(long)]
367 pub print: bool,
368
369 /// Output format
370 #[arg(long, default_value = "prax")]
371 pub format: OutputFormat,
372
373 /// Number of documents to sample for MongoDB schema inference
374 #[arg(long, default_value = "100")]
375 pub sample_size: usize,
376
377 /// Include column comments in schema
378 #[arg(long)]
379 pub comments: bool,
380}
381
382/// Output format for schema introspection
383#[derive(ValueEnum, Debug, Clone, Copy, Default)]
384pub enum OutputFormat {
385 /// Prax schema format (.prax)
386 #[default]
387 Prax,
388 /// JSON format
389 Json,
390 /// SQL DDL format
391 Sql,
392}
393
394/// Arguments for `db seed`
395#[derive(Args, Debug)]
396pub struct DbSeedArgs {
397 /// Path to seed file
398 #[arg(short, long)]
399 pub seed_file: Option<PathBuf>,
400
401 /// Reset database before seeding
402 #[arg(long)]
403 pub reset: bool,
404
405 /// Environment to run seed for (development, staging, production)
406 #[arg(short, long, default_value = "development")]
407 pub environment: String,
408
409 /// Force seeding even if environment config says not to
410 #[arg(short, long)]
411 pub force: bool,
412}
413
414/// Arguments for `db execute`
415#[derive(Args, Debug)]
416pub struct DbExecuteArgs {
417 /// SQL to execute
418 #[arg(short, long)]
419 pub sql: Option<String>,
420
421 /// Path to SQL file
422 #[arg(short, long)]
423 pub file: Option<PathBuf>,
424
425 /// Read SQL from stdin
426 #[arg(long)]
427 pub stdin: bool,
428
429 /// Skip confirmation prompt
430 #[arg(short = 'y', long)]
431 pub force: bool,
432}
433
434// =============================================================================
435// Import Command
436// =============================================================================
437
438/// Arguments for the `import` command
439#[derive(Args, Debug)]
440pub struct ImportArgs {
441 /// Source ORM to import from
442 #[arg(long, value_enum)]
443 pub from: ImportSource,
444
445 /// Input schema file path
446 #[arg(short, long)]
447 pub input: PathBuf,
448
449 /// Output Prax schema file path
450 #[arg(short, long)]
451 pub output: Option<PathBuf>,
452
453 /// Database provider for the imported schema
454 #[arg(short = 'P', long)]
455 pub provider: Option<DatabaseProvider>,
456
457 /// Database connection URL for the imported schema
458 #[arg(short, long)]
459 pub url: Option<String>,
460
461 /// Print to stdout instead of writing to file
462 #[arg(long)]
463 pub print: bool,
464
465 /// Overwrite existing output file without prompting
466 #[arg(short, long)]
467 pub force: bool,
468}
469
470/// Source ORM for import
471#[derive(ValueEnum, Debug, Clone, Copy, PartialEq, Eq)]
472pub enum ImportSource {
473 /// Prisma schema (.prisma files)
474 Prisma,
475 /// Diesel schema (schema.rs files with table! macros)
476 Diesel,
477 /// SeaORM entity (entity files with DeriveEntityModel)
478 SeaOrm,
479}