@liminalfunctions/framework 1.0.0

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 (181) hide show
  1. package/.mocharc.json +5 -0
  2. package/dist/F_Client_Collection_Registry.d.ts +18 -0
  3. package/dist/F_Client_Collection_Registry.js +36 -0
  4. package/dist/F_Client_Collection_Registry.js.map +1 -0
  5. package/dist/F_Collection.d.ts +21 -0
  6. package/dist/F_Collection.js +36 -0
  7. package/dist/F_Collection.js.map +1 -0
  8. package/dist/F_Collection_Registry.d.ts +11 -0
  9. package/dist/F_Collection_Registry.js +18 -0
  10. package/dist/F_Collection_Registry.js.map +1 -0
  11. package/dist/F_Compile.d.ts +4 -0
  12. package/dist/F_Compile.js +298 -0
  13. package/dist/F_Compile.js.map +1 -0
  14. package/dist/F_Security_Models/F_SM_Open_Access.d.ts +11 -0
  15. package/dist/F_Security_Models/F_SM_Open_Access.js +14 -0
  16. package/dist/F_Security_Models/F_SM_Open_Access.js.map +1 -0
  17. package/dist/F_Security_Models/F_SM_Ownership.d.ts +12 -0
  18. package/dist/F_Security_Models/F_SM_Ownership.js +46 -0
  19. package/dist/F_Security_Models/F_SM_Ownership.js.map +1 -0
  20. package/dist/F_Security_Models/F_SM_Role_Membership.d.ts +19 -0
  21. package/dist/F_Security_Models/F_SM_Role_Membership.js +73 -0
  22. package/dist/F_Security_Models/F_SM_Role_Membership.js.map +1 -0
  23. package/dist/F_Security_Models/F_Security_Model.d.ts +41 -0
  24. package/dist/F_Security_Models/F_Security_Model.js +29 -0
  25. package/dist/F_Security_Models/F_Security_Model.js.map +1 -0
  26. package/dist/code_generation/generate_client_library.d.ts +4 -0
  27. package/dist/code_generation/generate_client_library.js +158 -0
  28. package/dist/code_generation/generate_client_library.js.map +1 -0
  29. package/dist/code_generation/templates/.gitignore.mustache +383 -0
  30. package/dist/code_generation/templates/collection.mustache +106 -0
  31. package/dist/code_generation/templates/main.mustache +24 -0
  32. package/dist/code_generation/templates/package.json.mustache +18 -0
  33. package/dist/code_generation/templates/tsconfig.json.mustache +14 -0
  34. package/dist/code_generation/templates/types.mustache +4 -0
  35. package/dist/code_generation/templates/utils.ts.mustache +17 -0
  36. package/dist/code_generation/utils/tab_indent.d.ts +1 -0
  37. package/dist/code_generation/utils/tab_indent.js +4 -0
  38. package/dist/code_generation/utils/tab_indent.js.map +1 -0
  39. package/dist/code_generation/utils/type_from_zod.d.ts +2 -0
  40. package/dist/code_generation/utils/type_from_zod.js +102 -0
  41. package/dist/code_generation/utils/type_from_zod.js.map +1 -0
  42. package/dist/utils/cache.d.ts +13 -0
  43. package/dist/utils/cache.js +101 -0
  44. package/dist/utils/cache.js.map +1 -0
  45. package/dist/utils/mongoose_from_zod.d.ts +13 -0
  46. package/dist/utils/mongoose_from_zod.js +164 -0
  47. package/dist/utils/mongoose_from_zod.js.map +1 -0
  48. package/dist/utils/pretty_print_zod.d.ts +2 -0
  49. package/dist/utils/pretty_print_zod.js +63 -0
  50. package/dist/utils/pretty_print_zod.js.map +1 -0
  51. package/dist/utils/query_object_to_mongodb_query.d.ts +3 -0
  52. package/dist/utils/query_object_to_mongodb_query.js +61 -0
  53. package/dist/utils/query_object_to_mongodb_query.js.map +1 -0
  54. package/dist/utils/query_validator_from_zod.d.ts +6 -0
  55. package/dist/utils/query_validator_from_zod.js +216 -0
  56. package/dist/utils/query_validator_from_zod.js.map +1 -0
  57. package/package.json +36 -0
  58. package/src/F_Collection.ts +50 -0
  59. package/src/F_Collection_Registry.ts +29 -0
  60. package/src/F_Compile.ts +368 -0
  61. package/src/F_Security_Models/F_SM_Open_Access.ts +21 -0
  62. package/src/F_Security_Models/F_SM_Ownership.ts +72 -0
  63. package/src/F_Security_Models/F_SM_Role_Membership.ts +87 -0
  64. package/src/F_Security_Models/F_Security_Model.ts +85 -0
  65. package/src/code_generation/generate_client_library.ts +197 -0
  66. package/src/code_generation/templates/.gitignore.mustache +383 -0
  67. package/src/code_generation/templates/collection.mustache +106 -0
  68. package/src/code_generation/templates/main.mustache +24 -0
  69. package/src/code_generation/templates/package.json.mustache +18 -0
  70. package/src/code_generation/templates/tsconfig.json.mustache +14 -0
  71. package/src/code_generation/templates/types.mustache +4 -0
  72. package/src/code_generation/templates/utils.ts.mustache +17 -0
  73. package/src/code_generation/utils/tab_indent.ts +3 -0
  74. package/src/code_generation/utils/type_from_zod.ts +140 -0
  75. package/src/utils/cache.ts +149 -0
  76. package/src/utils/mongoose_from_zod.ts +191 -0
  77. package/src/utils/pretty_print_zod.ts +75 -0
  78. package/src/utils/query_object_to_mongodb_query.ts +73 -0
  79. package/src/utils/query_validator_from_zod.ts +246 -0
  80. package/test/0_0_mongoose_from_zod.test.ts +260 -0
  81. package/test/0_1_query_validator_from_zod.test.ts +518 -0
  82. package/test/0_2_query_validator_to_mongodb_query.test.ts +365 -0
  83. package/test/0_3_cache.test.ts +204 -0
  84. package/test/1_0_basic_server.test.ts +530 -0
  85. package/test/1_1_security_ownership.test.ts +328 -0
  86. package/test/1_2_role_membership.test.ts +731 -0
  87. package/test/2_0_client_library_basic_type_generation.test.ts +444 -0
  88. package/test/2_0_client_library_query_type_generation.test.ts +352 -0
  89. package/test/2_1_client_library_generation.test.ts +255 -0
  90. package/test/tmp/dist/Brief_News_Category.d.ts +16 -0
  91. package/test/tmp/dist/Brief_News_Category.js +85 -0
  92. package/test/tmp/dist/Brief_News_Category.js.map +1 -0
  93. package/test/tmp/dist/Client.d.ts +19 -0
  94. package/test/tmp/dist/Client.js +97 -0
  95. package/test/tmp/dist/Client.js.map +1 -0
  96. package/test/tmp/dist/Institution.d.ts +18 -0
  97. package/test/tmp/dist/Institution.js +94 -0
  98. package/test/tmp/dist/Institution.js.map +1 -0
  99. package/test/tmp/dist/Project.d.ts +16 -0
  100. package/test/tmp/dist/Project.js +85 -0
  101. package/test/tmp/dist/Project.js.map +1 -0
  102. package/test/tmp/dist/index.d.ts +4 -0
  103. package/test/tmp/dist/index.js +14 -0
  104. package/test/tmp/dist/index.js.map +1 -0
  105. package/test/tmp/dist/types/brief_news_category.d.ts +7 -0
  106. package/test/tmp/dist/types/brief_news_category.js +2 -0
  107. package/test/tmp/dist/types/brief_news_category.js.map +1 -0
  108. package/test/tmp/dist/types/brief_news_category_post.d.ts +7 -0
  109. package/test/tmp/dist/types/brief_news_category_post.js +2 -0
  110. package/test/tmp/dist/types/brief_news_category_post.js.map +1 -0
  111. package/test/tmp/dist/types/brief_news_category_put.d.ts +7 -0
  112. package/test/tmp/dist/types/brief_news_category_put.js +2 -0
  113. package/test/tmp/dist/types/brief_news_category_put.js.map +1 -0
  114. package/test/tmp/dist/types/brief_news_category_query.d.ts +26 -0
  115. package/test/tmp/dist/types/brief_news_category_query.js +2 -0
  116. package/test/tmp/dist/types/brief_news_category_query.js.map +1 -0
  117. package/test/tmp/dist/types/client.d.ts +5 -0
  118. package/test/tmp/dist/types/client.js +2 -0
  119. package/test/tmp/dist/types/client.js.map +1 -0
  120. package/test/tmp/dist/types/client_post.d.ts +5 -0
  121. package/test/tmp/dist/types/client_post.js +2 -0
  122. package/test/tmp/dist/types/client_post.js.map +1 -0
  123. package/test/tmp/dist/types/client_put.d.ts +5 -0
  124. package/test/tmp/dist/types/client_put.js +2 -0
  125. package/test/tmp/dist/types/client_put.js.map +1 -0
  126. package/test/tmp/dist/types/client_query.d.ts +18 -0
  127. package/test/tmp/dist/types/client_query.js +2 -0
  128. package/test/tmp/dist/types/client_query.js.map +1 -0
  129. package/test/tmp/dist/types/institution.d.ts +4 -0
  130. package/test/tmp/dist/types/institution.js +2 -0
  131. package/test/tmp/dist/types/institution.js.map +1 -0
  132. package/test/tmp/dist/types/institution_post.d.ts +4 -0
  133. package/test/tmp/dist/types/institution_post.js +2 -0
  134. package/test/tmp/dist/types/institution_post.js.map +1 -0
  135. package/test/tmp/dist/types/institution_put.d.ts +4 -0
  136. package/test/tmp/dist/types/institution_put.js +2 -0
  137. package/test/tmp/dist/types/institution_put.js.map +1 -0
  138. package/test/tmp/dist/types/institution_query.d.ts +14 -0
  139. package/test/tmp/dist/types/institution_query.js +2 -0
  140. package/test/tmp/dist/types/institution_query.js.map +1 -0
  141. package/test/tmp/dist/types/project.d.ts +7 -0
  142. package/test/tmp/dist/types/project.js +2 -0
  143. package/test/tmp/dist/types/project.js.map +1 -0
  144. package/test/tmp/dist/types/project_post.d.ts +7 -0
  145. package/test/tmp/dist/types/project_post.js +2 -0
  146. package/test/tmp/dist/types/project_post.js.map +1 -0
  147. package/test/tmp/dist/types/project_put.d.ts +7 -0
  148. package/test/tmp/dist/types/project_put.js +2 -0
  149. package/test/tmp/dist/types/project_put.js.map +1 -0
  150. package/test/tmp/dist/types/project_query.d.ts +27 -0
  151. package/test/tmp/dist/types/project_query.js +2 -0
  152. package/test/tmp/dist/types/project_query.js.map +1 -0
  153. package/test/tmp/dist/utils/utils.d.ts +11 -0
  154. package/test/tmp/dist/utils/utils.js +13 -0
  155. package/test/tmp/dist/utils/utils.js.map +1 -0
  156. package/test/tmp/package-lock.json +573 -0
  157. package/test/tmp/package.json +18 -0
  158. package/test/tmp/src/Brief_News_Category.ts +94 -0
  159. package/test/tmp/src/Client.ts +106 -0
  160. package/test/tmp/src/Institution.ts +103 -0
  161. package/test/tmp/src/Project.ts +94 -0
  162. package/test/tmp/src/index.ts +20 -0
  163. package/test/tmp/src/types/brief_news_category.ts +7 -0
  164. package/test/tmp/src/types/brief_news_category_post.ts +7 -0
  165. package/test/tmp/src/types/brief_news_category_put.ts +7 -0
  166. package/test/tmp/src/types/brief_news_category_query.ts +26 -0
  167. package/test/tmp/src/types/client.ts +5 -0
  168. package/test/tmp/src/types/client_post.ts +5 -0
  169. package/test/tmp/src/types/client_put.ts +5 -0
  170. package/test/tmp/src/types/client_query.ts +18 -0
  171. package/test/tmp/src/types/institution.ts +4 -0
  172. package/test/tmp/src/types/institution_post.ts +4 -0
  173. package/test/tmp/src/types/institution_put.ts +4 -0
  174. package/test/tmp/src/types/institution_query.ts +14 -0
  175. package/test/tmp/src/types/project.ts +7 -0
  176. package/test/tmp/src/types/project_post.ts +7 -0
  177. package/test/tmp/src/types/project_put.ts +7 -0
  178. package/test/tmp/src/types/project_query.ts +27 -0
  179. package/test/tmp/src/utils/utils.ts +17 -0
  180. package/test/tmp/tsconfig.json +14 -0
  181. package/tsconfig.json +14 -0
@@ -0,0 +1,365 @@
1
+ import assert from "assert";
2
+ import { array, boolean, z, ZodBoolean, ZodDate, ZodNumber, ZodString } from 'zod'
3
+
4
+ import { z_mongodb_id } from '../dist/utils/mongoose_from_zod.js';
5
+ import { query_validator_from_zod } from '../dist/utils/query_validator_from_zod.js';
6
+ import { query_object_to_mongodb_query, query_object_to_mongodb_limits } from '../dist/utils/query_object_to_mongodb_query.js';
7
+ import { Schema } from 'mongoose'
8
+
9
+ import { Cache } from '../dist/utils/cache.js'
10
+
11
+ describe('query validator to mongodb query', function () {
12
+
13
+ class Query_Mock {
14
+ filter: any
15
+ meta: any
16
+
17
+ constructor(){
18
+ this.filter = {};
19
+ this.meta = {};
20
+
21
+ }
22
+
23
+ sort(sort){
24
+ this.meta.sort = sort;
25
+ }
26
+
27
+ limit(limit){
28
+ this.meta.limit = limit;
29
+ }
30
+
31
+ gt(path, value){
32
+ this.filter[path] = {
33
+ $gt: value
34
+ }
35
+ }
36
+
37
+ lt(path, value){
38
+ this.filter[path] = {
39
+ $lt: value
40
+ }
41
+ }
42
+ }
43
+
44
+
45
+ it('should be able to transform basic parameters into a mongodb query', async function () {
46
+ let query_validator = query_validator_from_zod(z.object({
47
+ enum: z.enum(['one', 'two']),
48
+ string: z.string(),
49
+ number: z.number(),
50
+ int: z.int(),
51
+ nest: z.object({
52
+ nested: z.string()
53
+ }),
54
+ boolean: z.boolean(),
55
+ date: z.date(),
56
+ object_id: z_mongodb_id,
57
+ array: z.array(z.string())
58
+ }))
59
+
60
+ let date = new Date();
61
+
62
+ assert.deepEqual(
63
+ query_object_to_mongodb_query(query_validator.parse({
64
+ enum: 'one',
65
+ string: 'string',
66
+ number: '54',
67
+ int: '43',
68
+ 'nest.nested': 'panko',
69
+ boolean: 'true',
70
+ date: date.toISOString(),
71
+ object_id: '6894cba684185cb03275d511',
72
+ array: 'chupacabra'
73
+ })),
74
+ {
75
+ enum: 'one',
76
+ string: 'string',
77
+ number: 54,
78
+ int: 43,
79
+ 'nest.nested': 'panko',
80
+ boolean: true,
81
+ date: date,
82
+ object_id: '6894cba684185cb03275d511',
83
+ array: 'chupacabra'
84
+ }
85
+ )
86
+ });
87
+
88
+ it('should be able to transform gt', async function () {
89
+ let query_validator = query_validator_from_zod(z.object({
90
+ param: z.number(),
91
+ }))
92
+
93
+ assert.deepEqual(
94
+ query_object_to_mongodb_query(query_validator.parse({
95
+ param_gt: '5'
96
+ })),
97
+ {
98
+ param: {
99
+ $gt: 5
100
+ }
101
+ }
102
+ )
103
+ });
104
+
105
+ it('should be able to transform gte', async function () {
106
+ let query_validator = query_validator_from_zod(z.object({
107
+ param: z.number(),
108
+ }))
109
+
110
+ assert.deepEqual(
111
+ query_object_to_mongodb_query(query_validator.parse({
112
+ param_gte: '5'
113
+ })),
114
+ {
115
+ param: {
116
+ $gte: 5
117
+ }
118
+ }
119
+ )
120
+ });
121
+
122
+ it('should be able to transform lt', async function () {
123
+ let query_validator = query_validator_from_zod(z.object({
124
+ param: z.number(),
125
+ }))
126
+
127
+ assert.deepEqual(
128
+ query_object_to_mongodb_query(query_validator.parse({
129
+ param_lt: '5'
130
+ })),
131
+ {
132
+ param: {
133
+ $lt: 5
134
+ }
135
+ }
136
+ )
137
+ });
138
+
139
+ it('should be able to transform lte', async function () {
140
+ let query_validator = query_validator_from_zod(z.object({
141
+ param: z.number(),
142
+ }))
143
+
144
+ assert.deepEqual(
145
+ query_object_to_mongodb_query(query_validator.parse({
146
+ param_lte: '5'
147
+ })),
148
+ {
149
+ param: {
150
+ $lte: 5
151
+ }
152
+ }
153
+ )
154
+ });
155
+
156
+ it('should be able to transform in', async function () {
157
+ let query_validator = query_validator_from_zod(z.object({
158
+ param: z.string(),
159
+ }))
160
+
161
+ assert.deepEqual(
162
+ query_object_to_mongodb_query(query_validator.parse({
163
+ param_in: 'test1,test2,test3'
164
+ })),
165
+ {
166
+ param: {
167
+ $in: ['test1', 'test2', 'test3']
168
+ }
169
+ }
170
+ )
171
+ });
172
+
173
+ it('should be able to discard controllers', async function () {
174
+ let query_validator = query_validator_from_zod(z.object({
175
+ param: z.number(),
176
+ }))
177
+
178
+ assert.deepEqual(
179
+ query_object_to_mongodb_query(query_validator.parse({
180
+ param: '5',
181
+ limit: 6,
182
+ cursor: '6894cba684185cb03275d511',
183
+ sort: 'param',
184
+ sort_order: 'descending'
185
+ })),
186
+ {
187
+ param: 5
188
+ }
189
+ )
190
+ });
191
+
192
+ it('should be able to extract sort metadata', async function () {
193
+ let query_validator = query_validator_from_zod(z.object({
194
+ param: z.number(),
195
+ }))
196
+
197
+ let query = new Query_Mock();
198
+
199
+ //@ts-expect-error
200
+ query_object_to_mongodb_limits(query, query_validator.parse({
201
+ param: '5',
202
+ sort: 'param',
203
+ }));
204
+
205
+ assert.deepEqual(
206
+ query.filter,
207
+ {}
208
+ )
209
+
210
+ assert.deepEqual(
211
+ query.meta,
212
+ {
213
+ limit: 100,
214
+ sort: {
215
+ param: 'ascending'
216
+ }
217
+ }
218
+ )
219
+ });
220
+
221
+ it('should be able to extract sort metadata with a sort order', async function () {
222
+ let query_validator = query_validator_from_zod(z.object({
223
+ param: z.number(),
224
+ }))
225
+
226
+ let query = new Query_Mock();
227
+
228
+ //@ts-expect-error
229
+ query_object_to_mongodb_limits(query, query_validator.parse({
230
+ param: '5',
231
+ sort: 'param',
232
+ sort_order: 'descending'
233
+ }));
234
+
235
+ assert.deepEqual(
236
+ query.filter,
237
+ {}
238
+ )
239
+
240
+ assert.deepEqual(
241
+ query.meta,
242
+ {
243
+ limit: 100,
244
+ sort: {
245
+ param: 'descending'
246
+ }
247
+ }
248
+ )
249
+ });
250
+
251
+
252
+ it('should sort by ID if given a sort order without a sort field', async function () {
253
+ let query_validator = query_validator_from_zod(z.object({
254
+ param: z.number(),
255
+ }))
256
+
257
+ let query = new Query_Mock();
258
+
259
+ //@ts-expect-error
260
+ query_object_to_mongodb_limits(query, query_validator.parse({
261
+ param: '5',
262
+ sort_order: 'descending'
263
+ }));
264
+
265
+ assert.deepEqual(
266
+ query.filter,
267
+ {}
268
+ )
269
+
270
+ assert.deepEqual(
271
+ query.meta,
272
+ {
273
+ limit: 100,
274
+ sort: {
275
+ _id: 'descending'
276
+ }
277
+ }
278
+ )
279
+ });
280
+
281
+ it('should be able to extract limit metadata', async function () {
282
+ let query_validator = query_validator_from_zod(z.object({
283
+ param: z.number(),
284
+ }))
285
+
286
+ let query = new Query_Mock();
287
+
288
+ //@ts-expect-error
289
+ query_object_to_mongodb_limits(query, query_validator.parse({
290
+ param: '5',
291
+ limit: '5',
292
+ }));
293
+
294
+ assert.deepEqual(
295
+ query.filter,
296
+ {}
297
+ )
298
+
299
+ assert.deepEqual(
300
+ query.meta,
301
+ {
302
+ limit: 5
303
+ }
304
+ )
305
+ });
306
+
307
+ it('should default to sane limits', async function () {
308
+ let query_validator = query_validator_from_zod(z.object({
309
+ param: z.number(),
310
+ }))
311
+
312
+ let query = new Query_Mock();
313
+
314
+ //@ts-expect-error
315
+ query_object_to_mongodb_limits(query, query_validator.parse({
316
+ param: '5',
317
+ limit: '5000',
318
+ }));
319
+
320
+ assert.deepEqual(
321
+ query.filter,
322
+ {}
323
+ )
324
+
325
+ assert.deepEqual(
326
+ query.meta,
327
+ {
328
+ limit: 100
329
+ }
330
+ )
331
+ });
332
+
333
+ it('should filter by ID when using a cursor', async function () {
334
+ let query_validator = query_validator_from_zod(z.object({
335
+ param: z.number(),
336
+ }))
337
+
338
+ let query = new Query_Mock();
339
+
340
+ //@ts-expect-error
341
+ query_object_to_mongodb_limits(query, query_validator.parse({
342
+ param: '5',
343
+ cursor: '6894cba684185cb03275d511',
344
+ }));
345
+
346
+ assert.deepEqual(
347
+ query.filter,
348
+ {
349
+ _id: {
350
+ $gt: '6894cba684185cb03275d511'
351
+ }
352
+ }
353
+ )
354
+
355
+ assert.deepEqual(
356
+ query.meta,
357
+ {
358
+ limit: 100,
359
+ sort: {
360
+ _id: 'ascending'
361
+ }
362
+ }
363
+ )
364
+ });
365
+ });
@@ -0,0 +1,204 @@
1
+ import assert from "assert";
2
+ import { z, ZodBoolean, ZodDate, ZodNumber, ZodString } from 'zod'
3
+
4
+ import { schema_from_zod, z_mongodb_id } from '../dist/utils/mongoose_from_zod.js';
5
+ import { Schema } from 'mongoose'
6
+
7
+ import { Cache } from '../dist/utils/cache.js'
8
+
9
+ describe('Cache', function () {
10
+
11
+ function sleep(ms) {
12
+ return new Promise((resolve) => {
13
+ setTimeout(resolve, ms);
14
+ });
15
+ }
16
+
17
+ it('should be able to set and regurgitate elements at a key', async function () {
18
+ let cache = new Cache(10);
19
+
20
+ const key = 'best_animal'
21
+ const value = { 'test': 'flamingo' }
22
+
23
+ cache.set(key, value);
24
+ assert.deepEqual(cache.get(key), value);
25
+ });
26
+
27
+ it('should be able to set and regurgitate elements at a key using the first_get_then_fetch method', async function () {
28
+ let cache = new Cache(10);
29
+
30
+ const key = 'best_animal'
31
+ const value = { 'test': 'flamingo' }
32
+
33
+ assert.deepEqual(await cache.first_get_then_fetch(key, async () => value), value);
34
+ });
35
+
36
+ it('should set values in the cache for later retrieval when using the first_get_then_fetch method', async function () {
37
+ let cache = new Cache(10);
38
+
39
+ const key = 'best_animal'
40
+ const value = { 'test': 'flamingo' }
41
+
42
+ await cache.first_get_then_fetch(key, async () => value)
43
+
44
+ assert.deepEqual(cache.get(key), value);
45
+ });
46
+
47
+ it('cache values set through the standard set method should expire', async function () {
48
+ let cache = new Cache(10);
49
+
50
+ const key = 'best_animal'
51
+ const value = { 'test': 'flamingo' }
52
+
53
+ cache.set(key, value);
54
+
55
+ await sleep(20);
56
+
57
+ assert.deepEqual(cache.get(key), undefined);
58
+ });
59
+
60
+ it('cache values set through the first_get_then_fetch method should expire', async function () {
61
+ let cache = new Cache(10);
62
+
63
+ const key = 'best_animal'
64
+ const value = { 'test': 'flamingo' }
65
+
66
+ await cache.first_get_then_fetch(key, async () => value)
67
+
68
+ await sleep(20);
69
+
70
+ assert.deepEqual(cache.get(key), undefined);
71
+ });
72
+
73
+ it('if should delay throwing away the cached value every time the key is set', async function () {
74
+ let cache = new Cache(5);
75
+
76
+ const key = 'best_animal'
77
+ const value = { 'test': 'flamingo' }
78
+
79
+ cache.set(key, value);
80
+ await sleep(2);
81
+ cache.set(key, value);
82
+ await sleep(2);
83
+ cache.set(key, value);
84
+ await sleep(2);
85
+ cache.set(key, value);
86
+ await sleep(2);
87
+ cache.set(key, value);
88
+ await sleep(2);
89
+ cache.set(key, value);
90
+ await sleep(2);
91
+
92
+ assert.deepEqual(cache.get(key), value);
93
+ });
94
+
95
+ it('if should delay throwing away the cached value every time the key is fetched', async function () {
96
+ let cache = new Cache(5);
97
+
98
+ const key = 'best_animal'
99
+ const value = { 'test': 'flamingo' }
100
+
101
+ cache.set(key, value);
102
+ await sleep(2);
103
+ cache.get(key);
104
+ await sleep(2);
105
+ cache.get(key);
106
+ await sleep(2);
107
+ cache.get(key);
108
+ await sleep(2);
109
+ cache.get(key);
110
+ await sleep(2);
111
+ cache.get(key);
112
+ await sleep(2);
113
+
114
+ assert.deepEqual(cache.get(key), value);
115
+ });
116
+
117
+ it('if the first_get_then_fetch method throws an error, it should be passed upstream to be caught.', async function () {
118
+ let cache = new Cache(10);
119
+
120
+ const key = 'best_animal'
121
+ const value = { 'test': 'flamingo' }
122
+
123
+ assert.rejects(async() => {
124
+ await cache.first_get_then_fetch(key, async () => { throw new Error('bad data here bro') })
125
+ }, {message: 'bad data here bro'})
126
+ });
127
+
128
+ it('if the first_get_then_fetch method is called multiple times, the fetch method should run only once.', async function () {
129
+ let cache = new Cache(30);
130
+
131
+ const key = 'best_animal'
132
+ const value = { 'test': 'flamingo' }
133
+
134
+ let run_counter = 0;
135
+
136
+ cache.first_get_then_fetch(key, async () => { run_counter++; await sleep(5); return value; })
137
+ cache.first_get_then_fetch(key, async () => { run_counter++; await sleep(5); return value; })
138
+ cache.first_get_then_fetch(key, async () => { run_counter++; await sleep(5); return value; })
139
+ await cache.first_get_then_fetch(key, async () => { run_counter++; await sleep(5); return value; })
140
+ await sleep(5);
141
+
142
+ assert.deepEqual(cache.get(key), value);
143
+ assert.deepEqual(run_counter, 1);
144
+ });
145
+
146
+ it('if the first_fetch_then_refresh method is called and the key is not in the cache, it should be fetched', async function () {
147
+ let cache = new Cache(30);
148
+
149
+ const key = 'best_animal'
150
+ const value = { 'test': 'flamingo' }
151
+
152
+ let fetch_method = async () => { return value; };
153
+
154
+ await cache.first_fetch_then_refresh(key, fetch_method)
155
+
156
+ assert.deepEqual(cache.get(key), value);
157
+ });
158
+
159
+ it('if the first_fetch_then_refresh method is called multiple times, the fetch method should run only once.', async function () {
160
+ let cache = new Cache(30);
161
+
162
+ const key = 'best_animal'
163
+ const value = { 'test': 'flamingo' }
164
+
165
+ let fetch_method = async () => { run_counter++; await sleep(5); return value; };
166
+ let run_counter = 0;
167
+
168
+ cache.first_fetch_then_refresh(key, fetch_method)
169
+ cache.first_fetch_then_refresh(key, fetch_method)
170
+ cache.first_fetch_then_refresh(key, fetch_method)
171
+ await cache.first_fetch_then_refresh(key, fetch_method)
172
+ await sleep(5);
173
+
174
+ assert.deepEqual(cache.get(key), value);
175
+ assert.deepEqual(run_counter, 1);
176
+ });
177
+
178
+
179
+ it('if the first_fetch_then_refresh method is called when the cache already has the key, it should still refetch after the value is returned.', async function () {
180
+ let cache = new Cache(30);
181
+
182
+ const key = 'best_animal'
183
+ const value = { 'test': 'flamingo' }
184
+
185
+ let fetch_method = async () => { await sleep(5); run_counter++; return value; };
186
+ let run_counter = 0;
187
+
188
+ cache.set(key, value);
189
+
190
+ assert.deepEqual(cache.get(key), value);
191
+ assert.deepEqual(run_counter, 0);
192
+
193
+ let fetch_promise = cache.first_fetch_then_refresh(key, fetch_method)
194
+
195
+ assert.deepEqual(run_counter, 0);
196
+
197
+ await fetch_promise;
198
+ await sleep(7);
199
+
200
+ assert.deepEqual(cache.get(key), value);
201
+ assert.deepEqual(run_counter, 1);
202
+ });
203
+
204
+ });