@go-mailer/jarvis 3.2.0 → 3.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -0
- package/lib/query.js +86 -3
- package/package.json +4 -1
- package/test/query.test.js +46 -0
package/README.md
CHANGED
|
@@ -219,6 +219,11 @@ Keywords in request queries are used to prepare the following queries. Given the
|
|
|
219
219
|
```
|
|
220
220
|
GET https://go-mailer.com?count=1
|
|
221
221
|
```
|
|
222
|
+
6. **group**: To group items that match the query by a certain field, the `group_by` keyword is used.
|
|
223
|
+
|
|
224
|
+
```
|
|
225
|
+
GET https://go-mailer.com?group_by=age
|
|
226
|
+
```
|
|
222
227
|
|
|
223
228
|
### **Special Characters**
|
|
224
229
|
The use of special characters in query values indicate the need to prepare the following queries:
|
package/lib/query.js
CHANGED
|
@@ -2,7 +2,8 @@ const buildQuery = (options) => {
|
|
|
2
2
|
const sort_condition = options.sort_by ? buildSortOrderString(options.sort_by) : ''
|
|
3
3
|
const fields_to_return = options.return_only ? buildReturnFieldsString(options.return_only) : ''
|
|
4
4
|
const count = options.count || false
|
|
5
|
-
const seek_conditions = options.bool ? { ...buildBooleanQuery(options.bool || '')} : {}
|
|
5
|
+
const seek_conditions = options.bool ? { ...buildBooleanQuery(options.bool || '') } : {}
|
|
6
|
+
const group_by = options.group_by || null
|
|
6
7
|
|
|
7
8
|
const { skip, limit } = determinePagination(options.page, options.population)
|
|
8
9
|
|
|
@@ -31,8 +32,21 @@ const buildQuery = (options) => {
|
|
|
31
32
|
seek_conditions[field] = { ...condition }
|
|
32
33
|
})
|
|
33
34
|
|
|
35
|
+
let pipeline = []
|
|
36
|
+
if (group_by) {
|
|
37
|
+
pipeline = generatePipeline({
|
|
38
|
+
group_by,
|
|
39
|
+
seek_conditions,
|
|
40
|
+
fields_to_return,
|
|
41
|
+
sort_condition,
|
|
42
|
+
skip,
|
|
43
|
+
limit
|
|
44
|
+
})
|
|
45
|
+
}
|
|
46
|
+
|
|
34
47
|
return {
|
|
35
48
|
count,
|
|
49
|
+
group_by,
|
|
36
50
|
fields_to_return,
|
|
37
51
|
limit,
|
|
38
52
|
seek_conditions,
|
|
@@ -50,7 +64,7 @@ const buildBooleanQuery = (value) => {
|
|
|
50
64
|
truthiness = false
|
|
51
65
|
key = val.substr(1)
|
|
52
66
|
}
|
|
53
|
-
|
|
67
|
+
|
|
54
68
|
return {
|
|
55
69
|
...sac,
|
|
56
70
|
[key]: truthiness
|
|
@@ -108,6 +122,12 @@ const buildWildcardOptions = (key_list, value) => {
|
|
|
108
122
|
}
|
|
109
123
|
}
|
|
110
124
|
|
|
125
|
+
const cleanGroupBy = (value) => {
|
|
126
|
+
if (!value || typeof value !== string) return null
|
|
127
|
+
|
|
128
|
+
return value.split(',')[0]
|
|
129
|
+
}
|
|
130
|
+
|
|
111
131
|
const determinePagination = (page = 0, population = Number.MAX_SAFE_INTEGER) => {
|
|
112
132
|
return {
|
|
113
133
|
limit: Number(population),
|
|
@@ -115,6 +135,68 @@ const determinePagination = (page = 0, population = Number.MAX_SAFE_INTEGER) =>
|
|
|
115
135
|
}
|
|
116
136
|
}
|
|
117
137
|
|
|
138
|
+
const generateGroupPipeline = ({ group_by, seek_conditions, sort_condition, skip, limit, fields_to_return, count }) => {
|
|
139
|
+
if (!group_by || typeof group_by !== 'string') return null
|
|
140
|
+
|
|
141
|
+
const pipeline = []
|
|
142
|
+
const group_field = group_by.split(',')[0]
|
|
143
|
+
|
|
144
|
+
pipeline.push({
|
|
145
|
+
$match: { ...seek_conditions }
|
|
146
|
+
})
|
|
147
|
+
|
|
148
|
+
if (skip) {
|
|
149
|
+
pipeline.push({
|
|
150
|
+
$skip: { skip }
|
|
151
|
+
})
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (limit) {
|
|
155
|
+
pipeline.push({
|
|
156
|
+
$limit: { limit }
|
|
157
|
+
})
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (sort_condition){
|
|
161
|
+
const sort_options = sort_condition.split(' ').reduce((sac, condition) => {
|
|
162
|
+
let key = condition
|
|
163
|
+
let value = 1
|
|
164
|
+
if (key.includes('-')) {
|
|
165
|
+
key = key.split('-')[1]
|
|
166
|
+
value = -1
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return { ...sac, [key]: value }
|
|
170
|
+
}, {})
|
|
171
|
+
|
|
172
|
+
pipeline.push({
|
|
173
|
+
$sort: { ...sort_options }
|
|
174
|
+
})
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if (fields_to_return){
|
|
178
|
+
const projection_options = fields_to_return.split(' ').reduce((sac, condition) => ({ ...sac, [condition]: 1 }), {})
|
|
179
|
+
|
|
180
|
+
pipeline.push({
|
|
181
|
+
$project: { ...projection_options }
|
|
182
|
+
})
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
pipeline.push({
|
|
186
|
+
$group: {
|
|
187
|
+
_id: { group_field: `$${group_field}`}
|
|
188
|
+
}
|
|
189
|
+
})
|
|
190
|
+
|
|
191
|
+
if (count) {
|
|
192
|
+
pipeline.push({
|
|
193
|
+
$count: "size"
|
|
194
|
+
})
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
return pipeline
|
|
198
|
+
}
|
|
199
|
+
|
|
118
200
|
module.exports = {
|
|
119
201
|
buildInQuery,
|
|
120
202
|
buildNorQuery,
|
|
@@ -124,5 +206,6 @@ module.exports = {
|
|
|
124
206
|
buildReturnFieldsString,
|
|
125
207
|
buildSortOrderString,
|
|
126
208
|
buildWildcardOptions,
|
|
127
|
-
determinePagination
|
|
209
|
+
determinePagination,
|
|
210
|
+
generateGroupPipeline
|
|
128
211
|
}
|
package/package.json
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@go-mailer/jarvis",
|
|
3
|
-
"version": "3.2.
|
|
3
|
+
"version": "3.2.2",
|
|
4
4
|
"main": "index.js",
|
|
5
5
|
"repository": "git@github.com:go-mailer-ltd/jarvis-node.git",
|
|
6
6
|
"author": "Nathan Oguntuberu <nateoguns.work@gmail.com>",
|
|
7
7
|
"license": "MIT",
|
|
8
|
+
"scripts": {
|
|
9
|
+
"test": "mocha --recursive -w -c || true"
|
|
10
|
+
},
|
|
8
11
|
"dependencies": {
|
|
9
12
|
"@logtail/node": "^0.3.3",
|
|
10
13
|
"axios": "^1.3.4",
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/** */
|
|
2
|
+
const { expect } = require('chai')
|
|
3
|
+
const { generateGroupPipeline } = require('../lib/query')
|
|
4
|
+
|
|
5
|
+
describe('Query Processor', () => {
|
|
6
|
+
|
|
7
|
+
describe('Requests: Group By', () => {
|
|
8
|
+
it('should return `null` when the group_by keyword is not used.', () => {
|
|
9
|
+
const pipeline = generateGroupPipeline({ name: 'test name' })
|
|
10
|
+
expect(pipeline).to.be.null
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
it('create the correct pipeline with only `group_by` specified', () => {
|
|
14
|
+
const group_by = 'age'
|
|
15
|
+
const pipeline = generateGroupPipeline({ group_by })
|
|
16
|
+
expect(pipeline).to.deep.include({ $group: { _id: { group_field: `$${group_by}` } } })
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
it('create the correct pipeline with `seek_conditions` specified', () => {
|
|
20
|
+
const group_by = 'age'
|
|
21
|
+
const seek_conditions = { status: 'active' }
|
|
22
|
+
const pipeline = generateGroupPipeline({ group_by, seek_conditions })
|
|
23
|
+
expect(pipeline).to.deep.include({ $match: seek_conditions })
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
it('create the correct pipeline with `sort_conditions` specified', () => {
|
|
27
|
+
const group_by = 'age'
|
|
28
|
+
const sort_condition = '-created_on age'
|
|
29
|
+
const pipeline = generateGroupPipeline({ group_by, sort_condition })
|
|
30
|
+
expect(pipeline).to.deep.include({ $sort: { created_on: -1, age: 1 } })
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
it('create the correct pipeline with only `fields_to_return` specified', () => {
|
|
34
|
+
const group_by = 'age'
|
|
35
|
+
const fields_to_return = 'age name'
|
|
36
|
+
const pipeline = generateGroupPipeline({ group_by, fields_to_return })
|
|
37
|
+
expect(pipeline).to.deep.include({ $project: { age: 1, name: 1 } })
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
it('create the correct pipeline with only `count` specified', () => {
|
|
41
|
+
const group_by = 'age'
|
|
42
|
+
const pipeline = generateGroupPipeline({ group_by, count: true })
|
|
43
|
+
expect(pipeline).to.deep.include({ $count: 'size' })
|
|
44
|
+
})
|
|
45
|
+
})
|
|
46
|
+
})
|