mirror of
https://github.com/strapi/strapi.git
synced 2025-08-22 15:48:59 +00:00
Init compo & add publication field
This commit is contained in:
parent
65d612f364
commit
3ded0ef2bd
@ -26,6 +26,7 @@ const permissionDomain = require('../../domain/permission/index');
|
|||||||
* @returns {Promise<array>}
|
* @returns {Promise<array>}
|
||||||
*/
|
*/
|
||||||
const deleteByRolesIds = async rolesIds => {
|
const deleteByRolesIds = async rolesIds => {
|
||||||
|
// FIXME: need to delete associations in delete many
|
||||||
await strapi.query('strapi::permission').deleteMany({
|
await strapi.query('strapi::permission').deleteMany({
|
||||||
where: {
|
where: {
|
||||||
role: { id: rolesIds },
|
role: { id: rolesIds },
|
||||||
|
@ -21,26 +21,28 @@ async function main(connection) {
|
|||||||
await orm.schema.sync();
|
await orm.schema.sync();
|
||||||
await orm.schema.reset();
|
await orm.schema.reset();
|
||||||
|
|
||||||
|
await orm.query('compo').create({
|
||||||
|
data: {
|
||||||
|
key: 'A',
|
||||||
|
value: 1,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
await orm.query('article').create({
|
await orm.query('article').create({
|
||||||
// select: {},
|
// select: {},
|
||||||
// populate: {},
|
// populate: {},
|
||||||
data: {
|
data: {
|
||||||
compo: {
|
compo: 1,
|
||||||
id: 1,
|
|
||||||
__pivot: {
|
|
||||||
order: 1,
|
|
||||||
field: 'compo',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const articles = await orm.query('article').findMany({
|
await orm.query('article').findMany({
|
||||||
limit: 5,
|
populate: ['category.compo'],
|
||||||
where: { title: 'Article 001', createdAt: { $null: true } },
|
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log(articles);
|
// console.log(await orm.query('article').load(1, 'compo'));
|
||||||
|
|
||||||
|
// await orm.query('article').delete({ where: { id: 1 } });
|
||||||
|
|
||||||
// await tests(orm);
|
// await tests(orm);
|
||||||
} finally {
|
} finally {
|
||||||
@ -391,28 +393,40 @@ const tests = async orm => {
|
|||||||
// });
|
// });
|
||||||
|
|
||||||
await orm.query('article').findMany({
|
await orm.query('article').findMany({
|
||||||
limit: 5,
|
|
||||||
where: {
|
where: {
|
||||||
compos: {
|
$not: {
|
||||||
key: 'xx',
|
$or: [
|
||||||
|
{
|
||||||
|
category: {
|
||||||
|
title: 'Article 003',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: {
|
||||||
|
$in: ['Article 001', 'Article 002'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
title: {
|
||||||
|
$not: 'Article 007',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
orderBy: [{ category: { name: 'asc' } }],
|
||||||
|
offset: 0,
|
||||||
|
limit: 10,
|
||||||
populate: {
|
populate: {
|
||||||
category: {
|
category: {
|
||||||
select: ['id', 'title'],
|
|
||||||
limit: 5,
|
|
||||||
offset: 2,
|
|
||||||
orderBy: 'title',
|
orderBy: 'title',
|
||||||
populate: {
|
populate: {
|
||||||
articles: {
|
categories: {
|
||||||
populate: {
|
populate: {
|
||||||
tags: true,
|
tags: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
compos: true,
|
seo: true,
|
||||||
},
|
},
|
||||||
orderBy: { compos: { key: 'DESC' } },
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -38,24 +38,24 @@ const article = {
|
|||||||
title: {
|
title: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
},
|
},
|
||||||
// category: {
|
category: {
|
||||||
// type: 'relation',
|
type: 'relation',
|
||||||
// relation: 'manyToOne',
|
relation: 'manyToOne',
|
||||||
// target: 'category',
|
target: 'category',
|
||||||
// inversedBy: 'articles',
|
inversedBy: 'articles',
|
||||||
// // useJoinTable: false,
|
// useJoinTable: false,
|
||||||
// },
|
},
|
||||||
// tags: {
|
// tags: {
|
||||||
// type: 'relation',
|
// type: 'relation',
|
||||||
// relation: 'manyToMany',
|
// relation: 'manyToMany',
|
||||||
// target: 'tag',
|
// target: 'tag',
|
||||||
// inversedBy: 'articles',
|
// inversedBy: 'articles',
|
||||||
// },
|
// },
|
||||||
compo: {
|
// compo: {
|
||||||
type: 'component',
|
// type: 'component',
|
||||||
component: 'compo',
|
// component: 'compo',
|
||||||
// repeatable: true,
|
// // repeatable: true,
|
||||||
},
|
// },
|
||||||
// cover: {
|
// cover: {
|
||||||
// type: 'media',
|
// type: 'media',
|
||||||
// single: true,
|
// single: true,
|
||||||
|
@ -55,19 +55,19 @@ const createEntityManager = db => {
|
|||||||
const repoMap = {};
|
const repoMap = {};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
async findOne(uid, params) {
|
findOne(uid, params) {
|
||||||
const qb = this.createQueryBuilder(uid)
|
const qb = this.createQueryBuilder(uid)
|
||||||
.init(params)
|
.init(params)
|
||||||
.first();
|
.first();
|
||||||
|
|
||||||
return await qb.execute();
|
return qb.execute();
|
||||||
},
|
},
|
||||||
|
|
||||||
// should we name it findOne because people are used to it ?
|
// should we name it findOne because people are used to it ?
|
||||||
async findMany(uid, params) {
|
findMany(uid, params) {
|
||||||
const qb = this.createQueryBuilder(uid).init(params);
|
const qb = this.createQueryBuilder(uid).init(params);
|
||||||
|
|
||||||
return await qb.execute();
|
return qb.execute();
|
||||||
},
|
},
|
||||||
|
|
||||||
async count(uid, params = {}) {
|
async count(uid, params = {}) {
|
||||||
@ -195,15 +195,14 @@ const createEntityManager = db => {
|
|||||||
|
|
||||||
async delete(uid, params = {}) {
|
async delete(uid, params = {}) {
|
||||||
const { where, select, populate } = params;
|
const { where, select, populate } = params;
|
||||||
const metadata = db.metadata.get(uid);
|
|
||||||
|
|
||||||
if (_.isEmpty(where)) {
|
if (_.isEmpty(where)) {
|
||||||
throw new Error('Delete requires a where parameter');
|
throw new Error('Delete requires a where parameter');
|
||||||
}
|
}
|
||||||
|
|
||||||
const entity = await this.findOne(uid, {
|
const entity = await this.findOne(uid, {
|
||||||
where,
|
|
||||||
select: select && ['id'].concat(select),
|
select: select && ['id'].concat(select),
|
||||||
|
where,
|
||||||
populate,
|
populate,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -235,27 +234,6 @@ const createEntityManager = db => {
|
|||||||
return { count: deletedRows };
|
return { count: deletedRows };
|
||||||
},
|
},
|
||||||
|
|
||||||
// populate already loaded entry
|
|
||||||
async populate(uid, entry, name, params) {
|
|
||||||
return {
|
|
||||||
...entry,
|
|
||||||
relation: await this.load(entry, name, params),
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
// loads a relation
|
|
||||||
load(uid, entry, name, params) {
|
|
||||||
const { attributes } = db.metadata.get(uid);
|
|
||||||
|
|
||||||
return this.getRepository(attributes[name].target.uid).findMany({
|
|
||||||
...params,
|
|
||||||
where: {
|
|
||||||
...params.where,
|
|
||||||
// [parent]: entry.id,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attach relations to a new entity
|
* Attach relations to a new entity
|
||||||
*
|
*
|
||||||
@ -497,6 +475,35 @@ const createEntityManager = db => {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// populate already loaded entry
|
||||||
|
async populate(uid, entry, name, params) {
|
||||||
|
return {
|
||||||
|
...entry,
|
||||||
|
relation: await this.load(entry, name, params),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
// loads a relation
|
||||||
|
async load(uid, id, field, params) {
|
||||||
|
const { attributes } = db.metadata.get(uid);
|
||||||
|
|
||||||
|
const attribute = attributes[field];
|
||||||
|
|
||||||
|
if (!attribute || attribute.type !== 'relation') {
|
||||||
|
throw new Error('Invalid load expected a relational attribute');
|
||||||
|
}
|
||||||
|
|
||||||
|
const entry = await this.findOne(uid, {
|
||||||
|
select: ['id'],
|
||||||
|
where: { id },
|
||||||
|
populate: {
|
||||||
|
[field]: params || true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return entry[field];
|
||||||
|
},
|
||||||
|
|
||||||
// cascading
|
// cascading
|
||||||
// aggregations
|
// aggregations
|
||||||
// -> avg
|
// -> avg
|
||||||
|
@ -84,12 +84,13 @@ const createRepository = (uid, db) => {
|
|||||||
},
|
},
|
||||||
|
|
||||||
attachRelations(id, data) {
|
attachRelations(id, data) {
|
||||||
console.log(id, data)
|
|
||||||
return db.entityManager.attachRelations(uid, id, data);
|
return db.entityManager.attachRelations(uid, id, data);
|
||||||
},
|
},
|
||||||
|
|
||||||
updateRelations(id, data) {
|
updateRelations(id, data) {
|
||||||
return db.entityManager.updateRelations(uid, id, data);
|
return db.entityManager.updateRelations(uid, id, data);
|
||||||
},
|
},
|
||||||
|
|
||||||
deleteRelations(id) {
|
deleteRelations(id) {
|
||||||
return db.entityManager.deleteRelations(uid, id);
|
return db.entityManager.deleteRelations(uid, id);
|
||||||
},
|
},
|
||||||
@ -97,7 +98,9 @@ const createRepository = (uid, db) => {
|
|||||||
// TODO: add relation API
|
// TODO: add relation API
|
||||||
|
|
||||||
populate() {},
|
populate() {},
|
||||||
load() {},
|
load(id, field, params) {
|
||||||
|
return db.entityManager.load(uid, id, field, params);
|
||||||
|
},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -193,10 +193,10 @@ const relationFactoryMap = {
|
|||||||
manyToMany: createManyToMany,
|
manyToMany: createManyToMany,
|
||||||
};
|
};
|
||||||
|
|
||||||
const createJoinColum = (metadata, { attribute /*attributeName, meta */ }) => {
|
const createJoinColum = (metadata, { attribute, attributeName /*meta */ }) => {
|
||||||
const targetMeta = metadata.get(attribute.target);
|
const targetMeta = metadata.get(attribute.target);
|
||||||
|
|
||||||
const joinColumnName = _.snakeCase(`${targetMeta.singularName}_id`);
|
const joinColumnName = _.snakeCase(`${attributeName}_id`);
|
||||||
const joinColumn = {
|
const joinColumn = {
|
||||||
name: joinColumnName,
|
name: joinColumnName,
|
||||||
referencedColumn: 'id',
|
referencedColumn: 'id',
|
||||||
|
@ -470,7 +470,15 @@ const processPopulate = (populate, ctx) => {
|
|||||||
|
|
||||||
if (Array.isArray(populate)) {
|
if (Array.isArray(populate)) {
|
||||||
for (const key of populate) {
|
for (const key of populate) {
|
||||||
populateMap[key] = true;
|
const [root, ...rest] = key.split('.');
|
||||||
|
|
||||||
|
if (rest.length > 0) {
|
||||||
|
populateMap[root] = {
|
||||||
|
populate: rest,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
populateMap[root] = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
populateMap = populate;
|
populateMap = populate;
|
||||||
|
@ -20,11 +20,11 @@ const transformAttribute = attribute => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: add published_at for D&P
|
|
||||||
// TODO: add locale & localizations for I18N
|
// TODO: add locale & localizations for I18N
|
||||||
|
// TODO: model logic outside DB
|
||||||
const transformContentTypes = contentTypes => {
|
const transformContentTypes = contentTypes => {
|
||||||
return contentTypes.map(contentType => {
|
return contentTypes.map(contentType => {
|
||||||
return {
|
const model = {
|
||||||
...contentType,
|
...contentType,
|
||||||
// reuse new model def
|
// reuse new model def
|
||||||
singularName: contentType.modelName,
|
singularName: contentType.modelName,
|
||||||
@ -44,6 +44,8 @@ const transformContentTypes = contentTypes => {
|
|||||||
}, {}),
|
}, {}),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
return model;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ const getLimitParam = params => {
|
|||||||
return defaultLimit;
|
return defaultLimit;
|
||||||
}
|
}
|
||||||
|
|
||||||
const limit = _.toNumber(params._limit);
|
const limit = _.toNumber(params.limit);
|
||||||
// if there is max limit set and params._limit exceeds this number, return configured max limit
|
// if there is max limit set and params._limit exceeds this number, return configured max limit
|
||||||
if (maxLimit && (limit === -1 || limit > maxLimit)) {
|
if (maxLimit && (limit === -1 || limit > maxLimit)) {
|
||||||
return maxLimit;
|
return maxLimit;
|
||||||
@ -58,9 +58,9 @@ const getLimitParam = params => {
|
|||||||
*/
|
*/
|
||||||
const getFetchParams = (params = {}) => {
|
const getFetchParams = (params = {}) => {
|
||||||
return {
|
return {
|
||||||
// _publicationState: DP_PUB_STATE_LIVE,
|
publicationState: DP_PUB_STATE_LIVE,
|
||||||
...params,
|
...params,
|
||||||
// limit: getLimitParam(params),
|
limit: getLimitParam(params),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
const _ = require('lodash');
|
||||||
const { has, pick } = require('lodash/fp');
|
const { has, pick } = require('lodash/fp');
|
||||||
const delegate = require('delegates');
|
const delegate = require('delegates');
|
||||||
|
|
||||||
@ -43,34 +44,59 @@ module.exports = ctx => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// TODO: move to Controller ?
|
// TODO: move to Controller ?
|
||||||
const transformParamsToQuery = (params = {}) => {
|
const transformParamsToQuery = (uid, params = {}) => {
|
||||||
const query = {};
|
const model = strapi.getModel(uid);
|
||||||
|
|
||||||
|
const query = {
|
||||||
|
populate: [],
|
||||||
|
};
|
||||||
|
|
||||||
// TODO: check invalid values add defaults ....
|
// TODO: check invalid values add defaults ....
|
||||||
|
|
||||||
if (params.start) {
|
const { start, limit, sort, filters, fields, populate, publicationState } = params;
|
||||||
query.offset = convertStartQueryParams(params.start);
|
|
||||||
|
if (start) {
|
||||||
|
query.offset = convertStartQueryParams(start);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (params.limit) {
|
if (limit) {
|
||||||
query.limit = convertLimitQueryParams(params.limit);
|
query.limit = convertLimitQueryParams(limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (params.sort) {
|
if (sort) {
|
||||||
query.orderBy = convertSortQueryParams(params.sort);
|
query.orderBy = convertSortQueryParams(sort);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (params.filters) {
|
if (filters) {
|
||||||
query.where = params.filters;
|
query.where = filters;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (params.fields) {
|
if (fields) {
|
||||||
query.select = params.fields;
|
query.select = _.castArray(fields);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (params.populate) {
|
if (populate) {
|
||||||
const { populate } = params;
|
const { populate } = params;
|
||||||
query.populate = populate;
|
query.populate = _.castArray(populate);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: move to layer above ?
|
||||||
|
if (publicationState && contentTypesUtils.hasDraftAndPublish(model)) {
|
||||||
|
const { publicationState = 'live' } = params;
|
||||||
|
|
||||||
|
const liveClause = {
|
||||||
|
published_at: {
|
||||||
|
$notNull: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
if (publicationState === 'live') {
|
||||||
|
query.where = {
|
||||||
|
$and: [liveClause, query.where || {}],
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: propagate nested publicationState filter somehow
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return query;
|
return query;
|
||||||
@ -85,12 +111,21 @@ const createDefaultImplementation = ({ db, eventHub, entityValidator }) => ({
|
|||||||
return options;
|
return options;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
emitEvent(uid, event, entity) {
|
||||||
|
const model = strapi.getModel(uid);
|
||||||
|
|
||||||
|
eventHub.emit(event, {
|
||||||
|
model: model.modelName,
|
||||||
|
entry: sanitizeEntity(entity, { model }),
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
async find(uid, opts) {
|
async find(uid, opts) {
|
||||||
const { kind } = strapi.getModel(uid);
|
const { kind } = strapi.getModel(uid);
|
||||||
|
|
||||||
const { params } = await this.wrapOptions(opts, { uid, action: 'find' });
|
const { params } = await this.wrapOptions(opts, { uid, action: 'find' });
|
||||||
|
|
||||||
const query = transformParamsToQuery(params);
|
const query = transformParamsToQuery(uid, params);
|
||||||
|
|
||||||
// return first element and ignore filters
|
// return first element and ignore filters
|
||||||
if (kind === 'singleType') {
|
if (kind === 'singleType') {
|
||||||
@ -103,26 +138,21 @@ const createDefaultImplementation = ({ db, eventHub, entityValidator }) => ({
|
|||||||
async findPage(uid, opts) {
|
async findPage(uid, opts) {
|
||||||
const { params } = await this.wrapOptions(opts, { uid, action: 'findPage' });
|
const { params } = await this.wrapOptions(opts, { uid, action: 'findPage' });
|
||||||
|
|
||||||
// TODO: transform page pageSize
|
const query = transformParamsToQuery(uid, params);
|
||||||
const query = transformParamsToQuery(params);
|
|
||||||
|
|
||||||
return db.query(uid).findPage(query);
|
return db.query(uid).findPage(query);
|
||||||
},
|
},
|
||||||
|
|
||||||
async findWithRelationCounts(uid, opts) {
|
async findWithRelationCounts(uid, opts) {
|
||||||
const { params, populate } = await this.wrapOptions(opts, {
|
const { params } = await this.wrapOptions(opts, { uid, action: 'findWithRelationCounts' });
|
||||||
uid,
|
|
||||||
action: 'findWithRelationCounts',
|
|
||||||
});
|
|
||||||
|
|
||||||
// TODO: to impl
|
return db.query(uid).findWithRelationCounts(params);
|
||||||
return db.query(uid).findWithRelationCounts(params, populate);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
async findOne(uid, entityId, opts) {
|
async findOne(uid, entityId, opts) {
|
||||||
const { params } = await this.wrapOptions(opts, { uid, action: 'findOne' });
|
const { params } = await this.wrapOptions(opts, { uid, action: 'findOne' });
|
||||||
|
|
||||||
const query = transformParamsToQuery(pickSelectionParams(params));
|
const query = transformParamsToQuery(uid, pickSelectionParams(params));
|
||||||
|
|
||||||
return db.query(uid).findOne({ ...query, where: { id: entityId } });
|
return db.query(uid).findOne({ ...query, where: { id: entityId } });
|
||||||
},
|
},
|
||||||
@ -130,7 +160,7 @@ const createDefaultImplementation = ({ db, eventHub, entityValidator }) => ({
|
|||||||
async count(uid, opts) {
|
async count(uid, opts) {
|
||||||
const { params } = await this.wrapOptions(opts, { uid, action: 'count' });
|
const { params } = await this.wrapOptions(opts, { uid, action: 'count' });
|
||||||
|
|
||||||
const query = transformParamsToQuery(params);
|
const query = transformParamsToQuery(uid, params);
|
||||||
|
|
||||||
return db.query(uid).count(query);
|
return db.query(uid).count(query);
|
||||||
},
|
},
|
||||||
@ -138,36 +168,27 @@ const createDefaultImplementation = ({ db, eventHub, entityValidator }) => ({
|
|||||||
async create(uid, opts) {
|
async create(uid, opts) {
|
||||||
const { params, data, files } = await this.wrapOptions(opts, { uid, action: 'create' });
|
const { params, data, files } = await this.wrapOptions(opts, { uid, action: 'create' });
|
||||||
|
|
||||||
const modelDef = strapi.getModel(uid);
|
const model = strapi.getModel(uid);
|
||||||
|
const isDraft = contentTypesUtils.isDraft(data, model);
|
||||||
const isDraft = contentTypesUtils.isDraft(data, modelDef);
|
const validData = await entityValidator.validateEntityCreation(model, data, { isDraft });
|
||||||
|
|
||||||
const validData = await entityValidator.validateEntityCreation(modelDef, data, { isDraft });
|
|
||||||
|
|
||||||
// select / populate
|
// select / populate
|
||||||
const query = transformParamsToQuery(pickSelectionParams(params));
|
const query = transformParamsToQuery(uid, pickSelectionParams(params));
|
||||||
|
|
||||||
// TODO: wrap into transaction
|
// TODO: wrap into transaction
|
||||||
|
|
||||||
const componentData = await createComponents(uid, validData);
|
const componentData = await createComponents(uid, validData);
|
||||||
|
|
||||||
const entity = await db.query(uid).create({
|
const entity = await db.query(uid).create({
|
||||||
...query,
|
...query,
|
||||||
data: Object.assign(validData, componentData),
|
data: Object.assign(validData, componentData),
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO: Implement components CRUD
|
|
||||||
|
|
||||||
// TODO: implement files outside of the entity service
|
// TODO: implement files outside of the entity service
|
||||||
// if (files && Object.keys(files).length > 0) {
|
// if (files && Object.keys(files).length > 0) {
|
||||||
// await this.uploadFiles(entry, files, { model });
|
// await this.uploadFiles(entry, files, { model });
|
||||||
// entry = await this.findOne({ params: { id: entry.id } }, { model });
|
// entry = await this.findOne({ params: { id: entry.id } }, { model });
|
||||||
// }
|
// }
|
||||||
|
|
||||||
eventHub.emit(ENTRY_CREATE, {
|
this.emitEvent(uid, ENTRY_CREATE, entity);
|
||||||
model: modelDef.modelName,
|
|
||||||
entry: sanitizeEntity(entity, { model: modelDef }),
|
|
||||||
});
|
|
||||||
|
|
||||||
return entity;
|
return entity;
|
||||||
},
|
},
|
||||||
@ -175,72 +196,71 @@ const createDefaultImplementation = ({ db, eventHub, entityValidator }) => ({
|
|||||||
async update(uid, entityId, opts) {
|
async update(uid, entityId, opts) {
|
||||||
const { params, data, files } = await this.wrapOptions(opts, { uid, action: 'update' });
|
const { params, data, files } = await this.wrapOptions(opts, { uid, action: 'update' });
|
||||||
|
|
||||||
const modelDef = strapi.getModel(uid);
|
const model = strapi.getModel(uid);
|
||||||
|
|
||||||
// const existingEntry = await db.query(uid).findOne({ where: { id: entityId } });
|
const existingEntry = await db.query(uid).findOne({ where: { id: entityId } });
|
||||||
|
|
||||||
// const isDraft = contentTypesUtils.isDraft(existingEntry, modelDef);
|
const isDraft = contentTypesUtils.isDraft(existingEntry, model);
|
||||||
|
|
||||||
// TODO: validate
|
const validData = await entityValidator.validateEntityUpdate(model, data, {
|
||||||
// // const validData = await entityValidator.validateEntityUpdate(modelDef, data, {
|
isDraft,
|
||||||
// // isDraft,
|
|
||||||
// // });
|
|
||||||
|
|
||||||
// select / populate
|
|
||||||
const query = transformParamsToQuery(pickSelectionParams(params));
|
|
||||||
|
|
||||||
// TODO: wrap in transaction
|
|
||||||
|
|
||||||
const componentData = await updateComponents(uid, data);
|
|
||||||
|
|
||||||
let entry = await db.query(uid).update({
|
|
||||||
...query,
|
|
||||||
where: { id: entityId },
|
|
||||||
data: Object.assign(data, componentData),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO: implement files
|
const query = transformParamsToQuery(uid, pickSelectionParams(params));
|
||||||
|
|
||||||
|
// TODO: wrap in transaction
|
||||||
|
const componentData = await updateComponents(uid, entityId, validData);
|
||||||
|
|
||||||
|
const entity = await db.query(uid).update({
|
||||||
|
...query,
|
||||||
|
where: { id: entityId },
|
||||||
|
data: Object.assign(validData, componentData),
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO: implement files outside of the entity service
|
||||||
// if (files && Object.keys(files).length > 0) {
|
// if (files && Object.keys(files).length > 0) {
|
||||||
// await this.uploadFiles(entry, files, { model });
|
// await this.uploadFiles(entry, files, { model });
|
||||||
// entry = await this.findOne({ params: { id: entry.id } }, { model });
|
// entry = await this.findOne({ params: { id: entry.id } }, { model });
|
||||||
// }
|
// }
|
||||||
|
|
||||||
eventHub.emit(ENTRY_UPDATE, {
|
this.emitEvent(uid, ENTRY_UPDATE, entity);
|
||||||
model: modelDef.modelName,
|
|
||||||
entry: sanitizeEntity(entry, { model: modelDef }),
|
|
||||||
});
|
|
||||||
|
|
||||||
return entry;
|
return entity;
|
||||||
},
|
},
|
||||||
|
|
||||||
async delete(uid, entityId, opts) {
|
async delete(uid, entityId, opts) {
|
||||||
const { params } = await this.wrapOptions(opts, { uid, action: 'delete' });
|
const { params } = await this.wrapOptions(opts, { uid, action: 'delete' });
|
||||||
|
|
||||||
// select / populate
|
// select / populate
|
||||||
const query = transformParamsToQuery(pickSelectionParams(params));
|
const query = transformParamsToQuery(uid, pickSelectionParams(params));
|
||||||
|
|
||||||
const entry = await db.query(uid).delete({ ...query, where: { id: entityId } });
|
const entity = await db.query(uid).findOne({
|
||||||
|
...query,
|
||||||
const modelDef = strapi.getModel(uid);
|
where: { id: entityId },
|
||||||
eventHub.emit(ENTRY_DELETE, {
|
|
||||||
model: modelDef.modelName,
|
|
||||||
entry: sanitizeEntity(entry, { model: modelDef }),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return entry;
|
if (!entity) {
|
||||||
|
throw new Error('Entity not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
await deleteComponents(uid, entityId);
|
||||||
|
await db.query(uid).delete({ where: { id: entity.id } });
|
||||||
|
|
||||||
|
this.emitEvent(uid, ENTRY_DELETE, entity);
|
||||||
|
|
||||||
|
return entity;
|
||||||
},
|
},
|
||||||
|
|
||||||
async deleteMany(uid, opts) {
|
async deleteMany(uid, opts) {
|
||||||
const { params } = await this.wrapOptions(opts, { uid, action: 'delete' });
|
const { params } = await this.wrapOptions(opts, { uid, action: 'delete' });
|
||||||
|
|
||||||
// select / populate
|
// select / populate
|
||||||
const query = transformParamsToQuery(pickSelectionParams(params));
|
const query = transformParamsToQuery(uid, pickSelectionParams(params));
|
||||||
|
|
||||||
return db.query(uid).deleteMany(query);
|
return db.query(uid).deleteMany(query);
|
||||||
},
|
},
|
||||||
|
|
||||||
// TODO: Implement search features
|
// TODO: Implement search features
|
||||||
|
|
||||||
async search(uid, opts) {
|
async search(uid, opts) {
|
||||||
const { params, populate } = await this.wrapOptions(opts, { uid, action: 'search' });
|
const { params, populate } = await this.wrapOptions(opts, { uid, action: 'search' });
|
||||||
|
|
||||||
@ -350,6 +370,7 @@ const createComponents = async (uid, data) => {
|
|||||||
const updateOrCreateComponent = (componentUID, value) => {
|
const updateOrCreateComponent = (componentUID, value) => {
|
||||||
// update
|
// update
|
||||||
if (has('id', value)) {
|
if (has('id', value)) {
|
||||||
|
// TODO: verify the compo is associated with the entity
|
||||||
return strapi.query(componentUID).update({ where: { id: value.id }, data: value });
|
return strapi.query(componentUID).update({ where: { id: value.id }, data: value });
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -357,9 +378,8 @@ const updateOrCreateComponent = (componentUID, value) => {
|
|||||||
return strapi.query(componentUID).create({ data: value });
|
return strapi.query(componentUID).create({ data: value });
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateComponents = async (uid, data) => {
|
// TODO: delete old components
|
||||||
// TODO: clear old -> done in the updateRelation
|
const updateComponents = async (uid, entityId, data) => {
|
||||||
|
|
||||||
const { attributes } = strapi.getModel(uid);
|
const { attributes } = strapi.getModel(uid);
|
||||||
|
|
||||||
for (const attributeName in attributes) {
|
for (const attributeName in attributes) {
|
||||||
@ -372,8 +392,12 @@ const updateComponents = async (uid, data) => {
|
|||||||
if (attribute.type === 'component') {
|
if (attribute.type === 'component') {
|
||||||
const { component: componentUID, repeatable = false } = attribute;
|
const { component: componentUID, repeatable = false } = attribute;
|
||||||
|
|
||||||
|
const previousValue = await strapi.query(uid).load(entityId, attributeName);
|
||||||
const componentValue = data[attributeName];
|
const componentValue = data[attributeName];
|
||||||
|
|
||||||
|
// TODO: diff prev & new
|
||||||
|
|
||||||
|
// make diff between prev ids & data ids
|
||||||
if (componentValue === null) {
|
if (componentValue === null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -423,3 +447,39 @@ const updateComponents = async (uid, data) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const deleteComponents = async (uid, entityId) => {
|
||||||
|
const { attributes } = strapi.getModel(uid);
|
||||||
|
|
||||||
|
// TODO: find components and then delete them
|
||||||
|
for (const attributeName in attributes) {
|
||||||
|
const attribute = attributes[attributeName];
|
||||||
|
|
||||||
|
if (attribute.type === 'component') {
|
||||||
|
const { component: componentUID } = attribute;
|
||||||
|
|
||||||
|
// TODO: need to load before deleting the entry then delete the components then the entry
|
||||||
|
const value = await strapi.query(uid).load(entityId, attributeName);
|
||||||
|
|
||||||
|
if (!value) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
await Promise.all(
|
||||||
|
value.map(subValue => {
|
||||||
|
return strapi.query(componentUID).delete({ where: { id: subValue.id } });
|
||||||
|
})
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
await strapi.query(componentUID).delete({ where: { id: value.id } });
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attribute.type === 'dynamiczone') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
@ -80,6 +80,9 @@ describe('Core API - Basic + compo + draftAndPublish', () => {
|
|||||||
method: 'POST',
|
method: 'POST',
|
||||||
url: '/product-with-compo-and-dps',
|
url: '/product-with-compo-and-dps',
|
||||||
body: product,
|
body: product,
|
||||||
|
qs: {
|
||||||
|
populate: ['compo'],
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(res.statusCode).toBe(200);
|
expect(res.statusCode).toBe(200);
|
||||||
@ -92,6 +95,9 @@ describe('Core API - Basic + compo + draftAndPublish', () => {
|
|||||||
const res = await rq({
|
const res = await rq({
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
url: '/product-with-compo-and-dps',
|
url: '/product-with-compo-and-dps',
|
||||||
|
qs: {
|
||||||
|
populate: ['compo'],
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(res.statusCode).toBe(200);
|
expect(res.statusCode).toBe(200);
|
||||||
@ -118,6 +124,9 @@ describe('Core API - Basic + compo + draftAndPublish', () => {
|
|||||||
method: 'PUT',
|
method: 'PUT',
|
||||||
url: `/product-with-compo-and-dps/${data.productsWithCompoAndDP[0].id}`,
|
url: `/product-with-compo-and-dps/${data.productsWithCompoAndDP[0].id}`,
|
||||||
body: product,
|
body: product,
|
||||||
|
qs: {
|
||||||
|
populate: ['compo'],
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(res.statusCode).toBe(200);
|
expect(res.statusCode).toBe(200);
|
||||||
@ -131,6 +140,9 @@ describe('Core API - Basic + compo + draftAndPublish', () => {
|
|||||||
const res = await rq({
|
const res = await rq({
|
||||||
method: 'DELETE',
|
method: 'DELETE',
|
||||||
url: `/product-with-compo-and-dps/${data.productsWithCompoAndDP[0].id}`,
|
url: `/product-with-compo-and-dps/${data.productsWithCompoAndDP[0].id}`,
|
||||||
|
qs: {
|
||||||
|
populate: ['compo'],
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(res.statusCode).toBe(200);
|
expect(res.statusCode).toBe(200);
|
||||||
|
@ -77,6 +77,9 @@ describe('Core API - Basic + compo + draftAndPublish', () => {
|
|||||||
method: 'POST',
|
method: 'POST',
|
||||||
url: '/product-with-compo-and-dps',
|
url: '/product-with-compo-and-dps',
|
||||||
body: product,
|
body: product,
|
||||||
|
qs: {
|
||||||
|
populate: ['compo'],
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(res.statusCode).toBe(200);
|
expect(res.statusCode).toBe(200);
|
||||||
@ -89,6 +92,9 @@ describe('Core API - Basic + compo + draftAndPublish', () => {
|
|||||||
const res = await rq({
|
const res = await rq({
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
url: '/product-with-compo-and-dps',
|
url: '/product-with-compo-and-dps',
|
||||||
|
qs: {
|
||||||
|
populate: ['compo'],
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(res.statusCode).toBe(200);
|
expect(res.statusCode).toBe(200);
|
||||||
@ -113,6 +119,9 @@ describe('Core API - Basic + compo + draftAndPublish', () => {
|
|||||||
method: 'PUT',
|
method: 'PUT',
|
||||||
url: `/product-with-compo-and-dps/${data.productsWithCompoAndDP[0].id}`,
|
url: `/product-with-compo-and-dps/${data.productsWithCompoAndDP[0].id}`,
|
||||||
body: product,
|
body: product,
|
||||||
|
qs: {
|
||||||
|
populate: ['compo'],
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(res.statusCode).toBe(200);
|
expect(res.statusCode).toBe(200);
|
||||||
@ -126,6 +135,9 @@ describe('Core API - Basic + compo + draftAndPublish', () => {
|
|||||||
const res = await rq({
|
const res = await rq({
|
||||||
method: 'DELETE',
|
method: 'DELETE',
|
||||||
url: `/product-with-compo-and-dps/${data.productsWithCompoAndDP[0].id}`,
|
url: `/product-with-compo-and-dps/${data.productsWithCompoAndDP[0].id}`,
|
||||||
|
qs: {
|
||||||
|
populate: ['compo'],
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(res.statusCode).toBe(200);
|
expect(res.statusCode).toBe(200);
|
||||||
|
@ -122,7 +122,7 @@ const lengthFor = (name, { mode = 'live' } = {}) => {
|
|||||||
|
|
||||||
const getQueryFromMode = mode => {
|
const getQueryFromMode = mode => {
|
||||||
if (['live', 'preview'].includes(mode)) {
|
if (['live', 'preview'].includes(mode)) {
|
||||||
return `?_publicationState=${mode}`;
|
return `?publicationState=${mode}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
return '';
|
return '';
|
||||||
@ -188,7 +188,10 @@ describe('Publication State', () => {
|
|||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
const res = await rq({
|
const res = await rq({
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
url: `/${pluralizedModelName}?_publicationState=live`,
|
url: `/${pluralizedModelName}?publicationState=live`,
|
||||||
|
qs: {
|
||||||
|
populate: ['categories', 'comp.countries'],
|
||||||
|
},
|
||||||
});
|
});
|
||||||
products = res.body;
|
products = res.body;
|
||||||
});
|
});
|
||||||
|
@ -168,9 +168,42 @@ const createContentType = (model, { modelName }, { apiName, pluginName } = {}) =
|
|||||||
get() {
|
get() {
|
||||||
// FIXME: to fix
|
// FIXME: to fix
|
||||||
// return strapi.getModel(model.uid).privateAttributes;
|
// return strapi.getModel(model.uid).privateAttributes;
|
||||||
return []
|
return [];
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (hasDraftAndPublish(model)) {
|
||||||
|
model.attributes[PUBLISHED_AT_ATTRIBUTE] = {
|
||||||
|
type: 'datetime',
|
||||||
|
configurable: false,
|
||||||
|
writable: true,
|
||||||
|
visible: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const isPrivate = !_.get(model, 'options.populateCreatorFields', false);
|
||||||
|
|
||||||
|
model.attributes[CREATED_BY_ATTRIBUTE] = {
|
||||||
|
type: 'relation',
|
||||||
|
relation: 'oneToOne',
|
||||||
|
target: 'strapi::user',
|
||||||
|
configurable: false,
|
||||||
|
writable: false,
|
||||||
|
visible: false,
|
||||||
|
useJoinTable: false,
|
||||||
|
private: isPrivate,
|
||||||
|
};
|
||||||
|
|
||||||
|
model.attributes[UPDATED_BY_ATTRIBUTE] = {
|
||||||
|
type: 'relation',
|
||||||
|
relation: 'oneToOne',
|
||||||
|
target: 'strapi::user',
|
||||||
|
configurable: false,
|
||||||
|
writable: false,
|
||||||
|
visible: false,
|
||||||
|
useJoinTable: false,
|
||||||
|
private: isPrivate,
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const getGlobalId = (model, modelName, prefix) => {
|
const getGlobalId = (model, modelName, prefix) => {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user