UNPKG

5.86 kBJavaScriptView Raw
1'use strict'
2
3const { buildSchemas } = require('./schemas')
4const SerializerSelector = require('@fastify/fast-json-stringify-compiler')
5const ValidatorSelector = require('@fastify/ajv-compiler')
6
7/**
8 * Called at every fastify context that is being created.
9 * @param {object} parentSchemaCtrl: the SchemaController instance of the Fastify parent context
10 * @param {object} opts: the `schemaController` server option. It can be undefined when a parentSchemaCtrl is set
11 * @return {object}:a new SchemaController
12 */
13function buildSchemaController (parentSchemaCtrl, opts) {
14 if (parentSchemaCtrl) {
15 return new SchemaController(parentSchemaCtrl, opts)
16 }
17
18 const compilersFactory = Object.assign({
19 buildValidator: null,
20 buildSerializer: null
21 }, opts?.compilersFactory)
22
23 if (!compilersFactory.buildValidator) {
24 compilersFactory.buildValidator = ValidatorSelector()
25 }
26 if (!compilersFactory.buildSerializer) {
27 compilersFactory.buildSerializer = SerializerSelector()
28 }
29
30 const option = {
31 bucket: (opts && opts.bucket) || buildSchemas,
32 compilersFactory,
33 isCustomValidatorCompiler: typeof opts?.compilersFactory?.buildValidator === 'function',
34 isCustomSerializerCompiler: typeof opts?.compilersFactory?.buildValidator === 'function'
35 }
36
37 return new SchemaController(undefined, option)
38}
39
40class SchemaController {
41 constructor (parent, options) {
42 this.opts = options || parent?.opts
43 this.addedSchemas = false
44
45 this.compilersFactory = this.opts.compilersFactory
46
47 if (parent) {
48 this.schemaBucket = this.opts.bucket(parent.getSchemas())
49 this.validatorCompiler = parent.getValidatorCompiler()
50 this.serializerCompiler = parent.getSerializerCompiler()
51 this.isCustomValidatorCompiler = parent.isCustomValidatorCompiler
52 this.isCustomSerializerCompiler = parent.isCustomSerializerCompiler
53 this.parent = parent
54 } else {
55 this.schemaBucket = this.opts.bucket()
56 this.isCustomValidatorCompiler = this.opts.isCustomValidatorCompiler || false
57 this.isCustomSerializerCompiler = this.opts.isCustomSerializerCompiler || false
58 }
59 }
60
61 // Bucket interface
62 add (schema) {
63 this.addedSchemas = true
64 return this.schemaBucket.add(schema)
65 }
66
67 getSchema (schemaId) {
68 return this.schemaBucket.getSchema(schemaId)
69 }
70
71 getSchemas () {
72 return this.schemaBucket.getSchemas()
73 }
74
75 setValidatorCompiler (validatorCompiler) {
76 // Set up as if the fixed validator compiler had been provided
77 // by a custom 'options.compilersFactory.buildValidator' that
78 // always returns the same compiler object. This is required because:
79 //
80 // - setValidatorCompiler must immediately install a compiler to preserve
81 // legacy behavior
82 // - setupValidator will recreate compilers from builders in some
83 // circumstances, so we have to install this adapter to make it
84 // behave the same if the legacy API is used
85 //
86 // The cloning of the compilersFactory object is necessary because
87 // we are aliasing the parent compilersFactory if none was provided
88 // to us (see constructor.)
89 this.compilersFactory = Object.assign(
90 {},
91 this.compilersFactory,
92 { buildValidator: () => validatorCompiler })
93 this.validatorCompiler = validatorCompiler
94 this.isCustomValidatorCompiler = true
95 }
96
97 setSerializerCompiler (serializerCompiler) {
98 // Set up as if the fixed serializer compiler had been provided
99 // by a custom 'options.compilersFactory.buildSerializer' that
100 // always returns the same compiler object. This is required because:
101 //
102 // - setSerializerCompiler must immediately install a compiler to preserve
103 // legacy behavior
104 // - setupSerializer will recreate compilers from builders in some
105 // circumstances, so we have to install this adapter to make it
106 // behave the same if the legacy API is used
107 //
108 // The cloning of the compilersFactory object is necessary because
109 // we are aliasing the parent compilersFactory if none was provided
110 // to us (see constructor.)
111 this.compilersFactory = Object.assign(
112 {},
113 this.compilersFactory,
114 { buildSerializer: () => serializerCompiler })
115 this.serializerCompiler = serializerCompiler
116 this.isCustomSerializerCompiler = true
117 }
118
119 getValidatorCompiler () {
120 return this.validatorCompiler || (this.parent && this.parent.getValidatorCompiler())
121 }
122
123 getSerializerCompiler () {
124 return this.serializerCompiler || (this.parent && this.parent.getSerializerCompiler())
125 }
126
127 getSerializerBuilder () {
128 return this.compilersFactory.buildSerializer || (this.parent && this.parent.getSerializerBuilder())
129 }
130
131 getValidatorBuilder () {
132 return this.compilersFactory.buildValidator || (this.parent && this.parent.getValidatorBuilder())
133 }
134
135 /**
136 * This method will be called when a validator must be setup.
137 * Do not setup the compiler more than once
138 * @param {object} serverOptions the fastify server options
139 */
140 setupValidator (serverOptions) {
141 const isReady = this.validatorCompiler !== undefined && !this.addedSchemas
142 if (isReady) {
143 return
144 }
145 this.validatorCompiler = this.getValidatorBuilder()(this.schemaBucket.getSchemas(), serverOptions.ajv)
146 }
147
148 /**
149 * This method will be called when a serializer must be setup.
150 * Do not setup the compiler more than once
151 * @param {object} serverOptions the fastify server options
152 */
153 setupSerializer (serverOptions) {
154 const isReady = this.serializerCompiler !== undefined && !this.addedSchemas
155 if (isReady) {
156 return
157 }
158
159 this.serializerCompiler = this.getSerializerBuilder()(this.schemaBucket.getSchemas(), serverOptions.serializerOpts)
160 }
161}
162
163SchemaController.buildSchemaController = buildSchemaController
164module.exports = SchemaController