1+ use std:: collections:: HashMap ;
12use std:: path:: PathBuf ;
23use std:: sync:: { Arc , Mutex } ;
34use std:: { fs, io} ;
@@ -106,27 +107,28 @@ impl Metadata {
106107 }
107108}
108109
110+ static METADATA : Lazy < Mutex < HashMap < String , Metadata > > > = Lazy :: new ( Default :: default) ;
111+
109112// If we are in a workspace, lookup `workspace_root` since `CARGO_MANIFEST_DIR` won't
110113// reflect the workspace dir: https://github.com/rust-lang/cargo/issues/3946
111- static METADATA : Lazy < Metadata > = Lazy :: new ( || {
112- let manifest_dir: PathBuf = env ( "CARGO_MANIFEST_DIR" )
113- . expect ( "`CARGO_MANIFEST_DIR` must be set" )
114- . into ( ) ;
114+ fn init_metadata ( manifest_dir : & String ) -> Metadata {
115+ let manifest_dir: PathBuf = manifest_dir. into ( ) ;
115116
116117 // If a .env file exists at CARGO_MANIFEST_DIR, load environment variables from this,
117118 // otherwise fallback to default dotenv behaviour.
118119 let env_path = manifest_dir. join ( ".env" ) ;
119120
120121 #[ cfg_attr( not( procmacro2_semver_exempt) , allow( unused_variables) ) ]
121122 let env_path = if env_path. exists ( ) {
122- let res = dotenvy:: from_path ( & env_path) ;
123+ // Load the new environment variables and override the old ones if necessary.
124+ let res = dotenvy:: from_path_override ( & env_path) ;
123125 if let Err ( e) = res {
124126 panic ! ( "failed to load environment from {env_path:?}, {e}" ) ;
125127 }
126128
127129 Some ( env_path)
128130 } else {
129- dotenvy:: dotenv ( ) . ok ( )
131+ dotenvy:: dotenv_override ( ) . ok ( )
130132 } ;
131133
132134 // tell the compiler to watch the `.env` for changes, if applicable
@@ -147,32 +149,46 @@ static METADATA: Lazy<Metadata> = Lazy::new(|| {
147149 database_url,
148150 workspace_root : Arc :: new ( Mutex :: new ( None ) ) ,
149151 }
150- } ) ;
152+ }
151153
152154pub fn expand_input < ' a > (
153155 input : QueryMacroInput ,
154156 drivers : impl IntoIterator < Item = & ' a QueryDriver > ,
155157) -> crate :: Result < TokenStream > {
156- let data_source = match & * METADATA {
158+ let manifest_dir = env ( "CARGO_MANIFEST_DIR" ) . expect ( "`CARGO_MANIFEST_DIR` must be set" ) ;
159+
160+ let mut metadata_lock = METADATA
161+ . lock ( )
162+ // Just reset the metadata on error
163+ . unwrap_or_else ( |poison_err| {
164+ let mut guard = poison_err. into_inner ( ) ;
165+ * guard = Default :: default ( ) ;
166+ guard
167+ } ) ;
168+
169+ let metadata = metadata_lock
170+ . entry ( manifest_dir)
171+ . or_insert_with_key ( init_metadata) ;
172+
173+ let data_source = match & metadata {
157174 Metadata {
158175 offline : false ,
159176 database_url : Some ( db_url) ,
160177 ..
161178 } => QueryDataSource :: live ( db_url) ?,
162-
163179 Metadata { offline, .. } => {
164180 // Try load the cached query metadata file.
165181 let filename = format ! ( "query-{}.json" , hash_string( & input. sql) ) ;
166182
167183 // Check SQLX_OFFLINE_DIR, then local .sqlx, then workspace .sqlx.
168184 let dirs = [
169- || env ( "SQLX_OFFLINE_DIR" ) . ok ( ) . map ( PathBuf :: from) ,
170- || Some ( METADATA . manifest_dir . join ( ".sqlx" ) ) ,
171- || Some ( METADATA . workspace_root ( ) . join ( ".sqlx" ) ) ,
185+ |_ : & Metadata | env ( "SQLX_OFFLINE_DIR" ) . ok ( ) . map ( PathBuf :: from) ,
186+ |meta : & Metadata | Some ( meta . manifest_dir . join ( ".sqlx" ) ) ,
187+ |meta : & Metadata | Some ( meta . workspace_root ( ) . join ( ".sqlx" ) ) ,
172188 ] ;
173189 let Some ( data_file_path) = dirs
174190 . iter ( )
175- . filter_map ( |path| path ( ) )
191+ . filter_map ( |path| path ( metadata ) )
176192 . map ( |path| path. join ( & filename) )
177193 . find ( |path| path. exists ( ) )
178194 else {
@@ -184,7 +200,6 @@ pub fn expand_input<'a>(
184200 } . into ( )
185201 ) ;
186202 } ;
187-
188203 QueryDataSource :: Cached ( DynQueryData :: from_data_file ( & data_file_path, & input. sql ) ?)
189204 }
190205 } ;
0 commit comments