-
Notifications
You must be signed in to change notification settings - Fork 2
/
builder.ts
191 lines (145 loc) · 5.09 KB
/
builder.ts
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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
import { FilterQuery, PipelineStage, Types } from "mongoose";
export type Sort = {
value: string | undefined,
fields: string[]
}
export type Search = {
value: string | undefined,
trash: string | undefined;
fields: string[]
}
export type Project = {
value: string | undefined;
fields: {
default: Record<string, boolean>,
alt?: Record<string, Record<string, boolean>>
}
}
export type Data = {
sort: Sort,
project: Project,
search: Search,
page: string | undefined
}
export const build = (data: Data, defaultStaging: PipelineStage[] = []): PipelineStage[] => {
let pipeLineStages: PipelineStage[] = [...defaultStaging];
if (data.search.value || data.search.trash) pipeLineStages.push({ $match: queryBuilder(data.search) })
if (data.project.value) pipeLineStages.push({ $project: projectionBuilder(data.project) })
if (data.sort.value) pipeLineStages.push({ $sort: sortingBuilder(data.sort) })
let pagination = paginationBuilder(data.page)
pipeLineStages = [...pipeLineStages, { $skip: pagination.skip }, { $limit: pagination.limit }]
return pipeLineStages
}
export const queryBuilder = (search: Search) => {
let query: FilterQuery<any> = {};
if (search.value) {
query.$or = [];
if (Types.ObjectId.isValid(search.value)) {
query.$or.push({ _id: search.value });
}
search.fields.forEach((field: string) => {
query.$or?.push({ [field]: { $regex: new RegExp(search.value ?? "", "ig") } });
});
}
query.deletedAt = search.trash ? { $ne: null } : null;
return query;
};
export const projectionBuilder = (projectFields: Project) => {
// Define an empty object to hold the final projection result
let projection: Record<string, boolean> = {}
// Include some default fields in the projection result
projectFields.fields.default = { ...projectFields.fields.default, updatedAt: true, deletedAt: true, createdAt: true }
// Check if any specific fields were requested for projection
if (projectFields.value) {
// Split the comma-separated fields into an array
let splitFields = projectFields.value.split(",")
// Loop over each requested field
for (let field of splitFields) {
// If the requested field is a default field, include it in the projection
if (projectFields.fields.default[field]) {
projection[field] = true;
continue;
}
// If there are no alternative fields, skip to the next field
if (!projectFields.fields.alt) {
continue
}
// If the requested field is an alternative field, check if any subfields were included
if (projectFields.fields.alt[field]) {
let foundSubfield = false;
for (let subfield of splitFields) {
if (subfield.includes(field + ".")) {
foundSubfield = true
break;
}
}
// If no subfields were included, include the alternative field in the projection
if (!foundSubfield) {
projection[field] = true;
}
continue;
}
// If the requested field is a combination of multiple fields, check if both fields exist in the alternative fields
if (field.includes(".")) {
// Split the field into two subfields
let splitField = field.split(".");
// Check if both subfields exist in the alternative fields
if (projectFields.fields.alt[splitField[0]] && projectFields.fields.alt[splitField[0]][splitField[1]]) {
projection[field] = true
}
}
}
}
return projection
};
export const sortingBuilder = (sort: { value: string | undefined; fields: string[] }) => {
let sortingCriteria: Record<string, 1 | -1> = {};
sort.fields = [...sort.fields, "createdAt", "updatedAt", "deletedAt"]
if (sort.value) {
let splitedfields = sort.value.split(",");
for (let field of splitedfields) {
if (field.includes(":")) {
let [fieldName, order] = field.split(":")
if (!sort.fields.includes(fieldName)) {
continue;
}
sortingCriteria[fieldName] = order === "desc" ? -1 : 1;
continue;
}
if (!sort.fields.includes(field)) {
continue;
}
sortingCriteria[field] = 1
}
}
return sortingCriteria
};
/**
* This function used to create pagination
*
* @param paginationValue : number = 8 is the number of displayed documents
* @param page : number = 0 is the displayed page
* @returns { skib : number, limit : number }
* */
export const paginationBuilder = (page: string | undefined, paginationValue: number = 8): { skip: number; limit: number } => {
return {
skip: Number(page) ? Number(page) * paginationValue - paginationValue : 0,
limit: paginationValue,
};
};
/**
* generate random id that can be used to index a file in storage
* */
export const randomId = () => {
return Date.now() + "-" + Math.round(Math.random() * 1e9);
};
export const paginate = (data: any, count: number, page: string | undefined) => {
const pagination = paginationBuilder(page)
return {
data,
limit: pagination.limit,
skip: pagination.skip,
count,
page: Number(page) ? Number(page) : 1,
};
};