Skip to main content

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}