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
205/// Arguments for `migrate reset`
206#[derive(Args, Debug)]
207pub struct MigrateResetArgs {
208    /// Skip confirmation prompt
209    #[arg(short, long)]
210    pub force: bool,
211
212    /// Run seed after reset
213    #[arg(long)]
214    pub seed: bool,
215
216    /// Skip applying migrations (just reset)
217    #[arg(long)]
218    pub skip_migrations: bool,
219}
220
221/// Arguments for `migrate resolve`
222#[derive(Args, Debug)]
223pub struct MigrateResolveArgs {
224    /// Name of the migration to resolve
225    pub migration: String,
226
227    /// Mark migration as applied
228    #[arg(long)]
229    pub applied: bool,
230
231    /// Mark migration as rolled back
232    #[arg(long)]
233    pub rolled_back: bool,
234}
235
236/// Arguments for `migrate diff`
237#[derive(Args, Debug)]
238pub struct MigrateDiffArgs {
239    /// Path to schema file
240    #[arg(short, long)]
241    pub schema: Option<PathBuf>,
242
243    /// Output path for generated SQL
244    #[arg(short, long)]
245    pub output: Option<PathBuf>,
246
247    /// Compare against a specific migration
248    #[arg(long)]
249    pub from_migration: Option<String>,
250}
251
252/// Arguments for `migrate rollback`
253#[derive(Args, Debug)]
254pub struct MigrateRollbackArgs {
255    /// Reason for rollback
256    #[arg(long)]
257    pub reason: Option<String>,
258
259    /// User performing the rollback
260    #[arg(long)]
261    pub user: Option<String>,
262
263    /// Rollback to a specific migration
264    #[arg(long)]
265    pub to: Option<String>,
266}
267
268/// Arguments for `migrate history`
269#[derive(Args, Debug)]
270pub struct MigrateHistoryArgs {
271    /// Show history for a specific migration
272    #[arg(long)]
273    pub migration: Option<String>,
274}
275
276// =============================================================================
277// Db Command
278// =============================================================================
279
280/// Arguments for the `db` command
281#[derive(Args, Debug)]
282pub struct DbArgs {
283    #[command(subcommand)]
284    pub command: DbSubcommand,
285}
286
287/// Db subcommands
288#[derive(Subcommand, Debug)]
289pub enum DbSubcommand {
290    /// Push schema to database without migrations
291    Push(DbPushArgs),
292
293    /// Introspect database and generate schema
294    Pull(DbPullArgs),
295
296    /// Seed database with initial data
297    Seed(DbSeedArgs),
298
299    /// Execute raw SQL
300    Execute(DbExecuteArgs),
301}
302
303/// Arguments for `db push`
304#[derive(Args, Debug)]
305pub struct DbPushArgs {
306    /// Path to schema file
307    #[arg(short, long)]
308    pub schema: Option<PathBuf>,
309
310    /// Accept data loss from destructive changes
311    #[arg(long)]
312    pub accept_data_loss: bool,
313
314    /// Skip confirmation prompts
315    #[arg(short, long)]
316    pub force: bool,
317
318    /// Reset database before push
319    #[arg(long)]
320    pub reset: bool,
321}
322
323/// Arguments for `db pull`
324#[derive(Args, Debug)]
325pub struct DbPullArgs {
326    /// Output path for generated schema
327    #[arg(short, long)]
328    pub output: Option<PathBuf>,
329
330    /// Overwrite existing schema without prompting
331    #[arg(short, long)]
332    pub force: bool,
333
334    /// Include views in introspection
335    #[arg(long)]
336    pub include_views: bool,
337
338    /// Include materialized views in introspection
339    #[arg(long)]
340    pub include_materialized_views: bool,
341
342    /// Schema/namespace to introspect (default: public for PostgreSQL, dbo for MSSQL)
343    #[arg(long)]
344    pub schema: Option<String>,
345
346    /// Filter tables by pattern (glob-style, e.g., "user*")
347    #[arg(long)]
348    pub tables: Option<String>,
349
350    /// Exclude tables by pattern (glob-style, e.g., "_prisma*")
351    #[arg(long)]
352    pub exclude: Option<String>,
353
354    /// Print schema to stdout instead of writing to file
355    #[arg(long)]
356    pub print: bool,
357
358    /// Output format
359    #[arg(long, default_value = "prax")]
360    pub format: OutputFormat,
361
362    /// Number of documents to sample for MongoDB schema inference
363    #[arg(long, default_value = "100")]
364    pub sample_size: usize,
365
366    /// Include column comments in schema
367    #[arg(long)]
368    pub comments: bool,
369}
370
371/// Output format for schema introspection
372#[derive(ValueEnum, Debug, Clone, Copy, Default)]
373pub enum OutputFormat {
374    /// Prax schema format (.prax)
375    #[default]
376    Prax,
377    /// JSON format
378    Json,
379    /// SQL DDL format
380    Sql,
381}
382
383/// Arguments for `db seed`
384#[derive(Args, Debug)]
385pub struct DbSeedArgs {
386    /// Path to seed file
387    #[arg(short, long)]
388    pub seed_file: Option<PathBuf>,
389
390    /// Reset database before seeding
391    #[arg(long)]
392    pub reset: bool,
393
394    /// Environment to run seed for (development, staging, production)
395    #[arg(short, long, default_value = "development")]
396    pub environment: String,
397
398    /// Force seeding even if environment config says not to
399    #[arg(short, long)]
400    pub force: bool,
401}
402
403/// Arguments for `db execute`
404#[derive(Args, Debug)]
405pub struct DbExecuteArgs {
406    /// SQL to execute
407    #[arg(short, long)]
408    pub sql: Option<String>,
409
410    /// Path to SQL file
411    #[arg(short, long)]
412    pub file: Option<PathBuf>,
413
414    /// Read SQL from stdin
415    #[arg(long)]
416    pub stdin: bool,
417
418    /// Skip confirmation prompt
419    #[arg(short = 'y', long)]
420    pub force: bool,
421}
422
423// =============================================================================
424// Import Command
425// =============================================================================
426
427/// Arguments for the `import` command
428#[derive(Args, Debug)]
429pub struct ImportArgs {
430    /// Source ORM to import from
431    #[arg(long, value_enum)]
432    pub from: ImportSource,
433
434    /// Input schema file path
435    #[arg(short, long)]
436    pub input: PathBuf,
437
438    /// Output Prax schema file path
439    #[arg(short, long)]
440    pub output: Option<PathBuf>,
441
442    /// Database provider for the imported schema
443    #[arg(short = 'P', long)]
444    pub provider: Option<DatabaseProvider>,
445
446    /// Database connection URL for the imported schema
447    #[arg(short, long)]
448    pub url: Option<String>,
449
450    /// Print to stdout instead of writing to file
451    #[arg(long)]
452    pub print: bool,
453
454    /// Overwrite existing output file without prompting
455    #[arg(short, long)]
456    pub force: bool,
457}
458
459/// Source ORM for import
460#[derive(ValueEnum, Debug, Clone, Copy, PartialEq, Eq)]
461pub enum ImportSource {
462    /// Prisma schema (.prisma files)
463    Prisma,
464    /// Diesel schema (schema.rs files with table! macros)
465    Diesel,
466    /// SeaORM entity (entity files with DeriveEntityModel)
467    SeaOrm,
468}