UNPKG

5.46 kBJavaScriptView Raw
1"use strict";
2
3const tracer = require(`opentracing`).globalTracer();
4
5const {
6 store
7} = require(`../redux`);
8
9const nodeStore = require(`../db/nodes`);
10
11const {
12 createSchemaComposer
13} = require(`./schema-composer`);
14
15const {
16 buildSchema,
17 rebuildSchemaWithSitePage
18} = require(`./schema`);
19
20const {
21 builtInFieldExtensions
22} = require(`./extensions`);
23
24const {
25 builtInTypeDefinitions
26} = require(`./types/built-in-types`);
27
28const {
29 TypeConflictReporter
30} = require(`./infer/type-conflict-reporter`);
31
32const getAllTypeDefinitions = () => {
33 const {
34 schemaCustomization: {
35 types
36 }
37 } = store.getState();
38 const builtInTypes = builtInTypeDefinitions().map(typeDef => {
39 return {
40 typeOrTypeDef: typeDef,
41 plugin: undefined
42 };
43 }); // Ensure that user-defined types are processed last
44
45 return [...builtInTypes, ...types.filter(type => type.plugin && type.plugin.name !== `default-site-plugin`), ...types.filter(type => !type.plugin || type.plugin.name === `default-site-plugin`)];
46};
47
48const getAllFieldExtensions = () => {
49 const {
50 schemaCustomization: {
51 fieldExtensions: customFieldExtensions
52 }
53 } = store.getState();
54 return Object.assign({}, customFieldExtensions, {}, builtInFieldExtensions);
55}; // Schema building requires metadata for type inference.
56// Technically it means looping through all type nodes, analyzing node structure
57// and then using this aggregated node structure in related GraphQL type.
58// Actual logic for inference located in inferenceMetadata reducer and ./infer
59// Here we just orchestrate the process via redux actions
60
61
62const buildInferenceMetadata = ({
63 types
64}) => new Promise(resolve => {
65 if (!types || !types.length) {
66 resolve();
67 return;
68 }
69
70 const typeNames = [...types]; // TODO: use async iterators when we switch to node>=10
71 // or better investigate if we can offload metadata building to worker/Jobs API
72 // and then feed the result into redux?
73
74 const processNextType = () => {
75 const typeName = typeNames.pop();
76 store.dispatch({
77 type: `BUILD_TYPE_METADATA`,
78 payload: {
79 typeName,
80 nodes: nodeStore.getNodesByType(typeName)
81 }
82 });
83
84 if (typeNames.length > 0) {
85 // Give event-loop a break
86 setTimeout(processNextType, 0);
87 } else {
88 resolve();
89 }
90 };
91
92 processNextType();
93});
94
95const build = async ({
96 parentSpan,
97 fullMetadataBuild = true
98}) => {
99 const spanArgs = parentSpan ? {
100 childOf: parentSpan
101 } : {};
102 const span = tracer.startSpan(`build schema`, spanArgs);
103
104 if (fullMetadataBuild) {
105 // Build metadata for type inference and start updating it incrementally
106 // except for SitePage type: we rebuild it in rebuildWithSitePage anyway
107 // so it makes little sense to update it incrementally
108 // (and those updates may have significant performance overhead)
109 await buildInferenceMetadata({
110 types: nodeStore.getTypes()
111 });
112 store.dispatch({
113 type: `START_INCREMENTAL_INFERENCE`
114 });
115 store.dispatch({
116 type: `DISABLE_TYPE_INFERENCE`,
117 payload: [`SitePage`]
118 });
119 }
120
121 const {
122 schemaCustomization: {
123 thirdPartySchemas,
124 printConfig
125 },
126 inferenceMetadata,
127 config: {
128 mapping: typeMapping
129 }
130 } = store.getState();
131 const typeConflictReporter = new TypeConflictReporter();
132 const fieldExtensions = getAllFieldExtensions();
133 const schemaComposer = createSchemaComposer({
134 fieldExtensions
135 });
136 const schema = await buildSchema({
137 schemaComposer,
138 nodeStore,
139 types: getAllTypeDefinitions(),
140 fieldExtensions,
141 thirdPartySchemas,
142 typeMapping,
143 printConfig,
144 typeConflictReporter,
145 inferenceMetadata,
146 parentSpan
147 });
148 typeConflictReporter.printConflicts();
149 store.dispatch({
150 type: `SET_SCHEMA_COMPOSER`,
151 payload: schemaComposer
152 });
153 store.dispatch({
154 type: `SET_SCHEMA`,
155 payload: schema
156 });
157 span.finish();
158};
159
160const rebuild = async ({
161 parentSpan
162}) => await build({
163 parentSpan,
164 fullMetadataBuild: false
165});
166
167const rebuildWithSitePage = async ({
168 parentSpan
169}) => {
170 const spanArgs = parentSpan ? {
171 childOf: parentSpan
172 } : {};
173 const span = tracer.startSpan(`rebuild schema with SitePage context`, spanArgs);
174 await buildInferenceMetadata({
175 types: [`SitePage`]
176 }); // Disabling incremental inference for SitePage after the initial build
177 // as it has a significant performance cost for zero benefits.
178 // The only benefit is that schema rebuilds when SitePage.context structure changes.
179 // (one can just restart `develop` in this case)
180
181 store.dispatch({
182 type: `DISABLE_TYPE_INFERENCE`,
183 payload: [`SitePage`]
184 });
185 const {
186 schemaCustomization: {
187 composer: schemaComposer
188 },
189 config: {
190 mapping: typeMapping
191 },
192 inferenceMetadata
193 } = store.getState();
194 const typeConflictReporter = new TypeConflictReporter();
195 const schema = await rebuildSchemaWithSitePage({
196 schemaComposer,
197 nodeStore,
198 fieldExtensions: getAllFieldExtensions(),
199 typeMapping,
200 typeConflictReporter,
201 inferenceMetadata,
202 parentSpan
203 });
204 typeConflictReporter.printConflicts();
205 store.dispatch({
206 type: `SET_SCHEMA_COMPOSER`,
207 payload: schemaComposer
208 });
209 store.dispatch({
210 type: `SET_SCHEMA`,
211 payload: schema
212 });
213 span.finish();
214};
215
216module.exports = {
217 build,
218 rebuild,
219 rebuildWithSitePage
220};
221//# sourceMappingURL=index.js.map
\No newline at end of file