UNPKG

bookshelf-jsonapi-params

Version:

Automatically applies relations, filters, and more from the JSON API spec to your Bookshelf.js results

1,324 lines (1,113 loc) 68.4 kB
import Chai from 'chai'; const expect = Chai.expect; Chai.use(expect); import _ from 'lodash'; import JsonApiParams from '../../src/index'; import Promise from 'bluebird'; export default function (repository, dbClient) { describe('common tests', () => { repository.Models = {}; repository.Models.MovieModel = repository.Model.extend({ tableName: 'movie', format: function (attrs) { // This recreates the format behavior for those working with knex return _.reduce(attrs, (result, val, key) => { const columnComponentParts = key.split('.').map(_.snakeCase); result[columnComponentParts.join('.')] = val; return result; }, {}); } }); repository.Models.HouseModel = repository.Model.extend({ tableName: 'house', people: function () { return this.belongsToMany(repository.Models.PersonModel, 'person_house', 'house_id', 'person_id'); }, format: function (attrs) { // This recreates the format behavior for those working with knex return _.reduce(attrs, (result, val, key) => { const columnComponentParts = key.split('.').map(_.snakeCase); result[columnComponentParts.join('.')] = val; return result; }, {}); } }); repository.Models.ToyModel = repository.Model.extend({ tableName: 'toy', pet: function () { return this.belongsTo(repository.Models.PetModel, 'pet_id'); }, owner: function () { return this.belongsTo(repository.Models.PersonModel, 'pet_owner_id').through(repository.Models.PetModel, 'pet_id'); }, format: function (attrs) { // This recreates the format behavior for those working with knex return _.reduce(attrs, (result, val, key) => { const columnComponentParts = key.split('.').map(_.snakeCase); result[columnComponentParts.join('.')] = val; return result; }, {}); } }); repository.Models.PetModel = repository.Model.extend({ tableName: 'pet', petOwner: function () { return this.belongsTo(repository.Models.PersonModel, 'pet_owner_id'); }, toy: function () { return this.hasOne(repository.Models.ToyModel); }, format: function (attrs) { // This recreates the format behavior for those working with knex return _.reduce(attrs, (result, val, key) => { const columnComponentParts = key.split('.').map(_.snakeCase); result[columnComponentParts.join('.')] = val; return result; }, {}); } }); repository.Models.PersonModel = repository.Model.extend({ tableName: 'person', // Converts snake_case attributes to camelCase parse: function (attrs) { return _.reduce(attrs, (result, val, key) => { result[_.camelCase(key)] = val; return result; }, {}); }, // Converts camelCase attributes to snake_case. format: function (attrs) { return _.reduce(attrs, (result, val, key) => { const aggregateFunctions = ['count', 'sum', 'avg', 'max', 'min']; if (_.some(aggregateFunctions, (f) => _.startsWith(key, f + '('))) { result[key] = val; } else { result[_.snakeCase(key)] = val; } return result; }, {}); }, pet: function () { return this.hasOne(repository.Models.PetModel, 'pet_owner_id'); }, houses: function () { return this.belongsToMany(repository.Models.HouseModel, 'person_house', 'person_id', 'house_id'); } }); before((done) => { // Register the plugin with Bookshelf repository.plugin(JsonApiParams); // Build the schema and add some data Promise.join( repository.knex.schema.dropTableIfExists('person_house'), repository.knex.schema.dropTableIfExists('movie'), repository.knex.schema.dropTableIfExists('house'), repository.knex.schema.dropTableIfExists('person'), repository.knex.schema.dropTableIfExists('pet'), repository.knex.schema.dropTableIfExists('toy') ).then(() => { return Promise.join( repository.knex.schema.createTable('house', (table) => { table.increments('id').primary(); table.string('color'); table.string('year_built'); table.integer('bedrooms'); table.integer('bathrooms'); }), repository.knex.schema.createTable('movie', (table) => { table.increments('id').primary(); table.string('name'); table.string('type'); table.jsonb('extra'); }), repository.knex.schema.createTable('person', (table) => { table.increments('id').primary(); table.string('first_name'); table.integer('age'); table.string('gender'); table.string('type'); }), repository.knex.schema.createTable('person_house', (table) => { table.increments('id').primary(); table.integer('person_id'); table.integer('house_id'); }), repository.knex.schema.createTable('pet', (table) => { table.increments('id').primary(); table.string('name'); table.integer('pet_owner_id'); table.jsonb('style'); }), repository.knex.schema.createTable('toy', (table) => { table.increments('id').primary(); table.string('type'); table.string('color'); table.integer('pet_id'); }) ); }).then(() => { return Promise.join( repository.Models.HouseModel.forge().save({ id: 1, color: 'yellow', year_built: '1957', bedrooms: 3, bathrooms: 4 }), repository.Models.PersonModel.forge().save({ id: 1, firstName: 'Barney', age: 12, gender: 'm', type: 't-rex' }), repository.Models.PersonModel.forge().save({ id: 2, firstName: 'Baby Bop', age: 25, gender: 'f', type: 'triceratops' }), repository.Models.PersonModel.forge().save({ id: 3, firstName: 'Cookie Monster', age: 70, gender: 'm', type: 'monster' }), repository.Models.PersonModel.forge().save({ id: 4, firstName: 'Boo', age: 28, gender: 'f', type: 'nothing, here' }), repository.Models.PersonModel.forge().save({ id: 5, firstName: 'Elmo', age: 3, gender: 'm', type: null }), repository.Models.PersonModel.forge().save({ id: 6, firstName: 'Barney\'s Actor', age: 12, gender: 'm', type: 'zebra' }), repository.knex('person_house').insert({ house_id: 1, person_id: 1 }), repository.knex('person_house').insert({ house_id: 1, person_id: 3 }), repository.Models.PetModel.forge().save({ id: 1, name: 'Big Bird', pet_owner_id: 1, style: { species: 'bird', age: 42, birthday: new Date('March 20, 1969 03:24:00'), looks: { color: 'yellow', height: 'tall', tail: 'small' } } }), repository.Models.PetModel.forge().save({ id: 2, name: 'Godzilla', pet_owner_id: 2, style: { species: 'reptile', age: 62394, birthday: new Date('January 1, 1979 01:00:00'), looks: { color: 'black', height: 'monsterous', tail: 'enourmous' } } }), repository.Models.PetModel.forge().save({ id: 3, name: 'Patches', pet_owner_id: 3, style: { species: 'dog', age: 4, birthday: new Date('July 1, 2016 17:00:41'), looks: { color: 'brown', height: 'short', tail: null } } }), repository.Models.PetModel.forge().save({ id: 4, name: 'Grover', pet_owner_id: 6, style: { species: 'dog', age: 12, birthday: new Date('July 24, 2016 06:42:48'), looks: { color: 'brown', height: 'short', tail: 'long' } } }), repository.Models.PetModel.forge().save({ id: 5, name: 'Benny "The Terror" Terrier', pet_owner_id: 2, style: { species: 'dog', age: 8, birthday: new Date('July 8, 2015 13:53:21'), looks: { color: 'brown/white', height: 'short', tail: 'short' } } }), repository.Models.ToyModel.forge().save({ id: 1, type: 'skate', color: 'red', pet_id: 1 }), repository.Models.ToyModel.forge().save({ id: 2, type: 'car', color: 'black', pet_id: 2 }), repository.Models.MovieModel.forge().save({ id: 1, name: 'Scary Movie', type: 'null', extra: { time: null, rating: 'R' } }), repository.Models.MovieModel.forge().save({ id: 2, name: 'Spider', type: null, extra: { time: 2, rating: 'R' } }), repository.Models.MovieModel.forge().save({ id: 3, name: 'Go', type: 'Comedy', extra: { time: 'null', rating: 'R' } }) ); }).then(() => done()); }); describe('passing null values and strings', () => { before((done) => { repository.plugin(JsonApiParams, { nullString: '_null_' }); done(); }); it('should return value null while passing _null_', (done) => { repository.Models.MovieModel .forge() .fetchJsonApi({ filter: { 'type': '_null_' } }) .then((result) => { expect(result.models).to.have.length(1); expect(result.models[0].get('name')).to.equal('Spider'); done(); }); }); it('should return value null while passing value', (done) => { repository.Models.MovieModel .forge() .fetchJsonApi({ filter: { 'type': null } }) .then((result) => { expect(result.models).to.have.length(1); expect(result.models[0].get('name')).to.equal('Spider'); done(); }); }); it('should return string null while passing null', (done) => { repository.Models.MovieModel .forge() .fetchJsonApi({ filter: { 'type': 'null' } }) .then((result) => { expect(result.models).to.have.length(1); expect(result.models[0].get('name')).to.equal('Scary Movie'); done(); }); }); it('should not return value null while passing not _null_', (done) => { repository.Models.MovieModel .forge() .fetchJsonApi({ filter: { not: { type: '_null_' } }, sort: ['name'] }) .then((result) => { expect(result.models).to.have.length(2); expect(result.models[0].get('name')).to.equal('Go'); expect(result.models[1].get('name')).to.equal('Scary Movie'); done(); }); }); after((done) => { repository.plugin(JsonApiParams, {}); done(); }); }); describe('passing no parameters', () => { it('should return a single record', (done) => { repository.Models.PersonModel .where({ id: 1 }) .fetchJsonApi(null, false) .then((person) => { expect(person.get('firstName')).to.equal('Barney'); expect(person.get('gender')).to.equal('m'); done(); }); }); it('should return multiple records', (done) => { repository.Models.PersonModel .forge() .fetchJsonApi() .then((result) => { expect(result.models).to.have.length(6); done(); }); }); }); describe('passing a `fields` parameter', () => { it('should only return the specified field for the record', (done) => { repository.Models.PersonModel .where({ id: 2 }) .fetchJsonApi({ fields: { person: ['firstName'] } }, false) .then((person) => { expect(person.get('firstName')).to.equal('Baby Bop'); expect(person.get('gender')).to.be.undefined; done(); }); }); it('should only return the specified field for the record with a type specified', (done) => { repository.Models.PersonModel .where({ id: 2 }) .fetchJsonApi({ fields: { peoples: ['firstName'] } }, false, 'peoples') .then((person) => { expect(person.get('firstName')).to.equal('Baby Bop'); expect(person.get('gender')).to.be.undefined; done(); }); }); it('should only return the specified field for the included relationship', (done) => { repository.Models.PersonModel .where({ id: 1 }) .fetchJsonApi({ include: [{ pet(qb) { qb.select('name'); } }] }, false) .then((person) => { expect(person.get('firstName')).to.equal('Barney'); expect(person.related('pet').get('name')).to.equal('Big Bird'); expect(person.related('pet').get('style')).to.be.undefined; done(); }); }); it('should return all fields when adding where clause to included query', (done) => { repository.Models.PersonModel .where({ id: 1 }) .fetchJsonApi({ include: [{ pet(qb) { qb.where('name', 'Big Bird'); } }] }, false) .then((person) => { expect(person.get('firstName')).to.equal('Barney'); expect(person.related('pet').get('name')).to.equal('Big Bird'); expect(person.related('pet').get('style')).to.not.be.undefined; done(); }); }); it('should only return the specified field for the included relationship combined with fields parameter', (done) => { repository.Models.PersonModel .where({ id: 1 }) .fetchJsonApi({ include: [{ pet(qb) { qb.select('name'); } }], fields: { pet: ['style'] } }, false) .then((person) => { expect(person.get('firstName')).to.equal('Barney'); expect(person.related('pet').get('name')).to.equal('Big Bird'); expect(person.related('pet').get('style')).to.not.be.undefined; done(); }); }); it('should only return the specified field for the included relationship', (done) => { repository.Models.PersonModel .where({ id: 1 }) .fetchJsonApi({ include: ['pet'], fields: { pet: ['name'] } }, false) .then((person) => { expect(person.get('firstName')).to.equal('Barney'); expect(person.related('pet').get('name')).to.equal('Big Bird'); expect(person.related('pet').get('style')).to.be.undefined; done(); }); }); it('should only return the specified field for the included relationship and base model', (done) => { repository.Models.PersonModel .where({ id: 1 }) .fetchJsonApi({ include: ['pet.toy'], fields: { person: ['firstName'], pet: ['name'], 'pet.toy': ['type'] } }, false) .then((person) => { expect(person.get('firstName')).to.equal('Barney'); expect(person.get('gender')).to.be.undefined; expect(person.related('pet').get('name')).to.equal('Big Bird'); expect(person.related('pet').get('style')).to.be.undefined; expect(person.related('pet').related('toy').get('type')).to.equal('skate'); expect(person.related('pet').related('toy').get('color')).to.be.undefined; done(); }); }); it('should only return the specified field for the included relationship and base model using belongsToMany', (done) => { repository.Models.HouseModel .where({ id: 1 }) .fetchJsonApi({ include: ['people'], fields: { house: ['id'], people: ['firstName'] } }, false) .then((house) => { expect(house.id).to.not.be.undefined; expect(house.get('color')).to.be.undefined; const people = house.related('people'); people.forEach((person) => { expect(person.get('firstName')).to.not.be.undefined; expect(person.get('gender')).to.be.undefined; }); done(); }); }); it('should only return the specified field for the included relationship and base model using belongsTo.through', (done) => { repository.Models.ToyModel .where({ id: 1 }) .fetchJsonApi({ include: ['owner'], fields: { toy: ['id'], owner: ['firstName'] } }, false) .then((toy) => { expect(toy.get('id')).to.equal(1); expect(toy.get('color')).to.be.undefined; expect(toy.related('owner').get('firstName')).to.equal('Barney'); expect(toy.related('owner').get('gender')).to.be.undefined; done(); }); }); }); describe('passing a `filters` parameter with a single filter', () => { it('should return a single record with the matching id', (done) => { repository.Models.PersonModel .forge() .fetchJsonApi({ filter: { id: 1 } }) .then((result) => { expect(result.models).to.have.length(1); done(); }); }); it('should return a single record with the matching type as null', (done) => { repository.Models.PersonModel .forge() .fetchJsonApi({ filter: { type: null } }) .then((result) => { expect(result.models).to.have.length(1); expect(result.models[0].get('firstName')).to.equal('Elmo'); done(); }); }); }); describe('passing a `sort` parameter', () => { it('should return records sorted by type ascending (single word param name)', (done) => { repository.Models.PersonModel .forge() .fetchJsonApi({ sort: ['type'] }) .then((result) => { expect(result.models).to.have.length(6); let nullIndex = 0; let monsterIndex = 1; // postgres returns nulls last if (dbClient === 'pg') { nullIndex = 5; monsterIndex = 0; } expect(result.models[nullIndex].get('type')).to.equal(null); expect(result.models[monsterIndex].get('type')).to.equal('monster'); done(); }); }); it('should return records sorted by type descending (single word param name)', (done) => { repository.Models.PersonModel .forge() .fetchJsonApi({ sort: ['-type'] }) .then((result) => { expect(result.models).to.have.length(6); // postgres returns nulls first let nullIndex = 5; let triIndex = 0; if (dbClient === 'pg') { nullIndex = 0; triIndex = 1; } expect(result.models[triIndex].get('type')).to.equal('zebra'); expect(result.models[nullIndex].get('type')).to.equal(null); done(); }); }); it('should return records sorted by name ascending (multi-word param name)', (done) => { repository.Models.PersonModel .forge() .fetchJsonApi({ sort: ['firstName'] }) .then((result) => { expect(result.models).to.have.length(6); expect(result.models[0].get('firstName')).to.equal('Baby Bop'); done(); }); }); it('should return records sorted by name descending (multi-word param name)', (done) => { repository.Models.PersonModel .forge() .fetchJsonApi({ sort: ['-firstName'] }) .then((result) => { expect(result.models).to.have.length(6); expect(result.models[0].get('firstName')).to.equal('Elmo'); done(); }); }); it('should sort on deeply nested resources', (done) => { repository.Models.PersonModel .forge() .fetchJsonApi({ include: ['pet.toy'], sort: ['-pet.toy.type'], filter: { not: { 'pet.toy.type': null } } }) .then((result) => { expect(result.models).to.have.length(2); expect(result.models[0].related('pet').related('toy').get('type')).to.equal('skate'); expect(result.models[1].related('pet').related('toy').get('type')).to.equal('car'); done(); }); }); }); describe('passing a `filters` parameter with multiple filters', () => { it('should return a single record that matches both filters when passing in a comma separated string', (done) => { repository.Models.PersonModel .forge() .fetchJsonApi({ filter: { type: 't-rex,triceratops' } }) .then((result) => { expect(result.models).to.have.length(2); done(); }); }); it('should return a single record that matches both filters when passing in an array', (done) => { repository.Models.PersonModel .forge() .fetchJsonApi({ filter: { type: ['t-rex', 'triceratops'] } }) .then((result) => { expect(result.models).to.have.length(2); done(); }); }); it('should return a single record that matches both filters with a null', (done) => { repository.Models.PersonModel .forge() .fetchJsonApi({ filter: { type: 'null,t-rex' } }) .then((result) => { expect(result.models).to.have.length(2); done(); }); }); }); describe('passing a `filter[like]` parameter with a single filter', () => { it('should return all records that partially matches filter[like]', (done) => { repository.Models.PersonModel .forge() .fetchJsonApi({ filter: { like: { first_name: 'Ba' } } }) .then((result) => { expect(result.models).to.have.length(3); result.models = _.sortBy(result.models, ['id']); expect(result.models[0].get('firstName')).to.equal('Barney'); expect(result.models[1].get('firstName')).to.equal('Baby Bop'); expect(result.models[2].get('firstName')).to.equal('Barney\'s Actor'); done(); }); }); }); describe('passing a `filter[like]` parameter with multiple filters', () => { it('should return all records that partially matches both filter[like]', (done) => { repository.Models.PersonModel .forge() .fetchJsonApi({ filter: { like: { first_name: 'op,coo' } } }) .then((result) => { expect(result.models).to.have.length(2); result.models = _.sortBy(result.models, ['id']); expect(result.models[0].get('firstName')).to.equal('Baby Bop'); expect(result.models[1].get('firstName')).to.equal('Cookie Monster'); done(); }); }); }); describe('passing a `filter[like]` parameter with an equality filter of the same column', () => { it('should return all records that partially matches both filter[like] and equality filters', (done) => { repository.Models.PersonModel .forge() .fetchJsonApi({ filter: { like: { first_name: 'op' }, first_name: 'Cookie Monster' } }) .then((result) => { expect(result.models).to.have.length(2); result.models = _.sortBy(result.models, ['id']); expect(result.models[0].get('firstName')).to.equal('Baby Bop'); expect(result.models[1].get('firstName')).to.equal('Cookie Monster'); done(); }); }); }); describe('passing a `filter[not]` parameter with a single filter', () => { it('should return all records that do not match filter[not]', (done) => { repository.Models.PersonModel .forge() .fetchJsonApi({ filter: { not: { first_name: 'Barney' } } }) .then((result) => { expect(result.models).to.have.length(5); result.models = _.sortBy(result.models, ['id']); expect(result.models[0].get('firstName')).to.equal('Baby Bop'); expect(result.models[1].get('firstName')).to.equal('Cookie Monster'); expect(result.models[2].get('firstName')).to.equal('Boo'); expect(result.models[3].get('firstName')).to.equal('Elmo'); expect(result.models[4].get('firstName')).to.equal('Barney\'s Actor'); done(); }); }); it('should return all records that do not match filter[not] with null', (done) => { repository.Models.PersonModel .forge() .fetchJsonApi({ filter: { not: { type: null } } }) .then((result) => { expect(result.models).to.have.length(5); result.models = _.sortBy(result.models, ['id']); expect(result.models[0].get('type')).to.equal('t-rex'); expect(result.models[1].get('type')).to.equal('triceratops'); expect(result.models[2].get('type')).to.equal('monster'); expect(result.models[3].get('type')).to.equal('nothing, here'); expect(result.models[4].get('type')).to.equal('zebra'); done(); }); }); it('should return all records that do not match filter[not] with null as a string', (done) => { repository.Models.PersonModel .forge() .fetchJsonApi({ filter: { not: { type: 'null' } } }) .then((result) => { expect(result.models).to.have.length(5); result.models = _.sortBy(result.models, ['id']); expect(result.models[0].get('type')).to.equal('t-rex'); expect(result.models[1].get('type')).to.equal('triceratops'); expect(result.models[2].get('type')).to.equal('monster'); expect(result.models[3].get('type')).to.equal('nothing, here'); expect(result.models[4].get('type')).to.equal('zebra'); done(); }); }); }); describe('passing a `filter[not]` parameter with multiple filters', () => { it('should return all records that do not match filter[not] as comma separated string', (done) => { repository.Models.PersonModel .forge() .fetchJsonApi({ filter: { not: { first_name: 'Barney,Baby Bop,Boo,Elmo,Barney\'s Actor' } } }) .then((result) => { expect(result.models).to.have.length(1); expect(result.models[0].get('firstName')).to.equal('Cookie Monster'); done(); }); }); it('should return all records that do not match filter[not] as array of strings', (done) => { repository.Models.PersonModel .forge() .fetchJsonApi({ filter: { not: { first_name: ['Barney', 'Baby Bop', 'Boo', 'Elmo', 'Barney\'s Actor'] } } }) .then((result) => { expect(result.models).to.have.length(1); expect(result.models[0].get('firstName')).to.equal('Cookie Monster'); done(); }); }); it('should return all records that do not match filter[not] including null', (done) => { repository.Models.PersonModel .forge() .fetchJsonApi({ filter: { not: { type: 'null,t-rex,zebra' } } }) .then((result) => { expect(result.models).to.have.length(3); result.models = _.sortBy(result.models, ['id']); expect(result.models[0].get('type')).to.equal('triceratops'); expect(result.models[1].get('type')).to.equal('monster'); expect(result.models[2].get('type')).to.equal('nothing, here'); done(); }); }); }); describe('passing a `filter[lt]` parameter', () => { it('should return all records that are less than filter[lt]', (done) => { repository.Models.PersonModel .forge() .fetchJsonApi({ filter: { lt: { age: 25 } } }) .then((result) => { expect(result.models).to.have.length(3); result.models = _.sortBy(result.models, ['id']); expect(result.models[0].get('firstName')).to.equal('Barney'); expect(result.models[1].get('firstName')).to.equal('Elmo'); expect(result.models[2].get('firstName')).to.equal('Barney\'s Actor'); done(); }); }); }); describe('passing a `filter[lte]` parameter', () => { it('should return all records that are less than or equal to filter[lte]', (done) => { repository.Models.PersonModel .forge() .fetchJsonApi({ filter: { lte: { age: 25 } } }) .then((result) => { expect(result.models).to.have.length(4); result.models = _.sortBy(result.models, ['id']); expect(result.models[0].get('firstName')).to.equal('Barney'); expect(result.models[1].get('firstName')).to.equal('Baby Bop'); expect(result.models[2].get('firstName')).to.equal('Elmo'); expect(result.models[3].get('firstName')).to.equal('Barney\'s Actor'); done(); }); }); }); describe('passing a `filter[gt]` parameter', () => { it('should return all records that are greater than filter[gt]', (done) => { repository.Models.PersonModel .forge() .fetchJsonApi({ filter: { gt: { age: 25 } } }) .then((result) => { expect(result.models).to.have.length(2); result.models = _.sortBy(result.models, ['id']); expect(result.models[0].get('firstName')).to.equal('Cookie Monster'); expect(result.models[1].get('firstName')).to.equal('Boo'); done(); }); }); }); describe('passing a `filter[gte]` parameter', () => { it('should return all records that are greater than or equal to filter[gte]', (done) => { repository.Models.PersonModel .forge() .fetchJsonApi({ filter: { gte: { age: 25 } } }) .then((result) => { expect(result.models).to.have.length(3); result.models = _.sortBy(result.models, ['id']); expect(result.models[0].get('firstName')).to.equal('Baby Bop'); expect(result.models[1].get('firstName')).to.equal('Cookie Monster'); expect(result.models[2].get('firstName')).to.equal('Boo'); done(); }); }); }); describe('passing a `filter[gte]` and `filter[like]` parameter', () => { it('should return all records that are greater than or equal to filter[gte] and a partial match to filter[like]', (done) => { repository.Models.PersonModel .forge() .fetchJsonApi({ filter: { gte: { age: 25 }, like: { first_name: 'a' } } }) .then((result) => { expect(result.models).to.have.length(1); expect(result.models[0].get('firstName')).to.equal('Baby Bop'); done(); }); }); }); describe('passing a `filter` parameter for relationships', () => { it('should return all records that have a pet with name', (done) => { repository.Models.PersonModel .forge() .fetchJsonApi({ filter: { 'pet.name': 'Big Bird' } }) .then((result) => { expect(result.models).to.have.length(1); expect(result.models[0].get('firstName')).to.equal('Barney'); done(); }); }); it('should return the person named Cookie Monster', (done) => { repository.Models.PersonModel .forge() .fetchJsonApi({ filter: { firstName: 'Cookie Monster', gender: 'm' } }) .then((result) => { expect(result.models).to.have.length(1); expect(result.models[0].get('firstName')).to.equal('Cookie Monster'); done(); }); }); }); describe('passing in "or" filtering', () => { it('should return results for "or" filters combination', (done) => { repository.Models.PersonModel .forge() .fetchJsonApi({ filter: { or: [ { type: 'monster' }, { type: 't-rex' } ] }, sort: ['id'] }) .then((result) => { expect(result.models).to.have.length(2); expect(result.models[0].get('firstName')).to.equal('Barney'); expect(result.models[1].get('firstName')).to.equal('Cookie Monster'); done(); }); }); it('should return results for "or" filters for nested objects', (done) => { repository.Models.PersonModel .forge() .fetchJsonApi({ include: ['pet.toy'], filter: { or: [ { like: { 'pet.toy.type': 'skat' } }, { type: 'monster' } ] }, sort: ['id'] }) .then((result) => { expect(result.models[0].related('pet').related('toy').get('type')).to.equal('skate'); expect(result.models[1].get('type')).to.equal('monster'); done(); }); }); it('should return results for nested "or" filters for nested objects', (done) => { repository.Models.PersonModel .forge() .fetchJsonApi({ include: ['pet.toy'], filter: { or: [ { or: [ { like: { 'pet.toy.type': 'skat' } }, { type: 'monster' } ] } ] }, sort: ['id'] }) .then((result) => {