src/services/requested-fields-extractor.js
/**
* @typedef {{
* fields: Array<{
* field: string;
* isVirtual: boolean;
* }>
* }} Schema
*/
/**
* @param {string} associationName
* @param {string[]} requestedFields
* @param {Schema} schema
* @returns {string[]}
*/
function extractRequestedFieldsForAssociation(associationName, requestedFields, schema) {
const referencesSmartFields = requestedFields.some(
(fieldName) => schema.fields.some((field) => field.field === fieldName && field.isVirtual),
);
// TODO: have a way of specifying which actual field is used for the computation of a smart field
// and use that info to only retrieve fields that are needed
if (referencesSmartFields) {
return [`${associationName}`];
}
return requestedFields.map((fieldName) => `${associationName}.${fieldName}`);
}
function extractRequestedSmartField(requestedFields, schema) {
const schemaSmartFields = schema.fields.filter(({ isVirtual }) => isVirtual);
return requestedFields[schema.name].split(',')
.filter((fieldName) => schemaSmartFields.some(({ field }) => field === fieldName));
}
/**
* @param {Record<string, string>} requestedFields
* @param {*} modelOrAssociation
* @param {{
* [collection: string]: Schema
* }} schemas
* @returns {string[]}
*/
function extractRequestedFields(requestedFields, modelOrAssociation, schemas) {
if (!requestedFields || !requestedFields[modelOrAssociation.name]) { return null; }
// NOTICE: Force the primaryKey retrieval to store the records properly in
// the client.
const primaryKeyArray = [Object.keys(modelOrAssociation.primaryKeys)[0]];
const allAssociationFields = Object.keys(modelOrAssociation.associations)
// NOTICE: Remove fields for which attributes are not explicitly set
// in the requested fields
.filter((associationName) => requestedFields[associationName])
.map((associationName) => extractRequestedFieldsForAssociation(
associationName,
requestedFields && requestedFields[associationName]
? requestedFields[associationName].split(',')
: [],
schemas[modelOrAssociation.associations[associationName].target.name],
))
.flat();
const modelFields = requestedFields[modelOrAssociation.name]
.split(',')
.filter((fieldName) =>
Object.prototype.hasOwnProperty.call(modelOrAssociation.rawAttributes, fieldName));
const smartFields = extractRequestedSmartField(requestedFields, schemas[modelOrAssociation.name]);
return Array.from(new Set([
...primaryKeyArray,
...modelFields,
...smartFields,
...allAssociationFields,
]));
}
module.exports = extractRequestedFields;