Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@andrewscwei/mongodb-odm

Package Overview
Dependencies
Maintainers
1
Versions
84
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@andrewscwei/mongodb-odm - npm Package Compare versions

Comparing version 0.80.1 to 0.81.0

6

build/core/crud/insert.d.ts
import { BulkWriteOptions, InsertOneOptions } from 'mongodb';
import { AnyProps, Document, OptionallyIdentifiableDocument } from '../../types';
import { AnyProps, Document, InsertableDocument } from '../../types';
import Schema from '../Schema';
export declare function insertOne<P extends AnyProps = AnyProps>(schema: Schema<P>, doc: OptionallyIdentifiableDocument<P>, options?: InsertOneOptions): Promise<Document<P>>;
export declare function insertMany<P extends AnyProps = AnyProps>(schema: Schema<P>, docs: OptionallyIdentifiableDocument<P>[], options?: BulkWriteOptions): Promise<Document<P>[]>;
export declare function insertOne<P extends AnyProps = AnyProps>(schema: Schema<P>, doc: InsertableDocument<P>, options?: InsertOneOptions): Promise<Document<P>>;
export declare function insertMany<P extends AnyProps = AnyProps>(schema: Schema<P>, docs: InsertableDocument<P>[], options?: BulkWriteOptions): Promise<Document<P>[]>;
import { Filter, FindOneAndReplaceOptions, ReplaceOptions } from 'mongodb';
import { AnyProps, Document, OptionallyIdentifiableDocument } from '../../types';
import { AnyProps, Document, InsertableDocument } from '../../types';
import Schema from '../Schema';
export declare function replaceOne<P extends AnyProps = AnyProps>(schema: Schema<P>, filter: Filter<Document<P>>, replacement: OptionallyIdentifiableDocument<P>, options?: ReplaceOptions): Promise<void>;
export declare function findOneAndReplace<P extends AnyProps = AnyProps>(schema: Schema<P>, filter: Filter<Document<P>>, replacement: OptionallyIdentifiableDocument<P>, options?: FindOneAndReplaceOptions): Promise<[Document<P>, Document<P>]>;
export declare function replaceOne<P extends AnyProps = AnyProps>(schema: Schema<P>, filter: Filter<Document<P>>, replacement: InsertableDocument<P>, options?: ReplaceOptions): Promise<boolean>;
export declare function findOneAndReplace<P extends AnyProps = AnyProps>(schema: Schema<P>, filter: Filter<Document<P>>, replacement: InsertableDocument<P>, options?: FindOneAndReplaceOptions): Promise<[Document<P>, Document<P>]>;

@@ -40,4 +40,7 @@ "use strict";

throw new Error(`[${schema.model}] Unable to find and replace document`);
if (result.matchedCount <= 0)
throw new Error(`[${schema.model}] Unable to find and replace document`);
if (options.upsert === true && result.upsertedCount > 0)
return true;
if (result.modifiedCount > 0)
return true;
return false;
});

@@ -44,0 +47,0 @@ }

@@ -55,52 +55,31 @@ import { AggregateOptions, BulkWriteOptions, Collection, DeleteOptions, FindOneAndDeleteOptions, FindOneAndReplaceOptions, FindOneAndUpdateOptions, InsertOneOptions, ObjectId, ReplaceOptions, UpdateOptions } from 'mongodb';

export declare type ModelFindManyOptions = AggregateOptions;
export declare type ModelInsertOneOptions = ModelValidateDocumentOptions & InsertOneOptions & {
export declare type ModelInsertOneOptions = InsertOneOptions & SanitizeUpdateOptions & ModelValidateDocumentOptions;
export declare type ModelInsertManyOptions = BulkWriteOptions & SanitizeUpdateOptions & ModelValidateDocumentOptions;
export declare type ModelUpdateOptions = {
/**
* Specifies whether timestamp fields (i.e. `createdAt` and `updatedAt`) are automatically
* generated before insertion.
* Specifies whether the document(s) (before the update or after the update) is returned when
* update completes. If unspecified, no document(s) will be returned, resulting in a lighter
* update operation.
*/
ignoreTimestamps?: boolean;
returnDocument?: 'before' | 'after';
};
export declare type ModelInsertManyOptions = ModelValidateDocumentOptions & BulkWriteOptions & {
export declare type ModelUpdateOneOptions = (UpdateOptions | FindOneAndUpdateOptions) & SanitizeUpdateOptions & ModelValidateDocumentOptions & ModelUpdateOptions;
export declare type ModelUpdateManyOptions = (UpdateOptions | FindOneAndUpdateOptions) & SanitizeUpdateOptions & ModelValidateDocumentOptions & ModelUpdateOptions;
export declare type ModelDeleteOptions = {
/**
* Specifies whether timestamp fields (i.e. `createdAt` and `updatedAt`) are automatically
* generated before insertion.
* Specifies whether the deleted document(s) should be returned. If unspecified, no document(s)
* will be returned, resulting in a lighter delete operation.
*/
ignoreTimestamps?: boolean;
returnDocument?: boolean;
};
export declare type ModelUpdateOneOptions = ModelValidateDocumentOptions & SanitizeUpdateOptions & UpdateOptions & FindOneAndUpdateOptions & {
export declare type ModelDeleteOneOptions = (DeleteOptions | FindOneAndDeleteOptions) & ModelDeleteOptions;
export declare type ModelDeleteManyOptions = (DeleteOptions | FindOneAndDeleteOptions) & ModelDeleteOptions;
export declare type ModelReplaceOneOptions = (ReplaceOptions | FindOneAndReplaceOptions) & {
/**
* Specifies whether updated doc is returned when update completes.
* Specifies whether the document(s) (before the replacement or after the replacement) is returned
* when replacement completes. If unspecified, no document(s) will be returned, resulting in a
* lighter replace operation.
*/
returnDoc?: boolean;
/**
* Specifies whether timestamp fields (i.e. `createdAt` and `updatedAt`) are automatically
* generated before insertion.
*/
ignoreTimestamps?: boolean;
returnDocument?: 'before' | 'after';
};
export declare type ModelUpdateManyOptions = ModelValidateDocumentOptions & SanitizeUpdateOptions & UpdateOptions & FindOneAndUpdateOptions & {
/**
* Specifies whether updated docs are returned when update completes.
*/
returnDocs?: boolean;
/**
* Specifies whether timestamp fields (i.e. `createdAt` and `updatedAt`) are automatically
* generated before insertion.
*/
ignoreTimestamps?: boolean;
};
export declare type ModelDeleteOneOptions = DeleteOptions & FindOneAndDeleteOptions & {
/**
* Specifies whether deleted doc is returned when deletion completes.
*/
returnDoc?: boolean;
};
export declare type ModelDeleteManyOptions = DeleteOptions & FindOneAndReplaceOptions & {
/**
* Specifies whether deleted docs are returned when deletion completes.
*/
returnDocs?: boolean;
};
export declare type ModelReplaceOneOptions = ReplaceOptions & FindOneAndReplaceOptions & ModelInsertOneOptions;
export declare type ModelCountOptions = ModelFindManyOptions;
export declare type ModelValidateDocumentOptions = {

@@ -285,3 +264,3 @@ /**

*
* @todo This method iterates through every document to apply the `beforeInsert` hook. Consider a
* @todo This method iterates through every document to apply the `beforeInsertOne` hook. Consider a
* more cost-efficient approach?

@@ -304,18 +283,22 @@ *

*
* @returns The updated doc if `returnDoc` is set to `true`, or a boolean indicating whether a doc
* was updated or upserted.
* @returns A boolean indicating whether a document was updated or upserted if `returnDocument`
* was unspecified, or the updated document if `returnDocument` was set to `after`, or
* the document before the update if `returnDocument` was set to `before` and it existed,
* otherwise `undefined`.
*
* @see {@link https://docs.mongodb.com/manual/reference/operator/update-field/}
* @see {@link https://mongodb.github.io/node-mongodb-native/4.2/classes/Collection.html#updateOne}
* @see {@link https://mongodb.github.io/node-mongodb-native/4.2/classes/Collection.html#findOneAndUpdate}
* @see
* {@link https://mongodb.github.io/node-mongodb-native/4.2/classes/Collection.html#updateOne}
* @see
* {@link https://mongodb.github.io/node-mongodb-native/4.2/classes/Collection.html#findOneAndUpdate}
*
* @throws {Error} This method is called even though updates are disabled in the schema.
* @throws {Error} This method is called even though upserts are disabled in the schema.
* @throws {Error} Filter is invalid.
* @throws {Error} A doc is updated but it cannot be found.
*/
updateOneStrict(query: AnyFilter<T>, update: AnyUpdate<T>, options?: ModelUpdateOneOptions): Promise<boolean | Document<T>>;
updateOneStrict(query: AnyFilter<T>, update: AnyUpdate<T>, options?: ModelUpdateOneOptions): Promise<boolean | Document<T> | undefined>;
/**
* Same as the strict update one operation except this method drops all errors and returns
* `undefined` if no document was updated (and that `returnDoc` is `true`) or `true`/`false` (if
* `returnDoc` is `false`).
* Same as the {@link updateOneStrict} except this method drops all errors and returns `undefined`
* if no document was updated (if `returnDocument` is set) or `true`/`false` (if `returnDocument`
* is unspecified).
*

@@ -327,4 +310,6 @@ * @param filter - Filter for the document to update.

*
* @returns The updated doc if `returnDoc` is set to `true`, else either `true` or `false`
* depending on whether the operation was successful.
* @returns A boolean indicating whether document was updated or upserted if `returnDocument` was
* unspecified, or the updated document if `returnDocument` was set to `after`, or the
* document before the update if `returnDocument` was set to `before` and it existed,
* otherwise `undefined`.
*

@@ -342,4 +327,5 @@ * @see {@link Model.updateOneStrict}

*
* @returns The updated docs if `returnDocs` is set to `true`, else `true` or `false` depending on
* whether or not the operation was successful.
* @returns A boolean indicating whether documents were updated or upserted if `returnDocument`
* was unspecified, or the updated documents if `returnDocument` was set to `after`, or
* the documents before the update if `returnDocument` was set to `before`.
*

@@ -354,3 +340,3 @@ * @see {@link https://docs.mongodb.com/manual/reference/operator/update-field/}

*/
updateMany(filter: AnyFilter<T>, update: AnyUpdate<T>, options?: ModelUpdateManyOptions): Promise<Document<T>[] | boolean>;
updateMany(filter: AnyFilter<T>, update: AnyUpdate<T>, options?: ModelUpdateManyOptions): Promise<boolean | Document<T>[]>;
/**

@@ -362,4 +348,4 @@ * Deletes one document matched by `filter`.

*
* @returns The deleted doc if `returnDoc` is set to `true`, or a boolean indicating whether the
* doc is deleted.
* @returns A boolean indicating whether a document was deleted if `returnDocument` was
* unspecified, or the deleted document if `returnDocument` was set to `true`.
*

@@ -370,8 +356,8 @@ * @see {@link https://mongodb.github.io/node-mongodb-native/4.2/classes/Collection.html#deleteOne}

* @throws {Error} This method is called even though deletions are disabled in the schema.
* @throws {Error} Unable to return the deleted document when `returnDoc` is `true`.
* @throws {Error} Unable to return the deleted document when `returnDocument` is `true`.
* @throws {Error} Unable to delete document.
*/
deleteOneStrict(filter: AnyFilter<T>, options?: ModelDeleteOneOptions): Promise<Document<T> | boolean>;
deleteOneStrict(filter: AnyFilter<T>, options?: ModelDeleteOneOptions): Promise<boolean | Document<T>>;
/**
* Same as the strict delete one operation except this method drops all errors.
* Same as the {@link deleteOneStrict} except this method drops all errors.
*

@@ -381,8 +367,8 @@ * @param filter - Filter for document to delete.

*
* @returns The deleted doc if `returnDoc` is set to `true`, else `true` or `false` depending on
* whether or not the operation was successful.
* @returns A boolean indicating whether a document was deleted if `returnDocument` was
* unspecified, or the deleted document if `returnDocument` was set to `true`.
*
* @see {@link Model.deleteOneStrict}
*/
deleteOne(filter: AnyFilter<T>, options?: ModelDeleteOneOptions): Promise<Document<T> | boolean | undefined>;
deleteOne(filter: AnyFilter<T>, options?: ModelDeleteOneOptions): Promise<boolean | Document<T> | undefined>;
/**

@@ -394,4 +380,4 @@ * Deletes multiple documents matched by `filter`.

*
* @returns The deleted docs if `returnDocs` is set to `true`, else `true` or `false` depending on
* whether or not the operation was successful.
* @returns A boolean indicating whether a document was deleted if `returnDocument` was
* unspecified, or the deleted documents if `returnDocument` was set to `true`.
*

@@ -413,4 +399,5 @@ * @see {@link https://mongodb.github.io/node-mongodb-native/4.2/classes/Collection.html#deleteMany}

*
* @returns The replaced document (by default) or the new document (depending on the
* `returnDocument` option).
* @returns A boolean indicating whether document was replaced if `returnDocument` was
* unspecified, or the new document if `returnDocument` was set to `after`, or the
* document before the replacement if `returnDocument` was set to `before`.
*

@@ -422,5 +409,5 @@ * @see {@link https://mongodb.github.io/node-mongodb-native/4.2/classes/Collection.html#findOneAndReplace}

*/
findAndReplaceOneStrict(filter: AnyFilter<T>, replacement?: DocumentFragment<T>, options?: ModelReplaceOneOptions): Promise<Document<T>>;
replaceOneStrict(filter: AnyFilter<T>, replacement?: DocumentFragment<T>, options?: ModelReplaceOneOptions): Promise<boolean | Document<T>>;
/**
* Same as the strict find and replace one operation except this method drops all errors.
* Same as {@link replaceOneStrict} except this method drops all errors.
*

@@ -431,8 +418,9 @@ * @param filter - Filter for document to replace.

*
* @returns The replaced document (by default) or the new document (depending on the
* `returnDocument` option) if available, `undefined` otherwise.
* @returns A boolean indicating whether document was replaced if `returnDocument` was
* unspecified, or the new document if `returnDocument` was set to `after`, or the
* document before the replacement if `returnDocument` was set to `before`.
*
* @see {@link Model.findAndReplaceOneStrict}
* @see {@link Model.replaceOneStrict}
*/
findAndReplaceOne(filter: AnyFilter<T>, replacement?: DocumentFragment<T>, options?: ModelReplaceOneOptions): Promise<Document<T> | undefined>;
replaceOne(filter: AnyFilter<T>, replacement?: DocumentFragment<T>, options?: ModelReplaceOneOptions): Promise<boolean | Document<T> | undefined>;
/**

@@ -449,7 +437,7 @@ * Checks if a document exists.

*
* @param filter - Filter used for the `$match` stage of the aggregation pipeline.
* @param filter - Filter for documents to count.
*
* @returns The total number of documents found. The minimum is 0.
*/
count(filter: AnyFilter<T>, options?: ModelCountOptions): Promise<number>;
count(filter: AnyFilter<T>): Promise<number>;
/**

@@ -456,0 +444,0 @@ * Returns a document whose values are formatted according to the format functions defined in the

/**
* @file This is a static, abstract model that provides ORM for a single MongoDB collection. Every
* other model must inherit this class. It sets up the ground work for basic CRUD operations,
* event triggers, filter validations, etc. All returned documents are native JSON objects.
* @file This is the factory of abstract, static model classes that provide one-to-one
* object-relational mapping to MongoDB collections. Each model registered in this ODM library
* must inherit the generated model class to leverage its ORM features, such as eventful CRUD
* operations, default fields, field validations, etc. All MongoDB documents returned by the
* model are native JSON objects.
*
* @see {@link Model}
*/

@@ -10,8 +14,10 @@ import { AnyProps } from '../types';

/**
* Creates a static model class with the provided schema.
* Generates an abstract, static model class with the provided schema.
*
* @param schema - The schema of the model to be generated.
*
* @returns The generated static model.
* @returns The generated model class.
*
* @see {@link Model}
*/
export default function modelFactory<P extends AnyProps = AnyProps>(schema: Schema<P>): Model<P>;
"use strict";
/**
* @file This is a static, abstract model that provides ORM for a single MongoDB collection. Every
* other model must inherit this class. It sets up the ground work for basic CRUD operations,
* event triggers, filter validations, etc. All returned documents are native JSON objects.
* @file This is the factory of abstract, static model classes that provide one-to-one
* object-relational mapping to MongoDB collections. Each model registered in this ODM library
* must inherit the generated model class to leverage its ORM features, such as eventful CRUD
* operations, default fields, field validations, etc. All MongoDB documents returned by the
* model are native JSON objects.
*
* @see {@link Model}
*/

@@ -35,2 +39,13 @@ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {

};
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
var __importDefault = (this && this.__importDefault) || function (mod) {

@@ -47,7 +62,9 @@ return (mod && mod.__esModule) ? mod : { "default": mod };

/**
* Creates a static model class with the provided schema.
* Generates an abstract, static model class with the provided schema.
*
* @param schema - The schema of the model to be generated.
*
* @returns The generated static model.
* @returns The generated model class.
*
* @see {@link Model}
*/

@@ -101,3 +118,4 @@ function modelFactory(schema) {

try {
return yield this.identifyOneStrict(filter);
const res = yield this.identifyOneStrict(filter);
return res;
}

@@ -130,3 +148,4 @@ catch (err) {

try {
return yield this.findOneStrict(filter, options);
const res = yield this.findOneStrict(filter, options);
return res;
}

@@ -154,6 +173,6 @@ catch (err) {

throw new Error(`[${this.schema.model}] Insertions are disallowed for this model`);
const docToInsert = yield this.beforeInsert(doc !== null && doc !== void 0 ? doc : (yield this.randomFields()), Object.assign({ strict: true }, options));
const result = yield CRUD.insertOne(this.schema, docToInsert, options);
yield this.afterInsert(result);
return result;
const docToInsert = yield this.beforeInsertOne(doc !== null && doc !== void 0 ? doc : yield this.randomFields(), Object.assign({ strict: true }, options));
const insertedDoc = yield CRUD.insertOne(this.schema, docToInsert, options);
yield this.afterInsertOne(insertedDoc);
return insertedDoc;
});

@@ -165,3 +184,4 @@ }

try {
return yield this.insertOneStrict(doc, options);
const res = yield this.insertOneStrict(doc, options);
return res;
}

@@ -178,9 +198,6 @@ catch (err) {

throw new Error(`[${this.schema.model}] Multiple insertions are disallowed for this model`);
const docsToInsert = yield Promise.all(docs.map(doc => this.beforeInsert(doc)));
const docsToInsert = yield this.beforeInsertMany(docs, Object.assign({ strict: true }, options));
const insertedDocs = yield CRUD.insertMany(this.schema, docsToInsert, options);
debug('Inserting multiple documents...', 'OK', docsToInsert, insertedDocs);
const n = insertedDocs.length;
for (let i = 0; i < n; i++) {
yield this.afterInsert(insertedDocs[i]);
}
yield this.afterInsertMany(insertedDocs);
return insertedDocs;

@@ -194,14 +211,14 @@ });

throw new Error(`[${this.schema.model}] Updates are disallowed for this model`);
const f = (0, utils_1.sanitizeFilter)(this.schema, filter);
const u = yield this.beforeUpdate(f, (0, utils_1.sanitizeUpdate)(this.schema, update, options), options);
if (options.returnDoc === true) {
const [oldDoc, newDoc] = yield CRUD.findOneAndUpdate(this.schema, f, u, options);
debug('Updating an existing document...', 'OK', f, u, options, oldDoc, newDoc);
yield this.afterUpdate(oldDoc, newDoc);
return newDoc;
const filterToApply = (0, utils_1.sanitizeFilter)(this.schema, filter);
const updateToApply = yield this.beforeUpdateOne(filterToApply, update, options);
if (options.returnDocument) {
const [oldDoc, newDoc] = yield CRUD.findOneAndUpdate(this.schema, filterToApply, updateToApply, options);
debug('Updating an existing document...', 'OK', filterToApply, updateToApply, options, oldDoc, newDoc);
yield this.afterUpdateOne(oldDoc, newDoc);
return options.returnDocument === 'after' ? newDoc : oldDoc;
}
else {
const result = yield CRUD.updateOne(this.schema, f, u, options);
debug('Updating an existing document...', 'OK', f, u, options);
yield this.afterUpdate();
const result = yield CRUD.updateOne(this.schema, filterToApply, updateToApply, options);
debug('Updating an existing document...', 'OK', filterToApply, updateToApply, options);
yield this.afterUpdateOne();
return result;

@@ -215,12 +232,7 @@ }

try {
const result = yield this.updateOneStrict(filter, update, options);
if (!lodash_1.default.isBoolean(result) && options.returnDoc === true) {
return result;
}
else {
return result;
}
const res = yield this.updateOneStrict(filter, update, options);
return res;
}
catch (err) {
return options.returnDoc === true ? undefined : false;
return options.returnDocument ? undefined : false;
}

@@ -234,14 +246,14 @@ });

throw new Error(`[${this.schema.model}] Multiple updates are disallowed for this model`);
const f = (0, utils_1.sanitizeFilter)(this.schema, filter);
const u = yield this.beforeUpdate(f, (0, utils_1.sanitizeUpdate)(this.schema, update, options), options);
if (options.returnDocs === true) {
const [oldDocs, newDocs] = yield CRUD.findManyAndUpdate(this.schema, f, u, options);
debug('Updating multiple existing documents...', 'OK', f, u, options, newDocs);
yield this.afterUpdate(oldDocs, newDocs);
return newDocs;
const filterToApply = (0, utils_1.sanitizeFilter)(this.schema, filter);
const updateToApply = yield this.beforeUpdateMany(filterToApply, update, options);
if (options.returnDocument) {
const [, newDocs] = yield CRUD.findManyAndUpdate(this.schema, filterToApply, updateToApply, options);
debug('Updating multiple existing documents...', 'OK', filterToApply, updateToApply, options, newDocs);
yield this.afterUpdateMany(undefined, newDocs);
return options.returnDocument === 'after' ? newDocs : [];
}
else {
const result = yield CRUD.updateMany(this.schema, f, u, options);
debug('Updating multiple existing documents...', 'OK', f, u, options, result);
yield this.afterUpdate();
const result = yield CRUD.updateMany(this.schema, filterToApply, updateToApply, options);
debug('Updating multiple existing documents...', 'OK', filterToApply, updateToApply, options, result);
yield this.afterUpdateMany();
return result;

@@ -256,14 +268,14 @@ }

throw new Error(`[${this.schema.model}] Deletions are disallowed for this model`);
const f = (0, utils_1.sanitizeFilter)(this.schema, filter);
yield this.beforeDelete(f, options);
if (options.returnDoc === true) {
const deletedDoc = yield CRUD.findAndDeleteOne(this.schema, f, options);
const filterToApply = (0, utils_1.sanitizeFilter)(this.schema, filter);
yield this.beforeDeleteOne(filterToApply, options);
if (options.returnDocument === true) {
const deletedDoc = yield CRUD.findAndDeleteOne(this.schema, filterToApply, options);
debug('Deleting an existing document...', 'OK', filter, deletedDoc);
yield this.afterDelete(deletedDoc);
yield this.afterDeleteOne(deletedDoc);
return deletedDoc;
}
else {
const result = yield CRUD.deleteOne(this.schema, f, options);
const result = yield CRUD.deleteOne(this.schema, filterToApply, options);
debug('Deleting an existing document...', 'OK', filter);
yield this.afterDelete();
yield this.afterDeleteOne();
return result;

@@ -277,12 +289,7 @@ }

try {
const result = yield this.deleteOneStrict(filter, options);
if (!lodash_1.default.isBoolean(result) && options.returnDoc === true) {
return result;
}
else {
return result;
}
const res = yield this.deleteOneStrict(filter, options);
return res;
}
catch (err) {
return options.returnDoc === true ? undefined : false;
return options.returnDocument === true ? undefined : false;
}

@@ -296,14 +303,14 @@ });

throw new Error(`[${this.schema.model}] Multiple deletions are disallowed for this model`);
const f = (0, utils_1.sanitizeFilter)(this.schema, filter);
yield this.beforeDelete(f, options);
if (options.returnDocs === true) {
const deletedDocs = yield CRUD.findManyAndDelete(this.schema, f, options);
debug('Deleting multiple existing documents...:', 'OK', f, deletedDocs);
yield this.afterDelete(deletedDocs);
const filterToApply = (0, utils_1.sanitizeFilter)(this.schema, filter);
yield this.beforeDeleteMany(filterToApply, options);
if (options.returnDocument === true) {
const deletedDocs = yield CRUD.findManyAndDelete(this.schema, filterToApply, options);
debug('Deleting multiple existing documents...:', 'OK', filterToApply, deletedDocs);
yield this.afterDeleteMany(deletedDocs);
return deletedDocs;
}
else {
yield CRUD.deleteMany(this.schema, f, options);
debug('Deleting multiple existing documents...:', 'OK', f);
yield this.afterDelete();
yield CRUD.deleteMany(this.schema, filterToApply, options);
debug('Deleting multiple existing documents...:', 'OK', filterToApply);
yield this.afterDeleteMany();
return true;

@@ -313,19 +320,29 @@ }

}
/** @see {@link Model.findAndReplaceOneStrict} */
static findAndReplaceOneStrict(filter, replacement, options = {}) {
/** @see {@link Model.replaceOneStrict} */
static replaceOneStrict(filter, replacement, options = {}) {
return __awaiter(this, void 0, void 0, function* () {
const f = (0, utils_1.sanitizeFilter)(this.schema, filter);
const r = yield this.beforeInsert(replacement !== null && replacement !== void 0 ? replacement : (yield this.randomFields()), options);
const [oldDoc, newDoc] = yield CRUD.findOneAndReplace(this.schema, f, r, options);
debug('Replacing an existing document...', 'OK', f, r, oldDoc, newDoc);
yield this.afterDelete(oldDoc);
yield this.afterInsert(newDoc);
return options.returnDocument === 'before' ? oldDoc : newDoc;
if (options.upsert === true)
throw new Error('Replacement upserts are not supported at this point');
const filterToApply = (0, utils_1.sanitizeFilter)(this.schema, filter);
const replacementToApply = yield this.beforeReplaceOne(filterToApply, replacement !== null && replacement !== void 0 ? replacement : yield this.randomFields(), options);
if (options.returnDocument) {
const [oldDoc, newDoc] = yield CRUD.findOneAndReplace(this.schema, filterToApply, replacementToApply, options);
debug('Replacing an existing document...', 'OK', filterToApply, replacementToApply, oldDoc, newDoc);
yield this.afterReplaceOne(oldDoc, newDoc);
return options.returnDocument === 'before' ? oldDoc : newDoc;
}
else {
const result = yield CRUD.replaceOne(this.schema, filterToApply, replacementToApply, options);
debug('Replacing an existing document...', 'OK', filterToApply, replacementToApply);
yield this.afterReplaceOne();
return result;
}
});
}
/** @see {@link Model.findAndReplaceOne} */
static findAndReplaceOne(filter, replacement, options = {}) {
/** @see {@link Model.replaceOne} */
static replaceOne(filter, replacement, options = {}) {
return __awaiter(this, void 0, void 0, function* () {
try {
return yield this.findAndReplaceOneStrict(filter, replacement, options);
const res = yield this.replaceOneStrict(filter, replacement, options);
return res;
}

@@ -345,5 +362,5 @@ catch (err) {

/** @see {@link Model.count} */
static count(filter, options = {}) {
static count(filter) {
return __awaiter(this, void 0, void 0, function* () {
const result = yield this.findMany(filter, options);
const result = yield this.identifyMany(filter);
return result.length;

@@ -434,5 +451,5 @@ });

/**
* Handler called before an attempt to insert document into the database. This is a good place
* to apply any custom pre-processing to the document before it is inserted into the document.
* This method must return the document to be inserted.
* Handler invoked at the beginning of {@link insertOne} to apply any custom pre-processing to
* the document prior to inserting. Throwing an error within this handler will terminate
* {@link insertOne} immediately.
*

@@ -444,3 +461,3 @@ * @param doc - The document to be inserted.

*/
static willInsertDocument(doc) {
static willInsertOne(doc) {
return __awaiter(this, void 0, void 0, function* () {

@@ -451,200 +468,249 @@ return doc;

/**
* Handler called after the document is successfully inserted.
* Hanlder invoked after a successful {@link insertOne} operation. Throwing an error within this
* handler can prohib {@link insertOne} from returning.
*
* @param doc - The inserted document.
*/
static didInsertDocument(doc) {
static didInsertOne(doc) {
return __awaiter(this, void 0, void 0, function* () { });
}
/**
* Handler called before an attempted update operation. This method must return the filter and
* update descriptor for the update operation.
* Handler invoked at the beginning of {@link insertMany} to apply any custom pre-processing to
* the documents prior to inserting. Throwing an error within this handler will terminate
* {@link insertMany} immediately.
*
* @param filter - The filter for document(s) to update.
* @param update - The update descriptor.
* @param docs - The documents to be inserted.
*
* @returns A tuple of the filter and the update descriptor.
* @returns The modified documents to be inserted.
*/
static willUpdateDocument(filter, update) {
static willInsertMany(docs) {
return __awaiter(this, void 0, void 0, function* () {
return update;
return docs;
});
}
/**
* Handler called after a document or a set of documents have been successfully updated.
* Handler invoked after a successful {@link insertMany} operation. Throwing an error within
* this hanlder can prohibit {@link insertMany} from returning.
*
* @param prevDoc - The document before it is updated. This is only available if `returnDoc` was
* enabled, and only for updateOne().
* @param newDocs - The updated document(s). This is only available if `returnDoc` or
* `returnDocs` was enabled.
* @param docs - The inserted documents.
*/
static didUpdateDocument(prevDoc, newDocs) {
static didInsertMany(docs) {
return __awaiter(this, void 0, void 0, function* () { });
}
/**
* Handler called before an attempt to delete a document.
* Handler invoked at the beginning of {@link updateOne} to apply any custom pre-processing to
* the update filter prior to updating. Throwing an error within this handler will terminate
* {@link updateOne} immediately.
*
* @param filter - The filter for the document to be deleted.
* @param filter - The filter for the document to update.
* @param update - The update to be applied.
*
* @returns The document to be deleted.
* @returns The modified update to be applied.
*/
static willDeleteDocument(filter) {
return __awaiter(this, void 0, void 0, function* () { });
static willUpdateOne(filter, update) {
return __awaiter(this, void 0, void 0, function* () {
return update;
});
}
/**
* Handler called after a document or a set of documents are successfully deleted.
* Handler invoked after a successful {@link updateOne} operation. Throwing an error within this
* handler can prohibit {@link updateOne} from returning.
*
* @param docs - The deleted document(s) if available.
* @param oldDoc - The document before the update. This is only available if `returnDocument`
* was set during {@link updateOne}.
* @param newDoc - The document after the update. This is only available if `returnDocument` was
* set during {@link updateOne}.
*/
static didDeleteDocument(docs) {
static didUpdateOne(oldDoc, newDoc) {
return __awaiter(this, void 0, void 0, function* () { });
}
/**
* Processes a document before it is inserted. This is also used during an upsert operation.
* Handler invoked at the beginning of {@link updateMany} to apply any custom pre-processing to
* the update filter prior to updating. Throwing an error within this handler will terminate
* {@link updateMany} immediately.
*
* @param doc - The document to be inserted/upserted.
* @param options - See {@link ModelInsertOneOptions} and {@link ModelInsertManyOptions}.
* @param filter - The filter for the documents to update.
* @param update - The update to be applied.
*
* @returns Document to be inserted/upserted to the database.
* @returns The modified update to be applied.
*/
static beforeInsert(doc, options = {}) {
static willUpdateMany(filter, update) {
return __awaiter(this, void 0, void 0, function* () {
// Call event hook first.
const modifiedDoc = yield this.willInsertDocument(doc);
let sanitizedDoc = (0, utils_1.sanitizeDocument)(this.schema, modifiedDoc);
// Unless specified, always renew the `createdAt` and `updatedAt` fields.
if ((this.schema.timestamps === true) && (options.ignoreTimestamps !== true)) {
if (!lodash_1.default.isDate(sanitizedDoc.createdAt))
sanitizedDoc.createdAt = new Date();
if (!lodash_1.default.isDate(sanitizedDoc.updatedAt))
sanitizedDoc.updatedAt = new Date();
}
// Before inserting this document, go through each field and make sure that it has default
// values and that they are formatted correctly.
for (const key in this.schema.fields) {
if (!this.schema.fields.hasOwnProperty(key))
continue;
if (sanitizedDoc.hasOwnProperty(key))
continue;
const defaultValue = this.defaultProps[key];
// Check if the field has a default value defined in the schema. If so, apply it.
if (lodash_1.default.isUndefined(defaultValue))
continue;
sanitizedDoc[key] = (lodash_1.default.isFunction(defaultValue)) ? defaultValue() : defaultValue;
}
// Apply format function defined in the schema if applicable.
sanitizedDoc = yield this.formatDocument(sanitizedDoc);
// Finally, validate the document. Ignore unique indexes in this step. Let the db throw an
// error if the inserted doc violates those indexes.
yield this.validateDocument(sanitizedDoc, Object.assign({ ignoreUniqueIndex: true, strict: true, accountForDotNotation: false }, options));
return sanitizedDoc;
return update;
});
}
/**
* Handler invoked right after a document insertion.
* Handler invoked after a successful {@link updateMany} operation. Throwing an error within
* this handler can prohibit {@link updateMany} from returning.
*
* @param doc - The inserted document.
* @param oldDocs - The documents before the update. They are only available if `returnDocument`
* was set during {@link updateMany}.
* @param newDocs - The documents after the update (array order consistency with `oldDocs` not
* guaranteed). They are only available if `returnDocument` was set during
* {@link updateMany}.
*/
static afterInsert(doc) {
return __awaiter(this, void 0, void 0, function* () {
yield this.didInsertDocument(doc);
});
static didUpdateMany(oldDocs, newDocs) {
return __awaiter(this, void 0, void 0, function* () { });
}
/**
* Handler invoked right before an update. This is NOT invoked on an insertion.
* Handler invoked at the beginning of {@link deleteOne}. Throwing an error within this handler
* will terminate {@link deleteOne} immediately.
*
* @param filter - Filter for document to update.
* @param update - The update to apply.
* @param options - See {@link ModelUpdateOneOptions} and {@link ModelUpdateManyOptions}.
* @param filter - The filter for the document to be deleted.
*/
static willDeleteOne(filter) {
return __awaiter(this, void 0, void 0, function* () { });
}
/**
* Handler invoked after a successful {@link deleteOne} operation. Throwing an error within this
* handler can prohibit {@link deleteOne} from returning.
*
* @returns The modified update to apply.
* @param doc - The deleted document.
*/
static didDeleteOne(doc) {
return __awaiter(this, void 0, void 0, function* () { });
}
/**
* Handler invoked at the beginning of {@link deleteMany}. Throwing an error within this handler
* will terminate {@link deleteMany} immediately.
*
* @throws {Error} Attempting to upsert even though upserts are disabled in the schema.
*
* @todo Handle remaining update operators.
* @param filter - The filter for the documents to be deleted.
*/
static beforeUpdate(filter, update, options = {}) {
var _a, _b, _c;
return __awaiter(this, void 0, void 0, function* () {
if ((options.upsert === true) && (this.schema.allowUpserts !== true))
throw new Error(`[${this.schema.model}] Attempting to upsert a document while upserting is disallowed in the schema`);
const u = yield this.willUpdateDocument(filter, update);
// Format all fields in the update filter.
if (u.$set) {
u.$set = yield this.formatDocument(u.$set);
}
// In the case of an upsert, we need to preprocess the filter as if this was an insertion. We
// also need to tell the database to save all fields in the filter as well, unless they are
// already in the update query.
if (options.upsert === true && (0, utils_1.typeIsAnyDocument)(filter)) {
// Make a copy of the filter in case it is manipulated by the hooks.
const docIfUpsert = yield this.beforeInsert(filter, Object.assign(Object.assign({}, options), { strict: false }));
const setOnInsert = lodash_1.default.omit(Object.assign(Object.assign({}, (_a = u.$setOnInsert) !== null && _a !== void 0 ? _a : {}), docIfUpsert), [
...Object.keys((_b = u.$set) !== null && _b !== void 0 ? _b : {}),
...Object.keys((_c = u.$unset) !== null && _c !== void 0 ? _c : {}),
]);
if (!lodash_1.default.isEmpty(setOnInsert)) {
u.$setOnInsert = setOnInsert;
}
}
// Validate all fields in the update. Account for dot notations to facilitate updating fields
// in nested fields.
if (u.$set && !lodash_1.default.isEmpty(u.$set)) {
yield this.validateDocument(u.$set, Object.assign(Object.assign({}, options), { ignoreUniqueIndex: true, accountForDotNotation: true }));
}
return u;
});
static willDeleteMany(filter) {
return __awaiter(this, void 0, void 0, function* () { });
}
/**
* Handler invoked right after an update. This does not account for insertions.
* Handler invoked after a successful {@link deleteMany} operation. Throwing an error within
* this handler can prohibit {@link deleteMany} from returning.
*
* @param oldDoc - The original document.
* @param newDocOrNewDocs - The updated document(s).
* @param docs - The deleted documents.
*/
static afterUpdate(oldDoc, newDocOrNewDocs) {
return __awaiter(this, void 0, void 0, function* () {
yield this.didUpdateDocument(oldDoc, newDocOrNewDocs);
});
static didDeleteMany(docs) {
return __awaiter(this, void 0, void 0, function* () { });
}
/**
* Handler invoked before a deletion.
* Handler invoked at the beginning of {@link replaceOne} to apply any custom pre-processing to
* the new document prior to replacement. Throwing an error within this handler will terminate
* {@link replaceOne} immediately.
*
* @param filter - Filter for document to delete.
* @param options - See {@link ModelDeleteOneOptions} and {@link ModelDeleteManyOptions}.
* @param filter - The filter for the document to be replaced.
* @param replacement - The replacement document.
*
* @returns The processed filter for deletion.
* @returns The modified replacement document.
*/
static beforeDelete(filter, options) {
static willReplaceOne(filter, replacement) {
return __awaiter(this, void 0, void 0, function* () {
yield this.willDeleteDocument(filter);
return replacement;
});
}
/**
* Handler invoked after a deletion.
* Handler invoked after a successful {@link replaceOne} operation. Throwing an error within
* this handler can prohibit {@link replaceOne} from returning.
*
* @param docOrDocs - The deleted doc(s), if available.
*
* @todo Cascade deletion only works for first-level foreign keys so far.
* @param oldDoc - The document that was replaced. This is only available if `returnDocument`
* was set during {@link replaceOne}.
* @param newDoc - The new document. This is only available if `returnDocument` was set during
* {@link replaceOne}.
*/
static afterDelete(docOrDocs) {
static didReplaceOne(oldDoc, newDoc) {
return __awaiter(this, void 0, void 0, function* () { });
}
static beforeInsertOne(doc, options = {}) {
return __awaiter(this, void 0, void 0, function* () {
if (docOrDocs) {
if (lodash_1.default.isArray(docOrDocs)) {
const docs = docOrDocs;
for (const doc of docs) {
if (!(0, utils_1.typeIsValidObjectId)(doc._id))
continue;
yield this.cascadeDelete(doc._id);
}
const modifiedDoc = yield this.willInsertOne(doc);
const res = yield this.processDocumentBeforeInsert(modifiedDoc, options);
return res;
});
}
static afterInsertOne(doc) {
return __awaiter(this, void 0, void 0, function* () {
yield this.didInsertOne(doc);
});
}
static beforeInsertMany(docs, options = {}) {
return __awaiter(this, void 0, void 0, function* () {
const modifiedDocs = yield this.willInsertMany(docs);
const docsToInsert = [];
for (let i = 0, n = modifiedDocs.length; i < n; i++) {
const doc = modifiedDocs[i];
const docToInsert = yield this.processDocumentBeforeInsert(doc, options);
docsToInsert.push(docToInsert);
}
return docsToInsert;
});
}
static afterInsertMany(docs) {
return __awaiter(this, void 0, void 0, function* () {
yield this.didInsertMany(docs);
});
}
static beforeUpdateOne(filter, update, options = {}) {
return __awaiter(this, void 0, void 0, function* () {
const res = yield this.processUpdateBeforeUpdate(filter, update, options);
return res;
});
}
static afterUpdateOne(oldDoc, newDoc) {
return __awaiter(this, void 0, void 0, function* () {
yield this.didUpdateOne(oldDoc, newDoc);
});
}
static beforeUpdateMany(filter, update, options = {}) {
return __awaiter(this, void 0, void 0, function* () {
const res = yield this.processUpdateBeforeUpdate(filter, update, options);
return res;
});
}
static afterUpdateMany(oldDocs, newDocs) {
return __awaiter(this, void 0, void 0, function* () {
yield this.didUpdateMany(oldDocs, newDocs);
});
}
static beforeDeleteOne(filter, options) {
return __awaiter(this, void 0, void 0, function* () {
yield this.willDeleteOne(filter);
});
}
static afterDeleteOne(doc) {
return __awaiter(this, void 0, void 0, function* () {
if (doc) {
if ((0, utils_1.typeIsValidObjectId)(doc._id)) {
yield this.cascadeDelete(doc._id);
}
else {
const doc = docOrDocs;
if ((0, utils_1.typeIsValidObjectId)(doc._id)) {
yield this.cascadeDelete(doc._id);
}
}
yield this.didDeleteOne(doc);
});
}
static beforeDeleteMany(filter, options) {
return __awaiter(this, void 0, void 0, function* () {
this.willDeleteMany(filter);
});
}
static afterDeleteMany(docs) {
return __awaiter(this, void 0, void 0, function* () {
if (docs) {
for (const doc of docs) {
if (!(0, utils_1.typeIsValidObjectId)(doc._id))
continue;
yield this.cascadeDelete(doc._id);
}
}
yield this.didDeleteDocument(docOrDocs);
yield this.didDeleteMany(docs);
});
}
static beforeReplaceOne(filter, doc, options = {}) {
return __awaiter(this, void 0, void 0, function* () {
const modifiedDoc = yield this.willReplaceOne(filter, doc);
const res = yield this.processDocumentBeforeInsert(modifiedDoc, options);
return res;
});
}
static afterReplaceOne(oldDoc, newDoc) {
return __awaiter(this, void 0, void 0, function* () {
if (oldDoc) {
yield this.cascadeDelete(oldDoc._id);
}
yield this.didReplaceOne(oldDoc, newDoc);
});
}
/**

@@ -683,3 +749,70 @@ * Looks for documents **in all other registered collections** that have a foreign key to this

}
static processDocumentBeforeInsert(doc, _a = {}) {
var { ignoreTimestamps } = _a, opts = __rest(_a, ["ignoreTimestamps"]);
return __awaiter(this, void 0, void 0, function* () {
let docToInsert = (0, utils_1.sanitizeDocument)(this.schema, doc);
// Unless specified, always renew the `createdAt` and `updatedAt` fields.
if ((this.schema.timestamps === true) && (ignoreTimestamps !== true)) {
if (!lodash_1.default.isDate(docToInsert.createdAt))
docToInsert.createdAt = new Date();
if (!lodash_1.default.isDate(docToInsert.updatedAt))
docToInsert.updatedAt = new Date();
}
// Before inserting this document, go through each field and make sure that it has default
// values and that they are formatted correctly.
for (const key in this.schema.fields) {
if (!this.schema.fields.hasOwnProperty(key))
continue;
if (docToInsert.hasOwnProperty(key))
continue;
const defaultValue = this.defaultProps[key];
// Check if the field has a default value defined in the schema. If so, apply it.
if (lodash_1.default.isUndefined(defaultValue))
continue;
docToInsert[key] = (lodash_1.default.isFunction(defaultValue)) ? defaultValue() : defaultValue;
}
// Apply format function defined in the schema if applicable.
docToInsert = yield this.formatDocument(docToInsert);
// Finally, validate the document. Ignore unique indexes in this step. Let the db throw an
// error if the inserted doc violates those indexes.
yield this.validateDocument(docToInsert, Object.assign({ ignoreUniqueIndex: true, strict: true, accountForDotNotation: false }, opts));
return docToInsert;
});
}
/**
* @todo Handle remaining update operators.
*/
static processUpdateBeforeUpdate(filter, update, options = {}) {
var _a, _b, _c;
return __awaiter(this, void 0, void 0, function* () {
if ((options.upsert === true) && (this.schema.allowUpserts !== true))
throw new Error(`[${this.schema.model}] Attempting to upsert a document while upserting is disallowed in the schema`);
const updateToApply = (0, utils_1.sanitizeUpdate)(this.schema, update, options);
// Format all fields in the update filter.
if (updateToApply.$set) {
updateToApply.$set = yield this.formatDocument(updateToApply.$set);
}
// In the case of an upsert, we need to preprocess the filter as if this was an insertion. We
// also need to tell the database to save all fields in the filter as well, unless they are
// already in the update query.
if (options.upsert === true && (0, utils_1.typeIsAnyDocument)(filter)) {
// Make a copy of the filter in case it is manipulated by the hooks.
const docIfUpsert = yield this.processDocumentBeforeInsert(filter, Object.assign(Object.assign({}, options), { strict: false }));
const setOnInsert = lodash_1.default.omit(Object.assign(Object.assign({}, (_a = updateToApply.$setOnInsert) !== null && _a !== void 0 ? _a : {}), docIfUpsert), [
...Object.keys((_b = updateToApply.$set) !== null && _b !== void 0 ? _b : {}),
...Object.keys((_c = updateToApply.$unset) !== null && _c !== void 0 ? _c : {}),
]);
if (!lodash_1.default.isEmpty(setOnInsert)) {
updateToApply.$setOnInsert = setOnInsert;
}
}
// Validate all fields in the update. Account for dot notations to facilitate updating fields
// in nested fields.
if (updateToApply.$set && !lodash_1.default.isEmpty(updateToApply.$set)) {
yield this.validateDocument(updateToApply.$set, Object.assign(Object.assign({}, options), { ignoreUniqueIndex: true, accountForDotNotation: true }));
}
return updateToApply;
});
}
/**
* Validates a document of this model to see if the required fields (including nested fields)

@@ -686,0 +819,0 @@ * are in place.

@@ -114,4 +114,5 @@ import { CreateIndexesOptions, IndexSpecification, ObjectId } from 'mongodb';

* This array should contain a list of model names indicating that once a document in this
* collection is deleted, other documents in the models listed in this array should also be
* deleted if it has a foreign key to the deleted document.
* collection is deleted, other documents of the models listed in this array should also be
* deleted if they have a foreign key to the deleted document. Cascade deletion occurs **after**
* all event hooks.
*/

@@ -118,0 +119,0 @@ cascade?: string[];

@@ -17,5 +17,5 @@ import { Filter, ObjectId, UpdateFilter } from 'mongodb';

/**
* A document without `_id`.
* An insertable document.
*/
export declare type OptionallyIdentifiableDocument<P extends AnyProps = AnyProps> = Pick<Partial<Document<P>>, '_id'> & Omit<Document<P>, '_id'>;
export declare type InsertableDocument<P extends AnyProps = AnyProps> = Pick<Partial<Document<P>>, '_id'> & Omit<Document<P>, '_id'>;
/**

@@ -22,0 +22,0 @@ * A generic {@link Document}.

{
"name": "@andrewscwei/mongodb-odm",
"version": "0.80.1",
"version": "0.81.0",
"description": "ODM for MongoDB",

@@ -43,4 +43,4 @@ "main": "build/index.js",

"@types/mocha": "^9.0.0",
"@typescript-eslint/eslint-plugin": "^5.7.0",
"@typescript-eslint/parser": "^5.7.0",
"@typescript-eslint/eslint-plugin": "^5.8.0",
"@typescript-eslint/parser": "^5.8.0",
"cross-env": "^7.0.3",

@@ -47,0 +47,0 @@ "dotenv": "^10.0.0",

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc