Allow optional parents to be appended to the path

pull/4734/head
Alex Dik 8 years ago
parent 8cfc8ea8ee
commit f9bfb6014e
  1. 53
      frontend/app/components/api/path-builder/path-builder.service.test.ts
  2. 124
      frontend/app/components/api/path-builder/path-builder.service.ts

@ -46,6 +46,7 @@ describe('pathBuilder service', () => {
var pathConfig:any;
var path:any;
var result;
var params:any;
var withoutParams;
var withParams;
@ -72,7 +73,7 @@ describe('pathBuilder service', () => {
describe('when calling it with params', () => {
beforeEach(() => {
result = path({param: 'param'});
result = path(params);
});
it('should generate a path with the param', () => {
@ -84,15 +85,22 @@ describe('pathBuilder service', () => {
beforeEach(() => {
pathConfig = {
string: 'foo{/param}',
array: [
'bar{/param}',
{
nestedString: 'nested-string',
nestedArray: ['nested-array', {}]
}
]
array: ['bar{/param}', {
nestedString: 'nested-string',
nestedArray: ['nested-array', {}]
}],
withParent: ['hello{/param}', {}, {
stringParent: 'parent/{stringParent}',
arrayParent: ['parent/{arrayParent}']
}],
withParentAndChild: ['world', {
child: 'child{/child}'
}, {
parent: 'parent/{parent}'
}]
};
pathCollection = pathBuilder.buildPaths(pathConfig);
params = {param: 'param'};
});
it('should return the path collection', () => {
@ -138,5 +146,34 @@ describe('pathBuilder service', () => {
});
});
});
describe('when the path has a parent', () => {
beforeEach(() => {
path = pathCollection.withParent;
withParams = 'parent/parentId/hello';
withoutParams = 'hello';
});
describe('when the parent is a string', () => {
testCallablePath(() => {
params = {stringParent: 'parentId'};
});
});
describe('when the parent is a array', () => {
testCallablePath(() => {
params = {arrayParent: 'parentId'};
});
});
});
describe('when the path is a child of a path with a parent', () => {
testCallablePath(() => {
path = pathCollection.withParentAndChild.child;
params = {child: 'childId', parent: 'parentId'};
withParams = 'parent/parentId/world/child/childId';
withoutParams = 'world/child';
});
});
});
});

@ -28,6 +28,86 @@
import {opApiModule} from '../../../angular-modules';
class PathTemplate {
/**
* The template string of the path segment.
*/
public template:string;
/**
* The children of the path segment.
*/
public children = {};
/**
* The optional parents of the path segment.
* Parents are only prepended to the path segment, if a parameter of the same name as the parent
* is provided.
*/
public parents = {};
/**
* Create the object while initialising its optional parents and children.
*
* @param config
* @param parent
*/
constructor(public config?, public parent?:PathTemplate) {
var children;
var parents;
if (!Array.isArray(config)) {
this.config = [config];
}
[this.template = '', children = {}, parents = {}] = this.config;
angular.forEach(children, (childConfig, childName) => {
this.children[childName] = new PathTemplate(childConfig, this);
});
angular.forEach(parents, (parentConfig, parentName) => {
this.parents[parentName] = new PathTemplate(parentConfig, this.parent);
});
}
/**
* Return the path as a callable instance.
* Children of the pathTemplate object are properties of the callable.
*
* @return {(params?:{})=>string}
*/
public callable() {
const callable = (params = {}) => {
return URI.expand(this.build(params), params).valueOf();
};
angular.forEach(this.children, (child, childName) => {
callable[childName] = child.callable();
});
return callable;
}
/**
* Merge parent templates (if any) with the current template recursively.
*
* @param params
* @return {string}
*/
public build(params) {
Object.keys(params).forEach(name => {
console.log('NAME', name, params, this.parents);
const parent = this.parents[name];
if (parent) {
this.parent = parent;
return;
}
});
var parent = this.parent ? this.parent.build(params) + '/' : '';
return parent + this.template;
}
}
/**
* Allows defining flexible paths using urijs.
*
@ -36,9 +116,6 @@ import {opApiModule} from '../../../angular-modules';
* URITemplates: https://tools.ietf.org/html/rfc6570#section-2.1
*/
export class PathBuilderService {
constructor(protected URI) {
}
/**
* Return a collection of callable paths.
*
@ -49,49 +126,12 @@ export class PathBuilderService {
public buildPaths(templates:any) {
const pathCollection = {};
angular.forEach(templates, (template, name) => {
pathCollection[name] = this.buildPath(template);
angular.forEach(templates, (config, name) => {
pathCollection[name] = new PathTemplate(config).callable();
});
return pathCollection;
}
/**
* Return a callable path, that receives arguments to pass to the URITemplate.
*
* @param config: A string or an array where the first argument is the template and the second
* is config for nested paths.
* @return A callable path
*/
protected buildPath(config) {
const isArray = Array.isArray(config);
const template = isArray ? config[0] : config;
const callable = this.getCallable(template);
if (isArray) {
angular.forEach(config[1], (config, name) => {
if (Array.isArray(config)) {
config[0] = template + '/' + config[0];
} else {
config = template + '/' + config;
}
callable[name] = this.buildPath(config);
});
}
return callable;
}
/**
* Return a function wrapper for `URI.expand()`.
*
* @param template
* @return {(values?:{})=>boolean|string}
*/
private getCallable(template:string) {
return (values = {}) => this.URI.expand(template, values).valueOf();
}
}
opApiModule.service('pathBuilder', PathBuilderService);

Loading…
Cancel
Save