1use serde::{Deserialize, Serialize};
4use std::collections::HashMap;
5use std::path::Path;
6
7use crate::error::{SchemaError, SchemaResult};
8
9#[derive(Debug, Clone, Default, Deserialize, Serialize)]
11#[serde(deny_unknown_fields)]
12pub struct PraxConfig {
13 #[serde(default)]
15 pub database: DatabaseConfig,
16
17 #[serde(default)]
19 pub schema: SchemaConfig,
20
21 #[serde(default)]
23 pub generator: GeneratorConfig,
24
25 #[serde(default)]
27 pub migrations: MigrationConfig,
28
29 #[serde(default)]
31 pub seed: SeedConfig,
32
33 #[serde(default)]
35 pub debug: DebugConfig,
36
37 #[serde(default)]
39 pub environments: HashMap<String, EnvironmentOverride>,
40}
41
42impl PraxConfig {
43 pub fn from_file(path: impl AsRef<Path>) -> SchemaResult<Self> {
45 let path = path.as_ref();
46 let content = std::fs::read_to_string(path).map_err(|e| SchemaError::IoError {
47 path: path.display().to_string(),
48 source: e,
49 })?;
50
51 Self::from_str(&content)
52 }
53
54 #[allow(clippy::should_implement_trait)]
56 pub fn from_str(content: &str) -> SchemaResult<Self> {
57 let expanded = expand_env_vars(content);
59
60 toml::from_str(&expanded).map_err(|e| SchemaError::TomlError { source: e })
61 }
62
63 pub fn database_url(&self) -> Option<&str> {
65 self.database.url.as_deref()
66 }
67
68 pub fn with_environment(mut self, env: &str) -> Self {
70 if let Some(overrides) = self.environments.remove(env) {
71 if let Some(db) = overrides.database {
72 if let Some(url) = db.url {
73 self.database.url = Some(url);
74 }
75 if let Some(pool) = db.pool {
76 self.database.pool = pool;
77 }
78 }
79 if let Some(debug) = overrides.debug {
80 if let Some(log_queries) = debug.log_queries {
81 self.debug.log_queries = log_queries;
82 }
83 if let Some(pretty_sql) = debug.pretty_sql {
84 self.debug.pretty_sql = pretty_sql;
85 }
86 if let Some(threshold) = debug.slow_query_threshold {
87 self.debug.slow_query_threshold = threshold;
88 }
89 }
90 }
91 self
92 }
93}
94
95#[derive(Debug, Clone, Deserialize, Serialize)]
97#[serde(deny_unknown_fields)]
98pub struct DatabaseConfig {
99 #[serde(default = "default_provider")]
101 pub provider: DatabaseProvider,
102
103 pub url: Option<String>,
105
106 #[serde(default)]
108 pub pool: PoolConfig,
109}
110
111impl Default for DatabaseConfig {
112 fn default() -> Self {
113 Self {
114 provider: DatabaseProvider::PostgreSql,
115 url: None,
116 pool: PoolConfig::default(),
117 }
118 }
119}
120
121fn default_provider() -> DatabaseProvider {
122 DatabaseProvider::PostgreSql
123}
124
125#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)]
127#[serde(rename_all = "lowercase")]
128pub enum DatabaseProvider {
129 #[serde(alias = "postgres")]
131 PostgreSql,
132 MySql,
134 #[serde(alias = "sqlite3")]
136 Sqlite,
137 #[serde(alias = "mongo")]
139 MongoDb,
140}
141
142impl DatabaseProvider {
143 pub fn as_str(&self) -> &'static str {
145 match self {
146 Self::PostgreSql => "postgresql",
147 Self::MySql => "mysql",
148 Self::Sqlite => "sqlite",
149 Self::MongoDb => "mongodb",
150 }
151 }
152}
153
154#[derive(Debug, Clone, Deserialize, Serialize)]
156#[serde(deny_unknown_fields)]
157pub struct PoolConfig {
158 #[serde(default = "default_min_connections")]
160 pub min_connections: u32,
161
162 #[serde(default = "default_max_connections")]
164 pub max_connections: u32,
165
166 #[serde(default = "default_connect_timeout")]
168 pub connect_timeout: String,
169
170 #[serde(default = "default_idle_timeout")]
172 pub idle_timeout: String,
173
174 #[serde(default = "default_max_lifetime")]
176 pub max_lifetime: String,
177}
178
179impl Default for PoolConfig {
180 fn default() -> Self {
181 Self {
182 min_connections: default_min_connections(),
183 max_connections: default_max_connections(),
184 connect_timeout: default_connect_timeout(),
185 idle_timeout: default_idle_timeout(),
186 max_lifetime: default_max_lifetime(),
187 }
188 }
189}
190
191fn default_min_connections() -> u32 {
192 2
193}
194fn default_max_connections() -> u32 {
195 10
196}
197fn default_connect_timeout() -> String {
198 "30s".to_string()
199}
200fn default_idle_timeout() -> String {
201 "10m".to_string()
202}
203fn default_max_lifetime() -> String {
204 "30m".to_string()
205}
206
207#[derive(Debug, Clone, Deserialize, Serialize)]
209#[serde(deny_unknown_fields)]
210pub struct SchemaConfig {
211 #[serde(default = "default_schema_path")]
213 pub path: String,
214}
215
216impl Default for SchemaConfig {
217 fn default() -> Self {
218 Self {
219 path: default_schema_path(),
220 }
221 }
222}
223
224fn default_schema_path() -> String {
225 "schema.prax".to_string()
226}
227
228#[derive(Debug, Clone, Default, Deserialize, Serialize)]
230#[serde(deny_unknown_fields)]
231pub struct GeneratorConfig {
232 #[serde(default)]
234 pub client: ClientGeneratorConfig,
235}
236
237#[derive(Debug, Clone, Deserialize, Serialize)]
239#[serde(deny_unknown_fields)]
240pub struct ClientGeneratorConfig {
241 #[serde(default = "default_output")]
243 pub output: String,
244
245 #[serde(default = "default_true")]
247 pub async_client: bool,
248
249 #[serde(default)]
251 pub tracing: bool,
252
253 #[serde(default)]
255 pub preview_features: Vec<String>,
256}
257
258impl Default for ClientGeneratorConfig {
259 fn default() -> Self {
260 Self {
261 output: default_output(),
262 async_client: true,
263 tracing: false,
264 preview_features: vec![],
265 }
266 }
267}
268
269fn default_output() -> String {
270 "./src/generated".to_string()
271}
272fn default_true() -> bool {
273 true
274}
275
276#[derive(Debug, Clone, Deserialize, Serialize)]
278#[serde(deny_unknown_fields)]
279pub struct MigrationConfig {
280 #[serde(default = "default_migrations_dir")]
282 pub directory: String,
283
284 #[serde(default)]
286 pub auto_migrate: bool,
287
288 #[serde(default = "default_migrations_table")]
290 pub table_name: String,
291}
292
293impl Default for MigrationConfig {
294 fn default() -> Self {
295 Self {
296 directory: default_migrations_dir(),
297 auto_migrate: false,
298 table_name: default_migrations_table(),
299 }
300 }
301}
302
303fn default_migrations_dir() -> String {
304 "./migrations".to_string()
305}
306fn default_migrations_table() -> String {
307 "_prax_migrations".to_string()
308}
309
310#[derive(Debug, Clone, Default, Deserialize, Serialize)]
312#[serde(deny_unknown_fields)]
313pub struct SeedConfig {
314 pub script: Option<String>,
316
317 #[serde(default)]
319 pub auto_seed: bool,
320
321 #[serde(default)]
323 pub environments: HashMap<String, bool>,
324}
325
326#[derive(Debug, Clone, Deserialize, Serialize)]
328#[serde(deny_unknown_fields)]
329pub struct DebugConfig {
330 #[serde(default)]
332 pub log_queries: bool,
333
334 #[serde(default = "default_true")]
336 pub pretty_sql: bool,
337
338 #[serde(default = "default_slow_query_threshold")]
340 pub slow_query_threshold: u64,
341}
342
343impl Default for DebugConfig {
344 fn default() -> Self {
345 Self {
346 log_queries: false,
347 pretty_sql: true,
348 slow_query_threshold: default_slow_query_threshold(),
349 }
350 }
351}
352
353fn default_slow_query_threshold() -> u64 {
354 1000
355}
356
357#[derive(Debug, Clone, Default, Deserialize, Serialize)]
359#[serde(deny_unknown_fields)]
360pub struct EnvironmentOverride {
361 pub database: Option<DatabaseOverride>,
363
364 pub debug: Option<DebugOverride>,
366}
367
368#[derive(Debug, Clone, Default, Deserialize, Serialize)]
370#[serde(deny_unknown_fields)]
371pub struct DatabaseOverride {
372 pub url: Option<String>,
374
375 pub pool: Option<PoolConfig>,
377}
378
379#[derive(Debug, Clone, Default, Deserialize, Serialize)]
381#[serde(deny_unknown_fields)]
382pub struct DebugOverride {
383 pub log_queries: Option<bool>,
385
386 pub pretty_sql: Option<bool>,
388
389 pub slow_query_threshold: Option<u64>,
391}
392
393fn expand_env_vars(content: &str) -> String {
395 let mut result = content.to_string();
396 let re = regex_lite::Regex::new(r"\$\{([^}]+)\}").unwrap();
397
398 for cap in re.captures_iter(content) {
399 let var_name = &cap[1];
400 let full_match = &cap[0];
401
402 if let Ok(value) = std::env::var(var_name) {
403 result = result.replace(full_match, &value);
404 }
405 }
406
407 result
408}
409
410#[cfg(test)]
411mod tests {
412 use super::*;
413
414 #[test]
417 fn test_default_config() {
418 let config = PraxConfig::default();
419 assert_eq!(config.database.provider, DatabaseProvider::PostgreSql);
420 assert_eq!(config.schema.path, "schema.prax");
421 assert!(config.database.url.is_none());
422 assert!(config.environments.is_empty());
423 }
424
425 #[test]
426 fn test_parse_minimal_config() {
427 let toml = r#"
428 [database]
429 provider = "postgresql"
430 url = "postgres://localhost/test"
431 "#;
432
433 let config = PraxConfig::from_str(toml).unwrap();
434 assert_eq!(
435 config.database.url,
436 Some("postgres://localhost/test".to_string())
437 );
438 }
439
440 #[test]
441 fn test_parse_full_config() {
442 let toml = r#"
443 [database]
444 provider = "postgresql"
445 url = "postgres://user:pass@localhost:5432/db"
446
447 [database.pool]
448 min_connections = 5
449 max_connections = 20
450 connect_timeout = "60s"
451 idle_timeout = "5m"
452 max_lifetime = "1h"
453
454 [schema]
455 path = "prisma/schema.prax"
456
457 [generator.client]
458 output = "./src/db"
459 async_client = true
460 tracing = true
461 preview_features = ["json", "fulltext"]
462
463 [migrations]
464 directory = "./db/migrations"
465 auto_migrate = true
466 table_name = "_migrations"
467
468 [seed]
469 script = "./scripts/seed.sh"
470 auto_seed = true
471
472 [seed.environments]
473 development = true
474 test = true
475 production = false
476
477 [debug]
478 log_queries = true
479 pretty_sql = false
480 slow_query_threshold = 500
481 "#;
482
483 let config = PraxConfig::from_str(toml).unwrap();
484
485 assert_eq!(config.database.provider, DatabaseProvider::PostgreSql);
487 assert!(config.database.url.is_some());
488 assert_eq!(config.database.pool.min_connections, 5);
489 assert_eq!(config.database.pool.max_connections, 20);
490
491 assert_eq!(config.schema.path, "prisma/schema.prax");
493
494 assert_eq!(config.generator.client.output, "./src/db");
496 assert!(config.generator.client.async_client);
497 assert!(config.generator.client.tracing);
498 assert_eq!(config.generator.client.preview_features.len(), 2);
499
500 assert_eq!(config.migrations.directory, "./db/migrations");
502 assert!(config.migrations.auto_migrate);
503 assert_eq!(config.migrations.table_name, "_migrations");
504
505 assert_eq!(config.seed.script, Some("./scripts/seed.sh".to_string()));
507 assert!(config.seed.auto_seed);
508 assert!(
509 config
510 .seed
511 .environments
512 .get("development")
513 .copied()
514 .unwrap_or(false)
515 );
516
517 assert!(config.debug.log_queries);
519 assert!(!config.debug.pretty_sql);
520 assert_eq!(config.debug.slow_query_threshold, 500);
521 }
522
523 #[test]
524 fn test_database_url_method() {
525 let config = PraxConfig {
526 database: DatabaseConfig {
527 url: Some("postgres://localhost/test".to_string()),
528 ..Default::default()
529 },
530 ..Default::default()
531 };
532
533 assert_eq!(config.database_url(), Some("postgres://localhost/test"));
534 }
535
536 #[test]
537 fn test_database_url_method_none() {
538 let config = PraxConfig::default();
539 assert!(config.database_url().is_none());
540 }
541
542 #[test]
543 fn test_with_environment_overrides() {
544 let toml = r#"
545 [database]
546 url = "postgres://localhost/dev"
547
548 [debug]
549 log_queries = false
550
551 [environments.production]
552 [environments.production.database]
553 url = "postgres://prod.server/db"
554
555 [environments.production.debug]
556 log_queries = true
557 slow_query_threshold = 100
558 "#;
559
560 let config = PraxConfig::from_str(toml)
561 .unwrap()
562 .with_environment("production");
563
564 assert_eq!(
565 config.database.url,
566 Some("postgres://prod.server/db".to_string())
567 );
568 assert!(config.debug.log_queries);
569 assert_eq!(config.debug.slow_query_threshold, 100);
570 }
571
572 #[test]
573 fn test_with_environment_nonexistent() {
574 let config = PraxConfig::default().with_environment("nonexistent");
575 assert_eq!(config.database.provider, DatabaseProvider::PostgreSql);
577 }
578
579 #[test]
580 fn test_parse_invalid_toml() {
581 let toml = "this is not valid [[ toml";
582 let result = PraxConfig::from_str(toml);
583 assert!(result.is_err());
584 }
585
586 #[test]
589 fn test_database_provider_postgresql() {
590 let toml = r#"
591 [database]
592 provider = "postgresql"
593 "#;
594 let config = PraxConfig::from_str(toml).unwrap();
595 assert_eq!(config.database.provider, DatabaseProvider::PostgreSql);
596 assert_eq!(config.database.provider.as_str(), "postgresql");
597 }
598
599 #[test]
600 fn test_database_provider_postgres_alias() {
601 let toml = r#"
602 [database]
603 provider = "postgres"
604 "#;
605 let config = PraxConfig::from_str(toml).unwrap();
606 assert_eq!(config.database.provider, DatabaseProvider::PostgreSql);
607 }
608
609 #[test]
610 fn test_database_provider_mysql() {
611 let toml = r#"
612 [database]
613 provider = "mysql"
614 "#;
615 let config = PraxConfig::from_str(toml).unwrap();
616 assert_eq!(config.database.provider, DatabaseProvider::MySql);
617 assert_eq!(config.database.provider.as_str(), "mysql");
618 }
619
620 #[test]
621 fn test_database_provider_sqlite() {
622 let toml = r#"
623 [database]
624 provider = "sqlite"
625 "#;
626 let config = PraxConfig::from_str(toml).unwrap();
627 assert_eq!(config.database.provider, DatabaseProvider::Sqlite);
628 assert_eq!(config.database.provider.as_str(), "sqlite");
629 }
630
631 #[test]
632 fn test_database_provider_sqlite3_alias() {
633 let toml = r#"
634 [database]
635 provider = "sqlite3"
636 "#;
637 let config = PraxConfig::from_str(toml).unwrap();
638 assert_eq!(config.database.provider, DatabaseProvider::Sqlite);
639 }
640
641 #[test]
642 fn test_database_provider_mongodb() {
643 let toml = r#"
644 [database]
645 provider = "mongodb"
646 "#;
647 let config = PraxConfig::from_str(toml).unwrap();
648 assert_eq!(config.database.provider, DatabaseProvider::MongoDb);
649 assert_eq!(config.database.provider.as_str(), "mongodb");
650 }
651
652 #[test]
653 fn test_database_provider_mongo_alias() {
654 let toml = r#"
655 [database]
656 provider = "mongo"
657 "#;
658 let config = PraxConfig::from_str(toml).unwrap();
659 assert_eq!(config.database.provider, DatabaseProvider::MongoDb);
660 }
661
662 #[test]
665 fn test_pool_config_defaults() {
666 let config = PoolConfig::default();
667 assert_eq!(config.min_connections, 2);
668 assert_eq!(config.max_connections, 10);
669 assert_eq!(config.connect_timeout, "30s");
670 assert_eq!(config.idle_timeout, "10m");
671 assert_eq!(config.max_lifetime, "30m");
672 }
673
674 #[test]
675 fn test_pool_config_custom() {
676 let toml = r#"
677 [database]
678 provider = "postgresql"
679
680 [database.pool]
681 min_connections = 1
682 max_connections = 50
683 connect_timeout = "10s"
684 idle_timeout = "30m"
685 max_lifetime = "2h"
686 "#;
687
688 let config = PraxConfig::from_str(toml).unwrap();
689 assert_eq!(config.database.pool.min_connections, 1);
690 assert_eq!(config.database.pool.max_connections, 50);
691 assert_eq!(config.database.pool.connect_timeout, "10s");
692 }
693
694 #[test]
697 fn test_schema_config_default() {
698 let config = SchemaConfig::default();
699 assert_eq!(config.path, "schema.prax");
700 }
701
702 #[test]
703 fn test_schema_config_custom() {
704 let toml = r#"
705 [schema]
706 path = "db/schema.prax"
707 "#;
708
709 let config = PraxConfig::from_str(toml).unwrap();
710 assert_eq!(config.schema.path, "db/schema.prax");
711 }
712
713 #[test]
716 fn test_generator_config_default() {
717 let config = GeneratorConfig::default();
718 assert_eq!(config.client.output, "./src/generated");
719 assert!(config.client.async_client);
720 assert!(!config.client.tracing);
721 assert!(config.client.preview_features.is_empty());
722 }
723
724 #[test]
725 fn test_generator_config_custom() {
726 let toml = r#"
727 [generator.client]
728 output = "./generated"
729 async_client = false
730 tracing = true
731 preview_features = ["feature1", "feature2"]
732 "#;
733
734 let config = PraxConfig::from_str(toml).unwrap();
735 assert_eq!(config.generator.client.output, "./generated");
736 assert!(!config.generator.client.async_client);
737 assert!(config.generator.client.tracing);
738 assert_eq!(config.generator.client.preview_features.len(), 2);
739 }
740
741 #[test]
744 fn test_migration_config_default() {
745 let config = MigrationConfig::default();
746 assert_eq!(config.directory, "./migrations");
747 assert!(!config.auto_migrate);
748 assert_eq!(config.table_name, "_prax_migrations");
749 }
750
751 #[test]
752 fn test_migration_config_custom() {
753 let toml = r#"
754 [migrations]
755 directory = "./db/migrate"
756 auto_migrate = true
757 table_name = "schema_migrations"
758 "#;
759
760 let config = PraxConfig::from_str(toml).unwrap();
761 assert_eq!(config.migrations.directory, "./db/migrate");
762 assert!(config.migrations.auto_migrate);
763 assert_eq!(config.migrations.table_name, "schema_migrations");
764 }
765
766 #[test]
769 fn test_seed_config_default() {
770 let config = SeedConfig::default();
771 assert!(config.script.is_none());
772 assert!(!config.auto_seed);
773 assert!(config.environments.is_empty());
774 }
775
776 #[test]
777 fn test_seed_config_custom() {
778 let toml = r#"
779 [seed]
780 script = "seed.rs"
781 auto_seed = true
782
783 [seed.environments]
784 dev = true
785 prod = false
786 "#;
787
788 let config = PraxConfig::from_str(toml).unwrap();
789 assert_eq!(config.seed.script, Some("seed.rs".to_string()));
790 assert!(config.seed.auto_seed);
791 assert_eq!(config.seed.environments.get("dev"), Some(&true));
792 assert_eq!(config.seed.environments.get("prod"), Some(&false));
793 }
794
795 #[test]
798 fn test_debug_config_default() {
799 let config = DebugConfig::default();
800 assert!(!config.log_queries);
801 assert!(config.pretty_sql);
802 assert_eq!(config.slow_query_threshold, 1000);
803 }
804
805 #[test]
806 fn test_debug_config_custom() {
807 let toml = r#"
808 [debug]
809 log_queries = true
810 pretty_sql = false
811 slow_query_threshold = 200
812 "#;
813
814 let config = PraxConfig::from_str(toml).unwrap();
815 assert!(config.debug.log_queries);
816 assert!(!config.debug.pretty_sql);
817 assert_eq!(config.debug.slow_query_threshold, 200);
818 }
819
820 #[test]
823 fn test_env_var_expansion() {
824 unsafe {
826 std::env::set_var("TEST_DB_URL", "postgres://test");
827 }
828 let expanded = expand_env_vars("url = \"${TEST_DB_URL}\"");
829 assert_eq!(expanded, "url = \"postgres://test\"");
830 unsafe {
831 std::env::remove_var("TEST_DB_URL");
832 }
833 }
834
835 #[test]
836 fn test_env_var_expansion_multiple() {
837 unsafe {
838 std::env::set_var("TEST_HOST", "localhost");
839 std::env::set_var("TEST_PORT", "5432");
840 }
841 let content = "host = \"${TEST_HOST}\"\nport = \"${TEST_PORT}\"";
842 let expanded = expand_env_vars(content);
843 assert!(expanded.contains("localhost"));
844 assert!(expanded.contains("5432"));
845 unsafe {
846 std::env::remove_var("TEST_HOST");
847 std::env::remove_var("TEST_PORT");
848 }
849 }
850
851 #[test]
852 fn test_env_var_expansion_missing_var() {
853 let content = "url = \"${DEFINITELY_NOT_SET_VAR_12345}\"";
854 let expanded = expand_env_vars(content);
855 assert_eq!(expanded, content);
857 }
858
859 #[test]
860 fn test_env_var_expansion_in_config() {
861 unsafe {
862 std::env::set_var("TEST_DATABASE_URL_2", "postgres://user:pass@localhost/db");
863 }
864
865 let toml = r#"
866 [database]
867 url = "${TEST_DATABASE_URL_2}"
868 "#;
869
870 let config = PraxConfig::from_str(toml).unwrap();
871 assert_eq!(
872 config.database.url,
873 Some("postgres://user:pass@localhost/db".to_string())
874 );
875
876 unsafe {
877 std::env::remove_var("TEST_DATABASE_URL_2");
878 }
879 }
880
881 #[test]
884 fn test_environment_override_database_url() {
885 let toml = r#"
886 [database]
887 url = "postgres://localhost/dev"
888
889 [environments.test]
890 [environments.test.database]
891 url = "postgres://localhost/test_db"
892 "#;
893
894 let config = PraxConfig::from_str(toml).unwrap().with_environment("test");
895
896 assert_eq!(
897 config.database.url,
898 Some("postgres://localhost/test_db".to_string())
899 );
900 }
901
902 #[test]
903 fn test_environment_override_pool() {
904 let toml = r#"
905 [database.pool]
906 max_connections = 10
907
908 [environments.production]
909 [environments.production.database.pool]
910 max_connections = 100
911 min_connections = 10
912 "#;
913
914 let config = PraxConfig::from_str(toml)
915 .unwrap()
916 .with_environment("production");
917
918 assert_eq!(config.database.pool.max_connections, 100);
919 assert_eq!(config.database.pool.min_connections, 10);
920 }
921
922 #[test]
923 fn test_environment_override_debug() {
924 let toml = r#"
925 [debug]
926 log_queries = false
927 pretty_sql = true
928
929 [environments.development]
930 [environments.development.debug]
931 log_queries = true
932 pretty_sql = false
933 slow_query_threshold = 50
934 "#;
935
936 let config = PraxConfig::from_str(toml)
937 .unwrap()
938 .with_environment("development");
939
940 assert!(config.debug.log_queries);
941 assert!(!config.debug.pretty_sql);
942 assert_eq!(config.debug.slow_query_threshold, 50);
943 }
944
945 #[test]
948 fn test_config_serialization() {
949 let config = PraxConfig::default();
950 let toml_str = toml::to_string(&config).unwrap();
951 assert!(toml_str.contains("[database]"));
952 }
953
954 #[test]
955 fn test_config_roundtrip() {
956 let original = PraxConfig {
957 database: DatabaseConfig {
958 provider: DatabaseProvider::MySql,
959 url: Some("mysql://localhost/test".to_string()),
960 pool: PoolConfig::default(),
961 },
962 ..Default::default()
963 };
964
965 let toml_str = toml::to_string(&original).unwrap();
966 let parsed: PraxConfig = toml::from_str(&toml_str).unwrap();
967
968 assert_eq!(parsed.database.provider, original.database.provider);
969 assert_eq!(parsed.database.url, original.database.url);
970 }
971
972 #[test]
975 fn test_config_clone() {
976 let config = PraxConfig::default();
977 let cloned = config.clone();
978 assert_eq!(config.database.provider, cloned.database.provider);
979 }
980
981 #[test]
982 fn test_config_debug() {
983 let config = PraxConfig::default();
984 let debug_str = format!("{:?}", config);
985 assert!(debug_str.contains("PraxConfig"));
986 }
987
988 #[test]
989 fn test_provider_equality() {
990 assert_eq!(DatabaseProvider::PostgreSql, DatabaseProvider::PostgreSql);
991 assert_ne!(DatabaseProvider::PostgreSql, DatabaseProvider::MySql);
992 }
993
994 #[test]
997 fn test_default_functions() {
998 assert_eq!(default_provider(), DatabaseProvider::PostgreSql);
999 assert_eq!(default_min_connections(), 2);
1000 assert_eq!(default_max_connections(), 10);
1001 assert_eq!(default_connect_timeout(), "30s");
1002 assert_eq!(default_idle_timeout(), "10m");
1003 assert_eq!(default_max_lifetime(), "30m");
1004 assert_eq!(default_schema_path(), "schema.prax");
1005 assert_eq!(default_output(), "./src/generated");
1006 assert!(default_true());
1007 assert_eq!(default_migrations_dir(), "./migrations");
1008 assert_eq!(default_migrations_table(), "_prax_migrations");
1009 assert_eq!(default_slow_query_threshold(), 1000);
1010 }
1011}