@@ -37,10 +37,75 @@ fn create_file(
37
37
Ok ( ( ) )
38
38
}
39
39
40
+ enum MigrationOrdering {
41
+ Timestamp ( String ) ,
42
+ Sequential ( String ) ,
43
+ }
44
+
45
+ impl MigrationOrdering {
46
+ fn timestamp ( ) -> MigrationOrdering {
47
+ Self :: Timestamp ( Utc :: now ( ) . format ( "%Y%m%d%H%M%S" ) . to_string ( ) )
48
+ }
49
+
50
+ fn sequential ( version : i64 ) -> MigrationOrdering {
51
+ Self :: Sequential ( format ! ( "{:04}" , version) )
52
+ }
53
+
54
+ fn file_prefix ( & self ) -> & str {
55
+ match self {
56
+ MigrationOrdering :: Timestamp ( prefix) => prefix,
57
+ MigrationOrdering :: Sequential ( prefix) => prefix,
58
+ }
59
+ }
60
+
61
+ fn infer ( sequential : bool , timestamp : bool , migrator : & Migrator ) -> Self {
62
+ match ( timestamp, sequential) {
63
+ ( true , true ) => panic ! ( "Impossible to specify both timestamp and sequential mode" ) ,
64
+ ( true , false ) => MigrationOrdering :: timestamp ( ) ,
65
+ ( false , true ) => MigrationOrdering :: sequential (
66
+ migrator
67
+ . iter ( )
68
+ . last ( )
69
+ . map_or ( 1 , |last_migration| last_migration. version + 1 ) ,
70
+ ) ,
71
+ ( false , false ) => {
72
+ // inferring the naming scheme
73
+ let migrations = migrator
74
+ . iter ( )
75
+ . filter ( |migration| migration. migration_type . is_up_migration ( ) )
76
+ . rev ( )
77
+ . take ( 2 )
78
+ . collect :: < Vec < _ > > ( ) ;
79
+ if let [ last, pre_last] = & migrations[ ..] {
80
+ // there are at least two migrations, compare the last twothere's only one existing migration
81
+ if last. version - pre_last. version == 1 {
82
+ // their version numbers differ by 1, infer sequential
83
+ MigrationOrdering :: sequential ( last. version + 1 )
84
+ } else {
85
+ MigrationOrdering :: timestamp ( )
86
+ }
87
+ } else if let [ last] = & migrations[ ..] {
88
+ // there is only one existing migration
89
+ if last. version == 0 || last. version == 1 {
90
+ // infer sequential if the version number is 0 or 1
91
+ MigrationOrdering :: sequential ( last. version + 1 )
92
+ } else {
93
+ MigrationOrdering :: timestamp ( )
94
+ }
95
+ } else {
96
+ MigrationOrdering :: timestamp ( )
97
+ }
98
+ }
99
+ }
100
+ }
101
+ }
102
+
40
103
pub async fn add (
41
104
migration_source : & str ,
42
105
description : & str ,
43
106
reversible : bool ,
107
+ sequential : bool ,
108
+ timestamp : bool ,
44
109
) -> anyhow:: Result < ( ) > {
45
110
fs:: create_dir_all ( migration_source) . context ( "Unable to create migrations directory" ) ?;
46
111
@@ -50,15 +115,16 @@ pub async fn add(
50
115
. unwrap_or ( false ) ;
51
116
52
117
let migrator = Migrator :: new ( Path :: new ( migration_source) ) . await ?;
53
- // This checks if all existing migrations are of the same type as the reverisble flag passed
118
+ // This checks if all existing migrations are of the same type as the reversible flag passed
54
119
for migration in migrator. iter ( ) {
55
120
if migration. migration_type . is_reversible ( ) != reversible {
56
121
bail ! ( MigrateError :: InvalidMixReversibleAndSimple ) ;
57
122
}
58
123
}
59
124
60
- let dt = Utc :: now ( ) ;
61
- let file_prefix = dt. format ( "%Y%m%d%H%M%S" ) . to_string ( ) ;
125
+ let ordering = MigrationOrdering :: infer ( sequential, timestamp, & migrator) ;
126
+ let file_prefix = ordering. file_prefix ( ) ;
127
+
62
128
if reversible {
63
129
create_file (
64
130
migration_source,
0 commit comments