fix: add flatten syntax to udapteOne and UpdateMany

This commit is contained in:
yassinedorbozgithub 2025-05-06 08:34:30 +01:00
parent eae5eb4a64
commit 521619be0f
4 changed files with 65 additions and 18 deletions

View File

@ -175,9 +175,15 @@ export class ConversationService extends BaseService<
const criteria =
typeof convo.sender === 'object' ? convo.sender.id : convo.sender;
await this.subscriberService.updateOne(criteria, {
context: profile.context,
});
await this.subscriberService.updateOne(
criteria,
{
context: profile.context,
},
{
flatten: true,
},
);
return updatedConversation;
} catch (err) {

View File

@ -21,7 +21,6 @@ import {
Model,
ProjectionType,
Query,
QueryOptions,
SortOrder,
UpdateQuery,
UpdateWithAggregationPipeline,
@ -29,7 +28,11 @@ import {
} from 'mongoose';
import { LoggerService } from '@/logger/logger.service';
import { TFilterQuery } from '@/utils/types/filter.types';
import {
TFilterQuery,
TFlattenOption,
TQueryOptions,
} from '@/utils/types/filter.types';
import { PageQueryDto, QuerySortDto } from '../pagination/pagination-query.dto';
import { DtoAction, DtoConfig, DtoInfer } from '../types/dto.types';
@ -96,6 +99,24 @@ export abstract class BaseRepository<
this.registerLifeCycleHooks();
}
private flatten(obj: object, prefix: string = '', result = {}) {
for (const [key, value] of Object.entries(obj)) {
const path = prefix ? `${prefix}.${key}` : key;
if (
typeof value === 'object' &&
value !== null &&
!Array.isArray(value)
) {
this.flatten(value, path, result);
} else {
result[path] = value;
}
}
return result;
}
canPopulate(populate: string[]): boolean {
return populate.some((p) => this.populate.includes(p as P));
}
@ -495,18 +516,20 @@ export abstract class BaseRepository<
async updateOne<D extends Partial<U>>(
criteria: string | TFilterQuery<T>,
dto: UpdateQuery<DtoInfer<DtoAction.Update, Dto, D>>,
options: QueryOptions<D> | null = {
new: true,
},
options?: TQueryOptions<D>,
): Promise<T> {
const { flatten, ...rest } = {
new: true,
...options,
};
const query = this.model.findOneAndUpdate<T>(
{
...(typeof criteria === 'string' ? { _id: criteria } : criteria),
},
{
$set: dto,
$set: flatten ? this.flatten(dto) : dto,
},
options,
rest,
);
const filterCriteria = query.getFilter();
const queryUpdates = query.getUpdate();
@ -541,9 +564,10 @@ export abstract class BaseRepository<
async updateMany<D extends Partial<U>>(
filter: TFilterQuery<T>,
dto: UpdateQuery<D>,
options?: TFlattenOption,
): Promise<UpdateWriteOpResult> {
return await this.model.updateMany<T>(filter, {
$set: dto,
$set: options?.flatten ? this.flatten(dto) : dto,
});
}

View File

@ -9,10 +9,14 @@
import { ConflictException, Inject } from '@nestjs/common';
import { ClassTransformOptions } from 'class-transformer';
import { MongoError } from 'mongodb';
import { ProjectionType, QueryOptions } from 'mongoose';
import { ProjectionType } from 'mongoose';
import { LoggerService } from '@/logger/logger.service';
import { TFilterQuery } from '@/utils/types/filter.types';
import {
TFilterQuery,
TFlattenOption,
TQueryOptions,
} from '@/utils/types/filter.types';
import { PageQueryDto, QuerySortDto } from '../pagination/pagination-query.dto';
import { DtoAction, DtoConfig, DtoInfer } from '../types/dto.types';
@ -188,13 +192,17 @@ export abstract class BaseService<
async updateOne(
criteria: string | TFilterQuery<T>,
dto: DtoInfer<DtoAction.Update, Dto, Partial<U>>,
options?: QueryOptions<Partial<U>> | null,
options?: TQueryOptions<Partial<U>>,
): Promise<T> {
return await this.repository.updateOne(criteria, dto, options);
}
async updateMany(filter: TFilterQuery<T>, dto: Partial<U>) {
return await this.repository.updateMany(filter, dto);
async updateMany(
filter: TFilterQuery<T>,
dto: Partial<U>,
options?: TFlattenOption,
) {
return await this.repository.updateMany(filter, dto, options);
}
async deleteOne(criteria: string | TFilterQuery<T>) {

View File

@ -1,12 +1,17 @@
/*
* Copyright © 2024 Hexastack. All rights reserved.
* Copyright © 2025 Hexastack. All rights reserved.
*
* Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms:
* 1. The name "Hexabot" is a trademark of Hexastack. You may not use this name in derivative works without express written permission.
* 2. All derivative works must include clear attribution to the original creator and software, Hexastack and Hexabot, in a prominent location (e.g., in the software's "About" section, documentation, and README file).
*/
import { HydratedDocument, QuerySelector, RootQuerySelector } from 'mongoose';
import {
HydratedDocument,
QueryOptions,
QuerySelector,
RootQuerySelector,
} from 'mongoose';
export type TFilterKeysOfType<T, U> = {
[K in keyof T]: T[K] extends U ? K : never;
@ -137,3 +142,7 @@ export type TFilterQuery<T, S = TReplaceId<T>> = (
WithoutGenericAny<RootQuerySelector<S>>;
export type THydratedDocument<T> = TOmitId<HydratedDocument<T>>;
export type TFlattenOption = { flatten?: boolean };
export type TQueryOptions<D> = (QueryOptions<D> & TFlattenOption) | null;