pgtyped icon indicating copy to clipboard operation
pgtyped copied to clipboard

Feature Request: Support branded types and other type conversions

Open twk opened this issue 4 years ago • 4 comments

We use a lot of branded types in our typescript code, which helps us catch more bugs at compile time:

type Brand<K, T> = K & { __brand: T };
export type CustomerId = Brand<number, 'CustomerId'>;
export type Email = Brand<string, 'Email'>;

Of course, postgres doesn't support anything like this, so these are just stored as integers and strings in the database. So, it would be amazing if I could map certain fields in the code that pgtyped generates to the branded type that I really want.

Also, I have a few cases where I'm pulling bigints out of postgres but I can guarantee that they are valid integers in Typescript. It would be nice to be able to specify a function that is called to convert each value from the database to a new value that has the right type (and the conversion could include an assertion or other sanity check).

I'm not sure if you could parse these out 100% of the time before generating the real query, but one approach might be to specify some kind of mapping function in the SQL, since the @params are harder to keep in sync.

select
  customer_id as customerId via toCustomerId,
  email via toEmail
from customers

toCustomerId and toEmail would both be functions that are exported from a file that the pgtyped config knows about. For branded types, they would be very simple, but for things like string -> number conversion they would do a little more work

export function toEmail(s: string): Email {
  return s as Email;
}
export function toSafeInteger(s: string): Number {
  const val = Number.parseInt(s);
  if (!Number.isSafeInteger(val)) throw ...
  return val;
}

Anyway, just some suggestions. I love the library, so thanks for your work on it!

twk avatar Sep 07 '20 15:09 twk

Unfortunately given how pgTyped works, extending SQL like that won't be possible because we rely on Postgres for parsing and analyzing the queries.

One way to achieve this might be to use some TS type magic by building a generic type that iterates through the returned result type interface and maps certain key-value combinations to branded values.

adelsz avatar Sep 17 '20 20:09 adelsz

Ah, I thought you might be doing some SQL parsing before feeding it into Postgres.

Doing with an @param to suggest the type would be pretty good too.

twk avatar Sep 17 '20 22:09 twk

Agree, I have been thinking about providing a way to override the inferred types, maybe with something like an @override flag. Not sure yet about how dynamic will such an override mapping be, but it definitely be useful either way.

adelsz avatar Nov 20 '20 22:11 adelsz

@twk you can transform pgtyped types to something another with tools like https://github.com/millsp/ts-toolbelt

darky avatar Dec 01 '20 21:12 darky

For now branded types are a non-priority due to poor TS and Postgres support.

adelsz avatar Jan 29 '23 01:01 adelsz