New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
types: enhanced Document's methods #13739
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -135,7 +135,7 @@ declare module 'mongoose' { | |
errors?: Error.ValidationError; | ||
|
||
/** Returns the value of a path. */ | ||
get(path: string, type?: any, options?: any): any; | ||
get<T extends FlatPath<DocType>>(path: T, type?: any, options?: any): ExtractFromPath<DocType, T>; | ||
|
||
/** | ||
* Returns the changes that happened to the document | ||
|
@@ -157,31 +157,33 @@ declare module 'mongoose' { | |
init(obj: AnyObject, opts?: AnyObject): this; | ||
|
||
/** Marks a path as invalid, causing validation to fail. */ | ||
invalidate(path: string, errorMsg: string | NativeError, value?: any, kind?: string): NativeError | null; | ||
invalidate<T extends FlatPath<DocType>>(path: T, errorMsg: string | NativeError, value?: any, kind?: string): NativeError | null; | ||
|
||
/** Returns true if `path` was directly set and modified, else false. */ | ||
isDirectModified(path: string | Array<string>): boolean; | ||
isDirectModified<T extends FlatPath<DocType>>(path: T): boolean; | ||
|
||
/** Checks if `path` was explicitly selected. If no projection, always returns true. */ | ||
isDirectSelected(path: string): boolean; | ||
isDirectSelected<T extends FlatPath<DocType>>(path: T): boolean; | ||
|
||
/** Checks if `path` is in the `init` state, that is, it was set by `Document#init()` and not modified since. */ | ||
isInit(path: string): boolean; | ||
isInit<T extends keyof DocType>(path: T): boolean; | ||
|
||
/** | ||
* Returns true if any of the given paths are modified, else false. If no arguments, returns `true` if any path | ||
* in this document is modified. | ||
*/ | ||
isModified(path?: string | Array<string>): boolean; | ||
isModified<T extends FlatPath<DocType>>(path?: T | Array<T>): boolean; | ||
|
||
/** Boolean flag specifying if the document is new. */ | ||
isNew: boolean; | ||
|
||
/** Checks if `path` was selected in the source query which initialized this document. */ | ||
isSelected(path: string): boolean; | ||
isSelected<T extends FlatPath<DocType>>(path: T): boolean; | ||
|
||
/** Marks the path as having pending changes to write to the db. */ | ||
markModified(path: string, scope?: any): void; | ||
markModified<T extends FlatPath<DocType>>(path: T, scope?: any): void; | ||
|
||
/** Returns the list of paths that have been modified. */ | ||
modifiedPaths(options?: { includeChildren?: boolean }): Array<string>; | ||
|
@@ -191,7 +193,7 @@ declare module 'mongoose' { | |
* for immutable properties. Behaves similarly to `set()`, except for it | ||
* unsets all properties that aren't in `obj`. | ||
*/ | ||
overwrite(obj: AnyObject): this; | ||
overwrite(obj: Partial<Omit<DocType, '_id'>>): this; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Similar here. |
||
|
||
/** | ||
* If this document is a subdocument or populated document, returns the | ||
|
@@ -207,7 +209,7 @@ declare module 'mongoose' { | |
populated(path: string): any; | ||
|
||
/** Sends a replaceOne command with this document `_id` as the query selector. */ | ||
replaceOne(replacement?: AnyObject, options?: QueryOptions | null): Query<any, this>; | ||
replaceOne(replacement?: Partial<Omit<DocType, '_id'>>, options?: QueryOptions | null): Query<any, this>; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is incorrect. 1) |
||
|
||
/** Saves this document by inserting a new document into the database if [document.isNew](/docs/api/document.html#document_Document-isNew) is `true`, or sends an [updateOne](/docs/api/document.html#document_Document-updateOne) operation with just the modified paths if `isNew` is `false`. */ | ||
save(options?: SaveOptions): Promise<this>; | ||
|
@@ -216,9 +218,9 @@ declare module 'mongoose' { | |
schema: Schema; | ||
|
||
/** Sets the value of a path, or many paths. */ | ||
set(path: string | Record<string, any>, val: any, type: any, options?: DocumentSetOptions): this; | ||
set(path: string | Record<string, any>, val: any, options?: DocumentSetOptions): this; | ||
set(value: string | Record<string, any>): this; | ||
set<T extends FlatPath<DocType>>(path: T, val: ExtractFromPath<DocType, T>, type: any, options?: DocumentSetOptions): this; | ||
set<T extends FlatPath<DocType>>(path: T, val: ExtractFromPath<DocType, T>, options?: DocumentSetOptions): this; | ||
set(value: Partial<Omit<DocType, '_id'>>, options?: DocumentSetOptions): this; | ||
|
||
/** The return value of this method is used in calls to JSON.stringify(doc). */ | ||
toJSON<T = Require_id<DocType>>(options?: ToObjectOptions & { flattenMaps?: true }): FlattenMaps<T>; | ||
|
@@ -228,17 +230,17 @@ declare module 'mongoose' { | |
toObject<T = Require_id<DocType>>(options?: ToObjectOptions): Require_id<T>; | ||
|
||
/** Clears the modified state on the specified path. */ | ||
unmarkModified(path: string): void; | ||
unmarkModified<T extends FlatPath<DocType>>(path: T): void; | ||
|
||
/** Sends an updateOne command with this document `_id` as the query selector. */ | ||
updateOne(update?: UpdateQuery<this> | UpdateWithAggregationPipeline, options?: QueryOptions | null): Query<any, this>; | ||
|
||
/** Executes registered validation rules for this document. */ | ||
validate(pathsToValidate?: pathsToValidate, options?: AnyObject): Promise<void>; | ||
validate<T extends FlatPath<DocType>>(pathsToValidate?: T | T[], options?: AnyObject): Promise<void>; | ||
validate(options: { pathsToSkip?: pathsToSkip }): Promise<void>; | ||
|
||
/** Executes registered validation rules (skipping asynchronous validators) for this document. */ | ||
validateSync(options: { pathsToSkip?: pathsToSkip, [k: string]: any }): Error.ValidationError | null; | ||
validateSync(pathsToValidate?: pathsToValidate, options?: AnyObject): Error.ValidationError | null; | ||
validateSync<T extends FlatPath<DocType>>(pathsToValidate?: T | T[], options?: AnyObject): Error.ValidationError | null; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm a bit wary of using |
||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -40,4 +40,34 @@ type IfEquals<T, U, Y = true, N = false> = | |
(<G>() => G extends T ? 1 : 0) extends | ||
(<G>() => G extends U ? 1 : 0) ? Y : N; | ||
|
||
type IsAny<T> = unknown extends T ? ([keyof T] extends [never] ? false : true) : false; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We already have |
||
|
||
type FlatPath<T> = keyof { | ||
[key in keyof Required<T> as NonNullable<T[key]> extends Record<any, any> | ||
? Required<T>[key] extends Array<any> | ||
? never | ||
: Required<T>[key] extends Date | Types.ObjectId | Buffer | ||
? key | ||
: IsAny<Required<T>[key]> extends true | ||
? key | ||
: `${key extends string ? key : ''}.${FlatPath<Required<T>[key]> extends string | ||
? FlatPath<Required<T>[key]> | ||
: ''}` | ||
: keyof Required<T>]: 1; | ||
}; | ||
|
||
|
||
type ExtractFromPath< | ||
Obj, | ||
Path extends FlatPath<Obj>, | ||
> = Path extends `${infer A}.${infer B}` | ||
? A extends keyof Required<Obj> | ||
? B extends FlatPath<Required<Obj>[A]> | ||
? ExtractFromPath<Required<Obj>[A], B> | ||
: never | ||
: never | ||
: Path extends keyof Required<Obj> | ||
? Required<Obj>[Path] | ||
: never; | ||
|
||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This syntax is nice, but would be good to keep the
isDirectSelected(path: string): boolean;
syntax as a fallback because it is perfectly valid to callisDirectSelected()
on a field that's not in the schema.