@tmlmobilidade/interfaces
Version:
This package provides SDK-style connectors for interacting with databases (e.g., stops, plans, rides, alerts) and external providers (e.g., authentication, storage). It simplifies data access and integration across projects.
249 lines (248 loc) • 9.64 kB
JavaScript
/* * */
import { MongoConnector } from '@tmlmobilidade/connectors';
import { HttpException, HttpStatus } from '@tmlmobilidade/lib';
import { Dates, generateRandomString } from '@tmlmobilidade/utils';
/* * */
export class MongoCollectionClass {
createSchema = null;
mongoCollection;
mongoConnector;
updateSchema = null;
/**
* Gets all documents in the collection.
*
* @returns A promise that resolves to an array of all documents
*/
async all() {
return await this.mongoCollection.find().toArray();
}
/**
* Establishes a connection to the Mongo database and initializes the collection.
* @param options Optional Mongo client connection options
* @throws {Error} If connection fails
*/
async connect(options) {
//
const dbUri = process.env[this.getEnvName()];
if (!dbUri) {
throw new Error(`Missing ${this.getEnvName()} environment variable`);
}
try {
// Connect to the MongoDB database
this.mongoConnector = new MongoConnector(dbUri, options);
await this.mongoConnector.connect();
// Setup collection
this.mongoCollection = this.mongoConnector.client.db('production').collection(this.getCollectionName());
// Create indexes, if any are defined
// TODO: This should be refactored as indexes should be created in the database setup script
if (process.env.NODE_ENV === 'test' && this.getCollectionIndexes().length > 0) {
await this.mongoCollection.createIndexes(this.getCollectionIndexes());
}
}
catch (error) {
throw new Error(`Error connecting to ${this.getCollectionName()}`, { cause: error });
}
}
/**
* Counts documents matching the filter criteria.
*
* @param filter - The filter criteria to match documents
* @returns A promise that resolves to the count of matching documents
*/
async count(filter) {
return this.mongoCollection.countDocuments(filter);
}
/**
* Deletes a single document by its ID.
*
* @param id - The ID of the document to delete
* @returns A promise that resolves to the result of the delete operation
*/
async deleteById(id, options) {
return this.mongoCollection.deleteOne({ _id: { $eq: id } }, options);
}
/**
* Deletes multiple documents matching the filter criteria.
*
* @param filter - The filter criteria to match documents to delete
* @returns A promise that resolves to the result of the delete operation
*/
async deleteMany(filter) {
return this.mongoCollection.deleteMany(filter);
}
/**
* Deletes a single document matching the filter criteria.
*
* @param filter - The filter criteria to match the document to delete
* @returns A promise that resolves to the result of the delete operation
*/
async deleteOne(filter) {
return this.mongoCollection.deleteOne(filter);
}
/**
* Disconnects from the MongoDB database.
*/
async disconnect() {
await this.mongoConnector.disconnect();
}
/**
* Finds all distinct values for a key in the collection.
*
* @param key - The key to find distinct values for
* @returns A promise that resolves to an array of distinct values for the given key
*/
async distinct(key) {
return this.mongoCollection.distinct(key);
}
/**
* Finds a document by its ID.
*
* @param id - The ID of the document to find
* @returns A promise that resolves to the matching document or null if not found
*/
async findById(id, options) {
return this.mongoCollection.findOne({ _id: { $eq: id } }, options);
}
/**
* Finds multiple documents matching the filter criteria with optional pagination and sorting.
*
* @param filter - (Optional) filter criteria to match documents
* @param perPage - (Optional) number of documents per page for pagination
* @param page - (Optional) page number for pagination
* @param sort - (Optional) sort specification
* @returns A promise that resolves to an array of matching documents
*/
async findMany(filter, perPage, page, sort) {
const query = this.mongoCollection.find(filter ?? {});
if (perPage)
query.limit(perPage);
if (page && perPage)
query.skip(perPage * (page - 1));
if (sort)
query.sort(sort);
return query.toArray();
}
/**
* Finds a single document matching the filter criteria.
*
* @param filter - The filter criteria to match the document
* @returns A promise that resolves to the matching document or null if not found
*/
async findOne(filter) {
return this.mongoCollection.findOne(filter);
}
/**
* Gets the MongoDB collection instance.
*
* @returns The MongoDB collection instance
*/
async getCollection() {
return this.mongoCollection;
}
getMongoConnector() {
return this.mongoConnector;
}
/**
* Inserts a single document into the collection.
*
* @param doc - The document to insert
* @param options - The options for the insert operation
* @returns A promise that resolves to the result of the insert operation
*/
async insertOne(doc, { options, unsafe = false } = {}) {
const newDocument = {
...doc,
_id: doc._id || generateRandomString({ length: 5 }),
created_at: doc.created_at || Dates.now('utc').unix_timestamp,
updated_at: doc.updated_at || Dates.now('utc').unix_timestamp,
};
if (!doc._id) {
while (await this.findById(newDocument._id)) {
newDocument._id = generateRandomString({ length: 5 });
}
}
let parsedDocument = newDocument;
if (!unsafe) {
try {
if (!this.createSchema) {
throw new Error('No schema defined for insert operation. This is either an internal interface error or you should pass unsafe=true to the insert operation.');
}
parsedDocument = this.createSchema.parse(newDocument);
}
catch (error) {
throw new HttpException(HttpStatus.BAD_REQUEST, error.message, { cause: error });
}
}
return this.mongoCollection.insertOne(parsedDocument, options);
}
/**
* Updates a single document matching the filter criteria.
*
* @param filter - The filter criteria to match the document to update
* @param updateFields - The fields to update in the document
* @param options - The options for the update operation
* @returns A promise that resolves to the result of the update operation
*/
async updateById(id, updateFields, options) {
return this.updateOne({ _id: { $eq: id } }, updateFields, options);
}
// /**
// * Inserts multiple documents into the collection.
// *
// * @param docs - Array of documents to insert
// * @returns A promise that resolves to the result of the insert operation
// */
// async insertMany(docs: OptionalUnlessRequiredId<T>[]) {
// if (this.createSchema) {
// for (const doc of docs) {
// try {
// this.createSchema.parse(doc);
// }
// catch (error) {
// throw new HttpException(HttpStatus.BAD_REQUEST, error.message, { cause: error });
// }
// }
// }
// return this.mongoCollection.insertMany(docs.map(doc => ({ ...doc, created_at: new Date(), updated_at: new Date() })));
// }
/**
* Updates multiple documents matching the filter criteria.
*
* @param filter - The filter criteria to match documents to update
* @param updateFields - The fields to update in the documents
* @param options - The options for the update operation
* @returns A promise that resolves to the result of the update operation
*/
async updateMany(filter, updateFields, options) {
let parsedUpdateFields = updateFields;
if (this.updateSchema) {
try {
parsedUpdateFields = this.updateSchema.parse(updateFields);
}
catch (error) {
throw new HttpException(HttpStatus.BAD_REQUEST, error.message, { cause: error });
}
}
return this.mongoCollection.updateMany(filter, { $set: { ...parsedUpdateFields, updated_at: Dates.now('utc').unix_timestamp } }, options);
}
/**
* Updates a single document matching the filter criteria.
*
* @param filter - The filter criteria to match the document to update
* @param updateFields - The fields to update in the document
* @param options - The options for the update operation
* @returns A promise that resolves to the result of the update operation
*/
async updateOne(filter, updateFields, options) {
let parsedUpdateFields = updateFields;
if (this.updateSchema) {
try {
parsedUpdateFields = this.updateSchema.parse(updateFields);
}
catch (error) {
throw new HttpException(HttpStatus.BAD_REQUEST, error.message, { cause: error });
}
}
return this.mongoCollection.updateOne(filter, { $set: { ...parsedUpdateFields, updated_at: Dates.now('utc').unix_timestamp } }, options);
}
}