UNPKG

undeexcepturi

Version:

TypeScript ORM for Node.js based on Data Mapper, Unit of Work and Identity Map patterns. Supports MongoDB, MySQL, PostgreSQL and SQLite databases as well as usage with vanilla JavaScript.

246 lines (214 loc) 10.6 kB
import { v4 } from 'uuid'; import { Collection, Configuration, EntityManager, MikroORM, QueryOrder, Reference, wrap } from '@mikro-orm/core'; import { MariaDbDriver } from '@mikro-orm/mariadb'; import { Author2, Book2, BookTag2, Publisher2, PublisherType } from './entities-sql'; import { initORMMySql } from './bootstrap'; import { MySqlDriver } from '@mikro-orm/mysql'; describe('EntityManagerMariaDb', () => { let orm: MikroORM<MariaDbDriver>; beforeAll(async () => orm = await initORMMySql<MariaDbDriver>('mariadb', {}, true)); beforeEach(async () => orm.schema.clearDatabase()); afterAll(async () => { await orm.schema.dropDatabase(); await orm.close(true); }); test('isConnected()', async () => { expect(await orm.isConnected()).toBe(true); expect(await orm.checkConnection()).toEqual({ ok: true, }); await orm.close(true); expect(await orm.isConnected()).toBe(false); const check = await orm.checkConnection(); expect(check).toMatchObject({ ok: false, error: expect.any(Error), reason: 'Unable to acquire a connection', }); await orm.connect(); expect(await orm.isConnected()).toBe(true); expect(await orm.checkConnection()).toEqual({ ok: true, }); }); test('getConnectionOptions()', async () => { const config = new Configuration({ driver: MySqlDriver, clientUrl: 'mysql://root@127.0.0.1:3308/db_name', host: '127.0.0.10', password: 'secret', user: 'user', logger: jest.fn(), forceUtcTimezone: true, } as any, false); const driver = new MariaDbDriver(config); expect(driver.getConnection().getConnectionOptions()).toMatchObject({ database: 'db_name', host: '127.0.0.10', password: 'secret', port: 3308, user: 'user', timezone: 'Z', supportBigNumbers: true, bigNumberStrings: true, }); }); test('should return mariadb driver', async () => { const driver = orm.em.getDriver(); expect(driver).toBeInstanceOf(MariaDbDriver); await expect(driver.findOne(Book2.name, { double: 123 })).resolves.toBeNull(); const author = await driver.nativeInsert(Author2.name, { name: 'name', email: 'email' }); const tag = await driver.nativeInsert(BookTag2.name, { name: 'tag name' }); expect((await driver.nativeInsert(Book2.name, { uuid: v4(), author: author.insertId, tags: [tag.insertId] })).insertId).not.toBeNull(); await expect(driver.getConnection().execute('select 1 as count')).resolves.toEqual([{ count: 1 }]); await expect(driver.getConnection().execute('select 1 as count', [], 'get')).resolves.toEqual({ count: 1 }); await expect(driver.getConnection().execute('select 1 as count', [], 'run')).resolves.toEqual([{ count: 1 }]); await expect(driver.getConnection().execute('insert into test2 (name) values (?)', ['test'], 'run')).resolves.toEqual({ affectedRows: 1, insertId: 1, rows: [], }); await expect(driver.getConnection().execute('update test2 set name = ? where name = ?', ['test 2', 'test'], 'run')).resolves.toEqual({ affectedRows: 1, insertId: 0, rows: [], }); await expect(driver.getConnection().execute('delete from test2 where name = ?', ['test 2'], 'run')).resolves.toEqual({ affectedRows: 1, insertId: 0, rows: [], }); expect(driver.getPlatform().denormalizePrimaryKey(1)).toBe(1); expect(driver.getPlatform().denormalizePrimaryKey('1')).toBe('1'); await expect(driver.find(BookTag2.name, { books: { $in: [1] } })).resolves.not.toBeNull(); // multi inserts const res = await driver.nativeInsertMany(Publisher2.name, [ { name: 'test 1', type: PublisherType.GLOBAL }, { name: 'test 2', type: PublisherType.LOCAL }, { name: 'test 3', type: PublisherType.GLOBAL }, ]); // mysql returns the first inserted id expect(res).toMatchObject({ insertId: 1, affectedRows: 3, row: {}, rows: [{ id: 1 }, { id: 2 }, { id: 3 }] }); const res2 = await driver.find(Publisher2.name, {}); expect(res2).toMatchObject([ { id: 1, name: 'test 1', type: PublisherType.GLOBAL }, { id: 2, name: 'test 2', type: PublisherType.LOCAL }, { id: 3, name: 'test 3', type: PublisherType.GLOBAL }, ]); }); test('driver appends errored query', async () => { const driver = orm.em.getDriver(); const err1 = /insert into `not_existing` \(`foo`\) values \('bar'\) - \(conn=\d+, no: \d+, SQLState: \w+\) Table 'mikro_orm_test_\w+\.not_existing' doesn't exist/; await expect(driver.nativeInsert('not_existing', { foo: 'bar' })).rejects.toThrow(err1); const err2 = /delete from `not_existing` - \(conn=\d+, no: \d+, SQLState: \w+\) Table 'mikro_orm_test_\w+\.not_existing' doesn't exist/; await expect(driver.nativeDelete('not_existing', {})).rejects.toThrow(err2); }); test('should load entities', async () => { expect(orm).toBeInstanceOf(MikroORM); expect(orm.em).toBeInstanceOf(EntityManager); const god = new Author2('God', 'hello@heaven.god'); const bible = new Book2('Bible', god); await orm.em.persistAndFlush(bible); const author = new Author2('Jon Snow', 'snow@wall.st'); author.born = '1990-03-23'; author.favouriteBook = bible; const publisher = new Publisher2('7K publisher', PublisherType.GLOBAL); // as we order by Book.createdAt when populating collection, we need to make sure values will be sequential const book1 = new Book2('My Life on The Wall, part 1', author); book1.createdAt = new Date(Date.now() + 1); book1.publisher = wrap(publisher).toReference(); const book2 = new Book2('My Life on The Wall, part 2', author); book2.createdAt = new Date(Date.now() + 2); book2.publisher = wrap(publisher).toReference(); const book3 = new Book2('My Life on The Wall, part 3', author); book3.createdAt = new Date(Date.now() + 3); book3.publisher = wrap(publisher).toReference(); orm.em.persist(book1); orm.em.persist(book2); orm.em.persist(book3); await orm.em.flush(); orm.em.clear(); const publisher7k = (await orm.em.getRepository(Publisher2).findOne({ name: '7K publisher' }))!; expect(publisher7k).not.toBeNull(); expect(publisher7k.tests).toBeInstanceOf(Collection); expect(publisher7k.tests.isInitialized()).toBe(false); orm.em.clear(); const authorRepository = orm.em.getRepository(Author2); const booksRepository = orm.em.getRepository(Book2); const books = await booksRepository.findAll({ populate: ['author'] }); expect(wrap(books[0].author).isInitialized()).toBe(true); expect(await authorRepository.findOne({ favouriteBook: bible.uuid })).not.toBe(null); orm.em.clear(); const noBooks = await booksRepository.find({ title: 'not existing' }, { populate: ['author'] }); expect(noBooks.length).toBe(0); orm.em.clear(); const jon = (await authorRepository.findOne({ name: 'Jon Snow' }, { populate: ['books', 'favouriteBook'] }))!; const authors = await authorRepository.findAll({ populate: ['books', 'favouriteBook'] }); expect(await authorRepository.findOne({ email: 'not existing' })).toBeNull(); // full text search test const fullTextBooks = (await booksRepository.find({ title: { $fulltext: 'life wall' } }))!; expect(fullTextBooks.length).toBe(3); // count test const count = await authorRepository.count(); expect(count).toBe(authors.length); // identity map test authors.shift(); // shift the god away, as that entity is detached from IM expect(jon).toBe(authors[0]); expect(jon).toBe(await authorRepository.findOne(jon.id)); // serialization test const o = wrap(jon).toJSON(); expect(o).toMatchObject({ id: jon.id, createdAt: jon.createdAt, updatedAt: jon.updatedAt, books: [ { author: jon.id, publisher: publisher.id, title: 'My Life on The Wall, part 1' }, { author: jon.id, publisher: publisher.id, title: 'My Life on The Wall, part 2' }, { author: jon.id, publisher: publisher.id, title: 'My Life on The Wall, part 3' }, ], favouriteBook: { author: god.id, title: 'Bible' }, // born: '1990-03-23', // mariadb driver currently does not work with forced UTC timezone email: 'snow@wall.st', name: 'Jon Snow', }); expect(wrap(jon).toJSON()).toEqual(o); expect(jon.books.getIdentifiers()).toBeInstanceOf(Array); expect(typeof jon.books.getIdentifiers()[0]).toBe('string'); for (const author of authors) { expect(author.books).toBeInstanceOf(Collection); expect(author.books.isInitialized()).toBe(true); // iterator test for (const book of author.books) { expect(book.title).toMatch(/My Life on The Wall, part \d/); expect(book.author).toBeInstanceOf(Author2); expect(wrap(book.author).isInitialized()).toBe(true); expect(book.publisher).toBeInstanceOf(Reference); expect(book.publisher!.unwrap()).toBeInstanceOf(Publisher2); expect(book.publisher!.isInitialized()).toBe(false); } } const booksByTitleAsc = await booksRepository.find({ author: jon.id }, { orderBy: { title: QueryOrder.ASC } }); expect(booksByTitleAsc[0].title).toBe('My Life on The Wall, part 1'); expect(booksByTitleAsc[1].title).toBe('My Life on The Wall, part 2'); expect(booksByTitleAsc[2].title).toBe('My Life on The Wall, part 3'); const booksByTitleDesc = await booksRepository.find({ author: jon.id }, { orderBy: { title: QueryOrder.DESC } }); expect(booksByTitleDesc[0].title).toBe('My Life on The Wall, part 3'); expect(booksByTitleDesc[1].title).toBe('My Life on The Wall, part 2'); expect(booksByTitleDesc[2].title).toBe('My Life on The Wall, part 1'); const twoBooks = await booksRepository.find({ author: jon.id }, { orderBy: { title: QueryOrder.DESC }, limit: 2 }); expect(twoBooks.length).toBe(2); expect(twoBooks[0].title).toBe('My Life on The Wall, part 3'); expect(twoBooks[1].title).toBe('My Life on The Wall, part 2'); const lastBook = await booksRepository.find({ author: jon.id }, { populate: ['author'], orderBy: { title: QueryOrder.DESC }, limit: 2, offset: 2, }); expect(lastBook.length).toBe(1); expect(lastBook[0].title).toBe('My Life on The Wall, part 1'); expect(lastBook[0].author).toBeInstanceOf(Author2); expect(wrap(lastBook[0].author).isInitialized()).toBe(true); await orm.em.remove(lastBook[0]).flush(); }); });