jsm-utilities
Version:
A utilities library.
196 lines (195 loc) • 6.83 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createAggregateFilterBuilder = exports.AggregateFilterBuilder = void 0;
const query_utilities_v2_1 = require("./query.utilities.v2");
/**
* Fluent aggregation filter builder for creating MongoDB $match pipeline stages with method chaining.
*
* This class provides a chainable interface for building aggregation pipeline $match stages.
*
* @template F - Field names type constraint (extends string)
*
* @example
* ```typescript
* const builder = createAggregateFilterBuilder<UserFields>()
* .string('name', 'john', { mode: 'contains' })
* .number('age', { min: 18, max: 65 })
* .boolean('isActive', true)
* .dateRange('createdAt', [startDate, endDate]);
*
* const { pipeline } = builder.build();
* ```
*
* @since 2.0.0
*/
class AggregateFilterBuilder {
constructor(separateMatches = false) {
this.pipeline = [];
this.tempMatch = {};
this.separateMatches = separateMatches;
if (separateMatches) {
this.pipeline = [];
this.tempMatch = {};
}
else {
this.pipeline = [{ $match: {} }];
this.tempMatch = {};
}
}
addMatchStage() {
if (Object.keys(this.tempMatch).length > 0) {
if (this.separateMatches) {
this.pipeline.push({ $match: this.tempMatch });
}
else {
this.pipeline[0].$match = Object.assign(Object.assign({}, this.pipeline[0].$match), this.tempMatch);
}
this.tempMatch = {};
}
}
/**
* Adds a string filter to the aggregation pipeline.
*/
string(field, value, options) {
const result = (0, query_utilities_v2_1.createStringFilter)({ where: (filter) => (Object.assign(Object.assign({}, this.tempMatch), filter)) }, null, value, field, options);
this.tempMatch = result.q;
this.addMatchStage();
return this;
}
/**
* Adds a number filter to the aggregation pipeline.
*/
number(field, value, options) {
const result = (0, query_utilities_v2_1.createNumberFilter)({ where: (filter) => (Object.assign(Object.assign({}, this.tempMatch), filter)) }, null, value, field, options);
this.tempMatch = result.q;
this.addMatchStage();
return this;
}
/**
* Adds a date range filter to the aggregation pipeline.
*/
dateRange(field, value, options) {
const result = (0, query_utilities_v2_1.createDateRangeFilter)({ where: (filter) => (Object.assign(Object.assign({}, this.tempMatch), filter)) }, null, value, field, options);
this.tempMatch = result.q;
this.addMatchStage();
return this;
}
/**
* Adds a boolean filter to the aggregation pipeline.
*/
boolean(field, value, omit) {
const result = (0, query_utilities_v2_1.createBooleanFilter)({ where: (filter) => (Object.assign(Object.assign({}, this.tempMatch), filter)) }, null, value, field, omit);
this.tempMatch = result.q;
this.addMatchStage();
return this;
}
/**
* Adds an array filter to the aggregation pipeline.
*/
array(field, value, options) {
const result = (0, query_utilities_v2_1.createArrayFilter)({ where: (filter) => (Object.assign(Object.assign({}, this.tempMatch), filter)) }, null, value, field, options);
this.tempMatch = result.q;
this.addMatchStage();
return this;
}
/**
* Adds a geospatial filter to the aggregation pipeline.
*/
geo(field, geoFilter) {
const result = (0, query_utilities_v2_1.createGeoFilter)({ where: (filter) => (Object.assign(Object.assign({}, this.tempMatch), filter)) }, null, geoFilter, field);
this.tempMatch = result.q;
this.addMatchStage();
return this;
}
/**
* Adds a text search filter to the aggregation pipeline.
*/
textSearch(searchText, options) {
const result = (0, query_utilities_v2_1.createTextSearchFilter)({ where: (filter) => (Object.assign(Object.assign({}, this.tempMatch), filter)) }, null, searchText, options);
this.tempMatch = result.q;
this.addMatchStage();
return this;
}
/**
* Applies multiple filters using a configuration object.
*/
configurable(filters, config) {
const result = (0, query_utilities_v2_1.createConfigurableFilter)({ where: (filter) => (Object.assign(Object.assign({}, this.tempMatch), filter)) }, null, filters, config);
this.tempMatch = result.q;
this.addMatchStage();
return this;
}
/**
* Applies a custom filter function for advanced filtering scenarios.
*/
custom(filterFn) {
const result = filterFn(this.pipeline);
this.pipeline = result.pipeline;
return this;
}
/**
* Builds and returns the final aggregation pipeline result.
*/
build() {
return this.pipeline;
}
/**
* Gets the current aggregation pipeline.
*/
getPipeline() {
return this.pipeline;
}
/**
* Resets the builder to a new initial state with empty pipeline.
*/
reset() {
this.pipeline = [];
this.tempMatch = {};
return this;
}
/**
* Creates a clone of the current builder with the same state.
*/
clone() {
const newBuilder = new AggregateFilterBuilder();
newBuilder.pipeline = [...this.pipeline];
newBuilder.tempMatch = Object.assign({}, this.tempMatch);
return newBuilder;
}
}
exports.AggregateFilterBuilder = AggregateFilterBuilder;
/**
* Factory function to create a new AggregateFilterBuilder instance with fluent interface.
*
* @template F - Union type of allowed field names for type safety
* @template T - Document type (typically a Mongoose Document)
*
* @returns A new AggregateFilterBuilder instance ready for method chaining
*
* @example
* ```typescript
* // Basic usage
* const builder = createAggregateFilterBuilder<UserFields>()
* .string('name', 'john')
* .number('age', 25, { operator: 'gte' })
* .boolean('active', true);
*
* const { pipeline } = builder.build();
*
* // With typed field names
* type UserFields = 'name' | 'email' | 'age' | 'active';
* const typedBuilder = createAggregateFilterBuilder<UserFields>()
* .string('name', 'john') // ✅ Type-safe
* .number('invalidField', 123); // ❌ TypeScript error
*
* // Usage with Mongoose
* const results = await Model.aggregate([
* ...pipeline,
* // Additional stages
* ]);
* ```
*/
const createAggregateFilterBuilder = () => {
return new AggregateFilterBuilder();
};
exports.createAggregateFilterBuilder = createAggregateFilterBuilder;