-
-
Notifications
You must be signed in to change notification settings - Fork 574
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Rework TypeScript types around registry, codecs, resources and relations #1784
base: main
Are you sure you want to change the base?
Conversation
|
@benjie I think I found a way to delay the inference without causing export interface AnyPgCodec extends PgCodec {} // <-- allows use of default generic parameters, and prevents "circular default detected" errors
/**
* A codec for a Postgres type, tells us how to convert to-and-from Postgres
* (including changes to the SQL statement itself). Also includes metadata
* about the type, for example any of the attributes it has.
*/
export interface PgCodec<
TName extends string = string,
TCodecAttributes extends
ReadonlyArray<PgCodecAttribute> = ReadonlyArray<PgCodecAttribute>,
TFromPostgres = any,
TFromJavaScript = TFromPostgres,
TArrayItemCodec extends AnyPgCodec = AnyPgCodec, // <-- using just PgCodec here causes circular default parameter issues
TDomainItemCodec extends AnyPgCodec = AnyPgCodec,
TRangeItemCodec extends PgRangeItemCodec = PgRangeItemCodec,
> {
// snip
} For example, I think I might've been able to get I haven't done all of it yet, but it seems promising. |
Exciting! This reminds me of the kind of trick you need to do to build a JSONValue type, I should have thought about that - the difference between eager evaluated and lazily evaluated types... I'm not yet good enough at TypeScript to figure these things out for myself. Keep up the great work! |
066e2a1
to
1c5e313
Compare
Thanks, I've got a basic working example schema again. There are still loads of mismatches, and biggest one is the |
d3a7030
to
336f644
Compare
@@ -154,7 +154,7 @@ const makeV4Plugin = (options: V4Options): GraphileConfig.Plugin => { | |||
entityBehavior: { | |||
pgResource: "+delete:resource:select", | |||
pgCodecAttribute(behavior, [codec, attributeName]) { | |||
const attribute = codec.attributes[attributeName]; | |||
const attribute = codec.attributes![attributeName]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The !
shouldn't be required here since pgCodecAttribute
will only ever be called with a PgCodec that has attributes (formerly a PgCodecWithAttributes
)
@@ -42,7 +41,7 @@ declare global { | |||
_attributeName( | |||
this: GraphileBuild.Inflection, | |||
details: { | |||
codec: PgCodecWithAttributes; | |||
codec: DefaultPgCodec; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this (and the related changes below) have been DefaultPgCodecWithAttributes
or similar?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, but this gave me a lot of errors, so I opted to widen the constraint for now, as I felt it wasn't necessarily a requirement for the purpose of this PR.
.gitignore
Outdated
@@ -43,4 +43,4 @@ grafast/dataplan-pg/__tests__/**/*.mermaid.png | |||
/Session.vim | |||
/WHAT_ARE_YOU_DOING.md | |||
contrib | |||
/env | |||
/env |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you've removed the newline from the end of .gitignore
- perhaps when you removed the nix stuff?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll put it back, :-)
I've merged the latest and I've renamed
|
@@ -112,7 +161,7 @@ export interface PgCodecAttribute< | |||
* these are all plural relationships. So identicalVia is generally one-way | |||
* (except in 1-to-1 relationships). | |||
*/ | |||
identicalVia?: PgCodecAttributeVia; | |||
identicalVia?: _AnyPgCodecAttributeVia; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I change via
and identicalVia
to GenericPgCodecAttributeVia
then I get weird errors in exampleSchema.ts
. However, I know that if via
is set then it will always be string | { relation: string, attribute: string }
(or a narrower form of this) so I don't really understand why this needs to use any
s?
I've also fixed the linting issues, but I'm a bit lost in understanding what we're actually achieving here - seems that we're hitting |
(To be clear: the previous comment was stating that I'm lost because of my poor understanding of TypeScript, not because the PR is bad. It could be that we were hitting |
(@wesselvdv and I had a long call where we went through this, and unfortunately though it solves some issues it also creates others, in particular making the codebase harder to work on. Currently the |
Description
In this PR i've tried to rework to typescript system so it would be more ergonomic for both internal and external usage. Please be aware that it's mostly a showcase of how it could be, not how it should be.
Observations leading to the changes in this PR:
any
.PgRegistry
interface because of the type parameter being objects ({ [indexName: string]: etc }
) which causes early evaluation tostring
which loses the actual properties.keyof
when inferring objects, which can cause early evaluation resulting instring | number
even when explicitly defining an object with index string:keyof { [index: string]: number } === string | number
undefined
as bottom type instead ofnever
Changes in this PR:
Any<PgType>
andDefault<PgType>
interfaces.Any<PgType>
interfaces are for internal usage, and theDefault<PgType>
for external usage. This because the latter ones cause massive circular reference issue for typescript when used in places where they're being defined. (e.g. inside dataplan/pg, but not in graphile-build-pg)Expand<>
which is quite performance intensive.infer
to delay the inference internally and have less type casting.The changes in dataplan/pg are the core changes, and the resulting changes in graphile-build-pg and others are a consequence of this. The changes in the latter have mostly been changing
PgCodec
toDefaultPgCodec
and removing a LOT of explicit type casts because this now "just" works.Biggest achievement which I am not sure if this is because of this PR, but nonetheless useful. The correct typing of the below snippet in the exampleSchema:
crystal/grafast/dataplan-pg/src/examples/exampleSchema.ts
Lines 3386 to 3396 in 5589d14
Having the ability to define a correctly typed parent step with a specific resource, and having it infer correctly and type check that it adheres to said parent. (e.g.
RelationalTopicStep extends RelationalItemsLikeStep ? 'yes' : 'no' === 'yes'
)Outstanding tasks
GetPgCodecAttributes
vsPgCodecAttributes
, or even consider namespacesPgCodec.getAttributes<> | PgCodec.Attributes<>
)fixes #1755
Performance impact
Non empirical observation is that the
exampleSchema.ts
file has become significantly faster.Security impact
Checklist
yarn lint:fix
passes.yarn test
passes.RELEASE_NOTES.md
file (if one exists).