| 
									
										
										
										
											2016-03-18 11:12:50 +01:00
										 |  |  |  | 'use strict'; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /** | 
					
						
							|  |  |  |  |  * Module dependencies | 
					
						
							|  |  |  |  |  */ | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-30 15:04:21 +01:00
										 |  |  |  | // Core
 | 
					
						
							|  |  |  |  | const path = require('path'); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-18 11:12:50 +01:00
										 |  |  |  | // Public node modules.
 | 
					
						
							|  |  |  |  | const _ = require('lodash'); | 
					
						
							|  |  |  |  | const bookshelf = require('bookshelf'); | 
					
						
							|  |  |  |  | const pluralize = require('pluralize'); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // Local helpers.
 | 
					
						
							|  |  |  |  | const utils = require('./utils/'); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // Strapi helpers for models.
 | 
					
						
							| 
									
										
										
										
											2016-10-31 12:51:05 +01:00
										 |  |  |  | const utilsModels = require('strapi-utils').models; | 
					
						
							| 
									
										
										
										
											2016-03-18 11:12:50 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-15 14:43:09 +01:00
										 |  |  |  | const PIVOT_PREFIX = '_pivot_'; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-18 11:12:50 +01:00
										 |  |  |  | /** | 
					
						
							|  |  |  |  |  * Bookshelf hook | 
					
						
							|  |  |  |  |  */ | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-11 11:56:31 +02:00
										 |  |  |  | module.exports = function(strapi) { | 
					
						
							| 
									
										
										
										
											2016-03-18 11:12:50 +01:00
										 |  |  |  |   const hook = { | 
					
						
							|  |  |  |  |     /** | 
					
						
							|  |  |  |  |      * Default options | 
					
						
							|  |  |  |  |      */ | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     defaults: { | 
					
						
							| 
									
										
										
										
											2017-01-04 17:21:24 +01:00
										 |  |  |  |       defaultConnection: 'default', | 
					
						
							|  |  |  |  |       host: 'localhost' | 
					
						
							| 
									
										
										
										
											2016-03-18 11:12:50 +01:00
										 |  |  |  |     }, | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     /** | 
					
						
							|  |  |  |  |      * Initialize the hook | 
					
						
							|  |  |  |  |      */ | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-07 16:31:34 +01:00
										 |  |  |  |     initialize: cb => { | 
					
						
							| 
									
										
										
										
											2016-03-18 11:12:50 +01:00
										 |  |  |  |       let globalName; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-24 19:58:03 +02:00
										 |  |  |  |       // Initialize collections
 | 
					
						
							|  |  |  |  |       _.set(strapi, 'bookshelf.collections', {}); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       // Return callback if there is no model
 | 
					
						
							|  |  |  |  |       if (_.isEmpty(strapi.models)) { | 
					
						
							|  |  |  |  |         return cb(); | 
					
						
							| 
									
										
										
										
											2016-07-06 12:16:31 +02:00
										 |  |  |  |       } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-24 19:58:03 +02:00
										 |  |  |  |       const connections = _.pickBy(strapi.config.connections, { | 
					
						
							|  |  |  |  |         connector: 'strapi-bookshelf' | 
					
						
							|  |  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2016-03-18 11:12:50 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-24 19:58:03 +02:00
										 |  |  |  |       const done = _.after(_.size(connections), () => { | 
					
						
							|  |  |  |  |         cb(); | 
					
						
							|  |  |  |  |       }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       _.forEach(connections, (connection, connectionName) => { | 
					
						
							|  |  |  |  |         // Apply defaults
 | 
					
						
							| 
									
										
										
										
											2017-07-26 18:53:48 +02:00
										 |  |  |  |         _.defaults(connection.settings, strapi.config.hook.settings.bookshelf); | 
					
						
							| 
									
										
										
										
											2017-07-24 19:58:03 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |         // Create Bookshelf instance for this connection.
 | 
					
						
							|  |  |  |  |         const ORM = new bookshelf(strapi.connections[connectionName]); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         try { | 
					
						
							|  |  |  |  |           // Require `config/functions/bookshelf.js` file to customize connection.
 | 
					
						
							|  |  |  |  |           require(path.resolve( | 
					
						
							|  |  |  |  |             strapi.config.appPath, | 
					
						
							|  |  |  |  |             'config', | 
					
						
							|  |  |  |  |             'functions', | 
					
						
							|  |  |  |  |             'bookshelf.js' | 
					
						
							|  |  |  |  |           ))(ORM, strapi.connections[connectionName]); | 
					
						
							|  |  |  |  |         } catch (err) { | 
					
						
							|  |  |  |  |           // This is not an error if the file is not found.
 | 
					
						
							| 
									
										
										
										
											2016-03-18 11:12:50 +01:00
										 |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-24 19:58:03 +02:00
										 |  |  |  |         // Load plugins
 | 
					
						
							|  |  |  |  |         if (_.get(connection, 'options.plugins') !== false) { | 
					
						
							|  |  |  |  |           ORM.plugin('visibility'); | 
					
						
							|  |  |  |  |           ORM.plugin('pagination'); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         // Select models concerned by this connection
 | 
					
						
							|  |  |  |  |         const models = _.pickBy(strapi.models, { | 
					
						
							|  |  |  |  |           connection: connectionName | 
					
						
							| 
									
										
										
										
											2017-04-11 11:56:31 +02:00
										 |  |  |  |         }); | 
					
						
							| 
									
										
										
										
											2017-01-24 13:01:09 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-24 19:58:03 +02:00
										 |  |  |  |         // Return callback if there is no model
 | 
					
						
							|  |  |  |  |         if (_.isEmpty(models)) { | 
					
						
							| 
									
										
										
										
											2017-01-24 13:01:09 +01:00
										 |  |  |  |           cb(); | 
					
						
							| 
									
										
										
										
											2017-07-24 19:58:03 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |           // Break the loop.
 | 
					
						
							|  |  |  |  |           return false; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         const loadedHook = _.after(_.size(models), () => { | 
					
						
							|  |  |  |  |           done(); | 
					
						
							| 
									
										
										
										
											2017-01-24 13:01:09 +01:00
										 |  |  |  |         }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-24 19:58:03 +02:00
										 |  |  |  |         // Parse every registered model.
 | 
					
						
							|  |  |  |  |         _.forEach(models, (definition, model) => { | 
					
						
							|  |  |  |  |           globalName = _.upperFirst(_.camelCase(definition.globalId)); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-14 16:33:56 +02:00
										 |  |  |  |           _.defaults(definition, { | 
					
						
							|  |  |  |  |             primaryKey: 'id' | 
					
						
							|  |  |  |  |           }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-24 19:58:03 +02:00
										 |  |  |  |           // Make sure the model has a table name.
 | 
					
						
							|  |  |  |  |           // If not, use the model name.
 | 
					
						
							| 
									
										
										
										
											2017-07-28 16:31:23 +02:00
										 |  |  |  |           if (_.isEmpty(definition.collectionName)) { | 
					
						
							|  |  |  |  |             definition.collectionName = model; | 
					
						
							| 
									
										
										
										
											2017-01-30 15:15:22 +01:00
										 |  |  |  |           } | 
					
						
							| 
									
										
										
										
											2017-01-30 15:04:21 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-24 19:58:03 +02:00
										 |  |  |  |           // Add some informations about ORM & client connection
 | 
					
						
							|  |  |  |  |           definition.orm = 'bookshelf'; | 
					
						
							|  |  |  |  |           definition.client = _.get(connection.settings, 'client'); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |           // Register the final model for Bookshelf.
 | 
					
						
							|  |  |  |  |           const loadedModel = _.assign( | 
					
						
							|  |  |  |  |             { | 
					
						
							| 
									
										
										
										
											2017-07-28 16:31:23 +02:00
										 |  |  |  |               tableName: definition.collectionName, | 
					
						
							| 
									
										
										
										
											2017-07-24 19:58:03 +02:00
										 |  |  |  |               hasTimestamps: _.get(definition, 'options.timestamps') === true, | 
					
						
							|  |  |  |  |               idAttribute: _.get(definition, 'options.idAttribute') || 'id' | 
					
						
							|  |  |  |  |             }, | 
					
						
							|  |  |  |  |             definition.options | 
					
						
							|  |  |  |  |           ); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |           if (_.isString(_.get(connection, 'options.pivot_prefix'))) { | 
					
						
							|  |  |  |  |             loadedModel.toJSON = function(options = {}) { | 
					
						
							|  |  |  |  |               const { shallow = false, omitPivot = false } = options; | 
					
						
							|  |  |  |  |               const attributes = this.serialize(options); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |               if (!shallow) { | 
					
						
							|  |  |  |  |                 const pivot = this.pivot && | 
					
						
							|  |  |  |  |                   !omitPivot && | 
					
						
							|  |  |  |  |                   this.pivot.attributes; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |                 // Remove pivot attributes with prefix.
 | 
					
						
							|  |  |  |  |                 _.keys(pivot).forEach( | 
					
						
							|  |  |  |  |                   key => delete attributes[`${PIVOT_PREFIX}${key}`] | 
					
						
							|  |  |  |  |                 ); | 
					
						
							| 
									
										
										
										
											2016-03-18 11:12:50 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-24 19:58:03 +02:00
										 |  |  |  |                 // Add pivot attributes without prefix.
 | 
					
						
							|  |  |  |  |                 const pivotAttributes = _.mapKeys( | 
					
						
							|  |  |  |  |                   pivot, | 
					
						
							|  |  |  |  |                   (value, key) => `${connection.options.pivot_prefix}${key}` | 
					
						
							|  |  |  |  |                 ); | 
					
						
							| 
									
										
										
										
											2017-02-14 14:34:01 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-24 19:58:03 +02:00
										 |  |  |  |                 return Object.assign({}, attributes, pivotAttributes); | 
					
						
							|  |  |  |  |               } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |               return attributes; | 
					
						
							|  |  |  |  |             }; | 
					
						
							| 
									
										
										
										
											2016-03-18 11:12:50 +01:00
										 |  |  |  |           } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-24 19:58:03 +02:00
										 |  |  |  |           // Initialize the global variable with the
 | 
					
						
							|  |  |  |  |           // capitalized model name.
 | 
					
						
							|  |  |  |  |           global[globalName] = {}; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |           // Call this callback function after we are done parsing
 | 
					
						
							|  |  |  |  |           // all attributes for relationships-- see below.
 | 
					
						
							|  |  |  |  |           const done = _.after(_.size(definition.attributes), () => { | 
					
						
							|  |  |  |  |             try { | 
					
						
							|  |  |  |  |               // External function to map key that has been updated with `columnName`
 | 
					
						
							|  |  |  |  |               const mapper = (params = {}) => | 
					
						
							|  |  |  |  |                 _.mapKeys(params, (value, key) => { | 
					
						
							|  |  |  |  |                   const attr = definition.attributes[key] || {}; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |                   return _.isPlainObject(attr) && | 
					
						
							|  |  |  |  |                     _.isString(attr['columnName']) | 
					
						
							|  |  |  |  |                     ? attr['columnName'] | 
					
						
							|  |  |  |  |                     : key; | 
					
						
							|  |  |  |  |                 }); | 
					
						
							| 
									
										
										
										
											2016-03-18 11:12:50 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-24 19:58:03 +02:00
										 |  |  |  |               // Initialize lifecycle callbacks.
 | 
					
						
							|  |  |  |  |               loadedModel.initialize = function() { | 
					
						
							|  |  |  |  |                 const lifecycle = { | 
					
						
							|  |  |  |  |                   creating: 'beforeCreate', | 
					
						
							|  |  |  |  |                   created: 'afterCreate', | 
					
						
							|  |  |  |  |                   destroying: 'beforeDestroy', | 
					
						
							|  |  |  |  |                   destroyed: 'afterDestroy', | 
					
						
							|  |  |  |  |                   updating: 'beforeUpdate', | 
					
						
							|  |  |  |  |                   updated: 'afterUpdate', | 
					
						
							|  |  |  |  |                   fetching: 'beforeFetch', | 
					
						
							|  |  |  |  |                   'fetching:collection': 'beforeFetchCollection', | 
					
						
							|  |  |  |  |                   fetched: 'afterFetch', | 
					
						
							|  |  |  |  |                   'fetched:collection': 'afterFetchCollection', | 
					
						
							|  |  |  |  |                   saving: 'beforeSave', | 
					
						
							|  |  |  |  |                   saved: 'afterSave' | 
					
						
							|  |  |  |  |                 }; | 
					
						
							| 
									
										
										
										
											2016-03-22 15:50:33 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-24 19:58:03 +02:00
										 |  |  |  |                 _.forEach(lifecycle, (fn, key) => { | 
					
						
							|  |  |  |  |                   if (_.isFunction(strapi.models[model.toLowerCase()][fn])) { | 
					
						
							|  |  |  |  |                     this.on(key, strapi.models[model.toLowerCase()][fn]); | 
					
						
							|  |  |  |  |                   } | 
					
						
							|  |  |  |  |                 }); | 
					
						
							| 
									
										
										
										
											2016-03-22 15:50:33 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-24 19:58:03 +02:00
										 |  |  |  |                 this.on('saving', (instance, attrs, options) => { | 
					
						
							|  |  |  |  |                   instance.attributes = mapper(instance.attributes); | 
					
						
							|  |  |  |  |                   attrs = mapper(attrs); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |                   return _.isFunction( | 
					
						
							|  |  |  |  |                     strapi.models[model.toLowerCase()]['beforeSave'] | 
					
						
							|  |  |  |  |                   ) | 
					
						
							|  |  |  |  |                     ? strapi.models[model.toLowerCase()]['beforeSave'] | 
					
						
							|  |  |  |  |                     : Promise.resolve(); | 
					
						
							|  |  |  |  |                 }); | 
					
						
							|  |  |  |  |               }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |               loadedModel.hidden = _.keys( | 
					
						
							|  |  |  |  |                 _.keyBy( | 
					
						
							|  |  |  |  |                   _.filter(definition.attributes, (value, key) => { | 
					
						
							|  |  |  |  |                     if ( | 
					
						
							|  |  |  |  |                       value.hasOwnProperty('columnName') && | 
					
						
							|  |  |  |  |                       !_.isEmpty(value.columnName) && | 
					
						
							|  |  |  |  |                       value.columnName !== key | 
					
						
							|  |  |  |  |                     ) { | 
					
						
							|  |  |  |  |                       return true; | 
					
						
							|  |  |  |  |                     } | 
					
						
							|  |  |  |  |                   }), | 
					
						
							|  |  |  |  |                   'columnName' | 
					
						
							|  |  |  |  |                 ) | 
					
						
							| 
									
										
										
										
											2017-04-11 11:56:31 +02:00
										 |  |  |  |               ); | 
					
						
							| 
									
										
										
										
											2017-01-24 15:55:50 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-24 19:58:03 +02:00
										 |  |  |  |               global[globalName] = ORM.Model.extend(loadedModel); | 
					
						
							|  |  |  |  |               global[pluralize(globalName)] = ORM.Collection.extend({ | 
					
						
							|  |  |  |  |                 model: global[globalName] | 
					
						
							|  |  |  |  |               }); | 
					
						
							| 
									
										
										
										
											2017-01-04 17:21:24 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-24 19:58:03 +02:00
										 |  |  |  |               // Expose ORM functions through the `strapi.models` object.
 | 
					
						
							|  |  |  |  |               strapi.models[model] = _.assign(global[globalName], strapi.models[model]); | 
					
						
							| 
									
										
										
										
											2017-02-15 14:43:09 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-24 19:58:03 +02:00
										 |  |  |  |               // Push attributes to be aware of model schema.
 | 
					
						
							| 
									
										
										
										
											2017-09-18 18:20:33 +02:00
										 |  |  |  |               strapi.models[model]._attributes = definition.attributes; | 
					
						
							| 
									
										
										
										
											2017-02-15 14:43:09 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-24 19:58:03 +02:00
										 |  |  |  |               loadedHook(); | 
					
						
							|  |  |  |  |             } catch (err) { | 
					
						
							|  |  |  |  |               strapi.log.error( | 
					
						
							|  |  |  |  |                 'Impossible to register the `' + model + '` model.' | 
					
						
							|  |  |  |  |               ); | 
					
						
							|  |  |  |  |               strapi.log.error(err); | 
					
						
							|  |  |  |  |               strapi.stop(); | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |           }); | 
					
						
							| 
									
										
										
										
											2017-02-15 14:43:09 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-24 19:58:03 +02:00
										 |  |  |  |           if (_.isEmpty(definition.attributes)) { | 
					
						
							|  |  |  |  |             done(); | 
					
						
							|  |  |  |  |           } | 
					
						
							| 
									
										
										
										
											2017-02-15 14:43:09 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-24 19:58:03 +02:00
										 |  |  |  |           // Add every relationships to the loaded model for Bookshelf.
 | 
					
						
							|  |  |  |  |           // Basic attributes don't need this-- only relations.
 | 
					
						
							|  |  |  |  |           _.forEach(definition.attributes, (details, name) => { | 
					
						
							|  |  |  |  |             const verbose = _.get( | 
					
						
							| 
									
										
										
										
											2017-09-14 18:47:10 +02:00
										 |  |  |  |               utilsModels.getNature(details, name, undefined, model.toLowerCase()), | 
					
						
							| 
									
										
										
										
											2017-07-24 19:58:03 +02:00
										 |  |  |  |               'verbose' | 
					
						
							|  |  |  |  |             ) || ''; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             // Build associations key
 | 
					
						
							| 
									
										
										
										
											2017-09-19 13:40:26 +02:00
										 |  |  |  |             utilsModels.defineAssociations( | 
					
						
							|  |  |  |  |               globalName, | 
					
						
							|  |  |  |  |               definition, | 
					
						
							|  |  |  |  |               details, | 
					
						
							|  |  |  |  |               name | 
					
						
							|  |  |  |  |             ); | 
					
						
							| 
									
										
										
										
											2017-02-15 14:43:09 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-24 19:58:03 +02:00
										 |  |  |  |             switch (verbose) { | 
					
						
							|  |  |  |  |               case 'hasOne': { | 
					
						
							|  |  |  |  |                 const FK = _.findKey( | 
					
						
							|  |  |  |  |                   strapi.models[details.model].attributes, | 
					
						
							|  |  |  |  |                   details => { | 
					
						
							|  |  |  |  |                     if ( | 
					
						
							|  |  |  |  |                       details.hasOwnProperty('model') && | 
					
						
							|  |  |  |  |                       details.model === model && | 
					
						
							|  |  |  |  |                       details.hasOwnProperty('via') && | 
					
						
							|  |  |  |  |                       details.via === name | 
					
						
							|  |  |  |  |                     ) { | 
					
						
							|  |  |  |  |                       return details; | 
					
						
							| 
									
										
										
										
											2017-01-04 17:21:24 +01:00
										 |  |  |  |                     } | 
					
						
							| 
									
										
										
										
											2017-07-24 19:58:03 +02:00
										 |  |  |  |                   } | 
					
						
							| 
									
										
										
										
											2017-04-11 11:56:31 +02:00
										 |  |  |  |                 ); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-24 19:58:03 +02:00
										 |  |  |  |                 const globalId = _.get( | 
					
						
							|  |  |  |  |                   strapi.models, | 
					
						
							|  |  |  |  |                   `${details.model.toLowerCase()}.globalId` | 
					
						
							| 
									
										
										
										
											2017-04-11 11:56:31 +02:00
										 |  |  |  |                 ); | 
					
						
							| 
									
										
										
										
											2016-03-18 11:12:50 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-24 19:58:03 +02:00
										 |  |  |  |                 loadedModel[name] = function() { | 
					
						
							|  |  |  |  |                   return this.hasOne( | 
					
						
							|  |  |  |  |                     global[globalId], | 
					
						
							|  |  |  |  |                     _.get( | 
					
						
							|  |  |  |  |                       strapi.models[details.model].attributes, | 
					
						
							|  |  |  |  |                       `${FK}.columnName` | 
					
						
							|  |  |  |  |                     ) || FK | 
					
						
							|  |  |  |  |                   ); | 
					
						
							|  |  |  |  |                 }; | 
					
						
							|  |  |  |  |                 break; | 
					
						
							|  |  |  |  |               } | 
					
						
							|  |  |  |  |               case 'hasMany': { | 
					
						
							|  |  |  |  |                 const globalId = _.get( | 
					
						
							|  |  |  |  |                   strapi.models, | 
					
						
							|  |  |  |  |                   `${details.collection.toLowerCase()}.globalId` | 
					
						
							| 
									
										
										
										
											2017-04-11 11:56:31 +02:00
										 |  |  |  |                 ); | 
					
						
							| 
									
										
										
										
											2017-07-24 19:58:03 +02:00
										 |  |  |  |                 const FKTarget = _.get( | 
					
						
							|  |  |  |  |                   strapi.models[globalId.toLowerCase()].attributes, | 
					
						
							|  |  |  |  |                   `${details.via}.columnName` | 
					
						
							|  |  |  |  |                 ) || details.via; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-14 18:47:10 +02:00
										 |  |  |  |                 // Set this info to be able to see if this field is a real database's field.
 | 
					
						
							|  |  |  |  |                 details.isVirtual = true; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-24 19:58:03 +02:00
										 |  |  |  |                 loadedModel[name] = function() { | 
					
						
							|  |  |  |  |                   return this.hasMany(global[globalId], FKTarget); | 
					
						
							|  |  |  |  |                 }; | 
					
						
							|  |  |  |  |                 break; | 
					
						
							| 
									
										
										
										
											2017-01-04 17:21:24 +01:00
										 |  |  |  |               } | 
					
						
							| 
									
										
										
										
											2017-07-24 19:58:03 +02:00
										 |  |  |  |               case 'belongsTo': { | 
					
						
							|  |  |  |  |                 const globalId = _.get( | 
					
						
							|  |  |  |  |                   strapi.models, | 
					
						
							|  |  |  |  |                   `${details.model.toLowerCase()}.globalId` | 
					
						
							|  |  |  |  |                 ); | 
					
						
							| 
									
										
										
										
											2017-01-04 17:21:24 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-24 19:58:03 +02:00
										 |  |  |  |                 loadedModel[name] = function() { | 
					
						
							|  |  |  |  |                   return this.belongsTo( | 
					
						
							|  |  |  |  |                     global[globalId], | 
					
						
							|  |  |  |  |                     _.get(details, 'columnName') || name | 
					
						
							| 
									
										
										
										
											2017-04-11 11:56:31 +02:00
										 |  |  |  |                   ); | 
					
						
							| 
									
										
										
										
											2017-07-24 19:58:03 +02:00
										 |  |  |  |                 }; | 
					
						
							|  |  |  |  |                 break; | 
					
						
							|  |  |  |  |               } | 
					
						
							|  |  |  |  |               case 'belongsToMany': { | 
					
						
							| 
									
										
										
										
											2017-07-28 16:31:23 +02:00
										 |  |  |  |                 const collectionName = _.get(details, 'collectionName') || | 
					
						
							| 
									
										
										
										
											2017-07-24 19:58:03 +02:00
										 |  |  |  |                   _.map( | 
					
						
							|  |  |  |  |                     _.sortBy( | 
					
						
							|  |  |  |  |                       [ | 
					
						
							|  |  |  |  |                         strapi.models[details.collection].attributes[ | 
					
						
							|  |  |  |  |                           details.via | 
					
						
							|  |  |  |  |                         ], | 
					
						
							|  |  |  |  |                         details | 
					
						
							|  |  |  |  |                       ], | 
					
						
							|  |  |  |  |                       'collection' | 
					
						
							|  |  |  |  |                     ), | 
					
						
							|  |  |  |  |                     table => { | 
					
						
							|  |  |  |  |                       return _.snakeCase( | 
					
						
							|  |  |  |  |                         pluralize.plural(table.collection) + | 
					
						
							|  |  |  |  |                           ' ' + | 
					
						
							|  |  |  |  |                           pluralize.plural(table.via) | 
					
						
							|  |  |  |  |                       ); | 
					
						
							|  |  |  |  |                     } | 
					
						
							|  |  |  |  |                   ).join('__'); | 
					
						
							| 
									
										
										
										
											2017-04-11 11:56:31 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-24 19:58:03 +02:00
										 |  |  |  |                 const relationship = _.clone( | 
					
						
							|  |  |  |  |                   strapi.models[details.collection].attributes[details.via] | 
					
						
							|  |  |  |  |                 ); | 
					
						
							| 
									
										
										
										
											2017-04-11 11:56:31 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-24 19:58:03 +02:00
										 |  |  |  |                 // Force singular foreign key
 | 
					
						
							|  |  |  |  |                 relationship.attribute = pluralize.singular( | 
					
						
							|  |  |  |  |                   relationship.collection | 
					
						
							|  |  |  |  |                 ); | 
					
						
							|  |  |  |  |                 details.attribute = pluralize.singular(details.collection); | 
					
						
							| 
									
										
										
										
											2017-04-11 11:56:31 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-24 19:58:03 +02:00
										 |  |  |  |                 // Define PK column
 | 
					
						
							|  |  |  |  |                 details.column = utils.getPK(model, strapi.models); | 
					
						
							|  |  |  |  |                 relationship.column = utils.getPK( | 
					
						
							|  |  |  |  |                   details.collection, | 
					
						
							|  |  |  |  |                   strapi.models | 
					
						
							|  |  |  |  |                 ); | 
					
						
							| 
									
										
										
										
											2017-01-04 17:21:24 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-24 19:58:03 +02:00
										 |  |  |  |                 // Sometimes the many-to-many relationships
 | 
					
						
							|  |  |  |  |                 // is on the same keys on the same models (ex: `friends` key in model `User`)
 | 
					
						
							|  |  |  |  |                 if ( | 
					
						
							|  |  |  |  |                   details.attribute + '_' + details.column === | 
					
						
							|  |  |  |  |                   relationship.attribute + '_' + relationship.column | 
					
						
							|  |  |  |  |                 ) { | 
					
						
							|  |  |  |  |                   relationship.attribute = pluralize.singular(details.via); | 
					
						
							|  |  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2017-01-04 17:21:24 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-24 19:58:03 +02:00
										 |  |  |  |                 const globalId = _.get( | 
					
						
							|  |  |  |  |                   strapi.models, | 
					
						
							|  |  |  |  |                   `${details.collection.toLowerCase()}.globalId` | 
					
						
							|  |  |  |  |                 ); | 
					
						
							| 
									
										
										
										
											2017-01-04 17:21:24 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-14 18:47:10 +02:00
										 |  |  |  |                 // Set this info to be able to see if this field is a real database's field.
 | 
					
						
							|  |  |  |  |                 details.isVirtual = true; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-24 19:58:03 +02:00
										 |  |  |  |                 loadedModel[name] = function() { | 
					
						
							| 
									
										
										
										
											2017-04-11 11:56:31 +02:00
										 |  |  |  |                   if ( | 
					
						
							| 
									
										
										
										
											2017-07-24 19:58:03 +02:00
										 |  |  |  |                     _.isArray(_.get(details, 'withPivot')) && | 
					
						
							|  |  |  |  |                     !_.isEmpty(details.withPivot) | 
					
						
							| 
									
										
										
										
											2017-04-11 11:56:31 +02:00
										 |  |  |  |                   ) { | 
					
						
							|  |  |  |  |                     return this.belongsToMany( | 
					
						
							| 
									
										
										
										
											2017-04-12 15:43:18 +02:00
										 |  |  |  |                       global[globalId], | 
					
						
							| 
									
										
										
										
											2017-07-28 16:31:23 +02:00
										 |  |  |  |                       collectionName, | 
					
						
							| 
									
										
										
										
											2017-04-11 11:56:31 +02:00
										 |  |  |  |                       relationship.attribute + '_' + relationship.column, | 
					
						
							|  |  |  |  |                       details.attribute + '_' + details.column | 
					
						
							| 
									
										
										
										
											2017-07-24 19:58:03 +02:00
										 |  |  |  |                     ).withPivot(details.withPivot); | 
					
						
							|  |  |  |  |                   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |                   return this.belongsToMany( | 
					
						
							|  |  |  |  |                     global[globalId], | 
					
						
							| 
									
										
										
										
											2017-07-28 16:31:23 +02:00
										 |  |  |  |                     collectionName, | 
					
						
							| 
									
										
										
										
											2017-07-24 19:58:03 +02:00
										 |  |  |  |                     relationship.attribute + '_' + relationship.column, | 
					
						
							|  |  |  |  |                     details.attribute + '_' + details.column | 
					
						
							|  |  |  |  |                   ); | 
					
						
							|  |  |  |  |                 }; | 
					
						
							|  |  |  |  |                 break; | 
					
						
							| 
									
										
										
										
											2017-01-04 17:21:24 +01:00
										 |  |  |  |               } | 
					
						
							| 
									
										
										
										
											2017-07-24 19:58:03 +02:00
										 |  |  |  |               default: { | 
					
						
							|  |  |  |  |                 break; | 
					
						
							|  |  |  |  |               } | 
					
						
							|  |  |  |  |             } | 
					
						
							| 
									
										
										
										
											2016-03-18 11:12:50 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-24 19:58:03 +02:00
										 |  |  |  |             done(); | 
					
						
							| 
									
										
										
										
											2016-03-18 11:12:50 +01:00
										 |  |  |  |           }); | 
					
						
							|  |  |  |  |         }); | 
					
						
							|  |  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2017-09-13 12:18:54 +02:00
										 |  |  |  |     }, | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     getQueryParams: (value, type, key) => { | 
					
						
							|  |  |  |  |       const result = {}; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       switch (type) { | 
					
						
							|  |  |  |  |         case '=': | 
					
						
							|  |  |  |  |           result.key = `where.${key}[0]`; | 
					
						
							|  |  |  |  |           result.value = { | 
					
						
							|  |  |  |  |             symbol: '=', | 
					
						
							|  |  |  |  |             value | 
					
						
							|  |  |  |  |           }; | 
					
						
							|  |  |  |  |           break; | 
					
						
							|  |  |  |  |         case '_ne': | 
					
						
							|  |  |  |  |           result.key = `where.${key}[0]`; | 
					
						
							|  |  |  |  |           result.value = { | 
					
						
							|  |  |  |  |             symbol: '!=', | 
					
						
							|  |  |  |  |             value | 
					
						
							|  |  |  |  |           }; | 
					
						
							|  |  |  |  |           break; | 
					
						
							|  |  |  |  |         case '_lt': | 
					
						
							|  |  |  |  |           result.key = `where.${key}[0]`; | 
					
						
							|  |  |  |  |           result.value = { | 
					
						
							|  |  |  |  |             symbol: '<', | 
					
						
							|  |  |  |  |             value | 
					
						
							|  |  |  |  |           }; | 
					
						
							|  |  |  |  |           break; | 
					
						
							|  |  |  |  |         case '_gt': | 
					
						
							|  |  |  |  |           result.key = `where.${key}[0]`; | 
					
						
							|  |  |  |  |           result.value = { | 
					
						
							|  |  |  |  |             symbol: '>', | 
					
						
							|  |  |  |  |             value | 
					
						
							|  |  |  |  |           }; | 
					
						
							|  |  |  |  |           break; | 
					
						
							|  |  |  |  |         case '_lte': | 
					
						
							|  |  |  |  |           result.key = `where.${key}[0]`; | 
					
						
							|  |  |  |  |           result.value = { | 
					
						
							|  |  |  |  |             symbol: '<=', | 
					
						
							|  |  |  |  |             value | 
					
						
							|  |  |  |  |           }; | 
					
						
							|  |  |  |  |           break; | 
					
						
							|  |  |  |  |         case '_gte': | 
					
						
							|  |  |  |  |           result.key = `where.${key}[0]`; | 
					
						
							|  |  |  |  |           result.value = { | 
					
						
							|  |  |  |  |             symbol: '>=', | 
					
						
							|  |  |  |  |             value | 
					
						
							|  |  |  |  |           }; | 
					
						
							|  |  |  |  |           break; | 
					
						
							|  |  |  |  |         case '_sort': | 
					
						
							|  |  |  |  |           result.key = `sort`; | 
					
						
							|  |  |  |  |           result.value = (value === 'desc') ? '-' : ''; | 
					
						
							|  |  |  |  |           result.value += key; | 
					
						
							|  |  |  |  |           break; | 
					
						
							|  |  |  |  |         case '_start': | 
					
						
							|  |  |  |  |           result.key = `start`; | 
					
						
							|  |  |  |  |           result.value = parseFloat(value); | 
					
						
							|  |  |  |  |           break; | 
					
						
							|  |  |  |  |         case '_limit': | 
					
						
							|  |  |  |  |           result.key = `limit`; | 
					
						
							|  |  |  |  |           result.value = parseFloat(value); | 
					
						
							|  |  |  |  |           break; | 
					
						
							|  |  |  |  |         default: | 
					
						
							|  |  |  |  |           result = undefined; | 
					
						
							|  |  |  |  |       } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       return result; | 
					
						
							| 
									
										
										
										
											2016-03-18 11:12:50 +01:00
										 |  |  |  |     } | 
					
						
							|  |  |  |  |   }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   return hook; | 
					
						
							|  |  |  |  | }; |