From 1184295c0cadf04771fc377b0b6fd09507ceecc4 Mon Sep 17 00:00:00 2001
From: Hugo SUBTIL <ext.sopra.husubtil@grandlyon.com>
Date: Tue, 24 Nov 2020 14:06:40 +0100
Subject: [PATCH] feat: parse boolean string to boolean for search filter +
 Refacto

---
 .../categories-accompagnement.controller.ts   |  4 +-
 .../categories-formations.controller.ts       |  4 +-
 .../categories-others.controller.ts           |  4 +-
 .../categories-accompagnement.service.ts      |  4 +-
 .../services/categories-formations.service.ts |  4 +-
 .../services/categories-others.service.ts     |  4 +-
 src/structures/dto/query-structure.dto.ts     |  6 +++
 src/structures/schemas/filter.schema.ts       | 10 +++++
 src/structures/structures.controller.ts       | 29 +++++++-------
 src/structures/structures.service.ts          | 38 +++++++++++++++----
 10 files changed, 74 insertions(+), 33 deletions(-)
 create mode 100644 src/structures/dto/query-structure.dto.ts
 create mode 100644 src/structures/schemas/filter.schema.ts

diff --git a/src/categories/controllers/categories-accompagnement.controller.ts b/src/categories/controllers/categories-accompagnement.controller.ts
index 629a03708..a3333be16 100644
--- a/src/categories/controllers/categories-accompagnement.controller.ts
+++ b/src/categories/controllers/categories-accompagnement.controller.ts
@@ -8,12 +8,12 @@ export class CategoriesAccompagnementController {
   constructor(private readonly categoriesAccompagnementService: CategoriesAccompagnementService) {}
 
   @Post()
-  async create(@Body() createStructureDto: CreateCategoriesAccompagnement) {
+  public async create(@Body() createStructureDto: CreateCategoriesAccompagnement) {
     await this.categoriesAccompagnementService.create(createStructureDto);
   }
 
   @Get()
-  async findAll(): Promise<CategoriesAccompagnement[]> {
+  public async findAll(): Promise<CategoriesAccompagnement[]> {
     return this.categoriesAccompagnementService.findAll();
   }
 }
diff --git a/src/categories/controllers/categories-formations.controller.ts b/src/categories/controllers/categories-formations.controller.ts
index a3028f924..7b1ca152b 100644
--- a/src/categories/controllers/categories-formations.controller.ts
+++ b/src/categories/controllers/categories-formations.controller.ts
@@ -8,12 +8,12 @@ export class CategoriesFormationsController {
   constructor(private readonly categoriesFormationsService: CategoriesFormationsService) {}
 
   @Post()
-  async create(@Body() createStructureDto: CreateCategoriesFormations) {
+  public async create(@Body() createStructureDto: CreateCategoriesFormations) {
     await this.categoriesFormationsService.create(createStructureDto);
   }
 
   @Get()
-  async findAll(): Promise<CategoriesFormations[]> {
+  public async findAll(): Promise<CategoriesFormations[]> {
     return this.categoriesFormationsService.findAll();
   }
 }
diff --git a/src/categories/controllers/categories-others.controller.ts b/src/categories/controllers/categories-others.controller.ts
index 000159fe3..c535e195e 100644
--- a/src/categories/controllers/categories-others.controller.ts
+++ b/src/categories/controllers/categories-others.controller.ts
@@ -8,12 +8,12 @@ export class CategoriesOthersController {
   constructor(private readonly categoriesOthersService: CategoriesOthersService) {}
 
   @Post()
-  async create(@Body() createStructureDto: CreateCategoriesOthers) {
+  public async create(@Body() createStructureDto: CreateCategoriesOthers) {
     await this.categoriesOthersService.create(createStructureDto);
   }
 
   @Get()
-  async findAll(): Promise<CategoriesOthers[]> {
+  public async findAll(): Promise<CategoriesOthers[]> {
     return this.categoriesOthersService.findAll();
   }
 }
diff --git a/src/categories/services/categories-accompagnement.service.ts b/src/categories/services/categories-accompagnement.service.ts
index 049f28e35..830ad0c45 100644
--- a/src/categories/services/categories-accompagnement.service.ts
+++ b/src/categories/services/categories-accompagnement.service.ts
@@ -10,12 +10,12 @@ export class CategoriesAccompagnementService {
     @InjectModel(CategoriesAccompagnement.name) private structureModel: Model<CategoriesAccompagnementDocument>
   ) {}
 
-  async create(createDto: CreateCategoriesAccompagnement): Promise<CategoriesAccompagnement> {
+  public async create(createDto: CreateCategoriesAccompagnement): Promise<CategoriesAccompagnement> {
     const createdStructure = new this.structureModel(createDto);
     return createdStructure.save();
   }
 
-  async findAll(): Promise<CategoriesAccompagnement[]> {
+  public async findAll(): Promise<CategoriesAccompagnement[]> {
     return this.structureModel.find().exec();
   }
 }
diff --git a/src/categories/services/categories-formations.service.ts b/src/categories/services/categories-formations.service.ts
index bd6d6c66f..05ecae4af 100644
--- a/src/categories/services/categories-formations.service.ts
+++ b/src/categories/services/categories-formations.service.ts
@@ -8,12 +8,12 @@ import { CategoriesFormations, CategoriesFormationsDocument } from '../schemas/c
 export class CategoriesFormationsService {
   constructor(@InjectModel(CategoriesFormations.name) private structureModel: Model<CategoriesFormationsDocument>) {}
 
-  async create(createDto: CreateCategoriesFormations): Promise<CategoriesFormations> {
+  public async create(createDto: CreateCategoriesFormations): Promise<CategoriesFormations> {
     const createdStructure = new this.structureModel(createDto);
     return createdStructure.save();
   }
 
-  async findAll(): Promise<CategoriesFormations[]> {
+  public async findAll(): Promise<CategoriesFormations[]> {
     return this.structureModel.find().exec();
   }
 }
diff --git a/src/categories/services/categories-others.service.ts b/src/categories/services/categories-others.service.ts
index 3c34f0273..d229648e6 100644
--- a/src/categories/services/categories-others.service.ts
+++ b/src/categories/services/categories-others.service.ts
@@ -8,12 +8,12 @@ import { CategoriesOthers, CategoriesOthersDocument } from '../schemas/categorie
 export class CategoriesOthersService {
   constructor(@InjectModel(CategoriesOthers.name) private structureModel: Model<CategoriesOthersDocument>) {}
 
-  async create(createDto: CreateCategoriesOthers): Promise<CategoriesOthers> {
+  public async create(createDto: CreateCategoriesOthers): Promise<CategoriesOthers> {
     const createdStructure = new this.structureModel(createDto);
     return createdStructure.save();
   }
 
-  async findAll(): Promise<CategoriesOthers[]> {
+  public async findAll(): Promise<CategoriesOthers[]> {
     return this.structureModel.find().exec();
   }
 }
diff --git a/src/structures/dto/query-structure.dto.ts b/src/structures/dto/query-structure.dto.ts
new file mode 100644
index 000000000..4517495c1
--- /dev/null
+++ b/src/structures/dto/query-structure.dto.ts
@@ -0,0 +1,6 @@
+import { Filter } from '../schemas/filter.schema';
+
+export class QueryStructure {
+  query: string;
+  filters: Filter[];
+}
diff --git a/src/structures/schemas/filter.schema.ts b/src/structures/schemas/filter.schema.ts
new file mode 100644
index 000000000..d53ad3e75
--- /dev/null
+++ b/src/structures/schemas/filter.schema.ts
@@ -0,0 +1,10 @@
+import { SchemaFactory } from '@nestjs/mongoose';
+
+export type FilterDocument = Filter & Document;
+
+export class Filter {
+  name: string;
+  value: string | boolean;
+}
+
+export const FilterSchema = SchemaFactory.createForClass(Filter);
diff --git a/src/structures/structures.controller.ts b/src/structures/structures.controller.ts
index a60dea001..27fa79cc8 100644
--- a/src/structures/structures.controller.ts
+++ b/src/structures/structures.controller.ts
@@ -1,5 +1,6 @@
-import { Body, Controller, Get, Param, Post } from '@nestjs/common';
+import { Body, Controller, Get, Param, Post, Query, Req } from '@nestjs/common';
 import { CreateStructureDto } from './dto/create-structure.dto';
+import { QueryStructure } from './dto/query-structure.dto';
 import { Structure } from './schemas/structure.schema';
 import { StructuresService } from './structures.service';
 
@@ -8,22 +9,22 @@ export class StructuresController {
   constructor(private readonly structureService: StructuresService) {}
 
   @Post()
-  async create(@Body() createStructureDto: CreateStructureDto) {
+  public async create(@Body() createStructureDto: CreateStructureDto) {
     await this.structureService.create(createStructureDto);
   }
 
-  @Get()
-  async findAll(): Promise<Structure[]> {
-    return this.structureService.findAll();
+  @Post('search')
+  public async search(@Query() query: QueryStructure, @Body() body): Promise<Structure[]> {
+    return this.structureService.search(query.query, body ? body.filters : null);
   }
 
-  @Get(':text')
-  async search(@Param('text') text: string): Promise<Structure[]> {
-    return this.structureService.search(text);
+  @Get()
+  public async findAll(): Promise<Structure[]> {
+    return this.structureService.findAll();
   }
 
   @Get('count')
-  async countCategories(): Promise<Array<{ id: string; count: number }>> {
+  public async countCategories(): Promise<Array<{ id: string; count: number }>> {
     const data = await Promise.all([
       this.structureService.countByStructureKey('accesAuxDroits'),
       this.structureService.countByStructureKey('aideALaParentalite'),
@@ -34,11 +35,11 @@ export class StructuresController {
       this.structureService.countByStructureKey('publicsAcceptes'),
       this.structureService.countByStructureKey('modalitesDacces'),
       this.structureService.countByStructureKey('lesCompetencesDeBase'),
-      this.structureService.countByEquipmentsKey('wifiEnAccesLibre'),
-      this.structureService.countByEquipmentsKey('ordinateurs'),
-      this.structureService.countByEquipmentsKey('tablettes'),
-      this.structureService.countByEquipmentsKey('bornesNumeriques'),
-      this.structureService.countByEquipmentsKey('imprimantes'),
+      this.structureService.countByEquipmentsKey('wifiEnAccesLibre', 'Wifi en accès libre'),
+      this.structureService.countByEquipmentsKey('ordinateurs', 'Ordinateurs'),
+      this.structureService.countByEquipmentsKey('tablettes', 'Tablettes'),
+      this.structureService.countByEquipmentsKey('bornesNumeriques', 'Bornes numériques'),
+      this.structureService.countByEquipmentsKey('imprimantes', 'Imprimantes'),
     ]);
     // Return a concat of all arrays
     return data.reduce((a, b) => [...a, ...b]);
diff --git a/src/structures/structures.service.ts b/src/structures/structures.service.ts
index bd3f4f968..6b37ea7e5 100644
--- a/src/structures/structures.service.ts
+++ b/src/structures/structures.service.ts
@@ -2,22 +2,46 @@ import { Injectable } from '@nestjs/common';
 import { InjectModel } from '@nestjs/mongoose';
 import { Model } from 'mongoose';
 import { CreateStructureDto } from './dto/create-structure.dto';
+import { Filter } from './schemas/filter.schema';
 import { Structure, StructureDocument } from './schemas/structure.schema';
 
 @Injectable()
 export class StructuresService {
   constructor(@InjectModel(Structure.name) private structureModel: Model<StructureDocument>) {}
 
-  async create(createStructrureDto: CreateStructureDto): Promise<Structure> {
+  public async create(createStructrureDto: CreateStructureDto): Promise<Structure> {
     const createdStructure = new this.structureModel(createStructrureDto);
     return createdStructure.save();
   }
 
-  async search(searchString: string): Promise<Structure[]> {
-    return this.structureModel.find({ $text: { $search: searchString } }).exec();
+  public async search(searchString: string, filters?: Array<any>): Promise<Structure[]> {
+    let query: any;
+    if (searchString && filters) {
+      query = [...this.parseFilter(filters), { $text: { $search: searchString } }];
+    } else if (filters) {
+      query = this.parseFilter(filters);
+    } else {
+      query = [{ $text: { $search: searchString } }];
+    }
+    return this.structureModel.find({ $and: query }).exec();
   }
 
-  async findAll(): Promise<Structure[]> {
+  /**
+   * Parse filter value from string to boolean
+   * @param filters
+   */
+  private parseFilter(filters: Array<any>): Array<any> {
+    return filters.map((filter) => {
+      const key = Object.keys(filter)[0];
+      if (filter[key] === 'True') {
+        return { [key]: true };
+      } else {
+        return filter;
+      }
+    });
+  }
+
+  public async findAll(): Promise<Structure[]> {
     return this.structureModel.find().exec();
   }
 
@@ -26,7 +50,7 @@ export class StructuresService {
    * @param key structure key
    * @return [{id: 'key', count: 'value'}]
    */
-  async countByStructureKey(key: string): Promise<any> {
+  public async countByStructureKey(key: string): Promise<any> {
     const uniqueElements = await this.structureModel.distinct(key).exec();
     return await Promise.all(
       uniqueElements.map(async (value) => {
@@ -38,7 +62,7 @@ export class StructuresService {
     );
   }
 
-  async countByEquipmentsKey(key: string): Promise<any> {
-    return [{ id: key, count: await this.structureModel.countDocuments({ [key]: true }).exec() }];
+  public async countByEquipmentsKey(key: string, displayKey: string): Promise<any> {
+    return [{ id: displayKey, count: await this.structureModel.countDocuments({ [key]: true }).exec() }];
   }
 }
-- 
GitLab