UNPKG

igo

Version:

Igo is a Node.js Web Framework based on Express

294 lines (250 loc) 11.9 kB
require('../../src/dev/test/init'); const assert = require('assert'); const Model = require('../../src/db/Model'); describe('includes', () => { class Country extends Model({ table: 'countries', primary: ['id'], columns: [ 'id', 'name', ], associations: () => ([ ['has_many', 'cities', City, 'id', 'country_id'], ]) }) {} class City extends Model({ table: 'cities', primary: ['id'], columns: [ 'id', 'name', 'country_id', ], associations: () => ([ ['has_many', 'libraries', Library, 'id', 'city_id'], ['belongs_to', 'country', Country, 'country_id', 'id'], ]) }) {} class Library extends Model({ table: 'libraries', primary: ['id'], columns: [ 'id', 'title', 'collection', 'city_id', { name: 'details_json', type: 'json', attr: 'details' }, ], associations: () => ([ ['has_many', 'books', Book, 'id', 'library_id'], ['belongs_to', 'city', City, 'city_id', 'id'], ]), scopes: { default: query => query.includes('city') } }) {} class Book extends Model({ table: 'books', primary: ['id'], columns: [ 'id', 'code', 'title', { name: 'details_json', type: 'json', attr: 'details' }, { name: 'is_available', type: 'boolean' }, 'library_id', 'original_library_id', 'created_at' ], associations: () => ([ ['belongs_to', 'library', Library, 'library_id', 'id'], ['belongs_to', 'original_library', Library, 'original_library_id', 'id'], ]) }) {} describe('join', () => { it('should load a book join with its library collection', async () => { const library = await Library.create({ title: 'the big library', collection: 'A' }); const book = await Book.create({ library_id: library.id }); const foundBook = await Book.join('library').find(book.id); assert.strictEqual(foundBook.id, book.id); assert.strictEqual(foundBook.library.collection, library.collection); }); it('should load a book join with its library collection with custom select', async () => { const library = await Library.create({ title: 'A' }); const book = await Book.create({ library_id: library.id }); const foundBook = await Book .select('`books`.`id`, `libraries`.`title` AS library_title') .join('library') .find(book.id); assert.strictEqual(foundBook.library_title, library.title); }); it('should load a book join with specified columns, and a filter', async () => { const library = await Library.create({ title: 'A' }); const book = await Book.create({ library_id: library.id }); const foundBook = await Book.join('library', ['title']) .where({ 'library.title': library.title }) .find(book.id); assert.strictEqual(foundBook.library.title, library.title); }); // count with join it('should count books with join and where condition', async () => { const libraryA = await Library.create({ title: 'A' }); const libraryB = await Library.create({ title: 'B' }); await Book.create({ library_id: libraryA.id }); await Book.create({ library_id: libraryA.id }); await Book.create({ library_id: libraryB.id }); const count = await Book.join('library').where('`library`.`title` = \'B\'').count(); assert.strictEqual(count, 1); }); // cascade joins it('should load books with libraries and cities', async () => { const city = await City.create({ name: 'Paris' }); const library = await Library.create({ title: 'A', city_id: city.id }); await Book.create({ library_id: library.id }); await Book.create({ library_id: library.id }); const books = await Book.join({library: 'city'}).list(); assert.strictEqual(books.length, 2); assert.strictEqual(books[0].library.city.id, city.id); }); it('should load a book even if no library', async () => { const book = await Book.create({}); const foundBook = await Book.join('library').find(book.id); assert(foundBook); assert.strictEqual(foundBook.library, null); }); it('should load a book with a double join', async () => { const library = await Library.create({ title: 'the big library' }); const originalLibrary = await Library.create({ title: 'the original one' }); const book = await Book.create({ library_id: library.id, original_library_id: originalLibrary.id }); const foundBook = await Book.join(['library', 'original_library']).find(book.id); assert.strictEqual(foundBook.id, book.id); assert.strictEqual(foundBook.library.title, library.title); assert.strictEqual(foundBook.original_library.title, originalLibrary.title); }); it('should load a book with a three-level join', async () => { const country = await Country.create({ name: 'France' }); const city = await City.create({ name: 'Paris', country_id: country.id }); const library = await Library.create({ title: 'the big library', city_id: city.id }); const book = await Book.create({ library_id: library.id }); const foundBook = await Book.join({ library: { city: 'country' } }).find(book.id); assert.strictEqual(foundBook.id, book.id); assert.strictEqual(foundBook.library.city.country.name, country.name); }); it('should load a book and its library with includes city', async () => { const city = await City.create({ name: 'London' }); const library = await Library.create({ title: 'London Library', city_id: city.id }); const book = await Book.create({ library_id: library.id }); const foundBook = await Book.join('library').includes('library.city').find(book.id); assert.strictEqual(foundBook.id, book.id); assert.strictEqual(foundBook.library.city.name, city.name); }); it('should load a book and its library with its books', async () => { const library = await Library.create({ title: 'London Library' }); const book = await Book.create({ library_id: library.id }); const book2 = await Book.create({ library_id: library.id }); const foundBook = await Book.join('library').includes('library.books').find(book.id); assert.strictEqual(foundBook.id, book.id); assert.strictEqual(foundBook.library.books.length, 2); assert.strictEqual(foundBook.library.books[0].id, book.id); assert.strictEqual(foundBook.library.books[1].id, book2.id); }); it('should load a book and the city\'s libraries (nested includes)', async () => { const country = await Country.create({ name: 'France' }); const city = await City.create({ name: 'Paris', country_id: country.id }); const library1 = await Library.create({ title: 'Paris Library 1', city_id: city.id }); const library2 = await Library.create({ title: 'Paris Library 2', city_id: city.id }); await Library.create({ title: 'Other Library', city_id: null }); // Not associated with Paris const book = await Book.create({ library_id: library1.id }); const foundBook = await Book.join({library: 'city'}).includes('library.city.libraries').find(book.id); assert.strictEqual(foundBook.id, book.id); assert.strictEqual(foundBook.library.id, library1.id); assert.strictEqual(foundBook.library.city.id, city.id); assert(Array.isArray(foundBook.library.city.libraries)); assert.strictEqual(foundBook.library.city.libraries.length, 2); assert.strictEqual(foundBook.library.city.libraries[0].id, library1.id); assert.strictEqual(foundBook.library.city.libraries[1].id, library2.id); }); it('should load a book join with its library and details', async () => { const library = await Library.create({ title: 'the big library', collection: 'A', details: { description: 'A big library' } }); const book = await Book.create({ library_id: library.id }); const foundBook = await Book.join('library').find(book.id); assert.strictEqual(foundBook.id, book.id); assert.strictEqual(foundBook.library.collection, library.collection); assert.strictEqual(foundBook.library.details.description, library.details.description); }); it('should apply extraWhere conditions on join', async () => { class BookWithExtraWhere extends Model({ table: 'books', primary: ['id'], columns: [ 'id', 'code', 'title', 'library_id', ], associations: () => ([ ['belongs_to', 'library', Library, 'library_id', 'id', { collection: 'A' }], ]) }) {} const libraryA = await Library.create({ title: 'Library A', collection: 'A' }); const libraryB = await Library.create({ title: 'Library B', collection: 'B' }); const bookA = await BookWithExtraWhere.create({ library_id: libraryA.id }); const bookB = await BookWithExtraWhere.create({ library_id: libraryB.id }); // Book A should have its library joined (collection = 'A' matches extraWhere) const foundBookA = await BookWithExtraWhere.join('library').find(bookA.id); assert.strictEqual(foundBookA.id, bookA.id); assert.strictEqual(foundBookA.library.id, libraryA.id); // Book B should NOT have its library joined (collection = 'B' does not match extraWhere) const foundBookB = await BookWithExtraWhere.join('library').find(bookB.id); assert.strictEqual(foundBookB.id, bookB.id); assert.strictEqual(foundBookB.library, null); }); }); describe('paginatedOptimized join', () => { it('should attach joined data in selectFull phase (cloneDeep regression)', async () => { const city = await City.create({ name: 'Paris' }); const library = await Library.create({ title: 'BNF', city_id: city.id }); const book = await Book.create({ library_id: library.id }); const books = await Book.paginatedOptimized() .join('library') .limit(10) .list(); assert.strictEqual(books.length, 1); assert.strictEqual(books[0].id, book.id); assert.strictEqual(books[0].library.id, library.id); assert.strictEqual(books[0].library.title, 'BNF'); }); it('should attach nested joined data in selectFull phase', async () => { const city = await City.create({ name: 'Lyon' }); const library = await Library.create({ title: 'Municipale', city_id: city.id }); const book = await Book.create({ library_id: library.id }); const books = await Book.paginatedOptimized() .join({ library: 'city' }) .limit(10) .list(); assert.strictEqual(books.length, 1); assert.strictEqual(books[0].library.id, library.id); assert.strictEqual(books[0].library.city.id, city.id); assert.strictEqual(books[0].library.city.name, 'Lyon'); }); }); describe('auto-activation of optimized mode (page + join)', () => { it('should return correct paginated results via optimized path', async () => { const library = await Library.create({ title: 'Central' }); await Book.create({ library_id: library.id, title: 'Book A' }); await Book.create({ library_id: library.id, title: 'Book B' }); await Book.create({ title: 'Book C' }); // no library const result = await Book .where({ library_id: library.id }) .join('library') .page(1, 10) .list(); assert.ok(result.pagination, 'should return pagination object'); assert.strictEqual(result.pagination.count, 2); assert.strictEqual(result.rows.length, 2); assert.strictEqual(result.rows[0].library.id, library.id); assert.strictEqual(result.rows[0].library.title, 'Central'); }); }); });