@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 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.0",
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
+ })