Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 91 additions & 0 deletions docs/docs/guides/developer-guide/custom-fields/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -988,6 +988,9 @@ In addition to the common properties, the `relation` custom fields have some typ
- [`eager`](#eager)
- [`graphQLType`](#graphqltype)
- [`inverseSide`](#inverseside)
- [`cascade`](#cascade)
- [`onDelete`](#ondelete)
- [`onUpdate`](#onupdate)

#### entity

Expand Down Expand Up @@ -1102,6 +1105,94 @@ const { productReviews } = await this.connection.getRepository(ProductReview).fi
});
```

#### cascade

<CustomFieldProperty required={false} type="boolean | ('insert' | 'update' | 'remove' | 'soft-remove' | 'recover')[]" />

Whether to [cascade](https://typeorm.io/docs/relations/relations#cascade-options) operations on the relation. Defaults to `false`.

```ts title="src/vendure-config.ts"
import { Product } from '\@vendure/core';
import { ProductReview } from './entities/product-review.entity';

const config = {
// ...
customFields: {
Product: [
{
name: 'reviews',
list: true,
type: 'relation',
entity: ProductReview,
cascade: ['insert', 'update'], // [!code highlight]
},
]
}
};
```

#### onDelete
<CustomFieldProperty required={false} type="'RESTRICT' | 'CASCADE' | 'SET NULL' | 'NO ACTION' | 'SET DEFAULT'" />

The [onDelete](https://typeorm.io/docs/relations/relations/) behavior for the relation. Defaults to `NO ACTION`.

:::note

Setting `onDelete` to `CASCADE` or `cascade: ['remove']` means that if the referenced entity is deleted, rows owning this relation may also be deleted.
This can have unintended consequences, especially when referencing core Vendure entities.
For example, if you have a relation to `ProductVariant` and set `onDelete: 'CASCADE'`, deleting that `ProductVariant` can cascade to rows that reference it.
Use with caution.

Setting `onDelete` on a `ManyToMany` (`list: true`) relation will affect the join table, but not the related entity.

```ts title="src/vendure-config.ts"
import { Product } from '\@vendure/core';
import { ProductReview } from './entities/product-review.entity';

const config = {
// ...
customFields: {
Product: [
{
name: 'reviews',
list: false,
type: 'relation',
entity: ProductReview,
onDelete: 'SET NULL', // [!code highlight]
},
]
}
};
```

#### onUpdate
<CustomFieldProperty required={false} type="'RESTRICT' | 'CASCADE' | 'SET NULL' | 'NO ACTION' | 'SET DEFAULT'" />

The [onUpdate](https://typeorm.io/docs/relations/relations/) behavior for the relation. If not set, the database default (`NO ACTION`) applies.
`onUpdate` is not supported by SQLite and will be ignored if you are using SQLite as your database.

Setting `onUpdate` on a `ManyToMany` (`list: true`) relation will affect the join table, but not the related entity.

```ts title="src/vendure-config.ts"
import { Product } from '\@vendure/core';
import { ProductReview } from './entities/product-review.entity';

const config = {
// ...
customFields: {
Product: [
{
name: 'reviews',
list: false,
type: 'relation',
entity: ProductReview,
onUpdate: 'CASCADE', // [!code highlight]
},
]
}
};
```

## Custom Field UI

In the Dashboard, an appropriate default form input component is used for each custom field type. The Dashboard comes with a set of ready-made form input components, but it is also possible to create custom form input components. The ready-made components are:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: "TypedCustomSingleFieldConfig"
generated: true
---
<GenerationInfo sourceFile="packages/core/src/config/custom-field/custom-field-types.ts" sourceLine="101" packageName="@vendure/core" />
<GenerationInfo sourceFile="packages/core/src/config/custom-field/custom-field-types.ts" sourceLine="102" packageName="@vendure/core" />

Configures a custom field on an entity in the [CustomFields](/reference/typescript-api/custom-fields/#customfields) config object.

Expand Down
7 changes: 4 additions & 3 deletions packages/core/src/config/custom-field/custom-field-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import {
Type,
UiComponentConfig,
} from '@vendure/common/lib/shared-types';
import { RelationOptions } from 'typeorm';

import { RequestContext } from '../../api/common/request-context';
import { Injector } from '../../common/injector';
Expand Down Expand Up @@ -114,9 +115,10 @@ export type TypedCustomSingleFieldConfig<
export type TypedCustomListFieldConfig<
T extends CustomFieldType,
C extends CustomField,
> = BaseTypedCustomFieldConfig<T, C> & {
> = Omit<BaseTypedCustomFieldConfig<T, C>, 'nullable'> & {
list?: true;
defaultValue?: Array<DefaultValueType<T>>;
nullable?: never;
Comment on lines +118 to +121

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if this is overkill, but I find it useful to disallow options that will be ignored

validate?: (
value: Array<DefaultValueType<T>>,
) => string | LocalizedString[] | void | Promise<string | LocalizedString[] | void>;
Expand Down Expand Up @@ -149,9 +151,8 @@ export type RelationCustomFieldConfig = TypedCustomFieldConfig<
> & {
entity: Type<VendureEntity>;
graphQLType?: string;
eager?: boolean;
inverseSide?: string | ((object: any) => any);
};
} & Pick<RelationOptions, 'cascade' | 'onDelete' | 'onUpdate' | 'eager'>;

// Struct field definitions
export type BaseTypedStructFieldConfig<T extends StructFieldType, C extends GraphQLStructField> = Omit<
Expand Down
Loading
Loading