Add async type factory support, and InvalidObject support

master
Sven Slootweg 1 year ago
parent 3e0c1b6b56
commit 16c8f4d208

@ -7,6 +7,7 @@ const Result = require("@joepie91/result");
const createCursor = require("./cursor");
const deepMergeAndMap = require("./deep-merge-and-map");
const loadModules = require("./load-modules");
const InvalidObject = require("./invalid-object");
// TODO: Bounded/unbounded recursion
// TODO: Should we allow async context generation? Both in root schema *and* in modules
@ -172,7 +173,9 @@ function makeEnvironment(context, getContextForModule) {
let { cursor } = instruction;
if (Array.isArray(value)) {
return Promise.map(value, (item, i) => {
return Promise.filter(value, (object) => {
return (object !== InvalidObject);
}).map((item, i) => {
let itemCursor = cursor
.child(i, i)
.override({
@ -182,7 +185,7 @@ function makeEnvironment(context, getContextForModule) {
return applyRules(itemCursor);
});
} else {
} else if (value !== InvalidObject) {
let itemCursor = cursor
.override({
query: query,
@ -190,6 +193,8 @@ function makeEnvironment(context, getContextForModule) {
});
return applyRules(itemCursor);
} else {
return undefined;
}
}
@ -287,7 +292,7 @@ module.exports = function createDLayer(options) {
}
}
function make(typeID, args, existenceRequired) {
async function make(typeID, args, existenceRequired) {
let type = loaded.types[typeID].func;
if (type == null) {
@ -297,9 +302,9 @@ module.exports = function createDLayer(options) {
return;
}
} else {
let instance = type(args);
let instance = await type(args);
if (loaded.extensions[typeID] != null) {
if (loaded.extensions[typeID] != null && instance !== InvalidObject) {
for (let [ key, extension ] of Object.entries(loaded.extensions[typeID])) {
// TODO: Possibly make this more performant by making it possible to do an Object.assign? Or does that not matter for performance?
instance[key] = extension.func;
@ -330,4 +335,4 @@ module.exports.markAcceptableError = function (error) {
};
};
module.exports.InvalidObject = InvalidObject;

@ -0,0 +1,3 @@
"use strict";
module.exports = Symbol("dlayer:InvalidObject");

@ -4,6 +4,7 @@
const syncpipe = require("syncpipe");
const mapObject = require("map-obj");
const deepMergeAndMap = require("./deep-merge-and-map");
const InvalidObject = require("./invalid-object");
/*
Take a list of modules; each module specifies a name, schema root, types, type extensions, and a context factory function. Each module is internally assigned a unique ID. This unique ID is associated with each type factory and type extension method, and used as the key for a map of context factories; that way, upon invoking those methods, the module's own corresponding context can be injected. Only a single context should be created per module per request, so there should be a cache layer for the contexts (keyed by module ID), with each request creating a new cache.
@ -35,13 +36,17 @@ function createTypeTracker() {
// No context provided to type factory functions for now, since they are not allowed to be async for now anyway
// FIXME: Maybe add a warning if the user returns a Promise from a factory, asking them to file a bug if they really need it?
// func: wrapModuleFunction(module, factory)
func: function (... args) {
let instance = factory(... args);
// We need to patch every created object, so that the correct context gets injected into its type-specific methods when they are called
return mapObject(instance, (key, value) => {
return [ key, wrapModuleValue(module, value) ];
});
func: async function (... args) {
let instance = await factory(... args);
if (instance !== InvalidObject) {
// We need to patch every created object, so that the correct context gets injected into its type-specific methods when they are called
return mapObject(instance, (key, value) => {
return [ key, wrapModuleValue(module, value) ];
});
} else {
return instance;
}
}
};
}

@ -5,7 +5,7 @@ const dlayer = require("..");
const syncpipe = require("syncpipe");
let fakeDriveTree = {
one: [ "/dev/1a", "/dev/1b" ],
one: [ "/dev/1a", "/dev/1b", "INVALID" ],
two: [ "/dev/2a" ]
};
@ -53,7 +53,8 @@ let moduleDrives = {
_ => (names != null)
? _.filter(([ name, _devices ]) => names.includes(name))
: _,
_ => _.map(([ name, _devices ]) => $make("sysquery.core.Drive", { name }))
_ => _.map(([ name, _devices ]) => $make("sysquery.core.Drive", { name })),
_ => Promise.all(_)
]);
}
}
@ -68,14 +69,19 @@ let moduleDrives = {
let moduleBlockDevices = {
name: "Block Devices",
types: {
"sysquery.core.BlockDevice": function ({ path }) {
return {
path: path,
testContext: function (_, { counter }) {
console.log(`[context ${counter}] BlockDevice::testContext`);
return true;
}
};
"sysquery.core.BlockDevice": async function ({ path }) {
if (path === "INVALID") {
// Simulating an async type creation function that 'detects validity' of a specified path
return dlayer.InvalidObject;
} else {
return {
path: path,
testContext: function (_, { counter }) {
console.log(`[context ${counter}] BlockDevice::testContext`);
return true;
}
};
}
}
},
extensions: {
@ -83,7 +89,9 @@ let moduleBlockDevices = {
blockDevices: async function (_, { counter, $getProperty, $make }) {
console.log(`[context ${counter}] Drive::blockDevices`);
return fakeDriveTree[await $getProperty(this, "name")].map((path) => {
let root = fakeDriveTree[await $getProperty(this, "name")];
return Promise.map(root, (path) => {
return $make("sysquery.core.BlockDevice", { path });
});
}
@ -100,7 +108,8 @@ let moduleBlockDevices = {
_ => (paths != null)
? _.filter((path) => paths.includes(path))
: _,
_ => _.map((path) => $make("sysquery.core.BlockDevice", { path }))
_ => _.map((path) => $make("sysquery.core.BlockDevice", { path })),
_ => Promise.all(_)
]);
}
}

Loading…
Cancel
Save