TypeScript ORM for Node.js based on Data Mapper, Unit of Work and Identity Map patterns. Supports MongoDB, MySQL, MariaDB, PostgreSQL and SQLite databases.

Overview

MikroORM

TypeScript ORM for Node.js based on Data Mapper, Unit of Work and Identity Map patterns. Supports MongoDB, MySQL, MariaDB, PostgreSQL and SQLite databases.

Heavily inspired by Doctrine and Nextras Orm.

NPM version NPM dev version Chat on slack Downloads Coverage Status Maintainability Build Status

🤔 Unit of What?

You might be asking: What the hell is Unit of Work and why should I care about it?

Unit of Work maintains a list of objects (entities) affected by a business transaction and coordinates the writing out of changes. (Martin Fowler)

Identity Map ensures that each object (entity) gets loaded only once by keeping every loaded object in a map. Looks up objects using the map when referring to them. (Martin Fowler)

So what benefits does it bring to us?

Implicit Transactions

First and most important implication of having Unit of Work is that it allows handling transactions automatically.

When you call em.flush(), all computed changes are queried inside a database transaction (if supported by given driver). This means that you can control the boundaries of transactions simply by calling em.persistLater() and once all your changes are ready, calling flush() will run them inside a transaction.

You can also control the transaction boundaries manually via em.transactional(cb).

const user = await em.findOneOrFail(User, 1);
user.email = '[email protected]';
const car = new Car();
user.cars.add(car);

// thanks to bi-directional cascading we only need to persist user entity
// flushing will create a transaction, insert new car and update user with new email
// as user entity is managed, calling flush() is enough
await em.flush();

ChangeSet based persistence

MikroORM allows you to implement your domain/business logic directly in the entities. To maintain always valid entities, you can use constructors to mark required properties. Let's define the User entity used in previous example:

@Entity()
export class User {

  @PrimaryKey()
  id!: number;

  @Property()
  name!: string;

  @OneToOne()
  address?: Address;

  @ManyToMany()
  cars = new Collection<Car>(this);

  constructor(name: string) {
    this.name = name;
  }

}

Now to create new instance of the User entity, we are forced to provide the name:

const user = new User('John Doe'); // name is required to create new user instance
user.address = new Address('10 Downing Street'); // address is optional

Once your entities are loaded, make a number of synchronous actions on your entities, then call em.flush(). This will trigger computing of change sets. Only entities (and properties) that were changed will generate database queries, if there are no changes, no transaction will be started.

const user = await em.findOneOrFail(User, 1, ['cars', 'address']);
user.title = 'Mr.';
user.address.street = '10 Downing Street'; // address is 1:1 relation of Address entity
user.cars.getItems().forEach(car => car.forSale = true); // cars is 1:m collection of Car entities
const car = new Car('VW');
user.cars.add(car);

// now we can flush all changes done to managed entities
await em.flush();

em.flush() will then execute these queries from the example above:

begin;
update user set title = 'Mr.' where id = 1;
update user_address set street = '10 Downing Street' where id = 123;
update car set for_sale = true where id = 1;
update car set for_sale = true where id = 2;
update car set for_sale = true where id = 3;
insert into car (brand, owner) values ('VW', 1);
commit;

Only One Instance of Entity

Thanks to Identity Map, you will always have only one instance of given entity in one context. This allows for some optimizations (skipping loading of already loaded entities), as well as comparison by identity (ent1 === ent2).

📖 Documentation

MikroORM v4 documentation, included in this repo in the root directory, is built with Jekyll and publicly hosted on GitHub Pages at https://mikro-orm.io.

There is also auto-generated CHANGELOG.md file based on commit messages (via semantic-release).

You can browse MikroORM v3 docs at https://mikro-orm.io/docs/3.6/installation.

To upgrade to v4, please see the upgrading guide.

✨ Core Features

📦 Example Integrations

You can find example integrations for some popular frameworks in the mikro-orm-examples repository:

TypeScript Examples

JavaScript Examples

Articles

  • Introducing MikroORM, TypeScript data-mapper ORM with Identity Map
  • Handling transactions and concurrency in MikroORM
  • MikroORM 3: Knex.js, CLI, Schema Updates, Entity Generator and more…

🚀 Quick Start

First install the module via yarn or npm and do not forget to install the database driver as well:

Since v4, you should install the driver package, but not the db connector itself, e.g. install @mikro-orm/sqlite, but not sqlite3 as that is already included in the driver package.

yarn add @mikro-orm/core @mikro-orm/mongodb     # for mongo
yarn add @mikro-orm/core @mikro-orm/mysql       # for mysql/mariadb
yarn add @mikro-orm/core @mikro-orm/mariadb     # for mysql/mariadb
yarn add @mikro-orm/core @mikro-orm/postgresql  # for postgresql
yarn add @mikro-orm/core @mikro-orm/sqlite      # for sqlite

or

npm i -s @mikro-orm/core @mikro-orm/mongodb     # for mongo
npm i -s @mikro-orm/core @mikro-orm/mysql       # for mysql/mariadb
npm i -s @mikro-orm/core @mikro-orm/mariadb     # for mysql/mariadb
npm i -s @mikro-orm/core @mikro-orm/postgresql  # for postgresql
npm i -s @mikro-orm/core @mikro-orm/sqlite      # for sqlite

Next you will need to enable support for decorators as well as esModuleInterop in tsconfig.json via:

"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"esModuleInterop": true,

Then call MikroORM.init as part of bootstrapping your app:

const orm = await MikroORM.init({
  entities: ['./dist/entities'], // path to your JS entities (dist), relative to `baseDir`
  dbName: 'my-db-name',
  type: 'mongo',
  clientUrl: '...', // defaults to 'mongodb://localhost:27017' for mongodb driver
});
console.log(orm.em); // access EntityManager via `em` property

There are more ways to configure your entities, take a look at installation page.

Read more about all the possible configuration options in Advanced Configuration section.

Then you will need to fork entity manager for each request so their identity maps will not collide. To do so, use the RequestContext helper:

const app = express();

app.use((req, res, next) => {
  RequestContext.create(orm.em, next);
});

You should register this middleware as the last one just before request handlers and before any of your custom middleware that is using the ORM. There might be issues when you register it before request processing middleware like queryParser or bodyParser, so definitely register the context after them.

More info about RequestContext is described here.

Now you can start defining your entities (in one of the entities folders). This is how simple entity can look like in mongo driver:

./entities/MongoBook.ts

@Entity()
export class MongoBook {

  @PrimaryKey()
  _id: ObjectID;

  @SerializedPrimaryKey()
  id: string;

  @Property()
  title: string;

  @ManyToOne()
  author: Author;

  @ManyToMany()
  tags = new Collection<BookTag>(this);

  constructor(title: string, author: Author) {
    this.title = title;
    this.author = author;
  }

}

For SQL drivers, you can use id: number PK:

./entities/SqlBook.ts

@Entity()
export class SqlBook {

  @PrimaryKey()
  id: number;

}

Or if you want to use UUID primary keys:

./entities/UuidBook.ts

import { v4 } from 'uuid';

@Entity()
export class UuidBook {

  @PrimaryKey()
  uuid = v4();

}

More information can be found in defining entities section in docs.

When you have your entities defined, you can start using ORM either via EntityManager or via EntityRepositorys.

To save entity state to database, you need to persist it. Persist takes care or deciding whether to use insert or update and computes appropriate change-set. Entity references that are not persisted yet (does not have identifier) will be cascade persisted automatically.

// use constructors in your entities for required parameters
const author = new Author('Jon Snow', '[email protected]');
author.born = new Date();

const publisher = new Publisher('7K publisher');

const book1 = new Book('My Life on The Wall, part 1', author);
book1.publisher = publisher;
const book2 = new Book('My Life on The Wall, part 2', author);
book2.publisher = publisher;
const book3 = new Book('My Life on The Wall, part 3', author);
book3.publisher = publisher;

// just persist books, author and publisher will be automatically cascade persisted
await orm.em.persistAndFlush([book1, book2, book3]);

To fetch entities from database you can use find() and findOne() of EntityManager:

const authors = orm.em.find(Author, {});

for (const author of authors) {
  console.log(author); // instance of Author entity
  console.log(author.name); // Jon Snow

  for (const book of author.books) { // iterating books collection
    console.log(book); // instance of Book entity
    console.log(book.title); // My Life on The Wall, part 1/2/3
  }
}

More convenient way of fetching entities from database is by using EntityRepository, that carries the entity name so you do not have to pass it to every find and findOne calls:

const booksRepository = orm.em.getRepository(Book);

// with sorting, limit and offset parameters, populating author references
const books = await booksRepository.find({ author: '...' }, ['author'], { title: QueryOrder.DESC }, 2, 1);

// or with options object
const books = await booksRepository.find({ author: '...' }, { 
  populate: ['author'],
  limit: 1,
  offset: 2,
  orderBy: { title: QueryOrder.DESC },
});

console.log(books); // Book[]

Take a look at docs about working with EntityManager or using EntityRepository instead.

🤝 Contributing

Contributions, issues and feature requests are welcome. Please read CONTRIBUTING.md for details on the process for submitting pull requests to us.

Authors

👤 Martin Adámek

See also the list of contributors who participated in this project.

Show Your Support

Please ⭐️ this repository if this project helped you!

📝 License

Copyright © 2018 Martin Adámek.

This project is licensed under the MIT License - see the LICENSE file for details.

Comments
  • MikroORM v5

    MikroORM v5

    Progress

    • [x] Seeder package (#929)
    • [x] Improved schema diffing (should address most of the currently known issues) (#1641)
      • [x] Better mapping - adds mapped types to abstract most of the column types (e.g. { type: t.decimal })
      • [x] FK diffing
      • [x] Proper index diffing (before we compared just names)
      • [x] Custom index expressions
      • [x] Comment diffing
      • [x] Column length diffing (e.g. numeric(10,2) or varchar(100))
      • [x] Changing PK types
      • [x] Schena/namespace diffing (posgtres only)
    • [x] Support FKs in sqlite (including not null FKs)
    • [x] Use AsyncLocalStorage in the RequestContext helper
    • [x] ESM support via gen-esm-wrapper (#1010)
    • [x] Support index hints with the QueryBuilder (#1663)
    • [x] Strict typings for em.create() (#1456)
    • [x] Strict toObject(), toJSON() and toPOJO() return types
    • [x] Add more methods to naming strategy (index/unique/pk names, property names for entity generator)
    • [x] Allow column names with spaces
    • [x] Support partial loading with joined strategy
    • [x] Add support for more lock modes (skip locked/nowait) (#1786)
    • [x] Allow setting transaction isolation level
    • [x] Snapshotting of current db state in migrations (#1815)
    • [x] Allow using short lived tokens in config (#1818)
    • [x] Support entities inside embeddables (#1932)
    • [x] Rework deep assigning and enable it by default (#1811)
    • [x] Strict typings for populate array (dot notation and string literal types)
    • [x] Strict typings for fields array (dot notation and string literal types)
    • [x] Automatic down migrations
    • [x] Strictly typed FindOptions.orderBy, allowing arrays of objects too (#2010)
    • [x] Support for multiple schemas (including UoW) (#2074)
    • [x] Validate usage of forked EM (disallow using identity map on the global instance) (#2381)
    • [x] Improve aliasing of tables (e0/1/2/3...) and make it configurable (#2419)
    • [x] Upgrade mongodb driver to v4 (#2425)
    • [x] Polymorphic embeddables (#1165, #2426)
    • [x] Allow awaiting the QueryBuilder instance (#2446)
    • [x] Allow providing custom Logger instance (#2443)
    • [x] Support populating lazy scalar properties via em.populate() (#1479)
    • [x] Support flushing via Promise.all() (#2412)
    • [x] Support auto flush like in hibernate (#2359, #2491)

    Breaking changes

    • [x] Require TS 4.1+ to allow using template literals (maybe even 4.2 it if makes sense)
    • [x] Require Node v14+
    • [x] Some methods are now strictly typed (em.create(), em.assign(), qb.insert(), qb.update(), e.toObject(), e.toJSON(), ...)
    • [x] FindOptions.orderBy/fields/ are now strictly typed
    • [x] Remove additional find/findOne/... parameters (populate/orderBy/limit/offset) in favour of FindOptions
    • [x] Use options parameter in em.fork()
    • [x] Remove @Repository decorator (use @Entity({ customRepository: () => CustomRepository }) instead)
    • [x] Enable populateAfterFlush by default
    • [x] migrations.pattern is removed in favour of migrations.glob (#2556)

    https://mikro-orm.io/docs/next/upgrading-v4-to-v5/ https://github.com/mikro-orm/nestjs-realworld-example-app/pull/36

    opened by B4nan 120
  • MikroORM v4

    MikroORM v4

    Progress

    • [x] Single table inheritance (#33, #503)
    • [x] Allow adding items to not initialized collections (#489)
    • [x] Use absolute path to entity file in static MetadataStorage keys (fix for 'Multiple property decorators' validation issues) (#488)
    • [x] Embedded entities (allow in-lining child entity into parent one with prefixed keys) (#514)
    • [x] Add support for Node.js 14 (#522)
    • [x] Support subqueries in QB (#525)
    • [x] Nested conditions in qb.update() queries via subqueries (#319, #537)
    • [x] Nested conditions in em.remove() via subqueries (#492, #538)
    • [x] Use custom errors for specific cases (unique constraint violation, db not accessible, ...) (#539, #611)
    • [x] Paginator helper or something similar (doctrine docs) (#544)
    • [x] Add groupBy and distinct to FindOptions and FindOneOptions
    • [x] Support computed properties via @Formula() decorator (#553)
    • [x] Allow the use of TS path mapping (#554)
    • [x] Add custom types for blob, array, json (#476)
    • [x] Pass entity instance as parameter in onCreate and onUpdate (#564)
    • [x] Cache metadata only with ts-morph provider (#569)
    • [x] Allow using different primary key types than ObjectId in mongo driver (#349, #568)
    • [x] Lazy scalar properties (allow having props that won't be loaded by default, but can be populated) (#427, #585)
    • [x] Support for alternative loading strategies (#440, #556, #600)
    • [x] Support external hooks when using EntitySchema (hooks outside of entity) (#516, #614)
    • [x] Execute hooks via EventManager (adds EventArgs to hook params) (#622, #623)
    • [x] Add support for flush events (allows to modify change sets) (#637, #642)
    • [x] Use .d.ts files in TsMorphMetadataProvider (#616)
    • [x] Ensure correct order of tables in schema generator (#617)
    • [x] Ability to specify entities glob instead of entitiesDir glob (#605, #618)
    • [x] Refactor internal dependencies to support Yarn PnP (#645)
    • [x] Association scopes/filters (hibernate docs) (#385, #663)
    • [x] Add support for entity and property comments (#668)
    • [x] Add driver.nativeInsertMany() method (#688)
    • [x] Static checking of population (#214, #691)
    • [x] Add em.begin/commit/rollback methods (#717)
    • [x] Bulk deletes (#757)
    • [x] Refactor merging to allow querying by custom type (#800)

    Breaking changes

    • [x] Require node 10+
    • [x] Require TS 3.7 or newer
    • [x] Split into multiple packages (core, driver packages, TS support, SQL support, CLI) (#475)
    • [x] Remove autoFlush option (#439)
    • [x] Drop default value for platform type (currently defaults to mongodb)
    • [x] Remove IdEntity/UuidEntity/MongoEntity interfaces
    • [x] Use jsonb as default for object columns in postgres
    • [x] Do not define internal methods like init directly on the entity prototype (#506)
    • [x] Support multiple M:N with same properties without manually specifying pivotTable
    • [x] Type-safe custom Type class (#540)
    • [x] Change behaviour of property default, add defaultRaw (#546)
    • [x] Remove flush parameter, allow fluid em.persist().flush() calls instead (#648)
    • [x] Require entity instance in em.remove(), remove em.removeEntity() (#648)

    Summary (WIP): https://github.com/mikro-orm/mikro-orm/blob/master/docs/docs/upgrading-v3-to-v4.md Example migration: https://github.com/mikro-orm/nestjs-realworld-example-app/commit/89ec53ca678f9ef0c1538ff9fc14448a016daa72

    Planned release

    The aim is to have late beta or RC version at the end of ~may~ june, and release the full version during ~june~ july. You can track the progress also in PR #515. Some features might be postponed for some 4.x release.

    opened by B4nan 53
  • Static checking of population

    Static checking of population

    Is your feature request related to a problem? Please describe.

    For the moment em::find(...) and em::find(..., { populate: ['something'] }) return exactly the same entity types and compiler don't know was references populated or not.

    We have the solution to explicitly define references https://github.com/mikro-orm/mikro-orm/blob/dev/docs/entity-references.md#better-type-safety-with-referencet-wrapper but this solution is partial as you don't know were the references populated or not. You can await all populated references that will not perform database querying, but if you just remember population you may release the code that will produce a lot of unexpected queries to production. Also it causes significant boilerplate.

    It would be nice if ``em::find(..., { populate: ['something'] })``` will return mapped type with all populated fields de-referenced.

    Describe the solution you'd like

    Here is a very rough idea how to define types:

    class Reference<T> {
        unwrap<T>(): T {
            // implementation isn't important
            return undefined as any;
        }
    }
    
    type UnwrappedReference<T> = T extends Reference<infer U> ? U : T;
    
    type PopulatedEntity<E, R extends keyof E> = {
        [k in keyof E]: k extends R ? UnwrappedReference<E[k]> : E[k] 
    }
    
    class Credentials {
    }
    
    class Organization {
    }
    
    class User {
        name!: string;
        credentials!: Reference<Credentials>;
        organization!: Reference<Organization>;
    }
    
    function populate<E, R extends keyof E>(entities: E[], ...fields: R[]): PopulatedEntity<E, R>[] {
        // implementation isn't important
        return undefined as any;
    }
    
    const users = [new User()];
    
    const populated1 = populate(users, 'credentials');
    const credentials1: Credentials = populated1[0].credentials;
    const organization: Reference<Organization> = populated1[0].organization;
    
    const populated2 = populate(users, 'credentials', 'organization');
    const credentials2: Credentials = populated2[0].credentials;
    const organization2: Organization = populated2[0].organization;
    

    Additional context

    Types i provided allows to populate only one level of references. There is no generic ts solution to populate at any level, but if we limit deepness of population to some meaningful value like 3-5 correct typing is possible.

    enhancement breaking change 
    opened by vimmerru 47
  • High memory profile and very slow

    High memory profile and very slow

    Describe the bug

    I've integrated Mikro-ORM in a benchmark suite and noticed a memory leak and very slow execution times.

    The benchmark basically creates 10k objects, persist() each, and then flushes. After that it reads all 10k from the database. What happens with Mikro ORM is that the first 10k insert takes 7 seconds, the second 10k insert 11 seconds, the third 21 seconds. Memory climbing as well rapidly 166mb, then 278mb, then 417mb.

    Raw output:

    round 1
    0.13634226180139436 ops/s Mikro-ORM insert 7,334.482989996672 ms, 166.2109375 MB memory
    7.202537523174704 ops/s Mikro-ORM fetch 138.83995699882507 ms, 175.12109375 MB memory
    round 2
    0.09214466685562421 ops/s Mikro-ORM insert 10,852.500032007694 ms, 278.3046875 MB memory
    9.313704069546839 ops/s Mikro-ORM fetch 107.36866798996925 ms, 286.4140625 MB memory
    round 3
    0.04624159269974236 ops/s Mikro-ORM insert 21,625.552703022957 ms, 417.4453125 MB memory
    10.529599470788153 ops/s Mikro-ORM fetch 94.97037401795387 ms, 419.08984375 MB memory
    round 4
    0.03031239307193595 ops/s Mikro-ORM insert 32,989.80709397793 ms, 481.515625 MB memory
    15.424512427769912 ops/s Mikro-ORM fetch 64.83187100291252 ms, 482.24609375 MB memory
    round 5
    0.023591314642157822 ops/s Mikro-ORM insert 42,388.48131901026 ms, 548.6171875 MB memory
    9.086378374941388 ops/s Mikro-ORM fetch 110.05484899878502 ms, 550.55859375 MB memory
    

    To Reproduce Steps to reproduce the behavior:

    Execute the following Typescript code:

    import 'reflect-metadata';
    import {Entity as MikroEntity, MikroORM, PrimaryKey, Property, ReflectMetadataProvider} from 'mikro-orm';
    import {performance} from 'perf_hooks';
    
    export async function bench(times: number, title: string, exec: () => void | Promise<void>) {
        const start = performance.now();
        for (let i = 0; i < times; i++) {
            await exec();
        }
        const took = performance.now() - start;
    
        process.stdout.write([
            (1000 / took) * times, 'ops/s',
            title,
            took.toLocaleString(undefined, {maximumFractionDigits: 17}), 'ms,',
            process.memoryUsage().rss / 1024 / 1024, 'MB memory'
        ].join(' ') + '\n');
    }
    
    
    @MikroEntity({collection: 'mikro'})
    export class MikroModel {
        @PrimaryKey()
        _id!: any;
    
        @Property() id2!: number;
    
        @Property() ready?: boolean;
    
        @Property() tags: string[] = [];
    
        @Property() priority: number = 0;
    
        @Property()
        name: string;
    
        constructor(name: string) {
            this.name = name;
        }
    }
    
    
    (async () => {
        const count = 10_000;
    
        const orm = await MikroORM.init({
            entities: [MikroModel],
            dbName: 'bench-insert',
            type: 'mongo',
            metadataProvider: ReflectMetadataProvider,
            clientUrl: 'mongodb://localhost:27017'
        });
    
        for (let j = 1; j <= 15; j++) {
            console.log('round', j);
            await orm.em.remove(MikroModel, {}, true);
            await bench(1, 'Mikro-ORM insert', async () => {
                for (let i = 1; i <= count; i++) {
                    const user = new MikroModel('Peter ' + i);
                    user.id2 = i;
                    user.ready = true;
                    user.priority = 5;
                    user.tags = ['a', 'b', 'c'];
                    await orm.em.persist(user);
                }
    
                await orm.em.flush();
            });
    
            await bench(1, 'Mikro-ORM fetch', async () => {
                const items = await orm.em.find(MikroModel, {});
            });
        }
        await orm.close();
    })();
    

    Additional Information

    The same benchmark with TypeORM has following output.

    round 1
    0.44799316696261965 ops/s TypeORM insert 2,232.1769030094147 ms, 112.78515625 MB memory
    14.745251303605988 ops/s TypeORM fetch 67.81844401359558 ms, 116.30859375 MB memory
    round 2
    0.5518305396852811 ops/s TypeORM insert 1,812.1505210101604 ms, 157.296875 MB memory
    10.61794395223521 ops/s TypeORM fetch 94.18019199371338 ms, 125.12890625 MB memory
    round 3
    0.5414625441330295 ops/s TypeORM insert 1,846.8498159945011 ms, 139.37890625 MB memory
    7.658094507705051 ops/s TypeORM fetch 130.58078598976135 ms, 140.234375 MB memory
    round 4
    0.5847921986324484 ops/s TypeORM insert 1,710.009132027626 ms, 141.4921875 MB memory
    5.850612679085713 ops/s TypeORM fetch 170.92226999998093 ms, 154.796875 MB memory
    

    Note: TypeORM has no UnitOfWork and thus inserting 10k happens via typeorm.manager.save(TypeOrmModel, items), which is naturally faster. Here is a benchmark of a ORM with UnitOfWork for a better reference.

    round 1
    4.781501792938342 ops/s Marshal insert 209.1393129825592 ms, 70.2734375 MB memory
    16.781018394176918 ops/s Marshal fetch 59.591139018535614 ms, 86.30859375 MB memory
    round 2
    7.130604420772976 ops/s Marshal insert 140.24056601524353 ms, 100.296875 MB memory
    32.69504859809784 ops/s Marshal fetch 30.58567100763321 ms, 107.0390625 MB memory
    round 3
    8.989556662613543 ops/s Marshal insert 111.2401909828186 ms, 113.4609375 MB memory
    49.55669555919416 ops/s Marshal fetch 20.178907990455627 ms, 121.6015625 MB memory
    round 4
    8.519063107519148 ops/s Marshal insert 117.38379999995232 ms, 111.03515625 MB memory
    48.701026779872905 ops/s Marshal fetch 20.533447980880737 ms, 112 MB memory
    round 5
    10.715570703516867 ops/s Marshal insert 93.32214099168777 ms, 114.41015625 MB memory
    52.12080869452746 ops/s Marshal fetch 19.186195015907288 ms, 115.3828125 MB memory
    

    Without Identity Map

    When I add orm.em.clear(); right before the await bench(1, 'Mikro-ORM fetch, I basically disable Identity Map for the fetch, which I do as well for all other benchmarks (typeorm/marshal). The memory leak is then not that bad, however fetch times drastically increase.

    round 1
    0.14027045884962996 ops/s Mikro-ORM insert 7,129.08482798934 ms, 167.1484375 MB memory
    2.160074054846749 ops/s Mikro-ORM fetch 462.9470909833908 ms, 160.453125 MB memory
    round 2
    0.0850145411912262 ops/s Mikro-ORM insert 11,762.693604975939 ms, 166.82421875 MB memory
    2.45439285240989 ops/s Mikro-ORM fetch 407.43273800611496 ms, 181.80859375 MB memory
    round 3
    0.08564632189772563 ops/s Mikro-ORM insert 11,675.92463800311 ms, 321.8828125 MB memory
    2.701008498703899 ops/s Mikro-ORM fetch 370.2320820093155 ms, 330.484375 MB memory
    round 4
    0.09211291201040393 ops/s Mikro-ORM insert 10,856.241304010153 ms, 346.94140625 MB memory
    2.7796832507085085 ops/s Mikro-ORM fetch 359.7532199919224 ms, 352.234375 MB memory
    round 5
    0.08652217583452965 ops/s Mikro-ORM insert 11,557.73060899973 ms, 191.89453125 MB memory
    2.7081659883433256 ops/s Mikro-ORM fetch 369.253585010767 ms, 183.26171875 MB memory
    round 6
    0.08637979298259872 ops/s Mikro-ORM insert 11,576.781623005867 ms, 352.48828125 MB memory
    2.5409797655486086 ops/s Mikro-ORM fetch 393.5489819943905 ms, 355.92578125 MB memory
    

    Expected behavior

    Consistent insert times. Quicker inserts.

    Versions

    | Dependency | Version | | - | - | | node | 14.5.0 | | typescript | 3.9.6 | | mikro-orm | 3.6.15? | | mongodb | 3.6.0 |

    Questions

    Is there anything I did wrong with the code? It feels weird to me that orm.em.persist is an async function, so maybe its related to that.

    performance 
    opened by marcj 43
  • Cannot use v5.4.0 with ts-node on Node v16

    Cannot use v5.4.0 with ts-node on Node v16

    Describe the bug After upgrading to v5.4.0 I can no longer run npx mikro-orm debug (or use it in any other way) if ts-node is involved. It has something to do with how dynamic imports are handled now.

    I did make it work tho by running it like this:

    node_modules/.bin/ts-node-esm node_modules/@mikro-orm/cli/cli debug
    

    also like this (when running my app, not the mikro-orm's CLI itself):

    node --inspect=0.0.0.0:9229 --loader ts-node/esm bootstrap.ts
    

    Prior to the upgrade, it did work out of the box. Everything seems to be fine outside the ts-node's context (e.g. when running compiled JS).

    CLI

    npx mikro-orm debug 
    Current MikroORM CLI configuration
     - dependencies:
       - mikro-orm 5.4.0
       - node 16.17.0
       - typescript 4.6.4
     - package.json found
     - ts-node enabled
     - searched config paths:
       - /path/to/my/project/config/mikro-orm.config.override.ts (not found)
       - /path/to/my/project/config/mikro-orm.config.ts (found)
       - /path/to/my/project/config/mikro-orm.config.js (not found)
       - /path/to/my/project/mikro-orm.config.ts (not found)
       - /path/to/my/project/mikro-orm.config.js (not found)
    - configuration not found (Unknown file extension ".ts" for /path/to/my/project/config/mikro-orm.config.ts)
    

    tsconfig.json

    {
        "compilerOptions": {
          "target": "es2021",                       /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */
          "module": "commonjs",                     /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
          "lib": ["es2021", "DOM"],                 /* Specify library files to be included in the compilation. */
          "declaration": true,                      /* Generates corresponding '.d.ts' file. */
          "sourceMap": true,                        /* Generates corresponding '.map' file. */
           "outDir": "build",                       /* Redirect output structure to the directory. */
          "strict": true,                           /* Enable all strict type-checking options. */
           "strictPropertyInitialization": false,  /* Enable strict checking of property initialization in classes. */
           "alwaysStrict": true,                  /* Parse in strict mode and emit "use strict" for each source file. */
           "noUnusedLocals": true,                /* Report errors on unused locals. */
           "noUnusedParameters": true,            /* Report errors on unused parameters. */
           "noImplicitReturns": true,             /* Report error when not all code paths in function return a value. */
           "noFallthroughCasesInSwitch": true,    /* Report errors for fallthrough cases in switch statement. */
          "moduleResolution": "node",               /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
          "rootDirs": [                             /* List of root folders whose combined content represents the structure of the project at runtime. */
          ],
          "types": [                                /* Type declaration files to be included in compilation. */
              "node",
              "mocha"
          ],
          "esModuleInterop": true,                  /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
          "experimentalDecorators": true,           /* Enables experimental support for ES7 decorators. */
          "emitDecoratorMetadata": true,            /* Enables experimental support for emitting type metadata for decorators. */
          "resolveJsonModule": true,
          "forceConsistentCasingInFileNames": true
        }
      }
      
    

    Additional context I'm not actually using ESM in my app. This app remembers NodeJS v8 :)

    Versions

    | Dependency | Version | | - | - | | node | 16.17.0 | | typescript | 4.6.4 | | mikro-orm | 5.4.0 | | your-driver | MySQL |

    bug 
    opened by XanderEmu 38
  • Monorepo config support

    Monorepo config support

    Hi!

    I tried out MikroORM in an NX Workspace, and to use it there, I see a blocker.

    Really easy to try out, there is a create-nx-workspace npm package out there and it can scaffold up a workspace with nestjs in no time

    In an NX Monorepo setup, every single project uses the same top-level package.json, but MikroORM CLI relies on the config specified in the package.json.

    .
    ├── angular.json
    ├── apps
    │   ├── demo-server
    │   │   ├── src
    │   │   └── tsconfig.json
    │   └── demo-server-2
    │       ├── src
    │       └── tsconfig.json
    ├── nx.json
    ├── package.json
    ├── tsconfig.json
    └── tslint.json
    

    In this setup, demo-server and demo-server-2 needs separate configurations for the CLI, but there is only one package.json!

    I suppose I could make a shim package.json file, for only this but it would be rather ugly. I suggest that aside the package.json config (Lot of other libraries do it, I see no problem with that) to introduce an additional, optional config file that the CLI can pick up. Like mikroorm.config.json or something like that.

    I really like that the config itself is in JS/TS because this enables me to write some extra logic to handle multiple environments.

    enhancement 
    opened by AlexAegis 38
  • Sometimes calling em.populate does not init a relation

    Sometimes calling em.populate does not init a relation

    Describe the bug Sometimes calling em.populate does not init a relation

    Stack trace

    Cannot read properties of undefined (reading 'getItems') <- happens to 1:M / M:N relations
    

    or

    Cannot return null from non-nullable field <- GraphQL server throws it, happens to 1:1 relations
    

    To Reproduce Steps to reproduce the behavior: Unfortunately I was not able to reliably reproduce this behaviour. Mostly it works for us but typically a few times per day we get this error in the same parts of the code. Given its unstable nature I would suspect that there is a race condition somewhere. If needed, I'll be happy to add some debugging info into our code to get more information from runtime exceptions.

    We operate a GraphQL API and relevant entities look like the following:

    1:N / M:N

    abstract class BaseEntity {
    	@PrimaryKey({ length: 25, type: 'string' })
    	id = cuid()
    
    	@Property({
    		type: 'Date',
    		fieldName: 'createdAt',
    	})
    	createdAt = new Date()
    
    	@Property({
    		type: 'Date',
    		fieldName: 'updatedAt',
    		onUpdate: () => new Date(),
    	})
    	updatedAt = new Date()
    }
    
    @Entity({ collection: 'Trait' })
    class Trait extends BaseEntity {
    	[OptionalProps]?: 'createdAt' | 'updatedAt'
    
            @OneToMany({ entity: 'Translation', mappedBy: 'trait' })
    	translations = new Collection<Translation>(this)
    
    	@OneToMany({ entity: 'Translation', mappedBy: 'traitDescription' })
    	descriptions = new Collection<Translation>(this)
    }
    
    enum LOCALE {
    	DE = 'DE',
    	EN = 'EN',
    	FR = 'FR',
    	ES = 'ES',
    	PT = 'PT',
    }
    
    @Entity({ collection: 'Translation' })
    class Translation extends BaseEntity {
    	[OptionalProps]?: 'createdAt' | 'updatedAt'
    
    	@Enum({ items: () => LOCALE, type: 'LOCALE' })
    	locale!: LOCALE
    
    	@Property({ columnType: 'text', type: 'string' })
    	text!: string
    
    	@ManyToOne({
    		entity: () => Trait,
    		fieldName: 'trait',
    		onDelete: 'cascade',
    		nullable: true,
    	})
    	trait?: Trait
    
    	@ManyToOne({
    		entity: () => Trait,
    		fieldName: 'traitDescription',
    		onDelete: 'cascade',
    		nullable: true,
    	})
    	traitDescription?: Trait
    }
    
    async function pseudoGraphQL() {
    	const traits = await em.find(Trait, {})
    
    	const getTranslation = async (parent: Trait) => {
    		await em.populate(parent, ['translations'])
    
    		const translation = parent.translations
    			.getItems()
    			.find(({ locale }) => locale === 'EN')
    
    		return translation?.text
    	}
    
    	const getDescription = async (parent: Trait) => {
    		await em.populate(parent, ['descriptions'])
    
    		const description = parent.descriptions
    			.getItems()
    			.find(({ locale }) => locale === 'EN')
    
    		return description?.text
    	}
    
    	await Promise.all(
    		traits.map(traits => {
    			return Promise.all([getTranslation(traits), getDescription(traits)])
    		})
    	)
    }
    

    1:1

    @Entity({ collection: 'Company' })
    class Company extends BaseEntity {
            [OptionalProps]?: 'createdAt' | 'updatedAt'
    
    	@OneToOne({ entity: 'Image', mappedBy: 'companyLogo' })
    	logo!: Image
    
    	@OneToOne({ entity: 'Image', mappedBy: 'companyImage' })
    	image!: Image
    }
    
    @Entity({ collection: 'Image' })
    class Image extends BaseEntity {
    	[OptionalProps]?: 'createdAt' | 'updatedAt'
    
    	@Property({ columnType: 'text', type: 'string' })
    	url!: string
    
    	@OneToOne({ entity: 'Company', nullable: true, onDelete: 'cascade' })
    	companyLogo?: Company
    
    	@OneToOne({ entity: 'Company', nullable: true, onDelete: 'cascade' })
    	companyImage?: Company
    }
    
    async function pseudoGraphQL() {
    	const companies = await em.find(Company, {})
    
    	const getLogo = async (parent: Company) => {
    		await em.populate(parent, ['logo'])
    		if (!parent.logo) {
    			throw new Error(
    				'Cannot return null for non-nullable field Company.logo'
    			)
    		}
    		return parent.logo
    	}
    
    	const getImage = async (parent: Company) => {
    		await em.populate(parent, ['image'])
    		if (!parent.image) {
    			throw new Error(
    				'Cannot return null for non-nullable field Company.image'
    			)
    		}
    		return parent.image
    	}
    
    	await Promise.all(
    		companies.map(company => {
    			return Promise.all([getLogo(company), getImage(company)])
    		})
    	)
    }
    

    Expected behavior Calling em.populate does not result in a property being undefined

    Additional context One thing that comes to my mind is that for both these cases entities are connected twice through different fields:

          <--(logo)--> Image
    Company
          <--(image)--> Image
    
    
    
          <--(translations)--> Translation[]
    Trait
          <--(descriptions)--> Translation[]
    

    Versions

    | Dependency | Version | | - | - | | node | 16.16.0 | | typescript | 4.4.4 | | mikro-orm | 5.3.1 | | postgresql | 5.3.1 |

    opened by wasd171 37
  • Mysql - Datetime - Timestamp - Timezone issues

    Mysql - Datetime - Timestamp - Timezone issues

    Introduction

    This article will provide my results testing Timezone matters for various nodejs libraries/drivers when MySql does not hold datetime in UTC.

    One could argue that it is certainly way better to store all dates in UTC (especially because UTC is DST independant) however there maybe a couple of reason not having dates in UTC:

    • a legacy database with multiple apps where timezone considerations were not taken into account (and that's indeed why I've done this work)
    • because one would prefer to manipulate date in its own timezone when directly using a query tool.

    Because I was struggling with timezone and because the documentation does often leaves to be desired, I decided to to some testing with the following libraries:

    • mikroorm
    • mariadb connector
    • mysql
    • typeorm

    The setup

    • a separate Mysql server witht timezone configured to '+05:00'
    • a table that hold both a DATETIME column and a TIMESTAMP column
    • a separate server with a node application running the test. This server local time is GMT+1 based.

    What I'm testing

    • I'm retrieving an existing record that holds both a DATETIME and a TIMESTAMP column and see what I get and if it sounds coherent.
    • I insert a record using the same date for both the DATETIME and TIMESTAMP and retrieve back the record and see what I get

    notes

    Having Mysql timezone configured to '+05:00' basically means that all dates in Mysql are GMT+5 based. This is examplified by the fact that CURRENT_TIMESTAMP will return a GMT+5 date.

    In mysql, we can store date and time in DATETIME column and TIMESTAMP columns. DATETIME does not hold any timezone information. Therefore you have to know what you are doing by convention.
    TIMESTAMP Will store dates in UTC and will display using whatever timezone is currently configured.
    Initialising both type of columns with CURRENT_TIMESTAMP will display the exact same date. However, because TIMESTAMP are stored in UTC, if you change MySql current timezone, TIMESTAMP columns will display their DATETIME value according to the new timezone while DATETIME columns are left unchaged.

    Mysql Configuration

    UTC_TIMESTAMP() CURRENT_TIMESTAMP() @@system_time_zone @@time_zone @@GLOBAL.time_zone @@SESSION.time_zone
    2020-03-20 23:32:11 2020-03-21 04:32:11 CET +05:00 SYSTEM +05:00

    Retrieving an existing record - Connection timezone configured to '+05:00'

    MySql TimeZone: +05:00
    Nodejs env Timezone: CET
    mikroorm
    Cx timezone: +05:00
    mariadb
    Cx timezone: +05:00
    mysql
    Cx timezone: +05:00
    typeorm
    Cx timezone: +05:00
    DateTimeColumn TimeStampColumn DateTimeColumn TimeStampColumn DateTimeColumn TimeStampColumn DateTimeColumn TimeStampColumn
    As Displayed In MySql 2020-03-17 11:11:11 2020-03-17 11:11:11 2020-03-17 11:11:11 2020-03-17 11:11:11 2020-03-17 11:11:11 2020-03-17 11:11:11 2020-03-17 11:11:11 2020-03-17 11:11:11
    Date.toString() 2020-03-17 11:11:11 GMT+0100   2020-03-17 07:11:11 GMT+0100   2020-03-17 07:11:11 GMT+0100   2020-03-17 03:11:11 GMT+0100   2020-03-17 07:11:11 GMT+0100   2020-03-17 03:11:11 GMT+0100   2020-03-17 07:11:11 GMT+0100   2020-03-17 03:11:11 GMT+0100  
    Date.toUTCString() 2020-03-17 10:11:11 GMT 2020-03-17 06:11:11 GMT 2020-03-17 06:11:11 GMT 2020-03-17 02:11:11 GMT 2020-03-17 06:11:11 GMT 2020-03-17 02:11:11 GMT 2020-03-17 06:11:11 GMT 2020-03-17 02:11:11 GMT

    Analysis

    First of all, I would expect the exact same result for both DATETIME and TIMESTAMP column. The fact that MySql store TIMESTAMP values as UTC internally should not affect the expected result. Therefore I'm expecting the following results for both columns:

    As Displayed In MySql 2020-03-17 11:11:11
    Date.toString() 2020-03-17 07:11:11 GMT+0100  
    Date.toUTCString() 2020-03-17 06:11:11 GMT

    mariadb, mysql and typeorm

    They have the same results and seem to use the same approach. I suppose that typeorm relies on the driver. The DATETIME column is handled properly and I get the expected results. The TIMESTAMP column gives wrong results Not sure what it does because there is a 4 hours shift.

    mikroorm

    Has it's own approach here.
    Contrary to other libraries, TIMESTAMP provides the expected values here.
    On the other hand DATETIME column provides wrong result. It seems to be handled as if the value was in the timezone of the running node app (that's pure hypothesis, would need to change the running timezone to confirm)

    mikroorm only - Retrieving an existing record - timezone configured to '+05:00' - ForceUtcTimezone: true

    MySql TimeZone: +05:00
    Nodejs env Timezone: CET
    mikroorm
    Cx timezone: +05:00
    ForceUtcTimezone: true
    DateTimeColumn TimeStampColumn
    As Displayed In MySql 2020-03-17 11:11:11 2020-03-17 11:11:11
    Date.toString() 2020-03-17 12:11:11 GMT+0100   2020-03-17 08:11:11 GMT+0100  
    Date.toUTCString() 2020-03-17 11:11:11 GMT 2020-03-17 07:11:11 GMT

    Inserting a record with the following date: new Date('2020-03-17T07:11:11')

    MySql TimeZone: +05:00
    Nodejs env Timezone: CET
    mikroorm
    Cx timezone: +05:00
    mariadb
    Cx timezone: +05:00
    mysql
    Cx timezone: +05:00
    typeorm
    Cx timezone: +05:00
    DateTimeColumn TimeStampColumn DateTimeColumn TimeStampColumn DateTimeColumn TimeStampColumn DateTimeColumn TimeStampColumn
    As Displayed In MySql 2020-03-17 07:11:11 2020-03-17 11:11:11 2020-03-17 11:11:11 2020-03-17 15:11:11 2020-03-17 11:11:11 2020-03-17 15:11:11 2020-03-17 11:11:11 2020-03-17 15:11:11
    Date.toString() 2020-03-17 07:11:11 GMT+0100   2020-03-17 07:11:11 GMT+0100   2020-03-17 07:11:11 GMT+0100   2020-03-17 07:11:11 GMT+0100   2020-03-17 07:11:11 GMT+0100   2020-03-17 07:11:11 GMT+0100   2020-03-17 07:11:11 GMT+0100   2020-03-17 07:11:11 GMT+0100  
    Date.toUTCString() 2020-03-17 06:11:11 GMT 2020-03-17 06:11:11 GMT 2020-03-17 06:11:11 GMT 2020-03-17 06:11:11 GMT 2020-03-17 06:11:11 GMT 2020-03-17 06:11:11 GMT 2020-03-17 06:11:11 GMT 2020-03-17 06:11:11 GMT

    Analysis

    In that scenario, I insert a record in the database with respective libraries and use for both DATETIME and TIMESTAMP column the following value: new Date('2020-03-17T07:11:11').
    The node application being in a GMT+1 timezone, and considering how javascript date work, I'm expecting the following results for both columns:

    As Displayed In MySql 2020-03-17 11:11:11
    Date.toString() 2020-03-17 07:11:11 GMT+0100  
    Date.toUTCString() 2020-03-17 06:11:11 GMT

    mariadb, mysql and typeorm

    Once again, those libs have the same results.
    The DATETIME column provides the expected results as far as I am concerned.
    The TIMESTAMP column gives wrong results.

    mikroorm

    Has it's own approach here.
    Again as opposed to the other libraries, TIMESTAMP provides the expected values here.
    On the other hand DATETIME column provides wrong result. It looks like for DATETIME column, it will store the local time for the running node app.

    Conclusion

    I am by no mean an expert. Do not hesitate to comment, and correct me for whatever.
    As far as I am concerned, I feel like all libraries tested have it wrong in a way or another but one may disagree and prove me wrong.

    mikroorm

    It has it right for TIMESTAMP column using connection driver timezone.
    On the other hand I find their choice for DATETIME columns quite weird. Mikroorm considers DATETIME column value as local timezone date (local to the running application) unless you set forceUtcTimezone to true, in which case DATETIME column values will be considered utc dates. This is not consistent with the fact that CURRENT_TIMESTAMP as the default value of a DATETIME column will provide current MySql timezone date.

    mariadb, mysql and typeorm

    They got it rigt for the DATETIME column.
    TIMESTAMP handling is completely wrong in my mind.
    DATETIME column is stored as is by mysql. It is therefore a matter of convention. However, TIMESTAMP value is stored in UTC. Therefore there shouldn't be any amiguity regarding its value.

    I would appreciate any comments, correction, whatever.

    bug 
    opened by FredericLatour 30
  • ValidationError: You cannot call em.flush() from inside lifecycle hook handlers

    ValidationError: You cannot call em.flush() from inside lifecycle hook handlers

    Describe the bug My problem is related to #627 . As pretty much same thing is happening to me but not a custom repository but a service class. Is it cause I am not using a DI? I don't even know. I first used apollo-server-fastify and thought it had to something to do with fastify so I switched to apollo-server-express but it didn't solve the issue. I tried adding RequestContext middleware but it still didn't work.

    Here is the github repo. It contains a single user entity with basic crud operations. But here are the main files;

    1. Server init
    import express from "express";
    import { ApolloServer } from "apollo-server-express";
    import { MikroORM, RequestContext } from "mikro-orm";
    import config from "./mikro-orm.config";
    import { buildSchema } from "type-graphql";
    
    export const DI = {} as {
      orm: MikroORM;
    };
    // Init Server
    (async () => {
      const app = express();
      const port = process.env.PORT ? Number(process.env.PORT) : 3010;
    
      try {
        DI.orm = await MikroORM.init(config);
    
        const apolloServer = new ApolloServer({
          schema: await buildSchema({
            resolvers: [__dirname + "/modules/**/*.resolver.{ts,js}"],
            emitSchemaFile: false,
          }),
          context: ({ req, res }) => ({ req, res }),
        });
    
        app.use((_req, _res, next) => {
          RequestContext.create(DI.orm.em, next);
        });
    
        apolloServer.applyMiddleware({ app });
    
        app.listen(port, "0.0.0.0", () => console.log(`Server running on port: ${port}`));
      } catch (err) {
        console.log(err);
        process.exit(1);
      }
    })();
    
    
    1. Orm config
    import { Options } from "mikro-orm";
    import { BaseEntity } from "./globals/entity";
    import { User } from "./modules/user/user.entity";
    
    const config: Options = {
      type: "postgresql",
      clientUrl: "postgres://postgres:test@localhost:5432/mikro",
      entities: [BaseEntity, User],
      migrations: {
        path: "./src/migrations",
      },
    };
    
    export default config;
    
    1. User Entity
    import { Entity, Property } from "mikro-orm";
    import { BaseEntity } from "../../globals/entity";
    import { ObjectType, Field, Int } from "type-graphql";
    import bcrypt from "bcryptjs";
    
    @ObjectType()
    @Entity()
    export class User extends BaseEntity {
      @Field()
      @Property({ unique: true })
      username: string;
    
      @Field()
      @Property({ unique: true })
      email: string;
    
      @Property()
      password: string;
    
      @Field(() => Int)
      @Property()
      age: number;
    
      @Field()
      @Property()
      sex: string;
    
      async hashPassword(): Promise<void> {
        const salt = await bcrypt.genSalt();
        this.password = await bcrypt.hash(this.password, salt);
      }
    
      async comparePassword(password: string): Promise<boolean> {
        return bcrypt.compare(password, this.password);
      }
    }
    
    1. User Resolver
    import { Resolver, Mutation, Query, Args, Arg } from "type-graphql";
    import { User } from "./user.entity";
    import UserService from "./user.service";
    import {
      CreateUserDTO,
      UserFilterDTO,
      UserPaginationDTO,
      IdDTO,
      UpdateUserDTO,
      UpdateUserPasswordDTO,
    } from "./user.dto";
    
    @Resolver(User)
    export class UserResolver {
      public readonly userService = new UserService();
    
      @Mutation(() => User)
      async createUser(@Args() dto: CreateUserDTO): Promise<User> {
        return this.userService.createUser(dto);
      }
    
      @Query(() => [User])
      async getUsers(
        @Arg("filter", { nullable: true }) filter: UserFilterDTO,
        @Args() pagination: UserPaginationDTO,
      ): Promise<User[]> {
        return this.userService.getUsers(filter, pagination);
      }
    
      @Query(() => User)
      async getUser(@Args() { id }: IdDTO): Promise<User> {
        return this.userService.getUser(id);
      }
    
      @Mutation(() => User)
      async updateUser(@Args() { id }: IdDTO, @Args() dto: UpdateUserDTO): Promise<User> {
        return this.userService.updateUser(id, dto);
      }
    
      @Mutation(() => User)
      async updateUserPassword(@Args() { id }: IdDTO, @Args() dto: UpdateUserPasswordDTO): Promise<User> {
        return this.userService.updateUserPassword(id, dto);
      }
    
      @Mutation(() => Boolean)
      async deleteUser(@Args() { id }: IdDTO): Promise<boolean> {
        return this.userService.deleteUser(id);
      }
    }
    
    1. User Service
    export default class UserService {
      protected readonly userRepo = DI.orm.em.getRepository(User);
    
      async createUser(dto: CreateUserDTO): Promise<User> {
        const { username, email, password, confirm, age, sex } = dto;
    
        if (password !== confirm) {
          throw new Error("match fail");
        }
    
        const user = this.userRepo.create({
          username,
          email,
          password,
          age,
          sex,
        });
        try {
          await user.hashPassword();
          await this.userRepo.persist(user, true);
        } catch (error) {
          if (error.code === "23505") {
            const rxp = /\(([^)]+)\)/;
            const key = rxp.exec(error.detail);
            if (key) {
              throw new Error(`${key[1]} already exists`);
            }
          } else {
            throw new Error(error);
          }
        }
    
        return user;
      }
    
    async getUsers(filter: UserFilterDTO, pagination: UserPaginationDTO): Promise<User[]> {
        const query = this.userRepo.createQueryBuilder("user");
    
        if (filter) {
          const { username, email } = filter;
          if (username != null) {
            query.where({ username: { $like: username } });
          }
          if (email != null) {
            // This is how I wrote in TYPEORM
            // query.andWhere("user.email ILIKE :email", {email});
            // what is the equivalent of this in mikro-orm
          }
        }
    
        const { limit, offset, sort, by } = pagination;
        query
          .limit(limit)
          .offset(offset)
          .orderBy({ [by]: sort });
    
        console.log(query.getQuery(), query.getParams());
    
        return query.getResult();
      }
    }
    

    Can you review the code too and see if I can improve it or something that I did bad? Also how do you use ILIKE

    Stack trace

    ValidationError: You cannot call em.flush() from inside lifecycle hook handlers
        at Function.cannotCommit (/home/red/Documents/work/rewise/server/node_modules/mikro-orm/dist/utils/ValidationError.js:129:16)
        at UnitOfWork.commit (/home/red/Documents/work/rewise/server/node_modules/mikro-orm/dist/unit-of-work/UnitOfWork.js:87:43)
        at EntityManager.flush (/home/red/Documents/work/rewise/server/node_modules/mikro-orm/dist/EntityManager.js:330:36)
        at EntityManager.persistAndFlush (/home/red/Documents/work/rewise/server/node_modules/mikro-orm/dist/EntityManager.js:275:20)
        at EntityManager.persist (/home/red/Documents/work/rewise/server/node_modules/mikro-orm/dist/EntityManager.js:265:25)
        at EntityRepository.persist (/home/red/Documents/work/rewise/server/node_modules/mikro-orm/dist/entity/EntityRepository.js:9:24)
        at UserService.<anonymous> (/home/red/Documents/work/rewise/server/src/modules/user/user.service.ts:24:27)
        at Generator.next (<anonymous>)
        at fulfilled (/home/red/Documents/work/rewise/server/src/modules/user/user.service.ts:5:58) {
      entity: undefined
    }
    

    To Reproduce Steps to reproduce the behavior:

    1. Create a user
    2. Create/update another user with already used email/username Now the method is unusable

    Expected behavior Expected to work normal but after unique constraint error is thrown, following request on that method fails showing this error.

    Additional context ...

    Versions

    | Dependency | Version | | - | - | | node | 12.18.0 | | typescript | 3.9.7 | | mikro-orm | 3.6.15 |

    question 
    opened by asmimo 29
  • [bug] OneToOne inverse relationship not made

    [bug] OneToOne inverse relationship not made

    Looking at the database, the issue seems to be that dog.person isn't populated, but person.dog is.

    https://github.com/lookfirst/mikro-example/blob/master/test/dog.spec.ts#L51

    [query] begin
    [query] insert into `Dog` default values [took 1 ms]
    [query] insert into `Person` (`dog`, `email`, `id`) values (?, ?, ?) [took 1 ms]
    [query] commit
    [query] select `e0`.* from `Dog` as `e0` where `e0`.`id` = ? limit ? [took 1 ms]
    
    TypeError: Cannot read property 'init' of null
        at Context.<anonymous> (test/dog.spec.ts:61:42)
    
    bug 
    opened by lookfirst 29
  • MikroORM v3

    MikroORM v3

    Progress

    • [x] Change autoFlush default value to false #63
    • [x] Use knex as query runner #64
    • [x] Enable connection pooling #64
    • [x] Rework schema generator to use knex #81
    • [x] Remove deprecated 1:m fk parameter #87
    • [x] Move MetadataStorage.getClassName() to NamingStrategy #15
    • [x] Use instance of metadata instead of global storage #91
    • [x] Add onInit lifecycle hook #83
    • [x] Support virtual property getters #82
    • [x] Support multiple conditions in JOINs #70
    • [x] Add entity generator based on current db schema #78, #98
    • [x] Implement schema updates #97
    • [x] Add basic CLI tool #101, #102
    • [x] Improve logging - add namespaces, colors and highlighting #108, #109
    • [x] Support for read replica connections #77, #116
    • [x] Add Reference<T> wrapper to allow better type checking of m:1 and 1:1 references #107, #117
    • [x] Add support for MariaDB #110, #120
    • [x] Add findOneOrFail method to entity manager and repository #133, #142
    • [x] Add debug CLI command to ease debugging of ORM's configuration #136
    • [x] Allow logging full query including params #155
    • [x] Add type-safe way to define relationships #146
    • [x] Validate one to one relationship metadata #149
    • [x] Auto-wire missing references from owner to inverse side #149
    • [x] Allow populating all relationships via passing populate: true #160
    • [x] Add findAndCount() to EM and repository interface #123
    • [x] Allow querying by relationships #157
    • [x] Add support for eager loading #168
    • [x] Improve typing of FilterQuery #124, #193
    • [x] Rework IEntity interface and entity definition #171, #193
    • [x] Allow mapping results of query builder to entities directly
    • [x] Add support for bundling via Webpack #196, #200
    • [x] Allow using composite PK in M:N pivot tables #121, #204
    • [x] Do not require entity attribute in collection decorators #207
    • [x] Add support for migrations via umzug #209
    • [x] Add migrations support to CLI #209
    • [x] Add support for enums via @Enum() #215, #232
    • [x] Add support for create/drop database #237
    • [x] Add ReflectMetadataProvider #240
    • [ ] Add support for user defined indexes via @Index() #226
    • [ ] Support searching by regexp in query builder

    Documentation

    • [x] autoFlush
    • [x] new schema generator API
    • [x] entity generator
    • [x] CLI
    • [x] virtual properties
    • [x] new naming strategy api (getClassName())
    • [x] new logger configuration
    • [x] Reference<T> wrapper
    • [x] MariaDB driver
    • [x] Read replica connections
    • [x] Cross-database joins and cross-schema joins
    • [x] Defining relationships
    • [x] Upgrading v2 to v3 guide - autoFlush, knex, fk option, ...
    • [x] Reworked entity definition
    • [x] Deployment section
    • [x] Migrations
    • [x] Update example repositories, maybe split them to dedicated repos #131
    • [x] Metadata providers
    • [ ] Update roadmap

    docs for v3 can be found here: https://mikro-orm.github.io/docs/v3/

    upgrading guide:

    • up to date: https://github.com/mikro-orm/mikro-orm/blob/dev/docs/upgrading-v2-to-v3.md
    • snapshot: https://mikro-orm.github.io/docs/v3/upgrading-v2-to-v3/
    opened by B4nan 29
  • chore(deps): update dependency @types/fs-extra to v11

    chore(deps): update dependency @types/fs-extra to v11

    Mend Renovate

    This PR contains the following updates:

    | Package | Change | Age | Adoption | Passing | Confidence | |---|---|---|---|---|---| | @types/fs-extra (source) | 9.0.13 -> 11.0.0 | age | adoption | passing | confidence |


    Configuration

    📅 Schedule: Branch creation - "every weekday" (UTC), Automerge - At any time (no schedule defined).

    🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

    ♻ Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

    🔕 Ignore: Close this PR and you won't be reminded about this update again.


    • [ ] If you want to rebase/retry this PR, check this box

    This PR has been generated by Mend Renovate. View repository job log here.

    opened by renovate[bot] 1
  • findOne query where CustomType in not-id-PK with mapToPK=true throws an error

    findOne query where CustomType in not-id-PK with mapToPK=true throws an error

    Describe the bug During findOne query when do casting to CustomType mikro-orm throws an error. mapToPK = true and CustomType bound to Primary key

    Note: Without CustomType all is working fine

    Stack trace

    TypeError: Cannot read properties of undefined (reading 'getPrimaryKey')
        at eval (eval at createFunction (C:\Projects\backend-api\node_modules\@mikro-orm\core\utils\Utils.js:747:20), <anonymous>:26:69)
        at Function.callCompiledFunction (C:\Projects\backend-api\node_modules\@mikro-orm\core\utils\Utils.js:758:20)
        at ObjectHydrator.hydrate (C:\Projects\backend-api\node_modules\@mikro-orm\core\hydration\ObjectHydrator.js:24:23)
        at EntityFactory.hydrate (C:\Projects\backend-api\node_modules\@mikro-orm\core\entity\EntityFactory.js:177:27)
        at EntityFactory.create (C:\Projects\backend-api\node_modules\@mikro-orm\core\entity\EntityFactory.js:53:14)
        at SqlEntityManager.findOne (C:\Projects\backend-api\node_modules\@mikro-orm\core\EntityManager.js:335:35)
        at processTicksAndRejections (node:internal/process/task_queues:95:5)
        at DonationFulfilledListener.runAction (C:\Projects\backend-api\src\modules\my-module\listeners\some.listener.ts:31:28)
        at EventsManager.queueWorker (C:\Projects\backend-api\src\modules\other-module\events.manager.ts:325:5)
        at EventsManager.descriptor.value (C:\Projects\backend-api\node_modules\@mikro-orm\core\decorators\UseRequestContext.js:15:20)
    

    To Reproduce Steps to reproduce the behavior: Examples based on my real code:

    1. Entity classes
    @Entity({ tableName: 'user_groups' })
    export class UserGroup{
      @PrimaryKey({ type: CustomType })
      notIdPrimaryKey: string;
    
      [PrimaryKeyType]: string;
    
      @OneToMany(() => User, (u) => u.something)
      users = new Collection<User>(this);
    
      @Property()
      createdAt: Date = new Date();
    }
    
    @Entity({ tableName: 'users' })
    export class User {
      @PrimaryKey({ type: 'uuid', defaultRaw: 'uuid_generate_v4()' })
      id: string;
      
      @ManyToOne(() => UserGroup, {
        fieldName: 'user_group',
        onDelete: 'no action',
        onUpdateIntegrity: 'no action',
        mapToPk: true,
      })
      userGroup: string;
      
      @Property()
      otherField: string;
    }
    
    1. CustomType
    export class CustomType extends Type<string | undefined, string | undefined> {
      convertToDatabaseValue(value: string | undefined): string | undefined {
        if (value) {
          return someStringTransformer(value);
        }
    
        return undefined;
      }
    
      convertToJSValue(value: string | undefined): string | undefined {
        return value;
      }
    
      getColumnType() {
        return `varchar(64)`;
      }
    }
    
    
    1. Try to:
    em.findOne(User, { otherField: 'some value that exists in DB' }); // Record must exists to start hydration and reproduce the problem
    
    1. Error!

    Expected behavior No errors, PK is mapped to relation property of entity right

    Additional context Generated part of virtual function for eval with a problem pointed in stacktrace:

    if (data.userGroup != null && convertCustomTypes) {
    >     data.userGroup = convertToDatabaseValue_userGroup(entity.userGroup.__helper.getPrimaryKey());
                                                                         ^
        }
    
    

    Versions

    | Dependency | Version | | - | - | | node | 18.12.1 | | typescript | ^4.9.4 | | mikro-orm | ^5.6.4 | | your-driver | pg |

    opened by ZirionNeft 0
  • Unable querying on type-safe references

    Unable querying on type-safe references

    Describe the bug Seems it is unable to query entity by any Ref property even with primary ref key.

    To Reproduce

    Define any entity with type-safe reference. For example,

    @Entity()
    export class Cat {
      @PrimaryKey()
      public id!: number;
    
      @ManyToOne(() => User, { ref: true })
      public owner: Ref<User>
    }
    

    try to find any entity using Ref property. For example,

     const cat = await em.findOne(
            Cat,
            {
                id: 1,
                owner: {
                    id: 1
                }
            }
        )
    

    The code can't be compiled. tsc complains on missed Ref properties

    Argument of type '{ id: number; owner: { id: number; }; }' is not assignable to parameter of type 'FilterQuery<Cat>'.
      Types of property 'owner' are incompatible.
        Type '{ id: number; }' is not assignable to type '{ id: number; } & Reference<User>'.
          Type '{ id: number; }' is missing the following properties from type 'Reference<User>': entity, load, set, unwrap, and 5 more.ts(2345)
    

    Expected behavior

    Code compiles and executes fine

    Versions

    | Dependency | Version | | - | - | | node | 19.1.0 | | typescript | 4.9.4 | | mikro-orm | 5.6.4 | | your-driver | doesn't matter |

    opened by vimmerru 0
  • docs: add jsdoc for property

    docs: add jsdoc for property

    Hi,

    I addded js-doc for Property(), but I'm not sure it's what you meant in the issue Want to check if it is in line with your intention. 🫠

    BTW, some of the options of Property() are in docs while others like name, onCreation are not. Did you selected only some of them on purpose?

    Related https://github.com/mikro-orm/mikro-orm/issues/3893

    opened by erie0210 1
  • Support database-level defaults in embedded properties

    Support database-level defaults in embedded properties

    As long as the embeddable is inlined, this should work just fine. For object mode, we should validate metadata and throw.

    @Embeddable()
    abstract class Time {
      @Property({ defaultRaw: 'now()', nullable: false })
        timestamp?: Date;
    }
    
    @Entity()
    class Test extends BaseEntity<Test> {
      @Embedded()
        time!: Time;
    }
    
    await dbConnection.open();
    const em = dbConnection.em?.fork();
    if (em) {
      const e = new Test();
      e.time = {};
      await em.persist(e).flush();
    }
    
    NotNullConstraintViolationException: insert into "test" ("id", "time_timestamp") values ('50a071d3-633e-4055-9e0d-edbe44a0e085', NULL) returning "id" - null value in column "time_timestamp" of relation "test" violates not-null constraint
    

    Originally posted by @micchickenburger in https://github.com/mikro-orm/mikro-orm/discussions/3883#discussioncomment-4558022

    enhancement 
    opened by B4nan 0
  • Embeddable ignores `Unique` decorator when running migration:create

    Embeddable ignores `Unique` decorator when running migration:create

    Describe the bug When running npx mikro-orm migration:create @Unique decorator gets ignored, but @Property({ unique: true }) does not. When using embeddables

    To Reproduce I have created a repo https://github.com/Tronikelis/mikro-orm-issue-2

    1. Create an entity with an embeddable
    2. The embeddable should have a unique property @Unique
    3. migration:create => does not create a unique constraint
    4. Change the embeddable property to @Property({ unique: true }) => now it creates is

    With @Unique:

    import { Migration } from '@mikro-orm/migrations';
    
    export class Migration20221228181129 extends Migration {
    
      async up(): Promise<void> {
        this.addSql('create table "user" ("id" serial primary key, "metadata_slug" text not null);');
      }
    
      async down(): Promise<void> {
        this.addSql('drop table if exists "user" cascade;');
      }
    
    }
    

    With @Property({ unique: true }):

    import { Migration } from '@mikro-orm/migrations';
    
    export class Migration20221228181216 extends Migration {
    
      async up(): Promise<void> {
        this.addSql('create table "user" ("id" serial primary key, "metadata_slug" text not null);');
        this.addSql('alter table "user" add constraint "user_metadata_slug_unique" unique ("metadata_slug");');
      }
    
      async down(): Promise<void> {
        this.addSql('drop table if exists "user" cascade;');
      }
    
    }
    

    Expected behavior Both of the methods should work the same

    Versions

    | Dependency | Version | | - | - | | node | 16.19.0 | | typescript | 4.9.4 | | mikro-orm | 5.6.2 | | your-driver | postgres |

    enhancement 
    opened by Tronikelis 1
Releases(v5.6.4)
  • v5.6.4(Jan 4, 2023)

    5.6.4 (2023-01-04)

    Bug Fixes

    • core: improve inference of driver exported MikroORM.init() (497f274)
    • core: respect transaction context in em.execute() (832105d), closes #3896
    • mongo: register serialized PK get/set pair only when explicitly requested (7004100), closes #3900
    • mongo: respect field names in batch update conditions (3466c86), closes #3897

    Features

    Source code(tar.gz)
    Source code(zip)
  • v5.6.3(Dec 28, 2022)

  • v5.6.2(Dec 25, 2022)

  • v5.6.1(Dec 20, 2022)

    5.6.1 (2022-12-20)

    Bug Fixes

    • core: allow adding array of refs to collection (#3859) (0ce85e9)
    • core: clone event manager when forking in em.transactional (0e523b3), closes #3857
    • core: do not unset non-null relations when propagating remove operation (69a7f94), closes #3854
    • core: fix compiled functions when relation property uses hyphens (22350bd), closes #3813
    • core: fix populating relation with composite FK as primary key (b27578f), closes #3844
    • core: improve inference in em.findX() methods (fcb1739)
    • core: propagation with nullable 1:1 relation (#3851) (d77c370), closes #3850
    • core: remove readonly modifier from Populate type (7b2dfb9)
    • mariadb: do not force date strings (8861354), closes #3853
    • postgres: compare only simplified versions of check constraints (0fd8530), closes #3827
    • postgres: ignore internal timescale schemas automatically (85d9083)
    Source code(tar.gz)
    Source code(zip)
  • v5.6.0(Dec 9, 2022)

    5.6.0 (2022-12-09)

    Bug Fixes

    • core: deprecate type option in favour of driver exports (7180f23), closes #3743
    • core: do not mark entities as populated via em.merge() (bfa4962), closes #3812
    • core: do not process mapped types twice in em.upsert() (434d417), closes #3787
    • core: ensure correct result in ChangeSet.getPrimaryKey(true) (2e74a34), closes #3737
    • core: fix query execution inside hooks sometimes hanging (d68b9bd)
    • core: make ChangeSet.getPrimaryKey() response stable (d32c956)
    • core: remove readonly from properties of FilterQuery (2a2a13d), closes #3836
    • core: return Ref & LoadedReference from ref() (c85e507), closes #3840
    • core: serialize not managed relations as populated (89b4dab), closes #3788
    • core: support hidden flag on primary keys (4935505)
    • embeddables: respect explicit null only for object embeddables (6e0bedf), closes #3772
    • mysql: ensure bigint columns are mapped to string (d3d50ba), closes #3739
    • mysql: respect auto_increment_increment when batch inserting (516db6d), closes #3828
    • postgres: quote array literal items containing a comma (5ffa81c), closes #3810
    • postgres: use postgres as the management db name + allow override (eab1668), closes #3769
    • query-builder: fix cloning QB in some cases (c3b4c20), closes #3720
    • query-builder: fix querying for a composite FK when target is joined (dec4c9c), closes #3738
    • query-builder: respect case-insensitive regexp flag (1a1d381), closes #3801
    • query-build: fix query execution inside hooks sometimes hanging (dba6ce2)
    • schema: do not cache knex instance (dc00374), closes #3713
    • schema: ensure database exists before dropping schema (fd4c416), closes #3713
    • ts: allow string dates in em.create() (d0607d5)

    Features

    Performance Improvements

    • core: never clone Platform and EntityMetadata instances (9e05104), closes #3720
    Source code(tar.gz)
    Source code(zip)
  • v5.5.3(Nov 10, 2022)

  • v5.5.2(Nov 7, 2022)

  • v5.5.1(Nov 5, 2022)

    5.5.1 (2022-11-05)

    Bug Fixes

    • core: compare original entity data when checking for unique props (53ff984), closes #3644
    • core: fix em.upsert() when entity is already in context (f590b79), closes #3667
    • core: fix comparing empty arrays (be4cdf3), closes #3694
    • core: fix orphan removal for collections of complex/nested composite keys (925c1d2), closes #3666
    • core: fix querying for a complex composite key via inverse side (b99e7bb), closes #3669
    • core: handle $fulltext search correctly in nested queries (9a2f535), closes #3696
    • core: improve detection of entity file path via stack trace (d329d32), closes #3668
    • core: improve propagation of changes to 1:1 relations (389b4a2), closes #3614
    • embeddables: support partial loading hints (0c33e00), closes #3673
    • knex: ensure virtual properties are never part of returning clause (35d51fe), closes #3664
    • postgres: fix ensuring database exists when postgres database does not exist (b1a867d), closes #3671
    • reflection: fix reflection of embedded array types (786ba42), closes #3690
    • reflection: improve detection of array properties (8f8f820), closes #3690

    Features

    • core: add em.repo() shortcut (feebd7c)
    • core: add EntityOptions.repository shortcut (2cbb129)
    • core: add EntityRepository.upsert() shortcut (31d6d77)
    • core: add ref alias for wrappedReference relation property option (249a407)
    • core: add Rel<T> and Ref<T> relation types (44acefb)
    • core: add context param to Type.convertToDatabaseValue() (a933e98), closes #3567
    • core: allow using second argument of @OneToOne as options (115462d)
    • core: propagate parent entity to collection item payload in assign (6045511), closes #3654
    • core: propagate parent entity to collection item payload in create (bb9f8d9), closes #3654
    • core: support composite unique keys in em.upsert() (3cf79d6), closes #3656
    Source code(tar.gz)
    Source code(zip)
  • v5.5.0(Oct 23, 2022)

    5.5.0 (2022-10-23)

    Bug Fixes

    • cli: fix using npx --workspace with mikro-orm-esm (#3560) (64777af)
    • cli: improve success message of schema:update/drop commands (11d0fd9)
    • core: always compare boolean properties as booleans (c30c680), closes #3576
    • core: do not ignore default option in version properties (1572008)
    • core: do not ignore falsy version values like 0 (754d672)
    • core: fix assigning objects to collections (#3628) (82a9708)
    • core: fix changing 1:1 relations value (7b6e6f7), closes #3614
    • core: fix removing entities with complex composite keys (6d6e9f4), closes #3543
    • core: fix validation of EM param in assign (6572a59), closes #3571
    • core: hydrate mapToPk properties with the PK value (559ae28)
    • core: improve entity path detection with SWC 1.3.4+ (#3568) (9a2cb8c)
    • core: merge entity automatically via em.create(E, {}, { managed: true }) (24d206f), closes #3571
    • core: propagate entity removal to collection properties (25c1c06)
    • core: rework handling of orphan removal for 1:m collections (925c798), closes #3564
    • core: serialize embedded JSON properties correctly when used in inline embeddable (feef8b3), closes #3519
    • mongo: fix populating 1:1 owners from inverse side (25ee03a)
    • query-builder: support top level $not operator in join condition (#3609) (047504f)

    Features

    • core: add defineConfig helper (#3500) (67d3c68)
    • core: add em.refresh(entity) method (#3522) (dbe8aa4)
    • core: add em.upsert() method (#3525) (3285cdb), closes #3515
    • core: add MikroORM and Options exports to each driver package (#3499) (b68ed47)
    • core: add the offset into FindOneOptions (#3574) (9d5d457)
    • core: automatically detect src/dist/build folders and adjust configuration (#3497) (a8c8baf)
    • core: enable persistOnCreate by default (8424976)
    • core: maintain identity for the Reference wrapper (da1a0ef), closes #3582
    • core: provide meta and prop on custom mapped type instance (c1251d0), closes #3538
    • core: track changes on entity references (#3521) (0fb17bb)
    • core: validate missing items in enum definition (659c2de)
    • core: validate missing types in EntitySchema definition (0716566), closes #3603
    • migrations: allow configuring snapshot name (4bbe355), closes #3562
    • mongo: do not expand array queries to $in operator when nested inside $eq (e25d28e)
    • postgres: add qb.distinctOn() support (307d3a1)
    • query-builder: validate modification of finalized QB (b23f015), closes #3534
    • schema: add ability to ignore specific column changes (#3503) (05fb1ce), closes #1904 #1904
    • schema: try to infer runtime default values automatically (#3529) (d035781)
    • sqlite: enable returning statements in both SQLite drivers (eaf83c8)

    Performance Improvements

    • core: don't propagate serialization context to hidden relations (#3592) (e706ba2)
    • core: improve support for large collections (#3573) (ea3f6fd)
    • schema: improve schema inspection speed in SQL drivers (#3549) (74dc3b1)
    Source code(tar.gz)
    Source code(zip)
  • v5.4.2(Sep 12, 2022)

    5.4.2 (2022-09-12)

    Bug Fixes

    • core: do not double serialize nested JSON properties in embedded arrays (11112c6), closes #3327
    • core: fix dynamic loading of entities with default export (14f88cc), closes #3491
    • core: fix extracting entity reference for constructor params in em.create() (797cc3a)
    • core: fix populating of self referencing relationships (e3c835a), closes #3490
    • core: fix serialization of virtual entities (a15fc13), closes #3493
    • core: ignore * populate hints inferred from fields (c11bda6)
    • core: omit internal symbols from logged entities (29c430c)
    • core: respect serialization flags on embedded properties (8e9f6d9), closes #3429

    Features

    • cli: add mikro-orm-esm CLI script with registered ts-node/esm loader (443f0c8), closes #3485
    • entity-generator: generate OptionalProps symbols (#3482) (6ba3d40)
    • knex: allow changing FROM clause using QueryBuilder (#3378) (df7d939)
    Source code(tar.gz)
    Source code(zip)
  • v5.4.1(Sep 8, 2022)

    5.4.1 (2022-09-08)

    Bug Fixes

    • cli: only use dynamic imports for ESM projects (b3e43d0), closes #3442
    • core: add missing MIKRO_ORM_SCHEMA env var (#3464) (47fccac)
    • core: allow symbol as propertyKey in @UseRequestContext decorator (#3444) (6a60295)
    • core: change internal dependencies to use ~ instead of ^ (fdbf67c), closes #3468
    • core: support partial loading of inlined embeddables (9654e6e), closes #3365
    • migrations: replace backslash in the glob to fix windows support (9e2b549), closes #2243
    • postgres: fix inserting values with ? into FullTextType properties (5095ddb), closes #3457
    • postgres: fix parsing enum definition when one of the items has comma (c8062cb), closes #3460
    • reflection: fix inference of nullability (5f57ee1), closes #3447

    Features

    • core: allow custom ORM prop name in @UseRequestContext() (#3475) (d87219e)
    Source code(tar.gz)
    Source code(zip)
  • v5.4.0(Sep 1, 2022)

    5.4.0 (2022-09-01)

    Bug Fixes

    • cli: allow working with mongo migrations via CLI (14a07df)
    • core: allow embedded properties inside virtual entities (541d62d)
    • core: allow using $ne operator on embedded properties (89706b6), closes #3430
    • core: always use dynamic import, don't depend on MIKRO_ORM_DYNAMIC_IMPORTS (ba7eac6)
    • core: compile with module: 'Node16' to have real dynamic imports (#3439) (50347ef)
    • core: fix optimistic locking for entities with custom type on PK (e36bac5), closes #3440
    • core: lock entities in flush() to get around race conditions with Promise.all (b62799a), closes #2934 #3383
    • core: respect serialization options like hidden on embeddables (d198e44), closes #3429
    • core: support result caching on virtual entities (ce2b051)
    • core: update to TypeScript 4.8 and improve EntityDTO type (#3389) (f2957fb)
    • core: use acorn instead of escaya for extraction of method params (c5c09c5)
    • knex: support em.count() on virtual entities (5bb4ebe)
    • postgres: fix escaping of special chars in string arrays (#3405) (cd7c42f)
    • query-builder: allow using alias for delete queries (aa19a85), closes #3366
    • query-builder: support more operators in join conditions (#3399) (af885c8)
    • reflection: do not override user defined nullable attribute (75a6487)
    • reflection: fix array property type inference (4a69871)

    Features

    • core: add MikroORM.reconnect() method (53b836e)
    • core: add schema/migrator/seeder shortcuts to MikroORM class (95c8dd5)
    • entity-generator: add import extension for referenced entities (#3420) (f80809a)
    • knex: add options params to create + assign methods within EntityRepository (#3431) (cf7e9e1)
    Source code(tar.gz)
    Source code(zip)
  • v5.3.1(Aug 4, 2022)

  • v5.3.0(Aug 1, 2022)

    5.3.0 (2022-08-01)

    Bug Fixes

    • core: do not trigger auto flush from inside flush hooks (e3f34aa), closes #3345
    • entity-generator: ensure stable order of generated entities (06e0e05)
    • postgres: fix having non-PK serial column next to a non-serial PK (6c589b0), closes #3350
    • query-builder: fix qb.insert()/update() on embeddables in inline mode (#3340) (e611fa0)
    • schema: ensure stable order queries (e56a259), closes #3330
    • schema: respect explicit columnType when comparing columns (f0a20fa), closes #3317
    • schema: respect schema when renaming columns in postgres (#3344) (f905336)
    • sqlite: throw ForeignKeyConstraintViolationException where appropriate (#3343) (508e262)

    Features

    • add support for full text searches (#3317) (8b8f140)
    • core: add $exists mongodb operator with SQL fallback to is not null (112f2be), closes #3295
    • core: add disableContextResolution option to em.fork() (94442f9), closes #3338
    • core: add support for virtual entities (#3351) (dcd62ac)
    • core: add validation when using non-discovered entities in em.populate() (ab93106)
    • core: improve autocomplete for columnType (6bf616d)
    • core: improve autocomplete for type, onUpdateIntegrity and onDelete (7ee2dcb)
    • entity-generator: allow defining entities with EntitySchema instead of decorators (b423c10)
    • mongo: add support for migrations in mongo driver (#3347) (c5c6115)
    • mongo: allow reusing mongo client via driverOptions (df59ebf), closes #3352
    Source code(tar.gz)
    Source code(zip)
  • v5.2.4(Jul 25, 2022)

    5.2.4 (2022-07-25)

    Bug Fixes

    • core: do not allow passing null to required properties in em.create() (e7843fb), closes #3289
    • core: do not run onUpdate before we know something changed (6faa367), closes #3328
    • core: ensure m:n collection is not dirty after hydration (66e0a21), closes #3323 #3287
    • core: hidden properties are included in cache (#3300) (f0bc261)
    • core: respect schema when lazy loading reference via init (c876c9f), closes #3318
    • knex: fix $or over 1:m and m:1 auto-joined relations (#3307) (b6f12b2)

    Features

    • knex: allow partial loading of 1:1 owner property from inverse side (d642018), closes #3324
    Source code(tar.gz)
    Source code(zip)
  • v5.2.3(Jul 8, 2022)

  • v5.2.2(Jul 3, 2022)

    5.2.2 (2022-07-03)

    Bug Fixes

    • core: consider two NaN as equal when computing changesets (#3250) (95116a0)
    • core: ensure correct context usage in all EntityManager public methods (cc6d59b), closes #3271
    • core: ensure FK as PK is not marked as initialized too early (f12f92f), closes #3269
    • core: fix populating of 1:m collections between wildcard schema entities (69c06aa), closes #3270
    • core: fix populating of relations in afterFlush hook (26ab686), closes #3005
    • core: fix querying JSON properties with operators directly (077ca62), closes #3246
    • mongo: persist explicit null value on object embeddable as null (1c56e7a), closes #3258
    • mongo: retry only 3 times if ensuring indexes fails (#3272) (299a028)
    • seeder: fs-extra dep (#3268) (972e5ba)
    • sql: fix prefixing of JSON queries nested on relations (847ff46), closes #3242

    Features

    • core: propagate add operation to m:n owner even if not initialized (#3273) (dc9255c)
    Source code(tar.gz)
    Source code(zip)
  • v5.2.1(Jun 21, 2022)

    5.2.1 (2022-06-21)

    Bug Fixes

    • core: fix reloading version values with custom types on PKs (ebd7888), closes #3209
    • core: fix serialization of entities wrapped in POJOs (af4fadf), closes #3221
    • core: ignore undefined values during options merge (9e0f559), closes #3234
    • core: prefer current schema for loading wild card pivot table entities (f40cafa), closes #3177
    • mongo: recreate indexes when they differ (60fc7f6), closes #3118
    • mongo: use $unset when property value is undefined (f059811), closes #3233
    • mysql: handle mediumint PKs correctly (0bbbe5c), closes #3230
    • types: fix inference of optional PKs (424e0bb), closes #3230

    Features

    • core: allow to adjust default type mapping (ca8ce57), closes #3066

    Performance Improvements

    • core: allow disabling change tracking on property level (7d5e32d), closes #3019
    • core: make Collection.add on not managed entities much faster (75adda9), closes #3211
    Source code(tar.gz)
    Source code(zip)
  • v5.2.0(Jun 10, 2022)

    5.2.0 (2022-06-10)

    Bug Fixes

    • core: allow changing PK via UoW (32ab215), closes #3184
    • core: ensure correct cached value in loadCount (4471bb8)
    • query-builder: fix calling qb.count('id', true).getCount() (a97324a), closes #3182
    • query-builder: fix processing of custom types in explicitly aliased queries (db137a6), closes #3172
    • schema: do not consider autoincrement columns as primary automatically (088afdb), closes #3187
    • ts-morph: use module: 'node16' for reflection (024d9d9), closes #3168
    • typing detection with typescript 4.7 node16 (#3163) (08322fa)

    Features

    • core: automatically discover target embeddables and relationships (#3190) (8624dc5)
    • entity-generator: allow generating bidirectional relations (8b93400), closes #3181
    • entity-generator: allow generating identified references (1fbf5ac)
    • knex: allow reusing existing knex client via driverOptions (c169eda), closes #3167
    • schema: add logging to schema comparator (f96eaaf)
    Source code(tar.gz)
    Source code(zip)
  • v5.1.5(May 29, 2022)

  • v5.1.4(May 19, 2022)

    5.1.4 (2022-05-19)

    Bug Fixes

    • core: allow asterisk in FindOptions.fields on TS level (43e1d0b), closes #3127
    • core: fix aliasing of formula properties in complex conditions (#3130) (071846e)
    • core: improve type of em.getContext() (158f077), closes #3120
    • core: improve validation of wrong entity references (#3085) (f5de135)
    • core: wrap relations in Reference wrapper when assigning entity instance (97f1f59), closes #3092
    • mongo: support queries with mongo specific operators on embeddables (2fb9002)
    • postgres: do not try to create schema for migrations when it exists (d6af811), closes #3106
    • postgres: fix resolving knex when other version is explicitly installed (41f5665), closes #3129
    • postgres: ignore schemas prefixed with crdb_ too (049fea3), closes #3021
    • schema: always ignore PostGIS schemas when diffing (#3096) (626e3db)
    • ts-morph: do not mark properties as enums automatically based on type (c3923df), closes #3099

    Features

    • core: add strict option to em.findOneOrFail() (#3088) (d38242a)
    • postgres: allow ignoring specified schemas (3f1d2da)
    Source code(tar.gz)
    Source code(zip)
  • v5.1.3(Apr 27, 2022)

    5.1.3 (2022-04-27)

    Bug Fixes

    • core: allow replacing target entity in relations with assign (90ec83f), closes #3026
    • core: do not inline query for JSON properties that match PK names (e6005d8), closes #3054
    • core: fix serialization when using partial loading for nested relations (00be9f1), closes #3011
    • core: hydrate nullable embedded properties as null (e8490f6), closes #3063
    • core: respect mapToPk when expanding properties (#3031) (757801e)
    • core: try to fix FK order automatically for custom pivot entities (cc9e427), closes #3040
    • mongo: fix ensuring indexes with polymorphic embeddables (aa5e4d2), closes #3013
    • postgres: allow using special characters in string arrays (366da5f), closes #3037
    • postgres: ensure schema exists before creating migrations table (f211813), closes #3039
    • schema: fix diffing of indexes with too long inferred name (01ba9ed), closes #2932
    • schema: remove FKs first when trying to dropSchema without disabled FKs (b1b5f55), closes #3004
    • seeder: explicitly flush forks when calling Seeder.call() (c8ece7c), closes #2998
    • seeder: fix type of Factory methods (#3064) (06e88e7)
    • sqlite: fix reflection of tables with FKs (389bc0d), closes #2959
    • sqlite: upgrade knex to v2 + switch back to sqlite3 (f3e4b9d), closes #3046

    Features

    • core: validate decorator parameters are used properly (cb3e1dd), closes #3040
    • seeder: created shared context when calling other seeders (6fa04ae), closes #3022

    Performance Improvements

    • core: do not use contextual EM where we know we are in a fork already (ba16532)
    Source code(tar.gz)
    Source code(zip)
  • v5.1.2(Apr 10, 2022)

    5.1.2 (2022-04-10)

    Bug Fixes

    • core: allow converting custom types via em.nativeInsert() (#2979) (8d76852)
    • core: do not clean up UoW before each "flush step" (3ae732d), closes #2934
    • core: do not quote knex.raw() instances returned from custom types (8a4c836), closes #1841
    • core: fix eager loading of nested embeddable m:1 properties (4867db9), closes #2975
    • core: fix eager loading when multiple relations target same entity (21922ce), closes #2990
    • core: fix mapping of inserted PKs with custom field names from batch insert (080d8e0), closes #2977
    • core: never reassign the same entity via em.assign() (cdfbabd), closes #2974
    • core: propagate entity removal in em.transactional() to upper context (6e5166b), closes #2973
    • core: respect connectionType in populate queries (fe40a9f), closes #2994
    • core: support PopulateHint.INFER with pagination and joined strategy (56f8737), closes #2985
    • core: use correct path for relations inside embeddables with populate: true (4735dba), closes #2948
    • postgres: do not ignore custom PK constraint names (#2931) (24bf10e)
    • postgres: drop enum constraints only when the column was an enum (76fef39)
    • postgres: ensure correct column order in compound index/uniques (321be79), closes #2932
    • postgres: fix pagination with order by bool column (d5476cd), closes #2910
    • postgres: fix schema diffing on enums with case-sensitive names (050875b), closes #2938 #2932
    • schema: do not create FK index for 1:1 properties (they are unique already) (473795c), closes #2942

    Features

    • mariadb: implement check constraint support + fix json column diffing (b513b16), closes #2151
    • schema: support mysql 8 (#2961) (acc960e)
    Source code(tar.gz)
    Source code(zip)
  • v5.1.1(Mar 20, 2022)

    5.1.1 (2022-03-20)

    Bug Fixes

    • core: fix custom pivot table entities for unidirectional relations (01bdbf6)
    • knex: order by with a formula field should not include as for sub-queries (#2929) (74751fb)
    • postgres: allow explicit schema name in prop.pivotTable (1860ff5), closes #2919
    • postgres: fix pagination with order by UUID PK (042626c), closes #2910
    • postgres: respect known schema when loading wild card entity relations (61d1e85), closes #2909
    • schema: respect disableForeignKeys in schema generator (f1b8e46), closes #2912

    Features

    • core: validate em.begin was called when using em.commit/rollback (67fa076), closes #2918
    Source code(tar.gz)
    Source code(zip)
  • v5.1.0(Mar 13, 2022)

    5.1.0 (2022-03-13)

    Bug Fixes

    • core: do not alias JSON conditions on update/delete queries (5c0674e), closes #2839
    • core: ensure all entities from inner context are merged to the upper one (7b3a6b4), closes #2882
    • core: fix object key utilities for null prototype objects (#2847) (b2cf01e), closes #2846
    • core: fix ordering by complex composite PKs (dde11d3), closes #2886
    • core: fix strict type for orderBy when entity has length property (ef45871), closes #2829
    • core: type global entityRepository option weakly (3faf8bc)
    • knex: order by with a formula field should not include as (#2848) (09e8bfa)
    • knex: fully qualify sub-query order-by fields (#2835) (f74dc73)
    • mysql: mark FK columns as unsigned for mixed composite PKs (67806cb), closes #2844
    • postgres: respect schema name in migration storage (fbf9bfa), closes #2828

    Features

    • core: allow better control over connection type when using read-replicas (#2896) (e40ae2d)
    • core: allow specifying custom pivot table entity (#2901) (8237d16)
    • core: allow using hooks for interface entities (#2895) (aee99b1)
    • core: enable QueryFlag.PAGINATE automatically for em.find() (ccb4223), closes #2867
    • core: map check constraint failures to specific error type (ebcbdff), closes #2836
    Source code(tar.gz)
    Source code(zip)
  • v5.0.5(Feb 27, 2022)

  • v5.0.4(Feb 22, 2022)

    5.0.4 (2022-02-22)

    Bug Fixes

    • core: always create new entities as initialized (bbb30c5)
    • core: fix mapping default values of relation properties (bc57ed0)
    • core: fix propagation of FK as PK with not flushed entity (25be857), closes #2810
    • core: fix unsetting identity of orphans (1:1 with orphan removal) (91e7315), closes #2806
    • core: respect schema from config when adding new entities to context (7a6b6e2)
    • core: respect load strategy specified in property definition (1a6b4b2), closes #2803
    • entity-generator: fix property names for columns with dashes (#2813) (c920d5f)
    • schema: escape table/column comments (fff1581), closes #2805
    Source code(tar.gz)
    Source code(zip)
  • v5.0.3(Feb 20, 2022)

    5.0.3 (2022-02-20)

    Bug Fixes

    • core: do not trigger global context validation from repositories (f651865), closes #2778
    • core: fix processing of onUpdate properties (9cf454e), closes #2781
    • core: fix processing of multiple onUpdate properties on one entity (4f0e4cc), closes #2784
    • core: hydrate not-null embeddable prop even with all null values (09aee05), closes #2774
    • core: register entity to identity map as early as possible (d8f3613), closes #2777
    • core: respect onDelete: cascade when propagating removal (f1e8578), closes #2703
    • core: revert to require() when getting ORM version to fix webpack support (6cfb526), closes #2799
    • migrations: generate snapshot too when using --initial (4857be7), closes #2800
    • postgres: consider int8 as numeric when inferring autoincrement value (64bc99d), closes #2791
    • sqlite: respect autoincrement: false in schema diffing (b39b6ad), closes #2800
    • typing: fix populate hints on collections where both type args are provided (e39ef5b), closes #2771

    Features

    • add better-sqlite driver (#2792) (1b39d66)
    • core: add connect config option (8aaad33)
    • core: add SchemaGenerator.clearDatabase() (ecad9c6), closes #2220
    • core: add populate option to Reference.load and Collection.loadItems (1527c1a), closes #2796
    Source code(tar.gz)
    Source code(zip)
  • v5.0.2(Feb 16, 2022)

    5.0.2 (2022-02-16)

    Bug Fixes

    • core: allow passing entity instance in repo.nativeInsert() (791c009)
    • core: do not ignore schema name from config in em.getReference() (58680fc)
    • core: do not ignore schema name in batch queries (b47393e)
    • core: do not ignore schema name in collection updates (d688dc1)
    • core: do not ignore value from database even if we only have a getter (35103b3), closes #2760
    • core: respect global schema (b569686)
    • postgres: do not ignore custom PK constraint names (3201ef7), closes #2762
    • seeder: declare missing dependency on globby (0599032)
    • typing: remove overloads for em.nativeInsert() (e21d470)
    Source code(tar.gz)
    Source code(zip)
  • v5.0.1(Feb 13, 2022)

    5.0.1 (2022-02-13)

    Bug Fixes

    • core: allow cloning QB with raw conditions (04d9d88), closes #2748
    • core: allow using 0 as PK (a2e423c), closes #2729
    • core: do not propagate removal to FK as PK (a0a19c2), closes #2723
    • core: fix support for complex composite (nested) PKs (a7fc7a1), closes #2647
    • core: ignore ORM packages where we failed to extract version (b1627c5), closes #2732
    • core: respect null in Loaded type (72385b3), closes #2750
    • core: return entity type from em.create() instead of New<T> (8ff277d), closes #2727
    • core: support special characters in clientUrl (43e28b8), closes #2730
    • core: use createRequire instead of dynamic import for JSON files (f567d2d), closes #2738
    • embeddables: fix loading inline embeddables with joined strategy (adaa5c6), closes #2717
    • esm: fix getting ORM version on windows with ESM (eb3a1be)
    • mongo: fix caching populated results in mongo (42ea5be), closes #2754
    • query-builder: respect explicit entity schema (717aa5e), closes #2740
    • schema: fix explicit schema name support (#2752) (68631ea)
    • seeder: fix Factory type for entity with constructor params (#2745) (8b7b977)
    • typing: exclude symbols and functions from FilterQuery (1d24eb8), closes #2742

    Features

    • core: add getContext parameter to @UseRequestContext() (9516b48), closes #2721
    • query-builder: allow autocomplete on qb.orderBy() (fdf03c3), closes #2747
    • schema: ensure database when calling refreshDatabase() (7ce12d6)
    • seeder: refactor seeder to support running compiled files (#2751) (8d9c4c0), closes #2728
    Source code(tar.gz)
    Source code(zip)
Owner
MikroORM
MikroORM TypeScript ORM for Node.js based on data-mapper, unit-of-work and identity-map patterns.
MikroORM
Next-generation ORM for Node.js & TypeScript | PostgreSQL, MySQL, MariaDB, SQL Server & SQLite

Prisma Quickstart • Website • Docs • Examples • Blog • Slack • Twitter • Prisma 1 What is Prisma? Prisma is a next-generation ORM that consists of the

Prisma 28k Jan 2, 2023
A Node.js ORM for MySQL, SQLite, PostgreSQL, MongoDB, GitHub and serverless service like Deta, InspireCloud, CloudBase, LeanCloud.

Dittorm A Node.js ORM for MySQL, SQLite, PostgreSQL, MongoDB, GitHub and serverless service like Deta, InspireCloud, CloudBase, LeanCloud. Installatio

Waline 21 Dec 25, 2022
Database manager for MySQL, PostgreSQL, SQL Server, MongoDB, SQLite and others. Runs under Windows, Linux, Mac or as web application

Database manager for MySQL, PostgreSQL, SQL Server, MongoDB, SQLite and others. Runs under Windows, Linux, Mac or as web application

DbGate 2k Dec 30, 2022
A simple Node.js ORM for PostgreSQL, MySQL and SQLite3 built on top of Knex.js

bookshelf.js Bookshelf is a JavaScript ORM for Node.js, built on the Knex SQL query builder. It features both Promise-based and traditional callback i

Bookshelf.js 6.3k Jan 2, 2023
An adapter-based ORM for Node.js with support for mysql, mongo, postgres, mssql (SQL Server), and more

Waterline is a next-generation storage and retrieval engine, and the default ORM used in the Sails framework. It provides a uniform API for accessing

Balderdash 5.4k Jan 4, 2023
Explore, create and deploy your SQLite databases right from your browser. Quick and easy, no installation required.

SQLighter (under development, alpha code) SQLighter is a database explorer born for SQLite that helps you design and deploy your application database

sqlighter 11 Sep 20, 2022
just a graphql example created by typescript + fastify + mikro-orm(postgresql) + mercurius(graphql adaptor) + type-graphql

fastify-mikro-orm-mercurius-graphql-example A MikroORM boilerplate for GraphQL made with Fastify, Mercurius, Typescript using TypeGraphQL ?? Packages

Vigen 10 Aug 28, 2022
Ecommerce-backend-nestjs - Ecommerce app with Nestjs + Prisma ORM + GraphQL + SQLite

ECOMMERCE BACKEND NESTJS APP Nestjs + Prisma ORM + GraphQL + SQLite USER Create Account Login Product Create Product Get Products Get Product Search P

Rui Paulo Calei 5 Apr 6, 2022
This is a demo sample of linking NODEJS via ORM and MYSQL

Demons(Demo of Nodejs with SQL) This is a demo sample of linking NODEJS with ORM and MYSQL Connecting Node to SQL is a hard task and not much help is

Shivam Sourav Jha 3 Apr 14, 2022
A high performance MongoDB ORM for Node.js

Iridium A High Performance, IDE Friendly ODM for MongoDB Iridium is designed to offer a high performance, easy to use and above all, editor friendly O

Sierra Softworks 570 Dec 14, 2022
A remote nodejs Cached sqlite Database Server, for you to have your perfect MAP Cache Saved and useable remotely.

A remote nodejs Cached sqlite Database Server, for you to have your perfect MAP Cache Saved and useable remotely. Easy Server and Client Creations, fast, stores the Cache before stopping and restores it again! it uses ENMAP

Tomato6966 6 Dec 18, 2022
A query builder for PostgreSQL, MySQL and SQLite3, designed to be flexible, portable, and fun to use.

knex.js A SQL query builder that is flexible, portable, and fun to use! A batteries-included, multi-dialect (MSSQL, MySQL, PostgreSQL, SQLite3, Oracle

knex 16.9k Jan 4, 2023
Ultimate Script to complete PostgreSQL-to-PostgreSQL Migration right after AWS DMS task done

Ultimate Script to complete PostgreSQL-to-PostgreSQL Migration right after AWS DMS task done

방신우 22 Dec 23, 2022
The Blog system developed by nest.js based on node.js and the database orm used typeorm, the development language used TypeScript

考拉的 Nest 实战学习系列 readme 中有很多要说的,今天刚开源还没来及更新,晚些慢慢写,其实本人最近半年多没怎么写后端代码,主要在做低代码和中台么内容,操作的也不是原生数据库而是元数据Meta,文中的原生数据库操作也当作复习下,数据库的操作为了同时适合前端和Node开发小伙伴,所以并不是很

程序员成长指北 148 Dec 22, 2022
A typescript data mapping tool. To support mutual transforming between domain model and orm entity.

ts-data-mapper A typescript mapping tool supports mutual transforming between domain model and orm entity. In most case, domain model is not fully com

zed 8 Mar 26, 2022
Adapter based JavaScript ORM for Node.js and the browser

firenze.js A database agnostic adapter-based object relational mapper (ORM) targetting node.js and the browser. Visit http://firenze.js.org for docume

Fahad Heylaal 130 Jul 14, 2022
TypeScript clients for databases that prevent SQL Injection

Safe From HTML Injection Using tagged template literals for queries, e.g. db.query(sql`SELECT * FROM users WHERE id=${userID}`); makes it virtually im

Forbes Lindesay 478 Dec 21, 2022
MongoDB object modeling designed to work in an asynchronous environment.

Mongoose Mongoose is a MongoDB object modeling tool designed to work in an asynchronous environment. Mongoose supports both promises and callbacks. Do

Automattic 25.2k Dec 30, 2022