@ditojs/server 2.0.5 → 2.1.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.
- package/package.json +11 -13
- package/src/app/Application.js +226 -179
- package/src/app/Validator.js +53 -43
- package/src/cli/console.js +6 -4
- package/src/cli/db/createMigration.js +59 -30
- package/src/cli/db/migrate.js +6 -4
- package/src/cli/db/reset.js +8 -5
- package/src/cli/db/rollback.js +6 -4
- package/src/cli/db/seed.js +2 -1
- package/src/cli/index.js +1 -1
- package/src/controllers/AdminController.js +98 -84
- package/src/controllers/CollectionController.js +37 -30
- package/src/controllers/Controller.js +83 -43
- package/src/controllers/ControllerAction.js +27 -15
- package/src/controllers/ModelController.js +4 -1
- package/src/controllers/RelationController.js +19 -21
- package/src/controllers/UsersController.js +3 -4
- package/src/decorators/parameters.js +3 -1
- package/src/decorators/scope.js +1 -1
- package/src/errors/ControllerError.js +2 -1
- package/src/errors/DatabaseError.js +20 -11
- package/src/graph/DitoGraphProcessor.js +48 -40
- package/src/graph/expression.js +6 -8
- package/src/graph/graph.js +20 -11
- package/src/lib/EventEmitter.js +12 -12
- package/src/middleware/handleConnectMiddleware.js +16 -10
- package/src/middleware/handleError.js +6 -5
- package/src/middleware/handleSession.js +33 -29
- package/src/middleware/handleUser.js +2 -2
- package/src/middleware/index.js +1 -0
- package/src/middleware/logRequests.js +3 -3
- package/src/middleware/setupRequestStorage.js +14 -0
- package/src/mixins/AssetMixin.js +62 -58
- package/src/mixins/SessionMixin.js +13 -10
- package/src/mixins/TimeStampedMixin.js +33 -29
- package/src/mixins/UserMixin.js +130 -116
- package/src/models/Model.js +245 -194
- package/src/models/definitions/filters.js +14 -13
- package/src/query/QueryBuilder.js +252 -195
- package/src/query/QueryFilters.js +3 -3
- package/src/query/QueryParameters.js +2 -2
- package/src/query/Registry.js +8 -10
- package/src/schema/keywords/_validate.js +10 -8
- package/src/schema/properties.test.js +247 -206
- package/src/schema/relations.js +42 -20
- package/src/schema/relations.test.js +36 -19
- package/src/services/Service.js +8 -14
- package/src/storage/S3Storage.js +5 -3
- package/src/storage/Storage.js +16 -14
- package/src/utils/function.js +7 -4
- package/src/utils/function.test.js +30 -6
- package/src/utils/object.test.js +5 -1
- package/types/index.d.ts +244 -257
|
@@ -55,7 +55,9 @@ export class CollectionController extends Controller {
|
|
|
55
55
|
// @override
|
|
56
56
|
getPath(type, path) {
|
|
57
57
|
return type === 'member'
|
|
58
|
-
? path
|
|
58
|
+
? path
|
|
59
|
+
? `:${this.idParam}/${path}`
|
|
60
|
+
: `:${this.idParam}`
|
|
59
61
|
: path
|
|
60
62
|
}
|
|
61
63
|
|
|
@@ -91,9 +93,11 @@ export class CollectionController extends Controller {
|
|
|
91
93
|
// Returns the model ids that this request concerns, read from the param
|
|
92
94
|
// for member ids, and from the payload for collection ids:
|
|
93
95
|
const { type } = ctx.action
|
|
94
|
-
return type === 'member'
|
|
95
|
-
|
|
96
|
-
:
|
|
96
|
+
return type === 'member'
|
|
97
|
+
? [this.getMemberId(ctx)]
|
|
98
|
+
: type === 'collection'
|
|
99
|
+
? this.getCollectionIds(ctx)
|
|
100
|
+
: []
|
|
97
101
|
}
|
|
98
102
|
|
|
99
103
|
validateId(id) {
|
|
@@ -142,7 +146,7 @@ export class CollectionController extends Controller {
|
|
|
142
146
|
const { scope } = base
|
|
143
147
|
const { allowScope, allowFilter } = this
|
|
144
148
|
|
|
145
|
-
const asAllowArray = value => value === false ? [] : asArray(value)
|
|
149
|
+
const asAllowArray = value => (value === false ? [] : asArray(value))
|
|
146
150
|
|
|
147
151
|
if (allowScope !== undefined && allowScope !== true) {
|
|
148
152
|
query.allowScope(
|
|
@@ -168,8 +172,7 @@ export class CollectionController extends Controller {
|
|
|
168
172
|
async executeAndFetch(action, ctx, modify, body = ctx.request.body) {
|
|
169
173
|
const name = `${action}${this.graph ? 'DitoGraph' : ''}AndFetch`
|
|
170
174
|
return this.execute(ctx, (query, trx) =>
|
|
171
|
-
query[name](body)
|
|
172
|
-
.modify(getModify(modify, trx))
|
|
175
|
+
query[name](body).modify(getModify(modify, trx))
|
|
173
176
|
)
|
|
174
177
|
}
|
|
175
178
|
|
|
@@ -207,23 +210,25 @@ export class CollectionController extends Controller {
|
|
|
207
210
|
},
|
|
208
211
|
|
|
209
212
|
async delete(ctx, modify) {
|
|
210
|
-
const count = await this.execute(ctx, (query, trx) =>
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
213
|
+
const count = await this.execute(ctx, (query, trx) =>
|
|
214
|
+
query
|
|
215
|
+
.ignoreScope()
|
|
216
|
+
.find(ctx.query, this.allowParam)
|
|
217
|
+
.modify(query => this.isOneToOne && query.throwIfNotFound())
|
|
218
|
+
.modify(getModify(modify, trx))
|
|
219
|
+
.modify(query => (this.unrelate ? query.unrelate() : query.delete()))
|
|
216
220
|
)
|
|
217
221
|
return { count }
|
|
218
222
|
},
|
|
219
223
|
|
|
220
224
|
async post(ctx, modify) {
|
|
221
225
|
const result = this.relate
|
|
222
|
-
// Use patchDitoGraphAndFetch() to handle relates for us.
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
226
|
+
? // Use patchDitoGraphAndFetch() to handle relates for us.
|
|
227
|
+
await this.execute(ctx, (query, trx) =>
|
|
228
|
+
query
|
|
229
|
+
.patchDitoGraphAndFetch(ctx.request.body, { relate: true })
|
|
230
|
+
.modify(getModify(modify, trx))
|
|
231
|
+
)
|
|
227
232
|
: await this.executeAndFetch('insert', ctx, modify)
|
|
228
233
|
ctx.status = 201 // Created
|
|
229
234
|
if (isObject(result)) {
|
|
@@ -243,22 +248,24 @@ export class CollectionController extends Controller {
|
|
|
243
248
|
|
|
244
249
|
member = this.convertToCoreActions({
|
|
245
250
|
async get(ctx, modify) {
|
|
246
|
-
return this.execute(ctx, (query, trx) =>
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
+
return this.execute(ctx, (query, trx) =>
|
|
252
|
+
query
|
|
253
|
+
.findById(ctx.memberId)
|
|
254
|
+
.find(ctx.query, this.allowParam)
|
|
255
|
+
.throwIfNotFound()
|
|
256
|
+
.modify(getModify(modify, trx))
|
|
251
257
|
)
|
|
252
258
|
},
|
|
253
259
|
|
|
254
260
|
async delete(ctx, modify) {
|
|
255
|
-
const count = await this.execute(ctx, (query, trx) =>
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
261
|
+
const count = await this.execute(ctx, (query, trx) =>
|
|
262
|
+
query
|
|
263
|
+
.ignoreScope()
|
|
264
|
+
.findById(ctx.memberId)
|
|
265
|
+
.find(ctx.query, this.allowParam)
|
|
266
|
+
.throwIfNotFound()
|
|
267
|
+
.modify(getModify(modify, trx))
|
|
268
|
+
.modify(query => (this.unrelate ? query.unrelate() : query.delete()))
|
|
262
269
|
)
|
|
263
270
|
return { count }
|
|
264
271
|
},
|
|
@@ -3,18 +3,30 @@ import { EventEmitter } from '../lib/index.js'
|
|
|
3
3
|
import ControllerAction from './ControllerAction.js'
|
|
4
4
|
import MemberAction from './MemberAction.js'
|
|
5
5
|
import {
|
|
6
|
-
ResponseError,
|
|
6
|
+
ResponseError,
|
|
7
|
+
ControllerError,
|
|
8
|
+
AuthorizationError
|
|
7
9
|
} from '../errors/index.js'
|
|
8
10
|
import {
|
|
9
|
-
getOwnProperty,
|
|
11
|
+
getOwnProperty,
|
|
12
|
+
getOwnKeys,
|
|
13
|
+
getAllKeys,
|
|
14
|
+
getInheritanceChain
|
|
10
15
|
} from '../utils/object.js'
|
|
11
16
|
import { processHandlerParameters } from '../utils/handler.js'
|
|
12
17
|
import { describeFunction } from '../utils/function.js'
|
|
13
18
|
import { formatJson } from '../utils/json.js'
|
|
14
19
|
import { deprecate } from '../utils/deprecate.js'
|
|
15
20
|
import {
|
|
16
|
-
isObject,
|
|
17
|
-
|
|
21
|
+
isObject,
|
|
22
|
+
isString,
|
|
23
|
+
isArray,
|
|
24
|
+
isBoolean,
|
|
25
|
+
isFunction,
|
|
26
|
+
asArray,
|
|
27
|
+
equals,
|
|
28
|
+
parseDataPath,
|
|
29
|
+
normalizeDataPath
|
|
18
30
|
} from '@ditojs/utils'
|
|
19
31
|
|
|
20
32
|
export class Controller {
|
|
@@ -42,10 +54,14 @@ export class Controller {
|
|
|
42
54
|
// the callbacks from base classes are also run. And reverse the chain so
|
|
43
55
|
// that the base class callbacks are run first.
|
|
44
56
|
const chain = getInheritanceChain(hooks).reverse()
|
|
57
|
+
const keys = Object.keys(Object.assign({}, hooks, ...chain))
|
|
45
58
|
const events = Object.fromEntries(
|
|
46
|
-
|
|
47
|
-
event
|
|
48
|
-
|
|
59
|
+
keys.map(event => [
|
|
60
|
+
event,
|
|
61
|
+
chain
|
|
62
|
+
.map(hooks => (hooks.hasOwnProperty(event) ? hooks[event] : null))
|
|
63
|
+
.filter(Boolean)
|
|
64
|
+
])
|
|
49
65
|
)
|
|
50
66
|
this._configureEmitter(events, {
|
|
51
67
|
// Support wildcard hooks only on controllers:
|
|
@@ -174,7 +190,11 @@ export class Controller {
|
|
|
174
190
|
// Replace the action object with the converted action handler, so they
|
|
175
191
|
// too can benefit from prototypal inheritance:
|
|
176
192
|
actions[name] = this.setupAction(
|
|
177
|
-
type,
|
|
193
|
+
type,
|
|
194
|
+
actions,
|
|
195
|
+
name,
|
|
196
|
+
action,
|
|
197
|
+
authorize[name]
|
|
178
198
|
)
|
|
179
199
|
}
|
|
180
200
|
// Expose a direct reference to the controller on the action object, but
|
|
@@ -190,9 +210,11 @@ export class Controller {
|
|
|
190
210
|
}
|
|
191
211
|
|
|
192
212
|
setupAction(type, actions, name, action, authorize) {
|
|
193
|
-
const handler = isFunction(action)
|
|
194
|
-
|
|
195
|
-
:
|
|
213
|
+
const handler = isFunction(action)
|
|
214
|
+
? action
|
|
215
|
+
: isObject(action)
|
|
216
|
+
? convertActionObject(name, action, actions)
|
|
217
|
+
: null
|
|
196
218
|
// Action naming convention: `'<method> <path>'`, or just `'<method>'` for
|
|
197
219
|
// the default methods.
|
|
198
220
|
let [method, path = ''] = name.split(' ')
|
|
@@ -206,7 +228,14 @@ export class Controller {
|
|
|
206
228
|
type,
|
|
207
229
|
// eslint-disable-next-line new-cap
|
|
208
230
|
new actionClass(
|
|
209
|
-
this,
|
|
231
|
+
this,
|
|
232
|
+
actions,
|
|
233
|
+
handler,
|
|
234
|
+
type,
|
|
235
|
+
name,
|
|
236
|
+
method,
|
|
237
|
+
path,
|
|
238
|
+
authorize
|
|
210
239
|
)
|
|
211
240
|
)
|
|
212
241
|
return handler
|
|
@@ -249,7 +278,8 @@ export class Controller {
|
|
|
249
278
|
} = config
|
|
250
279
|
const storage = this.app.getStorage(storageName)
|
|
251
280
|
if (!storage) {
|
|
252
|
-
throw new ControllerError(
|
|
281
|
+
throw new ControllerError(
|
|
282
|
+
this,
|
|
253
283
|
`Unknown storage configuration: '${storageName}'`
|
|
254
284
|
)
|
|
255
285
|
}
|
|
@@ -258,9 +288,10 @@ export class Controller {
|
|
|
258
288
|
|
|
259
289
|
const normalizedPath = getDataPath(
|
|
260
290
|
// Router supports both shallow & deep wildcards, no normalization needed.
|
|
261
|
-
token =>
|
|
262
|
-
|
|
263
|
-
|
|
291
|
+
token =>
|
|
292
|
+
token === '*' || token === '**'
|
|
293
|
+
? token
|
|
294
|
+
: this.app.normalizePath(token)
|
|
264
295
|
)
|
|
265
296
|
|
|
266
297
|
// Convert `dataPath` to a regular expression to match field names
|
|
@@ -270,11 +301,12 @@ export class Controller {
|
|
|
270
301
|
`^${
|
|
271
302
|
getDataPath(
|
|
272
303
|
// Use the exact same regexps as in `Router`:
|
|
273
|
-
token =>
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
304
|
+
token =>
|
|
305
|
+
token === '*'
|
|
306
|
+
? '[^/]+' // shallow wildcard
|
|
307
|
+
: token === '**'
|
|
308
|
+
? '.+?' // deep wildcard
|
|
309
|
+
: token
|
|
278
310
|
)
|
|
279
311
|
}$`
|
|
280
312
|
)
|
|
@@ -525,17 +557,17 @@ export class Controller {
|
|
|
525
557
|
member = await this.getMember(ctx)
|
|
526
558
|
}
|
|
527
559
|
return !!values.find(
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
560
|
+
// Support 3 scenarios:
|
|
561
|
+
// - '$self': The requested member is checked against `ctx.state.user`
|
|
562
|
+
// and the action is only authorized if it matches the member.
|
|
563
|
+
// - '$owner': The member is asked if it is owned by `ctx.state.user`
|
|
564
|
+
// through the optional `Model.$hasOwner()` method.
|
|
565
|
+
// - any string: `ctx.state.user` is checked for this role through
|
|
566
|
+
// the overridable `UserModel.hasRole()` method.
|
|
535
567
|
value => {
|
|
536
568
|
return value === '$self'
|
|
537
569
|
? user.constructor === this.modelClass &&
|
|
538
|
-
|
|
570
|
+
equals(user.$id(), ctx.memberId)
|
|
539
571
|
: value === '$owner'
|
|
540
572
|
? member?.$hasOwner?.(user)
|
|
541
573
|
: user.$hasRole(value)
|
|
@@ -543,7 +575,8 @@ export class Controller {
|
|
|
543
575
|
)
|
|
544
576
|
}
|
|
545
577
|
} else {
|
|
546
|
-
throw new ControllerError(
|
|
578
|
+
throw new ControllerError(
|
|
579
|
+
this,
|
|
547
580
|
`Unsupported authorize setting: '${authorize}'`
|
|
548
581
|
)
|
|
549
582
|
}
|
|
@@ -588,14 +621,18 @@ function convertActionObject(name, object, actions) {
|
|
|
588
621
|
Object.setPrototypeOf(object, Object.getPrototypeOf(actions))
|
|
589
622
|
|
|
590
623
|
if (action) {
|
|
591
|
-
deprecate(
|
|
624
|
+
deprecate(
|
|
625
|
+
`action.action is deprecated. Use action.method and action.path instead.`
|
|
626
|
+
)
|
|
592
627
|
const [method, path] = asArray(action)
|
|
593
628
|
handler.method = method
|
|
594
629
|
handler.path = path
|
|
595
630
|
}
|
|
596
631
|
|
|
597
632
|
if (!handler) {
|
|
598
|
-
throw new Error(
|
|
633
|
+
throw new Error(
|
|
634
|
+
`Missing handler in '${name}' action: ${formatJson(object)}`
|
|
635
|
+
)
|
|
599
636
|
}
|
|
600
637
|
|
|
601
638
|
handler.authorize = authorize ?? null
|
|
@@ -609,15 +646,18 @@ function convertActionObject(name, object, actions) {
|
|
|
609
646
|
}
|
|
610
647
|
|
|
611
648
|
function isMethodAction(name) {
|
|
612
|
-
return
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
649
|
+
return (
|
|
650
|
+
{
|
|
651
|
+
get: true,
|
|
652
|
+
delete: true,
|
|
653
|
+
post: true,
|
|
654
|
+
put: true,
|
|
655
|
+
patch: true,
|
|
656
|
+
head: true,
|
|
657
|
+
options: true,
|
|
658
|
+
trace: true,
|
|
659
|
+
connect: true
|
|
660
|
+
}[name] ||
|
|
661
|
+
false
|
|
662
|
+
)
|
|
623
663
|
}
|
|
@@ -2,7 +2,14 @@ import { isString, isObject, asArray, clone } from '@ditojs/utils'
|
|
|
2
2
|
|
|
3
3
|
export default class ControllerAction {
|
|
4
4
|
constructor(
|
|
5
|
-
controller,
|
|
5
|
+
controller,
|
|
6
|
+
actions,
|
|
7
|
+
handler,
|
|
8
|
+
type,
|
|
9
|
+
name,
|
|
10
|
+
_method,
|
|
11
|
+
_path,
|
|
12
|
+
_authorize
|
|
6
13
|
) {
|
|
7
14
|
const {
|
|
8
15
|
core = false,
|
|
@@ -33,10 +40,12 @@ export default class ControllerAction {
|
|
|
33
40
|
this.authorize = authorize || _authorize
|
|
34
41
|
this.transacted = !!(
|
|
35
42
|
transacted ||
|
|
36
|
-
controller.transacted ||
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
43
|
+
controller.transacted ||
|
|
44
|
+
// Core graph and assets operations are always transacted, unless the
|
|
45
|
+
// method is 'get':
|
|
46
|
+
(
|
|
47
|
+
core &&
|
|
48
|
+
method !== 'get' && (
|
|
40
49
|
controller.graph ||
|
|
41
50
|
controller.assets
|
|
42
51
|
)
|
|
@@ -176,7 +185,7 @@ export default class ControllerAction {
|
|
|
176
185
|
}
|
|
177
186
|
}
|
|
178
187
|
|
|
179
|
-
const getData = () => unwrapRoot ? params[dataName] : params
|
|
188
|
+
const getData = () => (unwrapRoot ? params[dataName] : params)
|
|
180
189
|
try {
|
|
181
190
|
await this.parameters.validate(params)
|
|
182
191
|
return getData()
|
|
@@ -208,7 +217,7 @@ export default class ControllerAction {
|
|
|
208
217
|
|
|
209
218
|
// If a named result is defined, return the data wrapped,
|
|
210
219
|
// otherwise return the original unwrapped result object.
|
|
211
|
-
const getResult = () => returnsName ? data : result
|
|
220
|
+
const getResult = () => (returnsName ? data : result)
|
|
212
221
|
try {
|
|
213
222
|
await this.returns.validate(data)
|
|
214
223
|
return getResult()
|
|
@@ -279,14 +288,17 @@ export default class ControllerAction {
|
|
|
279
288
|
} else {
|
|
280
289
|
// A simple version of named key/value pairs, values can be
|
|
281
290
|
// strings or numbers.
|
|
282
|
-
value = Object.fromEntries(
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
291
|
+
value = Object.fromEntries(
|
|
292
|
+
value.split(/\s*,\s*/g).map(entry => {
|
|
293
|
+
let [key, val] = entry.split(/\s*:\s*/)
|
|
294
|
+
try {
|
|
295
|
+
// Try parsing basic types, but fall back to unquoted
|
|
296
|
+
// string.
|
|
297
|
+
val = JSON.parse(val)
|
|
298
|
+
} catch {}
|
|
299
|
+
return [key, val]
|
|
300
|
+
})
|
|
301
|
+
)
|
|
290
302
|
}
|
|
291
303
|
} else {
|
|
292
304
|
value = JSON.parse(value)
|
|
@@ -41,7 +41,10 @@ export class ModelController extends CollectionController {
|
|
|
41
41
|
throw new ControllerError(this, `Relation '${name}' not found.`)
|
|
42
42
|
}
|
|
43
43
|
const relation = new RelationController(
|
|
44
|
-
this,
|
|
44
|
+
this,
|
|
45
|
+
object,
|
|
46
|
+
relationInstance,
|
|
47
|
+
relationDefinition
|
|
45
48
|
)
|
|
46
49
|
// RelationController instances are not registered with the app, but are
|
|
47
50
|
// managed by their parent controller instead.
|
|
@@ -9,8 +9,10 @@ export class RelationController extends CollectionController {
|
|
|
9
9
|
constructor(parent, object, relationInstance, relationDefinition) {
|
|
10
10
|
super(parent.app, null)
|
|
11
11
|
if (parent.modelClass !== relationInstance.ownerModelClass) {
|
|
12
|
-
throw new ControllerError(
|
|
13
|
-
|
|
12
|
+
throw new ControllerError(
|
|
13
|
+
parent,
|
|
14
|
+
`Invalid parent controller for relation '${relationInstance.name}'.`
|
|
15
|
+
)
|
|
14
16
|
}
|
|
15
17
|
this.parent = parent
|
|
16
18
|
this.object = object
|
|
@@ -81,26 +83,22 @@ export class RelationController extends CollectionController {
|
|
|
81
83
|
// @override
|
|
82
84
|
async execute(ctx, execute) {
|
|
83
85
|
const id = this.parent.getMemberId(ctx)
|
|
84
|
-
return this.parent.execute(ctx,
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
}
|
|
98
|
-
)
|
|
86
|
+
return this.parent.execute(ctx, async (parentQuery, trx) => {
|
|
87
|
+
const model = await parentQuery
|
|
88
|
+
.ignoreScope()
|
|
89
|
+
.findById(id)
|
|
90
|
+
.throwIfNotFound()
|
|
91
|
+
// Explicitly only select the foreign key ids for more efficiency.
|
|
92
|
+
.select(...this.relationInstance.ownerProp.props)
|
|
93
|
+
// This is the same as `ModelController.execute()`, except for the use
|
|
94
|
+
// of `model.$relatedQuery()` instead of `modelClass.query()`:
|
|
95
|
+
const query = model.$relatedQuery(this.relationInstance.name, trx)
|
|
96
|
+
this.setupQuery(query)
|
|
97
|
+
return execute(query, trx)
|
|
98
|
+
})
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
-
collection = this.toCoreActions({
|
|
102
|
-
})
|
|
101
|
+
collection = this.toCoreActions({})
|
|
103
102
|
|
|
104
|
-
member = this.toCoreActions({
|
|
105
|
-
})
|
|
103
|
+
member = this.toCoreActions({})
|
|
106
104
|
}
|
|
@@ -40,16 +40,15 @@ export class UsersController extends ModelController {
|
|
|
40
40
|
return {
|
|
41
41
|
authenticated,
|
|
42
42
|
user: authenticated ? ctx.state.user : null
|
|
43
|
-
|
|
44
43
|
}
|
|
45
44
|
},
|
|
46
45
|
|
|
47
46
|
'get self'(ctx) {
|
|
48
47
|
return this.isAuthenticated(ctx)
|
|
49
48
|
? this.member.get.call(
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
49
|
+
this,
|
|
50
|
+
this.getContextWithMemberId(ctx, ctx.state.user.$id())
|
|
51
|
+
)
|
|
53
52
|
: null
|
|
54
53
|
}
|
|
55
54
|
}
|
|
@@ -16,7 +16,9 @@ export function parameters(parameters, options) {
|
|
|
16
16
|
}
|
|
17
17
|
}
|
|
18
18
|
if (!isArray(parameters) && !isObject(parameters)) {
|
|
19
|
-
throw new Error(
|
|
19
|
+
throw new Error(
|
|
20
|
+
`@parameters() need to be defined using array or object definitions`
|
|
21
|
+
)
|
|
20
22
|
}
|
|
21
23
|
|
|
22
24
|
return createDecorator(value => {
|
package/src/decorators/scope.js
CHANGED
|
@@ -3,7 +3,8 @@ import { ResponseError } from './ResponseError.js'
|
|
|
3
3
|
|
|
4
4
|
export class ControllerError extends ResponseError {
|
|
5
5
|
constructor(controller, error) {
|
|
6
|
-
const { name } = isFunction(controller)
|
|
6
|
+
const { name } = isFunction(controller)
|
|
7
|
+
? controller
|
|
7
8
|
: controller.constructor
|
|
8
9
|
super(`Controller ${name}: ${error}`, {
|
|
9
10
|
message: `Controller ${name}: Controller error`,
|
|
@@ -18,19 +18,28 @@ const {
|
|
|
18
18
|
|
|
19
19
|
export class DatabaseError extends ResponseError {
|
|
20
20
|
constructor(error, overrides) {
|
|
21
|
-
super(
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
21
|
+
super(
|
|
22
|
+
error,
|
|
23
|
+
{
|
|
24
|
+
type: error.constructor.name,
|
|
25
|
+
message: 'Database error',
|
|
26
|
+
status: getStatus(error)
|
|
27
|
+
},
|
|
28
|
+
overrides
|
|
29
|
+
)
|
|
26
30
|
}
|
|
27
31
|
}
|
|
28
32
|
|
|
29
33
|
function getStatus(error) {
|
|
30
|
-
return error instanceof CheckViolationError
|
|
31
|
-
|
|
32
|
-
: error instanceof
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
return error instanceof CheckViolationError
|
|
35
|
+
? 400
|
|
36
|
+
: error instanceof NotNullViolationError
|
|
37
|
+
? 400
|
|
38
|
+
: error instanceof ConstraintViolationError
|
|
39
|
+
? 409
|
|
40
|
+
: error instanceof DataError
|
|
41
|
+
? 400
|
|
42
|
+
: error instanceof DBError
|
|
43
|
+
? 500
|
|
44
|
+
: 400
|
|
36
45
|
}
|