Permalink
Browse files

feat(entity): allow custom id property names. Use @idProperty() decor…

…ator to set a custom id property name
  • Loading branch information...
doktordirk committed Jul 5, 2016
1 parent 09a31e2 commit 6d2f9b17fbcb68ae542fb9852942e1b2f773e698
@@ -250,7 +250,7 @@ Itself to allow chaining.
Get the resource this entity belongs to.
**Note:** Also works when called statically on custom entities.
**Note:** Also works when called statically on an Entity class.
### Parameters
@@ -266,7 +266,7 @@ The resource it belongs to (string).
Get the name of this entity.
**Note:** Also works when called statically on custom entities.
**Note:** Also works when called statically on an Entity class.
### Parameters
@@ -279,6 +279,52 @@ Defaults to the resource name (or null when also not set).
---------
## .getIdProperty()
Get the id property name of this entity.
**Note:** Also works when called statically on an Entity class.
### Parameters
* None
### Returns
The id property name of the entity. Defaults to 'id' or as configured using the `@idProperty` decorator.
---------
## .setId(id)
Set the id for this entity.
### Parameters
| Parameter | Type | Description |
| --------- | ------------- | --------------------- |
| id | string|number | The id of the entity. |
### Returns
Itself to allow chaining.
---------
## .getId()
Get the id of this entity.
### Parameters
* None
### Returns
The id of the entity instance.
---------
## .setData(data)
Set the values of the entity.
@@ -59,6 +59,18 @@ class HelloWorld {}
class HelloWorld {}
```
## @idProperty()
Usually, you won't need the `@idProperty()` decorator. Orm uses 'id' as default property for the id, but you can use this decorator to define a different property as the id property.
```js
import {Entity, idProperty} from 'aurelia-orm';
@resource()
@idProperty('userId')
export class User extends Entity {}
```
## @repository()
Usually, you won't need the `@repository()` decorator. It's used to define a custom repository for your entity (which can be useful if you wish to implement different methods).
@@ -0,0 +1,7 @@
import {OrmMetadata} from '../orm-metadata';
export function idProperty(propertyName) {
return function(target) {
OrmMetadata.forTarget(target).put('idProperty', propertyName);
};
}
@@ -60,6 +60,7 @@ export class Entity {
* @param {string} property
* @param {*} value
* @param {boolean} [writable]
* @chainable
*
* @return {Entity}
*/
@@ -82,6 +83,48 @@ export class Entity {
return this.__meta;
}
/**
* Get the id property name for this entity.
*
* return {String} The id property name
*/
getIdProperty() {
return this.getMeta().fetch('idProperty');
}
/**
* Get the id property name of the entity (static).
*
* @return {string} The id property name
*/
static getIdProperty() {
let idProperty = OrmMetadata.forTarget(this).fetch('idProperty');
return idProperty;
}
/**
* Get the Id value for this entity.
*
* return {Number|String} The id
*/
getId() {
return this[this.getIdProperty()];
}
/**
* Set the Id value for this entity.
*
* @return {Entity} this
* @chainable
*/
setId(id) {
this[this.getIdProperty()] = id;
return this;
}
/**
* Persist the entity's state to the server.
* Either creates a new record (POST) or updates an existing one (PUT) based on the entity's state,
@@ -97,7 +140,7 @@ export class Entity {
return this.getTransport()
.create(this.getResource(), this.asObject(true))
.then((created) => {
this.id = created.id;
this.setId(created[this.getIdProperty()]);
response = created;
})
.then(() => this.saveCollections())
@@ -130,10 +173,10 @@ export class Entity {
let requestBody = this.asObject(true);
let response;
delete requestBody.id;
delete requestBody[this.getIdProperty()];
return this.getTransport()
.update(this.getResource(), this.id, requestBody)
.update(this.getResource(), this.getId(), requestBody)
.then((updated) => response = updated)
.then(() => this.saveCollections())
.then(() => this.markClean())
@@ -152,7 +195,7 @@ export class Entity {
*/
addCollectionAssociation(entity, property) {
property = property || getPropertyForAssociation(this, entity);
let url = [this.getResource(), this.id, property];
let url = [this.getResource(), this.getId(), property];
if (this.isNew()) {
throw new Error('Cannot add association to entity that does not have an id.');
@@ -176,15 +219,15 @@ export class Entity {
}
// toOne relation, pass in ID to prevent extra request. Something something performance.
entity[associationProperty] = this.id;
entity[associationProperty] = this.getId();
return entity.save().then(() => {
return entity;
});
}
// Entity isn't new, just add id to url.
url.push(entity.id);
url.push(entity.getId());
return this.getTransport().create(url.join('/')).then(() => {
return entity;
@@ -204,14 +247,14 @@ export class Entity {
let idToRemove = entity;
if (entity instanceof Entity) {
if (!entity.id) {
if (!entity.getId()) {
return Promise.resolve(null);
}
idToRemove = entity.id;
idToRemove = entity.getId();
}
return this.getTransport().destroy([this.getResource(), this.id, property, idToRemove].join('/'));
return this.getTransport().destroy([this.getResource(), this.getId(), property, idToRemove].join('/'));
}
/**
@@ -286,7 +329,7 @@ export class Entity {
* @return {boolean}
*/
isNew() {
return typeof this.id === 'undefined';
return typeof this.getId() === 'undefined';
}
/**
@@ -324,11 +367,11 @@ export class Entity {
* @return {Promise}
*/
destroy() {
if (!this.id) {
if (!this.getId()) {
throw new Error('Required value "id" missing on entity.');
}
return this.getTransport().destroy(this.getResource(), this.id);
return this.getTransport().destroy(this.getResource(), this.getId());
}
/**
@@ -471,7 +514,7 @@ function asObject(entity, shallow) {
}
if (value.id) {
pojo[propertyName] = value.id;
pojo[propertyName] = value.id; // weird. entities always have an id!?
} else if (value instanceof Entity) {
pojo[propertyName] = value.asObject();
} else if (['string', 'number', 'boolean'].indexOf(typeof value) > -1 || value.constructor === Object) {
@@ -503,7 +546,7 @@ function asObject(entity, shallow) {
}
// If shallow, we don't handle toMany.
if (!shallow || (typeof childValue === 'object' && !childValue.id)) {
if (!shallow || (typeof childValue === 'object' && !childValue.getId())) {
asObjects.push(childValue.asObject(shallow));
}
});
@@ -570,7 +613,7 @@ function getCollectionsCompact(forEntity, includeNew) {
}
if (entity.id) {
collections[index].push(entity.id);
collections[index].push(entity.id); // again weird. see above
} else if (includeNew && entity instanceof Entity) {
collections[index].push(entity);
}
@@ -20,6 +20,7 @@ export class Metadata {
resource: null,
endpoint: null,
name: null,
idProperty: 'id',
associations: {}
};
}
@@ -183,7 +183,7 @@ describe('Entity', function() {
it('Should call .update on REST with an ID. (custom entity)', function(done) {
let entity = constructEntity(WithResource);
entity.foo = 'bar';
entity.id = 1337;
entity.idTag = 1337;
entity.save().then(response => {
expect(response.body).toEqual({foo: 'bar'});
@@ -331,7 +331,7 @@ describe('Entity', function() {
let entity = new WithResource(new Validation());
expect(entity.isNew()).toBe(true);
entity.setData({id: 667}).markClean();
entity.setData({idTag: 667}).markClean();
expect(entity.isNew()).toBe(false);
});
});
@@ -341,7 +341,7 @@ describe('Entity', function() {
let entity = new WithResource(new Validation());
entity.setData({
id: 667,
idTag: 667,
foo: 'bar',
city: {awesome: true}
}).markClean();
@@ -361,7 +361,7 @@ describe('Entity', function() {
describe('.update()', function() {
it('Should call .update with complete body.', function(done) {
let entity = constructEntity(WithResource);
entity.id = 666;
entity.idTag = 666;
entity.foo = 'bar';
entity.city = {awesome: true};
@@ -377,7 +377,7 @@ describe('Entity', function() {
it('Should not send a PUT request for .update when clean.', function(done) {
let entity = constructEntity(WithResource);
entity.setData({
id: 667,
idTag: 667,
foo: 'bar',
city: {awesome: true}
}).markClean();
@@ -444,6 +444,42 @@ describe('Entity', function() {
});
});
describe('.getIdProperty()', function() {
it(`Should return the entity's id property`, function() {
let instance = new WithResource();
expect(instance.getIdProperty()).toBe('idTag');
});
});
describe('static .getIdProperty()', function() {
it('Should return the entity id property name. (Default)', function() {
expect(Entity.getIdProperty()).toEqual('id');
});
it('Should return the entity id property name. (Custom)', function() {
expect(WithResource.getIdProperty()).toEqual('idTag');
});
});
describe('.getId()', function() {
it(`Should return the entity's id`, function() {
let instance = new WithResource();
instance.idTag = 1;
expect(instance.getId()).toBe(1);
});
});
describe('.setId()', function() {
it(`Should set the entity's id`, function() {
let instance = new WithResource();
instance.setId(1)
expect(instance.idTag).toBe(1);
});
});
describe('static .getResource()', function() {
it('Should return the entity resource. (Default)', function() {
expect(Entity.getResource()).toEqual(null);
@@ -509,7 +545,7 @@ describe('Entity', function() {
describe('.destroy()', function() {
it('Should call .destroy.', function(done) {
let entity = constructEntity(WithResource);
entity.id = 666;
entity.idTag = 666;
entity.destroy().then(response => {
expect(response.path).toEqual('/with-resource/666');
@@ -12,6 +12,7 @@ describe('OrmMetadata', function() {
resource: null,
endpoint: null,
name: null,
idProperty: 'id',
associations: {}
});
});
@@ -26,6 +27,7 @@ describe('OrmMetadata', function() {
resource: null,
name: null,
endpoint: null,
idProperty: 'id',
associations: {}
});
Oops, something went wrong.

0 comments on commit 6d2f9b1

Please sign in to comment.