Skip to content

Commit

Permalink
[FEAT] Adds support for parenless attr, belongsTo, and hasMany (#6339)
Browse files Browse the repository at this point in the history
  • Loading branch information
Chris Garrett authored and runspired committed Aug 20, 2019
1 parent 5b1f559 commit aa05d92
Show file tree
Hide file tree
Showing 8 changed files with 114 additions and 3 deletions.
1 change: 1 addition & 0 deletions packages/-ember-data/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
"broccoli-string-replace": "^0.1.2",
"broccoli-test-helper": "^2.0.0",
"broccoli-uglify-sourcemap": "^3.0.0",
"ember-compatibility-helpers": "^1.2.0",
"ember-cli": "^3.12.0",
"ember-cli-app-version": "^3.2.0",
"ember-cli-dependency-checker": "^3.2.0",
Expand Down
37 changes: 37 additions & 0 deletions packages/-ember-data/tests/unit/model-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import JSONSerializer from '@ember-data/serializer/json';
import { attr as DSattr } from '@ember-data/model';
import { recordDataFor } from 'ember-data/-private';
import { attr, hasMany, belongsTo } from '@ember-data/model';
import { gte } from 'ember-compatibility-helpers';

module('unit/model - Model', function(hooks) {
setupTest(hooks);
Expand Down Expand Up @@ -1442,6 +1443,42 @@ module('unit/model - Model', function(hooks) {

await cat.save();
});

if (gte('3.10.0')) {
test('@attr decorator works without parens', async function(assert) {
assert.expect(1);
let cat;

class Mascot extends Model {
@attr name;
}

this.owner.register('model:mascot', Mascot);
adapter.updateRecord = function() {
assert.deepEqual(cat.changedAttributes(), {
name: ['Argon', 'Helia'],
});

return { data: { id: '1', type: 'mascot' } };
};

cat = store.push({
data: {
type: 'mascot',
id: '1',
attributes: {
name: 'Argon',
},
},
});

cat.setProperties({
name: 'Helia',
});

await cat.save();
});
}
});

module('Misc', function() {
Expand Down
32 changes: 32 additions & 0 deletions packages/-ember-data/tests/unit/model/relationships-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { module, test } from 'qunit';
import Model from '@ember-data/model';
import { hasMany, belongsTo } from '@ember-data/model';
import { get } from '@ember/object';
import { gte } from 'ember-compatibility-helpers';

class Person extends Model {
@hasMany('occupation', { async: false }) occupations;
Expand Down Expand Up @@ -125,4 +126,35 @@ module('[@ember-data/model] unit - relationships', function(hooks) {

assert.equal(relationship.meta.name, 'streamItems', 'relationship name has not been changed');
});

if (gte('3.10.0')) {
test('decorators works without parens', function(assert) {
let store;
let { owner } = this;

class StreamItem extends Model {
@belongsTo user;
}

class User extends Model {
@hasMany streamItems;
}

owner.unregister('model:user');
owner.register('model:stream-item', StreamItem);
owner.register('model:user', User);

store = owner.lookup('service:store');

let user = store.modelFor('user');

const relationships = get(user, 'relationships');

assert.ok(relationships.has('stream-item'), 'relationship key has been normalized');

const relationship = relationships.get('stream-item')[0];

assert.equal(relationship.meta.name, 'streamItems', 'relationship name has not been changed');
});
}
});
5 changes: 4 additions & 1 deletion packages/model/addon/-private/attr.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { assert } from '@ember/debug';
import { DEBUG } from '@glimmer/env';
import { recordDataFor } from '@ember-data/store/-private';
import { RECORD_DATA_ERRORS } from '@ember-data/canary-features';
import { computedMacroWithOptionalParams } from './util';

/**
@module @ember-data/model
Expand Down Expand Up @@ -107,7 +108,7 @@ function hasValue(internalModel, key) {
@param {Object} options a hash of options
@return {Attribute}
*/
export default function attr(type, options) {
function attr(type, options) {
if (typeof type === 'object') {
options = type;
type = undefined;
Expand Down Expand Up @@ -160,3 +161,5 @@ export default function attr(type, options) {
},
}).meta(meta);
}

export default computedMacroWithOptionalParams(attr);
5 changes: 4 additions & 1 deletion packages/model/addon/-private/belongs-to.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { computed } from '@ember/object';
import { assert, warn, inspect } from '@ember/debug';
import { normalizeModelName } from '@ember-data/store';
import { DEBUG } from '@glimmer/env';
import { computedMacroWithOptionalParams } from './util';

/**
@module @ember-data/model
Expand Down Expand Up @@ -103,7 +104,7 @@ import { DEBUG } from '@glimmer/env';
@param {Object} options (optional) a hash of options
@return {Ember.computed} relationship
*/
export default function belongsTo(modelName, options) {
function belongsTo(modelName, options) {
let opts, userEnteredModelName;
if (typeof modelName === 'object') {
opts = modelName;
Expand Down Expand Up @@ -180,3 +181,5 @@ export default function belongsTo(modelName, options) {
},
}).meta(meta);
}

export default computedMacroWithOptionalParams(belongsTo);
5 changes: 4 additions & 1 deletion packages/model/addon/-private/has-many.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { computed } from '@ember/object';
import { assert, inspect } from '@ember/debug';
import { normalizeModelName } from '@ember-data/store';
import { DEBUG } from '@glimmer/env';
import { computedMacroWithOptionalParams } from './util';

/**
`hasMany` is used to define One-To-Many and Many-To-Many
Expand Down Expand Up @@ -141,7 +142,7 @@ import { DEBUG } from '@glimmer/env';
@param {Object} options (optional) a hash of options
@return {Ember.computed} relationship
*/
export default function hasMany(type, options) {
function hasMany(type, options) {
if (typeof type === 'object') {
options = type;
type = undefined;
Expand Down Expand Up @@ -199,3 +200,5 @@ export default function hasMany(type, options) {
},
}).meta(meta);
}

export default computedMacroWithOptionalParams(hasMany);
31 changes: 31 additions & 0 deletions packages/model/addon/-private/util.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { gte } from 'ember-compatibility-helpers';

export type DecoratorPropertyDescriptor = PropertyDescriptor & { initializer?: any } | undefined;

export function isElementDescriptor(args: any[]): args is [object, string, DecoratorPropertyDescriptor] {
let [maybeTarget, maybeKey, maybeDesc] = args;

return (
// Ensure we have the right number of args
args.length === 3 &&
// Make sure the target is a class or object (prototype)
(typeof maybeTarget === 'function' || (typeof maybeTarget === 'object' && maybeTarget !== null)) &&
// Make sure the key is a string
typeof maybeKey === 'string' &&
// Make sure the descriptor is the right shape
((typeof maybeDesc === 'object' &&
maybeDesc !== null &&
'enumerable' in maybeDesc &&
'configurable' in maybeDesc) ||
// TS compatibility
maybeDesc === undefined)
);
}

export function computedMacroWithOptionalParams(fn) {
if (gte('3.10.0')) {
return (...maybeDesc: any[]) => (isElementDescriptor(maybeDesc) ? fn()(...maybeDesc) : fn(...maybeDesc));
} else {
return fn;
}
}
1 change: 1 addition & 0 deletions packages/model/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"@ember-data/-build-infra": "3.14.0-alpha.1",
"@ember-data/canary-features": "3.14.0-alpha.1",
"@ember-data/store": "3.14.0-alpha.1",
"ember-compatibility-helpers": "^1.2.0",
"ember-cli-babel": "^7.10.0",
"ember-cli-string-utils": "^1.1.0",
"ember-cli-test-info": "^1.0.0",
Expand Down

0 comments on commit aa05d92

Please sign in to comment.