Skip to content
This repository has been archived by the owner on Oct 7, 2021. It is now read-only.

Commit

Permalink
Merge ec82cf5 into c5b637e
Browse files Browse the repository at this point in the history
  • Loading branch information
Smolli committed Jan 23, 2018
2 parents c5b637e + ec82cf5 commit 4d569ec
Show file tree
Hide file tree
Showing 9 changed files with 109 additions and 13 deletions.
6 changes: 6 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
root = true

[*]
indent_style = space
indent_size = 2
charset = utf-8
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,6 @@ node_modules
dist
coverage
html-report

*.iml
.idea/
19 changes: 12 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"url": "http://github.com/deblockt/hal-rest-client/issues"
},
"dependencies": {
"@types/lodash": "^4.14.92",
"axios": "^0.15.3",
"reflect-metadata": "^0.1.9",
"uri-templates": "^0.1.9"
Expand Down
2 changes: 1 addition & 1 deletion src/hal-json-parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ export class JSONParser {
for (const linkKey in json._links) {
if ("self" !== linkKey) {
const href = this.extractURI(links[linkKey]);
const type = Reflect.getMetadata("halClient:specificType", c.prototype, linkKey) || HalResource;
const propKey = halToTs[linkKey] || linkKey;
const type = Reflect.getMetadata("halClient:specificType", c.prototype, propKey) || HalResource;
const linkResource = createResource(this.halRestClient, type, href);
for (const propInLinkKey of Object.keys(links[linkKey])) {
linkResource.prop(propInLinkKey, links[linkKey][propInLinkKey]);
Expand Down
12 changes: 12 additions & 0 deletions src/hal-resource-interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,18 @@ export interface IHalResource {
*/
fetch(forceOrParams: boolean|object): Promise<this>;

/**
* fetch an array of the current resource
*
* Unlike #fetch(boolean|object) this method needs #uri to be set. So it's not possible to fetch a resource in
* advance.
*
* @param {object} params: If the uri is a template link, you can set the parameters.
* @param {IHalResourceConstructor<this>} resource: An optional resource to create the array items of.
* @returns {Promise<this[]>} Will return an array of resources.
*/
fetchArray(params?: object, resource?: IHalResourceConstructor<this>): Promise<this[]>;

/**
* get or set a prop or a link.
* if name is a link. link function is used
Expand Down
34 changes: 29 additions & 5 deletions src/hal-resource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { DefaultSerializer, IJSONSerializer } from "./hal-json-serializer";
import { IHalResource, IHalResourceConstructor } from "./hal-resource-interface";
import { HalRestClient } from "./hal-rest-client";
import { URI } from "./uri";
import * as _ from 'lodash';

export class HalResource implements IHalResource {
public readonly links = {};
Expand Down Expand Up @@ -39,6 +40,13 @@ export class HalResource implements IHalResource {
}
}

public fetchArray(params?: object, resource?: IHalResourceConstructor<this>): Promise<this[]> {
return this.restClient.fetchArray(
this.uri.fill(params as object),
resource ? resource.prototype.constructor : this.constructor as IHalResourceConstructor<this>,
) as Promise<this[]>;
}

/**
* to clear value use null not undefined
*/
Expand Down Expand Up @@ -133,11 +141,8 @@ export class HalResource implements IHalResource {

for (const prop of props) {
const jsonKey = this.tsProptoHalProd(prop) ;
if (this.props[prop] !== undefined && this.props[prop] !== null && this.props[prop].onInitEnded !== undefined) {
json[jsonKey] = serializer.parseResource(this.props[prop]);
} else {
json[jsonKey] = serializer.parseProp(this.props[prop]);
}

json[jsonKey] = this.serializeProperty(prop, serializer);
}

for (const link of links) {
Expand All @@ -147,4 +152,23 @@ export class HalResource implements IHalResource {

return json;
}

private serializeProperty(prop, serializer: IJSONSerializer, arrayItem?: any) {
let result = null;

const property = arrayItem || this.props[prop];

if (!_.isEmpty(property) && _.isFunction(property.onInitEnded)) {
result = serializer.parseResource(property)
} else if (_.isArray(property)) {
result = _(property)
.map(item => this.serializeProperty(prop, serializer, item))
.toArray()
.value()
} else {
result = serializer.parseProp(property)
}

return result
}
}
17 changes: 17 additions & 0 deletions src/test/model/array-resource.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import {HalResource} from '../../hal-resource';
import {HalProperty} from '../../hal-decorator';

export class ArrayResourceItem extends HalResource {

@HalProperty()
public id: Number;

}

export class ArrayResource extends HalResource {

@HalProperty('items', ArrayResourceItem)
public items: ArrayResourceItem[];

}

28 changes: 28 additions & 0 deletions src/test/test-resource-class.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { test } from "tape-async";
import { ContactInfos } from "./model/contact-infos";
import { Cyclical, CyclicalList } from "./model/cyclical";
import { Person } from "./model/person";
import {ArrayResource, ArrayResourceItem} from './model/array-resource';

// mock list response
function initTests() {
Expand Down Expand Up @@ -122,6 +123,20 @@ function initTests() {
testNock
.get("/cyclicals/refresh")
.reply(200, cyclicals);

const arrayResource = {
_links: {
self: 'http://test.fr/array',
},
items: [
{id: 1, _links: {self: {href: 'http://test.fr/array/1'}}},
{id: 2, _links: {self: {href: 'http://test.fr/array/2'}}},
],
};

testNock
.get("/arrayResource")
.reply(200, arrayResource);
}

test("can get single string prop", async (t) => {
Expand Down Expand Up @@ -267,3 +282,16 @@ test("cyclical property have good class type", async (t) => {
t.ok(Array.isArray(cyclicals.cyclicals), "cyclicals is an array");
t.equals(cyclicals.cyclicals[0].property, "name");
});

test('fetching resource with array contains valid typed resources', async (t) => {
initTests();

const client = createClient('http://test.fr');
const resource: ArrayResource = await client.fetch('/arrayResource', ArrayResource);

t.ok(resource instanceof ArrayResource, 'Result has the correct type');
t.ok(Array.isArray(resource.items), 'Result content is array');
t.ok(resource.items.length === 2, 'Correct count of array items');
t.ok(resource.items[0] instanceof ArrayResourceItem, 'Array item has correct type');
t.ok(resource.items[0].id === 1, 'Correct item returned.');
});

0 comments on commit 4d569ec

Please sign in to comment.