@liminalfunctions/framework 1.0.52 → 1.0.53
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/dist/F_Collection.d.ts +2 -0
- package/dist/F_Collection.js +9 -0
- package/dist/F_Collection.js.map +1 -1
- package/dist/F_Compile.js +247 -0
- package/dist/F_Compile.js.map +1 -1
- package/dist/code_generation/generate_client_library.d.ts +1 -0
- package/dist/code_generation/generate_client_library.js +37 -16
- package/dist/code_generation/generate_client_library.js.map +1 -1
- package/dist/code_generation/templates/collection.mustache +79 -1
- package/dist/utils/array_children_from_zod.d.ts +3 -0
- package/dist/utils/array_children_from_zod.js +39 -0
- package/dist/utils/array_children_from_zod.js.map +1 -0
- package/dist/utils/mongoose_from_zod.js +6 -1
- package/dist/utils/mongoose_from_zod.js.map +1 -1
- package/package.json +1 -1
- package/src/F_Collection.ts +14 -3
- package/src/F_Compile.ts +288 -16
- package/src/code_generation/generate_client_library.ts +35 -8
- package/src/code_generation/templates/collection.mustache +79 -1
- package/src/utils/array_children_from_zod.ts +44 -0
- package/src/utils/mongoose_from_zod.ts +7 -3
- package/test/0_1_mongoose_from_zod.test.ts +16 -10
- package/test/0_6_array_children.test.ts +127 -0
- package/test/1_0_basic_server.test.ts +107 -2
- package/test/1_1_security_ownership.test.ts +186 -6
- package/test/1_2_role_membership.test.ts +329 -9
- package/test/2_1_client_library_generation.test.ts +125 -1
- package/test/tmp/dist/Brief_News_Category.js.map +1 -1
- package/test/tmp/dist/Client.js.map +1 -1
- package/test/tmp/dist/Institution.js.map +1 -1
- package/test/tmp/dist/Project.d.ts +20 -0
- package/test/tmp/dist/Project.js +63 -0
- package/test/tmp/dist/Project.js.map +1 -1
- package/test/tmp/dist/types/project.d.ts +4 -0
- package/test/tmp/dist/types/project_post.d.ts +4 -0
- package/test/tmp/dist/types/project_put.d.ts +4 -0
- package/test/tmp/package-lock.json +111 -111
- package/test/tmp/src/Brief_News_Category.ts +3 -1
- package/test/tmp/src/Client.ts +3 -1
- package/test/tmp/src/Institution.ts +3 -1
- package/test/tmp/src/Project.ts +73 -1
- package/test/tmp/src/types/project.ts +4 -0
- package/test/tmp/src/types/project_post.ts +4 -0
- package/test/tmp/src/types/project_put.ts +4 -0
|
@@ -130,4 +130,82 @@ class Document {
|
|
|
130
130
|
}
|
|
131
131
|
}
|
|
132
132
|
{{/has_subcollections}}
|
|
133
|
-
|
|
133
|
+
|
|
134
|
+
{{#has_array_children}}
|
|
135
|
+
{{#array_children}}
|
|
136
|
+
array(key: "{{array_name}}"): Collection_{{my_built_collection}}_Array_{{array_name}};
|
|
137
|
+
{{/array_children}}
|
|
138
|
+
array(key: string) {
|
|
139
|
+
switch(key) {
|
|
140
|
+
{{#array_children}}
|
|
141
|
+
case "{{array_name}}":
|
|
142
|
+
return new Collection_{{my_built_collection}}_Array_{{array_name}}([...this.path, this.document_id, "{{array_name}}"], this.get_auth);
|
|
143
|
+
{{/array_children}}
|
|
144
|
+
default:
|
|
145
|
+
throw new Error(`Collection ${this.collection_id} does not have an array at the key ${key}`)
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
{{/has_array_children}}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
{{#array_children}}
|
|
152
|
+
{{array_type_put_definition}}
|
|
153
|
+
{{array_type_post_definition}}
|
|
154
|
+
|
|
155
|
+
export class Collection_{{my_built_collection}}_Array_{{array_name}} {
|
|
156
|
+
path: string[]
|
|
157
|
+
get_auth: () => Promise<any>
|
|
158
|
+
collection_id: string
|
|
159
|
+
collection_name_plural: string
|
|
160
|
+
array_key: string
|
|
161
|
+
|
|
162
|
+
constructor(path: string[], get_auth: () => Promise<any>) {
|
|
163
|
+
this.path = path;
|
|
164
|
+
this.get_auth = get_auth;
|
|
165
|
+
this.collection_id = "{{collection_id}}";
|
|
166
|
+
this.collection_name_plural = "{{collection_name_plural}}"
|
|
167
|
+
this.array_key = "{{array_name}}"
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
async push(document: {{type_array_child_post}}): Promise<{{type_return}}>{
|
|
171
|
+
try {
|
|
172
|
+
let result = await ky.post(this.path.join('/'), {
|
|
173
|
+
headers: {
|
|
174
|
+
authorization: await this.get_auth()
|
|
175
|
+
},
|
|
176
|
+
json: document
|
|
177
|
+
}).json() as Response<{{type_return}}>;
|
|
178
|
+
return result.data;
|
|
179
|
+
} catch(err){
|
|
180
|
+
return Promise.reject(err)
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
async replace(document: {{type_array_child_put}}): Promise<{{type_return}}>{
|
|
185
|
+
try {
|
|
186
|
+
let result = await ky.put([...this.path, document._id].join('/'), {
|
|
187
|
+
headers: {
|
|
188
|
+
authorization: await this.get_auth()
|
|
189
|
+
},
|
|
190
|
+
json: document
|
|
191
|
+
}).json() as Response<{{type_return}}>;
|
|
192
|
+
return result.data;
|
|
193
|
+
} catch(err){
|
|
194
|
+
return Promise.reject(err)
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
async delete(document_id: string): Promise<{{type_return}}>{
|
|
199
|
+
try {
|
|
200
|
+
let result = await ky.delete([...this.path, document_id].join('/'), {
|
|
201
|
+
headers: {
|
|
202
|
+
authorization: await this.get_auth()
|
|
203
|
+
}
|
|
204
|
+
}).json() as Response<{{type_return}}>;
|
|
205
|
+
return result.data;
|
|
206
|
+
} catch(err){
|
|
207
|
+
return Promise.reject(err)
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
{{/array_children}}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import z from "zod/v4";
|
|
2
|
+
import { find_loops, validator_group } from './zod_loop_seperator.js'
|
|
3
|
+
|
|
4
|
+
export function array_children_from_zod(zod_definition: z.ZodObject, loop_detector?: Map<any, validator_group>, built_map?: Map<string, z.ZodObject>, prefix: string = ''): Map<string, z.ZodObject> {
|
|
5
|
+
let loops = loop_detector ?? find_loops(zod_definition as z.ZodType);
|
|
6
|
+
let results = built_map ?? new Map<string, z.ZodObject>();
|
|
7
|
+
|
|
8
|
+
for(let [key, value] of Object.entries(zod_definition.shape)){
|
|
9
|
+
if(loops.has(value._zod.def)){ continue; }
|
|
10
|
+
let real_value = distill_zod(value);
|
|
11
|
+
switch (real_value._zod.def.type) {
|
|
12
|
+
case "object":
|
|
13
|
+
array_children_from_zod(real_value as z.ZodObject, loop_detector, results, prefix.length > 0 ? `${prefix}.${key}` : key)
|
|
14
|
+
break;
|
|
15
|
+
case "array":
|
|
16
|
+
//@ts-ignore
|
|
17
|
+
let element = distill_zod((real_value as z.ZodArray).element);
|
|
18
|
+
if(element._zod.def.type === 'object') {
|
|
19
|
+
let objdef = element._zod.def as z.core.$ZodObjectDef;
|
|
20
|
+
if(objdef.shape._id){
|
|
21
|
+
results.set(prefix.length > 0 ? `${prefix}.${key}` : key, element as z.ZodObject);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
break;
|
|
25
|
+
default:
|
|
26
|
+
break;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
}
|
|
30
|
+
return results;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function distill_zod(zod_definition: z.ZodType): z.ZodType {
|
|
34
|
+
switch (zod_definition._zod.def.type) {
|
|
35
|
+
case "nullable":
|
|
36
|
+
//@ts-ignore
|
|
37
|
+
return zod_definition._zod.def.innerType;
|
|
38
|
+
case "optional":
|
|
39
|
+
//@ts-ignore
|
|
40
|
+
return zod_definition._zod.def.innerType;
|
|
41
|
+
default:
|
|
42
|
+
return zod_definition;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -100,10 +100,10 @@ export function schema_entry_from_zod(zod_definition: z.ZodType, loop_detector:
|
|
|
100
100
|
result.required = !zod_definition.safeParse(undefined).success
|
|
101
101
|
return result;
|
|
102
102
|
case "nullable":
|
|
103
|
-
// stuff is nullable in mongodb by default, so just return the ordinary results of the parse
|
|
104
|
-
//@ts-expect-error
|
|
105
|
-
return schema_entry_from_zod((zod_definition as z.core.$ZodNullable)._zod.def.innerType, loop_detector)
|
|
106
103
|
case "optional":
|
|
104
|
+
// stuff is nullable in mongodb by default, so just return the ordinary results of the parse
|
|
105
|
+
////@ts-expect-error
|
|
106
|
+
//return schema_entry_from_zod((zod_definition as z.core.$ZodNullable)._zod.def.innerType, loop_detector)
|
|
107
107
|
return parse_optional(zod_definition._zod.def as z.core.$ZodOptionalDef, loop_detector);
|
|
108
108
|
case "record":
|
|
109
109
|
result = parse_record(zod_definition._zod.def as z.core.$ZodRecordDef, loop_detector);
|
|
@@ -171,6 +171,10 @@ function parse_object(def: z.core.$ZodObjectDef, loop_detector: Map<any, validat
|
|
|
171
171
|
//@ts-ignore
|
|
172
172
|
retval[key] = schema_entry_from_zod(value, loop_detector);
|
|
173
173
|
}
|
|
174
|
+
|
|
175
|
+
// handle the edge cases arouund mongoose's auto-IDs
|
|
176
|
+
if(!retval._id){ retval._id = false; }
|
|
177
|
+
else { delete retval._id; }
|
|
174
178
|
return {mongoose_type: retval, required: true};
|
|
175
179
|
}
|
|
176
180
|
|
|
@@ -69,7 +69,7 @@ describe('Mongoose from Zod', function () {
|
|
|
69
69
|
it(`should convert ${basic_type.label} to mongoose type with nullable`, function () {
|
|
70
70
|
let zodSchema = z.object({ test_value: basic_type.zod_function().nullable() })
|
|
71
71
|
let mongooseSchema = schema_from_zod(zodSchema)
|
|
72
|
-
assert.deepEqual({ test_value: { mongoose_type: basic_type.mongoose_type, required:
|
|
72
|
+
assert.deepEqual({ test_value: { mongoose_type: basic_type.mongoose_type, required: false } }, mongooseSchema)
|
|
73
73
|
});
|
|
74
74
|
|
|
75
75
|
it(`should convert ${basic_type.label} to mongoose type with optional AND default values`, function () {
|
|
@@ -87,20 +87,26 @@ describe('Mongoose from Zod', function () {
|
|
|
87
87
|
it(`should convert a nested object containing a ${basic_type.label} property to mongoose type`, function () {
|
|
88
88
|
let zodSchema = z.object({ test_value: z.object({test_value: basic_type.zod_function() }) })
|
|
89
89
|
let mongooseSchema = schema_from_zod(zodSchema)
|
|
90
|
-
assert.deepEqual({ test_value: { mongoose_type: {test_value: { mongoose_type: basic_type.mongoose_type, required: true }}, required: true} }, mongooseSchema)
|
|
90
|
+
assert.deepEqual({ test_value: { mongoose_type: { _id: false, test_value: { mongoose_type: basic_type.mongoose_type, required: true }}, required: true} }, mongooseSchema)
|
|
91
91
|
});
|
|
92
92
|
|
|
93
93
|
it(`should convert a nested object containing a ${basic_type.label} property to mongoose type with optional`, function () {
|
|
94
94
|
let zodSchema = z.object({ test_value: z.object({test_value: basic_type.zod_function().optional() }) })
|
|
95
95
|
let mongooseSchema = schema_from_zod(zodSchema)
|
|
96
|
-
assert.deepEqual({ test_value: { mongoose_type: {test_value: { mongoose_type: basic_type.mongoose_type, required: false }}, required: true } }, mongooseSchema)
|
|
96
|
+
assert.deepEqual({ test_value: { mongoose_type: {_id: false, test_value: { mongoose_type: basic_type.mongoose_type, required: false }}, required: true } }, mongooseSchema)
|
|
97
97
|
});
|
|
98
98
|
|
|
99
99
|
it(`should convert a nested object containing a ${basic_type.label} property to mongoose type with default values`, function () {
|
|
100
100
|
//@ts-ignore
|
|
101
101
|
let zodSchema = z.object({ test_value: z.object({test_value: basic_type.zod_function().default(basic_type.default_val) }) })
|
|
102
102
|
let mongooseSchema = schema_from_zod(zodSchema)
|
|
103
|
-
assert.deepEqual({ test_value: { mongoose_type: {test_value: {
|
|
103
|
+
assert.deepEqual({ test_value: { mongoose_type: {_id: false, test_value: { mongoose_type: basic_type.mongoose_type, required: true, default: basic_type.default_val }}, required: true } }, mongooseSchema)
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it(`should convert a nested object containing a ${basic_type.label} property to mongoose type while allowing for auto-ID`, function () {
|
|
107
|
+
let zodSchema = z.object({ test_value: z.object({_id: z_mongodb_id_optional, test_value: basic_type.zod_function() }) })
|
|
108
|
+
let mongooseSchema = schema_from_zod(zodSchema)
|
|
109
|
+
assert.deepEqual({ test_value: { mongoose_type: {test_value: { mongoose_type: basic_type.mongoose_type, required: true }}, required: true} }, mongooseSchema)
|
|
104
110
|
});
|
|
105
111
|
}
|
|
106
112
|
|
|
@@ -268,14 +274,14 @@ describe('Mongoose from Zod', function () {
|
|
|
268
274
|
c: z.object({
|
|
269
275
|
name: z.string()
|
|
270
276
|
}),
|
|
271
|
-
})
|
|
272
|
-
let mongooseSchema = schema_from_zod(zodSchema)
|
|
277
|
+
});
|
|
278
|
+
let mongooseSchema = schema_from_zod(zodSchema);
|
|
273
279
|
|
|
274
280
|
assert.deepEqual({
|
|
275
|
-
a: { mongoose_type: { name: { mongoose_type: String, required: true } }, required: true },
|
|
276
|
-
b: { mongoose_type: { name: { mongoose_type: String, required: true } }, required: true },
|
|
277
|
-
c: { mongoose_type: { name: { mongoose_type: String, required: true } }, required: true },
|
|
278
|
-
}, mongooseSchema)
|
|
281
|
+
a: { mongoose_type: { _id: false, name: { mongoose_type: String, required: true } }, required: true },
|
|
282
|
+
b: { mongoose_type: { _id: false, name: { mongoose_type: String, required: true } }, required: true },
|
|
283
|
+
c: { mongoose_type: { _id: false, name: { mongoose_type: String, required: true } }, required: true },
|
|
284
|
+
}, mongooseSchema);
|
|
279
285
|
})
|
|
280
286
|
|
|
281
287
|
/*
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import assert from "assert";
|
|
2
|
+
import { z, ZodBoolean, ZodDate, ZodNumber, ZodString } from 'zod'
|
|
3
|
+
|
|
4
|
+
import { array_children_from_zod } from '../dist/utils/array_children_from_zod.js';
|
|
5
|
+
import mongoose, { Schema } from 'mongoose'
|
|
6
|
+
import { required } from "zod/mini";
|
|
7
|
+
import { z_mongodb_id } from "../dist/utils/mongoose_from_zod.js";
|
|
8
|
+
|
|
9
|
+
process.env.DEBUG = 'express:*'
|
|
10
|
+
|
|
11
|
+
describe('Mongoose from Zod', function () {
|
|
12
|
+
it('should detect no loops in an empty object', function () {
|
|
13
|
+
let zodSchema = z.object({ })
|
|
14
|
+
let array_children = array_children_from_zod(zodSchema);
|
|
15
|
+
assert.equal(array_children.size, 0)
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('should detect an array child if one exists', function () {
|
|
19
|
+
let zodSchema = z.object({
|
|
20
|
+
val: z.array(z.object({
|
|
21
|
+
_id: z_mongodb_id,
|
|
22
|
+
test: z.string()
|
|
23
|
+
}))
|
|
24
|
+
})
|
|
25
|
+
let array_children = array_children_from_zod(zodSchema);
|
|
26
|
+
assert.equal(array_children.size, 1)
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('should detect multiple array children if they exist', function () {
|
|
30
|
+
|
|
31
|
+
let zodSchema = z.object({
|
|
32
|
+
val: z.array(z.object({
|
|
33
|
+
_id: z_mongodb_id,
|
|
34
|
+
test: z.string()
|
|
35
|
+
})),
|
|
36
|
+
other_val: z.array(z.object({
|
|
37
|
+
_id: z_mongodb_id,
|
|
38
|
+
test: z.string()
|
|
39
|
+
}))
|
|
40
|
+
})
|
|
41
|
+
let array_children = array_children_from_zod(zodSchema);
|
|
42
|
+
assert.equal(array_children.size, 2)
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('should detect array children within nullable', function () {
|
|
46
|
+
let zodSchema = z.object({
|
|
47
|
+
val: z.nullable(z.array(z.object({
|
|
48
|
+
_id: z_mongodb_id,
|
|
49
|
+
test: z.string()
|
|
50
|
+
})))
|
|
51
|
+
})
|
|
52
|
+
let array_children = array_children_from_zod(zodSchema);
|
|
53
|
+
assert.equal(array_children.size, 1)
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it('should detect array children within optional', function () {
|
|
57
|
+
let zodSchema = z.object({
|
|
58
|
+
val: z.optional(z.array(z.object({
|
|
59
|
+
_id: z_mongodb_id,
|
|
60
|
+
test: z.string()
|
|
61
|
+
})))
|
|
62
|
+
})
|
|
63
|
+
let array_children = array_children_from_zod(zodSchema);
|
|
64
|
+
assert.equal(array_children.size, 1)
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('should detect array children nested within an object', function () {
|
|
68
|
+
let zodSchema = z.object({
|
|
69
|
+
alpha: z.object({
|
|
70
|
+
val: z.array(z.object({
|
|
71
|
+
_id: z_mongodb_id,
|
|
72
|
+
test: z.string()
|
|
73
|
+
}))
|
|
74
|
+
})
|
|
75
|
+
})
|
|
76
|
+
let array_children = array_children_from_zod(zodSchema);
|
|
77
|
+
assert.equal(array_children.size, 1)
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('should have correct array children and nested array children names', function () {
|
|
81
|
+
let zodSchema = z.object({
|
|
82
|
+
alpha: z.object({
|
|
83
|
+
val: z.array(z.object({
|
|
84
|
+
_id: z_mongodb_id,
|
|
85
|
+
test: z.string()
|
|
86
|
+
}))
|
|
87
|
+
}),
|
|
88
|
+
latex: z.array(z.object({
|
|
89
|
+
_id: z_mongodb_id,
|
|
90
|
+
test: z.string()
|
|
91
|
+
}))
|
|
92
|
+
})
|
|
93
|
+
let array_children = array_children_from_zod(zodSchema);
|
|
94
|
+
assert.equal(Array.from(array_children.keys()).includes('alpha.val'), true);
|
|
95
|
+
assert.equal(Array.from(array_children.keys()).includes('latex'), true);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it('should return the validator for a child', function () {
|
|
99
|
+
let zodSchema = z.object({
|
|
100
|
+
val: z.array(z.object({
|
|
101
|
+
_id: z_mongodb_id,
|
|
102
|
+
test: z.string()
|
|
103
|
+
}))
|
|
104
|
+
})
|
|
105
|
+
let array_children = array_children_from_zod(zodSchema);
|
|
106
|
+
let objectid = new mongoose.Types.ObjectId()
|
|
107
|
+
assert.deepEqual(array_children.get('val')?.parse({_id: '' + objectid, test: 'testval'}), {_id: '' + objectid, test: 'testval'})
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
it('should only detect array children that have an _id field', function () {
|
|
112
|
+
let zodSchema = z.object({
|
|
113
|
+
alpha: z.object({
|
|
114
|
+
val: z.array(z.object({
|
|
115
|
+
_id: z_mongodb_id,
|
|
116
|
+
test: z.string()
|
|
117
|
+
}))
|
|
118
|
+
}),
|
|
119
|
+
latex: z.array(z.object({
|
|
120
|
+
test: z.string()
|
|
121
|
+
}))
|
|
122
|
+
})
|
|
123
|
+
let array_children = array_children_from_zod(zodSchema);
|
|
124
|
+
assert.equal(Array.from(array_children.keys()).includes('alpha.val'), true);
|
|
125
|
+
assert.equal(Array.from(array_children.keys()).includes('latex'), false);
|
|
126
|
+
});
|
|
127
|
+
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
|
|
2
2
|
import assert from "assert";
|
|
3
3
|
|
|
4
|
-
import { z_mongodb_id } from '../dist/utils/mongoose_from_zod.js';
|
|
4
|
+
import { z_mongodb_id, z_mongodb_id_optional } from '../dist/utils/mongoose_from_zod.js';
|
|
5
5
|
import { F_Collection } from '../dist/f_collection.js';
|
|
6
6
|
import { F_Collection_Registry } from '../dist/F_Collection_Registry.js'
|
|
7
7
|
import { F_SM_Open_Access } from '../dist/F_Security_Models/F_SM_Open_Access.js'
|
|
@@ -41,10 +41,20 @@ describe('Basic Server', function () {
|
|
|
41
41
|
client_id: z_mongodb_id,
|
|
42
42
|
name: z.string(),
|
|
43
43
|
});
|
|
44
|
+
const validate_list_container = z.object({
|
|
45
|
+
_id: z_mongodb_id,
|
|
46
|
+
container: z.object({
|
|
47
|
+
list: z.array(z.object({
|
|
48
|
+
_id: z_mongodb_id_optional,
|
|
49
|
+
value: z.string()
|
|
50
|
+
}))
|
|
51
|
+
})
|
|
52
|
+
});
|
|
44
53
|
|
|
45
54
|
let institution: F_Collection<'institution', typeof validate_institution>;
|
|
46
55
|
let client: F_Collection<'client', typeof validate_client>;
|
|
47
56
|
let project: F_Collection<'project', typeof validate_project>;
|
|
57
|
+
let list_container: F_Collection<'list_container', typeof validate_list_container>;
|
|
48
58
|
|
|
49
59
|
let registry: F_Collection_Registry;
|
|
50
60
|
|
|
@@ -67,9 +77,12 @@ describe('Basic Server', function () {
|
|
|
67
77
|
project = new F_Collection('project', 'projects', validate_project);
|
|
68
78
|
project.add_layers([institution.collection_id, client.collection_id], [new F_SM_Open_Access(project)]);
|
|
69
79
|
|
|
80
|
+
list_container = new F_Collection('list_container', 'list_containers', validate_list_container);
|
|
81
|
+
list_container.add_layers([], [new F_SM_Open_Access(list_container)]);
|
|
82
|
+
|
|
70
83
|
// build registry
|
|
71
84
|
let proto_registry = new F_Collection_Registry();
|
|
72
|
-
registry = proto_registry.register(institution).register(client).register(project);
|
|
85
|
+
registry = proto_registry.register(institution).register(client).register(project).register(list_container);
|
|
73
86
|
registry.compile(express_app, '/api');
|
|
74
87
|
|
|
75
88
|
server = express_app.listen(port);
|
|
@@ -563,6 +576,40 @@ describe('Basic Server', function () {
|
|
|
563
576
|
});
|
|
564
577
|
});
|
|
565
578
|
|
|
579
|
+
it(`should reject a PUT operation that changes the document id`, async function () {
|
|
580
|
+
let test_institution = await institution.mongoose_model.create({
|
|
581
|
+
name: 'Spandex Co'
|
|
582
|
+
});
|
|
583
|
+
|
|
584
|
+
let test_client = await client.mongoose_model.create({
|
|
585
|
+
institution_id: test_institution._id,
|
|
586
|
+
name: `Bob's spandex house`
|
|
587
|
+
})
|
|
588
|
+
|
|
589
|
+
let test_project = await project.mongoose_model.create({
|
|
590
|
+
institution_id: test_institution._id,
|
|
591
|
+
client_id: test_client._id,
|
|
592
|
+
name: `Spandex Reincarnation`
|
|
593
|
+
})
|
|
594
|
+
|
|
595
|
+
let test_project_2 = await project.mongoose_model.create({
|
|
596
|
+
institution_id: test_institution._id,
|
|
597
|
+
client_id: test_client._id,
|
|
598
|
+
name: `Olfactory Hurricane`
|
|
599
|
+
})
|
|
600
|
+
|
|
601
|
+
await assert.rejects(async () => {
|
|
602
|
+
let results = await got.put(`http://localhost:${port}/api/institution/${test_institution._id}/client/${test_client._id}/project/${test_project._id}`, {
|
|
603
|
+
json: {
|
|
604
|
+
_id: test_project_2._id,
|
|
605
|
+
name: `Leather Pants Transubstantiation`,
|
|
606
|
+
},
|
|
607
|
+
}).json();
|
|
608
|
+
}, {
|
|
609
|
+
message: 'Response code 400 (Bad Request)'
|
|
610
|
+
});
|
|
611
|
+
});
|
|
612
|
+
|
|
566
613
|
it(`should reject a PUT operation with a malicious key in the body`, async function () {
|
|
567
614
|
let test_institution = await institution.mongoose_model.create({
|
|
568
615
|
name: 'Spandex Co'
|
|
@@ -769,4 +816,62 @@ describe('Basic Server', function () {
|
|
|
769
816
|
assert.deepEqual(null, results.data);
|
|
770
817
|
assert.deepEqual(JSON.parse(JSON.stringify(await project.mongoose_model.findById(test_project._id))), JSON.parse(JSON.stringify(test_project)));
|
|
771
818
|
});
|
|
819
|
+
|
|
820
|
+
it(`should allow entries to be added to object arrays`, async function () {
|
|
821
|
+
let test_list_container = await list_container.mongoose_model.create({
|
|
822
|
+
container: {
|
|
823
|
+
list: []
|
|
824
|
+
}
|
|
825
|
+
});
|
|
826
|
+
|
|
827
|
+
let results = await got.post(`http://localhost:${port}/api/list_container/${test_list_container._id}/container.list`, {
|
|
828
|
+
json: {
|
|
829
|
+
value: 'test value'
|
|
830
|
+
}
|
|
831
|
+
}).json();
|
|
832
|
+
|
|
833
|
+
//@ts-ignore
|
|
834
|
+
assert.deepEqual('test value', results.data.container.list[0].value);
|
|
835
|
+
//@ts-ignore
|
|
836
|
+
assert.deepEqual(JSON.parse(JSON.stringify(await list_container.mongoose_model.findById(test_list_container._id))), JSON.parse(JSON.stringify(results.data)));
|
|
837
|
+
});
|
|
838
|
+
|
|
839
|
+
it(`should allow object array entries to be updated`, async function () {
|
|
840
|
+
let test_list_container = await list_container.mongoose_model.create({
|
|
841
|
+
container: {
|
|
842
|
+
list: [{
|
|
843
|
+
value: 'original value'
|
|
844
|
+
}]
|
|
845
|
+
}
|
|
846
|
+
});
|
|
847
|
+
|
|
848
|
+
let results = await got.put(`http://localhost:${port}/api/list_container/${test_list_container._id}/container.list/${test_list_container.container.list[0]._id}`, {
|
|
849
|
+
json: {
|
|
850
|
+
value: 'updated value'
|
|
851
|
+
}
|
|
852
|
+
}).json();
|
|
853
|
+
|
|
854
|
+
//@ts-ignore
|
|
855
|
+
assert.deepEqual('updated value', results.data.container.list[0].value);
|
|
856
|
+
//@ts-ignore
|
|
857
|
+
assert.deepEqual(JSON.parse(JSON.stringify(await list_container.mongoose_model.findById(test_list_container._id))), JSON.parse(JSON.stringify(results.data)));
|
|
858
|
+
});
|
|
859
|
+
|
|
860
|
+
it(`should allow object array entries to be deleted`, async function () {
|
|
861
|
+
let test_list_container = await list_container.mongoose_model.create({
|
|
862
|
+
container: {
|
|
863
|
+
list: [{
|
|
864
|
+
value: 'original value'
|
|
865
|
+
}]
|
|
866
|
+
}
|
|
867
|
+
});
|
|
868
|
+
|
|
869
|
+
let results = await got.delete(`http://localhost:${port}/api/list_container/${test_list_container._id}/container.list/${test_list_container.container.list[0]._id}`).json();
|
|
870
|
+
|
|
871
|
+
//@ts-ignore
|
|
872
|
+
assert.deepEqual(0, results.data.container.list.length);
|
|
873
|
+
//@ts-ignore
|
|
874
|
+
assert.deepEqual(JSON.parse(JSON.stringify(await list_container.mongoose_model.findById(test_list_container._id))), JSON.parse(JSON.stringify(results.data)));
|
|
875
|
+
});
|
|
876
|
+
|
|
772
877
|
});
|