|
4 | 4 | extern crate failure;
|
5 | 5 | extern crate graphql_parser;
|
6 | 6 | extern crate heck;
|
| 7 | +#[macro_use] |
| 8 | +extern crate lazy_static; |
7 | 9 | extern crate proc_macro;
|
8 | 10 | extern crate proc_macro2;
|
9 | 11 | extern crate serde;
|
@@ -42,6 +44,13 @@ mod tests;
|
42 | 44 | use heck::*;
|
43 | 45 | use proc_macro2::{Ident, Span};
|
44 | 46 |
|
| 47 | +type CacheMap<T> = ::std::sync::Mutex<::std::collections::hash_map::HashMap<::std::path::PathBuf, T>>; |
| 48 | + |
| 49 | +lazy_static! { |
| 50 | + static ref SCHEMA_CACHE: CacheMap<schema::Schema> = CacheMap::default(); |
| 51 | + static ref QUERY_CACHE: CacheMap<(String, graphql_parser::query::Document)> = CacheMap::default(); |
| 52 | +} |
| 53 | + |
45 | 54 | #[proc_macro_derive(GraphQLQuery, attributes(graphql))]
|
46 | 55 | pub fn graphql_query_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
47 | 56 | let input = TokenStream::from(input);
|
@@ -89,28 +98,51 @@ fn impl_gql_query(input: &syn::DeriveInput) -> Result<TokenStream, failure::Erro
|
89 | 98 |
|
90 | 99 | // We need to qualify the query with the path to the crate it is part of
|
91 | 100 | let query_path = ::std::path::Path::new(&cargo_manifest_dir).join(query_path);
|
92 |
| - let query_string = read_file(&query_path)?; |
93 |
| - let query = graphql_parser::parse_query(&query_string)?; |
| 101 | + // Check the query cache. |
| 102 | + let (query_string, query) = { |
| 103 | + let mut lock = QUERY_CACHE.lock().expect("query cache is poisoned"); |
| 104 | + match lock.entry(query_path) { |
| 105 | + ::std::collections::hash_map::Entry::Occupied(o) => o.get().clone(), |
| 106 | + ::std::collections::hash_map::Entry::Vacant(v) => { |
| 107 | + let query_string = read_file(v.key())?; |
| 108 | + let query = graphql_parser::parse_query(&query_string)?; |
| 109 | + v.insert((query_string, query)).clone() |
| 110 | + }, |
| 111 | + } |
| 112 | + }; |
94 | 113 |
|
95 | 114 | // We need to qualify the schema with the path to the crate it is part of
|
96 | 115 | let schema_path = ::std::path::Path::new(&cargo_manifest_dir).join(schema_path);
|
97 |
| - let schema_string = read_file(&schema_path)?; |
98 |
| - |
99 |
| - let extension = schema_path |
100 |
| - .extension() |
101 |
| - .and_then(|e| e.to_str()) |
102 |
| - .unwrap_or("INVALID"); |
103 |
| - |
104 |
| - let schema = match extension { |
105 |
| - "graphql" | "gql" => { |
106 |
| - let s = graphql_parser::schema::parse_schema(&schema_string)?; |
107 |
| - schema::Schema::from(s) |
108 |
| - } |
109 |
| - "json" => { |
110 |
| - let parsed: FullResponse<introspection_response::IntrospectionResponse> = ::serde_json::from_str(&schema_string)?; |
111 |
| - schema::Schema::from(parsed.data) |
| 116 | + // Check the schema cache. |
| 117 | + let schema = { |
| 118 | + let mut lock = SCHEMA_CACHE.lock().expect("schema cache is poisoned"); |
| 119 | + match lock.entry(schema_path) { |
| 120 | + ::std::collections::hash_map::Entry::Occupied(o) => o.get().clone(), |
| 121 | + ::std::collections::hash_map::Entry::Vacant(v) => { |
| 122 | + let schema_string = read_file(v.key())?; |
| 123 | + let schema = { |
| 124 | + let extension = v |
| 125 | + .key() |
| 126 | + .extension() |
| 127 | + .and_then(|e| e.to_str()) |
| 128 | + .unwrap_or("INVALID"); |
| 129 | + |
| 130 | + match extension { |
| 131 | + "graphql" | "gql" => { |
| 132 | + let s = graphql_parser::schema::parse_schema(&schema_string)?; |
| 133 | + schema::Schema::from(s) |
| 134 | + } |
| 135 | + "json" => { |
| 136 | + let parsed: FullResponse<introspection_response::IntrospectionResponse> = ::serde_json::from_str(&schema_string)?; |
| 137 | + schema::Schema::from(parsed.data) |
| 138 | + } |
| 139 | + extension => panic!("Unsupported extension for the GraphQL schema: {} (only .json and .graphql are supported)", extension) |
| 140 | + } |
| 141 | + }; |
| 142 | + |
| 143 | + v.insert(schema).clone() |
| 144 | + }, |
112 | 145 | }
|
113 |
| - extension => panic!("Unsupported extension for the GraphQL schema: {} (only .json and .graphql are supported)", extension) |
114 | 146 | };
|
115 | 147 |
|
116 | 148 | let module_name = Ident::new(&input.ident.to_string().to_snake_case(), Span::call_site());
|
|
0 commit comments