Open tdolsen opened 2 years ago
This is driving me nuts. I am having to cast the property every time I use it since I have built around expecting an enum. I think I would be fine if it was just a union type every time. We could something like this to basically get the same effect as an Enum:
const ALL_SUITS = ['hearts', 'diamonds', 'spades', 'clubs'] as const;
type SuitTuple = typeof ALL_SUITS; // readonly ['hearts', 'diamonds', 'spades', 'clubs']
type Suit = SuitTuple[number]; // "hearts" | "diamonds" | "spades" | "clubs"
It does split it into two which is maybe not as nice, but you still do programatic things with ALL_SUITS
eg looping. You can also do discrimination with Suit
eg:
export type ADTMember<ADT, Key extends string, Type extends string> = Extract<
ADT,
{ [k in Key]: Type }
>
type Matchers<Key extends string, ADT extends { [k in Key]: string }, Out> = {
[D in ADT[Key]]: (v: ADTMember<ADT, Key, D>) => Out
}
export const matchOn =
<K extends string>(key: K) =>
<ADT extends { [k in K]: string }, Z>(matchObj: Matchers<K, ADT, Z>) =>
(v: ADT) =>
matchObj[v[key]](v as ADTMember<ADT, K, typeof v[K]>)
type result = {
suit: Suit
}
const matchSuit = matchOn('suit')
const displaySuit = (result: result) => matchSuit({
hearts: () => 'hearts',
diamonds: () => 'diamonds',
spades: () => 'spaded',
clubs: () => 'clubs',
})(result)
I don't know if this is still applicable, but my solution this spring was to do the following in my package.json
's script declarations:
{
"scripts": {
"generate:edgeql": "yarn edgeql-js --output-dir ./generated/edgeql --target cjs",
"postgenerate:edgeql": "yarn format:generated:edgeql && yarn postgenerate:edgeql:enum-patch",
"postgenerate:edgeql:enum-patch": "replace-in-files --regex='(\\t*)export enum (\\w+)' --replacement='$1export type $2 = _$2 | `$${_$2}`;\\n$1export enum _$2' ./generated/edgeql/types.d.ts",
"format:generated:edgeql": "prettier --write \"generated/edgeql/**/*.{ts,js}\"",
...
},
"dependencies": {
"edgedb": "^0.19.15",
},
"devDependencies": {
"prettier": "^2.6.0",
"replace-in-files-cli": "^2.0.0",
...
}
}
Doing so I ended up with actually exported enums I could use, together with the standard const declarations edgeql-js outputted.
Note that my patch hinges on the generated code being formatted with my prettier ruleset, using tabs for indentation. Mileage my vary.
edgedb-js: 0.19.15 server: 1.2 cli: 1.1.0+96c3d69 typescript: 4.6.2
Current behavior
When selecting for enum properties, the query returns the string representation of the enum value.
Assuming this dbschema:
And given the following select expression:
The query returns this type:
With the value of
status
being set to either"Pending"
or"Purchase"
strings.Expected behavior
Return the actual enum value.
Querying the same expression, the returned type should be:
With the value of
status
being set to eithere.PurchaseStatus.Pending
ore.PurchasaeStatus.Purchased
, avoiding string values entirely.Details
When using the generated types and helpers, (that ensures beautiful end-to-end type safety in all other regards,) it is extremely frustrating not being able to consistently use the enums defined in the schema. As it is now I can't rely on type matching and casting working, and value validation requires extra handling.
I especially painfully wrestled with this trying to type cast select results containing enums to their respective data transfer objects. The DTOs of course implementing a perfect shape match, with exactly the same enums as exported to the generated code.
So my options seems limited to:
e.select
/expr.run
. (Hah - as if!)Needless to say really, but none of these "solutions" have any appeal at all.
As I understand it it's the underlying engine of the server core that dictates this behavior, and
edgedb-js
can't do anything with how the values are returned from the server. (Maybe the issue should be raised in edgedb/edgedb as well.)However, considering that all the types and values are readily available in the generated code, shouldn't it be possible to handle it in the client library, converting the values/types before returning the result?