File size: 2,321 Bytes
484fdbc
 
 
 
 
 
 
 
 
 
 
 
 
61c7d9c
484fdbc
 
 
61c7d9c
 
 
484fdbc
 
61c7d9c
 
 
 
 
 
 
 
 
 
 
484fdbc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61c7d9c
484fdbc
 
 
 
61c7d9c
 
 
 
 
 
484fdbc
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
import { HttpError } from "@lib/error-handling/http-error";
import { AnyKeys, Document, FilterQuery, Model } from "mongoose";

export const CrudService = <ModelDoc extends Document>(
  model: Model<ModelDoc>
) => {
  return class CrudServiceClass {
    protected model: Model<ModelDoc> = model;

    async create(data: AnyKeys<ModelDoc>): Promise<ModelDoc> {
      return this.model.create(data);
    }

    async updateOne(
      filter: FilterQuery<ModelDoc>,
      data: AnyKeys<ModelDoc>
    ): Promise<ModelDoc> {
      await this.existsOrThrow(filter);
      await this.model.updateOne(filter, data);
      return this.findOneOrFail(filter);
    }

    async updateMany(
      filter: FilterQuery<ModelDoc>,
      data: AnyKeys<ModelDoc>
    ): Promise<ModelDoc[]> {
      await this.existsOrThrow(filter);
      await this.model.updateMany(filter, data);
      return this.model.find(filter);
    }

    async deleteOne(filter: FilterQuery<ModelDoc>): Promise<ModelDoc> {
      await this.existsOrThrow(filter);
      return this.model.findOneAndDelete(filter);
    }

    async list(
      filter: FilterQuery<ModelDoc>,
      paginationOptions: {
        limit?: number;
        skip?: number;
      } = {
        limit: 10,
        skip: 0,
      }
    ): Promise<{
      docs: ModelDoc[];
      paginationData: {
        total: number;
        page: number;
        perPage: number;
      };
    }> {
      const docs = await this.model
        .find(filter)
        .limit(paginationOptions.limit)
        .skip(paginationOptions.skip);

      const total = await this.model.countDocuments(filter);
      const paginationData = {
        total: total,
        page: paginationOptions.skip,
        perPage: paginationOptions.limit,
      };

      return { docs, paginationData };
    }

    async findOne(filter: FilterQuery<ModelDoc>): Promise<ModelDoc | null> {
      return this.model.findOne(filter);
    }

    async findOneOrFail(filter: FilterQuery<ModelDoc>): Promise<ModelDoc> {
      await this.existsOrThrow(filter);
      const document = await this.findOne(filter);

      return document;
    }

    private async existsOrThrow(filter: FilterQuery<ModelDoc>) {
      if (!(await this.model.exists(filter))) {
        throw new HttpError(404, "No Matching Result Found.");
      }
    }
  };
};