forked from Automattic/mongoose
/
virtuals.test.ts
122 lines (101 loc) · 3.23 KB
/
virtuals.test.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
import { Document, Model, Schema, model, InferSchemaType, FlatRecord, ObtainSchemaGeneric } from 'mongoose';
import { expectType } from 'tsd';
interface IPerson {
_id: number;
firstName: string;
lastName: string;
fullName: string;
}
interface IPet {
name: string;
isDeleted: boolean;
ownerId: number;
owner: IPerson;
}
interface PetVirtuals {
owner: IPerson;
}
const personSchema = new Schema<IPerson & Document, Model<IPerson & Document>, IPerson>({
_id: { type: Number, required: true },
firstName: { type: String, required: true },
lastName: { type: String, required: true }
});
const petSchema = new Schema<IPet & Document, Model<IPet & Document>, IPet>({
name: { type: String, required: true },
ownerId: { type: Number, required: true },
isDeleted: { type: Boolean, default: false }
});
// Virtual getters and setters
personSchema.virtual('fullName')
.get(function(this: IPerson, value, virtual, doc) {
return `${this.firstName} ${this.lastName}`;
})
.set(function(this: IPerson, value, virtual, doc) {
const splittedName = value.split(' ');
this.firstName = splittedName[0];
this.lastName = splittedName[1];
});
personSchema.virtual('fullNameAlt')
.get(function() {
return `${this.firstName} ${this.lastName}`;
})
.set(function(value) {
const splittedName = value.split(' ');
this.firstName = splittedName[0];
this.lastName = splittedName[1];
});
// Populated virtuals
petSchema.virtual('owner', {
ref: 'Person',
localField: 'ownerId',
foreignField: '_id',
justOne: true,
autopopulate: true,
options: {
match: { isDeleted: false }
}
});
const Person = model<IPerson>('Person', personSchema);
const Pet = model<IPet>('Pet', petSchema);
(async() => {
const person = await Person.create({ _id: 1, firstName: 'John', lastName: 'Wick' });
await Pet.create({ name: 'Andy', ownerId: person._id });
const pet = await Pet.findOne().orFail().populate('owner');
console.log(pet.owner.fullName); // John Wick
})();
function gh11543() {
const personSchema = new Schema<IPerson, Model<IPerson, {}, {}, PetVirtuals>, {}, {}, PetVirtuals>({
_id: { type: Number, required: true },
firstName: { type: String, required: true },
lastName: { type: String, required: true }
});
expectType<PetVirtuals>(personSchema.virtuals);
}
function autoTypedVirtuals() {
type AutoTypedSchemaType = InferSchemaType<typeof testSchema>;
type VirtualsType = { domain: string };
type InferredDocType = FlatRecord<AutoTypedSchemaType & ObtainSchemaGeneric<typeof testSchema, 'TVirtuals'>>;
const testSchema = new Schema({
email: {
type: String,
required: [true, 'email is required']
}
}, {
virtuals: {
domain: {
get() {
expectType<Document<any, any, { email: string }> & AutoTypedSchemaType>(this);
return this.email.slice(this.email.indexOf('@') + 1);
},
set() {
expectType<Document<any, any, AutoTypedSchemaType> & AutoTypedSchemaType>(this);
},
options: {}
}
}
});
const TestModel = model('AutoTypedVirtuals', testSchema);
const doc = new TestModel();
expectType<string>(doc.domain);
expectType<FlatRecord<AutoTypedSchemaType & VirtualsType >>({} as InferredDocType);
}