Live data from Hacker News

Litdb – type safe SQL for JavaScript/TS

litdb.dev

41–50 of 70 posts

Re: Litdb – type safe SQL for JavaScript/TS

#41
post #39
post #36

This looks great. But in my view there's still some scope for improvement in expressive-ness (compared to something like LINQ). A future area of exploration could be to add a parser to the mix, so that we can write: const jane = db.contacts.one(c => c.email === janeEmail); instead of: const jane = db.one ($.from(Contact).where(c => $`${c.email} = ${janeEmail}`))! The former is so naturally typesafe, without having to…

That won't be possible without a lot of work. You'll need to tweak the TypeScript compiler to make the parser comprehend exported variables. For example, import { contacts } from "db" const jane = contacts.one(c => c.email === janeEmail) Marco-like magic can be confusing, as we learned from Svelte. Especially when it's half-baked like the one you are suggesting. Another drawback is that you'll need to compile the cod…

> Marco-like magic can be confusing, as we learned from Svelte. Especially when it's half-baked like the one you are suggesting.

When I'm giving examples on a forum thread, I try to provide one that's simpler to understand and captures the essence of the argument. I am not making any claims on completeness.

> Marco-like magic can be confusing, as we learned from Svelte. Especially when it's half-baked like the one you are suggesting.

Svelte invents new syntax, which in my view isn't great. This is pure JS, and it could even run in a browser against arrays (for tables).

Add:

> That won't be possible without a lot of work. You'll need to tweak the TypeScript compiler to make the parser comprehend exported variables.

Not required. I was suggesting that the expression could be parsed at runtime. There are various options, with different tradeoffs.

Re: Litdb – type safe SQL for JavaScript/TS

#42
post #40
post #38

Earlier quoted context omitted.

It's an intentional decision that drivers are decoupled from the Application and query builder it executes, i.e. all driver APIs provide different ways of executing SQL + Params or a function that returns SQL + Params (Query Builder). This allows drivers to remain flexible to executing (non-litdb) SQL/Params or Query builders from a different library. Your proposed API would require augmenting the driver with an appl…

> It's an intentional decision that drivers are decoupled from the Application and query builder it executes, i.e. all driver APIs provide different ways of executing SQL + Params or a function that returns SQL + Params (Query Builder). This allows drivers to flexible to exec (non-litdb) SQL/Params or Query builders from a different library. But my suggestion doesn't couple the driver and the Application/query builde…

> The broad applicability of this approach has been proven to work by EF being the defacto DB access method in the .Net work (over 15 years now).

It's only the defacto DB access method in .NET because that's what Microsoft's EF library chose and .NET ecosystem just uses the default MS option but EF's influence doesn't extend outside of .NET. AFAIK no other .NET ORM does this including our .NET ORM [1] which litdb is the spiritual port of.

[1] https://docs.servicestack.net/ormlite/

Re: Litdb – type safe SQL for JavaScript/TS

#43
post #42
post #40

Earlier quoted context omitted.

> It's an intentional decision that drivers are decoupled from the Application and query builder it executes, i.e. all driver APIs provide different ways of executing SQL + Params or a function that returns SQL + Params (Query Builder). This allows drivers to flexible to exec (non-litdb) SQL/Params or Query builders from a different library. But my suggestion doesn't couple the driver and the Application/query builde…

> The broad applicability of this approach has been proven to work by EF being the defacto DB access method in the .Net work (over 15 years now). It's only the defacto DB access method in .NET because that's what Microsoft's EF library chose and .NET ecosystem just uses the default MS option but EF's influence doesn't extend outside of .NET. AFAIK no other .NET ORM does this including our .NET ORM [1] which litdb is…

The approach has more to do with C# the language, and the Code-as-Data principles it explored and executed well. I had seen various ORMs starting from the early 2000s (Hibernate etc), and when C# added Code-as-Data into the mix my jaw dropped. Like a bit of Lisp in a mainstream language, with mainstream applicability.

Nothing wrong with your approach, I was just arguing that language-native query patterns (such as customers.filter(c => c.country === "Chile")) can be appealing. And at the same time, reachable with current JS/TS tooling.

But like you said, it may not be the direction litdb wants to go.

Re: Litdb – type safe SQL for JavaScript/TS

#44

I'm sure a lot of effort went into this, but I would rather raw dog my database layer with node-postgres/postgres.js and zod. The decorator heavy implementation is visually very busy. Also, I would not consider any SQL toolkit for serious use unless it comes with a sufficiently competent code generation accompaniment.

Manual type declarations are error prone, tedious, and subject to drift. Meanwhile, query builders are clumsy and sometimes limiting or buggy, so I don't blame you for betting on raw SQL.

I'm building a middle ground of sorts. Raw SQL (or PL/pgSQL which can be quite powerful) with generated, type-safe client "bindings" (TypeScript functions). It also includes "declarative SQL schema" (instantly update the schema of your dev DB on file save). Generated migrations and "seed scripts" are also on the roadmap.

If any of that interests you, check it out (https://github.com/pg-nano/pg-nano). I would also love to discuss it with whoever's reading this on Discord (@aleclarson).

Re: Litdb – type safe SQL for JavaScript/TS

#45
post #26
post #24

Earlier quoted context omitted.

litdb does include support for registering TypeConverters for mapping custom RDBMS types [1]. The drivers doesn't include any converters for custom RDBMS-specific types yet, but you should be able to register your own in your App or even better submit a PR to the postgres driver [2] so it'll work OOB (tho it'll be dependent on whatever postgres.js can be configured to support). [1] https://litdb.dev/customize#type-co…

Correct me if I'm misunderstanding, but this would allow me to register the desired conversion type for a basic postgres type, to and from JavaScript but not for the return value of a specific function or even a specific invocation of a function. PostGIS uses a lot of functions like ST_AsEWKT, ST_AsMVT or ST_AsGeoJSON [1] to marshal data. While ST_AsGeoJSON will always return "text", ideally you'd want an invocation…

Hey, I'm developing a different approach that may appeal to a Kysely user such as yourself. I'd be glad to get your thoughts on it :)

Raw SQL (or PL/pgSQL which can be quite powerful) with generated, type-safe client "bindings" (TypeScript functions). It also includes "declarative SQL schema" (instantly update the schema of your dev DB on file save). Generated migrations and "seed scripts" are also on the roadmap.

If any of that interests you, check it out (https://github.com/pg-nano/pg-nano). I would also be happy to discuss it with you on Discord (@aleclarson).

Re: Litdb – type safe SQL for JavaScript/TS

#46
post #18

It seems like a step back to have to write SQL in Javascript syntax with a non-standard API. You can use real SQL and get type-safety just using typescript’s “… as MyType”. Of course it blows up if the database doesn’t match up, but so does this, I think. (Yes, you may want some mechanisms to validate the data has the expected form.)

You sound like someone who might be intrigued about what I'm building.

Raw SQL (or PL/pgSQL which can be quite powerful) with generated, type-safe client "bindings" (TypeScript functions). It also includes "declarative SQL schema" (instantly update the schema of your dev DB on file save). Generated migrations and "seed scripts" are also on the roadmap.

If any of that interests you, check it out (https://github.com/pg-nano/pg-nano). I would also love to discuss it with whoever's reading this on Discord (@aleclarson).

Re: Litdb – type safe SQL for JavaScript/TS

#47
post #16
post #10

Earlier quoted context omitted.

My feelings are similar and I cringe every time I see a "typesafe" db interface that doesn't run time validate the data.

typescript people want types on everything cuz it feels good that way.

Also it allows AI tools in IDEs like Cursor to work a lot more effectivley because they can leverage type/lint errors to make sure suggestions are correct on the first try.

Re: Litdb – type safe SQL for JavaScript/TS

#48
post #8
post #6

Seems very similar to [drizzle]( https://orm.drizzle.team/ ) - although drizzle is a more mature product.

From Drizzle's SQL-like example [1] by following classical SQL and including .select() first it wont to be able to provide type-safe queries. E.g. In litdb every from/join returns a new typed query builder where every reference is typed to a joined table that's included in the query. Drizzle also uses its own custom query language e.g. .where(eq(countries.id, 10)) Whereas litdb lets you use the full expressiveness of…

Does using template strings not compromise with type-safety? The drizzle example will be a compile time error for example if id wasn't a numeric column.

Seems a strange design choice for a library that claims to offer a type-safe sql builder.

Re: Litdb – type safe SQL for JavaScript/TS

#49
post #41
post #39

Earlier quoted context omitted.

That won't be possible without a lot of work. You'll need to tweak the TypeScript compiler to make the parser comprehend exported variables. For example, import { contacts } from "db" const jane = contacts.one(c => c.email === janeEmail) Marco-like magic can be confusing, as we learned from Svelte. Especially when it's half-baked like the one you are suggesting. Another drawback is that you'll need to compile the cod…

> Marco-like magic can be confusing, as we learned from Svelte. Especially when it's half-baked like the one you are suggesting. When I'm giving examples on a forum thread, I try to provide one that's simpler to understand and captures the essence of the argument. I am not making any claims on completeness. > Marco-like magic can be confusing, as we learned from Svelte. Especially when it's half-baked like the one yo…

> Not required. I was suggesting that the expression could be parsed at runtime. There are various options, with different tradeoffs.

Good idea. That might be possible, though not every JavaScript runtime implements Function.prototype.toString. I'm not sure if Node does.

  const aFunction = arg => arg.a === arg.b
  
  const aFunctionSrc = aFunction.toString()
  console.log(aFunctionSrc) // 'arg => arg.a === arg.b'

  const transformedFunctionSrc = transform(aFunctionSrc)
  const transformedFunction = new Function(transformedFunctionSrc)
  console.log(transformedFunction) // [Function: anonymous]
  
  // Cache the transformed function in a WeakMap
  // WeakMap values are garbage collected when their keys are garbage collected
  const functionMap = new WeakMap()
  functionMap.set(aFunction, transformedFunction)
  console.log(functionMap.get(aFunction)) // [Function: anonymous]

Re: Litdb – type safe SQL for JavaScript/TS

#50

I sort of see the value here, but isn't SQL already mostly "type safe"? Isn't following a repository pattern or something sufficient to ensure this behavior? My IDE already cries from how slow tsc / the ts language server is.

Your repository return type may say what it returns, but how would you statically prove the structure of the raw SQL string? Most of the detection today is at runtime perhaps building a class or validating the data.

You can take the raw SQL string and pass it--at compile time, treating the database itself as part of the product you are linking against (and it doesn't have to be the full production one: it can be a local one built from the artifacts in the repository)--to the database server along with the types of the input placeholders and it should be able to tell you the types of the output columns in the result set. I've implemented this before as a macro for Clojure and it was a godsend.
Post reply on HN