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