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