Skip to content

Commit

Permalink
Merge pull request #11947 from Automattic/6.4
Browse files Browse the repository at this point in the history
6.4
  • Loading branch information
vkarpov15 committed Jun 17, 2022
2 parents 4e7e6ca + 40fef4a commit 259cc7f
Show file tree
Hide file tree
Showing 49 changed files with 5,043 additions and 312 deletions.
95 changes: 61 additions & 34 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,43 +4,70 @@
],
"ignorePatterns": [
"docs",
"tools",
"dist",
"test/files/*"
"website.js",
"test/files/*",
"benchmarks"
],
"overrides": [{
"files": [
"**/*.{ts,tsx}"
],
"extends": [
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended"
],
"plugins": [
"@typescript-eslint"
],
"rules": {
"@typescript-eslint/triple-slash-reference": "off",
"spaced-comment": ["error", "always", {
"markers": ["/"]
}],
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/ban-types": "off",
"@typescript-eslint/no-unused-vars": "off",
"@typescript-eslint/explicit-module-boundary-types": "off",
"@typescript-eslint/indent": ["error", 2, {
"SwitchCase": 1
}],
"@typescript-eslint/prefer-optional-chain": "error",
"@typescript-eslint/brace-style": "error",
"@typescript-eslint/no-dupe-class-members": "error",
"@typescript-eslint/no-redeclare": "error",
"@typescript-eslint/type-annotation-spacing": "error",
"@typescript-eslint/object-curly-spacing": ["error", "always"],
"@typescript-eslint/semi": "error",
"@typescript-eslint/space-before-function-paren": ["error", "never"],
"@typescript-eslint/space-infix-ops": "off"
"overrides": [
{
"files": [
"**/*.{ts,tsx}"
],
"extends": [
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended"
],
"plugins": [
"@typescript-eslint"
],
"rules": {
"@typescript-eslint/triple-slash-reference": "off",
"spaced-comment": [
"error",
"always",
{
"block": {
"markers": [
"!"
],
"balanced": true
},
"markers": [
"/"
]
}
],
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/ban-types": "off",
"@typescript-eslint/no-unused-vars": "off",
"@typescript-eslint/explicit-module-boundary-types": "off",
"@typescript-eslint/indent": [
"error",
2,
{
"SwitchCase": 1
}
],
"@typescript-eslint/prefer-optional-chain": "error",
"@typescript-eslint/brace-style": "error",
"@typescript-eslint/no-dupe-class-members": "error",
"@typescript-eslint/no-redeclare": "error",
"@typescript-eslint/type-annotation-spacing": "error",
"@typescript-eslint/object-curly-spacing": [
"error",
"always"
],
"@typescript-eslint/semi": "error",
"@typescript-eslint/space-before-function-paren": [
"error",
"never"
],
"@typescript-eslint/space-infix-ops": "off"
}
}
}],
],
"plugins": [
"mocha-no-only"
],
Expand Down
48 changes: 44 additions & 4 deletions docs/guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,9 +143,18 @@ We may also define our own custom document instance methods.

```javascript
// define a schema
const animalSchema = new Schema({ name: String, type: String });
const animalSchema = new Schema({ name: String, type: String },
{
// Assign a function to the "methods" object of our animalSchema through schema options.
// By following this approach, there is no need to create a separate TS type to define the type of the instance functions.
methods:{
findSimilarTypes(cb){
return mongoose.model('Animal').find({ type: this.type }, cb);
}
}
});

// assign a function to the "methods" object of our animalSchema
// Or, assign a function to the "methods" object of our animalSchema
animalSchema.methods.findSimilarTypes = function(cb) {
return mongoose.model('Animal').find({ type: this.type }, cb);
};
Expand All @@ -169,14 +178,28 @@ dog.findSimilarTypes((err, dogs) => {

<h3 id="statics"><a href="#statics">Statics</a></h3>

You can also add static functions to your model. There are two equivalent
You can also add static functions to your model. There are three equivalent
ways to add a static:

- Add a function property to the second argument of the schema-constructor (`statics`)
- Add a function property to `schema.statics`
- Call the [`Schema#static()` function](/docs/api.html#schema_Schema-static)

```javascript
// Assign a function to the "statics" object of our animalSchema

// define a schema
const animalSchema = new Schema({ name: String, type: String },
{
// Assign a function to the "statics" object of our animalSchema through schema options.
// By following this approach, there is no need to create a separate TS type to define the type of the statics functions.
statics:{
findByName(name){
return this.find({ name: new RegExp(name, 'i') });
}
}
});

// Or, Assign a function to the "statics" object of our animalSchema
animalSchema.statics.findByName = function(name) {
return this.find({ name: new RegExp(name, 'i') });
};
Expand All @@ -197,6 +220,20 @@ but for mongoose queries. Query helper methods let you extend mongoose's
[chainable query builder API](./queries.html).

```javascript

// define a schema
const animalSchema = new Schema({ name: String, type: String },
{
// Assign a function to the "query" object of our animalSchema through schema options.
// By following this approach, there is no need to create a separate TS type to define the type of the query functions.
query:{
byName(name){
return this.where({ name: new RegExp(name, 'i') })
}
}
});

// Or, Assign a function to the "query" object of our animalSchema
animalSchema.query.byName = function(name) {
return this.where({ name: new RegExp(name, 'i') })
};
Expand Down Expand Up @@ -409,6 +446,7 @@ Valid options:
- [read](#read)
- [writeConcern](#writeConcern)
- [shardKey](#shardKey)
- [statics](#statics)
- [strict](#strict)
- [strictQuery](#strictQuery)
- [toJSON](#toJSON)
Expand All @@ -423,6 +461,8 @@ Valid options:
- [skipVersioning](#skipVersioning)
- [timestamps](#timestamps)
- [storeSubdocValidationError](#storeSubdocValidationError)
- [methods](#methods)
- [query](#query-helpers)

<h3 id="autoIndex"><a href="#autoIndex">option: autoIndex</a></h3>

Expand Down
33 changes: 32 additions & 1 deletion docs/typescript/query-helpers.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@ var Project = mongoose.model('Project', ProjectSchema);
Project.find().where('stars').gt(1000).byName('mongoose');
```

In TypeScript, Mongoose's `Model` takes 3 generic parameters:
In TypeScript, Mongoose does support manually typed and automatically typed Query Helpers.

1- Manually typed:
Mongoose's `Model` takes 3 generic parameters:

1. The `DocType`
2. a `TQueryHelpers` type
Expand Down Expand Up @@ -58,4 +61,32 @@ async function run(): Promise<void> {
// Equivalent to `ProjectModel.find({ stars: { $gt: 1000 }, name: 'mongoose' })`
await ProjectModel.find().where('stars').gt(1000).byName('mongoose');
}
```

2- Automatically typed:
Mongoose does support auto typed Query Helpers that it are supplied in schema options.
Query Helpers functions can be defined as following:

```typescript
import { Schema, model } from 'mongoose';

const schema = new Schema({
name: { type: String, required: true },
stars: { type: Number, required: true }
}, {
query: {
byName(name) {
return this.find({ name: name });
}
}
});

const ProjectModel = model(
'Project',
schema
);

// Equivalent to `ProjectModel.find({ stars: { $gt: 1000 }, name: 'mongoose' })`
await ProjectModel.find().where('stars').gt(1000).byName('mongoose');
}
```
49 changes: 42 additions & 7 deletions docs/typescript/schemas.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
# Schemas in TypeScript

Mongoose [schemas](/docs/guide.html) are how you tell Mongoose what your documents look like.
Mongoose schemas are separate from TypeScript interfaces, so you need to define both a _document interface_ and a _schema_.
Mongoose schemas are separate from TypeScript interfaces, so you need to define both a _document interface_ and a _schema_ until V6.3.1.
Mongoose supports auto typed schemas so you don't need to define additional typescript interface anymore but you are still able to do so.
Mongoose provides a `InferSchemaType`, which infers the type of the auto typed schema document when needed.

`Until mongoose V6.3.1:`

```typescript
import { Schema } from 'mongoose';
Expand All @@ -21,6 +25,37 @@ const schema = new Schema<User>({
});
```

`another approach:`

```typescript
import { Schema, InferSchemaType } from 'mongoose';

// Document interface
// No need to define TS interface any more.
// interface User {
// name: string;
// email: string;
// avatar?: string;
// }

// Schema
const schema = new Schema({
name: { type: String, required: true },
email: { type: String, required: true },
avatar: String
});

type User = InferSchemaType<typeof schema>;
// InferSchemaType will determine the type as follows:
// type User = {
// name: string;
// email: string;
// avatar?: string;
// }


```

By default, Mongoose does **not** check if your document interface lines up with your schema.
For example, the above code won't throw an error if `email` is optional in the document interface, but `required` in `schema`.

Expand Down Expand Up @@ -51,7 +86,7 @@ Mongoose wraps `DocType` in a Mongoose document for cases like the `this` parame
For example:

```typescript
schema.pre('save', function(): void {
schema.pre('save', function (): void {
console.log(this.name); // TypeScript knows that `this` is a `mongoose.Document & User` by default
});
```
Expand Down Expand Up @@ -102,7 +137,7 @@ interface User {
const schema = new Schema<User, Model<User>>({
name: { type: String, required: true },
email: { type: String, required: true },
avatar: String
avatar: String,
});
```

Expand All @@ -121,13 +156,13 @@ interface BlogPost {
}

interface User {
tags: Types.Array<string>,
blogPosts: Types.DocumentArray<BlogPost>
tags: Types.Array<string>;
blogPosts: Types.DocumentArray<BlogPost>;
}

const schema = new Schema<User, Model<User>>({
tags: [String],
blogPosts: [{ title: String }]
blogPosts: [{ title: String }],
});
```

Expand All @@ -139,4 +174,4 @@ If you use `Types.DocumentArray` in the above case, you'll be able to `push()` a
const user = new User({ blogPosts: [] });

user.blogPosts.push({ title: 'test' }); // Would not work if you did `blogPosts: BlogPost[]`
```
```
21 changes: 21 additions & 0 deletions docs/typescript/statics-and-methods.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,27 @@ const User = model<IUser, UserModel>('User', schema);
const answer: number = User.myStaticMethod(); // 42
```

Mongoose does support auto typed static functions now that it is supplied in schema options.
Statics functions can be defined as following:

```typescript
import { Schema, model } from 'mongoose';

const schema = new Schema(
{ name: String },
{
statics: {
myStaticMethod() {
return 42;
},
},
}
);

const User = model('User', schema);

const answer = User.myStaticMethod(); // 42
```
## Both Methods and Statics

Below is how you can define a model that has both methods and statics.
Expand Down

0 comments on commit 259cc7f

Please sign in to comment.