Skip to content

Commit

Permalink
feat: entry list class CMS-2765
Browse files Browse the repository at this point in the history
  • Loading branch information
simon-scherzinger committed May 12, 2017
1 parent 578c6d6 commit aee1ab8
Show file tree
Hide file tree
Showing 7 changed files with 268 additions and 8 deletions.
12 changes: 10 additions & 2 deletions src/resources/ListResource.js
Expand Up @@ -3,6 +3,7 @@ import Resource, { environmentSymbol, resourceSymbol } from './Resource';
const nameSymbol = Symbol('_name');
const listClassSymbol = Symbol('_listClass');
const itemClassSymbol = Symbol('_itemClass');
const itemSchemaSymbol = Symbol('_itmeSchema');

/**
* Generic list resource class. Represents {@link
Expand All @@ -25,8 +26,9 @@ export default class ListResource extends Resource {
* @param {?object} traversal traversal from which traverson can continue.
* @param {ListResource} ListClass Class constructor for list types
* @param {Resource} ItemClass Class constructor for item types
* @param {object?} itemSchema optional schema for list items
*/
constructor(resource, environment, name, traversal, ListClass = ListResource, ItemClass = Resource) {
constructor(resource, environment, name, traversal, ListClass = ListResource, ItemClass = Resource, itemSchema) {
super(resource, environment, traversal);

Object.defineProperties(this, {
Expand All @@ -42,6 +44,7 @@ export default class ListResource extends Resource {

this[listClassSymbol] = ListClass;
this[itemClassSymbol] = ItemClass;
this[itemSchemaSymbol] = itemSchema;
this[nameSymbol] = name || Object.keys(this[resourceSymbol].allEmbeddedResources())[0];
}

Expand All @@ -53,7 +56,12 @@ export default class ListResource extends Resource {
*/
getAllItems() {
const array = this[resourceSymbol].embeddedArray(this[nameSymbol]) || [];
return array.map(resource => new this[itemClassSymbol](resource, this[environmentSymbol]));
return array.map((resource) => {
if (this[itemSchemaSymbol]) {
return new this[itemClassSymbol](resource, this[environmentSymbol], this[itemSchemaSymbol]);
}
return new this[itemClassSymbol](resource, this[environmentSymbol]);
});
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/resources/datamanager/TemplateList.js
Expand Up @@ -2,7 +2,7 @@ import ListResource from '../ListResource';
import TemplateResource from './TemplateResource';

/**
* Client list class
* Template list class
*
* @class
*/
Expand Down
45 changes: 45 additions & 0 deletions src/resources/publicAPI/EntryList.js
@@ -0,0 +1,45 @@
import halfred from 'halfred';

import { getSchema } from '../../helper';
import ListResource from '../ListResource';
import EntryResource from './EntryResource';

/**
* Entry list class
*
* @class
*/
export default class EntryList extends ListResource {
/**
* Creates a new {@link EntryList}.
*
* @param {object} resource resource loaded from the API.
* @param {string} environment the environment this resource is associated to.
* @param {string} name name of the embedded items.
* @param {object} schema JSON Schema for list items.
* @param {object?} traversal traversal from which traverson can continue.
*/
constructor(resource, environment, name, schema, traversal) {
super(resource, environment, name, traversal, EntryList, EntryResource, schema);
}
}

/**
* Asynchronously create a new {@link EntryList}. This can be used when the schema is not known
* before creating the EntryList.
*
* @param {object} resource loaded resource
* @param {environment} environment the environment of this resource
* @param {string} name name of the embedded items
* @param {object?} traversal traversal for continuing
* @returns {Promise<EntryResource>} {@link Promise} resolving to the newly created {@link
* EntryResource}
*/
export function create(resource, environment, name, traversal) {
return Promise.resolve()
.then(() => {
const res = halfred.parse(resource);
return getSchema(res.link('self').profile);
})
.then(schema => new EntryList(resource, environment, name, schema, traversal));
}
6 changes: 3 additions & 3 deletions src/resources/publicAPI/EntryResource.js
Expand Up @@ -54,10 +54,10 @@ export default class EntryResource extends Resource {
* Creates a new EntryResource
* @param {object} resource loaded resource
* @param {environment} environment the environment of this resource
* @param {object|undefined} traversal traversal for continuing
* @param {object} schema JSON Schema for this entry
* @param {object?} traversal traversal for continuing
*/
constructor(resource, environment, traversal, schema) {
constructor(resource, environment, schema, traversal) {
super(resource, environment, traversal);

if (!schema) {
Expand Down Expand Up @@ -283,5 +283,5 @@ export function create(resource, environment, traversal) {
const res = halfred.parse(resource);
return getSchema(res.link('self').profile);
})
.then(schema => new EntryResource(resource, environment, traversal, schema));
.then(schema => new EntryResource(resource, environment, schema, traversal));
}
2 changes: 1 addition & 1 deletion test/datamanager/Model.test.js
Expand Up @@ -41,7 +41,7 @@ describe('Model ListResource', () => {
it('should be instance of ModelList', () => {
list.should.be.instanceOf(ModelList);
});
it('should have AccountResource items', () => {
it('should have ModelResource items', () => {
list.getAllItems().forEach(item => item.should.be.instanceOf(ModelResource));
});
});
Expand Down
170 changes: 170 additions & 0 deletions test/mocks/public-entry-list.json
@@ -0,0 +1,170 @@
{
"count": 1,
"total": 1,
"_links": {
"collection": {
"profile": "https://datamanager.entrecode.de/api/schema/beefbeef/allFields",
"href": "https://datamanager.entrecode.de/api/beefbeef"
},
"curies": {
"name": "Test DM",
"href": "https://datamanager.entrecode.de/api/doc/beefbeef/{rel}",
"templated": true
},
"self": {
"profile": "https://datamanager.entrecode.de/api/schema/beefbeef/allFields",
"href": "https://datamanager.entrecode.de/api/beefbeef/allFields"
},
"beefbeef:allFields/options": {
"href": "https://datamanager.entrecode.de/api/beefbeef/allFields{?_created,_createdFrom,_createdTo,_creator,_fields,_id,_levels,_modified,_modifiedFrom,_modifiedTo,_private,account,asset,assets,assets~,boolean,created,createdFrom,createdTo,datetime,datetimeFrom,datetimeTo,decimal,decimalFrom,decimalTo,email,email~,entries,entries~,entry,formattedText~,id,location,locationFrom,locationTo,modified,modifiedFrom,modifiedTo,number,numberFrom,numberTo,page,phone,phone~,private,role,size,sort,text,text~,url,url~}",
"templated": true
}
},
"_embedded": {
"beefbeef:allFields": {
"_id": "B17u3r5lx-",
"_created": "2017-05-10T13:29:19.893Z",
"_creator": null,
"_modified": "2017-05-10T13:29:19.893Z",
"id": "B17u3r5lx-",
"created": "2017-05-10T13:29:19.893Z",
"modified": "2017-05-10T13:29:19.893Z",
"private": false,
"text": "asdf",
"formattedText": "asdf",
"number": 1,
"decimal": 1,
"boolean": true,
"datetime": "2017-04-29T22:00:00.000Z",
"location": {
"latitude": 4,
"longitude": 3
},
"email": "me@what.com",
"url": "example.com",
"phone": "+49 5555 5521",
"json": {},
"entry": "EJlJtSrkgl",
"entries": [
"EJlJtSrkgl"
],
"asset": "03685901-8bbe-40a2-89f2-a7c9a5db5bf8",
"assets": [
"03685901-8bbe-40a2-89f2-a7c9a5db5bf8"
],
"account": null,
"role": null,
"_links": {
"collection": {
"profile": "https://datamanager.entrecode.de/api/schema/beefbeef/allFields",
"href": "https://datamanager.entrecode.de/api/beefbeef/allFields"
},
"self": {
"profile": "https://datamanager.entrecode.de/api/schema/beefbeef/allFields",
"href": "https://datamanager.entrecode.de/api/beefbeef/allFields?_id=B17u3r5lx-"
},
"beefbeef:allFields/asset": {
"profile": "https://entrecode.de/schema/asset",
"title": "dafuq",
"href": "https://datamanager.entrecode.de/files/03685901-8bbe-40a2-89f2-a7c9a5db5bf8"
},
"beefbeef:allFields/assets": {
"profile": "https://entrecode.de/schema/asset",
"title": "dafuq",
"href": "https://datamanager.entrecode.de/files/03685901-8bbe-40a2-89f2-a7c9a5db5bf8"
},
"beefbeef:allFields/entry": {
"profile": "https://datamanager.entrecode.de/api/schema/beefbeef/contains_entries",
"href": "https://datamanager.entrecode.de/api/beefbeef/contains_entries?id=EJlJtSrkgl",
"name": "contains_entries",
"title": "EJlJtSrkgl"
},
"beefbeef:allFields/entries": {
"profile": "https://datamanager.entrecode.de/api/schema/beefbeef/contains_entries",
"href": "https://datamanager.entrecode.de/api/beefbeef/contains_entries?id=EJlJtSrkgl",
"name": "contains_entries",
"title": "EJlJtSrkgl"
}
},
"_embedded": {
"beefbeef:allFields/asset/asset": {
"assetID": "03685901-8bbe-40a2-89f2-a7c9a5db5bf8",
"title": "dafuq",
"type": "image",
"created": "2017-04-05T11:29:22.974Z",
"deleted": null,
"files": [
{
"url": "https://cdn2.entrecode.de/files/beefbeef/PdQoDSKVaujMjvCm9j4G3fEF.gif",
"mimetype": "image/gif",
"size": 121190,
"resolution": {
"width": 784,
"height": 487
},
"locale": null,
"created": "2017-04-05T11:29:22.968+00:00",
"modified": "2017-04-05T11:29:22.968+00:00",
"assetID": "03685901-8bbe-40a2-89f2-a7c9a5db5bf8"
}
],
"_links": {
"self": {
"profile": "https://entrecode.de/schema/asset",
"href": "https://datamanager.entrecode.de/asset/beefbeef?assetID=03685901-8bbe-40a2-89f2-a7c9a5db5bf8",
"title": "dafuq"
},
"collection": {
"profile": "https://entrecode.de/schema/assets",
"href": "https://datamanager.entrecode.de/asset/beefbeef"
},
"ec:asset/best-file": {
"href": "https://datamanager.entrecode.de/files/03685901-8bbe-40a2-89f2-a7c9a5db5bf8{?size,thumb}",
"templated": true
}
}
},
"beefbeef:allFields/assets/asset": {
"assetID": "03685901-8bbe-40a2-89f2-a7c9a5db5bf8",
"title": "dafuq",
"type": "image",
"created": "2017-04-05T11:29:22.974Z",
"deleted": null,
"files": [
{
"url": "https://cdn2.entrecode.de/files/beefbeef/PdQoDSKVaujMjvCm9j4G3fEF.gif",
"mimetype": "image/gif",
"size": 121190,
"resolution": {
"width": 784,
"height": 487
},
"locale": null,
"created": "2017-04-05T11:29:22.968+00:00",
"modified": "2017-04-05T11:29:22.968+00:00",
"assetID": "03685901-8bbe-40a2-89f2-a7c9a5db5bf8"
}
],
"_links": {
"self": {
"profile": "https://entrecode.de/schema/asset",
"href": "https://datamanager.entrecode.de/asset/beefbeef?assetID=03685901-8bbe-40a2-89f2-a7c9a5db5bf8",
"title": "dafuq"
},
"collection": {
"profile": "https://entrecode.de/schema/assets",
"href": "https://datamanager.entrecode.de/asset/beefbeef"
},
"ec:asset/best-file": {
"href": "https://datamanager.entrecode.de/files/03685901-8bbe-40a2-89f2-a7c9a5db5bf8{?size,thumb}",
"templated": true
}
}
}
},
"_modelTitleField": "_id",
"_modelTitle": "allFields",
"_entryTitle": "B17u3r5lx-"
}
}
}
39 changes: 38 additions & 1 deletion test/publicAPI/EntryResource.test.js
Expand Up @@ -7,11 +7,48 @@ const fs = require('fs');
const mock = require('../mocks/nock');

const Resource = require('../../lib/resources/Resource').default;
const ListResource = require('../../lib/resources/ListResource').default;
const EntryList = require('../../lib/resources/publicAPI/EntryList');
const EntryResource = require('../../lib/resources/publicAPI/EntryResource');

const should = chai.should();
chai.use(sinonChai);

describe('Entry List', () => {
let listJson;
let list;
before(() => {
return new Promise((resolve, reject) => {
fs.readFile(`${__dirname}/../mocks/public-entry-list.json`, 'utf-8', (err, res) => {
if (err) {
return reject(err);
}
return resolve(JSON.parse(res));
});
})
.then((json) => {
listJson = json;
});
});
beforeEach(() => {
mock.reset();
return EntryList.create(listJson, 'live', 'beefbeef:allFields')
.then(l => list = l); // eslint-disable-line no-return-assign
});
afterEach(() => {
list = null;
});
it('should be instance of ListResource', () => {
list.should.be.instanceOf(ListResource);
});
it('should be instance of ModelList', () => {
list.should.be.instanceOf(EntryList.default);
});
it('should have ModelResource items', () => {
list.getAllItems().forEach(item => item.should.be.instanceOf(EntryResource.default));
});
});

describe('Entry Resource', () => {
let resourceJson;
let resource;
Expand Down Expand Up @@ -64,7 +101,7 @@ describe('Entry Resource', () => {
should.not.exist(resource.getFieldType('nonexistent'));
});
it('should return undefined on non matching type', () => {
const res = new EntryResource.default(resourceJson, 'live', null, { // eslint-disable-line new-cap
const res = new EntryResource.default(resourceJson, 'live', { // eslint-disable-line new-cap
allOf: [
null,
{
Expand Down

0 comments on commit aee1ab8

Please sign in to comment.