@strapi/strapi 4.0.0-next.7 → 4.0.1
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/README.md +14 -14
- package/bin/strapi.js +46 -60
- package/lib/Strapi.js +193 -98
- package/lib/commands/build.js +19 -8
- package/lib/commands/console.js +1 -1
- package/lib/commands/content-types/list.js +22 -0
- package/lib/commands/controllers/list.js +22 -0
- package/lib/commands/develop.js +22 -27
- package/lib/commands/generate-template.js +4 -5
- package/lib/commands/hooks/list.js +22 -0
- package/lib/commands/middlewares/list.js +22 -0
- package/lib/commands/new.js +3 -1
- package/lib/commands/policies/list.js +22 -0
- package/lib/commands/routes/list.js +28 -0
- package/lib/commands/services/list.js +22 -0
- package/lib/commands/watchAdmin.js +18 -9
- package/lib/core/app-configuration/index.js +3 -36
- package/lib/core/bootstrap.js +25 -0
- package/lib/core/domain/content-type/index.js +26 -29
- package/lib/core/domain/content-type/validator.js +22 -3
- package/lib/core/domain/module/index.js +42 -11
- package/lib/core/domain/module/validation.js +16 -19
- package/lib/core/loaders/admin.js +16 -0
- package/lib/core/loaders/apis.js +159 -0
- package/lib/core/loaders/{load-components.js → components.js} +5 -6
- package/lib/core/loaders/index.js +11 -0
- package/lib/core/loaders/middlewares.js +36 -0
- package/lib/core/{load-plugins → loaders/plugins}/get-enabled-plugins.js +55 -19
- package/lib/core/loaders/plugins/get-user-plugins-config.js +37 -0
- package/lib/core/{load-plugins → loaders/plugins}/index.js +35 -19
- package/lib/core/loaders/policies.js +28 -0
- package/lib/core/loaders/src-index.js +39 -0
- package/lib/core/registries/apis.js +29 -0
- package/lib/core/registries/content-types.js +66 -10
- package/lib/core/registries/controllers.d.ts +7 -0
- package/lib/core/registries/controllers.js +92 -7
- package/lib/core/registries/hooks.d.ts +20 -0
- package/lib/core/registries/hooks.js +87 -0
- package/lib/core/registries/middlewares.d.ts +5 -0
- package/lib/core/registries/middlewares.js +65 -5
- package/lib/core/registries/modules.js +3 -3
- package/lib/core/registries/plugins.js +2 -2
- package/lib/core/registries/policies.d.ts +9 -0
- package/lib/core/registries/policies.js +65 -5
- package/lib/core/registries/services.d.ts +7 -0
- package/lib/core/registries/services.js +88 -17
- package/lib/core/utils.js +35 -0
- package/lib/core-api/controller/collection-type.js +45 -26
- package/lib/core-api/controller/index.d.ts +25 -0
- package/lib/core-api/controller/index.js +33 -11
- package/lib/core-api/controller/single-type.js +29 -15
- package/lib/core-api/controller/transform.js +62 -6
- package/lib/core-api/routes/index.js +71 -0
- package/lib/core-api/service/collection-type.js +43 -21
- package/lib/core-api/service/index.d.ts +21 -0
- package/lib/core-api/service/index.js +8 -67
- package/lib/core-api/service/pagination.js +125 -0
- package/lib/core-api/service/single-type.js +17 -19
- package/lib/factories.d.ts +48 -0
- package/lib/factories.js +84 -0
- package/lib/index.d.ts +10 -31
- package/lib/index.js +5 -1
- package/lib/middlewares/body.js +33 -0
- package/lib/middlewares/compression.js +8 -0
- package/lib/middlewares/cors.js +58 -0
- package/lib/middlewares/errors.js +40 -0
- package/lib/middlewares/favicon.js +19 -0
- package/lib/middlewares/index.d.ts +5 -0
- package/lib/middlewares/index.js +30 -116
- package/lib/middlewares/ip.js +8 -0
- package/lib/middlewares/logger.js +27 -0
- package/lib/middlewares/powered-by.js +20 -0
- package/lib/middlewares/public/index.js +72 -77
- package/lib/middlewares/query.js +46 -0
- package/lib/middlewares/response-time.js +15 -0
- package/lib/middlewares/responses.js +19 -0
- package/lib/middlewares/security.js +51 -0
- package/lib/middlewares/session/index.js +6 -6
- package/lib/migrations/draft-publish.js +57 -0
- package/lib/services/auth/index.js +87 -0
- package/lib/services/core-store.js +64 -51
- package/lib/services/cron.js +54 -0
- package/lib/services/entity-service/attributes/index.js +31 -0
- package/lib/services/entity-service/attributes/transforms.js +20 -0
- package/lib/services/entity-service/components.js +39 -15
- package/lib/services/entity-service/index.d.ts +91 -0
- package/lib/services/entity-service/index.js +120 -59
- package/lib/services/entity-service/params.js +52 -94
- package/lib/services/entity-validator/index.js +76 -43
- package/lib/services/entity-validator/validators.js +131 -43
- package/lib/services/errors.js +77 -0
- package/lib/{core → services}/fs.js +1 -1
- package/lib/services/metrics/index.js +38 -36
- package/lib/services/server/admin-api.js +14 -0
- package/lib/services/server/api.js +36 -0
- package/lib/services/server/compose-endpoint.js +141 -0
- package/lib/services/server/content-api.js +16 -0
- package/lib/{server.js → services/server/http-server.js} +0 -0
- package/lib/services/server/index.js +127 -0
- package/lib/services/server/koa.js +64 -0
- package/lib/services/server/middleware.js +122 -0
- package/lib/services/server/policy.js +32 -0
- package/lib/services/server/register-middlewares.js +110 -0
- package/lib/services/server/register-routes.js +106 -0
- package/lib/services/server/routing.js +120 -0
- package/lib/services/webhook-runner.js +1 -1
- package/lib/utils/ee.js +3 -3
- package/lib/utils/get-dirs.js +17 -0
- package/lib/utils/index.js +2 -0
- package/lib/utils/is-initialized.js +1 -1
- package/lib/utils/signals.js +24 -0
- package/lib/utils/startup-logger.js +2 -2
- package/lib/utils/update-notifier/index.js +3 -2
- package/package.json +94 -97
- package/lib/commands/generate.js +0 -76
- package/lib/core/loaders/bootstrap.js +0 -176
- package/lib/core/loaders/load-apis.js +0 -20
- package/lib/core/loaders/load-functions.js +0 -21
- package/lib/core/loaders/load-middlewares.js +0 -136
- package/lib/core/loaders/load-modules.js +0 -21
- package/lib/core/loaders/load-policies.js +0 -36
- package/lib/core/loaders/walk.js +0 -27
- package/lib/core-api/index.js +0 -39
- package/lib/load/check-reserved-filename.js +0 -10
- package/lib/load/load-config-files.js +0 -22
- package/lib/load/require-file-parse.js +0 -15
- package/lib/middlewares/boom/defaults.json +0 -5
- package/lib/middlewares/boom/index.js +0 -147
- package/lib/middlewares/cors/index.js +0 -66
- package/lib/middlewares/cron/defaults.json +0 -5
- package/lib/middlewares/cron/index.js +0 -43
- package/lib/middlewares/favicon/defaults.json +0 -7
- package/lib/middlewares/favicon/index.js +0 -32
- package/lib/middlewares/gzip/defaults.json +0 -6
- package/lib/middlewares/gzip/index.js +0 -19
- package/lib/middlewares/helmet/defaults.json +0 -18
- package/lib/middlewares/helmet/index.js +0 -9
- package/lib/middlewares/ip/defaults.json +0 -7
- package/lib/middlewares/ip/index.js +0 -25
- package/lib/middlewares/language/defaults.json +0 -9
- package/lib/middlewares/language/index.js +0 -40
- package/lib/middlewares/logger/defaults.json +0 -5
- package/lib/middlewares/logger/index.js +0 -37
- package/lib/middlewares/parser/defaults.json +0 -11
- package/lib/middlewares/parser/index.js +0 -71
- package/lib/middlewares/poweredBy/defaults.json +0 -5
- package/lib/middlewares/poweredBy/index.js +0 -16
- package/lib/middlewares/public/defaults.json +0 -8
- package/lib/middlewares/responseTime/defaults.json +0 -5
- package/lib/middlewares/responseTime/index.js +0 -25
- package/lib/middlewares/responses/defaults.json +0 -5
- package/lib/middlewares/responses/index.js +0 -18
- package/lib/middlewares/router/defaults.json +0 -7
- package/lib/middlewares/router/index.js +0 -56
- package/lib/middlewares/router/utils/composeEndpoint.js +0 -25
- package/lib/middlewares/router/utils/routerChecker.js +0 -96
- package/lib/utils/get-prefixed-dependencies.js +0 -7
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const _ = require('lodash');
|
|
3
4
|
const delegate = require('delegates');
|
|
4
5
|
const {
|
|
5
|
-
|
|
6
|
+
InvalidTimeError,
|
|
7
|
+
InvalidDateError,
|
|
8
|
+
InvalidDateTimeError,
|
|
9
|
+
} = require('@strapi/database').errors;
|
|
10
|
+
const {
|
|
6
11
|
webhook: webhookUtils,
|
|
7
12
|
contentTypes: contentTypesUtils,
|
|
8
|
-
|
|
13
|
+
sanitize,
|
|
9
14
|
} = require('@strapi/utils');
|
|
15
|
+
const { ValidationError } = require('@strapi/utils').errors;
|
|
10
16
|
const uploadFiles = require('../utils/upload-files');
|
|
11
17
|
|
|
12
18
|
const {
|
|
@@ -16,12 +22,21 @@ const {
|
|
|
16
22
|
deleteComponents,
|
|
17
23
|
} = require('./components');
|
|
18
24
|
const { transformParamsToQuery, pickSelectionParams } = require('./params');
|
|
19
|
-
|
|
20
|
-
const { MANY_RELATIONS } = relationsUtils.constants;
|
|
25
|
+
const { applyTransforms } = require('./attributes');
|
|
21
26
|
|
|
22
27
|
// TODO: those should be strapi events used by the webhooks not the other way arround
|
|
23
28
|
const { ENTRY_CREATE, ENTRY_UPDATE, ENTRY_DELETE } = webhookUtils.webhookEvents;
|
|
24
29
|
|
|
30
|
+
const databaseErrorsToTransform = [InvalidTimeError, InvalidDateTimeError, InvalidDateError];
|
|
31
|
+
|
|
32
|
+
const creationPipeline = (data, context) => {
|
|
33
|
+
return applyTransforms(data, context);
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const updatePipeline = (data, context) => {
|
|
37
|
+
return applyTransforms(data, context);
|
|
38
|
+
};
|
|
39
|
+
|
|
25
40
|
module.exports = ctx => {
|
|
26
41
|
const implementation = createDefaultImplementation(ctx);
|
|
27
42
|
|
|
@@ -42,31 +57,57 @@ module.exports = ctx => {
|
|
|
42
57
|
// delegate every method in implementation
|
|
43
58
|
Object.keys(service.implementation).forEach(key => delegator.method(key));
|
|
44
59
|
|
|
60
|
+
// wrap methods to handle Database Errors
|
|
61
|
+
service.decorate(oldService => {
|
|
62
|
+
const newService = _.mapValues(
|
|
63
|
+
oldService,
|
|
64
|
+
(method, methodName) =>
|
|
65
|
+
async function(...args) {
|
|
66
|
+
try {
|
|
67
|
+
return await oldService[methodName].call(this, ...args);
|
|
68
|
+
} catch (error) {
|
|
69
|
+
if (
|
|
70
|
+
databaseErrorsToTransform.some(errorToTransform => error instanceof errorToTransform)
|
|
71
|
+
) {
|
|
72
|
+
throw new ValidationError(error.message);
|
|
73
|
+
}
|
|
74
|
+
throw error;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
return newService;
|
|
80
|
+
});
|
|
81
|
+
|
|
45
82
|
return service;
|
|
46
83
|
};
|
|
47
84
|
|
|
85
|
+
/**
|
|
86
|
+
* @type {import('.').default}
|
|
87
|
+
*/
|
|
48
88
|
const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator }) => ({
|
|
49
89
|
uploadFiles,
|
|
50
90
|
|
|
51
|
-
async
|
|
91
|
+
async wrapParams(options = {}) {
|
|
52
92
|
return options;
|
|
53
93
|
},
|
|
54
94
|
|
|
55
|
-
emitEvent(uid, event, entity) {
|
|
95
|
+
async emitEvent(uid, event, entity) {
|
|
56
96
|
const model = strapi.getModel(uid);
|
|
97
|
+
const sanitizedEntity = await sanitize.sanitizers.defaultSanitizeOutput(model, entity);
|
|
57
98
|
|
|
58
99
|
eventHub.emit(event, {
|
|
59
100
|
model: model.modelName,
|
|
60
|
-
entry:
|
|
101
|
+
entry: sanitizedEntity,
|
|
61
102
|
});
|
|
62
103
|
},
|
|
63
104
|
|
|
64
|
-
async
|
|
105
|
+
async findMany(uid, opts) {
|
|
65
106
|
const { kind } = strapi.getModel(uid);
|
|
66
107
|
|
|
67
|
-
const
|
|
108
|
+
const wrappedParams = await this.wrapParams(opts, { uid, action: 'findMany' });
|
|
68
109
|
|
|
69
|
-
const query = transformParamsToQuery(uid,
|
|
110
|
+
const query = transformParamsToQuery(uid, wrappedParams);
|
|
70
111
|
|
|
71
112
|
if (kind === 'singleType') {
|
|
72
113
|
return db.query(uid).findOne(query);
|
|
@@ -76,41 +117,20 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
|
|
|
76
117
|
},
|
|
77
118
|
|
|
78
119
|
async findPage(uid, opts) {
|
|
79
|
-
const
|
|
120
|
+
const wrappedParams = await this.wrapParams(opts, { uid, action: 'findPage' });
|
|
80
121
|
|
|
81
|
-
const query = transformParamsToQuery(uid,
|
|
122
|
+
const query = transformParamsToQuery(uid, wrappedParams);
|
|
82
123
|
|
|
83
124
|
return db.query(uid).findPage(query);
|
|
84
125
|
},
|
|
85
126
|
|
|
127
|
+
// TODO: streamline the logic based on the populate option
|
|
86
128
|
async findWithRelationCounts(uid, opts) {
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
const { params } = await this.wrapOptions(opts, { uid, action: 'findWithRelationCounts' });
|
|
129
|
+
const wrappedParams = await this.wrapParams(opts, { uid, action: 'findWithRelationCounts' });
|
|
90
130
|
|
|
91
|
-
const query = transformParamsToQuery(uid,
|
|
131
|
+
const query = transformParamsToQuery(uid, wrappedParams);
|
|
92
132
|
|
|
93
|
-
const {
|
|
94
|
-
|
|
95
|
-
const populate = (query.populate || []).reduce((populate, attributeName) => {
|
|
96
|
-
const attribute = attributes[attributeName];
|
|
97
|
-
|
|
98
|
-
if (
|
|
99
|
-
MANY_RELATIONS.includes(attribute.relation) &&
|
|
100
|
-
contentTypesUtils.isVisibleAttribute(model, attributeName)
|
|
101
|
-
) {
|
|
102
|
-
populate[attributeName] = { count: true };
|
|
103
|
-
} else {
|
|
104
|
-
populate[attributeName] = true;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
return populate;
|
|
108
|
-
}, {});
|
|
109
|
-
|
|
110
|
-
const { results, pagination } = await db.query(uid).findPage({
|
|
111
|
-
...query,
|
|
112
|
-
populate,
|
|
113
|
-
});
|
|
133
|
+
const { results, pagination } = await db.query(uid).findPage(query);
|
|
114
134
|
|
|
115
135
|
return {
|
|
116
136
|
results,
|
|
@@ -119,23 +139,24 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
|
|
|
119
139
|
},
|
|
120
140
|
|
|
121
141
|
async findOne(uid, entityId, opts) {
|
|
122
|
-
const
|
|
142
|
+
const wrappedParams = await this.wrapParams(opts, { uid, action: 'findOne' });
|
|
123
143
|
|
|
124
|
-
const query = transformParamsToQuery(uid, pickSelectionParams(
|
|
144
|
+
const query = transformParamsToQuery(uid, pickSelectionParams(wrappedParams));
|
|
125
145
|
|
|
126
146
|
return db.query(uid).findOne({ ...query, where: { id: entityId } });
|
|
127
147
|
},
|
|
128
148
|
|
|
129
149
|
async count(uid, opts) {
|
|
130
|
-
const
|
|
150
|
+
const wrappedParams = await this.wrapParams(opts, { uid, action: 'count' });
|
|
131
151
|
|
|
132
|
-
const query = transformParamsToQuery(uid,
|
|
152
|
+
const query = transformParamsToQuery(uid, wrappedParams);
|
|
133
153
|
|
|
134
154
|
return db.query(uid).count(query);
|
|
135
155
|
},
|
|
136
156
|
|
|
137
157
|
async create(uid, opts) {
|
|
138
|
-
const
|
|
158
|
+
const wrappedParams = await this.wrapParams(opts, { uid, action: 'create' });
|
|
159
|
+
const { data, files } = wrappedParams;
|
|
139
160
|
|
|
140
161
|
const model = strapi.getModel(uid);
|
|
141
162
|
|
|
@@ -143,30 +164,33 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
|
|
|
143
164
|
const validData = await entityValidator.validateEntityCreation(model, data, { isDraft });
|
|
144
165
|
|
|
145
166
|
// select / populate
|
|
146
|
-
const query = transformParamsToQuery(uid, pickSelectionParams(
|
|
167
|
+
const query = transformParamsToQuery(uid, pickSelectionParams(wrappedParams));
|
|
147
168
|
|
|
148
169
|
// TODO: wrap into transaction
|
|
149
170
|
const componentData = await createComponents(uid, validData);
|
|
150
171
|
|
|
151
172
|
let entity = await db.query(uid).create({
|
|
152
173
|
...query,
|
|
153
|
-
data: Object.assign(omitComponentData(model, validData), componentData),
|
|
174
|
+
data: creationPipeline(Object.assign(omitComponentData(model, validData), componentData), {
|
|
175
|
+
contentType: model,
|
|
176
|
+
}),
|
|
154
177
|
});
|
|
155
178
|
|
|
156
179
|
// TODO: upload the files then set the links in the entity like with compo to avoid making too many queries
|
|
157
180
|
// FIXME: upload in components
|
|
158
181
|
if (files && Object.keys(files).length > 0) {
|
|
159
182
|
await this.uploadFiles(uid, entity, files);
|
|
160
|
-
entity = await this.findOne(uid, entity.id,
|
|
183
|
+
entity = await this.findOne(uid, entity.id, wrappedParams);
|
|
161
184
|
}
|
|
162
185
|
|
|
163
|
-
this.emitEvent(uid, ENTRY_CREATE, entity);
|
|
186
|
+
await this.emitEvent(uid, ENTRY_CREATE, entity);
|
|
164
187
|
|
|
165
188
|
return entity;
|
|
166
189
|
},
|
|
167
190
|
|
|
168
191
|
async update(uid, entityId, opts) {
|
|
169
|
-
const
|
|
192
|
+
const wrappedParams = await this.wrapParams(opts, { uid, action: 'update' });
|
|
193
|
+
const { data, files } = wrappedParams;
|
|
170
194
|
|
|
171
195
|
const model = strapi.getModel(uid);
|
|
172
196
|
|
|
@@ -178,11 +202,16 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
|
|
|
178
202
|
|
|
179
203
|
const isDraft = contentTypesUtils.isDraft(entityToUpdate, model);
|
|
180
204
|
|
|
181
|
-
const validData = await entityValidator.validateEntityUpdate(
|
|
182
|
-
|
|
183
|
-
|
|
205
|
+
const validData = await entityValidator.validateEntityUpdate(
|
|
206
|
+
model,
|
|
207
|
+
data,
|
|
208
|
+
{
|
|
209
|
+
isDraft,
|
|
210
|
+
},
|
|
211
|
+
entityToUpdate
|
|
212
|
+
);
|
|
184
213
|
|
|
185
|
-
const query = transformParamsToQuery(uid, pickSelectionParams(
|
|
214
|
+
const query = transformParamsToQuery(uid, pickSelectionParams(wrappedParams));
|
|
186
215
|
|
|
187
216
|
// TODO: wrap in transaction
|
|
188
217
|
const componentData = await updateComponents(uid, entityToUpdate, validData);
|
|
@@ -190,26 +219,28 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
|
|
|
190
219
|
let entity = await db.query(uid).update({
|
|
191
220
|
...query,
|
|
192
221
|
where: { id: entityId },
|
|
193
|
-
data: Object.assign(omitComponentData(model, validData), componentData),
|
|
222
|
+
data: updatePipeline(Object.assign(omitComponentData(model, validData), componentData), {
|
|
223
|
+
contentType: model,
|
|
224
|
+
}),
|
|
194
225
|
});
|
|
195
226
|
|
|
196
227
|
// TODO: upload the files then set the links in the entity like with compo to avoid making too many queries
|
|
197
228
|
// FIXME: upload in components
|
|
198
229
|
if (files && Object.keys(files).length > 0) {
|
|
199
230
|
await this.uploadFiles(uid, entity, files);
|
|
200
|
-
entity = await this.findOne(uid, entity.id,
|
|
231
|
+
entity = await this.findOne(uid, entity.id, wrappedParams);
|
|
201
232
|
}
|
|
202
233
|
|
|
203
|
-
this.emitEvent(uid, ENTRY_UPDATE, entity);
|
|
234
|
+
await this.emitEvent(uid, ENTRY_UPDATE, entity);
|
|
204
235
|
|
|
205
236
|
return entity;
|
|
206
237
|
},
|
|
207
238
|
|
|
208
239
|
async delete(uid, entityId, opts) {
|
|
209
|
-
const
|
|
240
|
+
const wrappedParams = await this.wrapParams(opts, { uid, action: 'delete' });
|
|
210
241
|
|
|
211
242
|
// select / populate
|
|
212
|
-
const query = transformParamsToQuery(uid, pickSelectionParams(
|
|
243
|
+
const query = transformParamsToQuery(uid, pickSelectionParams(wrappedParams));
|
|
213
244
|
|
|
214
245
|
const entityToDelete = await db.query(uid).findOne({
|
|
215
246
|
...query,
|
|
@@ -223,17 +254,47 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
|
|
|
223
254
|
await deleteComponents(uid, entityToDelete);
|
|
224
255
|
await db.query(uid).delete({ where: { id: entityToDelete.id } });
|
|
225
256
|
|
|
226
|
-
this.emitEvent(uid, ENTRY_DELETE, entityToDelete);
|
|
257
|
+
await this.emitEvent(uid, ENTRY_DELETE, entityToDelete);
|
|
227
258
|
|
|
228
259
|
return entityToDelete;
|
|
229
260
|
},
|
|
230
261
|
|
|
262
|
+
// FIXME: used only for the CM to be removed
|
|
231
263
|
async deleteMany(uid, opts) {
|
|
232
|
-
const
|
|
264
|
+
const wrappedParams = await this.wrapParams(opts, { uid, action: 'delete' });
|
|
233
265
|
|
|
234
266
|
// select / populate
|
|
235
|
-
const query = transformParamsToQuery(uid,
|
|
267
|
+
const query = transformParamsToQuery(uid, wrappedParams);
|
|
236
268
|
|
|
237
269
|
return db.query(uid).deleteMany(query);
|
|
238
270
|
},
|
|
271
|
+
|
|
272
|
+
load(uid, entity, field, params = {}) {
|
|
273
|
+
const { attributes } = strapi.getModel(uid);
|
|
274
|
+
|
|
275
|
+
const attribute = attributes[field];
|
|
276
|
+
|
|
277
|
+
const loadParams = {};
|
|
278
|
+
|
|
279
|
+
switch (attribute.type) {
|
|
280
|
+
case 'relation': {
|
|
281
|
+
Object.assign(loadParams, transformParamsToQuery(attribute.target, params));
|
|
282
|
+
break;
|
|
283
|
+
}
|
|
284
|
+
case 'component': {
|
|
285
|
+
Object.assign(loadParams, transformParamsToQuery(attribute.component, params));
|
|
286
|
+
break;
|
|
287
|
+
}
|
|
288
|
+
case 'dynamiczone': {
|
|
289
|
+
Object.assign(loadParams, transformParamsToQuery(null, params));
|
|
290
|
+
break;
|
|
291
|
+
}
|
|
292
|
+
case 'media': {
|
|
293
|
+
Object.assign(loadParams, transformParamsToQuery('plugin::upload.file', params));
|
|
294
|
+
break;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
return db.query(uid).load(entity, field, loadParams);
|
|
299
|
+
},
|
|
239
300
|
});
|
|
@@ -1,136 +1,94 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
const {
|
|
3
|
+
const { pick, isNil, toNumber, isInteger } = require('lodash/fp');
|
|
4
|
+
const { PaginationError } = require('@strapi/utils').errors;
|
|
5
5
|
|
|
6
6
|
const {
|
|
7
7
|
convertSortQueryParams,
|
|
8
8
|
convertLimitQueryParams,
|
|
9
9
|
convertStartQueryParams,
|
|
10
|
-
|
|
10
|
+
convertPopulateQueryParams,
|
|
11
|
+
convertFiltersQueryParams,
|
|
12
|
+
convertFieldsQueryParams,
|
|
13
|
+
convertPublicationStateParams,
|
|
14
|
+
} = require('@strapi/utils/lib/convert-query-params');
|
|
11
15
|
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
const { PUBLISHED_AT_ATTRIBUTE } = contentTypesUtils.constants;
|
|
16
|
+
const pickSelectionParams = pick(['fields', 'populate']);
|
|
15
17
|
|
|
16
|
-
const transformParamsToQuery = (uid, params
|
|
17
|
-
|
|
18
|
+
const transformParamsToQuery = (uid, params) => {
|
|
19
|
+
// NOTE: can be a CT, a Compo or nothing in the case of polymorphism (DZ & morph relations)
|
|
20
|
+
const type = strapi.getModel(uid);
|
|
18
21
|
|
|
19
22
|
const query = {};
|
|
20
23
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
const {
|
|
24
|
-
start,
|
|
25
|
-
page,
|
|
26
|
-
pageSize,
|
|
27
|
-
limit,
|
|
28
|
-
sort,
|
|
29
|
-
filters,
|
|
30
|
-
fields,
|
|
31
|
-
populate,
|
|
32
|
-
publicationState,
|
|
33
|
-
_q,
|
|
34
|
-
_where,
|
|
35
|
-
...rest
|
|
36
|
-
} = params;
|
|
37
|
-
|
|
38
|
-
if (_q) {
|
|
39
|
-
query._q = _q;
|
|
40
|
-
}
|
|
24
|
+
const { _q, sort, filters, fields, populate, page, pageSize, start, limit } = params;
|
|
41
25
|
|
|
42
|
-
if (
|
|
43
|
-
query.
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
if (pageSize) {
|
|
47
|
-
query.pageSize = Number(pageSize);
|
|
26
|
+
if (!isNil(_q)) {
|
|
27
|
+
query._q = _q;
|
|
48
28
|
}
|
|
49
29
|
|
|
50
|
-
if (
|
|
51
|
-
query.
|
|
30
|
+
if (!isNil(sort)) {
|
|
31
|
+
query.orderBy = convertSortQueryParams(sort);
|
|
52
32
|
}
|
|
53
33
|
|
|
54
|
-
if (
|
|
55
|
-
query.
|
|
34
|
+
if (!isNil(filters)) {
|
|
35
|
+
query.where = convertFiltersQueryParams(filters);
|
|
56
36
|
}
|
|
57
37
|
|
|
58
|
-
if (
|
|
59
|
-
query.
|
|
38
|
+
if (!isNil(fields)) {
|
|
39
|
+
query.select = convertFieldsQueryParams(fields);
|
|
60
40
|
}
|
|
61
41
|
|
|
62
|
-
if (
|
|
63
|
-
query.
|
|
42
|
+
if (!isNil(populate)) {
|
|
43
|
+
query.populate = convertPopulateQueryParams(populate);
|
|
64
44
|
}
|
|
65
45
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
$and: [_where].concat(query.where || []),
|
|
69
|
-
};
|
|
70
|
-
}
|
|
46
|
+
const isPagePagination = !isNil(page) || !isNil(pageSize);
|
|
47
|
+
const isOffsetPagination = !isNil(start) || !isNil(limit);
|
|
71
48
|
|
|
72
|
-
if (
|
|
73
|
-
|
|
74
|
-
|
|
49
|
+
if (isPagePagination && isOffsetPagination) {
|
|
50
|
+
throw new PaginationError(
|
|
51
|
+
'Invalid pagination attributes. You cannot use page and offset pagination in the same query'
|
|
52
|
+
);
|
|
75
53
|
}
|
|
76
54
|
|
|
77
|
-
if (
|
|
78
|
-
|
|
79
|
-
const { populate } = params;
|
|
55
|
+
if (!isNil(page)) {
|
|
56
|
+
const pageVal = toNumber(page);
|
|
80
57
|
|
|
81
|
-
if (
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
} else {
|
|
86
|
-
query.populate = _.castArray(populate);
|
|
58
|
+
if (!isInteger(pageVal) || pageVal <= 0) {
|
|
59
|
+
throw new PaginationError(
|
|
60
|
+
`Invalid 'page' parameter. Expected an integer > 0, received: ${page}`
|
|
61
|
+
);
|
|
87
62
|
}
|
|
88
|
-
}
|
|
89
63
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
const { publicationState = 'live' } = params;
|
|
93
|
-
|
|
94
|
-
const liveClause = {
|
|
95
|
-
[PUBLISHED_AT_ATTRIBUTE]: {
|
|
96
|
-
$notNull: true,
|
|
97
|
-
},
|
|
98
|
-
};
|
|
64
|
+
query.page = pageVal;
|
|
65
|
+
}
|
|
99
66
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
$and: [liveClause].concat(query.where || []),
|
|
103
|
-
};
|
|
67
|
+
if (!isNil(pageSize)) {
|
|
68
|
+
const pageSizeVal = toNumber(pageSize);
|
|
104
69
|
|
|
105
|
-
|
|
70
|
+
if (!isInteger(pageSizeVal) || pageSizeVal <= 0) {
|
|
71
|
+
throw new PaginationError(
|
|
72
|
+
`Invalid 'pageSize' parameter. Expected an integer > 0, received: ${page}`
|
|
73
|
+
);
|
|
106
74
|
}
|
|
107
|
-
}
|
|
108
75
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
...query,
|
|
112
|
-
};
|
|
76
|
+
query.pageSize = pageSizeVal;
|
|
77
|
+
}
|
|
113
78
|
|
|
114
|
-
|
|
115
|
-
|
|
79
|
+
if (!isNil(start)) {
|
|
80
|
+
query.offset = convertStartQueryParams(start);
|
|
81
|
+
}
|
|
116
82
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
83
|
+
if (!isNil(limit)) {
|
|
84
|
+
query.limit = convertLimitQueryParams(limit);
|
|
85
|
+
}
|
|
120
86
|
|
|
121
|
-
|
|
122
|
-
if (key.startsWith('_')) {
|
|
123
|
-
obj[key.slice(1)] = params[key];
|
|
124
|
-
} else {
|
|
125
|
-
obj[key] = params[key];
|
|
126
|
-
}
|
|
127
|
-
});
|
|
87
|
+
convertPublicationStateParams(type, params, query);
|
|
128
88
|
|
|
129
|
-
return
|
|
89
|
+
return query;
|
|
130
90
|
};
|
|
131
91
|
|
|
132
|
-
const pickSelectionParams = pick(['fields', 'populate']);
|
|
133
|
-
|
|
134
92
|
module.exports = {
|
|
135
93
|
transformParamsToQuery,
|
|
136
94
|
pickSelectionParams,
|