diff --git a/packages/strapi-mongoose/lib/index.js b/packages/strapi-mongoose/lib/index.js index 38ec0c4436..9711382ffe 100644 --- a/packages/strapi-mongoose/lib/index.js +++ b/packages/strapi-mongoose/lib/index.js @@ -147,8 +147,10 @@ module.exports = function (strapi) { // Push model to strapi global variables. collection = global[definition.globalName]; + console.log(collection.associations); + // Push attributes to be aware of model schema. - collection._attributes = definition.attributes; + strapi.models[model]._attributes = definition.attributes; } catch (err) { strapi.log.error('Impossible to register the `' + model + '` model.'); strapi.log.error(err); @@ -248,13 +250,18 @@ module.exports = function (strapi) { case 'belongsTo': FK = _.find(definition.associations, {alias: name}); - if (FK && FK.nature === 'oneToOne') { + console.log(name, FK); + + if (FK && FK.nature !== 'oneToOne' && FK.nature !== 'oneToMany') { definition.loadedModel[name] = { type: 'virtual', ref: _.capitalize(details.model), via: FK.via, justOne: true }; + + // Set this info to be able to see if this field is a real database's field. + details.isVirtual = true; } else { definition.loadedModel[name] = { type: mongoose.Schema.Types.ObjectId, diff --git a/packages/strapi-plugin-content-manager/admin/src/components/SelectMany/index.js b/packages/strapi-plugin-content-manager/admin/src/components/SelectMany/index.js index a54ee7758e..58b2701d96 100644 --- a/packages/strapi-plugin-content-manager/admin/src/components/SelectMany/index.js +++ b/packages/strapi-plugin-content-manager/admin/src/components/SelectMany/index.js @@ -7,7 +7,7 @@ import React from 'react'; import Select from 'react-select'; import 'react-select/dist/react-select.css'; -import { isArray, isNull, isUndefined } from 'lodash'; +import { isArray, isNull, isUndefined, get } from 'lodash'; import request from 'utils/request'; import templateObject from 'utils/templateObject'; @@ -58,6 +58,8 @@ class SelectMany extends React.Component { // eslint-disable-line react/prefer-s label: response[this.props.relation.displayedAttribute], }]; + console.log(options); + return { options }; }); } @@ -79,7 +81,7 @@ class SelectMany extends React.Component { // eslint-disable-line react/prefer-s loadOptions={this.getOptions} multi value={isNull(value) || isUndefined(value) || value.size === 0 ? null : value.toJS().map(item => ({ - value: item, + value: get(item, 'value') || item, label: item.label || templateObject({ mainField: this.props.relation.displayedAttribute }, item).mainField, }))} /> diff --git a/packages/strapi-plugin-content-manager/admin/src/components/SelectOne/index.js b/packages/strapi-plugin-content-manager/admin/src/components/SelectOne/index.js index d21f520b55..a6c6974aed 100644 --- a/packages/strapi-plugin-content-manager/admin/src/components/SelectOne/index.js +++ b/packages/strapi-plugin-content-manager/admin/src/components/SelectOne/index.js @@ -51,11 +51,11 @@ class SelectOne extends React.Component { // eslint-disable-line react/prefer-st const options = isArray(response) ? map(response, item => ({ value: item, - label: item[this.props.relation.displayedAttribute], + label: templateObject({ mainField: this.props.relation.displayedAttribute }, item).mainField, })) : [{ value: response, - label: response[this.props.relation.displayedAttribute], + label: templateObject({ mainField: this.props.relation.displayedAttribute }, response).mainField, }]; return {options}; @@ -79,7 +79,7 @@ class SelectOne extends React.Component { // eslint-disable-line react/prefer-st loadOptions={this.getOptions} simpleValue value={isNull(value) || isUndefined(value) ? null : { - value: value.toJS().id, + value: value.toJS(), label: templateObject({ mainField: this.props.relation.displayedAttribute }, value.toJS()).mainField, }} /> diff --git a/packages/strapi-plugin-content-manager/admin/src/containers/Edit/index.js b/packages/strapi-plugin-content-manager/admin/src/containers/Edit/index.js index 0bc549cf0f..82c9bc0aa8 100644 --- a/packages/strapi-plugin-content-manager/admin/src/containers/Edit/index.js +++ b/packages/strapi-plugin-content-manager/admin/src/containers/Edit/index.js @@ -68,15 +68,10 @@ export class Edit extends React.Component { if (this.props.match.params.id === 'create') { this.props.setIsCreating(); } else { - console.log("LOAD RECORD"); this.props.loadRecord(this.props.match.params.id); } } - componentWillUnmount() { - console.log("UNMOUNTED"); - } - handleChange = (e) => { if (isObject(e.target.value) && e.target.value._isAMomentObject === true) { e.target.value = moment(e.target.value, 'YYYY-MM-DD HH:mm:ss').format(); diff --git a/packages/strapi-plugin-content-manager/admin/src/containers/Edit/sagas.js b/packages/strapi-plugin-content-manager/admin/src/containers/Edit/sagas.js index aed233efa8..bc1dfe5c43 100644 --- a/packages/strapi-plugin-content-manager/admin/src/containers/Edit/sagas.js +++ b/packages/strapi-plugin-content-manager/admin/src/containers/Edit/sagas.js @@ -42,6 +42,7 @@ export function* editRecord() { const recordJSON = record.toJSON(); const recordCleaned = Object.keys(recordJSON).reduce((acc, current) => { + console.log(recordJSON[current]); acc[current] = cleanData(recordJSON[current], 'value', 'id'); return acc; @@ -72,7 +73,6 @@ export function* editRecord() { } export function* deleteRecord({ id, modelName }) { - console.log(id, modelName); function* httpCall(id, modelName) { try { const requestUrl = `${window.Strapi.apiUrl}/content-manager/explorer/${modelName}/${id}`; diff --git a/packages/strapi-plugin-content-manager/config/queries/mongoose.js b/packages/strapi-plugin-content-manager/config/queries/mongoose.js index a268779a90..8512ad99a5 100644 --- a/packages/strapi-plugin-content-manager/config/queries/mongoose.js +++ b/packages/strapi-plugin-content-manager/config/queries/mongoose.js @@ -23,21 +23,128 @@ module.exports = { }, create: async function (params) { - return await this + return this .create(params.values); }, update: async function (params) { - return await this + const virtualFields = []; + const response = await module.exports.findOne.call(this, params); + + console.log(); + console.log("UPDATE"); + console.log(params); + console.log(response); + + console.log(this.associations); + console.log(); + + // Only update fields which are on this document. + const values = Object.keys(JSON.parse(JSON.stringify(params.values))).reduce((acc, current) => { + const association = this.associations.filter(x => x.alias === current)[0]; + const details = this._attributes[current]; + + if (_.get(this._attributes, `${current}.isVirtual`) !== true && _.isUndefined(association)) { + acc[current] = params.values[current]; + } else { + switch (association.nature) { + case 'oneToOne': + if (!_.isUndefined(response[current]) && response[current] !== params.values[current]) { + const value = _.isNull(response[current]) ? params.values : response[current]; + + delete value[details.via]; + + // Update the record on the other side. + // When params.values[current] is null this means that we are removing the relation. + virtualFields.push(strapi.query(details.model || details.collection).update({ + id: _.isNull(params.values[current]) ? value[this.primaryKey] || value.id || value._id : params.values[current], + values: { + [details.via]: _.isNull(params.values[current]) ? null : value[this.primaryKey] || value.id || value._id + } + })); + + acc[current] = _.isNull(params.values[current]) ? null : params.values[current]; + } + + break; + case 'oneToMany': + case 'manyToMany': + if (details.dominant === true) { + acc[current] = params.values[current]; + } else if (response[current] && _.isArray(response[current]) && current !== 'id') { + // Records to add in the relation. + const toAdd = _.differenceWith(params.values[current], response[current], (a, b) => + a[this.primaryKey].toString() === b[this.primaryKey].toString() + ); + // Records to remove in the relation. + const toRemove = _.differenceWith(response[current], params.values[current], (a, b) => + a[this.primaryKey].toString() === b[this.primaryKey].toString() + ) + .filter(x => toAdd.find(y => x.id === y.id) === undefined); + + console.log("ADD"); + console.log(toAdd); + console.log("REMOVE"); + console.log(toRemove); + console.log('-----------'); + + // Push the work into the flow process. + toAdd.forEach(value => { + if (association.nature === 'manyToMany' && !_.isArray(params.values[this.primaryKey])) { + value[details.via] = (response[current] === null ? [] : response[current]).concat([params.values[this.primaryKey]]); + } else { + value[details.via] = params.values[this.primaryKey]; + } + + virtualFields.push(strapi.query(details.model || details.collection).addRelation({ + id: value[this.primaryKey] || value.id || value._id, + values: value, + foreignKey: current + })); + }); + + toRemove.forEach(value => { + if (association.nature === 'manyToMany' && !_.isArray(params.values[this.primaryKey])) { + value[details.via] = value[details.via].filter(x => x.toString() !== params.values[this.primaryKey].toString()); + } else { + value[details.via] = params.values[this.primaryKey]; + } + + virtualFields.push(strapi.query(details.model || details.collection).removeRelation({ + id: value[this.primaryKey] || value.id || value._id, + values: value, + foreignKey: current + })); + }); + } else if (_.get(this._attributes, `${current}.isVirtual`) !== true) { + acc[current] = params.values[current]; + } + + break; + default: + } + } + + return acc; + }, {}); + + console.log(values); + + virtualFields.push(this .update({ [this.primaryKey]: params.id - }, params.values, { + }, values, { strict: false - }); + })); + + // Update virtuals fields. + const process = await Promise.all(virtualFields); + + return process[process.length - 1]; }, delete: async function (params) { - return await this + return this .remove({ [this.primaryKey]: params.id }); diff --git a/packages/strapi-plugin-content-manager/controllers/ContentManager.js b/packages/strapi-plugin-content-manager/controllers/ContentManager.js index 4e260cb404..3ebccd5df8 100644 --- a/packages/strapi-plugin-content-manager/controllers/ContentManager.js +++ b/packages/strapi-plugin-content-manager/controllers/ContentManager.js @@ -73,86 +73,14 @@ module.exports = { }, update: async ctx => { - const virtualFields = []; - const params = { + // Add current model to the flow of updates. + const entry = strapi.query(ctx.params.model).update({ id: ctx.params.id, values: ctx.request.body - }; - - // Retrieve current record. - const response = await strapi.query(ctx.params.model).findOne(params) || {}; - // Save current model into variable to get virtual and p - const model = strapi.models[ctx.params.model]; - - // Only update fields which are on this document. - const values = Object.keys(params.values).reduce((acc, current) => { - const association = model.associations.filter(x => x.alias === current)[0]; - - if (_.get(model._attributes, `${current}.isVirtual`) !== true && _.isUndefined(association)) { - acc[current] = params.values[current]; - } else if (!_.isUndefined(response[current]) && _.isPlainObject(association) && association.nature === 'oneToOne') { - if (response[current] !== params.values[current]) { - - const details = model.attributes[current]; - const value = _.isNull(response[current]) ? params.values : response[current]; - - delete value[details.via]; - - virtualFields.push(strapi.query(details.model || details.collection).update({ - id: value[model.primaryKey] || value.id || value._id, - values: { - [details.via]: params.values[current] - } - })); - - acc[current] = _.isNull(params.values[current]) ? null : value[model.primaryKey] || value.id || value._id; - } - } else if (response[current] && _.isArray(response[current]) && current !== 'id'){ - const details = model.attributes[current]; - - const toAdd = _.differenceWith(params.values[current], response[current], (a, b) => - a[model.primaryKey].toString() === b[model.primaryKey].toString() - ); - const toRemove = _.differenceWith(response[current], params.values[current], (a, b) => - a[model.primaryKey].toString() === b[model.primaryKey].toString() - ) - .filter(x => toAdd.find(y => x.id === y.id) === undefined); - - toAdd.forEach(value => { - value[details.via] = params.values[model.primaryKey]; - - virtualFields.push(strapi.query(details.model || details.collection).addRelation({ - id: value[model.primaryKey] || value.id || value._id, - values: value, - foreignKey: current - })); - }); - - toRemove.forEach(value => { - value[details.via] = null; - - virtualFields.push(strapi.query(details.model || details.collection).removeRelation({ - id: value[model.primaryKey] || value.id || value._id, - values: value, - foreignKey: current - })); - }); - } - - return acc; - }, {}); - - // Add current model to the flow of updates. - virtualFields.push(strapi.query(ctx.params.model).update({ - id: params.id, - values - })); - - // Update virtuals fields. - const process = await Promise.all(virtualFields); + }); // Return the last one which is the current model. - ctx.body = process[process.length - 1]; + ctx.body = entry; }, delete: async ctx => {