MichalLytek / MichalLytek/type-graphql

MetadataStorage: Access to unbuilt metadata

Open
#134 14 comments 3 reactions 0 assignees View on GitHub
Community :family_man_girl: Discussion :speech_balloon: Enhancement :new:
Dominant language
TypeScript
Stars
8.1k
Forks
672
PR merge metrics
No merged PRs in 30d

Description

The current `MetadataStorage` works in two phases.

1. It gathers all the _definitions_ and stores them in _unprocessed_ arrays
2. Builds collective metadata from them during the schema generation

The problem is that if I want to access the metadata (ie. defined fields) anytime before the schema generation occurs I cannot do that because it was not _built_ yet. This prevents use-cases like generating dynamic input types / object types based on existing metadata.

**Example of the problem:**

I have `CreateUser` input type and I want to create `UpdateUser` input type which would have exactly the same _fields_ as `CreateUser` but all _nullable_ (basically GraphQL equivalent to TS `Partial`).

For this I would like to access metadata definition of `CreateUser` but I cannot do it directly because the metadata has not been built yet. Instead I have to access the information about input type's fields through access to private property.

Here is a described helper with an workaround for current situation:

```ts
import { getMetadataStorage } from 'type-graphql/metadata/getMetadataStorage'
import { InputType } from 'type-graphql'

/**
* Creates partial sub-type of given InputType.
*
* Usage:
* @InputType()
* export class UpdateUserDTO extends createPartialInputType(CreateUserDTO) {}
*/
export function createPartialInputType(InputTypeClass: {
new (...args: any[]): T
}): { new (...args: any[]): Partial } {
@InputType()
class PartialInputType extends (InputTypeClass as any) {}

const fields = (getMetadataStorage() as any).fields
fields.push(
...fields.filter((f: any) => f.target === InputTypeClass).map((f: any) => ({
...f,
target: PartialInputType,
typeOptions: { ...f.typeOptions, nullable: true },
})),
)

return PartialInputType as any
}
```

**Ideal solution**

I think we should rethink the way we store the metadata (at least for input / object types) and register them directly within a _built structure_ of given target. We would have to think carefully about which information is available at given time.

**The minimum effort solution**

If you think that the redesign of `MetadataStorage` is not worth the trouble (or will not be within next few versions), it would be nice to add at least this method to the public API of `MetadataStorage`.

```ts
findFields(target: Function): FieldMetadata[] {
return this.fields.filter(field => field.target === target);
}
```

Contributor guide

Open the contributing guide

Research direction

Start with the MetadataStorage implementation and the getMetadataStorage entry point referenced in the issue, then trace when unprocessed fields become built metadata. Compare the proposed public findFields method with the broader storage redesign, and define done as allowing access to a target's field metadata before schema generation without relying on private properties.

Written by the indexing model from the issue text.

Assessment

Tech stack
graphql, typescript
Domain
api
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
32/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.