diff --git a/package.json b/package.json index 002485b..ef0d548 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "prebuild": "rm -rf es5 || true", "build": "tsc -p tsconfig.publish.json", "prepublish": "npm run build", - "pretest": "npm run build -- -p tsconfig.test.json", + "pretest": "npm run build -- -p tsconfig.test.json && ./node_modules/.bin/cpx ./spec/bookshelf-es6-spec.js ./es5/spec", "test": "jasmine" }, "repository": { @@ -60,6 +60,7 @@ "@types/lodash": "4.14.93", "@types/qs": "6.5.1", "bookshelf": "0.10.4", + "cpx": "^1.5.0", "jasmine": "2.9.0", "knex": "0.13.0", "typescript": "2.6.2" diff --git a/spec/bookshelf-es6-spec.js b/spec/bookshelf-es6-spec.js new file mode 100644 index 0000000..305ee62 --- /dev/null +++ b/spec/bookshelf-es6-spec.js @@ -0,0 +1,193 @@ +"use strict" + +const _ = require('lodash') +const Bookshelf = require('bookshelf') +const knex = require('knex') +const Mapper = require('../src') + +describe('Issues', () => { + let bookshelf; + let mapper; + const domain = 'https://domain.com' + + beforeAll(() => { + bookshelf = Bookshelf(knex(({ client: 'sqlite3', useNullAsDefault: true }))) + mapper = new Mapper.Bookshelf(domain) + }) + + afterAll(done => { + bookshelf.knex.destroy(done) + }) + + describe('ES6 virtuals', () => { + beforeAll(() => { + bookshelf.plugin('virtuals'); + mapper = new Mapper.Bookshelf(domain); + }) + + it('should return virtuals', () => { + class UserModel extends bookshelf.Model { + get virtuals() { + return { + full_name: function() { + return `${this.get('first_name')} ${this.get('last_name')}` + } + } + } + } + + const user = new UserModel({ + id: 1, + first_name: 'Al', + last_name: 'Bundy' + }) + + const result = mapper.map(user, 'user') + const expected = { + links: { + self: 'https://domain.com/users' + }, + data: { + type: 'users', + id: '1', + links: { + self: 'https://domain.com/users/1' + }, + attributes: { + first_name: 'Al', + last_name: 'Bundy', + full_name: 'Al Bundy' + } + } + } + + expect(_.isMatch(result, expected)).toBe(true) + }) + + it('shouldn\'t return virtuals if outputVirtuals is set to false', () => { + class UserModel extends bookshelf.Model { + get virtuals() { + return { + full_name: function() { + return `${this.get('first_name')} ${this.get('last_name')}` + } + } + } + get outputVirtuals() { + return false + } + } + + const user = new UserModel({ + id: 1, + first_name: 'Al', + last_name: 'Bundy' + }); + + const result = mapper.map(user, 'user') + const expected = { + links: { + self: 'https://domain.com/users' + }, + data: { + type: 'users', + id: '1', + links: { + self: 'https://domain.com/users/1' + }, + attributes: { + first_name: 'Al', + last_name: 'Bundy' + } + } + } + + expect(_.isMatch(result, expected)).toBe(true) + }) + + it('outputVirtuals as mapper option should override the default outputVirtuals', () => { + class UserModel extends bookshelf.Model { + get virtuals() { + return { + full_name: function() { + return `${this.get('first_name')} ${this.get('last_name')}` + } + } + } + get outputVirtuals() { + return false + } + } + + class UserModel1 extends bookshelf.Model { + get virtuals() { + return { + full_name: function() { + return `${this.get('first_name')} ${this.get('last_name')}` + } + } + } + get outputVirtuals() { + return true + } + } + + const user1 = new UserModel({ + id: 1, + first_name: 'Al', + last_name: 'Bundy' + }); + + const user2 = new UserModel1({ + id: 1, + first_name: 'Al', + last_name: 'Bundy' + }); + + const result1_with = mapper.map(user1, 'user', {outputVirtuals: true}) + const result1_without = mapper.map(user1, 'user', {outputVirtuals: false}) + const result2_with = mapper.map(user2, 'user', {outputVirtuals: true}) + const result2_without = mapper.map(user2, 'user', {outputVirtuals: false}) + + const expected_with = { + links: { + self: 'https://domain.com/users' + }, + data: { + type: 'users', + id: '1', + links: { + self: 'https://domain.com/users/1' + }, + attributes: { + first_name: 'Al', + last_name: 'Bundy' + } + } + } + + const expected_without = { + links: { + self: 'https://domain.com/users' + }, + data: { + type: 'users', + id: '1', + links: { + self: 'https://domain.com/users/1' + }, + attributes: { + first_name: 'Al', + last_name: 'Bundy' + } + } + } + + expect(_.isMatch(result1_with, expected_with)).toBe(true) + expect(_.isMatch(result2_with, expected_with)).toBe(true) + expect(_.isMatch(result1_without, expected_without)).toBe(true) + expect(_.isMatch(result2_without, expected_without)).toBe(true) + }) + + }); +}); diff --git a/src/bookshelf/utils.ts b/src/bookshelf/utils.ts index 15c31a6..c3502d3 100644 --- a/src/bookshelf/utils.ts +++ b/src/bookshelf/utils.ts @@ -118,7 +118,9 @@ function sample(data: Data): Sample { // Override type because we will overwrite relations const sampled: Sample = cloneDeep(omit(data, 'relations')) as Sample; sampled.relations = mapValues(data.relations, sample); - + if (!isUndefined(data.virtuals)) { + sampled.virtuals = cloneDeep(data.virtuals); + } return sampled; } else if (isCollection(data)) { const first: Model = data.head();