UNPKG

igo

Version:

Igo is a Node.js Web Framework based on Express

511 lines (434 loc) 15.9 kB
require('../../src/dev/test/init'); const assert = require('assert'); const _ = require('lodash'); const Model = require('../../src/db/Model'); describe('db.Model', () => { const schema = { table: 'books', primary: ['id'], columns: [ 'id', 'code', 'title', {name: 'details_json', type: 'json', attr: 'details'}, {name:'is_available', type: 'boolean'}, 'library_id', 'created_at' ] }; class Book extends Model(schema) {} const schema2 = { table: 'books', primary: ['id'], columns: [ 'id', 'code', 'title', {name: 'details_json', type: 'json', attr: 'details'}, {name:'is_available', type: 'boolean'}, 'library_id', 'created_at' ], scopes: { default: query => query.limit(2) } }; class Book2 extends Model(schema2) {} describe('standard crud operations', () => { // describe('insert', () => { it('should insert a book', async () => { const book = await Book.create(); assert(book && book.id); assert.strictEqual(book.is_available, null); }); it('should insert a book with values', async () => { const book = await Book.create({code: 123}); assert(book && book.id); assert.strictEqual(book.code, '123'); }); it('should insert a book with values and go through beforeCreate', async () => { class BookWithTitle extends Model(schema) { beforeCreate() { this.title = this.title || this.code; } } const book = await BookWithTitle.create({code: 123}); assert(book && book.id); assert.strictEqual(book.code, '123'); assert.strictEqual(book.title, '123'); }); }); // describe('find', () => { it('should find book by id', async () => { const first = await Book.create(); const book = await Book.find(first.id); assert.strictEqual(book.id, first.id); }); it('should not find book if id is null', async () => { await Book.create(); const book = await Book.find(null); assert.strictEqual(book, null); }); }); // describe('list', () => { it('should handle empty arrays in where conditions', async () => { const books = await Book.where({id: []}).list(); assert.strictEqual(0, books.length); }); it('should handle 1k elements', async () => { const nb = 1000; const books = []; for (let n = 0; n < nb; n++) { const book = await Book.create(); books.push(book); } // const books = await Book.create(next) assert.strictEqual(nb, books.length); const books2 = await Book.list(); assert.strictEqual(nb, books2.length); }); it('should handle a simple where condition as string', async () => { const book1 = await Book.create(); const book2 = await Book.create(); const books = await Book.where('`id` > ' + book1.id).list(); assert.strictEqual(1, books.length); assert.strictEqual(books[0].id, book2.id); }); it('should handle a simple where condition with param', async () => { const book1 = await Book.create(); const book2 = await Book.create(); const books = await Book.where('`id` > ?', book1.id).list(); assert.strictEqual(1, books.length); assert.strictEqual(books[0].id, book2.id); }); it('should handle where not condition with id', async () => { const book1 = await Book.create(); const book2 = await Book.create(); const books = await Book.whereNot({id: book1.id}).list(); assert.strictEqual(1, books.length); assert.strictEqual(books[0].id, book2.id); }); it('should handle where not with array', async () => { const book1 = await Book.create(); const book2 = await Book.create(); const books = await Book.whereNot({id: [book1.id, book2.id]}).list(); assert.strictEqual(0, books.length); }); it('should handle where not with empty array', async () => { await Book.create(); await Book.create(); const books = await Book.whereNot({id: []}).list(); assert.strictEqual(2, books.length); }); it('should handle two where / whereNot conditions', async () => { const book1 = await Book.create(); const book2 = await Book.create(); const books = await Book.where('`id` > ?', book1.id).whereNot({ id: book2.id }).list(); assert.strictEqual(0, books.length); }); it('should handle two whereNoy / where conditions', async () => { const book1 = await Book.create(); const book2 = await Book.create(); const books = await Book.whereNot({ id: book2.id }).where('`id` > ?', book1.id).list(); assert.strictEqual(0, books.length); }); it.skip('should allow override default scope limit', async () => { await Book2.create({ code: '123', title: 'title' }); await Book2.create({ code: '12345', title: 'title 2' }); const books = await Book2.list(); assert.strictEqual(books.length, 2); const one = await Book2.limit(1).list(); assert.strictEqual(one.id, 1); }); }); // describe('first', () => { it('should select first book', async () => { const first = await Book.create(); const hibook = await Book.create({title: 'hi'}); await Book.create(); const book = await Book.unscoped().first(); assert.strictEqual(first.id, book.id); assert.strictEqual('hi', hibook.title); }); it('should allow a limit in the default scope and select first book', async () => { const first = await Book2.create(); const hibook = await Book2.create({title: 'hi'}); await Book2.create(); const book = await Book2.first(); assert.strictEqual(first.id, book.id); assert.strictEqual('hi', hibook.title); }); }); // describe('last', () => { it('should select last book', async () => { await Book.create(); await Book.create(); const last = await Book.create(); const book = await Book.unscoped().last(); assert.strictEqual(last.id, book.id); }); }); // describe('delete', () => { it('should delete a book', async () => { const first = await Book.create(); await Book.create(); await Book.create(); await Book.delete(first.id); const book = await Book.find(first.id); assert(!book); }); it('should delete selected books', async () => { await Book.create({ code: '123' }); await Book.create({ code: '123' }); await Book.create(); await Book.where({ code: '123' }).delete(); const books = await Book.list(); assert(books.length, 1); }); }); // describe('update', () => { it('should update books', async () => { await Book.create({ code: '123' }); await Book.create({ code: '123' }); await Book.create(); await Book.where({ code: '123' }).update({ title: 'undeuxtrois'}); const books = await Book.where({ title: 'undeuxtrois'}).list(); assert.strictEqual(books.length, 2); }); it('should update all books', async () => { await Book.create({ code: '123' }); await Book.create({ code: '123' }); await Book.create(); await Book.update({ title: 'undeuxtrois'}); const books = await Book.where({ title: 'undeuxtrois'}).list(); assert.strictEqual(books.length, 3); }); it('should load distinct codes', async () => { await Book.create({ code: '000' }); await Book.create({ code: '111' }); await Book.create({ code: '111' }); const codes = await Book.distinct('code').list(); assert.strictEqual(codes.length, 2); }); it('should load distinct codes and titles', async () => { await Book.create({ code: '000' }); await Book.create({ code: '111', title: '111' }); await Book.create({ code: '111', title: '111' }); await Book.create({ code: '222', title: '111' }); const res = await Book.where({title: '111' }).distinct([ 'code', 'title' ]).list(); assert.strictEqual(res.length, 2); }); }); // describe('select', () => { it('should use custom select', async () => { await Book.create({ code: '123', title: 'title' }); const books = await Book.select('title').list(); assert(books[0].title, 'title'); assert(!books[0].code); }); it('should use custom select', async () => { await Book.create({ code: '123', title: 'title' }); const books = await Book.select('*, EXTRACT(YEAR FROM created_at) AS "year"').list(); const currentYear = new Date().getFullYear(); assert(books[0].title, 'title'); assert(books[0].year, currentYear); }); }); // describe('count', () => { it('should count elements', async () => { const nb = 100; const books = []; for (let n = 0; n < nb; n++) { const book = await Book.create(); books.push(book); } assert.strictEqual(nb, books.length); const count = await Book.count(); assert.strictEqual(nb, count); }); }); }); describe('instance operations', () => { describe('delete', () => { it('should delete a book', async () => { await Book.create(); await Book.create(); const last = await Book.create(); await last.delete(); const book = await Book.find(last.id); assert(!book); }); }); describe('update', () => { it('should update a book', async () => { let book = await Book.create(); book = await book.update({ code: 'hop', hello: 'world' }); assert.strictEqual(book.code, 'hop'); assert.notStrictEqual(book.hello, 'world'); book = await book.reload(); assert.strictEqual(book.code, 'hop'); }); it('should update a book with beforeUpdate', async () => { class BookWithBeforeUpdate extends Model(schema) { beforeUpdate(values) { values.title = values.code; } } let book = await BookWithBeforeUpdate.create(); book = await book.update({ code: '234' }); assert.strictEqual(book.title, '234'); book = await book.reload(); assert.strictEqual(book.title, '234'); }); }); }); describe('scopes', () => { var schema = { table: 'books', primary: ['id'], columns: [ 'id', 'code', 'title', {name: 'details_json', type: 'json', attr: 'details'}, {name:'is_available', type: 'boolean'}, 'library_id', 'created_at' ], scopes: { default: query => query.where({ code: 'abc' }), a: query => query.where({ code: 'a' }), } }; class BookWithScopes extends Model(schema) {} it('should use default scope', async () => { await BookWithScopes.create({code: 'a'}); await BookWithScopes.create({code: 'abc'}); const books = await BookWithScopes.list(); assert.strictEqual(books.length, 1); }); it('should use a scope', async () => { await BookWithScopes.create({code: 'a'}); await BookWithScopes.create({code: 'abc'}); const books = await BookWithScopes.unscoped().scope('a').list(); assert.strictEqual(books.length, 1); }); }); describe('count', () => { it('should count rows', async () => { for (let n = 0; n < 10; n++) { await Book.create({ code: 'first' }); } for (let n = 0; n < 20; n++) { await Book.create({ code: 'second' }); } let count = await Book.where({code: 'first'}).count(); assert.strictEqual(count, 10); count = await Book.count(); assert.strictEqual(count, 30); }); }); describe('group', () => { it('should group by code', async () => { for (let n = 0; n < 10; n++) { await Book.create({ code: 'first' }); } for (let n = 0; n < 20; n++) { await Book.create({ code: 'second' }); } const groups = await Book.select('COUNT(*) AS "count", code').group('code').list(); const firsts = _.find(groups, {code: 'first'}); const seconds = _.find(groups, {code: 'second'}); assert.strictEqual(firsts.count, 10); assert.strictEqual(seconds.count, 20); }); it('should group by year', async () => { for (let n = 0; n < 10; n++) { await Book.create({ code: 'first' }); } for (let n = 0; n < 20; n++) { await Book.create({ code: 'second' }); } const groups = await Book.select('COUNT(*) AS "count", EXTRACT(YEAR FROM created_at) AS "year"').group('year').list(); const currentYear = new Date().getFullYear(); assert.strictEqual(groups[0].count, 30); assert.strictEqual(groups[0].year, currentYear); }); }); describe('json columns', () => { const details = { a: 'hello', b: 'world', c: { d: '!' } }; it('should stringify on insert', async () => { let book = await Book.create({ details }); assert.strictEqual(book.details.a, 'hello'); book = await Book.find(book.id); assert.strictEqual(book.details.a, 'hello'); }); it('should stringify on update', async () => { let book = await Book.create({ details }); book = await book.update({ details: { a: 'world' }}); assert.strictEqual(book.details.a, 'world'); book = await Book.find(book.id); assert.strictEqual(book.details.a, 'world'); }); it('should stringify on global update', async () => { let book = await Book.create({ details }); await Book.update({ details: { a: 'world' }}); book = await Book.find(book.id); assert.strictEqual(book.details.a, 'world'); }); it('should parsejson on reload', async () => { let book = await Book.create({ details }); book = await book.reload(); assert.strictEqual(book.details.a, 'hello'); }); }); describe('bool columns', () => { it('should handle true booleans', async () => { const book = await Book.create({ is_available: 'true' }); assert.strictEqual(book.is_available, true); }); it('should handle false booleans', async () => { const book = await Book.create({ is_available: '' }); assert.strictEqual(book.is_available, false); }); it.skip('should let boolean to null', async () => { const book = await Book.create({ is_available: null }); assert.strictEqual(book.is_available, null); }); }); describe('array columns', () => { var schema = { table: 'books', primary: ['id'], columns: [ 'id', 'code', 'title', {name: 'details_json', type: 'array', attr: 'details'}, {name:'is_available', type: 'boolean'}, 'library_id', 'created_at' ] }; class Book extends Model(schema) {} it('should handle array', async () => { const book = await Book.create({ details: [1, 2] }); assert(Array.isArray(book.details)); assert.strictEqual(book.details.length, 2); }); it('should handle array', async () => { const book = await Book.create({ details: '' }); assert(Array.isArray(book.details)); assert.strictEqual(book.details.length, 0); }); }); });