Reputation: 1
I'm attempting to dynamically set properties for an HTTP response using the getL
function, but it gives me back a Promise and I cannot set async
over the forEach
, since that breaks it (see the generateLinksForList
function). Is there another way to do this?
/**
* @module domain/helper
*/
const {
complement,
compose,
isNil,
pickBy
} = require('ramda');
const notNull = compose(complement(isNil));
/**
* @function cleanData
* @returns {undefined}
*/
const cleanData = (entity) => pickBy(notNull, entity);
/**
* @name generateRelations
* @returns {undefined}
*/
const generateRelations = () => ([]);
async function getL(repo, entityContext) {
let d = await repo.nextItem(entityContext);
console.log(d)
return d;
}
/**
* @name generateLinksForList
* @returns {undefined}
*/
const generateLinksForList = (entityContext, type, entityName, repo) => {
const relations = require(`./${entityName}/relations.js`)
const namespace = type + 'Relations';
const _relations = relations[namespace];
let host = 'http://localhost:4000';
let relationsList = [];
_relations.forEach((linkRelation) => {
Object.keys(linkRelation).forEach((key) => {
if (linkRelation.hasOwnProperty('next')) {
let relation = {};
let l = getL(repo, entityContext);
console.log('---- getL');
console.log(l);
if (l.length) {
relation.next = linkRelation.next
.replace('{nextId}', l[0].id)
}
relation.next = linkRelation.next
.replace('{fullhost}', host)
.replace('{id}', entityContext.id);
relationsList.push(relation);
}
if (linkRelation.hasOwnProperty('self')) {
let relation = {};
relation.self = linkRelation['self']
.replace('{fullhost}', host)
.replace('{id}', entityContext.id);
relationsList.push(relation);
}
})
});
return relationsList;
};
/**
* @function generateLinksForItem
* @static
* @returns {array}
*/
const generateLinksForItem = (entityContext, type, entityName) => {
const relations = require(`./${entityName}/relations.js`)
const namespace = type + 'Relations';
const _relations = relations[namespace];
let host = 'http://localhost:4000';
let token, eventToken;
let _list = [];
_relations.forEach((relRef) => {
Object.keys(relRef).forEach((keyRef) => {
if (relRef[keyRef].includes('{id}')) {
relRef[keyRef] = relRef[keyRef].replace(/{id}/, entityContext.id);
}
if (relRef[keyRef].includes('{fullhost}')) {
relRef[keyRef] = relRef[keyRef].replace(/{fullhost}/, host);
}
if (relRef[keyRef].includes('{token}')) {
relRef[keyRef] = relRef[keyRef].replace(/{token}/, token);
}
if (relRef[keyRef].includes('{eventToken}')) {
relRef[keyRef] = relRef[keyRef].replace(/{eventToken}/, eventToken);
}
_list.push({
rel: keyRef,
href: relRef[keyRef]
});
});
});
return _list;
};
/**
* @function generateClassList
* @static
* @returns {array}
*/
const generateClassList = (context) => (['organization']);
/**
* @function generateEntities
* @param {object} repo Repostory for generating entities under a resource.
* @returns {array}
*/
const generateEntities = (repo) => {
return repo.getAll()
.then((documentSnapshots) => {
return documentSnapshots.map((doc) => {
if (doc.exists) {
let data = doc.data()
return {
//class: generateClassList(data.id),
//rel: generateRelations(data.id),
properties: data
//links: generateLinksForItem(data.id, 'item', 'user')
};
}
});
});
};
/**
* @function generateActions
* @static
* @returns {array}
* @description
* Ok, so here we're basically scripting with CasperJS. The presumption is
* that there will be a generic client through which we can automate browser
* behaviors and platform capabilities (Cordova). We can think of hypermedia
* controls as projections from rhetorical relations over a domain knowledge
* graph that represents the plurality of connections or links in hypermedia
* ensembles (differentiations of numerical and other kinds of identity).
*/
const generateActions = (_itemForms, entity, entityName) => {
let host = `http://localhost:4000/api/${entityName}`;
_itemForms.forEach(function (itemRef, key) {
Object.keys(itemRef).forEach(function (keyRef) {
if (itemRef[keyRef].includes('{id}')) {
itemRef[keyRef] = itemRef[keyRef].replace(/{id}/, entity.id);
}
if (itemRef[keyRef].includes('{fullhost}')) {
itemRef[keyRef] = itemRef[keyRef].replace(/{fullhost}/, host);
}
if (itemRef.hasOwnProperty('properties')) {
itemRef.properties.forEach((p) => {
Object.keys(p).forEach((k) => {
if (p[k].includes('{status}')) {
p[k] = p[k].replace(/{status}/, 'pending');
}
});
});
}
});
});
return _itemForms;
};
module.exports = {
cleanData,
generateLinksForItem,
generateLinksForList,
generateClassList,
generateActions,
generateEntities
};
// EOF
This is where I'm using the generateLinksForList
function, hence why I cannot use async
for the containing map
:
/**
* @module app/place/get
* @description
* Get all places.
*/
const { itemForms } = require('../../domain/place/transitions');
const { Place } = require('../../domain/place');
const {
generateActions,
generateLinksForList,
} = require('../../domain/helper.js');
module.exports = ({ placeRepository }) => {
const all = () => {
return Promise
.resolve()
.then(() => placeRepository.getAll()
.then((documentSnapshots) => {
return documentSnapshots.map((doc) => {
let properties = doc.data() || {};
let place = Place(properties);
let links = generateLinksForList(place, 'item', 'place', placeRepository);
let actions = generateActions(itemForms, doc, 'places');
let props = Object.assign({}, place, {});
let hypermediaResponse = {
actions: actions,
links: links,
properties: props,
class: ['place'],
entities: []
};
if (doc.exists) {
return hypermediaResponse;
}
});
})
)
.catch(error => {
throw new Error(error);
})
}
return {
all
};
};
// EOF
The repo function:
/**
* @module infrastructure/repositories/place/index
* @description
* Repo/methods for places.
*/
const { toEntity } = require('./transform');
module.exports = ({ model, database }) => {
/**
* @name getAll
* @param {Object} args - Firestore clause (where, etc.);
* @returns {Object}
*/
const _getAll = async (...args) =>
await model
.listDocuments().then((docRefs) => database.firestore.getAll(...docRefs));
/**
* @name getAll
* @returns {Promise}
*/
const getAll = async () =>
await model.listDocuments()
.then((docRefs) => database.firestore.getAll(...docRefs));
/**
* @name prev
* @returns {undefined}
*/
const prev = async (...args) => {
let payload = args[0];
let docRef = model.doc(payload.id);
let snapshot = await docRef.get();
let last = snapshot.docs[snapshot.docs.length - 1];
return last.data();
};
/**
* @name next
* @returns {undefined}
*/
const nextItem = async (...args) => {
let payload = args[0];
const docRef = model.doc(payload.id);
const snapshot = (await docRef.get()).data();
const start = await model
.orderBy('createdAt')
.endBefore(snapshot.createdAt)
.limitToLast(1)
//.startAt(snapshot)
//.offset(1)
//.limit(1)
.get();
let list = [];
start.forEach((d) => {
list.push(d.data());
});
return list;
};
/**
* @name create
* @returns {object}
*/
const create = async (...args) => {
let payload = args[0];
let docRef = await model.doc(payload.id);
await docRef.set(payload);
return docRef.get().then((documentSnapshot) => {
return documentSnapshot.data();
})
};
/**
* @name update
* @returns {object}
*/
const update = async (...args) =>
await model.doc(args.id).update(...args);
/**
* @name findById
* @returns {object}
*/
const findById = async (...args) =>
await model.where('id', '==', args.id).get();
/**
* @name findOne
* @returns {object}
*/
const findOne = async (...args) => await model
.limit(1)
.get();
/**
* @name destroy
* @returns {object}
*/
const destroy = async (...args) =>
await model.doc(args.id).delete();
return {
getAll,
create,
update,
findById,
findOne,
destroy,
nextItem,
prev
};
};
// EOF
Upvotes: 0
Views: 421
Reputation: 4596
.forEach
won't wait for an async function. Use a normal loop:
for ( const linkRelation of relations ) {
for ( const key in linkRelation) {
...
const l = await getL(repo, entityContext);
...
}
}
Upvotes: 1