1
1
#[ cfg( any( sqlx_macros_unstable, procmacro2_semver_exempt) ) ]
2
2
extern crate proc_macro;
3
3
4
+ use std:: path:: { Path , PathBuf } ;
5
+
4
6
use proc_macro2:: TokenStream ;
5
7
use quote:: { quote, ToTokens , TokenStreamExt } ;
6
- use sha2:: { Digest , Sha384 } ;
7
- use sqlx_core:: migrate:: MigrationType ;
8
- use std:: fs;
9
- use std:: path:: Path ;
10
8
use syn:: LitStr ;
11
9
12
- pub struct QuotedMigrationType ( MigrationType ) ;
10
+ use sqlx_core:: migrate:: { Migration , MigrationType } ;
11
+
12
+ pub struct QuoteMigrationType ( MigrationType ) ;
13
13
14
- impl ToTokens for QuotedMigrationType {
14
+ impl ToTokens for QuoteMigrationType {
15
15
fn to_tokens ( & self , tokens : & mut TokenStream ) {
16
16
let ts = match self . 0 {
17
17
MigrationType :: Simple => quote ! { :: sqlx:: migrate:: MigrationType :: Simple } ,
@@ -24,31 +24,51 @@ impl ToTokens for QuotedMigrationType {
24
24
}
25
25
}
26
26
27
- struct QuotedMigration {
28
- version : i64 ,
29
- description : String ,
30
- migration_type : QuotedMigrationType ,
31
- path : String ,
32
- checksum : Vec < u8 > ,
27
+ struct QuoteMigration {
28
+ migration : Migration ,
29
+ path : PathBuf ,
33
30
}
34
31
35
- impl ToTokens for QuotedMigration {
32
+ impl ToTokens for QuoteMigration {
36
33
fn to_tokens ( & self , tokens : & mut TokenStream ) {
37
- let QuotedMigration {
34
+ let Migration {
38
35
version,
39
36
description,
40
37
migration_type,
41
- path,
42
38
checksum,
43
- } = & self ;
39
+ ..
40
+ } = & self . migration ;
41
+
42
+ let migration_type = QuoteMigrationType ( * migration_type) ;
43
+
44
+ let sql = self
45
+ . path
46
+ . canonicalize ( )
47
+ . map_err ( |e| {
48
+ format ! (
49
+ "error canonicalizing migration path {}: {e}" ,
50
+ self . path. display( )
51
+ )
52
+ } )
53
+ . and_then ( |path| {
54
+ let path_str = path. to_str ( ) . ok_or_else ( || {
55
+ format ! (
56
+ "migration path cannot be represented as a string: {}" ,
57
+ self . path. display( )
58
+ )
59
+ } ) ?;
60
+
61
+ // this tells the compiler to watch this path for changes
62
+ Ok ( quote ! { include_str!( #path_str) } )
63
+ } )
64
+ . unwrap_or_else ( |e| quote ! { compile_error!( #e) } ) ;
44
65
45
66
let ts = quote ! {
46
67
:: sqlx:: migrate:: Migration {
47
68
version: #version,
48
69
description: :: std:: borrow:: Cow :: Borrowed ( #description) ,
49
70
migration_type: #migration_type,
50
- // this tells the compiler to watch this path for changes
51
- sql: :: std:: borrow:: Cow :: Borrowed ( include_str!( #path) ) ,
71
+ sql: :: std:: borrow:: Cow :: Borrowed ( #sql) ,
52
72
checksum: :: std:: borrow:: Cow :: Borrowed ( & [
53
73
#( #checksum) , *
54
74
] ) ,
@@ -59,7 +79,6 @@ impl ToTokens for QuotedMigration {
59
79
}
60
80
}
61
81
62
- // mostly copied from sqlx-core/src/migrate/source.rs
63
82
pub fn expand_migrator_from_lit_dir ( dir : LitStr ) -> crate :: Result < TokenStream > {
64
83
expand_migrator_from_dir ( & dir. value ( ) , dir. span ( ) )
65
84
}
@@ -74,65 +93,20 @@ pub(crate) fn expand_migrator_from_dir(
74
93
}
75
94
76
95
pub ( crate ) fn expand_migrator ( path : & Path ) -> crate :: Result < TokenStream > {
77
- let mut migrations = Vec :: new ( ) ;
78
-
79
- for entry in fs:: read_dir ( & path) ? {
80
- let entry = entry?;
81
- if !fs:: metadata ( entry. path ( ) ) ?. is_file ( ) {
82
- // not a file; ignore
83
- continue ;
84
- }
85
-
86
- let file_name = entry. file_name ( ) ;
87
- let file_name = file_name. to_string_lossy ( ) ;
88
-
89
- let parts = file_name. splitn ( 2 , '_' ) . collect :: < Vec < _ > > ( ) ;
90
-
91
- if parts. len ( ) != 2 || !parts[ 1 ] . ends_with ( ".sql" ) {
92
- // not of the format: <VERSION>_<DESCRIPTION>.sql; ignore
93
- continue ;
94
- }
95
-
96
- let version: i64 = parts[ 0 ] . parse ( ) ?;
97
-
98
- let migration_type = MigrationType :: from_filename ( parts[ 1 ] ) ;
99
- // remove the `.sql` and replace `_` with ` `
100
- let description = parts[ 1 ]
101
- . trim_end_matches ( migration_type. suffix ( ) )
102
- . replace ( '_' , " " )
103
- . to_owned ( ) ;
104
-
105
- let sql = fs:: read_to_string ( & entry. path ( ) ) ?;
106
-
107
- let checksum = Vec :: from ( Sha384 :: digest ( sql. as_bytes ( ) ) . as_slice ( ) ) ;
108
-
109
- // canonicalize the path so we can pass it to `include_str!()`
110
- let path = entry. path ( ) . canonicalize ( ) ?;
111
- let path = path
112
- . to_str ( )
113
- . ok_or_else ( || {
114
- format ! (
115
- "migration path cannot be represented as a string: {:?}" ,
116
- path
117
- )
118
- } ) ?
119
- . to_owned ( ) ;
120
-
121
- migrations. push ( QuotedMigration {
122
- version,
123
- description,
124
- migration_type : QuotedMigrationType ( migration_type) ,
125
- path,
126
- checksum,
127
- } )
128
- }
129
-
130
- // ensure that we are sorted by `VERSION ASC`
131
- migrations. sort_by_key ( |m| m. version ) ;
96
+ let path = path. canonicalize ( ) . map_err ( |e| {
97
+ format ! (
98
+ "error canonicalizing migration directory {}: {e}" ,
99
+ path. display( )
100
+ )
101
+ } ) ?;
102
+
103
+ // Use the same code path to resolve migrations at compile time and runtime.
104
+ let migrations = sqlx_core:: migrate:: resolve_blocking ( path) ?
105
+ . into_iter ( )
106
+ . map ( |( migration, path) | QuoteMigration { migration, path } ) ;
132
107
133
108
#[ cfg( any( sqlx_macros_unstable, procmacro2_semver_exempt) ) ]
134
109
{
135
- let path = path. canonicalize ( ) ?;
136
110
let path = path. to_str ( ) . ok_or_else ( || {
137
111
format ! (
138
112
"migration directory path cannot be represented as a string: {:?}" ,
0 commit comments