Compare commits

...

4 Commits

@ -15,6 +15,7 @@ const loadModules = require("./load-modules");
// FIXME: $getProperty, $getPropertyPath, maybe $resolveObject/$query?
// FIXME: Allow setting an evaluation depth limit for queries, to limit eg. recursion
// FIXME: recurseDepth, recurseLabel/recurseGoto
// TODO: Internal queries, but only in modules, and only as a last resort
/* Process design:
@ -38,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;
}
});
}
@ -121,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();
@ -154,7 +160,7 @@ function makeEnvironment(context, getContextForModule) {
assignErrorPath(error, cursor);
});
} else {
throw new Error(`No key '${schemaKey}' exists in the schema`);
throw new Error(`No key '${cursor.schemaPath.at(-1)}' exists in the schema`);
}
}
@ -234,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
@ -242,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`);
@ -271,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);

@ -72,7 +72,6 @@ let moduleBlockDevices = {
return {
path: path,
testContext: function (_, { counter }) {
// MARKER: Patch context on type methods, and continue testing LVM implementation in CVM/sysquery
console.log(`[context ${counter}] BlockDevice::testContext`);
return true;
}

@ -1,6 +1,6 @@
{
"name": "dlayer",
"version": "0.1.2",
"version": "0.1.3",
"main": "index.js",
"repository": "https://git.cryto.net/joepie91/dlayer.git",
"author": "Sven Slootweg <admin@cryto.net>",

Loading…
Cancel
Save