Skip to content

Commit

Permalink
Merge pull request #6 from ChrisLahaye/feat/directives
Browse files Browse the repository at this point in the history
feat: add option to apply directives
  • Loading branch information
ChrisLahaye authored Jul 5, 2023
2 parents b8774e2 + 651a32e commit 43dd8f3
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 12 deletions.
12 changes: 8 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,18 +83,22 @@ input UserInput3 {

**`names`**: The fields to transform. A potentially optional object containing the names of the fields as key, e.g. `{ id: 1, name: 1 }`. The TypeScript type enforces all values to be *1*, but the value isn't actually used. We just need the names as object to determine if a name is included in constant time.

### `Pick(BaseClass, names)`
**`options`**: The transformation options. An optional object containing any of the following properties:

- `directives`: A boolean that indicates whether to apply directives. By default, false.

### `Pick(BaseClass, names, [options])`

Constructs a type by picking the keys of `names` from `BaseClass`.

### `Omit(BaseClass, names)`
### `Omit(BaseClass, names, [options])`

Constructs a type by picking all fields from `BaseClass` and then removing the keys of `names`.

### `Partial(BaseClass, [names])`
### `Partial(BaseClass, [names], [options])`

Constructs a type by picking all fields from `BaseClass` and then setting the keys of `names` to optional. The opposite of Required. By default, `names` contains all names.

### `Required(BaseClass, [names])`
### `Required(BaseClass, [names], [options])`

Constructs a type by picking all fields from `BaseClass` and then setting the keys of `names` to required. The opposite of Partial. By default, `names` contains all names.
33 changes: 25 additions & 8 deletions lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,14 @@ export function buildEnum<T extends ClassType>(
return enumObj;
}

export interface Options {
directives?: boolean;
}

export function buildType(
BaseClass: ClassType,
buildFn: (f: FieldMetadata) => FieldMetadata | FieldMetadata[] | undefined,
options?: Options,
): any {
@InputType({ isAbstract: true })
@ObjectType({ isAbstract: true })
Expand All @@ -47,21 +52,33 @@ export function buildType(
}
});

if (options?.directives) {
const fieldNames = metadata.fields.filter((f) => f.target === ChildClass).map((f) => f.name);

metadata.fieldDirectives.forEach((f) => {
if (f.target !== BaseClass && !f.target.isPrototypeOf(BaseClass)) return;

if (fieldNames.includes(f.fieldName)) {
metadata.fieldDirectives.push({ ...f, target: ChildClass });
}
});
}

return ChildClass;
}

export function Pick<T extends ClassType, K extends keyof InstanceType<T>>(BaseClass: T, names: Record<K, 1>): ClassType<Pick<InstanceType<T>, K>> {
return buildType(BaseClass, (f) => f.name in names ? f : undefined);
export function Pick<T extends ClassType, K extends keyof InstanceType<T>>(BaseClass: T, names: Record<K, 1>, options?: Options): ClassType<Pick<InstanceType<T>, K>> {
return buildType(BaseClass, (f) => f.name in names ? f : undefined, options);
}

export function Omit<T extends ClassType, K extends keyof InstanceType<T>>(BaseClass: T, names: Record<K, 1>): ClassType<Omit<InstanceType<T>, K>> {
return buildType(BaseClass, (f) => f.name in names ? undefined : f);
export function Omit<T extends ClassType, K extends keyof InstanceType<T>>(BaseClass: T, names: Record<K, 1>, options?: Options): ClassType<Omit<InstanceType<T>, K>> {
return buildType(BaseClass, (f) => f.name in names ? undefined : f, options);
}

export function Partial<T extends ClassType, K extends keyof InstanceType<T> = keyof InstanceType<T>>(BaseClass: T, names?: Record<K, 1>): ClassType<PartialBy<InstanceType<T>, K>> {
return buildType(BaseClass, (f) => !names || f.name in names ? { ...f, typeOptions: { ...f.typeOptions, nullable: true } } : f);
export function Partial<T extends ClassType, K extends keyof InstanceType<T> = keyof InstanceType<T>>(BaseClass: T, names?: Record<K, 1> | null, options?: Options): ClassType<PartialBy<InstanceType<T>, K>> {
return buildType(BaseClass, (f) => !names || f.name in names ? { ...f, typeOptions: { ...f.typeOptions, nullable: true } } : f, options);
}

export function Required<T extends ClassType, K extends keyof InstanceType<T> = keyof InstanceType<T>>(BaseClass: T, names?: Record<K, 1>): ClassType<RequiredBy<InstanceType<T>, K>> {
return buildType(BaseClass, (f) => !names || f.name in names ? { ...f, typeOptions: { ...f.typeOptions, nullable: false } } : f);
export function Required<T extends ClassType, K extends keyof InstanceType<T> = keyof InstanceType<T>>(BaseClass: T, names?: Record<K, 1> | null, options?: Options): ClassType<RequiredBy<InstanceType<T>, K>> {
return buildType(BaseClass, (f) => !names || f.name in names ? { ...f, typeOptions: { ...f.typeOptions, nullable: false } } : f, options);
}

0 comments on commit 43dd8f3

Please sign in to comment.