@invariant--labs/foundation 1.1.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.
Files changed (214) hide show
  1. package/.pnp.cjs +22192 -0
  2. package/.pnp.loader.mjs +2126 -0
  3. package/.yarnrc.yml +1 -0
  4. package/CHANGELOG.md +527 -0
  5. package/README.md +3 -0
  6. package/eslint.config.mjs +52 -0
  7. package/invariant.json +22 -0
  8. package/jest/jest.config.base.ts +30 -0
  9. package/jest/jest.spec.base.ts +7 -0
  10. package/jest.config.js +49 -0
  11. package/package.json +99 -0
  12. package/src/core/application/index.ts +1 -0
  13. package/src/core/application/persistence/index.ts +3 -0
  14. package/src/core/application/persistence/query-builder.ts +2 -0
  15. package/src/core/application/persistence/read-projection.ts +2 -0
  16. package/src/core/application/persistence/repository.ts +23 -0
  17. package/src/core/domain/entities/aggregate-root.ts +34 -0
  18. package/src/core/domain/entities/entity.spec.ts +43 -0
  19. package/src/core/domain/entities/entity.ts +29 -0
  20. package/src/core/domain/entities/identifier.spec.ts +34 -0
  21. package/src/core/domain/entities/identifier.ts +16 -0
  22. package/src/core/domain/entities/index.ts +5 -0
  23. package/src/core/domain/entities/projection.ts +7 -0
  24. package/src/core/domain/entities/unique-entity-id.ts +9 -0
  25. package/src/core/domain/events/domain-event.ts +7 -0
  26. package/src/core/domain/events/index.ts +1 -0
  27. package/src/core/domain/index.ts +3 -0
  28. package/src/core/domain/value-objects/index.ts +2 -0
  29. package/src/core/domain/value-objects/range.ts +4 -0
  30. package/src/core/domain/value-objects/value-object.spec.ts +45 -0
  31. package/src/core/domain/value-objects/value-object.ts +17 -0
  32. package/src/core/errors/command-failure.error.spec.ts +30 -0
  33. package/src/core/errors/command-failure.error.ts +9 -0
  34. package/src/core/errors/command-filter.error.ts +3 -0
  35. package/src/core/errors/detailed.error.ts +25 -0
  36. package/src/core/errors/domain.error.spec.ts +27 -0
  37. package/src/core/errors/domain.error.ts +9 -0
  38. package/src/core/errors/entity-not-found.error.spec.ts +32 -0
  39. package/src/core/errors/entity-not-found.error.ts +9 -0
  40. package/src/core/errors/fake-implementation.error.spec.ts +27 -0
  41. package/src/core/errors/fake-implementation.error.ts +15 -0
  42. package/src/core/errors/index.ts +8 -0
  43. package/src/core/errors/query-failure.error.ts +8 -0
  44. package/src/core/errors/too-many-results.error.ts +3 -0
  45. package/src/core/index.ts +4 -0
  46. package/src/core/infrastructure/config/config.provider.ts +78 -0
  47. package/src/core/infrastructure/config/config.service.ts +25 -0
  48. package/src/core/infrastructure/config/index.ts +2 -0
  49. package/src/core/infrastructure/messaging/fake/fake-messaging.service.ts +17 -0
  50. package/src/core/infrastructure/messaging/fake/fake-queue-manager.service.ts +9 -0
  51. package/src/core/infrastructure/messaging/fake/fake-queue-messaging.service.ts +9 -0
  52. package/src/core/infrastructure/messaging/fake/index.ts +3 -0
  53. package/src/core/infrastructure/messaging/index.ts +6 -0
  54. package/src/core/infrastructure/messaging/messaging.service.ts +3 -0
  55. package/src/core/infrastructure/messaging/queue-manager.service.ts +6 -0
  56. package/src/core/infrastructure/messaging/queue-messaging.service.ts +3 -0
  57. package/src/core/infrastructure/messaging/rabbitmq/index.ts +2 -0
  58. package/src/core/infrastructure/messaging/rabbitmq/rabbit-messaging.service.ts +11 -0
  59. package/src/core/infrastructure/messaging/rabbitmq/rabbit-queue-messaging.service.ts +11 -0
  60. package/src/core/infrastructure/messaging/types.ts +28 -0
  61. package/src/core/infrastructure/persistence/errors/index.ts +2 -0
  62. package/src/core/infrastructure/persistence/errors/model-to-entity-conversion.error.ts +9 -0
  63. package/src/core/infrastructure/persistence/errors/persistence.error.ts +8 -0
  64. package/src/core/infrastructure/persistence/in-memory/fake.repository.ts +79 -0
  65. package/src/core/infrastructure/persistence/in-memory/in-memory.query-builder.ts +4 -0
  66. package/src/core/infrastructure/persistence/in-memory/in-memory.repository.spec.ts +50 -0
  67. package/src/core/infrastructure/persistence/in-memory/in-memory.repository.ts +81 -0
  68. package/src/core/infrastructure/persistence/in-memory/index.ts +3 -0
  69. package/src/core/infrastructure/persistence/index.ts +4 -0
  70. package/src/core/infrastructure/persistence/read-side/in-memory.query-builder.ts +4 -0
  71. package/src/core/infrastructure/persistence/read-side/index.ts +1 -0
  72. package/src/core/infrastructure/persistence/read-side/knex/index.ts +2 -0
  73. package/src/core/infrastructure/persistence/read-side/knex/knex-types.definition.ts +13 -0
  74. package/src/core/infrastructure/persistence/read-side/knex/knex.query-builder.ts +70 -0
  75. package/src/core/infrastructure/persistence/read-side/knex-query-builder.ts +70 -0
  76. package/src/core/infrastructure/persistence/read-side/knex-types.definition.ts +13 -0
  77. package/src/core/infrastructure/persistence/write-side/aggregate-typeorm-repository.ts +87 -0
  78. package/src/core/infrastructure/persistence/write-side/entity-typeorm-repository.ts +64 -0
  79. package/src/core/infrastructure/persistence/write-side/in-memory.repository.ts +82 -0
  80. package/src/core/infrastructure/persistence/write-side/index.ts +1 -0
  81. package/src/core/infrastructure/persistence/write-side/model-attributes.ts +4 -0
  82. package/src/core/infrastructure/persistence/write-side/orm-embedded-mapper.ts +11 -0
  83. package/src/core/infrastructure/persistence/write-side/orm-mapper.ts +11 -0
  84. package/src/core/infrastructure/persistence/write-side/typeorm/aggregate-typeorm.repository.ts +87 -0
  85. package/src/core/infrastructure/persistence/write-side/typeorm/entity-typeorm.repository.ts +64 -0
  86. package/src/core/infrastructure/persistence/write-side/typeorm/index.ts +5 -0
  87. package/src/core/infrastructure/persistence/write-side/typeorm/model-attributes.ts +4 -0
  88. package/src/core/infrastructure/persistence/write-side/typeorm/orm-embedded.mapper.ts +11 -0
  89. package/src/core/infrastructure/persistence/write-side/typeorm/orm.mapper.ts +11 -0
  90. package/src/core/types/architecture-layer.ts +52 -0
  91. package/src/core/types/array-element.ts +5 -0
  92. package/src/core/types/index.ts +2 -0
  93. package/src/index.ts +30 -0
  94. package/src/modules/config/config.module.ts +9 -0
  95. package/src/modules/config/index.ts +2 -0
  96. package/src/modules/graphql/index.ts +1 -0
  97. package/src/modules/graphql/paginated-response.object-type.ts +23 -0
  98. package/src/modules/healthcheck/healthcheck-out.dto.ts +43 -0
  99. package/src/modules/healthcheck/index.ts +1 -0
  100. package/src/modules/knex/index.ts +3 -0
  101. package/src/modules/knex/knex-core.module.ts +30 -0
  102. package/src/modules/knex/knex.decorator.ts +5 -0
  103. package/src/modules/knex/knex.interface.ts +12 -0
  104. package/src/modules/knex/knex.module.ts +14 -0
  105. package/src/modules/knex/knex.token.ts +2 -0
  106. package/src/modules/logger/app-logger.ts +28 -0
  107. package/src/modules/logger/index.ts +5 -0
  108. package/src/modules/logger/log.ts +26 -0
  109. package/src/modules/logger/logger.module.ts +47 -0
  110. package/src/modules/logger/logger.service.ts +131 -0
  111. package/src/modules/logger/transports/console-color.transport.ts +41 -0
  112. package/src/modules/logger/transports/console-json.transport.ts +23 -0
  113. package/src/modules/logger/transports/console.transport.ts +10 -0
  114. package/src/modules/logger/transports/fake.transport.ts +18 -0
  115. package/src/modules/logger/transports/index.ts +5 -0
  116. package/src/modules/logger/transports/logger-transport.ts +22 -0
  117. package/src/modules/messaging/index.ts +2 -0
  118. package/src/modules/messaging/messaging.module.ts +92 -0
  119. package/src/modules/queue/default-queue-name.resolver.ts +5 -0
  120. package/src/modules/queue/index.ts +3 -0
  121. package/src/modules/queue/queue.module.ts +73 -0
  122. package/src/modules/queue/rabbit-queue-manager.service.ts +67 -0
  123. package/src/nestjs/errors/handlers/error-handler.ts +38 -0
  124. package/src/nestjs/errors/handlers/error-handler.type.ts +23 -0
  125. package/src/nestjs/errors/handlers/generic-error-handler.ts +59 -0
  126. package/src/nestjs/errors/handlers/handle-errors.decorator.ts +43 -0
  127. package/src/nestjs/errors/handlers/index.ts +5 -0
  128. package/src/nestjs/errors/handlers/validation-error-handler.ts +46 -0
  129. package/src/nestjs/errors/index.ts +2 -0
  130. package/src/nestjs/errors/parsers/axios-metadata.parser.ts +21 -0
  131. package/src/nestjs/errors/parsers/error-metadata.definition.ts +1 -0
  132. package/src/nestjs/errors/parsers/index.ts +5 -0
  133. package/src/nestjs/errors/parsers/knex-metadata.parser.ts +18 -0
  134. package/src/nestjs/errors/parsers/typeorm-metadata.parser.ts +19 -0
  135. package/src/nestjs/errors/parsers/workos-metadata.parser.ts +17 -0
  136. package/src/nestjs/http/decorators/index.ts +1 -0
  137. package/src/nestjs/http/decorators/log-app-ctx.decorator.ts +32 -0
  138. package/src/nestjs/http/dtos/date-range.dto.ts +15 -0
  139. package/src/nestjs/http/dtos/index.ts +1 -0
  140. package/src/nestjs/http/filters/all-exceptions.filter.ts +92 -0
  141. package/src/nestjs/http/filters/command-failure.filter.ts +12 -0
  142. package/src/nestjs/http/filters/index.ts +4 -0
  143. package/src/nestjs/http/filters/rpc-exceptions.filter.ts +10 -0
  144. package/src/nestjs/http/filters/too-many-results.filter.ts +12 -0
  145. package/src/nestjs/http/index.ts +6 -0
  146. package/src/nestjs/http/interceptors/index.ts +2 -0
  147. package/src/nestjs/http/interceptors/log-app-ctx.interceptor.ts +109 -0
  148. package/src/nestjs/http/interceptors/serialize-output.interceptor.ts +19 -0
  149. package/src/nestjs/http/middleware/http-logger.middleware.ts +31 -0
  150. package/src/nestjs/http/middleware/index.ts +2 -0
  151. package/src/nestjs/http/middleware/logger.middleware.ts +21 -0
  152. package/src/nestjs/http/swagger/index.ts +1 -0
  153. package/src/nestjs/http/swagger/swagger.ts +44 -0
  154. package/src/nestjs/index.ts +2 -0
  155. package/src/testing/command-bus.stub.ts +33 -0
  156. package/src/testing/event-bus.stub.ts +56 -0
  157. package/src/testing/event-publisher.stub.ts +24 -0
  158. package/src/testing/fake-logger.ts +20 -0
  159. package/src/testing/index.ts +2 -0
  160. package/src/testing/query-bus.stub.ts +27 -0
  161. package/src/testing/stub.spec.ts +250 -0
  162. package/src/testing/stub.ts +170 -0
  163. package/src/testing/stubs/command-bus.stub.ts +33 -0
  164. package/src/testing/stubs/event-bus.stub.ts +56 -0
  165. package/src/testing/stubs/event-publisher.stub.ts +24 -0
  166. package/src/testing/stubs/index.ts +5 -0
  167. package/src/testing/stubs/query-bus.stub.ts +27 -0
  168. package/src/testing/stubs/stub.ts +170 -0
  169. package/src/utils/array.spec.ts +29 -0
  170. package/src/utils/array.ts +10 -0
  171. package/src/utils/base64.spec.ts +18 -0
  172. package/src/utils/base64.ts +6 -0
  173. package/src/utils/collection.ts +4 -0
  174. package/src/utils/common.ts +13 -0
  175. package/src/utils/csv.ts +49 -0
  176. package/src/utils/date/date-range.ts +4 -0
  177. package/src/utils/date/date.spec.ts +100 -0
  178. package/src/utils/date/date.ts +177 -0
  179. package/src/utils/date/diff.spec.ts +66 -0
  180. package/src/utils/date/diffYear.spec.ts +23 -0
  181. package/src/utils/date/fillMissingRangeValues.spec.ts +523 -0
  182. package/src/utils/date/groubBy.spec.ts +183 -0
  183. package/src/utils/date/index.ts +2 -0
  184. package/src/utils/date/isSame.spec.ts +111 -0
  185. package/src/utils/file.spec.ts +66 -0
  186. package/src/utils/file.ts +5 -0
  187. package/src/utils/hash-key.ts +23 -0
  188. package/src/utils/index.ts +14 -0
  189. package/src/utils/invariant.ts +3 -0
  190. package/src/utils/iso-date.ts +11 -0
  191. package/src/utils/object.spec.ts +18 -0
  192. package/src/utils/object.ts +6 -0
  193. package/src/utils/paginated.ts +36 -0
  194. package/src/utils/string.spec.ts +10 -0
  195. package/src/utils/string.ts +19 -0
  196. package/src/utils/type.ts +9 -0
  197. package/src/utils/xml.ts +6 -0
  198. package/src/validation/ensure-array.decorator.ts +5 -0
  199. package/src/validation/index.ts +7 -0
  200. package/src/validation/is-iso-date.decorator.spec.ts +29 -0
  201. package/src/validation/is-iso-date.decorator.ts +30 -0
  202. package/src/validation/is-less-than-or-equal.decorator.spec.ts +30 -0
  203. package/src/validation/is-less-than-or-equal.decorator.ts +52 -0
  204. package/src/validation/is-less-than.decorator.spec.ts +36 -0
  205. package/src/validation/is-less-than.decorator.ts +52 -0
  206. package/src/validation/is-more-than-or-equal.decorator.spec.ts +30 -0
  207. package/src/validation/is-more-than-or-equal.decorator.ts +52 -0
  208. package/src/validation/is-more-than.decorator.spec.ts +36 -0
  209. package/src/validation/is-more-than.decorator.ts +52 -0
  210. package/src/validation/is-time-string.decorator.spec.ts +35 -0
  211. package/src/validation/is-time-string.decorator.ts +29 -0
  212. package/tsconfig.build.json +6 -0
  213. package/tsconfig.json +34 -0
  214. package/tsconfig.spec.json +14 -0
@@ -0,0 +1,523 @@
1
+ import { endOf, fillMissingRangeValues, groupBy, startOf } from "./date";
2
+
3
+ describe("fillMissingRangeValues", () => {
4
+ it("should fill missing values grouped by day", () => {
5
+ const unit = "day";
6
+ const fixture = [
7
+ {
8
+ date: new Date(2022, 0, 1, 0),
9
+ value: 0,
10
+ },
11
+ {
12
+ date: new Date(2022, 0, 1, 1),
13
+ value: 1,
14
+ },
15
+ {
16
+ date: new Date(2022, 0, 4, 0),
17
+ value: 2,
18
+ },
19
+ {
20
+ date: new Date(2022, 0, 5, 0),
21
+ value: 3,
22
+ },
23
+ ];
24
+
25
+ const grouped = groupBy(fixture, "date", unit);
26
+ const result = fillMissingRangeValues(grouped, unit);
27
+ const expectedResult = [
28
+ {
29
+ beginOfUnit: startOf(fixture[0].date, unit),
30
+ endOfUnit: endOf(fixture[0].date, unit),
31
+ values: [fixture[0], fixture[1]],
32
+ unit,
33
+ },
34
+ {
35
+ beginOfUnit: startOf(new Date(2022, 0, 2, 0), unit),
36
+ endOfUnit: endOf(new Date(2022, 0, 2, 0), unit),
37
+ values: [],
38
+ unit,
39
+ },
40
+ {
41
+ beginOfUnit: startOf(new Date(2022, 0, 3, 0), unit),
42
+ endOfUnit: endOf(new Date(2022, 0, 3, 0), unit),
43
+ values: [],
44
+ unit,
45
+ },
46
+ {
47
+ beginOfUnit: startOf(fixture[2].date, unit),
48
+ endOfUnit: endOf(fixture[2].date, unit),
49
+ values: [fixture[2]],
50
+ unit,
51
+ },
52
+ {
53
+ beginOfUnit: startOf(fixture[3].date, unit),
54
+ endOfUnit: endOf(fixture[3].date, unit),
55
+ values: [fixture[3]],
56
+ unit,
57
+ },
58
+ ];
59
+
60
+ expect(result).toEqual(expect.arrayContaining(expectedResult));
61
+ expect(expectedResult).toEqual(expect.arrayContaining(result));
62
+ });
63
+
64
+ it("should fill missing values grouped by day within a given dateRange", () => {
65
+ const unit = "day";
66
+ const dateRange = {
67
+ from: new Date(2021, 11, 29, 0),
68
+ to: new Date(2022, 0, 6, 0, 0),
69
+ };
70
+ const fixture = [
71
+ {
72
+ date: new Date(2022, 0, 1, 0),
73
+ value: 0,
74
+ },
75
+ {
76
+ date: new Date(2022, 0, 1, 1),
77
+ value: 1,
78
+ },
79
+ {
80
+ date: new Date(2022, 0, 4, 0),
81
+ value: 2,
82
+ },
83
+ {
84
+ date: new Date(2022, 0, 5, 0),
85
+ value: 3,
86
+ },
87
+ ];
88
+
89
+ const grouped = groupBy(fixture, "date", unit);
90
+ const result = fillMissingRangeValues(grouped, unit, dateRange);
91
+ const expectedResult = [
92
+ {
93
+ beginOfUnit: startOf(new Date(2021, 11, 29, 0), unit),
94
+ endOfUnit: endOf(new Date(2021, 11, 29, 0), unit),
95
+ values: [],
96
+ unit,
97
+ },
98
+ {
99
+ beginOfUnit: startOf(new Date(2021, 11, 30, 0), unit),
100
+ endOfUnit: endOf(new Date(2021, 11, 30, 0), unit),
101
+ values: [],
102
+ unit,
103
+ },
104
+ {
105
+ beginOfUnit: startOf(new Date(2021, 11, 31, 0), unit),
106
+ endOfUnit: endOf(new Date(2021, 11, 31, 0), unit),
107
+ values: [],
108
+ unit,
109
+ },
110
+ {
111
+ beginOfUnit: startOf(fixture[0].date, unit),
112
+ endOfUnit: endOf(fixture[0].date, unit),
113
+ values: [fixture[0], fixture[1]],
114
+ unit,
115
+ },
116
+ {
117
+ beginOfUnit: startOf(new Date(2022, 0, 2, 0), unit),
118
+ endOfUnit: endOf(new Date(2022, 0, 2, 0), unit),
119
+ values: [],
120
+ unit,
121
+ },
122
+ {
123
+ beginOfUnit: startOf(new Date(2022, 0, 3, 0), unit),
124
+ endOfUnit: endOf(new Date(2022, 0, 3, 0), unit),
125
+ values: [],
126
+ unit,
127
+ },
128
+ {
129
+ beginOfUnit: startOf(fixture[2].date, unit),
130
+ endOfUnit: endOf(fixture[2].date, unit),
131
+ values: [fixture[2]],
132
+ unit,
133
+ },
134
+ {
135
+ beginOfUnit: startOf(fixture[3].date, unit),
136
+ endOfUnit: endOf(fixture[3].date, unit),
137
+ values: [fixture[3]],
138
+ unit,
139
+ },
140
+ {
141
+ beginOfUnit: startOf(new Date(2022, 0, 6, 0), unit),
142
+ endOfUnit: endOf(new Date(2022, 0, 6, 0), unit),
143
+ values: [],
144
+ unit,
145
+ },
146
+ ];
147
+
148
+ expect(result).toEqual(expect.arrayContaining(expectedResult));
149
+ expect(expectedResult).toEqual(expect.arrayContaining(result));
150
+ });
151
+
152
+ it("should fill missing values grouped by month", () => {
153
+ const unit = "month";
154
+ const fixture = [
155
+ {
156
+ date: new Date(2022, 0, 1),
157
+ value: 0,
158
+ },
159
+ {
160
+ date: new Date(2022, 0, 2),
161
+ value: 1,
162
+ },
163
+ {
164
+ date: new Date(2022, 2, 1),
165
+ value: 2,
166
+ },
167
+ {
168
+ date: new Date(2022, 3, 1),
169
+ value: 3,
170
+ },
171
+ ];
172
+
173
+ const grouped = groupBy(fixture, "date", unit);
174
+ const result = fillMissingRangeValues(grouped, unit);
175
+ const expectedResult = [
176
+ {
177
+ beginOfUnit: startOf(fixture[0].date, unit),
178
+ endOfUnit: endOf(fixture[0].date, unit),
179
+ values: [fixture[0], fixture[1]],
180
+ unit,
181
+ },
182
+ {
183
+ beginOfUnit: startOf(new Date(2022, 1, 1), unit),
184
+ endOfUnit: endOf(new Date(2022, 1, 1), unit),
185
+ values: [],
186
+ unit,
187
+ },
188
+ {
189
+ beginOfUnit: startOf(fixture[2].date, unit),
190
+ endOfUnit: endOf(fixture[2].date, unit),
191
+ values: [fixture[2]],
192
+ unit,
193
+ },
194
+ {
195
+ beginOfUnit: startOf(fixture[3].date, unit),
196
+ endOfUnit: endOf(fixture[3].date, unit),
197
+ values: [fixture[3]],
198
+ unit,
199
+ },
200
+ ];
201
+
202
+ expect(result).toEqual(expect.arrayContaining(expectedResult));
203
+ expect(expectedResult).toEqual(expect.arrayContaining(result));
204
+ });
205
+
206
+ it("should fill missing values grouped by month within a given dateRange", () => {
207
+ const unit = "month";
208
+ const dateRange = {
209
+ from: new Date(2021, 11, 1),
210
+ to: new Date(2022, 4, 1),
211
+ };
212
+ const fixture = [
213
+ {
214
+ date: new Date(2022, 0, 1),
215
+ value: 0,
216
+ },
217
+ {
218
+ date: new Date(2022, 0, 1),
219
+ value: 1,
220
+ },
221
+ {
222
+ date: new Date(2022, 2, 1),
223
+ value: 2,
224
+ },
225
+ {
226
+ date: new Date(2022, 3, 1),
227
+ value: 3,
228
+ },
229
+ ];
230
+
231
+ const grouped = groupBy(fixture, "date", unit);
232
+ const result = fillMissingRangeValues(grouped, unit, dateRange);
233
+ const expectedResult = [
234
+ {
235
+ beginOfUnit: startOf(new Date(2021, 11, 1), unit),
236
+ endOfUnit: endOf(new Date(2021, 11, 1), unit),
237
+ values: [],
238
+ unit,
239
+ },
240
+ {
241
+ beginOfUnit: startOf(fixture[0].date, unit),
242
+ endOfUnit: endOf(fixture[0].date, unit),
243
+ values: [fixture[0], fixture[1]],
244
+ unit,
245
+ },
246
+ {
247
+ beginOfUnit: startOf(new Date(2022, 1, 1), unit),
248
+ endOfUnit: endOf(new Date(2022, 1, 1), unit),
249
+ values: [],
250
+ unit,
251
+ },
252
+ {
253
+ beginOfUnit: startOf(fixture[2].date, unit),
254
+ endOfUnit: endOf(fixture[2].date, unit),
255
+ values: [fixture[2]],
256
+ unit,
257
+ },
258
+ {
259
+ beginOfUnit: startOf(fixture[3].date, unit),
260
+ endOfUnit: endOf(fixture[3].date, unit),
261
+ values: [fixture[3]],
262
+ unit,
263
+ },
264
+ {
265
+ beginOfUnit: startOf(new Date(2022, 4, 1), unit),
266
+ endOfUnit: endOf(new Date(2022, 4, 1), unit),
267
+ values: [],
268
+ unit,
269
+ },
270
+ ];
271
+
272
+ expect(result).toEqual(expect.arrayContaining(expectedResult));
273
+ expect(expectedResult).toEqual(expect.arrayContaining(result));
274
+ });
275
+
276
+ it("should fill missing values grouped by year", () => {
277
+ const unit = "year";
278
+ const fixture = [
279
+ {
280
+ date: new Date(2022, 0, 1),
281
+ value: 0,
282
+ },
283
+ {
284
+ date: new Date(2022, 0, 2),
285
+ value: 1,
286
+ },
287
+ {
288
+ date: new Date(2024, 0, 1),
289
+ value: 2,
290
+ },
291
+ {
292
+ date: new Date(2025, 0, 1),
293
+ value: 3,
294
+ },
295
+ ];
296
+
297
+ const grouped = groupBy(fixture, "date", unit);
298
+ const result = fillMissingRangeValues(grouped, unit);
299
+ const expectedResult = [
300
+ {
301
+ beginOfUnit: startOf(fixture[0].date, unit),
302
+ endOfUnit: endOf(fixture[0].date, unit),
303
+ values: [fixture[0], fixture[1]],
304
+ unit,
305
+ },
306
+ {
307
+ beginOfUnit: startOf(new Date(2023, 0, 1), unit),
308
+ endOfUnit: endOf(new Date(2023, 0, 1), unit),
309
+ values: [],
310
+ unit,
311
+ },
312
+ {
313
+ beginOfUnit: startOf(fixture[2].date, unit),
314
+ endOfUnit: endOf(fixture[2].date, unit),
315
+ values: [fixture[2]],
316
+ unit,
317
+ },
318
+ {
319
+ beginOfUnit: startOf(fixture[3].date, unit),
320
+ endOfUnit: endOf(fixture[3].date, unit),
321
+ values: [fixture[3]],
322
+ unit,
323
+ },
324
+ ];
325
+
326
+ expect(result).toEqual(expect.arrayContaining(expectedResult));
327
+ expect(expectedResult).toEqual(expect.arrayContaining(result));
328
+ });
329
+
330
+ it("should fill missing values grouped by year within a given dateRange", () => {
331
+ const unit = "year";
332
+ const dateRange = {
333
+ from: new Date(2021, 0, 1),
334
+ to: new Date(2026, 0, 1),
335
+ };
336
+ const fixture = [
337
+ {
338
+ date: new Date(2022, 0, 1),
339
+ value: 0,
340
+ },
341
+ {
342
+ date: new Date(2022, 0, 2),
343
+ value: 1,
344
+ },
345
+ {
346
+ date: new Date(2024, 0, 1),
347
+ value: 2,
348
+ },
349
+ {
350
+ date: new Date(2025, 0, 1),
351
+ value: 3,
352
+ },
353
+ ];
354
+
355
+ const grouped = groupBy(fixture, "date", unit);
356
+ const result = fillMissingRangeValues(grouped, unit, dateRange);
357
+ const expectedResult = [
358
+ {
359
+ beginOfUnit: startOf(new Date(2021, 0, 1), unit),
360
+ endOfUnit: endOf(new Date(2021, 0, 1), unit),
361
+ values: [],
362
+ unit,
363
+ },
364
+ {
365
+ beginOfUnit: startOf(fixture[0].date, unit),
366
+ endOfUnit: endOf(fixture[0].date, unit),
367
+ values: [fixture[0], fixture[1]],
368
+ unit,
369
+ },
370
+ {
371
+ beginOfUnit: startOf(new Date(2023, 0, 1), unit),
372
+ endOfUnit: endOf(new Date(2023, 0, 1), unit),
373
+ values: [],
374
+ unit,
375
+ },
376
+ {
377
+ beginOfUnit: startOf(fixture[2].date, unit),
378
+ endOfUnit: endOf(fixture[2].date, unit),
379
+ values: [fixture[2]],
380
+ unit,
381
+ },
382
+ {
383
+ beginOfUnit: startOf(fixture[3].date, unit),
384
+ endOfUnit: endOf(fixture[3].date, unit),
385
+ values: [fixture[3]],
386
+ unit,
387
+ },
388
+ {
389
+ beginOfUnit: startOf(new Date(2026, 0, 1), unit),
390
+ endOfUnit: endOf(new Date(2026, 0, 1), unit),
391
+ values: [],
392
+ unit,
393
+ },
394
+ ];
395
+
396
+ expect(result).toEqual(expect.arrayContaining(expectedResult));
397
+ expect(expectedResult).toEqual(expect.arrayContaining(result));
398
+ });
399
+
400
+ it("should fill missing values grouped by quarter", () => {
401
+ const unit = "quarter";
402
+ const fixture = [
403
+ {
404
+ date: new Date(2022, 0, 1),
405
+ value: 0,
406
+ },
407
+ {
408
+ date: new Date(2022, 1, 1),
409
+ value: 1,
410
+ },
411
+ {
412
+ date: new Date(2022, 7, 1),
413
+ value: 2,
414
+ },
415
+ {
416
+ date: new Date(2022, 10, 1),
417
+ value: 3,
418
+ },
419
+ ];
420
+
421
+ const grouped = groupBy(fixture, "date", unit);
422
+ const result = fillMissingRangeValues(grouped, unit);
423
+ const expectedResult = [
424
+ {
425
+ beginOfUnit: startOf(fixture[0].date, unit),
426
+ endOfUnit: endOf(fixture[0].date, unit),
427
+ values: [fixture[0], fixture[1]],
428
+ unit,
429
+ },
430
+ {
431
+ beginOfUnit: startOf(new Date(2022, 3, 1), unit),
432
+ endOfUnit: endOf(new Date(2022, 3, 1), unit),
433
+ values: [],
434
+ unit,
435
+ },
436
+ {
437
+ beginOfUnit: startOf(fixture[2].date, unit),
438
+ endOfUnit: endOf(fixture[2].date, unit),
439
+ values: [fixture[2]],
440
+ unit,
441
+ },
442
+ {
443
+ beginOfUnit: startOf(fixture[3].date, unit),
444
+ endOfUnit: endOf(fixture[3].date, unit),
445
+ values: [fixture[3]],
446
+ unit,
447
+ },
448
+ ];
449
+
450
+ expect(result).toEqual(expect.arrayContaining(expectedResult));
451
+ expect(expectedResult).toEqual(expect.arrayContaining(result));
452
+ });
453
+
454
+ it("should fill missing values grouped by year within a given dateRange", () => {
455
+ const unit = "quarter";
456
+ const dateRange = {
457
+ from: new Date(2021, 10, 1),
458
+ to: new Date(2023, 2, 1),
459
+ };
460
+ const fixture = [
461
+ {
462
+ date: new Date(2022, 0, 1),
463
+ value: 0,
464
+ },
465
+ {
466
+ date: new Date(2022, 1, 1),
467
+ value: 1,
468
+ },
469
+ {
470
+ date: new Date(2022, 7, 1),
471
+ value: 2,
472
+ },
473
+ {
474
+ date: new Date(2022, 10, 1),
475
+ value: 3,
476
+ },
477
+ ];
478
+
479
+ const grouped = groupBy(fixture, "date", unit);
480
+ const result = fillMissingRangeValues(grouped, unit, dateRange);
481
+ const expectedResult = [
482
+ {
483
+ beginOfUnit: startOf(new Date(2021, 9, 1), unit),
484
+ endOfUnit: endOf(new Date(2021, 9, 1), unit),
485
+ values: [],
486
+ unit,
487
+ },
488
+ {
489
+ beginOfUnit: startOf(fixture[0].date, unit),
490
+ endOfUnit: endOf(fixture[0].date, unit),
491
+ values: [fixture[0], fixture[1]],
492
+ unit,
493
+ },
494
+ {
495
+ beginOfUnit: startOf(new Date(2022, 3, 1), unit),
496
+ endOfUnit: endOf(new Date(2022, 3, 1), unit),
497
+ values: [],
498
+ unit,
499
+ },
500
+ {
501
+ beginOfUnit: startOf(fixture[2].date, unit),
502
+ endOfUnit: endOf(fixture[2].date, unit),
503
+ values: [fixture[2]],
504
+ unit,
505
+ },
506
+ {
507
+ beginOfUnit: startOf(fixture[3].date, unit),
508
+ endOfUnit: endOf(fixture[3].date, unit),
509
+ values: [fixture[3]],
510
+ unit,
511
+ },
512
+ {
513
+ beginOfUnit: startOf(new Date(2023, 0, 1), unit),
514
+ endOfUnit: endOf(new Date(2023, 0, 1), unit),
515
+ values: [],
516
+ unit,
517
+ },
518
+ ];
519
+
520
+ expect(result).toEqual(expect.arrayContaining(expectedResult));
521
+ expect(expectedResult).toEqual(expect.arrayContaining(result));
522
+ });
523
+ });
@@ -0,0 +1,183 @@
1
+ import { endOf, groupBy, startOf } from "./date";
2
+
3
+ describe("groupBy", () => {
4
+ it("should grouped by day", () => {
5
+ const unit = "day";
6
+ const fixture = [
7
+ {
8
+ date: new Date(2022, 0, 1, 0),
9
+ value: 0,
10
+ },
11
+ {
12
+ date: new Date(2022, 0, 1, 1),
13
+ value: 1,
14
+ },
15
+ {
16
+ date: new Date(2022, 0, 2, 0),
17
+ value: 2,
18
+ },
19
+ {
20
+ date: new Date(2022, 0, 3, 0),
21
+ value: 3,
22
+ },
23
+ ];
24
+
25
+ const result = groupBy(fixture, "date", unit);
26
+
27
+ expect(result).toEqual([
28
+ {
29
+ beginOfUnit: startOf(fixture[0].date, unit),
30
+ endOfUnit: endOf(fixture[0].date, unit),
31
+ values: [fixture[0], fixture[1]],
32
+ unit,
33
+ },
34
+ {
35
+ beginOfUnit: startOf(fixture[2].date, unit),
36
+ endOfUnit: endOf(fixture[2].date, unit),
37
+ values: [fixture[2]],
38
+ unit,
39
+ },
40
+ {
41
+ beginOfUnit: startOf(fixture[3].date, unit),
42
+ endOfUnit: endOf(fixture[3].date, unit),
43
+ values: [fixture[3]],
44
+ unit,
45
+ },
46
+ ]);
47
+ });
48
+
49
+ it("should grouped by month", () => {
50
+ const unit = "month";
51
+ const fixture = [
52
+ {
53
+ date: new Date(2022, 0, 1),
54
+ value: 0,
55
+ },
56
+ {
57
+ date: new Date(2022, 0, 2),
58
+ value: 1,
59
+ },
60
+ {
61
+ date: new Date(2022, 1, 1),
62
+ value: 2,
63
+ },
64
+ {
65
+ date: new Date(2022, 2, 1),
66
+ value: 3,
67
+ },
68
+ ];
69
+
70
+ const result = groupBy(fixture, "date", unit);
71
+
72
+ expect(result).toEqual([
73
+ {
74
+ beginOfUnit: startOf(fixture[0].date, unit),
75
+ endOfUnit: endOf(fixture[0].date, unit),
76
+ values: [fixture[0], fixture[1]],
77
+ unit,
78
+ },
79
+ {
80
+ beginOfUnit: startOf(fixture[2].date, unit),
81
+ endOfUnit: endOf(fixture[2].date, unit),
82
+ values: [fixture[2]],
83
+ unit,
84
+ },
85
+ {
86
+ beginOfUnit: startOf(fixture[3].date, unit),
87
+ endOfUnit: endOf(fixture[3].date, unit),
88
+ values: [fixture[3]],
89
+ unit,
90
+ },
91
+ ]);
92
+ });
93
+
94
+ it("should grouped by year", () => {
95
+ const unit = "year";
96
+ const fixture = [
97
+ {
98
+ date: new Date(2021, 0, 1),
99
+ value: 0,
100
+ },
101
+ {
102
+ date: new Date(2021, 1, 1),
103
+ value: 1,
104
+ },
105
+ {
106
+ date: new Date(2022, 1, 1),
107
+ value: 2,
108
+ },
109
+ {
110
+ date: new Date(2023, 2, 1),
111
+ value: 3,
112
+ },
113
+ ];
114
+
115
+ const result = groupBy(fixture, "date", unit);
116
+
117
+ expect(result).toEqual([
118
+ {
119
+ beginOfUnit: startOf(fixture[0].date, unit),
120
+ endOfUnit: endOf(fixture[0].date, unit),
121
+ values: [fixture[0], fixture[1]],
122
+ unit,
123
+ },
124
+ {
125
+ beginOfUnit: startOf(fixture[2].date, unit),
126
+ endOfUnit: endOf(fixture[2].date, unit),
127
+ values: [fixture[2]],
128
+ unit,
129
+ },
130
+ {
131
+ beginOfUnit: startOf(fixture[3].date, unit),
132
+ endOfUnit: endOf(fixture[3].date, unit),
133
+ values: [fixture[3]],
134
+ unit,
135
+ },
136
+ ]);
137
+ });
138
+
139
+ it("should grouped by quarter", () => {
140
+ const unit = "quarter";
141
+ const fixture = [
142
+ {
143
+ date: new Date(2022, 0, 1),
144
+ value: 0,
145
+ },
146
+ {
147
+ date: new Date(2022, 1, 2),
148
+ value: 1,
149
+ },
150
+ {
151
+ date: new Date(2022, 7, 1),
152
+ value: 2,
153
+ },
154
+ {
155
+ date: new Date(2022, 10, 1),
156
+ value: 3,
157
+ },
158
+ ];
159
+
160
+ const result = groupBy(fixture, "date", unit);
161
+
162
+ expect(result).toEqual([
163
+ {
164
+ beginOfUnit: startOf(fixture[0].date, unit),
165
+ endOfUnit: endOf(fixture[0].date, unit),
166
+ values: [fixture[0], fixture[1]],
167
+ unit,
168
+ },
169
+ {
170
+ beginOfUnit: startOf(fixture[2].date, unit),
171
+ endOfUnit: endOf(fixture[2].date, unit),
172
+ values: [fixture[2]],
173
+ unit,
174
+ },
175
+ {
176
+ beginOfUnit: startOf(fixture[3].date, unit),
177
+ endOfUnit: endOf(fixture[3].date, unit),
178
+ values: [fixture[3]],
179
+ unit,
180
+ },
181
+ ]);
182
+ });
183
+ });
@@ -0,0 +1,2 @@
1
+ export * from "./date";
2
+ export * from "./date-range";