You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

74 lines
2.5 KiB
JavaScript

"use strict";
const Promise = require("bluebird");
const syncpipe = require("syncpipe");
const util = require("util");
const ID = Symbol("dlayer-source object ID");
// TODO: Make more readable
module.exports = {
withSources: function withSources(schemaObject) {
let { $sources, ... rest } = schemaObject;
let generatedProperties = syncpipe($sources ?? {}, [
(_) => Object.entries(_),
(_) => _.flatMap(([ source, properties ]) => {
return Object.entries(properties).map(([ property, selector ]) => {
// This is to support property name shorthand used in place of a selector function
let effectiveSelector = (typeof selector === "string")
? (result) => {
// FIXME: Consider whether to add this check or not; currently, it would break stuff in CVM
// if (selector in result) {
return result[selector];
// } else {
// throw new Error(`Result object does not have a '${selector}' property`);
// }
}
: selector;
let getter = function (_args, context) {
return Promise.try(() => {
if (properties[ID] != null) {
let dataSource = context.sources[source];
if (dataSource != null) {
// console.log(`Calling source '${source}' with ID ${util.inspect(properties[ID])}`);
return dataSource.load(properties[ID]);
} else {
throw new Error(`Attempted to read from source '${source}', but no such source is registered`);
}
} else {
// FIXME: Better error message
throw new Error(`Must specify a dlayer-source ID`);
}
}).then((result) => {
// console.log(`Result [${source}|${util.inspect(properties[ID])}] ${util.inspect(result)}`);
// TODO: How to deal with null results? Allow them or not? Make it an option?
if (result != null) {
return effectiveSelector(result);
} else {
throw new Error(`Null-ish result returned for ID '${properties[ID]}' from source '${source}'; this is not allowed, and there is probably a bug in your code. Please file a ticket if you have a good usecase for null-ish results!`);
}
});
};
return [ property, getter ];
});
}),
(_) => Object.fromEntries(_)
]);
// NOTE: We always specify the generated properties first, so that properties can be overridden by explicit known values to bypass the source lookup, if needed by the implementation
return {
... generatedProperties,
... rest
};
},
ID: ID
};