Fix(crud) include param lookup now works w/plurals
Previously, {one,many}-to-many relationships with models would result in
`associationNames` that were plural. e.g. `Team` might have many
players and one location. The validation was expecting to see the plural
`Players` and the singular `Location` but Sequelize is expecting the
singular `Player` (`Location` worked fine). This meant that include
lookups would silently fail. This fixes the problem in a backward-
compatible way.
It continues to allow `include=Location` (capitalized) for backward-
compatibility. And now allows and actually does the lookup for
`include=players`, `include=player`, `include=Player`, `include=Players`
lookup relationships.
			
			
This commit is contained in:
		
							
								
								
									
										13
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								README.md
									
									
									
									
									
								
							| @@ -109,7 +109,7 @@ Getting related models is easy, just use a query parameter `include`. | |||||||
|  |  | ||||||
| ```js | ```js | ||||||
| // returns all teams with their related City model | // returns all teams with their related City model | ||||||
| // GET /teams?include=City | // GET /teams?include=city | ||||||
|  |  | ||||||
| // results in a Sequelize query: | // results in a Sequelize query: | ||||||
| Team.findAll({include: City}) | Team.findAll({include: City}) | ||||||
| @@ -118,12 +118,21 @@ Team.findAll({include: City}) | |||||||
| If you want to get multiple related models, just pass multiple `include` parameters. | If you want to get multiple related models, just pass multiple `include` parameters. | ||||||
| ```js | ```js | ||||||
| // returns all teams with their related City and Uniform models | // returns all teams with their related City and Uniform models | ||||||
| // GET /teams?include=City&include=Uniform | // GET /teams?include[]=city&include[]=uniform | ||||||
|  |  | ||||||
| // results in a Sequelize query: | // results in a Sequelize query: | ||||||
| Team.findAll({include: [City, Uniform]}) | Team.findAll({include: [City, Uniform]}) | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
|  | For models that have a many-to-many relationship, you can also pass the plural version of the association. | ||||||
|  | ```js | ||||||
|  | // returns all teams with their related City and Uniform models | ||||||
|  | // GET /teams?include=players | ||||||
|  |  | ||||||
|  | // results in a Sequelize query: | ||||||
|  | Team.findAll({include: [Player]}) | ||||||
|  | ``` | ||||||
|  |  | ||||||
| ## `limit` and `offset` queries | ## `limit` and `offset` queries | ||||||
| Restricting list (`GET`) and scope queries to a restricted count can be done by passing `limit=<number>` and/or `offset=<number>`. | Restricting list (`GET`) and scope queries to a restricted count can be done by passing `limit=<number>` and/or `offset=<number>`. | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										10
									
								
								src/crud.js
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								src/crud.js
									
									
									
									
									
								
							| @@ -55,7 +55,15 @@ models: { | |||||||
| export default (server, model, { prefix, defaultConfig: config, models: permissions }) => { | export default (server, model, { prefix, defaultConfig: config, models: permissions }) => { | ||||||
|   const modelName = model._singular; |   const modelName = model._singular; | ||||||
|   const modelAttributes = Object.keys(model.attributes); |   const modelAttributes = Object.keys(model.attributes); | ||||||
|   const modelAssociations = Object.keys(model.associations); |   const associatedModelNames = Object.keys(model.associations); | ||||||
|  |   const modelAssociations = [ | ||||||
|  |     ...associatedModelNames, | ||||||
|  |     ..._.flatMap(associatedModelNames, (associationName) => { | ||||||
|  |       const { target } = model.associations[associationName]; | ||||||
|  |       const { _singular, _plural, _Singular, _Plural } = target; | ||||||
|  |       return [_singular, _plural, _Singular, _Plural]; | ||||||
|  |     }), | ||||||
|  |   ]; | ||||||
|  |  | ||||||
|   const attributeValidation = modelAttributes.reduce((params, attribute) => { |   const attributeValidation = modelAttributes.reduce((params, attribute) => { | ||||||
|     params[attribute] = joi.any(); |     params[attribute] = joi.any(); | ||||||
|   | |||||||
| @@ -32,6 +32,8 @@ const register = (server, options = {}, next) => { | |||||||
|     const { plural, singular } = model.options.name; |     const { plural, singular } = model.options.name; | ||||||
|     model._plural = plural.toLowerCase(); |     model._plural = plural.toLowerCase(); | ||||||
|     model._singular = singular.toLowerCase(); |     model._singular = singular.toLowerCase(); | ||||||
|  |     model._Plural = plural; | ||||||
|  |     model._Singular = singular; | ||||||
|  |  | ||||||
|     // Join tables |     // Join tables | ||||||
|     if (model.options.name.singular !== model.name) continue; |     if (model.options.name.singular !== model.name) continue; | ||||||
|   | |||||||
| @@ -20,6 +20,13 @@ export const parseInclude = request => { | |||||||
|   const { models } = noGetDb ? request : request.getDb(); |   const { models } = noGetDb ? request : request.getDb(); | ||||||
|  |  | ||||||
|   return include.map(a => { |   return include.map(a => { | ||||||
|  |     const singluarOrPluralMatch = Object.keys(models).find((modelName) => { | ||||||
|  |       const { _singular, _plural } = models[modelName]; | ||||||
|  |       return _singular === a || _plural === a; | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  |     if (singluarOrPluralMatch) return models[singluarOrPluralMatch]; | ||||||
|  |  | ||||||
|     if (typeof a === 'string') return models[a]; |     if (typeof a === 'string') return models[a]; | ||||||
|  |  | ||||||
|     if (a && typeof a.model === 'string' && a.model.length) { |     if (a && typeof a.model === 'string' && a.model.length) { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user