Skip to content

Commit

Permalink
Auto merge of #4986 - gabrielgrant:fix-model-blueprint, r=stefanpenner
Browse files Browse the repository at this point in the history
fix model relationship name generation

It is not currently possible to generate a model with a relationship named differently from the model's name ([despite the help indicating it should be](https://github.com/ember-cli/ember-cli/blob/master/blueprints/model/HELP.md))

This patch brings the code's behavior in line with the docs.

The blueprint part of this patch will be obsoleted if #4909 lands, so I've also PRed the changes to the blueprint in ED: emberjs/data#3885 

(the arg-parsing-fix part of this patch is still needed to pass a distinct name, though)
  • Loading branch information
homu committed Oct 26, 2015
2 parents 5e4c854 + 846ed72 commit 5c38ee5
Show file tree
Hide file tree
Showing 3 changed files with 127 additions and 9 deletions.
28 changes: 21 additions & 7 deletions blueprints/model/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,25 +19,40 @@ module.exports = {

for (var name in entityOptions) {
var type = entityOptions[name] || '';
var foreignModel = name;
if (type.indexOf(':') > -1) {
foreignModel = type.split(':')[1];
type = type.split(':')[0];
}
var dasherizedName = stringUtils.dasherize(name);
var dasherizedNameSingular = inflection.singularize(dasherizedName);
var camelizedName = stringUtils.camelize(name);
var dasherizedType = stringUtils.dasherize(type);
var dasherizedForeignModel = stringUtils.dasherize(foreignModel);
var dasherizedForeignModelSingular = inflection.singularize(dasherizedForeignModel);

var attr;
if (/has-many/.test(dasherizedType)) {
var camelizedNamePlural = inflection.pluralize(camelizedName);
attrs.push(camelizedNamePlural + ': ' + dsAttr(dasherizedName, dasherizedType));
attr = dsAttr(dasherizedForeignModelSingular, dasherizedType);
attrs.push(camelizedNamePlural + ': ' + attr);
} else if (/belongs-to/.test(dasherizedType)) {
attr = dsAttr(dasherizedForeignModel, dasherizedType);
attrs.push(camelizedName + ': ' + attr);
} else {
attrs.push(camelizedName + ': ' + dsAttr(dasherizedName, dasherizedType));
attr = dsAttr(dasherizedName, dasherizedType);
attrs.push(camelizedName + ': ' + attr);
}

if (/has-many|belongs-to/.test(dasherizedType)) {
needs.push("'model:" + dasherizedNameSingular + "'");
needs.push("'model:" + dasherizedForeignModelSingular + "'");
}
}
var needsDeduplicated = needs.filter(function(need, i) {
return needs.indexOf(need) === i;
});

attrs = attrs.join(',' + EOL + ' ');
needs = ' needs: [' + needs.join(', ') + ']';
needs = ' needs: [' + needsDeduplicated.join(', ') + ']';

return {
attrs: attrs,
Expand All @@ -51,8 +66,7 @@ function dsAttr(name, type) {
case 'belongs-to':
return 'DS.belongsTo(\'' + name + '\')';
case 'has-many':
var singularizedName = inflection.singularize(name);
return 'DS.hasMany(\'' + singularizedName + '\')';
return 'DS.hasMany(\'' + name + '\')';
case '':
//"If you don't specify the type of the attribute, it will be whatever was provided by the server"
//http://emberjs.com/guides/models/defining-models/
Expand Down
4 changes: 2 additions & 2 deletions lib/utilities/parse-options.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ var reduce = require('lodash/collection/reduce');

module.exports = function parseOptions(args) {
return reduce(args, function(result, arg) {
var pair = arg.split(':');
result[pair[0]] = pair[1];
var parts = arg.split(':');
result[parts[0]] = parts.slice(1).join(':');
return result;
}, {});
};
104 changes: 104 additions & 0 deletions tests/unit/blueprints/model-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
'use strict';

var Blueprint = require('../../../lib/models/blueprint');
var expect = require('chai').expect;

var EOL = require('os').EOL;

function makeOpts(opts){
return {entity: {options: opts}};
}

describe('blueprint - model', function(){
describe('entityName', function(){
it('generates individual un-typed properties', function(){
var blueprint = Blueprint.lookup('model');

var out = blueprint.locals(makeOpts({
name: ''
}));
console.log(out);
expect(out.attrs).to.equal('name: DS.attr()');
expect(out.needs).to.equal(' needs: []');
});

it('generates individual typed properties', function(){
var blueprint = Blueprint.lookup('model');

var out = blueprint.locals(makeOpts({
name: 'type'
}));
expect(out.attrs).to.equal('name: DS.attr(\'type\')');
expect(out.needs).to.equal(' needs: []');
})

it('accepts camel-cased properties', function(){
var blueprint = Blueprint.lookup('model');

var out = blueprint.locals(makeOpts({
aliceTheCamel: 'humps'
}));
console.log(out);
expect(out.attrs).to.equal('aliceTheCamel: DS.attr(\'humps\')');
expect(out.needs).to.equal(' needs: []');
});

it('accepts dasheriezed properties', function(){
var blueprint = Blueprint.lookup('model');

var out = blueprint.locals(makeOpts({
'dash-to-the-future': 'time-machine'
}));
expect(out.attrs).to.equal('dashToTheFuture: DS.attr(\'time-machine\')');
expect(out.needs).to.equal(' needs: []');
})

it('accepts underscored properties', function(){
var blueprint = Blueprint.lookup('model');

var out = blueprint.locals(makeOpts({
six_feet_underscored: ''
}));
console.log(out);
expect(out.attrs).to.equal('sixFeetUnderscored: DS.attr()');
expect(out.needs).to.equal(' needs: []');
});

it('generates multiple properties', function(){
var blueprint = Blueprint.lookup('model');

var out = blueprint.locals(makeOpts({
one: 'Fish',
two: 'Fish'
}));
console.log(out);
expect(out.attrs).to.equal('one: DS.attr(\'fish\'),' + EOL + ' two: DS.attr(\'fish\')');
expect(out.needs).to.equal(' needs: []');
});

it('links model by name if type is undefined', function(){
var blueprint = Blueprint.lookup('model');

var out = blueprint.locals(makeOpts({
virtue: 'belongs-to',
vices: 'has-many'
}));
console.log(out);
expect(out.attrs).to.equal('virtue: DS.belongsTo(\'virtue\'),' + EOL + ' vices: DS.hasMany(\'vice\')');
expect(out.needs).to.equal(' needs: [\'model:virtue\', \'model:vice\']');
});

it('links supplied model name (singularized) if defined', function(){
var blueprint = Blueprint.lookup('model');

var out = blueprint.locals(makeOpts({
tomster: 'belongs-to:leah',
irlTom: 'has-many:twitterRants'
}));
console.log(out);
expect(out.attrs).to.equal('tomster: DS.belongsTo(\'leah\'),' + EOL + ' irlToms: DS.hasMany(\'twitter-rant\')');
expect(out.needs).to.equal(' needs: [\'model:leah\', \'model:twitter-rant\']');
});

});
});

0 comments on commit 5c38ee5

Please sign in to comment.