From 324f2733e1cca66dcd2184dabf29724c20ab9aa0 Mon Sep 17 00:00:00 2001 From: Pavel Denisjuk Date: Fri, 11 Oct 2019 19:06:39 +0200 Subject: [PATCH 1/3] feat: add support for custom method invocation on a template file. --- serverless.js | 18 +++++++++++++++++- utils.js | 50 +++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 66 insertions(+), 2 deletions(-) diff --git a/serverless.js b/serverless.js index 88efe12..b8156c2 100644 --- a/serverless.js +++ b/serverless.js @@ -8,10 +8,26 @@ const { createGraph, executeGraph, syncState, - getOutputs + getOutputs, + createCustomMethodHandler } = require('./utils') class Template extends Component { + constructor(id, context) { + const defaultFunction = super(id, context) + + return new Proxy(defaultFunction, { + get: (obj, method) => { + if (obj.hasOwnProperty(method)) { + return obj[method] + } + + // Return a catch-all function that will invoke the custom method on requested components + return createCustomMethodHandler(obj, method) + } + }) + } + async default(inputs = {}) { this.context.status('Deploying') diff --git a/utils.js b/utils.js index 52f9139..95861dc 100644 --- a/utils.js +++ b/utils.js @@ -341,6 +341,53 @@ const syncState = async (allComponents, instance) => { await instance.save() } +const createCustomMethodHandler = (instance, method) => { + return async ({ component, template, ...inputs }) => { + let components = Array.isArray(component) ? component : [component] + components = components.filter(Boolean) + + if (!components.length) { + throw Error(`"component" input is required to run custom methods`) + } + + instance.context.debug( + `Attempting to run method "${method}" on template aliases: ${components.join(', ')}` + ) + // Load template components + const templateComponents = await getAllComponents(template) + + // Get only the requested components ("component" input) + const componentsToRun = Object.keys(templateComponents) + .filter((alias) => components.includes(alias)) + .reduce((acc, item) => { + acc.push({ alias: item, path: templateComponents[item].path }) + return acc + }, []) + + // Verify all the components have the requested method implemented + instance.context.debug(`Verifying presence of method "${method}" in requested components...`) + for (let i = 0; i < componentsToRun.length; i++) { + const item = componentsToRun[i] + const cmp = await instance.load(item.path) + if (typeof cmp[method] !== 'function') { + throw Error(`method "${method}" not found in "${item.path}"`) + } + // Store the loaded component so we don't have to load it again + componentsToRun[i].component = cmp + } + + // Run custom method and return output + const outputs = {} + for (let i = 0; i < componentsToRun.length; i++) { + const cmp = componentsToRun[i] + instance.context.debug(`Running method "${method}" on "${cmp.path}"...`) + outputs[cmp.alias] = await cmp.component[method](inputs) + } + + return outputs + } +} + module.exports = { getTemplate, resolveTemplate, @@ -350,5 +397,6 @@ module.exports = { createGraph, executeGraph, syncState, - getOutputs + getOutputs, + createCustomMethodHandler } From fb981484897bc4bc100393616b05c8b4426f3d68 Mon Sep 17 00:00:00 2001 From: Pavel Denisjuk Date: Sun, 13 Oct 2019 19:56:57 +0200 Subject: [PATCH 2/3] chore: improve comment text and prop name. --- serverless.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/serverless.js b/serverless.js index b8156c2..602edbe 100644 --- a/serverless.js +++ b/serverless.js @@ -17,13 +17,13 @@ class Template extends Component { const defaultFunction = super(id, context) return new Proxy(defaultFunction, { - get: (obj, method) => { - if (obj.hasOwnProperty(method)) { - return obj[method] + get: (obj, prop) => { + if (obj.hasOwnProperty(prop)) { + return obj[prop] } - // Return a catch-all function that will invoke the custom method on requested components - return createCustomMethodHandler(obj, method) + // Return a function that will invoke the custom method on requested components + return createCustomMethodHandler(obj, prop) } }) } From 57119e04e5a2f9540f4b055769364c13a5a4ed29 Mon Sep 17 00:00:00 2001 From: Pavel Denisjuk Date: Sun, 13 Oct 2019 20:02:42 +0200 Subject: [PATCH 3/3] fix: pass alias to "load" method to load proper component state. --- utils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils.js b/utils.js index 95861dc..8c37d2c 100644 --- a/utils.js +++ b/utils.js @@ -368,7 +368,7 @@ const createCustomMethodHandler = (instance, method) => { instance.context.debug(`Verifying presence of method "${method}" in requested components...`) for (let i = 0; i < componentsToRun.length; i++) { const item = componentsToRun[i] - const cmp = await instance.load(item.path) + const cmp = await instance.load(item.path, item.alias) if (typeof cmp[method] !== 'function') { throw Error(`method "${method}" not found in "${item.path}"`) }