mirror of
				https://github.com/KevinMidboe/immich.git
				synced 2025-10-29 17:40:28 +00:00 
			
		
		
		
	fix(server): people sorting (#3713)
This commit is contained in:
		| @@ -4,6 +4,7 @@ export const IPersonRepository = 'IPersonRepository'; | |||||||
|  |  | ||||||
| export interface PersonSearchOptions { | export interface PersonSearchOptions { | ||||||
|   minimumFaceCount: number; |   minimumFaceCount: number; | ||||||
|  |   withHidden: boolean; | ||||||
| } | } | ||||||
|  |  | ||||||
| export interface UpdateFacesData { | export interface UpdateFacesData { | ||||||
|   | |||||||
| @@ -47,7 +47,7 @@ describe(PersonService.name, () => { | |||||||
|         visible: 1, |         visible: 1, | ||||||
|         people: [responseDto], |         people: [responseDto], | ||||||
|       }); |       }); | ||||||
|       expect(personMock.getAll).toHaveBeenCalledWith(authStub.admin.id, { minimumFaceCount: 1 }); |       expect(personMock.getAll).toHaveBeenCalledWith(authStub.admin.id, { minimumFaceCount: 1, withHidden: false }); | ||||||
|     }); |     }); | ||||||
|     it('should get all visible people with thumbnails', async () => { |     it('should get all visible people with thumbnails', async () => { | ||||||
|       personMock.getAll.mockResolvedValue([personStub.withName, personStub.hidden]); |       personMock.getAll.mockResolvedValue([personStub.withName, personStub.hidden]); | ||||||
| @@ -56,7 +56,7 @@ describe(PersonService.name, () => { | |||||||
|         visible: 1, |         visible: 1, | ||||||
|         people: [responseDto], |         people: [responseDto], | ||||||
|       }); |       }); | ||||||
|       expect(personMock.getAll).toHaveBeenCalledWith(authStub.admin.id, { minimumFaceCount: 1 }); |       expect(personMock.getAll).toHaveBeenCalledWith(authStub.admin.id, { minimumFaceCount: 1, withHidden: false }); | ||||||
|     }); |     }); | ||||||
|     it('should get all hidden and visible people with thumbnails', async () => { |     it('should get all hidden and visible people with thumbnails', async () => { | ||||||
|       personMock.getAll.mockResolvedValue([personStub.withName, personStub.hidden]); |       personMock.getAll.mockResolvedValue([personStub.withName, personStub.hidden]); | ||||||
| @@ -73,7 +73,7 @@ describe(PersonService.name, () => { | |||||||
|           }, |           }, | ||||||
|         ], |         ], | ||||||
|       }); |       }); | ||||||
|       expect(personMock.getAll).toHaveBeenCalledWith(authStub.admin.id, { minimumFaceCount: 1 }); |       expect(personMock.getAll).toHaveBeenCalledWith(authStub.admin.id, { minimumFaceCount: 1, withHidden: true }); | ||||||
|     }); |     }); | ||||||
|   }); |   }); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -26,8 +26,10 @@ export class PersonService { | |||||||
|   ) {} |   ) {} | ||||||
|  |  | ||||||
|   async getAll(authUser: AuthUserDto, dto: PersonSearchDto): Promise<PeopleResponseDto> { |   async getAll(authUser: AuthUserDto, dto: PersonSearchDto): Promise<PeopleResponseDto> { | ||||||
|     const people = await this.repository.getAll(authUser.id, { minimumFaceCount: 1 }); |     const people = await this.repository.getAll(authUser.id, { | ||||||
|  |       minimumFaceCount: 1, | ||||||
|  |       withHidden: dto.withHidden || false, | ||||||
|  |     }); | ||||||
|     const persons: PersonResponseDto[] = people |     const persons: PersonResponseDto[] = people | ||||||
|       // with thumbnails |       // with thumbnails | ||||||
|       .filter((person) => !!person.thumbnailPath) |       .filter((person) => !!person.thumbnailPath) | ||||||
|   | |||||||
| @@ -51,16 +51,22 @@ export class PersonRepository implements IPersonRepository { | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   getAll(userId: string, options?: PersonSearchOptions): Promise<PersonEntity[]> { |   getAll(userId: string, options?: PersonSearchOptions): Promise<PersonEntity[]> { | ||||||
|     return this.personRepository |     const queryBuilder = this.personRepository | ||||||
|       .createQueryBuilder('person') |       .createQueryBuilder('person') | ||||||
|       .leftJoin('person.faces', 'face') |       .leftJoin('person.faces', 'face') | ||||||
|       .where('person.ownerId = :userId', { userId }) |       .where('person.ownerId = :userId', { userId }) | ||||||
|       .orderBy('COUNT(face.assetId)', 'DESC') |       .orderBy('person.isHidden', 'ASC') | ||||||
|  |       .addOrderBy("NULLIF(person.name, '') IS NULL", 'ASC') | ||||||
|  |       .addOrderBy('COUNT(face.assetId)', 'DESC') | ||||||
|       .addOrderBy("NULLIF(person.name, '')", 'ASC', 'NULLS LAST') |       .addOrderBy("NULLIF(person.name, '')", 'ASC', 'NULLS LAST') | ||||||
|       .having('COUNT(face.assetId) >= :faces', { faces: options?.minimumFaceCount || 1 }) |       .having('COUNT(face.assetId) >= :faces', { faces: options?.minimumFaceCount || 1 }) | ||||||
|       .groupBy('person.id') |       .groupBy('person.id') | ||||||
|       .limit(500) |       .limit(500); | ||||||
|       .getMany(); |     if (!options?.withHidden) { | ||||||
|  |       queryBuilder.andWhere('person.isHidden = false'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return queryBuilder.getMany(); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   getAllWithoutFaces(): Promise<PersonEntity[]> { |   getAllWithoutFaces(): Promise<PersonEntity[]> { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user