mongoose 8.20.0 → 9.0.0-rc0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/eslint.config.mjs +198 -0
  2. package/lib/aggregate.js +17 -73
  3. package/lib/cast/bigint.js +1 -1
  4. package/lib/cast/double.js +1 -1
  5. package/lib/cast/uuid.js +5 -48
  6. package/lib/cast.js +2 -2
  7. package/lib/connection.js +0 -1
  8. package/lib/cursor/aggregationCursor.js +14 -24
  9. package/lib/cursor/queryCursor.js +7 -14
  10. package/lib/document.js +125 -121
  11. package/lib/drivers/node-mongodb-native/connection.js +3 -10
  12. package/lib/error/objectParameter.js +1 -2
  13. package/lib/error/validation.js +0 -8
  14. package/lib/helpers/clone.js +1 -1
  15. package/lib/helpers/common.js +1 -1
  16. package/lib/helpers/indexes/isIndexEqual.js +0 -1
  17. package/lib/helpers/model/applyDefaultsToPOJO.js +2 -2
  18. package/lib/helpers/model/applyHooks.js +43 -53
  19. package/lib/helpers/model/applyMethods.js +2 -2
  20. package/lib/helpers/model/applyStaticHooks.js +1 -48
  21. package/lib/helpers/model/castBulkWrite.js +1 -1
  22. package/lib/helpers/parallelLimit.js +18 -36
  23. package/lib/helpers/pluralize.js +3 -3
  24. package/lib/helpers/populate/assignRawDocsToIdStructure.js +1 -8
  25. package/lib/helpers/populate/createPopulateQueryFilter.js +1 -1
  26. package/lib/helpers/populate/getModelsMapForPopulate.js +17 -9
  27. package/lib/helpers/populate/getSchemaTypes.js +5 -5
  28. package/lib/helpers/query/cast$expr.js +8 -10
  29. package/lib/helpers/query/castFilterPath.js +1 -1
  30. package/lib/helpers/query/castUpdate.js +14 -12
  31. package/lib/helpers/query/getEmbeddedDiscriminatorPath.js +1 -1
  32. package/lib/helpers/schema/applyPlugins.js +1 -1
  33. package/lib/helpers/schema/getIndexes.js +1 -7
  34. package/lib/helpers/timestamps/setupTimestamps.js +3 -6
  35. package/lib/helpers/updateValidators.js +57 -111
  36. package/lib/model.js +419 -607
  37. package/lib/mongoose.js +41 -13
  38. package/lib/plugins/saveSubdocs.js +24 -51
  39. package/lib/plugins/sharding.js +5 -4
  40. package/lib/plugins/validateBeforeSave.js +3 -13
  41. package/lib/query.js +101 -145
  42. package/lib/queryHelpers.js +2 -2
  43. package/lib/schema/array.js +41 -84
  44. package/lib/schema/documentArray.js +57 -94
  45. package/lib/schema/documentArrayElement.js +16 -11
  46. package/lib/schema/string.js +1 -1
  47. package/lib/schema/subdocument.js +22 -28
  48. package/lib/schema/uuid.js +0 -21
  49. package/lib/schema.js +81 -39
  50. package/lib/schemaType.js +39 -57
  51. package/lib/types/array/index.js +2 -2
  52. package/lib/types/array/methods/index.js +4 -4
  53. package/lib/types/arraySubdocument.js +1 -1
  54. package/lib/types/buffer.js +10 -10
  55. package/lib/types/decimal128.js +1 -1
  56. package/lib/types/documentArray/index.js +1 -1
  57. package/lib/types/documentArray/methods/index.js +5 -3
  58. package/lib/types/double.js +1 -1
  59. package/lib/types/objectid.js +1 -1
  60. package/lib/types/subdocument.js +15 -43
  61. package/lib/types/uuid.js +1 -1
  62. package/lib/utils.js +1 -8
  63. package/lib/validOptions.js +3 -3
  64. package/package.json +11 -24
  65. package/types/connection.d.ts +20 -11
  66. package/types/document.d.ts +95 -26
  67. package/types/index.d.ts +143 -39
  68. package/types/inferhydrateddoctype.d.ts +115 -0
  69. package/types/inferrawdoctype.d.ts +99 -75
  70. package/types/inferschematype.d.ts +17 -3
  71. package/types/middlewares.d.ts +0 -2
  72. package/types/models.d.ts +131 -199
  73. package/types/mongooseoptions.d.ts +6 -5
  74. package/types/pipelinestage.d.ts +1 -1
  75. package/types/query.d.ts +71 -139
  76. package/types/schemaoptions.d.ts +1 -1
  77. package/types/schematypes.d.ts +14 -10
  78. package/types/types.d.ts +3 -4
  79. package/types/utility.d.ts +68 -48
  80. package/types/validation.d.ts +18 -14
  81. package/browser.js +0 -8
  82. package/dist/browser.umd.js +0 -2
  83. package/lib/browser.js +0 -141
  84. package/lib/browserDocument.js +0 -101
  85. package/lib/documentProvider.js +0 -30
  86. package/lib/drivers/browser/binary.js +0 -14
  87. package/lib/drivers/browser/decimal128.js +0 -7
  88. package/lib/drivers/browser/index.js +0 -13
  89. package/lib/drivers/browser/objectid.js +0 -29
  90. package/lib/helpers/promiseOrCallback.js +0 -54
@@ -0,0 +1,198 @@
1
+ import { defineConfig, globalIgnores } from 'eslint/config';
2
+ import mochaNoOnly from 'eslint-plugin-mocha-no-only';
3
+ import globals from 'globals';
4
+ import tseslint from 'typescript-eslint';
5
+ import js from '@eslint/js';
6
+
7
+ export default defineConfig([
8
+ globalIgnores([
9
+ '**/tools',
10
+ '**/dist',
11
+ 'test/files/*',
12
+ '**/benchmarks',
13
+ '**/*.min.js',
14
+ '**/docs/js/native.js',
15
+ '!**/.*',
16
+ '**/node_modules',
17
+ '**/.git',
18
+ '**/data'
19
+ ]),
20
+ js.configs.recommended,
21
+ // general options
22
+ {
23
+ languageOptions: {
24
+ globals: globals.node,
25
+ ecmaVersion: 2022, // nodejs 18.0.0,
26
+ sourceType: 'commonjs'
27
+ },
28
+ rules: {
29
+ 'comma-style': 'error',
30
+
31
+ indent: ['error', 2, {
32
+ SwitchCase: 1,
33
+ VariableDeclarator: 2
34
+ }],
35
+
36
+ 'keyword-spacing': 'error',
37
+ 'no-whitespace-before-property': 'error',
38
+ 'no-buffer-constructor': 'warn',
39
+ 'no-console': 'off',
40
+ 'no-constant-condition': 'off',
41
+ 'no-multi-spaces': 'error',
42
+ 'func-call-spacing': 'error',
43
+ 'no-trailing-spaces': 'error',
44
+ 'no-undef': 'error',
45
+ 'no-unneeded-ternary': 'error',
46
+ 'no-const-assign': 'error',
47
+ 'no-useless-rename': 'error',
48
+ 'no-dupe-keys': 'error',
49
+ 'space-in-parens': ['error', 'never'],
50
+
51
+ 'spaced-comment': ['error', 'always', {
52
+ block: {
53
+ markers: ['!'],
54
+ balanced: true
55
+ }
56
+ }],
57
+
58
+ 'key-spacing': ['error', {
59
+ beforeColon: false,
60
+ afterColon: true
61
+ }],
62
+
63
+ 'comma-spacing': ['error', {
64
+ before: false,
65
+ after: true
66
+ }],
67
+
68
+ 'array-bracket-spacing': 1,
69
+
70
+ 'arrow-spacing': ['error', {
71
+ before: true,
72
+ after: true
73
+ }],
74
+
75
+ 'object-curly-spacing': ['error', 'always'],
76
+ 'comma-dangle': ['error', 'never'],
77
+ 'no-unreachable': 'error',
78
+ quotes: ['error', 'single'],
79
+ 'quote-props': ['error', 'as-needed'],
80
+ semi: 'error',
81
+ 'no-extra-semi': 'error',
82
+ 'semi-spacing': 'error',
83
+ 'no-spaced-func': 'error',
84
+ 'no-throw-literal': 'error',
85
+ 'space-before-blocks': 'error',
86
+ 'space-before-function-paren': ['error', 'never'],
87
+ 'space-infix-ops': 'error',
88
+ 'space-unary-ops': 'error',
89
+ 'no-var': 'warn',
90
+ 'prefer-const': 'warn',
91
+ strict: ['error', 'global'],
92
+
93
+ 'no-restricted-globals': ['error', {
94
+ name: 'context',
95
+ message: 'Don\'t use Mocha\'s global context'
96
+ }],
97
+
98
+ 'no-prototype-builtins': 'off',
99
+ 'no-empty': 'off',
100
+ 'eol-last': 'warn',
101
+
102
+ 'no-multiple-empty-lines': ['warn', {
103
+ max: 2
104
+ }]
105
+ }
106
+ },
107
+ // general typescript options
108
+ {
109
+ files: ['**/*.{ts,tsx}', '**/*.md/*.ts', '**/*.md/*.typescript'],
110
+ extends: [
111
+ tseslint.configs.recommended
112
+ ],
113
+ languageOptions: {
114
+ parserOptions: {
115
+ projectService: {
116
+ allowDefaultProject: [],
117
+ defaultProject: 'tsconfig.json'
118
+ }
119
+ }
120
+ },
121
+ rules: {
122
+ '@typescript-eslint/triple-slash-reference': 'off',
123
+ '@typescript-eslint/no-non-null-assertion': 'off',
124
+ '@typescript-eslint/no-empty-function': 'off',
125
+
126
+ 'spaced-comment': ['error', 'always', {
127
+ block: {
128
+ markers: ['!'],
129
+ balanced: true
130
+ },
131
+
132
+ markers: ['/']
133
+ }],
134
+
135
+ '@typescript-eslint/no-explicit-any': 'off',
136
+ '@typescript-eslint/ban-types': 'off',
137
+ '@typescript-eslint/no-unused-vars': 'off',
138
+ '@typescript-eslint/explicit-module-boundary-types': 'off',
139
+ '@typescript-eslint/prefer-optional-chain': 'error',
140
+ '@typescript-eslint/no-dupe-class-members': 'error',
141
+ '@typescript-eslint/no-redeclare': 'error',
142
+ '@typescript-eslint/space-infix-ops': 'off',
143
+ '@typescript-eslint/no-require-imports': 'off',
144
+ '@typescript-eslint/no-empty-object-type': 'off',
145
+ '@typescript-eslint/no-wrapper-object-types': 'off',
146
+ '@typescript-eslint/no-unused-expressions': 'off',
147
+ '@typescript-eslint/no-unsafe-function-type': 'off'
148
+ }
149
+ },
150
+ // type test specific options
151
+ {
152
+ files: ['test/types/**/*.ts'],
153
+ rules: {
154
+ '@typescript-eslint/no-empty-interface': 'off'
155
+ }
156
+ },
157
+ // test specific options (including type tests)
158
+ {
159
+ files: ['test/**/*.js', 'test/**/*.ts'],
160
+ ignores: ['deno*.mjs'],
161
+ plugins: {
162
+ 'mocha-no-only': mochaNoOnly
163
+ },
164
+ languageOptions: {
165
+ globals: globals.mocha
166
+ },
167
+ rules: {
168
+ 'no-self-assign': 'off',
169
+ 'mocha-no-only/mocha-no-only': ['error']
170
+ }
171
+ },
172
+ // deno specific options
173
+ {
174
+ files: ['**/deno*.mjs'],
175
+ languageOptions: {
176
+ globals: {
177
+ // "globals" currently has no definition for deno
178
+ Deno: 'readonly'
179
+ }
180
+ }
181
+ },
182
+ // general options for module files
183
+ {
184
+ files: ['**/*.mjs'],
185
+ languageOptions: {
186
+ sourceType: 'module'
187
+ }
188
+ },
189
+ // doc script specific options
190
+ {
191
+ files: ['**/docs/js/**/*.js'],
192
+ languageOptions: {
193
+ globals: {
194
+ ...Object.fromEntries(Object.entries(globals.node).map(([key]) => [key, 'off'])),
195
+ ...globals.browser }
196
+ }
197
+ }
198
+ ]);
package/lib/aggregate.js CHANGED
@@ -800,18 +800,11 @@ Aggregate.prototype.explain = async function explain(verbosity) {
800
800
 
801
801
  prepareDiscriminatorPipeline(this._pipeline, this._model.schema);
802
802
 
803
- await new Promise((resolve, reject) => {
804
- model.hooks.execPre('aggregate', this, error => {
805
- if (error) {
806
- const _opts = { error: error };
807
- return model.hooks.execPost('aggregate', this, [null], _opts, error => {
808
- reject(error);
809
- });
810
- } else {
811
- resolve();
812
- }
813
- });
814
- });
803
+ try {
804
+ await model.hooks.execPre('aggregate', this);
805
+ } catch (error) {
806
+ return await model.hooks.execPost('aggregate', this, [null], { error });
807
+ }
815
808
 
816
809
  const cursor = model.collection.aggregate(this._pipeline, this.options);
817
810
 
@@ -823,26 +816,10 @@ Aggregate.prototype.explain = async function explain(verbosity) {
823
816
  try {
824
817
  result = await cursor.explain(verbosity);
825
818
  } catch (error) {
826
- await new Promise((resolve, reject) => {
827
- const _opts = { error: error };
828
- model.hooks.execPost('aggregate', this, [null], _opts, error => {
829
- if (error) {
830
- return reject(error);
831
- }
832
- return resolve();
833
- });
834
- });
819
+ return await model.hooks.execPost('aggregate', this, [null], { error });
835
820
  }
836
821
 
837
- const _opts = { error: null };
838
- await new Promise((resolve, reject) => {
839
- model.hooks.execPost('aggregate', this, [result], _opts, error => {
840
- if (error) {
841
- return reject(error);
842
- }
843
- return resolve();
844
- });
845
- });
822
+ await model.hooks.execPost('aggregate', this, [result], { error: null });
846
823
 
847
824
  return result;
848
825
  };
@@ -1079,18 +1056,11 @@ Aggregate.prototype.exec = async function exec() {
1079
1056
  prepareDiscriminatorPipeline(this._pipeline, this._model.schema);
1080
1057
  stringifyFunctionOperators(this._pipeline);
1081
1058
 
1082
- await new Promise((resolve, reject) => {
1083
- model.hooks.execPre('aggregate', this, error => {
1084
- if (error) {
1085
- const _opts = { error: error };
1086
- return model.hooks.execPost('aggregate', this, [null], _opts, error => {
1087
- reject(error);
1088
- });
1089
- } else {
1090
- resolve();
1091
- }
1092
- });
1093
- });
1059
+ try {
1060
+ await model.hooks.execPre('aggregate', this);
1061
+ } catch (error) {
1062
+ return await model.hooks.execPost('aggregate', this, [null], { error });
1063
+ }
1094
1064
 
1095
1065
  if (!this._pipeline.length) {
1096
1066
  throw new MongooseError('Aggregate has empty pipeline');
@@ -1103,27 +1073,10 @@ Aggregate.prototype.exec = async function exec() {
1103
1073
  const cursor = await collection.aggregate(this._pipeline, options);
1104
1074
  result = await cursor.toArray();
1105
1075
  } catch (error) {
1106
- await new Promise((resolve, reject) => {
1107
- const _opts = { error: error };
1108
- model.hooks.execPost('aggregate', this, [null], _opts, (error) => {
1109
- if (error) {
1110
- return reject(error);
1111
- }
1112
-
1113
- resolve();
1114
- });
1115
- });
1076
+ return await model.hooks.execPost('aggregate', this, [null], { error });
1116
1077
  }
1117
1078
 
1118
- const _opts = { error: null };
1119
- await new Promise((resolve, reject) => {
1120
- model.hooks.execPost('aggregate', this, [result], _opts, error => {
1121
- if (error) {
1122
- return reject(error);
1123
- }
1124
- return resolve();
1125
- });
1126
- });
1079
+ await model.hooks.execPost('aggregate', this, [result], { error: null });
1127
1080
 
1128
1081
  return result;
1129
1082
  };
@@ -1186,24 +1139,15 @@ Aggregate.prototype.finally = function(onFinally) {
1186
1139
  * console.log(doc.name);
1187
1140
  * }
1188
1141
  *
1189
- * Node.js 10.x supports async iterators natively without any flags. You can
1190
- * enable async iterators in Node.js 8.x using the [`--harmony_async_iteration` flag](https://github.com/tc39/proposal-async-iteration/issues/117#issuecomment-346695187).
1191
- *
1192
- * **Note:** This function is not set if `Symbol.asyncIterator` is undefined. If
1193
- * `Symbol.asyncIterator` is undefined, that means your Node.js version does not
1194
- * support async iterators.
1195
- *
1196
1142
  * @method [Symbol.asyncIterator]
1197
1143
  * @memberOf Aggregate
1198
1144
  * @instance
1199
1145
  * @api public
1200
1146
  */
1201
1147
 
1202
- if (Symbol.asyncIterator != null) {
1203
- Aggregate.prototype[Symbol.asyncIterator] = function() {
1204
- return this.cursor({ useMongooseAggCursor: true }).transformNull()._transformForAsyncIterator();
1205
- };
1206
- }
1148
+ Aggregate.prototype[Symbol.asyncIterator] = function() {
1149
+ return this.cursor({ useMongooseAggCursor: true }).transformNull()._transformForAsyncIterator();
1150
+ };
1207
1151
 
1208
1152
  /*!
1209
1153
  * Helpers
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- const { Long } = require('bson');
3
+ const { Long } = require('mongodb/lib/bson');
4
4
 
5
5
  /**
6
6
  * Given a value, cast it to a BigInt, or throw an `Error` if the value
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  const assert = require('assert');
4
- const BSON = require('bson');
4
+ const BSON = require('mongodb/lib/bson');
5
5
  const isBsonType = require('../helpers/isBsonType');
6
6
 
7
7
  /**
package/lib/cast/uuid.js CHANGED
@@ -1,43 +1,31 @@
1
1
  'use strict';
2
2
 
3
- const MongooseBuffer = require('../types/buffer');
3
+ const UUID = require('mongodb/lib/bson').UUID;
4
4
 
5
5
  const UUID_FORMAT = /[0-9a-f]{8}-[0-9a-f]{4}-[0-9][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}/i;
6
- const Binary = MongooseBuffer.Binary;
7
6
 
8
7
  module.exports = function castUUID(value) {
9
8
  if (value == null) {
10
9
  return value;
11
10
  }
12
11
 
13
- function newBuffer(initbuff) {
14
- const buff = new MongooseBuffer(initbuff);
15
- buff._subtype = 4;
16
- return buff;
12
+ if (value instanceof UUID) {
13
+ return value;
17
14
  }
18
-
19
15
  if (typeof value === 'string') {
20
16
  if (UUID_FORMAT.test(value)) {
21
- return stringToBinary(value);
17
+ return new UUID(value);
22
18
  } else {
23
19
  throw new Error(`"${value}" is not a valid UUID string`);
24
20
  }
25
21
  }
26
22
 
27
- if (Buffer.isBuffer(value)) {
28
- return newBuffer(value);
29
- }
30
-
31
- if (value instanceof Binary) {
32
- return newBuffer(value.value(true));
33
- }
34
-
35
23
  // Re: gh-647 and gh-3030, we're ok with casting using `toString()`
36
24
  // **unless** its the default Object.toString, because "[object Object]"
37
25
  // doesn't really qualify as useful data
38
26
  if (value.toString && value.toString !== Object.prototype.toString) {
39
27
  if (UUID_FORMAT.test(value.toString())) {
40
- return stringToBinary(value.toString());
28
+ return new UUID(value.toString());
41
29
  }
42
30
  }
43
31
 
@@ -45,34 +33,3 @@ module.exports = function castUUID(value) {
45
33
  };
46
34
 
47
35
  module.exports.UUID_FORMAT = UUID_FORMAT;
48
-
49
- /**
50
- * Helper function to convert the input hex-string to a buffer
51
- * @param {String} hex The hex string to convert
52
- * @returns {Buffer} The hex as buffer
53
- * @api private
54
- */
55
-
56
- function hex2buffer(hex) {
57
- // use buffer built-in function to convert from hex-string to buffer
58
- const buff = hex != null && Buffer.from(hex, 'hex');
59
- return buff;
60
- }
61
-
62
- /**
63
- * Convert a String to Binary
64
- * @param {String} uuidStr The value to process
65
- * @returns {MongooseBuffer} The binary to store
66
- * @api private
67
- */
68
-
69
- function stringToBinary(uuidStr) {
70
- // Protect against undefined & throwing err
71
- if (typeof uuidStr !== 'string') uuidStr = '';
72
- const hex = uuidStr.replace(/[{}-]/g, ''); // remove extra characters
73
- const bytes = hex2buffer(hex);
74
- const buff = new MongooseBuffer(bytes);
75
- buff._subtype = 4;
76
-
77
- return buff;
78
- }
package/lib/cast.js CHANGED
@@ -175,12 +175,12 @@ module.exports = function cast(schema, obj, options, context) {
175
175
  // If a substring of the input path resolves to an actual real path...
176
176
  if (schematype) {
177
177
  // Apply the casting; similar code for $elemMatch in schema/array.js
178
- if (schematype.caster && schematype.caster.schema) {
178
+ if (schematype.schema) {
179
179
  remainingConds = {};
180
180
  pathLastHalf = split.slice(j).join('.');
181
181
  remainingConds[pathLastHalf] = val;
182
182
 
183
- const ret = cast(schematype.caster.schema, remainingConds, options, context)[pathLastHalf];
183
+ const ret = cast(schematype.schema, remainingConds, options, context)[pathLastHalf];
184
184
  if (ret === void 0) {
185
185
  delete obj[path];
186
186
  } else {
package/lib/connection.js CHANGED
@@ -1802,7 +1802,6 @@ Connection.prototype.syncIndexes = async function syncIndexes(options = {}) {
1802
1802
  * @param {String} name The database name
1803
1803
  * @param {Object} [options]
1804
1804
  * @param {Boolean} [options.useCache=false] If true, cache results so calling `useDb()` multiple times with the same name only creates 1 connection object.
1805
- * @param {Boolean} [options.noListener=false] If true, the connection object will not make the db listen to events on the original connection. See [issue #9961](https://github.com/Automattic/mongoose/issues/9961).
1806
1805
  * @return {Connection} New Connection Object
1807
1806
  * @api public
1808
1807
  */
@@ -63,34 +63,24 @@ util.inherits(AggregationCursor, Readable);
63
63
 
64
64
  function _init(model, c, agg) {
65
65
  if (!model.collection.buffer) {
66
- model.hooks.execPre('aggregate', agg, function(err) {
67
- if (err != null) {
68
- _handlePreHookError(c, err);
69
- return;
70
- }
71
- if (typeof agg.options?.cursor?.transform === 'function') {
72
- c._transforms.push(agg.options.cursor.transform);
73
- }
74
-
75
- c.cursor = model.collection.aggregate(agg._pipeline, agg.options || {});
76
- c.emit('cursor', c.cursor);
77
- });
66
+ model.hooks.execPre('aggregate', agg).then(() => onPreComplete(null), err => onPreComplete(err));
78
67
  } else {
79
68
  model.collection.emitter.once('queue', function() {
80
- model.hooks.execPre('aggregate', agg, function(err) {
81
- if (err != null) {
82
- _handlePreHookError(c, err);
83
- return;
84
- }
69
+ model.hooks.execPre('aggregate', agg).then(() => onPreComplete(null), err => onPreComplete(err));
70
+ });
71
+ }
85
72
 
86
- if (typeof agg.options?.cursor?.transform === 'function') {
87
- c._transforms.push(agg.options.cursor.transform);
88
- }
73
+ function onPreComplete(err) {
74
+ if (err != null) {
75
+ _handlePreHookError(c, err);
76
+ return;
77
+ }
78
+ if (typeof agg.options?.cursor?.transform === 'function') {
79
+ c._transforms.push(agg.options.cursor.transform);
80
+ }
89
81
 
90
- c.cursor = model.collection.aggregate(agg._pipeline, agg.options || {});
91
- c.emit('cursor', c.cursor);
92
- });
93
- });
82
+ c.cursor = model.collection.aggregate(agg._pipeline, agg.options || {});
83
+ c.emit('cursor', c.cursor);
94
84
  }
95
85
  }
96
86
 
@@ -49,7 +49,8 @@ function QueryCursor(query) {
49
49
  this._transforms = [];
50
50
  this.model = model;
51
51
  this.options = {};
52
- model.hooks.execPre('find', query, (err) => {
52
+
53
+ const onPreComplete = (err) => {
53
54
  if (err != null) {
54
55
  if (err instanceof kareem.skipWrappedFunction) {
55
56
  const resultValue = err.args[0];
@@ -94,7 +95,9 @@ function QueryCursor(query) {
94
95
  } else {
95
96
  _getRawCursor(query, this);
96
97
  }
97
- });
98
+ };
99
+
100
+ model.hooks.execPre('find', query).then(() => onPreComplete(null), err => onPreComplete(err));
98
101
  }
99
102
 
100
103
  util.inherits(QueryCursor, Readable);
@@ -588,12 +591,7 @@ function _populateBatch() {
588
591
 
589
592
  function _nextDoc(ctx, doc, pop, callback) {
590
593
  if (ctx.query._mongooseOptions.lean) {
591
- return ctx.model.hooks.execPost('find', ctx.query, [[doc]], err => {
592
- if (err != null) {
593
- return callback(err);
594
- }
595
- callback(null, doc);
596
- });
594
+ return ctx.model.hooks.execPost('find', ctx.query, [[doc]]).then(() => callback(null, doc), err => callback(err));
597
595
  }
598
596
 
599
597
  const { model, _fields, _userProvidedFields, options } = ctx.query;
@@ -601,12 +599,7 @@ function _nextDoc(ctx, doc, pop, callback) {
601
599
  if (err != null) {
602
600
  return callback(err);
603
601
  }
604
- ctx.model.hooks.execPost('find', ctx.query, [[doc]], err => {
605
- if (err != null) {
606
- return callback(err);
607
- }
608
- callback(null, doc);
609
- });
602
+ ctx.model.hooks.execPost('find', ctx.query, [[doc]]).then(() => callback(null, doc), err => callback(err));
610
603
  });
611
604
  }
612
605