mikro-orm-find-dataloader
Version:
Additional dataloaders for the MikroORM EntityManager find/findOne/etc methods.
154 lines (131 loc) • 4.16 kB
text/typescript
/* eslint-disable @typescript-eslint/no-non-null-assertion */
import {
MikroORM,
Entity,
PrimaryKey,
Property,
Collection,
OneToMany,
Ref,
ref,
ManyToOne,
EntityRepositoryType,
SimpleLogger,
type SqlEntityManager,
} from "@mikro-orm/sqlite";
import { type IFindDataloaderEntityRepository, getFindDataloaderEntityRepository } from "./findRepository";
import { type LoggerNamespace } from "@mikro-orm/core";
function mockLogger(
orm: MikroORM,
debug: LoggerNamespace[] = ["query", "query-params"],
mock = jest.fn(),
): jest.Mock<any, any, any> {
const logger = orm.config.getLogger();
Object.assign(logger, { writer: mock });
orm.config.set("debug", debug);
logger.setDebugMode(debug);
return mock;
}
const findDataloaderDefault = true;
()
class Author {
()
id!: number;
()
name: string;
(() => Book, (book) => book.author)
books = new Collection<Book>(this);
[EntityRepositoryType]?: IFindDataloaderEntityRepository<Author, typeof findDataloaderDefault>;
constructor({ id, name }: { id?: number; name: string }) {
if (id != null) {
this.id = id;
}
this.name = name;
}
}
()
class Book {
()
id!: number;
()
title: string;
(() => Author, { ref: true })
author: Ref<Author>;
[EntityRepositoryType]?: IFindDataloaderEntityRepository<Book, typeof findDataloaderDefault>;
constructor({ id, title, author }: { id?: number; title: string; author: Author | Ref<Author> }) {
if (id != null) {
this.id = id;
}
this.title = title;
this.author = ref(author);
}
}
async function populateDatabase(em: MikroORM["em"]): Promise<void> {
const authors = [
new Author({ id: 1, name: "a" }),
new Author({ id: 2, name: "b" }),
new Author({ id: 3, name: "c" }),
new Author({ id: 4, name: "d" }),
new Author({ id: 5, name: "e" }),
];
em.persist(authors);
const books = [
new Book({ id: 1, title: "One", author: authors[0]! }),
new Book({ id: 2, title: "Two", author: authors[0]! }),
new Book({ id: 3, title: "Three", author: authors[1]! }),
new Book({ id: 4, title: "Four", author: authors[2]! }),
new Book({ id: 5, title: "Five", author: authors[2]! }),
new Book({ id: 6, title: "Six", author: authors[2]! }),
];
em.persist(books);
await em.flush();
}
describe("find", () => {
let orm: MikroORM;
let em: SqlEntityManager;
beforeAll(async () => {
orm = await MikroORM.init({
entityRepository: getFindDataloaderEntityRepository(findDataloaderDefault),
dbName: ":memory:",
entities: [Author, Book],
loggerFactory: (options) => new SimpleLogger(options),
});
try {
await orm.schema.clearDatabase();
} catch {}
try {
const generator = orm.getSchemaGenerator();
await generator.createSchema({ wrap: true });
} catch {}
await populateDatabase(orm.em.fork());
});
beforeEach(async () => {
em = orm.em.fork();
});
it("should fetch books with the find dataloader", async () => {
const authors = await em.fork().find(Author, {});
const mock = mockLogger(orm);
const authorBooks = await Promise.all(
authors.map(async ({ id }) => await em.getRepository(Book).find({ author: id })),
);
expect(authorBooks).toBeDefined();
expect(authorBooks).toMatchSnapshot();
expect(mock.mock.calls).toEqual([
["[query] select `b0`.* from `book` as `b0` where `b0`.`author_id` in (1, 2, 3, 4, 5)"],
]);
});
it("should return the same books as find", async () => {
const authors = await em.fork().find(Author, {});
const dataloaderBooks = await Promise.all(
authors.map(async ({ id }) => await em.getRepository(Book).find({ author: id })),
);
const findBooks = await Promise.all(authors.map(async ({ id }) => await em.fork().find(Book, { author: id })));
expect(dataloaderBooks.map((res) => res.map(({ id }) => id))).toEqual(
findBooks.map((res) => res.map(({ id }) => id)),
);
});
afterEach(async () => {});
afterAll(async () => {
await orm.close(true);
});
});