DEV Community

prasanna malla
prasanna malla

Posted on

Adding fields to existing types in Vendure

Custom fields allow you to add your own custom data properties to many of the Vendure entities. The entities which may have custom fields defined are listed in the CustomFields documentation. While this approach is flexible it becomes quite cumbersome when dealing with a huge number of fields, for example, ingredients for food products. Rather than adding each ingredient as a custom field on the product, we can create an Ingredient entity and have ProductVariant extend it.

import { DeepPartial, ProductVariant, VendureEntity } from '@vendure/core';
import { Entity, Column, ManyToMany, JoinTable } from 'typeorm';

@Entity()
export class Ingredient extends VendureEntity {
    constructor(input?: DeepPartial<Ingredient>) {
        super(input);
    }

    @Column({ nullable: false })
    name!: string;

    @ManyToMany(type => ProductVariant, { nullable: false })
    @JoinTable()
    productVariants!: ProductVariant[];
}
Enter fullscreen mode Exit fullscreen mode

Add the entity, types and resolver to VendureConfig

@VendurePlugin({
    imports: [PluginCommonModule],
    entities: [Ingredient],
    adminApiExtensions: {
        schema: gql`
            type Ingredient implements Node {
                id: ID!
                name: String!
                productVariants: [ProductVariant!]!
            }

            extend type ProductVariant {
                ingredients: [Ingredient!]
            }
        `,
        resolvers: [ProductVariantEntityResolver],
    },
})
Enter fullscreen mode Exit fullscreen mode

Add the field resolver for the ingredients field in ProductVariant entity

import { Parent, ResolveField, Resolver } from '@nestjs/graphql';
import { Ctx, RequestContext, ProductVariant, TransactionalConnection } from '@vendure/core';
import { Ingredient } from '../entity/ingredient.entity';

@Resolver('ProductVariant')
export class ProductVariantEntityResolver {
    constructor(private connection: TransactionalConnection) {}

    @ResolveField()
    ingredients(@Ctx() ctx: RequestContext, @Parent() variant: ProductVariant) {
        return this.connection
            .getRepository(ctx, Ingredient)
            .createQueryBuilder('ing')
            .leftJoin('ing.productVariants', 'variant')
            .where('variant.id = :id', { id: variant.id })
            .getMany();
    }
}
Enter fullscreen mode Exit fullscreen mode

Since Ingredient entity owns the relation, ProductVariant entity does not know about it directly so we are using the above field resolver. Finally, you can query productVariants with ingredients sub-selection.

Vendure v2.0 is coming out soon! come share the excitement on slack.

Top comments (0)