From a3618f5c3b00f3cf57e66c84ed5cbd5f3605f19c Mon Sep 17 00:00:00 2001 From: joelchu Date: Fri, 4 Oct 2019 23:19:51 +0800 Subject: [PATCH 1/6] finally found the problem its the jsdoc not written correctly --- packages/contract-cli/src/ast/jsdoc.js | 8 +++++++- packages/resolver/package.json | 2 +- .../tests/fixtures/contract/contract.json | 15 ++++++++++++++- .../tests/fixtures/resolvers/query/to-fail.js | 8 ++------ 4 files changed, 24 insertions(+), 9 deletions(-) diff --git a/packages/contract-cli/src/ast/jsdoc.js b/packages/contract-cli/src/ast/jsdoc.js index 068b66ff..1b0e07df 100644 --- a/packages/contract-cli/src/ast/jsdoc.js +++ b/packages/contract-cli/src/ast/jsdoc.js @@ -132,6 +132,12 @@ const processParams = function(params) { if (params && Array.isArray(params)) { return params.map(param => { // always return array from now on + // @TODO if the jsdoc is wrong (the problem was cause by without a type) + // then there is no names field, how do we notify the user about the correct + // error? + if (!param.type || !param.type.names) { + throw new Error(`Please check your documentation is correct or not!`) + } param.type = param.type.names.map(normalizeType) // pass through return param; @@ -146,7 +152,7 @@ const processParams = function(params) { * @return {*} false on nothing */ const getParams = res => ( - !!res.params ? ( foldParams( processParams(res.params) ) || false ) + !!res.params ? ( foldParams( processParams(res.params) ) || false ) : ( res.undocumented ? false : [] ) ) diff --git a/packages/resolver/package.json b/packages/resolver/package.json index fadea093..5bd534ca 100644 --- a/packages/resolver/package.json +++ b/packages/resolver/package.json @@ -35,7 +35,7 @@ }, "devDependencies": { "ava": "^2.4.0", - "jsonql-contract": "^1.7.18", + "jsonql-contract": "^1.7.19", "jsonql-koa": "^1.3.9", "server-io-core": "^1.2.0" }, diff --git a/packages/resolver/tests/fixtures/contract/contract.json b/packages/resolver/tests/fixtures/contract/contract.json index ccb1840a..bd9eef96 100644 --- a/packages/resolver/tests/fixtures/contract/contract.json +++ b/packages/resolver/tests/fixtures/contract/contract.json @@ -61,10 +61,23 @@ "description": "name with prefix" } ] + }, + "toFail": { + "file": "/home/joel/projects/open-source/jsonql/packages/resolver/tests/fixtures/resolvers/query/to-fail.js", + "description": "This resolver will fail and throw an error", + "params": [], + "returns": [ + { + "type": [ + "any" + ], + "description": "a variable that didn't exist" + } + ] } }, "mutation": {}, "auth": {}, - "timestamp": 1566054454129, + "timestamp": 1570202373, "sourceType": "script" } diff --git a/packages/resolver/tests/fixtures/resolvers/query/to-fail.js b/packages/resolver/tests/fixtures/resolvers/query/to-fail.js index ad66613e..2a681edb 100644 --- a/packages/resolver/tests/fixtures/resolvers/query/to-fail.js +++ b/packages/resolver/tests/fixtures/resolvers/query/to-fail.js @@ -1,11 +1,7 @@ /** * This resolver will fail and throw an error - * @return a variable that didn't exist + * @return {*} a variable that didn't exist */ module.exports = function toFail() { - try { - return 1; - } catch(e) { - throw new Error(e) - } + return varNotExisted; } -- Gitee From b68950cc2695e8f763d32609332bd239b976d3ef Mon Sep 17 00:00:00 2001 From: joelchu Date: Fri, 4 Oct 2019 23:35:47 +0800 Subject: [PATCH 2/6] the test finish but the assertion is still pending wtf --- packages/resolver/tests/throw.test.js | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/packages/resolver/tests/throw.test.js b/packages/resolver/tests/throw.test.js index 9d4bf285..d32a0b89 100644 --- a/packages/resolver/tests/throw.test.js +++ b/packages/resolver/tests/throw.test.js @@ -19,10 +19,26 @@ test.before(async t => { test(`When resolver throw error, it should able to throw back a JsonqlResolverAppError`, async t => { - const res = {} - t.false(!!res.params) + const resolverName = 'toFail'; + const payload = createQuery(resolverName, []) + + const fn = async () => { + return await executeResolver( + t.context.opts, + 'query', + resolverName, + payload[resolverName], + t.context.contract + ) + } + + + t.throwsAsync(async () => { + const result = await fn() + + console.log(result) - t.false(Array.isArray(res.params)) + }, JsonqlResolverAppError) }) -- Gitee From 5570634cc48582fcf820dce9708ff858c750a9de Mon Sep 17 00:00:00 2001 From: joelchu Date: Sat, 5 Oct 2019 14:38:48 +0800 Subject: [PATCH 3/6] update several interface to return promise --- packages/resolver/package.json | 2 +- packages/resolver/src/provide-node-clients.js | 42 ++++++++------- packages/resolver/src/resolve-methods.js | 53 +++++++------------ packages/resolver/src/search-resolvers.js | 20 ++++++- packages/resolver/src/utils.js | 18 +++++-- 5 files changed, 78 insertions(+), 57 deletions(-) diff --git a/packages/resolver/package.json b/packages/resolver/package.json index 5bd534ca..1f2520a6 100644 --- a/packages/resolver/package.json +++ b/packages/resolver/package.json @@ -1,6 +1,6 @@ { "name": "jsonql-resolver", - "version": "0.8.7", + "version": "0.9.0", "description": "This is NOT for general use, please do not install it directly. This module is part of the jsonql tools supporting modules.", "main": "index.js", "files": [ diff --git a/packages/resolver/src/provide-node-clients.js b/packages/resolver/src/provide-node-clients.js index 7ffc907d..1275e65a 100644 --- a/packages/resolver/src/provide-node-clients.js +++ b/packages/resolver/src/provide-node-clients.js @@ -15,25 +15,29 @@ let hasClientConfig; * @param {object} config configuration * @return {function} the resolver with injection if any */ -async function provideNodeClients(resolver, config) { - if (hasClientConfig === false) { - debug(`nothing to inject`) - return resolver; // nothing to do - } - // if there is cache clients - if (clients.length) { - debug(`inject client from cache`) - return injectNodeClient(resolver, clients) - } - hasClientConfig = validateClientConfig(config) - if (hasClientConfig === false) { - debug(`check and nothing to inject`, config) - return resolver; // nothing to do - } - debug(`run init clients`) - // run init client once - clients = await clientsGenerator(hasClientConfig) - return injectNodeClient(resolver, clients) +function provideNodeClients(resolver, config) { + return new Promise(resolve => { + if (hasClientConfig === false) { + debug(`nothing to inject`) + return resolve(resolver) // nothing to do + } + // if there is cache clients + if (clients.length) { + debug(`inject client from cache`) + return resolve(injectNodeClient(resolver, clients)) + } + hasClientConfig = validateClientConfig(config) + if (hasClientConfig === false) { + debug(`check and nothing to inject`, config) + return resolve(resolver) // nothing to do + } + debug(`run init clients`) + // run init client once + clientsGenerator(hasClientConfig) + .then(clients => { + resolve(injectNodeClient(resolver, clients)) + }) + }) } module.exports = { provideNodeClients } diff --git a/packages/resolver/src/resolve-methods.js b/packages/resolver/src/resolve-methods.js index 9df112cf..e5856b70 100644 --- a/packages/resolver/src/resolve-methods.js +++ b/packages/resolver/src/resolve-methods.js @@ -11,10 +11,7 @@ const { } = require('jsonql-errors') // @TODO this should move to the jsonql-utils! const { provideUserdata } = require('jsonql-jwt') -const { - MODULE_TYPE, - DEFAULT_RESOLVER_IMPORT_FILE_NAME -} = require('jsonql-constants') +const { MODULE_TYPE } = require('jsonql-constants') const { handleOutput, ctxErrorHandler, @@ -22,26 +19,12 @@ const { extractArgsFromPayload } = require('jsonql-utils') const { getDebug } = require('./utils') -const { searchResolvers } = require('./search-resolvers') +const { searchResolvers, importFromModule } = require('./search-resolvers') const { validateAndCall } = require('./validate-and-call') const { provideNodeClients } = require('./provide-node-clients') const debug = getDebug('resolve-method') -/** - * @TODO we might have to change to the contract folder instead - * New for ES6 module features - * @param {string} resolverDir resolver directory - * @param {string} type of resolver - * @param {string} resolverName name of resolver - * @return {function} the imported resolver - */ -function importFromModule(resolverDir, type, resolverName) { - debug('[importFromModule]', resolverDir, type, resolverName) - const resolvers = require( join(resolverDir, DEFAULT_RESOLVER_IMPORT_FILE_NAME) ) - return resolvers[ [type, resolverName].join('') ] -} - /** * A new method breaking out the get resolver and prepare code * then make the original resolveMethod as a koa render handler @@ -53,7 +36,7 @@ function importFromModule(resolverDir, type, resolverName) { * @param {*} [userdata=false] if there is any * @return {*} result - process result from resolver */ -const executeResolver = async (opts, type, resolverName, payload, contract, userdata = false) => { +const executeResolver = (opts, type, resolverName, payload, contract, userdata = false) => { let fn; const { sourceType } = contract; if (sourceType === MODULE_TYPE) { @@ -64,18 +47,21 @@ const executeResolver = async (opts, type, resolverName, payload, contract, user } const args = extractArgsFromPayload(payload, type) // inject the node client if any - fn = await provideNodeClients(fn, opts) - // here we could apply the userdata to the method - const result = await validateAndCall( - provideUserdata(fn, userdata), // always call this one even auth is false - args, - contract, - type, - resolverName, - opts) - // @TODO if we need to check returns in the future - debug('called and now serve up', result) - return result; + // @0.9.0 change everything to promise and stop using async + return provideNodeClients(fn, opts) + .then(fn => validateAndCall( + provideUserdata(fn, userdata), // always call this one even auth is false + args, + contract, + type, + resolverName, + opts) + ) + .then(result => { + // @TODO if we need to check returns in the future + debug('called and now serve up', result) + return result + }) } /** @@ -88,7 +74,7 @@ const executeResolver = async (opts, type, resolverName, payload, contract, user * @param {object} contract to search via the file name info * @return {mixed} depends on the contract */ -const resolverRenderHandler = async (ctx, type, opts, contract) => { +async function resolverRenderHandler(ctx, type, opts, contract) { const { payload, resolverName, userdata } = ctx.state.jsonql; debug('resolveMethod', resolverName, payload, type) // There must be only one method call @@ -96,6 +82,7 @@ const resolverRenderHandler = async (ctx, type, opts, contract) => { // first try to catch the resolve error try { const result = await executeResolver(opts, type, resolverName, payload, contract, userdata) + return renderHandler(ctx, packResult(result)) } catch (e) { debug('resolveMethod error', e) diff --git a/packages/resolver/src/search-resolvers.js b/packages/resolver/src/search-resolvers.js index 3ea03c02..38521f6a 100644 --- a/packages/resolver/src/search-resolvers.js +++ b/packages/resolver/src/search-resolvers.js @@ -3,12 +3,27 @@ const { JsonqlResolverNotFoundError } = require('jsonql-errors') const { getPathToFn, findFromContract } = require('jsonql-utils') +const { DEFAULT_RESOLVER_IMPORT_FILE_NAME } = require('jsonql-constants') const { getDebug } = require('./utils') const debug = getDebug('search-resolvers') const prod = process.env.NODE_ENV === 'production'; +/** + * @TODO we might have to change to the contract folder instead + * New for ES6 module features + * @param {string} resolverDir resolver directory + * @param {string} type of resolver + * @param {string} resolverName name of resolver + * @return {function} the imported resolver + */ +function importFromModule(resolverDir, type, resolverName) { + debug('[importFromModule]', resolverDir, type, resolverName) + const resolvers = require( join(resolverDir, DEFAULT_RESOLVER_IMPORT_FILE_NAME) ) + return resolvers[ [type, resolverName].join('') ] +} + /** * search for the file starting with * 1. Is the path in the contract (or do we have a contract file) @@ -42,4 +57,7 @@ function searchResolvers(name, type, opts, contract) { } } -module.exports = { searchResolvers } +module.exports = { + searchResolvers, + importFromModule +} diff --git a/packages/resolver/src/utils.js b/packages/resolver/src/utils.js index b92db0c5..ffa36f89 100644 --- a/packages/resolver/src/utils.js +++ b/packages/resolver/src/utils.js @@ -2,8 +2,20 @@ const debug = require('debug') const MODULE_NAME = 'jsonql-resolver' +/** + * return the debug method + * @param {string} name the base name + * @return {function} the debug function + */ +const getDebug = function(name) { + return debug(MODULE_NAME).extend(name) +} + +// The following are moved back from utils + + + + module.exports = { - getDebug: function(name) { - return debug(MODULE_NAME).extend(name) - } + getDebug } -- Gitee From 1e9fca678caa5c1a2cc9e38c8548d626702effd2 Mon Sep 17 00:00:00 2001 From: joelchu Date: Sat, 5 Oct 2019 14:40:04 +0800 Subject: [PATCH 4/6] The original test all passed --- packages/resolver/tests/throw.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/resolver/tests/throw.test.js b/packages/resolver/tests/throw.test.js index d32a0b89..2bc78ac2 100644 --- a/packages/resolver/tests/throw.test.js +++ b/packages/resolver/tests/throw.test.js @@ -18,7 +18,7 @@ test.before(async t => { }) -test(`When resolver throw error, it should able to throw back a JsonqlResolverAppError`, async t => { +test.skip(`When resolver throw error, it should able to throw back a JsonqlResolverAppError`, async t => { const resolverName = 'toFail'; const payload = createQuery(resolverName, []) -- Gitee From 823e8297234a43f39808603fc33b14acb27754d0 Mon Sep 17 00:00:00 2001 From: joelchu Date: Sat, 5 Oct 2019 15:17:54 +0800 Subject: [PATCH 5/6] fixed on the point where we need to swap the default error Type --- packages/resolver/package.json | 2 +- packages/resolver/src/resolve-methods.js | 8 +++- packages/resolver/src/validate-and-call.js | 9 +--- packages/resolver/tests/throw.test.js | 48 +++++++++++++--------- 4 files changed, 38 insertions(+), 29 deletions(-) diff --git a/packages/resolver/package.json b/packages/resolver/package.json index 1f2520a6..d5a3573b 100644 --- a/packages/resolver/package.json +++ b/packages/resolver/package.json @@ -10,7 +10,7 @@ "scripts": { "test": "ava --verbose", "test:clients": "DEBUG=jsonql* ava --verbose ./tests/clients.test.js", - "test:throw": "DEBUG=jsonql* ava --verbose ./tests/throw.test.js", + "test:throw": "DEBUG=jsonql-resolver* ava --verbose ./tests/throw.test.js", "contract": "DEBUG=jsonql-contract* jsonql-contract create ./tests/fixtures/resolvers ./tests/fixtures/contract" }, "keywords": [ diff --git a/packages/resolver/src/resolve-methods.js b/packages/resolver/src/resolve-methods.js index e5856b70..ed37f153 100644 --- a/packages/resolver/src/resolve-methods.js +++ b/packages/resolver/src/resolve-methods.js @@ -6,7 +6,7 @@ const { JsonqlResolverAppError, JsonqlValidationError, JsonqlAuthorisationError, - getErrorNameByInstanceWithDefault, + getErrorNameByInstance, UNKNOWN_ERROR } = require('jsonql-errors') // @TODO this should move to the jsonql-utils! @@ -86,12 +86,16 @@ async function resolverRenderHandler(ctx, type, opts, contract) { return renderHandler(ctx, packResult(result)) } catch (e) { debug('resolveMethod error', e) - let errorName = getErrorNameByInstanceWithDefault([ + let errorName = getErrorNameByInstance([ JsonqlResolverNotFoundError, JsonqlAuthorisationError, JsonqlValidationError, JsonqlResolverAppError ], e) + // if this is an unknown error then it will be JsonqlResolverAppError + if (errorName === UNKNOWN_ERROR) { + errorName = 'JsonqlResolverAppError' + } return ctxErrorHandler(ctx, errorName, e) } diff --git a/packages/resolver/src/validate-and-call.js b/packages/resolver/src/validate-and-call.js index 16c7996c..d1b4729b 100644 --- a/packages/resolver/src/validate-and-call.js +++ b/packages/resolver/src/validate-and-call.js @@ -61,13 +61,8 @@ function validateAndCall(fn, args, contract, type, name, opts) { } return Promise - .resolve(Reflect.apply(fn, null, args)) - .then(applyJwtMethod(type, name, opts, contract)) - /* we will debug this from the other side - .catch(e => { - debug(`error throw inside the promise`, e) - throw e; - }) */ + .resolve(Reflect.apply(fn, null, args)) + .then(applyJwtMethod(type, name, opts, contract)) } module.exports = { validateAndCall } diff --git a/packages/resolver/tests/throw.test.js b/packages/resolver/tests/throw.test.js index 2bc78ac2..b4858994 100644 --- a/packages/resolver/tests/throw.test.js +++ b/packages/resolver/tests/throw.test.js @@ -1,6 +1,13 @@ // testing the throw error problem const test = require('ava') -const { JsonqlResolverAppError } = require('jsonql-errors') +const { + JsonqlResolverNotFoundError, + JsonqlAuthorisationError, + JsonqlValidationError, + JsonqlResolverAppError, + getErrorNameByInstance, + UNKNOWN_ERROR +} = require('jsonql-errors') const { join } = require('path') const { executeResolver } = require('../') @@ -18,27 +25,30 @@ test.before(async t => { }) -test.skip(`When resolver throw error, it should able to throw back a JsonqlResolverAppError`, async t => { +test.cb(`When resolver throw error, it should able to throw back a JsonqlResolverAppError`, t => { + t.plan(1) const resolverName = 'toFail'; const payload = createQuery(resolverName, []) - const fn = async () => { - return await executeResolver( - t.context.opts, - 'query', - resolverName, - payload[resolverName], - t.context.contract - ) - } - - - t.throwsAsync(async () => { - const result = await fn() - - console.log(result) - - }, JsonqlResolverAppError) + executeResolver( + t.context.opts, + 'query', + resolverName, + payload[resolverName], + t.context.contract + ) + .catch(e => { + let errorName = getErrorNameByInstance([ + JsonqlResolverNotFoundError, + JsonqlAuthorisationError, + JsonqlValidationError, + JsonqlResolverAppError + ], e) + + t.is(errorName, UNKNOWN_ERROR) + t.end() + + }) }) -- Gitee From f0fa33b1ab88bbf16276e174a17000edf2cc5408 Mon Sep 17 00:00:00 2001 From: joelchu Date: Sat, 5 Oct 2019 15:18:35 +0800 Subject: [PATCH 6/6] jsonql-resolver to 0.9.0 --- packages/resolver/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/resolver/package.json b/packages/resolver/package.json index d5a3573b..9bfc5c2d 100644 --- a/packages/resolver/package.json +++ b/packages/resolver/package.json @@ -9,6 +9,7 @@ ], "scripts": { "test": "ava --verbose", + "prepare": "npm run test", "test:clients": "DEBUG=jsonql* ava --verbose ./tests/clients.test.js", "test:throw": "DEBUG=jsonql-resolver* ava --verbose ./tests/throw.test.js", "contract": "DEBUG=jsonql-contract* jsonql-contract create ./tests/fixtures/resolvers ./tests/fixtures/contract" -- Gitee