Skip to content

Commit

Permalink
feat(mongodb): add better return types for insertX functions (Definit…
Browse files Browse the repository at this point in the history
  • Loading branch information
HosseinAgha authored and mrcrane committed Sep 30, 2019
1 parent 3d9e9bb commit fc4cbfd
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 24 deletions.
53 changes: 31 additions & 22 deletions types/mongodb/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@

/// <reference types="node" />

import { Binary, ObjectID, Timestamp } from 'bson';
import { Binary, ObjectId, Timestamp } from 'bson';
import { EventEmitter } from 'events';
import { Readable, Writable } from "stream";
import { checkServerIdentity } from "tls";
Expand Down Expand Up @@ -857,6 +857,15 @@ export interface FSyncOptions extends CommonOptions {

type OptionalId<TSchema> = Omit<TSchema, '_id'> & { _id?: any };

type ExtractIdType<TSchema> =
TSchema extends { _id: infer U } // user has defined a type for _id
? ({} extends U ? Exclude<U, {}> : U) // Exclude is used here to fix typescript 2 bug when TSchema is "any"
: ObjectId; // user has not defined _id on schema

// this adds _id as required property
type WithId<TSchema> =
Omit<TSchema, '_id'> & { _id: ExtractIdType<TSchema> };

/** http://mongodb.github.io/node-mongodb-native/3.1/api/Collection.html */
export interface Collection<TSchema = Default> {
/**
Expand Down Expand Up @@ -1005,19 +1014,19 @@ export interface Collection<TSchema = Default> {
initializeUnorderedBulkOp(options?: CommonOptions): UnorderedBulkOperation;
/** http://mongodb.github.io/node-mongodb-native/3.1/api/Collection.html#insertOne */
/** @deprecated Use insertOne, insertMany or bulkWrite */
insert(docs: OptionalId<TSchema>, callback: MongoCallback<InsertOneWriteOpResult>): void;
insert(docs: OptionalId<TSchema>, callback: MongoCallback<InsertWriteOpResult<WithId<TSchema>>>): void;
/** @deprecated Use insertOne, insertMany or bulkWrite */
insert(docs: OptionalId<TSchema>, options?: CollectionInsertOneOptions): Promise<InsertOneWriteOpResult>;
insert(docs: OptionalId<TSchema>, options?: CollectionInsertOneOptions): Promise<InsertWriteOpResult<WithId<TSchema>>>;
/** @deprecated Use insertOne, insertMany or bulkWrite */
insert(docs: OptionalId<TSchema>, options: CollectionInsertOneOptions, callback: MongoCallback<InsertOneWriteOpResult>): void;
insert(docs: OptionalId<TSchema>, options: CollectionInsertOneOptions, callback: MongoCallback<InsertWriteOpResult<WithId<TSchema>>>): void;
/** http://mongodb.github.io/node-mongodb-native/3.1/api/Collection.html#insertMany */
insertMany(docs: Array<OptionalId<TSchema>>, callback: MongoCallback<InsertWriteOpResult>): void;
insertMany(docs: Array<OptionalId<TSchema>>, options?: CollectionInsertManyOptions): Promise<InsertWriteOpResult>;
insertMany(docs: Array<OptionalId<TSchema>>, options: CollectionInsertManyOptions, callback: MongoCallback<InsertWriteOpResult>): void;
insertMany(docs: Array<OptionalId<TSchema>>, callback: MongoCallback<InsertWriteOpResult<WithId<TSchema>>>): void;
insertMany(docs: Array<OptionalId<TSchema>>, options?: CollectionInsertManyOptions): Promise<InsertWriteOpResult<WithId<TSchema>>>;
insertMany(docs: Array<OptionalId<TSchema>>, options: CollectionInsertManyOptions, callback: MongoCallback<InsertWriteOpResult<WithId<TSchema>>>): void;
/** http://mongodb.github.io/node-mongodb-native/3.1/api/Collection.html#insertOne */
insertOne(docs: OptionalId<TSchema>, callback: MongoCallback<InsertOneWriteOpResult>): void;
insertOne(docs: OptionalId<TSchema>, options?: CollectionInsertOneOptions): Promise<InsertOneWriteOpResult>;
insertOne(docs: OptionalId<TSchema>, options: CollectionInsertOneOptions, callback: MongoCallback<InsertOneWriteOpResult>): void;
insertOne(docs: OptionalId<TSchema>, callback: MongoCallback<InsertOneWriteOpResult<WithId<TSchema>>>): void;
insertOne(docs: OptionalId<TSchema>, options?: CollectionInsertOneOptions): Promise<InsertOneWriteOpResult<WithId<TSchema>>>;
insertOne(docs: OptionalId<TSchema>, options: CollectionInsertOneOptions, callback: MongoCallback<InsertOneWriteOpResult<WithId<TSchema>>>): void;
/** http://mongodb.github.io/node-mongodb-native/3.1/api/Collection.html#isCapped */
isCapped(options?: { session: ClientSession }): Promise<any>;
isCapped(callback: MongoCallback<any>): void;
Expand Down Expand Up @@ -1730,10 +1739,10 @@ export interface FindOneOptions {
}

/** http://mongodb.github.io/node-mongodb-native/3.1/api/Collection.html#~insertWriteOpResult */
export interface InsertWriteOpResult {
export interface InsertWriteOpResult<TSchema extends Record<string, any>> {
insertedCount: number;
ops: any[];
insertedIds: { [key: number]: ObjectID };
ops: TSchema[];
insertedIds: { [key: number]: TSchema['_id'] };
connection: any;
result: { ok: number, n: number };
}
Expand All @@ -1751,10 +1760,10 @@ export interface CollectionInsertOneOptions extends CommonOptions {
}

/** http://mongodb.github.io/node-mongodb-native/3.1/api/Collection.html#~insertOneWriteOpResult */
export interface InsertOneWriteOpResult {
export interface InsertOneWriteOpResult<TSchema extends Record<string, any>> {
insertedCount: number;
ops: any[];
insertedId: ObjectID;
ops: TSchema[];
insertedId: TSchema['_id'];
connection: any;
result: { ok: number, n: number };
}
Expand Down Expand Up @@ -1792,7 +1801,7 @@ export interface UpdateWriteOpResult {
matchedCount: number;
modifiedCount: number;
upsertedCount: number;
upsertedId: { _id: ObjectID };
upsertedId: { _id: ObjectId };
}

/** https://github.com/mongodb/node-mongodb-native/blob/2.2/lib/collection.js#L957 */
Expand Down Expand Up @@ -2037,21 +2046,21 @@ export class CommandCursor extends Readable {
export class GridFSBucket {
constructor(db: Db, options?: GridFSBucketOptions);
/** http://mongodb.github.io/node-mongodb-native/3.1/api/GridFSBucket.html#delete */
delete(id: ObjectID, callback?: GridFSBucketErrorCallback): void;
delete(id: ObjectId, callback?: GridFSBucketErrorCallback): void;
/** http://mongodb.github.io/node-mongodb-native/3.1/api/GridFSBucket.html#drop */
drop(callback?: GridFSBucketErrorCallback): void;
/** http://mongodb.github.io/node-mongodb-native/3.1/api/GridFSBucket.html#find */
find(filter?: object, options?: GridFSBucketFindOptions): Cursor<any>;
/** http://mongodb.github.io/node-mongodb-native/3.1/api/GridFSBucket.html#openDownloadStream */
openDownloadStream(id: ObjectID, options?: { start: number, end: number }): GridFSBucketReadStream;
openDownloadStream(id: ObjectId, options?: { start: number, end: number }): GridFSBucketReadStream;
/** http://mongodb.github.io/node-mongodb-native/3.1/api/GridFSBucket.html#openDownloadStreamByName */
openDownloadStreamByName(filename: string, options?: { revision: number, start: number, end: number }): GridFSBucketReadStream;
/** http://mongodb.github.io/node-mongodb-native/3.1/api/GridFSBucket.html#openUploadStream */
openUploadStream(filename: string, options?: GridFSBucketOpenUploadStreamOptions): GridFSBucketWriteStream;
/** http://mongodb.github.io/node-mongodb-native/3.1/api/GridFSBucket.html#openUploadStreamWithId */
openUploadStreamWithId(id: GridFSBucketWriteStreamId, filename: string, options?: GridFSBucketOpenUploadStreamOptions): GridFSBucketWriteStream;
/** http://mongodb.github.io/node-mongodb-native/3.1/api/GridFSBucket.html#rename */
rename(id: ObjectID, filename: string, callback?: GridFSBucketErrorCallback): void;
rename(id: ObjectId, filename: string, callback?: GridFSBucketErrorCallback): void;
}

/** http://mongodb.github.io/node-mongodb-native/3.1/api/GridFSBucket.html */
Expand Down Expand Up @@ -2087,7 +2096,7 @@ export interface GridFSBucketOpenUploadStreamOptions {

/** https://mongodb.github.io/node-mongodb-native/3.1/api/GridFSBucketReadStream.html */
export class GridFSBucketReadStream extends Readable {
id: ObjectID;
id: ObjectId;
constructor(chunks: Collection<any>, files: Collection<any>, readPreference: object, filter: object, options?: GridFSBucketReadStreamOptions);
}

Expand Down Expand Up @@ -2154,7 +2163,7 @@ export interface ChangeStreamOptions {
startAfter?: object;
}

type GridFSBucketWriteStreamId = string | number | object | ObjectID;
type GridFSBucketWriteStreamId = string | number | object | ObjectId;

export interface LoggerOptions {
/**
Expand Down
37 changes: 35 additions & 2 deletions types/mongodb/test/collection/insertX.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { connect } from 'mongodb';
import { connectionString } from '../index';
import { ObjectId } from 'bson';

// test collection.insertX functions
async function run() {
Expand All @@ -20,13 +21,45 @@ async function run() {
numberField?: number;
fruitTags: string[];
}
type TestModelWithId = TestModel & { _id: ObjectId; };
const collection = db.collection<TestModel>('testCollection');
collection.insertOne({
const result = await collection.insert({
stringField: 'hola',
fruitTags: ['Strawberry'],
});
collection.insertMany([
const resultOne = await collection.insertOne({
stringField: 'hola',
fruitTags: ['Strawberry'],
});
const resultMany = await collection.insertMany([
{ stringField: 'hola', fruitTags: ['Apple', 'Lemon'] },
{ stringField: 'hola', numberField: 1, fruitTags: [] },
]);

// test results type
// should add a _id field with ObjectId type if it does not exist on collection type
result.ops[0]._id; // $ExpectType ObjectId
resultMany.ops[0]._id; // $ExpectType ObjectId
resultOne.ops[0]._id; // $ExpectType ObjectId
result.insertedIds; // $ExpectType { [key: number]: ObjectId; }
resultMany.insertedIds; // $ExpectType { [key: number]: ObjectId; }
resultOne.insertedId; // $ExpectType ObjectId

// should add a _id field with user specified type
type TestModelWithCustomId = TestModel & { _id: number; };
const collectionWithId = db.collection<TestModelWithCustomId>('testCollection');

const resultOneWithId = await collectionWithId.insertOne({
stringField: 'hola',
fruitTags: ['Strawberry'],
});
const resultManyWithId = await collectionWithId.insertMany([
{ stringField: 'hola', fruitTags: ['Apple', 'Lemon'] },
{ stringField: 'hola', numberField: 1, fruitTags: [] },
]);

resultOneWithId.ops[0]._id; // $ExpectType number
resultOneWithId.insertedId; // $ExpectType number
resultManyWithId.ops[0]._id; // $ExpectType number
resultManyWithId.insertedIds; // $ExpectType { [key: number]: number; }
}

0 comments on commit fc4cbfd

Please sign in to comment.