graphql_composition/
subgraphs.rs1mod definitions;
2mod directives;
3mod enums;
4mod extensions;
5mod field_types;
6mod fields;
7mod ids;
8mod keys;
9mod linked_schemas;
10mod strings;
11mod top;
12mod unions;
13mod view;
14
15pub(crate) use self::{
16 definitions::*, directives::*, enums::*, extensions::*, field_types::*, fields::*, ids::*, keys::*,
17 linked_schemas::*, strings::StringId, top::*, view::View,
18};
19
20use crate::VecExt;
21use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
22
23pub struct Subgraphs {
25 pub(super) strings: strings::Strings,
26 subgraphs: Vec<Subgraph>,
27 definitions: definitions::Definitions,
28 directives: directives::Directives,
29 enums: enums::Enums,
30 fields: fields::Fields,
31 keys: keys::Keys,
32 unions: unions::Unions,
33 linked_schemas: linked_schemas::LinkedSchemas,
34
35 ingestion_diagnostics: crate::Diagnostics,
36
37 extensions: Vec<ExtensionRecord>,
38
39 definition_names: BTreeMap<(StringId, SubgraphId), DefinitionId>,
47}
48
49impl Default for Subgraphs {
50 fn default() -> Self {
51 let mut strings = strings::Strings::default();
52 BUILTIN_SCALARS.into_iter().for_each(|scalar| {
53 strings.intern(scalar);
54 });
55
56 Self {
57 strings,
58 subgraphs: Default::default(),
59 definitions: Default::default(),
60 directives: Default::default(),
61 enums: Default::default(),
62 fields: Default::default(),
63 keys: Default::default(),
64 unions: Default::default(),
65 ingestion_diagnostics: Default::default(),
66 definition_names: Default::default(),
67 linked_schemas: Default::default(),
68 extensions: Vec::new(),
69 }
70 }
71}
72
73const BUILTIN_SCALARS: [&str; 5] = ["ID", "String", "Boolean", "Int", "Float"];
74
75#[derive(Debug)]
77pub struct IngestError {
78 error: cynic_parser::Error,
79 report: String,
80}
81
82impl std::error::Error for IngestError {
83 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
84 self.error.source()
85 }
86}
87
88impl std::fmt::Display for IngestError {
89 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
90 if f.alternate() {
91 return self.report.fmt(f);
92 }
93 std::fmt::Display::fmt(&self.error, f)
94 }
95}
96
97impl Subgraphs {
98 pub fn ingest(&mut self, subgraph_schema: &cynic_parser::TypeSystemDocument, name: &str, url: Option<&str>) {
100 crate::ingest_subgraph::ingest_subgraph(subgraph_schema, name, url, self);
101 }
102
103 pub fn ingest_str(&mut self, subgraph_schema: &str, name: &str, url: Option<&str>) -> Result<(), IngestError> {
105 let subgraph_schema =
106 cynic_parser::parse_type_system_document(subgraph_schema).map_err(|error| IngestError {
107 report: error.to_report(subgraph_schema).to_string(),
108 error,
109 })?;
110 crate::ingest_subgraph::ingest_subgraph(&subgraph_schema, name, url, self);
111 Ok(())
112 }
113
114 #[doc(hidden)]
118 pub fn ingest_loaded_extensions(&mut self, extensions: impl IntoIterator<Item = crate::LoadedExtension>) {
119 self.extensions
120 .extend(extensions.into_iter().map(|ext| ExtensionRecord {
121 url: self.strings.intern(ext.url.as_str()),
122 link_url: self.strings.intern(ext.link_url.as_str()),
123 name: self.strings.intern(ext.name),
124 }));
125 }
126
127 pub fn is_empty(&self) -> bool {
129 self.subgraphs.is_empty()
130 }
131
132 pub(crate) fn iter_definition_groups<'a>(&'a self, mut compose_fn: impl FnMut(&[DefinitionView<'a>])) {
136 let mut key = None;
137 let mut buf = Vec::new();
138
139 for ((name, subgraph), definition) in &self.definition_names {
140 if Some(name) != key {
141 compose_fn(&buf);
143 buf.clear();
144 key = Some(name);
145 }
146
147 if self.is_root_type(*subgraph, *definition) {
150 continue; }
152
153 buf.push(self.at(*definition));
154 }
155
156 compose_fn(&buf)
157 }
158
159 pub(crate) fn push_ingestion_diagnostic(&mut self, subgraph: SubgraphId, message: String) {
160 self.ingestion_diagnostics
161 .push_fatal(format!("[{}]: {message}", self[self.at(subgraph).name]));
162 }
163
164 pub(crate) fn push_ingestion_warning(&mut self, subgraph: SubgraphId, message: String) {
165 self.ingestion_diagnostics
166 .push_warning(format!("[{}]: {message}", self[self.at(subgraph).name]));
167 }
168
169 pub(crate) fn iter_builtin_scalars(&self) -> impl ExactSizeIterator<Item = &str> + '_ {
171 BUILTIN_SCALARS.into_iter()
172 }
173
174 pub(crate) fn emit_ingestion_diagnostics(&self, diagnostics: &mut crate::Diagnostics) {
175 diagnostics.clone_all_from(&self.ingestion_diagnostics);
176 }
177
178 pub(crate) fn sort_pre_composition(&mut self) {
180 self.keys.keys.sort_unstable_by_key(|key| key.definition_id);
181
182 self.directives
183 .extra_directives
184 .sort_unstable_by_key(|directive| directive.directive_site_id);
185
186 self.enums
187 .values
188 .sort_unstable_by_key(|value| (value.parent_enum_id, value.name));
189
190 self.fields
191 .fields
192 .sort_unstable_by_key(|field| (field.parent_definition_id, field.name));
193
194 self.fields.arguments.sort_unstable_by_key(|argument| {
195 (argument.parent_definition_id, argument.parent_field_name, argument.name)
196 });
197 }
198}