Hacker News new | ask | show | jobs
by kingdomcome50 2085 days ago
I'm honestly curious. What other languages have a type system the would allow for this project? That is, (a subset of) SQL as a type. And assuming these languages exist, are they as ergonomic to the developer as TS while instrumenting the above?
3 comments

Are you really calling this ergonomic? https://github.com/codemix/ts-sql/blob/master/src/Evaluator....

Same thing but actually readable and maintanable would've been better implemented as a compile-time (build-time) script, basically source code generation.

Nobody said it's ergonomic to implement SQL in a type system. It was simply an answer to your question "What do you think is advanced about TS' type system and why?". It's advanced because you're able to implement SQL in types alone when with most languages you couldn't. The question on ergonomics is for the other languages where you can do this is it more or less ergonomic than this. Again that doesn't mean this IS ergonomic it's about finding a language with a powerful type system that could do it MORE ergonomically.
This thread made me read about conditional types in TS and in general more about its type system. I was ignorant. I agree now that it's advanced. Previously I only heard bad things about it without bothering to study it myself. Turns out, it's not all bad, there is some good as well. Still wouldn't want to work with it, ever; but that's beside the point.
Well said. It's amusing imagining the soup that would result from attempting to do this sort of thing in various other languages!
Yes. What you don't see it that the TS language server provides things like autocomplete, definitions on hover, squiggly lines, sane error messages, etc. to the developer as they write the parsing code. What you don't see is that because that file compiles, it is guaranteed to parse (certain) "SQL" strings into types. This is because the code doesn't have to actually run to work, rather, TS's powerful type system does the parsing.

Source code generation wouldn't really provide the same end-user ergonomics and, frankly, would barely resemble the same project. How would that work? You generate source code from a SQL string and a data source? At that point you might as well just... write the actual code. The point of this package is that type information is dynamically assigned according to arbitrary "SQL" queries at compile-time[0].

Have you gone through short exercise I outlined below? Surely you can't think it would be better to manually generate type information than have it automagically available and enforced instantly as you work?

The closest thing I've seen to this is "type providers" in F#. Where, given a database connection, a "Provider" can offer compile-time contracts between your code and the schema of the database. What it does not do is provide contracts against arbitrary projections of the database (SQL queries). Of course one can write code that queries and transforms the data in a type-safe way, but these "transformations" must happen in F# for the compiler to infer any new types.

This project takes the above to a different level and infers the type of the result of an arbitrary (subset of) SQL operation before it is ever executed. It's fairly impressive.

[0] This has been pointed out more than once already, but this project does offer compile-time guarantees

Not sure if it makes it possible, but this is fun anyway: https://aphyr.com/posts/342-typing-the-technical-interview
What compile-time guarantees does that SQL library give? I don't see any docs or explanations at that Github repo and my TS knowledge is limited to be able to infer everything from a small code example.
Maybe clicking on the playground link would help your understanding of the project. You can literally hover over the types defined like:

      type EX = Query<"some query string", db>; 
and see the that the type as defined by the TS language server (i.e. in your editor) is the result of "running" the query without actually running the code. It's a little insane and somewhat akin to "type providers" in languages like F#.

For example, add this below `EX1` (line 66) in the TS Playground:

    let names = (persons: EX1) => persons.map(person => person.name);
Now change the column alias in `EX1` to something other than "name" and see what happens. You see that? There is now a compile-time error.
all of the functionality happens at compile time