From 9a1aef8f88ebf5c900304a1cb49ec8bd0f674478 Mon Sep 17 00:00:00 2001 From: James Lambie Date: Sat, 25 Feb 2017 10:25:53 +0800 Subject: [PATCH] fix: rebuild chained ds endpoint after applying results from chainee Fix #123 --- README.md | 2 +- dadi/lib/controller/index.js | 13 +++++-- dadi/lib/providers/remote.js | 6 ++-- package.json | 6 ++-- test/app/datasources/car-makes.json | 4 +-- test/app/datasources/global.json | 18 ++++++++++ test/unit/controller.js | 55 +++++++++++++++++++++++++++++ 7 files changed, 94 insertions(+), 10 deletions(-) create mode 100644 test/app/datasources/global.json diff --git a/README.md b/README.md index a53e3167..b8b9c25c 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ DADI Web [![npm (scoped)](https://img.shields.io/npm/v/@dadi/web.svg?maxAge=10800&style=flat-square)](https://www.npmjs.com/package/@dadi/web) -[![coverage](https://img.shields.io/badge/coverage-64%25-yellow.svg?style=flat-square)](https://github.com/dadi/web) +[![coverage](https://img.shields.io/badge/coverage-66%25-yellow.svg?style=flat-square)](https://github.com/dadi/web) [![Build Status](https://travis-ci.org/dadi/web.svg?branch=master)](https://travis-ci.org/dadi/web) [![JavaScript Style Guide](https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat-square)](http://standardjs.com/) [![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg?style=flat-square)](https://github.com/semantic-release/semantic-release) diff --git a/dadi/lib/controller/index.js b/dadi/lib/controller/index.js index 81cfa452..ac216709 100755 --- a/dadi/lib/controller/index.js +++ b/dadi/lib/controller/index.js @@ -4,6 +4,7 @@ var _ = require('underscore') var async = require('async') var crypto = require('crypto') +var debug = require('debug')('web:controller') var path = require('path') var url = require('url') @@ -152,6 +153,7 @@ Controller.prototype.buildInitialViewData = function (req) { * */ Controller.prototype.process = function process (req, res, next) { + debug('%s %s', req.method, req.url) help.timer.start(req.method.toLowerCase()) var self = this @@ -283,6 +285,9 @@ Controller.prototype.loadData = function (req, res, data, done) { var primaryDatasources = {} var chainedDatasources = {} + + debug('datasources %o %o', _.map(self.datasources, (ds) => { return ds.name })) + _.each(self.datasources, function (ds, key) { if (ds.chained) { chainedDatasources[key] = ds @@ -291,6 +296,8 @@ Controller.prototype.loadData = function (req, res, data, done) { } }) + debug('loadData %o %o', _.map(primaryDatasources, (ds) => { return ds.name }), _.map(chainedDatasources, (ds) => { return ds.name })) + help.timer.start('load data') async.waterfall([ @@ -386,6 +393,7 @@ Controller.prototype.processChained = function (chainedDatasources, data, req, d } _.each(chainedDatasources, function (chainedDatasource, chainedKey) { + debug('datasource (chained): %s > %s', chainedDatasource.chained.datasource, chainedKey) help.timer.start('datasource: ' + chainedDatasource.name + ' (chained)') if (!data[chainedDatasource.chained.datasource]) { @@ -448,8 +456,9 @@ Controller.prototype.processChained = function (chainedDatasources, data, req, d chainedDatasource.schema.datasource.filter = JSON.parse(filter) } - // needed? - // chainedDatasource.provider.buildEndpoint(chainedDatasource.schema, function() {}) + chainedDatasource.provider.buildEndpoint(chainedDatasource.schema, function () {}) + + debug('datasource (load): %s %o', chainedDatasource.name, chainedDatasource.schema.datasource.filter) chainedDatasource.provider.load(req.url, function (err, result) { if (err) log.error({module: 'controller'}, err) diff --git a/dadi/lib/providers/remote.js b/dadi/lib/providers/remote.js index c8f4b26a..ffc64ef4 100644 --- a/dadi/lib/providers/remote.js +++ b/dadi/lib/providers/remote.js @@ -1,6 +1,7 @@ 'use strict' const _ = require('underscore') +const debug = require('debug')('web:provider:remote') const url = require('url') const http = require('http') const https = require('https') @@ -165,6 +166,7 @@ RemoteProvider.prototype.keepAliveAgent = function keepAliveAgent (protocol) { * @return {void} */ RemoteProvider.prototype.load = function (requestUrl, done) { + debug('load %s', this.endpoint) const self = this this.requestUrl = requestUrl @@ -213,9 +215,9 @@ RemoteProvider.prototype.load = function (requestUrl, done) { /** * processDatasourceParameters - adds querystring parameters to the datasource endpoint using properties defined in the schema * - * @param {json} schema - the datasource schema + * @param {Object} schema - the datasource schema * @param {type} uri - the original datasource endpoint - * @return {string} uri with query string appended + * @returns {string} uri with query string appended */ RemoteProvider.prototype.processDatasourceParameters = function processDatasourceParameters (schema, uri) { let query = '?' diff --git a/package.json b/package.json index c2beb2f7..5fad32e0 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "scripts": { "init": "validate-commit-msg", "start": "node ./main.js", - "test": "standard && env NODE_ENV=test ./node_modules/.bin/istanbul cover -x '**/workspace/**' -x '**/app/**' --report cobertura --report text --report html --report lcov ./node_modules/mocha/bin/_mocha test -- --require babel-register", + "test": "standard && env NODE_ENV=test ./node_modules/.bin/istanbul cover -x '**/workspace/**' -x '**/app/**' --report cobertura --report text --report html --report lcov ./node_modules/mocha/bin/_mocha test", "posttest": "node ./scripts/coverage.js", "semantic-release": "semantic-release pre && npm publish && semantic-release post", "snyk-protect": "snyk protect", @@ -59,14 +59,14 @@ "serve-favicon": "^2.3.0", "serve-static": "^1.10.0", "server-destroy": "1.0.1", + "snyk": "^1.25.0", "stack-trace": "latest", "toobusy-js": "^0.4.2", "uglify-js": "^2.6.2", "underscore": "~1.6.0", "underscore.string": "^3.2.2", "validate-commit-message": "^3.0.1", - "wildcard": "^1.1.2", - "snyk": "^1.25.0" + "wildcard": "^1.1.2" }, "devDependencies": { "babel-register": "^6.18.0", diff --git a/test/app/datasources/car-makes.json b/test/app/datasources/car-makes.json index 46581c8e..275b5dcb 100755 --- a/test/app/datasources/car-makes.json +++ b/test/app/datasources/car-makes.json @@ -39,8 +39,8 @@ "chained": { "datasource": "global", "outputParam": { - "param": "results.0.id", - "field": "makeId" + "param": "results.0.id", + "field": "_id" } }, "requestParams": [ diff --git a/test/app/datasources/global.json b/test/app/datasources/global.json new file mode 100644 index 00000000..26a29ebd --- /dev/null +++ b/test/app/datasources/global.json @@ -0,0 +1,18 @@ +{ + "datasource": { + "key": "global", + "name": "Global datasource", + "source": { + "type": "remote", + "protocol": "http", + "host": "127.0.0.1", + "port": "3000", + "endpoint": "1.0/system/all" + }, + "paginate": true, + "count": 20, + "sort": { "name":1 }, + "search": {}, + "filter": {} + } +} diff --git a/test/unit/controller.js b/test/unit/controller.js index e83b2d51..610a8669 100644 --- a/test/unit/controller.js +++ b/test/unit/controller.js @@ -239,6 +239,61 @@ describe('Controller', function (done) { }) }) + describe('Chained Datasource', function () { + this.timeout(5000) + + it('should apply datasource output params to the chained datasource', function (done) { + TestHelper.enableApiConfig().then(() => { + var pages = TestHelper.setUpPages() + pages[0].datasources = ['global','car-makes'] + + var host = 'http://' + config.get('api.host') + ':' + config.get('api.port') + + var endpointGlobal = '/1.0/system/all?count=20&page=1&filter=%7B%7D&fields=%7B%7D&sort=%7B%22name%22:1%7D' + + var results1 = JSON.stringify({ results: [ { id: '1234', name: 'Test' } ] }) + var results2 = JSON.stringify({ results: [ { name: 'Crime' } ] }) + + TestHelper.setupApiIntercepts() + + var scope1 = nock(host) + .get(endpointGlobal) + .reply(200, results1) + + var scope2 = nock(host) + .get(/cars\/makes/) + .reply(200, results2) + + var providerSpy = sinon.spy(remoteProvider.prototype, 'load') + + TestHelper.startServer(pages).then(() => { + var client = request(connectionString) + + client + .get(pages[0].routes[0].path) + .end(function (err, res) { + if (err) return done(err) + + providerSpy.restore() + + var call = providerSpy.secondCall + var provider = call.thisValue + + var q = require('url').parse(provider.endpoint, true).query + var filter = q.filter + var filterObj = JSON.parse(filter) + should.exist(filterObj._id) + filterObj._id.should.eql('1234') + + done() + }) + }).catch((err) => { + done(err) + }) + }) + }) + }) + describe.skip('Datasource Filter Events', function (done) { it('should run an attached `filterEvent` before datasource loads', function (done) { TestHelper.enableApiConfig().then(() => {