Also inject context when calling via getProperty

master
Sven Slootweg 11 months ago
parent 417eb403fa
commit cf11bce977

@ -39,17 +39,28 @@ The schema merging will eventually become deep-merging, when multi-level recursi
const specialKeyRegex = /^\$[^\$]/;
function maybeCall(value, args, thisContext) {
function maybeCall(value, args, baseContext, getContextForModule, thisContext) {
return Promise.try(() => {
// TODO" Is the $get thing still relevant?
// FIXME: Only do this for actual fetch requests
let getter = (typeof value === "object" && value != null && value.$get != null)
? value.$get
: value;
if (typeof getter === "function") {
return getter.call(thisContext, ...args);
let actualGetter = (getter.__moduleID != null)
? getter.func
: getter;
if (typeof actualGetter === "function") {
let applicableContext = (getter.__moduleID != null)
// Defined in a module
? getContextForModule(getter.__moduleID)
// Defined in the root schema
: baseContext;
return actualGetter.call(thisContext, args, applicableContext);
} else {
return getter;
return actualGetter;
}
});
}
@ -122,18 +133,12 @@ function assignErrorPath(error, cursor) {
function makeEnvironment(context, getContextForModule) {
function callHandler(instruction) {
// NOTE: cursor is assumed to already be the key of the child
let { schemaKey, handler, args, allowErrors, cursor } = instruction;
let { handler, args, allowErrors, cursor } = instruction;
if (handler != null) {
return Promise.try(() => {
// This calls the data provider in the schema
if (handler.__moduleID != null) {
// Defined in a module
return Result.wrapAsync(() => maybeCall(handler.func, [ args, getContextForModule(handler.__moduleID) ], cursor.parent.schema));
} else {
// Defined in the root schema
return Result.wrapAsync(() => maybeCall(handler, [ args, context ], cursor.parent.schema));
}
return Result.wrapAsync(() => maybeCall(handler, args, context, getContextForModule, cursor.parent.schema));
}).then((result) => {
if (result.isOK) {
return result.value();
@ -235,6 +240,36 @@ module.exports = function createDLayer(options) {
? options.makeContext()
: {};
// NOTE: The code order is important here - there's a cyclical reference between getProperty and the combinedContext, and only getProperty gets hoisted!
let combinedContext = {
... generatedContext,
... context,
// FIXME: Figure out a way to annotate errors here with the path at which they occurred, *and* make clear that it was an internal property lookup
$getProperty: getProperty,
$getPropertyPath: function (object, propertyPath) {
let parsedPath = (typeof propertyPath === "string")
? propertyPath.split(".")
: propertyPath;
return Promise.reduce(parsedPath, (currentObject, pathSegment) => {
if (currentObject != null) {
return getProperty(currentObject, pathSegment);
} else {
// Effectively null-coalescing
return null;
}
}, object);
},
$make: function (typeID, args) {
return make(typeID, args, true);
},
$maybeMake: function (typeID, args) {
return make(typeID, args, false);
}
};
let getContextForModule = loaded.makeContextFactory(combinedContext);
function getProperty(object, property, args = {}) {
// TODO: Should this allow a single-argument, property-string-only variant for looking up properties on self?
// FIXME: Validatem
@ -243,7 +278,7 @@ module.exports = function createDLayer(options) {
}
if (property in object) {
return maybeCall(object[property], [ args, combinedContext ], object);
return maybeCall(object[property], args, combinedContext, getContextForModule, object);
} else {
// FIXME: Better error message with path
throw new Error(`No key '${property}' exists in the schema`);
@ -272,40 +307,13 @@ module.exports = function createDLayer(options) {
return instance;
}
}
let combinedContext = {
... generatedContext,
... context,
// FIXME: Figure out a way to annotate errors here with the path at which they occurred, *and* make clear that it was an internal property lookup
$getProperty: getProperty,
$getPropertyPath: function (object, propertyPath) {
let parsedPath = (typeof propertyPath === "string")
? propertyPath.split(".")
: propertyPath;
return Promise.reduce(parsedPath, (currentObject, pathSegment) => {
if (currentObject != null) {
return getProperty(currentObject, pathSegment);
} else {
// Effectively null-coalescing
return null;
}
}, object);
},
$make: function (typeID, args) {
return make(typeID, args, true);
},
$maybeMake: function (typeID, args) {
return make(typeID, args, false);
}
};
let cursor = createCursor({
query: query,
schema: schema
});
let evaluate = makeEnvironment(combinedContext, loaded.makeContextFactory(combinedContext));
let evaluate = makeEnvironment(combinedContext, getContextForModule);
// FIXME: Currently, top-level errors do not get a path property assigned to them, because that assignment happens on nested calls above
return evaluate(cursor);

Loading…
Cancel
Save