From cdc1d335cea1d9b0baf6a5ad0451f1b3156640e5 Mon Sep 17 00:00:00 2001 From: Alex Dik Date: Thu, 3 Mar 2016 16:56:59 +0100 Subject: [PATCH] Make linked and embedded resources accessible via properties --- .../api-v3/hal/hal-resource.service.test.ts | 92 +++++++++++++++++-- .../api/api-v3/hal/hal-resource.service.ts | 39 +++++++- 2 files changed, 120 insertions(+), 11 deletions(-) diff --git a/frontend/app/components/api/api-v3/hal/hal-resource.service.test.ts b/frontend/app/components/api/api-v3/hal/hal-resource.service.test.ts index 64a5787f8e..507e164ab5 100644 --- a/frontend/app/components/api/api-v3/hal/hal-resource.service.test.ts +++ b/frontend/app/components/api/api-v3/hal/hal-resource.service.test.ts @@ -270,8 +270,7 @@ describe('halTransform service', () => { }); }); - //TODO: Implement distinction between linked actions and properties - describe.skip('when transforming an object with _links and/or _embedded', () => { + describe('when transforming an object with _links and/or _embedded', () => { var transformedElement; beforeEach(() => { @@ -281,8 +280,8 @@ describe('halTransform service', () => { href: '/api/property', title: 'Property' }, - embeddedProperty: { - href: '/api/embedded-property' + embedded: { + href: '/api/embedded', }, action: { href: '/api/action', @@ -290,8 +289,20 @@ describe('halTransform service', () => { } }, _embedded: { - embeddedProperty: { + embedded: { + _links: { + self: { + href: '/api/embedded' + } + }, name: 'name' + }, + notLinked: { + _links: { + self: { + href: '/api/not-linked' + } + } } } }; @@ -299,13 +310,78 @@ describe('halTransform service', () => { transformedElement = halTransform(plainElement); }); - it('should be a property of the element', () => { + it('should be loaded', () => { + expect(transformedElement.$loaded).to.be.true; + }); + + it('should have linked resources as properties', () => { expect(transformedElement.property).to.exist; - expect(transformedElement.embeddedProperty).to.exist; + }); + + it('should have linked actions as properties', () => { expect(transformedElement.action).to.exist; }); - describe('when using one of the properties', () => { + it('should have embedded resources as properties', () => { + expect(transformedElement.embedded).to.exist; + }); + + it('should have embedded, but not linked, resources as properties', () => { + expect(transformedElement.notLinked).to.exist; + }); + + describe('when after generating the properties from the links, each property', () => { + it('should be a function, if the link method is not "get"', () => { + expect(transformedElement).to.respondTo('action'); + }); + + it('should be a resource, if the link method is "get"', () => { + expect(transformedElement.property.$halTransformed).to.be.true; + }); + + describe('when a property is a resource', () => { + it('should not be callable', () => { + expect(transformedElement).to.not.to.respondTo('property'); + }); + + it('should not be loaded initially', () => { + expect(transformedElement.property.$loaded).to.be.false; + expect(transformedElement.notLinked.$loaded).to.be.true; + }); + + it('should be loaded, if the resource is embedded', () => { + expect(transformedElement.embedded.$loaded).to.be.true; + }); + + describe('when loading it', () => { + var resource; + + beforeEach(() => { + resource = transformedElement.property; + resource.$load(); + + $httpBackend.expectGET('/api/property').respond(200, { + name: 'name' + }); + $httpBackend.flush(); + }); + + it('should be loaded', () => { + expect(resource.$loaded).to.be.true; + }); + + it('should be updated', () => { + expect(resource.name).to.eq('name'); + }); + + it('should return itself in a promise if already loaded', () => { + expect(resource.$load()).to.eventually.eql(resource); + }); + }); + }); + }); + + describe.skip('when using one of the properties', () => { it('should have the same properties as the original', () => { expect(transformedElement.property.href).to.eq('/api/property'); expect(transformedElement.property.title).to.eq('Property'); diff --git a/frontend/app/components/api/api-v3/hal/hal-resource.service.ts b/frontend/app/components/api/api-v3/hal/hal-resource.service.ts index 0fba60a532..4824abdb06 100644 --- a/frontend/app/components/api/api-v3/hal/hal-resource.service.ts +++ b/frontend/app/components/api/api-v3/hal/hal-resource.service.ts @@ -26,20 +26,53 @@ // See doc/COPYRIGHT.rdoc for more details. //++ -function halResource(halTransform, HalLink) { +function halResource(halTransform, HalLink, $q) { return class HalResource { public $links; public $embedded; public $halTransformed: boolean = true; - constructor(protected $source) { - var source = this.$source.restangularized ? this.$source.plain() : angular.copy(this.$source); + protected static fromLink(link) { + return new HalResource({_links: {self: link}}, false); + } + + constructor(protected $source, public $loaded = true) { + var source = $source.restangularized ? $source.plain() : angular.copy($source); + this.$links = this.transformLinks(); this.$embedded = this.transformEmbedded(); delete source._links; delete source._embedded; angular.extend(this, source); + + angular.forEach(this.$links, (link, name:string) => { + link = link.$link; + + if (link.href && link.method == 'get' && name !== 'self') { + this[name] = HalResource.fromLink(link); + } + else if (link.method !== 'get') { + this[name] = link.$toFunc(); + } + }); + + angular.forEach(this.$embedded, (resource, name) => { + this[name] = resource; + }); + } + + public $load() { + if (!this.$loaded) { + this.$loaded = true; + + return this.$links.self().then(resource => { + angular.extend(this, resource); + return this; + }); + } + + return $q.when(this); } public $plain() {