1 | ;
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | exports._buildSchema = void 0;
|
4 | const mongoose = require("mongoose");
|
5 | const logSettings_1 = require("../logSettings");
|
6 | const typegoose_1 = require("../typegoose");
|
7 | const constants_1 = require("./constants");
|
8 | const data_1 = require("./data");
|
9 | const errors_1 = require("./errors");
|
10 | const processProp_1 = require("./processProp");
|
11 | const utils_1 = require("./utils");
|
12 | /**
|
13 | * Internal Schema Builder for Classes
|
14 | * This Function should not be used directly outside of typegoose internals, use "buildSchema" from typegoose.ts directly
|
15 | * @param cl The Class to build a Model from
|
16 | * @param origSch A Schema to clone and extend onto
|
17 | * @param opt Overwrite SchemaOptions (Merged with Decorator Options)
|
18 | * @param isFinalSchema Set if this Schema is the final (top-level) to build, only when "true" are discriminators, hooks, virtuals, etc applied
|
19 | * @param overwriteNaming Overwrite options for name generation
|
20 | * @param extraOptions Extra options to affect what needs to be done
|
21 | * @returns Returns the Build Schema
|
22 | * @private
|
23 | */
|
24 | function _buildSchema(cl, origSch, opt, isFinalSchema = true, overwriteNaming, extraOptions) {
|
25 | (0, utils_1.assertionIsClass)(cl);
|
26 | (0, utils_1.assignGlobalModelOptions)(cl); // to ensure global options are applied to the current class
|
27 | // Options sanity check
|
28 | opt = (0, utils_1.mergeSchemaOptions)((0, utils_1.isNullOrUndefined)(opt) || typeof opt !== 'object' ? {} : opt, cl);
|
29 | const finalName = (0, utils_1.getName)(cl, overwriteNaming);
|
30 | logSettings_1.logger.debug('_buildSchema Called for %s with options:', finalName, opt);
|
31 | /** Simplify the usage */
|
32 | const Schema = mongoose.Schema;
|
33 | const ropt = Reflect.getMetadata(constants_1.DecoratorKeys.ModelOptions, cl) ?? {};
|
34 | const schemaOptions = Object.assign({}, ropt?.schemaOptions ?? {}, opt);
|
35 | const decorators = Reflect.getMetadata(constants_1.DecoratorKeys.PropCache, cl.prototype);
|
36 | if (!(0, utils_1.isNullOrUndefined)(decorators)) {
|
37 | for (const decorator of decorators.values()) {
|
38 | (0, processProp_1.processProp)({ ...decorator, cl: cl });
|
39 | }
|
40 | }
|
41 | let sch;
|
42 | {
|
43 | const schemaReflectTarget = (0, utils_1.getCachedSchema)(cl);
|
44 | if (!(origSch instanceof Schema)) {
|
45 | sch = new Schema(schemaReflectTarget, schemaOptions);
|
46 | }
|
47 | else {
|
48 | sch = origSch.clone();
|
49 | sch.add(schemaReflectTarget);
|
50 | }
|
51 | }
|
52 | sch.loadClass(cl);
|
53 | // in the block below are all the things that need to be done for each class, not just the final schema
|
54 | // for example when using "getOwnMetadata" over "getMetadata" (and having a clone in there)
|
55 | {
|
56 | /** Get Metadata for indices */
|
57 | const indices = Reflect.getOwnMetadata(constants_1.DecoratorKeys.Index, cl);
|
58 | const buildIndexes = typeof extraOptions?.buildIndexes === 'boolean' ? extraOptions?.buildIndexes : true;
|
59 | if (Array.isArray(indices) && buildIndexes) {
|
60 | for (const index of indices) {
|
61 | logSettings_1.logger.debug('Applying Index:', index);
|
62 | sch.index(index.fields, index.options);
|
63 | }
|
64 | }
|
65 | }
|
66 | if (isFinalSchema) {
|
67 | /** Get Metadata for Nested Discriminators */
|
68 | const disMap = Reflect.getMetadata(constants_1.DecoratorKeys.NestedDiscriminators, cl);
|
69 | if (disMap instanceof Map) {
|
70 | for (const [key, discriminators] of disMap) {
|
71 | logSettings_1.logger.debug('Applying Nested Discriminators for:', key, discriminators);
|
72 | const path = sch.path(key);
|
73 | (0, utils_1.assertion)(!(0, utils_1.isNullOrUndefined)(path), () => new errors_1.PathNotInSchemaError(finalName, key));
|
74 | (0, utils_1.assertion)(typeof path.discriminator === 'function', () => new errors_1.NoDiscriminatorFunctionError(finalName, key));
|
75 | for (const { type: child, value: childName } of discriminators) {
|
76 | const childSch = (0, utils_1.getName)(child) === finalName ? sch : (0, typegoose_1.buildSchema)(child);
|
77 | const discriminatorKey = childSch.get('discriminatorKey');
|
78 | if (!!discriminatorKey && childSch.path(discriminatorKey)) {
|
79 | // skip this check, otherwise "extends DiscriminatorBase" would not be allowed (discriminators cannot have the discriminator key defined multiple times)
|
80 | childSch.paths[discriminatorKey].options.$skipDiscriminatorCheck = true;
|
81 | }
|
82 | path.discriminator((0, utils_1.getName)(child), childSch, childName);
|
83 | }
|
84 | }
|
85 | }
|
86 | // Hooks
|
87 | {
|
88 | /** Get Metadata for PreHooks */
|
89 | const preHooks = Reflect.getMetadata(constants_1.DecoratorKeys.HooksPre, cl);
|
90 | if (Array.isArray(preHooks)) {
|
91 | // "as any" is used here because mongoose explicitly types out many methods, but the input type (from IHooksArray) is a combination of multiple types
|
92 | preHooks.forEach((obj) => callCorrectSignature(sch, 'pre', obj));
|
93 | }
|
94 | /** Get Metadata for PreHooks */
|
95 | const postHooks = Reflect.getMetadata(constants_1.DecoratorKeys.HooksPost, cl);
|
96 | if (Array.isArray(postHooks)) {
|
97 | // "as any" is used here because mongoose explicitly types out many methods, but the input type (from IHooksArray) is a combination of multiple types
|
98 | postHooks.forEach((obj) => callCorrectSignature(sch, 'post', obj));
|
99 | }
|
100 | }
|
101 | /** Get Metadata for Virtual Populates */
|
102 | const virtuals = Reflect.getMetadata(constants_1.DecoratorKeys.VirtualPopulate, cl);
|
103 | if (virtuals instanceof Map) {
|
104 | for (const [key, options] of virtuals) {
|
105 | logSettings_1.logger.debug('Applying Virtual Populates:', key, options);
|
106 | sch.virtual(key, options);
|
107 | }
|
108 | }
|
109 | /** Get Metadata for Query Methods */
|
110 | const queryMethods = Reflect.getMetadata(constants_1.DecoratorKeys.QueryMethod, cl);
|
111 | if (queryMethods instanceof Map) {
|
112 | for (const [funcName, func] of queryMethods) {
|
113 | logSettings_1.logger.debug('Applying Query Method:', funcName, func);
|
114 | sch.query[funcName] = func;
|
115 | }
|
116 | }
|
117 | /** Get Metadata for indices */
|
118 | const plugins = Reflect.getMetadata(constants_1.DecoratorKeys.Plugins, cl);
|
119 | if (Array.isArray(plugins)) {
|
120 | for (const plugin of plugins) {
|
121 | logSettings_1.logger.debug('Applying Plugin:', plugin);
|
122 | sch.plugin(plugin.mongoosePlugin, plugin.options);
|
123 | }
|
124 | }
|
125 | // this method is to get the typegoose name of the model/class if it is user-handled (like buildSchema, then manually mongoose.model)
|
126 | sch.method('typegooseName', () => {
|
127 | return finalName;
|
128 | });
|
129 | }
|
130 | // add the class to the constructors map
|
131 | data_1.constructors.set(finalName, cl);
|
132 | return sch;
|
133 | }
|
134 | exports._buildSchema = _buildSchema;
|
135 | /**
|
136 | * Helper function to call the correct signature for a given "fnToCall" (pre / post hooks)
|
137 | * @param fnToCall The function to call (sch.pre / sch.post)
|
138 | * @param obj The object to call as arguments with
|
139 | */
|
140 | function callCorrectSignature(sch, fn, obj) {
|
141 | // we have to bind "sch", otherwise "this" will not be defined in the "pre / post" functions
|
142 | const fnToCall = (fn === 'pre' ? sch.pre : sch.post).bind(sch);
|
143 | if (!(0, utils_1.isNullOrUndefined)(obj.options)) {
|
144 | return fnToCall(obj.methods, obj.options, obj.func);
|
145 | }
|
146 | return fnToCall(obj.methods, obj.func);
|
147 | }
|
148 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2NoZW1hLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2ludGVybmFsL3NjaGVtYS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSxxQ0FBcUM7QUFDckMsZ0RBQXdDO0FBQ3hDLDRDQUEyQztBQWMzQywyQ0FBNEM7QUFDNUMsaUNBQXNDO0FBQ3RDLHFDQUE4RTtBQUM5RSwrQ0FBNEM7QUFDNUMsbUNBUWlCO0FBRWpCOzs7Ozs7Ozs7OztHQVdHO0FBQ0gsU0FBZ0IsWUFBWSxDQUMxQixFQUFLLEVBQ0wsT0FBOEIsRUFDOUIsR0FBNEIsRUFDNUIsZ0JBQXlCLElBQUksRUFDN0IsZUFBZ0MsRUFDaEMsWUFBa0M7SUFFbEMsSUFBQSx3QkFBZ0IsRUFBQyxFQUFFLENBQUMsQ0FBQztJQUVyQixJQUFBLGdDQUF3QixFQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsNERBQTREO0lBRTFGLHVCQUF1QjtJQUN2QixHQUFHLEdBQUcsSUFBQSwwQkFBa0IsRUFBQyxJQUFBLHlCQUFpQixFQUFDLEdBQUcsQ0FBQyxJQUFJLE9BQU8sR0FBRyxLQUFLLFFBQVEsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxHQUFHLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFFM0YsTUFBTSxTQUFTLEdBQUcsSUFBQSxlQUFPLEVBQUMsRUFBRSxFQUFFLGVBQWUsQ0FBQyxDQUFDO0lBRS9DLG9CQUFNLENBQUMsS0FBSyxDQUFDLDBDQUEwQyxFQUFFLFNBQVMsRUFBRSxHQUFHLENBQUMsQ0FBQztJQUV6RSx5QkFBeUI7SUFDekIsTUFBTSxNQUFNLEdBQUcsUUFBUSxDQUFDLE1BQU0sQ0FBQztJQUMvQixNQUFNLElBQUksR0FBa0IsT0FBTyxDQUFDLFdBQVcsQ0FBQyx5QkFBYSxDQUFDLFlBQVksRUFBRSxFQUFFLENBQUMsSUFBSSxFQUFFLENBQUM7SUFDdEYsTUFBTSxhQUFhLEdBQUcsTUFBTSxDQUFDLE1BQU0sQ0FBQyxFQUFFLEVBQUUsSUFB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 |
\ | No newline at end of file |