23 comments

[ 3.5 ms ] story [ 63.2 ms ] thread
I've also torn it up with MikroORM this weekend. I figured I'd give my 2¢ review of ORMs in NodeJS.

MikroORM: is maintained, with a lead developer who is receptive to feedback, checks issues and responds. It's also built around the unit-of-work pattern. Unfortunately, there are some bugs – and having looked at the lack and quality of tests, this is unsurprising. Also, look at my note on type-native at the end. Ultimately, I left the weekend with the following thoughts:

1) is using an ORM in NodeJS even worth it or should I just go a level higher to Knex?

2) how smart is it to adopt a framework that may go unmaintained in the future, and is already big enough (in complexity) with a lack of quality tests and promising-but-incomplete docs? am I pointing a gun at my foot?

3) if I were going to go with an ORM in TypeScript today, this would be it. I hope that download numbers will increase, the community will get larger, and the product will continue to advance. The owner cares, but I don't think he can get there on his own.

Non-MikroORM / Community: Many of the ORMs are abandoned – this includes TypeORM, or aren't type-native [f1]. TypeORM was promising (I guess), but I'm really reluctant to work with it on even the most basic tasks. That the documentation is out of date, the issues are unresolved, and maintenance is lacking make this a no-go for me.

p.s. I do sorely miss SQLAlchemy (thanks zzzeek for those good times) when working with DBs in NodeJS.

[f1] type-native: this is actually a double edged sword. The ORM is never going to have type-parity with the underlying DB. So, you really shouldn't invest in building your "schemas" or "migration files" from type metadata. And you'll also only ever be able to type the most basic queries. I'm concerned MikroORM has gone too far down this path.

What do you think about Prisma? It has typescript support.
It does have TS support. It definitely seems pretty interesting, but there are a few reasons I wasn't ready to move on it:

1) schema generation problems (e.g. it'll rename your associations)

2) I'm reluctant to believe that I don't actually want a real query-builder beneath the ORM. (https://www.prisma.io/docs/understand-prisma/why-prisma#sql-...)

3) transaction support is experimental, and it's not /really/ what app developers mean when they say "transaction". (https://www.prisma.io/docs/reference/tools-and-interfaces/pr...)

I think something like this might be nice as it evolves. But, I think they're taking over too much of the stack (e.g. with inner Rust bindings, and not really exposing the power-APIs) whereas with something like MikroORM you can access the underlying query builder (knex).

Thanks for sharing your thoughts. Daniel from the Prisma team here.

regarding 1: Can you share more about schema generation problems? Are you using introspection to create the Prisma schema? If so, we're actively working to improve this flow with "re-introspection": https://github.com/prisma/prisma/issues/2829

Regarding 3: Prisma supports transactions with nested writes and it's stable (https://www.prisma.io/docs/reference/tools-and-interfaces/pr...).

The new experimental transaction API pushes the idea of transactions further by combining multiple individual Prisma Client calls into a transaction.

Long running transactions are indeed not supported. Long-running transactions require holding a stateful connection open between two components for an extended period of time which can be at odds with the way modern scalable systems are built.

Perhaps you can share more what you/app developers mean by transaction?

Hey dude!

1) schema-generation: uh, I can't find the video anymore! But basically (https://www.prisma.io/docs/reference/tools-and-interfaces/pr...) when you re-generate your schema, FK relationships names would be reset, and you'd have to go back through and manually re-update them. (think user.favorite_book would be changed to user.book). Jeeze, I wish I could find the video for that.

3) perhaps I just don't have a good enough understanding of that system to think through it's pitfalls. You guys obviously understand which workflows you cover well through /that/ approach to transactions. Might be good to see which sorts of strategies (won't work). For example, what if I want to `flush` my changes, and `rollback` or use a `savepoint` elsewhere. It seems like everything is in the context of one call. Is that correct?

1) Prisma supports two workflows depending on whether you already have an existing database (introspection) or using Prisma Migrate. It sounds based on your description like something that would happen in the introspection workflow which this "re-introspection" feature resolves by retaining name mapping of relation fields.

3)

> For example, what if I want to `flush` my changes, and `rollback` or use a `savepoint` elsewhere.

That's not possible.

> It seems like everything is in the context of one call. Is that correct?

Not exactly, as you can batch multiple calls into one transaction guaranteeing that either all get committed or none. (https://www.prisma.io/docs/reference/tools-and-interfaces/pr...)

I went through the same thoughts as you and went straight to knex for my last project. Turns out knex also has bugs and the limitations from having it support all the databases means some really useful features are not available.

For my latest project I've gone with pg, writing sql directly, and I'm not looking back. It's so nice not having to write sql through the abstraction layer of knex.

Of course if you think you'll swap your database provider down the line, maybe stay with knex. But I really can't see why I'd want to switch away from postgres at a later date.

Have you looked at Hasura?

For some of my latest dev, I've just stopped worrying about writing data plumbing. I have a tool that I can use to update the schema from any arbitrary state to any arbitrary state so long as there are no column modifications, and then Hasura is able to query my entire schema via GraphQL.

You also get row, column, & table-level permissions, an easy auth hook, and the promise of schema stitching (which I must admit I haven't used yet, so I don't know if it's easy or performant).

I can't really speak to performance, but I think the Hasura guys did their best to use Postgres' internals wherever possible. Try it out!

Also, a similar tool is "Xgenecloud", but I didn't like it as much and have only invested time into Hasura.

hey, XgeneCloud creator here. How can we improve ? which parts you didn't like
I don't have great feedback for you, it's just that I downloaded and ran xgenecloud and was exceedingly confused what to do from the UI that it spawned. It didn't seem clear to me how I could get started, and my options were plentiful; I would've been ok to make a new database thru your UI, point your tool at an existing database, or anything else, but I just didn't have a clear path to querying a schema.

With Hasura, I could run it with about 2 docker commands and build a schema thru their web UI, use GraphiQL in their web UI to query the schema, and read docs to get a clear path on how I might use this artifact in production.

I guess I would just use Hasura if I was you and see what the experience is like vs XgeneCloud, maybe it will show you what I saw.

I hear you - thank you for the feedback. I've got similar feedback from devs who are liking XgeneCloud as well. We are in really early days of our journey - I promise to improve this flow by many folds.

The way it currently works is :

* Each new project has a folder in your filesystem where GraphQL API source code is generated on pointing to database! So when we generate APIs, we also generate source code for those APIs (node.js/express.js) behind the scenes. This is a big leap on how easy it becomes to customise APIs or put some business logic in them

* Thereafter, as and when a developer changes schema (add table, add column etc) - the underlying GraphQL code also gets updated automatically.

Here is a demo of generating GraphQL on postgres & GUI based schema design:

https://youtu.be/QEq3Mjbeelg

https://youtu.be/ETEEcY4mmEg

Feel to free reach out on twitter/Discord (in profile). Happy to help you get started.

edit: sentence corrections

We are using

ts + apollo-server-koa + dataloader (caching) + knex + graphql-codegen + schemats (for types generated from postgres)

It works great. We only have issues with gql resolver types, when resolver expects a string, but in reality, resolver can be a function that returns a string

This is completely valid

  export const resolver: Place = {
    id: ({ id }: GeneratedDb.Place) => toGlobalId(TYPE,  String(id)),
But typings expect

  export const resolver: Place = {
    id: 'xxx',
is typeorm really abandoned though? I've been playing with rc3.0.0 recently... I'm having fun using it with GraphQL Modules and TypeGraphQL

The docs are pretty decent too!

Oh, you must be using `0.3.0-rc.19` not 3.0.0. (https://www.npmjs.com/package/typeorm)

The one that was released 5 months ago. Look at the velocity of releases, and you'll come to the conclusion many others have.

Also, take a look at the pinned issue for the 0.4.0 release (from Dec, 2018), with no updates, here: https://github.com/typeorm/typeorm/issues/3251

Or, the "future of TypeORM" issue (also from Dec, 2018) here: https://github.com/typeorm/typeorm/issues/3267

I'm not upset by any of this. That's just the reality of OSS. I really appreciate the foundation TypeORM provided. But, I think it's role will probably be as a sort of "godfather" for the ORM ecosystem in TS rather than a leader – going foward.

TypeORM's velocity and/or lack of a 1.0 release is troubling. I've been trying to push nest recently to gain some consistency vs wild-west express apps, but TypeORM has been the rough spot. I can see the appeal of using something like the pg driver directly, but then there's all that data mapping.
This is pretty good though > pleerock commented 25 days ago I would like to ask not to spam here. Thank you. If somebody prefer some alternative - try it, maybe it can better fit your needs. Nothing is perfect and there are always set cons and pros from every project you will use. Open source always lack of accountability, and if you are using some tool, try to support it if you can, because any author can end up switching to something else. It's just matter of time, or your support. So, try to support your favorite tools, no matter if thats TypeORM or MicroORM.

Thank you for all your suggestions and support. I find many really good suggestions here, but the reason I don't implement them is because right now I'm able to implement only some of them, others would take too much time and efforts to do. But I think it wouldn't take a good effect to only implement some of them. That's why I'm waiting for a right time.

I just want to tell you that I already do have enough money to maintain this library for around 6 months without working on something else. So, I still plan to return back to it and put all my efforts to move it forward and apply all suggestions you have provided. I just need some time, because I took a big project under my responsibility and I can't leave until it's finished. Thanks for understanding. Right now I do my best (considering my business and health) to release new TypeORM versions very month or two to keep it updated with the most critical fixe

What bugs did you run into with MikroORM? It looks like there are only two open issues that are classified as bugs on their issue tracker (github).
Ha. Well, one of 'em was just fixed. https://github.com/mikro-orm/mikro-orm/issues/725

There's also a known issue where an insert statement with an `undefined` for a field (rather than the lack of a presence) translates to a null (this is actually a `pg` driver situation). https://github.com/mikro-orm/mikro-orm/issues/719

Finally, the docs have entities which use TypeScript's `optional` indicator (e.g. `image?: string`).

Problem is, that reflects the state of an entity pre-creation. After creation it's going to be `null`, which will definitely escape the type system (you've got strict null checks on in TS, right?).

However, typing that same column as `image: string | null` actually produces a `columnType` of JSONB(?) rather than `STRING NULL`.

That's a couple examples, but yeah. I invested some heavy hours into the codebase this weekend.

I remember resorting to using typeorm's queryrunner.query writing SQL by hand quite a few times. Eventually I figured I'll just get really good at SQL. Haven't tried it but MikroORM has been on my list of tools to try out. Hoping its good.
(comment deleted)
Currently using TypeORM in a production system, has caused us so many issues to be honest highly recommend everyone avoiding.

IMO they’ve added every feature under the sun but not bothered on focusing on quality, some things just don’t work at all, or you get stuck with horrific performance issues. If we weren’t so far down the line with it I’d rip the whole thing out although it’s causing so much pain I might just bite the bullet and do it anyways

I did see MikroORM the other day and looked promising so cheers for the quick review, if anyone else has any recommendations would be good to hear!

Looking through the docs it looks kind of like EntityFramework, which may or may not be a good thing depending on your use case.

My goto for nodejs is still sequelize but without typescript...

I’m loving zapatos now.

Although not an ORM, it fits my needs.