Show HN: Node.js ORM to query SQL database through an array-like API

tilyupo | 123 points

My take on this is that it's not always the best idea to abstract-out SQL. You see, the SQL itself is too valuable abstraction, and also a very "wide" one. Any attempt to hide it behind another abstraction layer will face these problems:

- need to learn secondary API which still doesn't cover the whole scope of SQL

- abstraction which is guaranteed to leak, because any time you'll need to optimize - you'll need to start reason in terms of SQL and try to force the ORM produce SQL you need.

- performance

- deceptive simplicity, when it's super-easy to start on simple examples, but it's getting increasingly hard as you go. But at the point you realize it doesn't work (well) - you already produced tons of code which business will disallow you to simply rewrite

(knowledge based on my own hard experiences)

xonix | 11 days ago

Nice, looks promising. How does this compare to drizzle?

Context:

We've had a lot of ORM frameworks come and go in node.js - sequelize, typeorm etc, but none of them have really caught on.

Things have been changing a lot lately after typescript took over, so we've seen a bunch of ORMs take off that give you a really good typescript experience.

So, the juggernaut in this space is of course prisma, which is super expressive and over all pretty decent - it comes with its own way to define schemas, migrations etc .. so that might not be everybody's cup of tea. (and then there's the larger runtime, that have lambda-users complaining - though that has mostly been addressed now where the binary is much smaller)

So despite it being a pretty opinionated framework really, what it gives you are really rich typescript integrated queries. And all in all it works pretty well - i've been using it at work for about 3 years and I'm just really pleased with it for the most part.

The newcomer in the space that's gaining a lot of traction is Drizzle - where it's mostly a way to define tables and queries - it also gives you really rich typed queries - and it happens all in TS/JS land.

this project of yours reminds of drizzle - kind of similar in a lot of ways.

I'm super interested to understand how this compares to drizzle and which problems with drizzle this attempts to solve

arnorhs | 11 days ago

Now that we have about 15 years of ORMs, do they really make things easier?

SQL is not a difficult language to learn, and views and stored procedures provide a stable interface that decouples the underlying table schema, allowing for migrations and refactoring of the database structure without having to rewrite a lot of code.

ORMs seem to me to be mostly about syntactic sugar nowadays; I’m worried that the abstractions that they set up insulate the developer from the reality of the system they’re depending on - like any abstraction, they probably work fine right to the very point they don’t work at all.

I’m not complaining about this project; it looks cool and I can see the attraction of staying in a single language paradigm, but I am very wary of abstractions, especially those that hide complex systems behind them.

efitz | 11 days ago

Cool project!

Looking at the docs, for example the pg connector, I couldn't easily find information about how it parameterizes the queries built through method chaining.

For example, if I run

   .filter(user => user.name.eq(unsanitizedInput))
I am presuming that the unsanitizedInput will be put into a parameter? For me, using ORMs on a team that may include juniors, that is one of the key things an ORM provides: the ability to know for sure that a query is immune to SQL injection.

If you had more examples on the connectors of queries like this, and also maybe some larger ones, with the resulting SQL output, I think that might increase adoption.

sigseg1v | 11 days ago

Very nice! Almost everyone I know misses Entityframework if they ever worked with it and similar ergonomic ways in other languages (clojure/cl). Entityframework has it's downsides, but it's so nice to develop with. I don't mind (and often use SQL), in fact, since no longer using C#, I find myself using SQL more often than ORMs as everything is so ... clumsy... compared to entityframework.

Continue doing the excellent work please!

anonzzzies | 11 days ago

An intriguing idea! I like this approach for being an innovative interface to SQL. I wonder if it would reduce cognitive load when interfacing with the DB.

I'm a game dev and often need to avoid situations where I'm using '.map' to iterate an entire array, for performance reasons. It would feel odd to use the concept, knowing it wasn't really iterating and/or was using an index. Is that how it works?

EarthLaunch | 11 days ago

I love your syntax for joins and unions!

A bit puzzled by why the connector slots into the query, instead of the query slotting into the connector, given that it’s the connector that’s actually doing the work. I.e. ‘connector.fetch(query)‘ … rather than… ‘query.fetch(connector)‘

Eric_WVGG | 11 days ago

It is dope, please continue on this.

I used to work with TypeORM and really missed using EntityFramework. That actually led me to switch to Mongo (Mongoose).

I'm really looking forward to this project!

v_b | 11 days ago

I never use orms and don’t find them appealing, but one thing I do with my sqls may interest you.

I always wrap .query(…) or simply pass its result to a set of quantifiers: .all(), .one(), .opt(), run(), count(). These assert there’s 0+, 1, 0-1, 0, 0 rows.

This is useful to control singletons (and nonetons), otherwise you end up check-throwing every other sql line. One/opt de-array results automatically from T[] to T and T | undefined. Count returns a number.

Sometimes I add many() which means 1+, but that’s rare in practice, cause sqls that return 1+ are semantically non-singleton related but business logic related, so explicit check is better.

I also thought about .{run,count}([max,[min]]) sometimes to limit destructiveness of unbounded updates and deletes, but never implemented that in real projects.

Maybe there’s a better way but I’m fine with this one.

Edit: messed up paragraphs on my phone, now it’s ok

wruza | 10 days ago

This is a really cool project, but I'm not sure I like some of the APIs.

`orderByDesc` seems like it could be better suited for an object constant indicating the sort direction.

``` orderBy(OrderBy.Desc, user => user.age) ```

Overall still very nice and looking forward to seeing more development!

richwater | 11 days ago

Why are we trying so hard to pretend the database is something else?

I've had more success modelling database concepts directly in the language; tables, columns, keys, indexes, queries, records etc.

https://github.com/codr7/hostr/tree/main/src/Hostr/DB

codr7 | 8 days ago

Oh, that’s Entity Framework but in typescript ?

pjerem | 11 days ago

This is like the lambda / Linq on .NET. Well done. Take a look at PRQL too. You may enjoy it, it may even help you simplify query transformations to sql.

tehlike | 10 days ago

Thanks for this. While I have no problem with SQL, I enjoy the type checking, autocomplete, and 'compilation' this TS syntax gives you. Please continue!

gedy | 11 days ago

It looks like this isn't really an ORM, it's more like a node-based layer to simplify DB access.

Which I actually like more, because I want to understand the database, not abstract it away. But dealing with SQL is/can be awkward. This library means I don't have to dynamically build sql queries in code.

Handy!

mannyv | 9 days ago

A while back I wanted to do a project in NodeJS to refresh my JS skills a bit, wanted to find a nice ORM similar to EF because I use it so frequently but unfortunately didn't come across anything.

Ended up using drizzle and just hated every moment of it. This is definitely going in the "Use this eventually" folder!

gsck | 10 days ago

I might have missed it but I would like to see what the return types look like, and how type safe they are. The query interface is interesting, I'm not sure I'm sold but if I don't know how to use the result then I'm not going to adopt it.

ericyd | 11 days ago

Pretty cool! The only thing I didn't like in the examples were things like .eq and .add, which are kind of a DSL, so it takes away from the "just plain JS" approach. But I assume it's because JS doesn't allow operator overloading?

brap | 11 days ago

I am not sure I am understanding array-like in this context?

It seems to be more like knex or https://kysely.dev/

bearjaws | 11 days ago

This looks really nice. It's not so much an ORM as a embedded DSL for SQL. The raw SQL with the tagged template literal is quite nice too.

spankalee | 10 days ago

Just like we did HTML in JS via JSX or lit html, I wonder if we should have better SQL in JS that way.

atishay811 | 10 days ago

Qustar sounds nice, I would think "Exact" is what it is.

todotask | 11 days ago

So basically like entity framework & LINQ in the C# world

but for nodejs

jdthedisciple | 10 days ago

Very cool. Reminds me of linq to sql

arrty88 | 11 days ago

"Codegen free"

why is codegen bad?

EGreg | 11 days ago

can i suggest saying “iterator api” instead of array-like?

marcelr | 11 days ago

> array-like API

why is this arbitrary property desirable?

nsonha | 11 days ago

The API doesn’t really look “array-like”.

layer8 | 11 days ago

I've come to the conclusion that ORMs are good for simple queries like User.find_by(email: "john@snow.com"), but once you get beyond that you are better off just writing sql.

fourseventy | 11 days ago

Scala has a library called Slick which takes a similar approach: https://scala-slick.org

The DSL is nice for simple querying and for composing queries based upon user input. But, for anything slightly complex, I found it's better to just use regular SQL.

khy | 11 days ago

[dead]

FutureCrafter | 7 days ago

[flagged]

thr0w | 11 days ago

[flagged]

matt-p | 11 days ago

[flagged]

_1 | 11 days ago

[flagged]

wredcoll | 11 days ago