@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,530 @@
1
+
2
+ import assert from "assert";
3
+
4
+ import { z_mongodb_id } from '../dist/utils/mongoose_from_zod.js';
5
+ import { F_Collection } from '../dist/f_collection.js';
6
+ import { F_Collection_Registry } from '../dist/F_Collection_Registry.js'
7
+ import { F_SM_Open_Access } from '../dist/F_Security_Models/F_SM_Open_Access.js'
8
+ import { z, ZodBoolean, ZodDate, ZodNumber, ZodString } from 'zod'
9
+
10
+ import got from 'got'
11
+ import express, { Express, Request, Response, NextFunction } from 'express'
12
+ import mongoose, { Mongoose } from "mongoose";
13
+ import { Server } from "http";
14
+
15
+ /*mongoose.connection.on('connected', () => console.log('connected'));
16
+ mongoose.connection.on('open', () => console.log('open'));
17
+ mongoose.connection.on('disconnected', () => console.log('disconnected'));
18
+ mongoose.connection.on('reconnected', () => console.log('reconnected'));
19
+ mongoose.connection.on('disconnecting', () => console.log('disconnecting'));
20
+ mongoose.connection.on('close', () => console.log('close'));*/
21
+
22
+ describe('Basic Server', function () {
23
+ const port = 4601;
24
+ let express_app: Express;
25
+ let server: Server;
26
+ let db_connection: Mongoose;
27
+
28
+ const validate_institution = z.object({
29
+ _id: z_mongodb_id,
30
+ name: z.string(),
31
+ });
32
+ const validate_client = z.object({
33
+ _id: z_mongodb_id,
34
+ institution_id: z_mongodb_id,
35
+ name: z.string(),
36
+ });
37
+ const validate_project = z.object({
38
+ _id: z_mongodb_id,
39
+ institution_id: z_mongodb_id,
40
+ client_id: z_mongodb_id,
41
+ name: z.string(),
42
+ });
43
+
44
+ let institution: F_Collection<'institution', typeof validate_institution>;
45
+ let client: F_Collection<'client', typeof validate_client>;
46
+ let project: F_Collection<'project', typeof validate_project>;
47
+
48
+ let registry: F_Collection_Registry;
49
+
50
+
51
+ // before any tests run, set up the server and the db connection
52
+ before(async function() {
53
+ express_app = express();
54
+ express_app.use(express.json());
55
+ db_connection = await mongoose.connect('mongodb://127.0.0.1:27017/');
56
+
57
+ // if we define these in mocha's describe() function, it runs before connecting to the database.
58
+ // this causes the mongoose definitions to get attached to a database instance that is closed at
59
+ // the end of the previous test, spawning a MongoNotConnectedError error.
60
+ institution = new F_Collection('institution', validate_institution);
61
+ institution.add_layers([], [new F_SM_Open_Access(institution)]);
62
+
63
+ client = new F_Collection('client', validate_client);
64
+ client.add_layers([institution.collection_id], [new F_SM_Open_Access(client)]);
65
+
66
+ project = new F_Collection('project', validate_project);
67
+ project.add_layers([institution.collection_id, client.collection_id], [new F_SM_Open_Access(project)]);
68
+
69
+ // build registry
70
+ let proto_registry = new F_Collection_Registry();
71
+ registry = proto_registry.register(institution).register(client).register(project);
72
+ registry.compile(express_app, '/api');
73
+
74
+ server = express_app.listen(port);
75
+
76
+ // wait for a moment because otherwise stuff breaks for no reason
77
+ await new Promise(resolve => setTimeout(resolve, 200))
78
+ })
79
+
80
+ after(async function (){
81
+ await server.close();
82
+ mongoose.connection.modelNames().forEach(ele => mongoose.connection.deleteModel(ele));
83
+ db_connection.modelNames().forEach(ele => db_connection.deleteModel(ele));
84
+ await db_connection.disconnect()
85
+ });
86
+
87
+ beforeEach(async function(){
88
+ for(let collection of Object.values(registry.collections)){
89
+ //@ts-ignore
90
+ await collection.mongoose_model.collection.drop();
91
+ }
92
+ })
93
+
94
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
95
+ ///////////////////////////////////////////////////////////// GET one ////////////////////////////////////////////////////////////////////////////////
96
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
97
+
98
+ it(`should be able to perform a basic GET operation`, async function () {
99
+ let test_institution = await institution.mongoose_model.create({
100
+ name: 'Spandex Co'
101
+ });
102
+
103
+ let test_client = await client.mongoose_model.create({
104
+ institution_id: test_institution._id,
105
+ name: `Bob's spandex house`
106
+ })
107
+
108
+ let results = await got.get(`http://localhost:${port}/api/institution/${test_institution._id}`).json();
109
+ //@ts-ignore
110
+ assert.deepEqual(JSON.parse(JSON.stringify(test_institution)), results.data);
111
+ });
112
+
113
+ it(`should be able to perform a basic GET operation of something one layer deep`, async function () {
114
+ let test_institution = await institution.mongoose_model.create({
115
+ name: 'Spandex Co'
116
+ });
117
+
118
+ let test_client = await client.mongoose_model.create({
119
+ institution_id: test_institution._id,
120
+ name: `Bob's spandex house`
121
+ })
122
+
123
+ let results = await got.get(`http://localhost:${port}/api/institution/${test_institution._id}/client/${test_client._id}`).json();
124
+ //@ts-ignore
125
+ assert.deepEqual(JSON.parse(JSON.stringify(test_client)), results.data);
126
+ });
127
+
128
+ it(`should be able to perform a basic GET operation of a leaf`, async function () {
129
+ let test_institution = await institution.mongoose_model.create({
130
+ name: 'Spandex Co'
131
+ });
132
+
133
+ let test_client = await client.mongoose_model.create({
134
+ institution_id: test_institution._id,
135
+ name: `Bob's spandex house`
136
+ })
137
+
138
+ let test_project = await project.mongoose_model.create({
139
+ institution_id: test_institution._id,
140
+ client_id: test_client._id,
141
+ name: `Spandex Reincarnation`
142
+ })
143
+
144
+ let results = await got.get(`http://localhost:${port}/api/institution/${test_institution._id}/client/${test_client._id}/project/${test_project._id}`).json();
145
+ //@ts-ignore
146
+ assert.deepEqual(JSON.parse(JSON.stringify(test_project)), results.data);
147
+ });
148
+
149
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
150
+ ///////////////////////////////////////////////////////////// GET multiple ///////////////////////////////////////////////////////////////////////////
151
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
152
+
153
+
154
+ it(`should be able to perform a basic GET multiple operation`, async function () {
155
+ let test_institutions = []
156
+ for(let q = 0; q < 5; q++){
157
+ let test_institution = await institution.mongoose_model.create({
158
+ name: ['spandex co',
159
+ 'the ordinary institute',
160
+ 'saliva branding collective',
161
+ 'united league of billionare communitsts',
162
+ 'geriatric co',
163
+ 'jousing club of omaha, nebraska',
164
+ 'dental hygenist paratrooper union',
165
+ 'martha stewart\'s cannibal fan club',
166
+ 'wrecking ball operator crochet club',
167
+ 'accidental co'
168
+ ][q]
169
+ });
170
+ //@ts-ignore
171
+ test_institutions.push(test_institution);
172
+ }
173
+
174
+ let results = await got.get(`http://localhost:${port}/api/institution`).json();
175
+ //@ts-ignore
176
+ assert.deepEqual(JSON.parse(JSON.stringify(test_institutions)), results.data);
177
+ });
178
+
179
+ it(`should be able to perform a basic GET multiple operation of something one layer deep`, async function () {
180
+ let test_institution_1 = await institution.mongoose_model.create({
181
+ name: 'Spandex Co'
182
+ });
183
+
184
+ let test_institution_2 = await institution.mongoose_model.create({
185
+ name: 'the ordinary institute'
186
+ });
187
+
188
+ let test_clients = []
189
+ for(let q = 0; q < 5; q++){
190
+ let test_client = await client.mongoose_model.create({
191
+ institution_id: test_institution_1._id,
192
+ name: `test_client_${q}`
193
+ });
194
+ //@ts-ignore
195
+ test_clients.push(test_client);
196
+
197
+ // create a test client for the other institution to make sure
198
+ // the endpoint doesn't return test clients from other institutions
199
+ await client.mongoose_model.create({
200
+ institution_id: test_institution_2._id,
201
+ name: `test_client_${q}`
202
+ });
203
+ }
204
+
205
+ let results = await got.get(`http://localhost:${port}/api/institution/${test_institution_1._id}/client`).json();
206
+ //@ts-ignore
207
+ assert.deepEqual(JSON.parse(JSON.stringify(test_clients)), results.data);
208
+ });
209
+
210
+ it(`should be able to perform a basic GET multiple operation of a leaf`, async function () {
211
+ let test_institution_1 = await institution.mongoose_model.create({
212
+ name: 'Spandex Co'
213
+ });
214
+
215
+ let test_client_1 = await client.mongoose_model.create({
216
+ institution_id: test_institution_1._id,
217
+ name: `Bob's spandex house`
218
+ })
219
+
220
+ let test_institution_2 = await institution.mongoose_model.create({
221
+ name: 'Spandex Co'
222
+ });
223
+
224
+ let test_client_2 = await client.mongoose_model.create({
225
+ institution_id: test_institution_2._id,
226
+ name: `Bob's spandex house`
227
+ })
228
+
229
+ let test_projects = []
230
+ for(let q = 0; q < 5; q++){
231
+ let test_client = await project.mongoose_model.create({
232
+ institution_id: test_institution_1._id,
233
+ client_id: test_client_1._id,
234
+ name: `Spandex Reincarnation`
235
+ });
236
+ //@ts-ignore
237
+ test_projects.push(test_client);
238
+
239
+ // create a test project for the other institution to make sure
240
+ // the endpoint doesn't return test project from other institutions
241
+ await project.mongoose_model.create({
242
+ institution_id: test_institution_2._id,
243
+ client_id: test_client_2._id,
244
+ name: `Spandex Reincarnation`
245
+ });
246
+ }
247
+
248
+ let results = await got.get(`http://localhost:${port}/api/institution/${test_institution_1._id}/client/${test_client_1._id}/project`).json();
249
+ //@ts-ignore
250
+ assert.deepEqual(JSON.parse(JSON.stringify(test_projects)), results.data);
251
+ });
252
+
253
+
254
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
255
+ ///////////////////////////////////////////////////////////// PUT ////////////////////////////////////////////////////////////////////////////////////
256
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
257
+
258
+
259
+
260
+ it(`should be able to perform a basic PUT operation`, async function () {
261
+ let test_institution = await institution.mongoose_model.create({
262
+ name: 'Spandex Co'
263
+ });
264
+
265
+ let results = await got.put(`http://localhost:${port}/api/institution/${test_institution._id}`, {
266
+ json: {
267
+ name: 'Leather Pants Co'
268
+ },
269
+ }).json();
270
+
271
+ //@ts-ignore
272
+ assert.notDeepEqual(JSON.parse(JSON.stringify(test_institution)), results.data);
273
+ //@ts-ignore
274
+ assert.deepEqual(JSON.parse(JSON.stringify(await institution.mongoose_model.findById(test_institution._id))), results.data);
275
+ });
276
+
277
+ it(`should be able to perform a basic PUT operation of something one layer deep`, async function () {
278
+ let test_institution = await institution.mongoose_model.create({
279
+ name: 'Spandex Co'
280
+ });
281
+
282
+ let test_client = await client.mongoose_model.create({
283
+ institution_id: test_institution._id,
284
+ name: `Bob's spandex house`
285
+ })
286
+
287
+ let results = await got.put(`http://localhost:${port}/api/institution/${test_institution._id}/client/${test_client._id}`, {
288
+ json: {
289
+ name: `International house of leather pants`
290
+ },
291
+ }).json();
292
+ //@ts-ignore
293
+ assert.notDeepEqual(JSON.parse(JSON.stringify(test_client)), results.data);
294
+ //@ts-ignore
295
+ assert.deepEqual(JSON.parse(JSON.stringify(await client.mongoose_model.findById(test_client._id))), results.data);
296
+ });
297
+
298
+ it(`should be able to perform a basic PUT operation of a leaf`, async function () {
299
+ let test_institution = await institution.mongoose_model.create({
300
+ name: 'Spandex Co'
301
+ });
302
+
303
+ let test_client = await client.mongoose_model.create({
304
+ institution_id: test_institution._id,
305
+ name: `Bob's spandex house`
306
+ })
307
+
308
+ let test_project = await project.mongoose_model.create({
309
+ institution_id: test_institution._id,
310
+ client_id: test_client._id,
311
+ name: `Spandex Reincarnation`
312
+ })
313
+
314
+ let results = await got.put(`http://localhost:${port}/api/institution/${test_institution._id}/client/${test_client._id}/project/${test_project._id}`, {
315
+ json: {
316
+ name: `Leather Pants Transubstantiation`
317
+ },
318
+ }).json();
319
+ //@ts-ignore
320
+ assert.notDeepEqual(JSON.parse(JSON.stringify(test_project)), results.data);
321
+ //@ts-ignore
322
+ assert.deepEqual(JSON.parse(JSON.stringify(await project.mongoose_model.findById(test_project._id))), results.data);
323
+ });
324
+
325
+ it(`should reject a PUT operation that changes layer membership`, async function () {
326
+ let test_institution = await institution.mongoose_model.create({
327
+ name: 'Spandex Co'
328
+ });
329
+
330
+ let test_client = await client.mongoose_model.create({
331
+ institution_id: test_institution._id,
332
+ name: `Bob's spandex house`
333
+ })
334
+
335
+ let test_client_2 = await client.mongoose_model.create({
336
+ institution_id: test_institution._id,
337
+ name: `Anna's Latex Emporium`
338
+ })
339
+
340
+ let test_project = await project.mongoose_model.create({
341
+ institution_id: test_institution._id,
342
+ client_id: test_client._id,
343
+ name: `Spandex Reincarnation`
344
+ })
345
+
346
+ assert.rejects(async () => {
347
+ let results = await got.put(`http://localhost:${port}/api/institution/${test_institution._id}/client/${test_client._id}/project/${test_project._id}`, {
348
+ json: {
349
+ name: `Leather Pants Transubstantiation`,
350
+ client_id: test_client_2._id
351
+
352
+ },
353
+ }).json();
354
+ }, {
355
+ message: 'HTTPError: Response code 403 (Forbidden)'
356
+ });
357
+ });
358
+
359
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
360
+ ///////////////////////////////////////////////////////////// POST ///////////////////////////////////////////////////////////////////////////////////
361
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
362
+
363
+ it(`should be able to perform a basic POST operation`, async function () {
364
+ let results = await got.post(`http://localhost:${port}/api/institution`, {
365
+ json: {
366
+ name: 'Leather Pants Co'
367
+ },
368
+ }).json();
369
+
370
+ //@ts-ignore
371
+ assert.deepEqual(JSON.parse(JSON.stringify(await institution.mongoose_model.findById(results.data._id))), results.data);
372
+ });
373
+
374
+ it(`should be able to perform a basic POST operation of something one layer deep`, async function () {
375
+ this.timeout(1000 * 20);
376
+ let test_institution = await institution.mongoose_model.create({
377
+ name: 'Spandex Co'
378
+ });
379
+
380
+ let results = await got.post(`http://localhost:${port}/api/institution/${test_institution._id}/client`, {
381
+ json: {
382
+ name: `International house of leather pants`,
383
+ institution_id: test_institution._id,
384
+ },
385
+ }).json();
386
+
387
+ //@ts-ignore
388
+ assert.deepEqual(JSON.parse(JSON.stringify(await client.mongoose_model.findById(results.data._id))), results.data);
389
+ });
390
+
391
+ it(`should be able to perform a basic POST operation of a leaf`, async function () {
392
+ this.timeout(1000 * 20);
393
+ let test_institution = await institution.mongoose_model.create({
394
+ name: 'Spandex Co'
395
+ });
396
+
397
+ let test_client = await client.mongoose_model.create({
398
+ institution_id: test_institution._id,
399
+ name: `Bob's spandex house`
400
+ })
401
+
402
+ let results = await got.post(`http://localhost:${port}/api/institution/${test_institution._id}/client/${test_client._id}/project`, {
403
+ json: {
404
+ name: `Leather Pants Transubstantiation`,
405
+ institution_id: test_institution._id,
406
+ client_id: test_client._id,
407
+ },
408
+ }).json();
409
+
410
+ //@ts-ignore
411
+ assert.deepEqual(JSON.parse(JSON.stringify(await project.mongoose_model.findById(results.data._id))), results.data);
412
+ });
413
+
414
+ it(`should reject a POST operation at the wrong layer membership`, async function () {
415
+ let test_institution = await institution.mongoose_model.create({
416
+ name: 'Spandex Co'
417
+ });
418
+
419
+ let test_client = await client.mongoose_model.create({
420
+ institution_id: test_institution._id,
421
+ name: `Bob's spandex house`
422
+ })
423
+
424
+ let test_client_2 = await client.mongoose_model.create({
425
+ institution_id: test_institution._id,
426
+ name: `Anna's Latex Emporium`
427
+ })
428
+
429
+ assert.rejects(async () => {
430
+ let results = await got.post(`http://localhost:${port}/api/institution/${test_institution._id}/client/${test_client._id}/project`, {
431
+ json: {
432
+ name: `Leather Pants Transubstantiation`,
433
+ client_id: test_client_2._id,
434
+ institution_id: test_institution._id,
435
+ },
436
+ }).json();
437
+ }, {
438
+ message: 'HTTPError: Response code 403 (Forbidden)'
439
+ });
440
+ });
441
+
442
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
443
+ ///////////////////////////////////////////////////////////// DELETE /////////////////////////////////////////////////////////////////////////////////
444
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
445
+
446
+ it(`should be able to perform a basic DELETE operation`, async function () {
447
+
448
+ let test_institution = await institution.mongoose_model.create({
449
+ name: 'test institution'
450
+ })
451
+
452
+ let results = await got.delete(`http://localhost:${port}/api/institution/${test_institution._id}`).json();
453
+
454
+ //@ts-ignore
455
+ assert.deepEqual(JSON.parse(JSON.stringify(test_institution)), results.data);
456
+ assert.deepEqual(JSON.parse(JSON.stringify(await institution.mongoose_model.findById(test_institution._id))), undefined);
457
+ });
458
+
459
+ it(`should be able to perform a basic DELETE operation of something one layer deep`, async function () {
460
+ let test_institution = await institution.mongoose_model.create({
461
+ name: 'test institution'
462
+ })
463
+
464
+ let test_client = await client.mongoose_model.create({
465
+ name: 'test client',
466
+ institution_id: test_institution._id
467
+ })
468
+
469
+ let results = await got.delete(`http://localhost:${port}/api/institution/${test_institution._id}/client/${test_client._id}`).json();
470
+
471
+ //@ts-ignore
472
+ assert.deepEqual(JSON.parse(JSON.stringify(test_client)), results.data);
473
+ assert.deepEqual(JSON.parse(JSON.stringify(await client.mongoose_model.findById(test_client._id))), undefined);
474
+ });
475
+
476
+ it(`should be able to perform a basic DELETE operation of a leaf`, async function () {
477
+ this.timeout(1000 * 20);
478
+ let test_institution = await institution.mongoose_model.create({
479
+ name: 'Spandex Co'
480
+ });
481
+
482
+ let test_client = await client.mongoose_model.create({
483
+ institution_id: test_institution._id,
484
+ name: `Bob's spandex house`
485
+ })
486
+
487
+ let test_project = await project.mongoose_model.create({
488
+ institution_id: test_institution._id,
489
+ name: `Bob's spandex house`,
490
+ client_id: test_client._id,
491
+ })
492
+
493
+ let results = await got.delete(`http://localhost:${port}/api/institution/${test_institution._id}/client/${test_client._id}/project/${test_project._id}`).json();
494
+
495
+ //@ts-ignore
496
+ assert.deepEqual(JSON.parse(JSON.stringify(test_project)), results.data);
497
+ assert.deepEqual(JSON.parse(JSON.stringify(await project.mongoose_model.findById(test_project._id))), undefined);
498
+ });
499
+
500
+ it(`should reject a DELETE operation at the wrong layer membership`, async function () {
501
+ let test_institution = await institution.mongoose_model.create({
502
+ name: 'Spandex Co'
503
+ });
504
+
505
+ let test_client = await client.mongoose_model.create({
506
+ institution_id: test_institution._id,
507
+ name: `Bob's spandex house`
508
+ })
509
+
510
+ let test_client_2 = await client.mongoose_model.create({
511
+ institution_id: test_institution._id,
512
+ name: `Anna's Latex Emporium`
513
+ })
514
+
515
+ let test_project = await project.mongoose_model.create({
516
+ institution_id: test_institution._id,
517
+ name: `Bob's spandex house`,
518
+ client_id: test_client_2._id,
519
+ })
520
+
521
+ let results = await got.delete(`http://localhost:${port}/api/institution/${test_institution._id}/client/${test_client._id}/project/${test_project._id}`).json();
522
+
523
+ // this will just produce null rather than throwing an error, because there was nothing at the path to delete.
524
+ // this is different than a POST or PUT, where it's easier to detect a mismatch because the body may have an
525
+ // institution ID.
526
+ //@ts-ignore
527
+ assert.deepEqual(null, results.data);
528
+ assert.deepEqual(JSON.parse(JSON.stringify(await project.mongoose_model.findById(test_project._id))), JSON.parse(JSON.stringify(test_project)));
529
+ });
530
+ });