UNPKG

jsm-utilities

Version:
196 lines (195 loc) 6.83 kB
"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;