{"id":13683118,"url":"https://github.com/pragmaticivan/mikro-orm-entity-factory","last_synced_at":"2025-04-30T12:33:24.348Z","repository":{"id":41903083,"uuid":"340201525","full_name":"pragmaticivan/mikro-orm-entity-factory","owner":"pragmaticivan","description":"A MikroORM testing utility for bulk inserting entity objects.","archived":true,"fork":false,"pushed_at":"2023-03-28T15:51:26.000Z","size":249,"stargazers_count":5,"open_issues_count":2,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-23T14:07:21.178Z","etag":null,"topics":["mikro-orm","mikroorm"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pragmaticivan.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2021-02-18T23:09:03.000Z","updated_at":"2023-03-28T15:51:43.000Z","dependencies_parsed_at":"2024-01-14T15:24:36.400Z","dependency_job_id":"f1b5defe-509e-4669-9fbf-d8ae5159af9a","html_url":"https://github.com/pragmaticivan/mikro-orm-entity-factory","commit_stats":null,"previous_names":[],"tags_count":11,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pragmaticivan%2Fmikro-orm-entity-factory","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pragmaticivan%2Fmikro-orm-entity-factory/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pragmaticivan%2Fmikro-orm-entity-factory/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pragmaticivan%2Fmikro-orm-entity-factory/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pragmaticivan","download_url":"https://codeload.github.com/pragmaticivan/mikro-orm-entity-factory/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251701833,"owners_count":21629902,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["mikro-orm","mikroorm"],"created_at":"2024-08-02T13:02:01.091Z","updated_at":"2025-04-30T12:33:24.017Z","avatar_url":"https://github.com/pragmaticivan.png","language":"TypeScript","funding_links":[],"categories":["TypeScript"],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003ch1\u003eMikroORM-Entity-Factory\u003c/h1\u003e\n\u003c/p\u003e\n\n[![Actions Status](https://github.com/pragmaticivan/mikro-orm-entity-factory/workflows/nodejs-tests/badge.svg)](https://github.com/{owner}/{repo}/actions)\n\u003ca href=\"https://www.npmjs.com/mikro-orm-entity-factory\" target=\"_blank\"\u003e\n\u003cimg src=\"https://img.shields.io/npm/dw/mikro-orm-entity-factory\" alt=\"NPM Downloads\" /\u003e\n\u003c/a\u003e\n\n# This repository is retired. Please use https://mikro-orm.io/docs/seeding#using-entity-factories instead\n\nA module for saving bulk entities for E2E database testing.\n\nThis module is a rewrite of the [typeorm-entity-factory](https://github.com/adamdubicki/typeorm-entity-factory) using [MikroORM](https://github.com/mikro-orm/mikro-orm).\n\n## Motivation\n\nFor E2E testing it is useful to have sample data within a database for testing queries. Unfortunately, inserting hundreds of entities can be tedious. Furthermore, with relational data, it is time-consuming to ensure that the data is random enough for the testing to be thorough.\n\nThis package allows for the bulk creation of MikroORM entities. Each entity has pseudo-random data which can be overridden.\n\n```typescript\n/** Declare the injection container */\nconst container = await FactoryContainer.init({\n  em, // Your MikroORM database entity manager\n  factories: [\n    // An array of factory classes for bulk creating entities\n    BookFactory,\n    AuthorFactory,\n    GenreFactory\n  ]\n});\n\n/** Retrieve the factories */\nconst authorFactory = container.getFactory(Author);\nconst bookFactory = container.getFactory(Book);\nconst genreFactory = container.getFactory(Genre);\n\n/** Create single entity with random data and relations. */\nconst author = await authorFactory.saveOne();\n/**\n *  Author {\n *    id: 'fc0286d2-5442-4228-bfb5-a98863f002c6',\n *    firstName: 'Lavina',\n *    lastName: 'Maggio',\n *    books: [\n *      Book {\n *        id: '1af79ea2-5baa-480f-9456-f5b04a7d1c0f',\n *        title: 'Chief Paradigm Assistant',\n *        genre: [Genre]\n *      },\n *      Book {\n *        id: '3ea7f6b7-477a-4c92-a5c0-3f96c6de9da6',\n *        title: 'Lead Communications Coordinator',\n *        genre: [Genre]\n *      },\n *      Book {\n *        id: 'ed9637ef-f11b-48b5-bf1a-5ce4960604c2',\n *        title: 'Corporate Integration Architect',\n *        genre: [Genre]\n *      },\n *      Book {\n *        id: '64f04192-7f5e-4b95-ba6b-76598012f61c',\n *        title: 'Product Implementation Agent',\n *        genre: [Genre]\n *      },\n *      Book {\n *        id: '2a739e2e-487d-4104-98c0-70454ab36ea2',\n *        title: 'Internal Configuration Consultant',\n *        genre: [Genre]\n *      }\n *    ]\n *  }\n */\n\n/** Create many entities with random data */\nconst books = await bookFactory.saveMany(5);\n/**\n * [\n *   Book {\n *     id: '1eb24072-57eb-46be-8657-6fcaf41aaac1',\n *     title: 'SMS Fresh Brand'\n *   },\n *   Book {\n *     id: '4b43bb2e-b309-49b9-9f6e-9940aff45ff8',\n *     title: 'Senior Brand Agent'\n *   },\n *   Book {\n *     id: 'd0f737e3-3ace-4b81-8f14-c3d1773addad',\n *     title: 'Customer Response Director'\n *   },\n *   Book {\n *     id: '1bbc1e43-e7f4-48cd-9289-c9d68e3c381d',\n *     title: 'District Accounts Engineer'\n *   },\n *   Book {\n *     id: '9d4acedb-d253-4bb6-8a6b-16e2c6720c60',\n *     title: 'Direct Paradigm Executive'\n *   },\n * ]\n */\n\n/** Pass in optional override values to generate specific data */\nconst programmingGenre = await genreFactory.saveOne({\n  name: \"Programming\"\n});\n/**\n * Genre {\n *  name: 'Programming',\n *  id: 6637\n * }\n */\n\n/** Combine factories for bulk relational data */\nconst programmingBooks = await bookFactory.saveMany(10, {\n  genre: programmingGenre\n});\n/**\n * [\n *   Book {\n *     id: '932f74f8-3dd9-4225-8372-62bce0b47442',\n *     title: 'Chief Configuration Specialist',\n *     genre: Genre { name: 'Programming', id: 6637 }\n *   },\n *   Book {\n *     id: '63452727-4321-4477-8fd6-1a90dce36693',\n *     title: 'Senior Operations Assistant',\n *     genre: Genre { name: 'Programming', id: 6637 }\n *   },\n *   Book {\n *     id: '73acc12e-0366-43d9-a7c3-378f824bf9c4',\n *     title: 'Global Program Engineer',\n *     genre: Genre { name: 'Programming', id: 6637 }\n *   },\n *   Book {\n *     id: '78557247-1e21-4e38-828a-e24405fe8185',\n *     title: 'Forward Tactics Orchestrator',\n *     genre: Genre { name: 'Programming', id: 6637 }\n *   },\n *   Book {\n *     id: 'eaa40ccd-fa4b-4765-b8d7-e67c3b060025',\n *     title: 'Legacy Web Developer',\n *     genre: Genre { name: 'Programming', id: 6637 }\n *   },\n * ]\n */\n```\n\n## Example\n\nThis quick-start assumes you already have a MikroORM database: `https://github.com/mikro-orm/mikro-orm`.\n\nFor the examples below we will be using a simple database schema.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/adamdubicki/typeorm-entity-factory/master/images/sample-entity-relationship-diagram.png\" width=\"600\" alt=\"Sample ERD\" /\u003e\n\u003c/p\u003e\n\nIn this simple example, an author writes many books, and book belongs to a single genre.\nThese map to the following MikroORM entities:\n\n```typescript\n@Entity()\nexport class Author {\n  @PrimaryKey()\n  id: string = v4();\n\n  @Property({\n    length: 255,\n    name: \"first_name\"\n  })\n  firstName: string;\n\n  @Property({\n    length: 255,\n    name: \"last_name\"\n  })\n  lastName: string;\n\n  @ManyToMany({ entity: () =\u003e Book })\n  books: Book[];\n}\n\n@Entity()\nexport class Book {\n  @PrimaryKey()\n  id: string = v4();\n\n  @Property({\n    length: 255,\n    name: \"title\"\n  })\n  title: string;\n\n  @ManyToOne({ entity: () =\u003e Genre })\n  genre: Genre;\n}\n\n@Entity()\nexport class Genre {\n  @PrimaryKey()\n  id: string = v4();\n\n  @Property({\n    length: 255,\n    name: \"name\"\n  })\n  name: string;\n}\n```\n\n### Creating our first factory\n\nAn entity factory generates entities in bulk and stubs them with default data. To start off with we will make the GenreFactory to bulk create Genres. Each factory has an instance of [faker](https://github.com/marak/Faker.js/) for creating random data.\n\n```typescript\n@FactoryFor(Genre)\nexport class GenreFactory extends EntityFactory\u003cGenre\u003e {\n  /**\n   * @inheritdoc\n   * Create a Genre with default parameters\n   * @returns a stubbed Genre\n   */\n  async make(): Promise\u003cGenre\u003e {\n    const genre = new Genre();\n    genre.name = this.faker.random.word();\n    return genre;\n  }\n}\n```\n\nEach entity factory only needs to implement a make() function. The make function returns an instantiated entity class with stub data.\n\nTo use our new factory, we need to pass it into init function of the FactoryContainer class.\n\n```typescript\nconst container = FactoryContainer.init({\n  em, // Your MikroORM database connection's entity manager\n  factories: [\n    // // An array of our entity factories\n    GenreFactory\n  ]\n});\n```\n\nThis will inject the database connection into all factories and allow us to use nested factories as described later. The connection must be to the database which has the entity generated by the factories parameter.\n\nUsing the container instance we can retrieve an instance of the genre factory.\n\n```typescript\nconst genreFactory = container.getFactory(Genre);\n```\n\nThe factory class has two methods of interest makeOne() and makeMany(). These method calls invoke the make method that we defined in our factory.\n\n```typescript\n/**\n * Create a genre with name 'Romance'.\n * The saveOne method takes in a override param object.\n * Any keys within the object which are shared with the entity\n * will be overridden automatically.\n */\n\nconst genre = await genreFactory.saveOne({ name: \"Romance\" });\n\n/**\n * Create five genres with no overrides.\n * The saveMany method is nearly the same as the saveOne method\n * but takes in a `count` as a primary argument which decides\n * how many of that entity it will create. The secondary argument\n * is the same overrides object as on saveOne. The override object will\n * be applied to each of the entities created in the saveMany() invocation.\n */\nconst genres = await genreFactory.saveMany(5);\n```\n\n### Nested Factories\n\nNow that we are familiar with creating factories - lets make a more complicated factory that auto-generates its own relations.\n\n```typescript\n@FactoryFor(Book)\nexport class BookFactory extends EntityFactory\u003cBook\u003e {\n  /**\n   * @inheritdoc\n   * Create a Book with default parameters\n   * @returns a stubbed Book\n   */\n  async make(): Promise\u003cBook\u003e {\n    const book = new Book();\n    book.id = this.faker.random.uuid();\n    book.title = this.faker.name.title();\n    // Each factory has a reference to the container that it was injected into\n    book.genre = await this.container.getFactory(Genre).saveOne();\n    return book;\n  }\n}\n```\n\nThe BookFactory creates its own Genre using the GenreFactory we declared earlier. Factories can be 'nested' in this way for creating data with relations.\n\nJust like the GenreFactory, the BookFactory has to be injected into the container so that all factory references can be resolved at run-time.\n\n```typescript\nconst container = FactoryContainer.init({\n  em,\n  factories: [\n    GenreFactory,\n    BookFactory // \u003c\u003c\u003c Newly Added\n  ]\n});\n```\n\nWith our two factories completed, we are now able to bulk create some more sophisticated data.\n\n```typescript\nconst bookFactory = container.getFactory(Genre);\n\n/** Create 10 random books - each with their own unique Genre */\nconst randomBooks = await bookFactory.saveMany(10);\n\n/** Pass in optional override values to generate specific data */\nconst programmingGenre = await genreFactory.saveOne({\n  name: \"Programming\"\n});\n\n/** Combine factories for bulk relational data */\nconst programmingBooks = await bookFactory.saveMany(10, {\n  genre: programmingGenre\n});\n```\n\nAnd finally the AuthorFactory ...\n\n```typescript\n@FactoryFor(Author)\nexport class AuthorFactory extends EntityFactory\u003cAuthor\u003e {\n  /**\n   * @inheritdoc\n   * Create an Author with default parameters\n   * @returns an stubbed Author\n   */\n  async make(): Promise\u003cAuthor\u003e {\n    const author = new Author();\n    author.id = this.faker.random.uuid();\n    author.firstName = this.faker.name.firstName();\n    author.lastName = this.faker.name.lastName();\n    // Auto generates 5 books on each author declaration\n    author.books = await this.container.getFactory(Book).saveMany(5);\n    return author;\n  }\n}\n```\n\nJust like the BookFactory and GenreFactory, we have to add this to container.\n\n```typescript\nconst container = FactoryContainer.init({\n  em,\n  factories: [GenreFactory, BookFactory, AuthorFactory]\n});\n```\n\nInvoking `saveOne()` on the AuthorFactory class will create five books, each with their own genre.\n\n```typescript\nconst authorFactory = container.getFactory(Author);\nawait authorFactory.saveOne();\n/**\n *  Author {\n *    id: 'fc0286d2-5442-4228-bfb5-a98863f002c6',\n *    firstName: 'Lavina',\n *    lastName: 'Maggio',\n *    books: [\n *      Book {\n *        id: '1af79ea2-5baa-480f-9456-f5b04a7d1c0f',\n *        title: 'Chief Paradigm Assistant',\n *        genre: [Genre]\n *      },\n *      Book {\n *        id: '3ea7f6b7-477a-4c92-a5c0-3f96c6de9da6',\n *        title: 'Lead Communications Coordinator',\n *        genre: [Genre]\n *      },\n *      Book {\n *        id: 'ed9637ef-f11b-48b5-bf1a-5ce4960604c2',\n *        title: 'Corporate Integration Architect',\n *        genre: [Genre]\n *      },\n *      Book {\n *        id: '64f04192-7f5e-4b95-ba6b-76598012f61c',\n *        title: 'Product Implementation Agent',\n *        genre: [Genre]\n *      },\n *      Book {\n *        id: '2a739e2e-487d-4104-98c0-70454ab36ea2',\n *        title: 'Internal Configuration Consultant',\n *        genre: [Genre]\n *      }\n *    ]\n *  }\n */\n```\n\n### Multiple Factories for an entity\n\nSince the container uses the entity name when retrieving the factory, we need to provide a namespace if we want to use multiple factories for the same entity.\nThis can be achieved with the `namespace key` parameter in the FactoryFor decorator.\n\nFor example, if we wanted to have a more specialized version of the AuthorFactory called FamousAuthorFactory.\n\n```typescript\nimport { Author } from \"src/tests/sample/entities/author\";\nimport { EntityFactory } from \"src/entity-factory\";\nimport { FactoryFor } from \"src/factory-for.decorator\";\nimport { Book } from \"src/tests/sample/entities/book\";\n\n@FactoryFor(Author, \"famous\") /** \u003c-- Additional optional param */\nexport class FamousAuthorFactory extends EntityFactory\u003cAuthor\u003e {\n  /**\n   * @inheritdoc\n   * Create an Author with default parameters\n   * @returns an stubbed Author\n   */\n  async make(): Promise\u003cAuthor\u003e {\n    const author = new Author();\n    author.id = this.faker.random.uuid();\n\n    const bookFactory = await this.container.getFactory(Book);\n    const firstDigit: number = parseInt(author.id.charAt(0), 10);\n\n    if (firstDigit % 2 === 0) {\n      author.firstName = \"Kurt\";\n      author.lastName = \"Vonnegut\";\n      const book1 = await bookFactory.saveOne({\n        title: \"Slaughterhouse 5\"\n      });\n      const book2 = await bookFactory.saveOne({\n        title: \"Cats Cradle\"\n      });\n      author.books = [book1, book2];\n    } else {\n      author.firstName = \"Douglas\";\n      author.lastName = \"Adams\";\n      const book1 = await bookFactory.saveOne({\n        title: \"The Hitchhikers Guide to the Galaxy\"\n      });\n      const book2 = await bookFactory.saveOne({\n        title: \"The Restaurant at the End of the Universe\"\n      });\n      author.books = [book1, book2];\n    }\n    return author;\n  }\n}\n```\n\nWhen we want to retrieve the FamousAuthorFactory from the container, we\nprovide the namespace key.\n\n```typescript\n/** This will retrieve the original factory **/\nconst authorFactory = container.getFactory(Author);\n\n/** This will retrieve the famous author factory **/\nconst famousAuthorFactory = container.getFactory(Author, \"famous\");\n```\n\n## Examples\n\nSee the examples directory for integrations.\nCurrently there are example projects for:\n\n- NestJS\n\n## Local development\n\nThis repository uses docker-compose for it's local development. Please refer to the [docker documentation](https://docs.docker.com/install/]) for installing docker onto your machine.\n\nTo use this repository for development:\n\n1. Clone the repository: `git clone https://github.com/pragmaticivan/mikro-orm-entity-factory`\n\n2. Instantiate the development and database container: `docker-compose up -d` The development container is configured with npm and a test suite for experimenting with changes. The docker-compose.yml maps the src files into the container, changes made in your local repository will be reflected in the container.\n\n3. You can then shell into the development container with `docker exec -it mikro-orm-entity-factory /bin/bash`.\n\n4. From within the container you can run the test suite with `npm run test`.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpragmaticivan%2Fmikro-orm-entity-factory","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpragmaticivan%2Fmikro-orm-entity-factory","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpragmaticivan%2Fmikro-orm-entity-factory/lists"}