Skip to content

Commit

Permalink
feat(core): Allow length of custom field strings to be specified
Browse files Browse the repository at this point in the history
Closes #166
  • Loading branch information
michaelbromley committed Sep 25, 2019
1 parent 09eb34e commit fe360f5
Show file tree
Hide file tree
Showing 11 changed files with 54 additions and 6 deletions.
1 change: 1 addition & 0 deletions packages/admin-ui/src/app/common/generated-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3153,6 +3153,7 @@ export type StringCustomFieldConfig = CustomField & {
__typename?: 'StringCustomFieldConfig',
name: Scalars['String'],
type: Scalars['String'],
length?: Maybe<Scalars['Int']>,
label?: Maybe<Array<LocalizedString>>,
description?: Maybe<Array<LocalizedString>>,
pattern?: Maybe<Scalars['String']>,
Expand Down
1 change: 1 addition & 0 deletions packages/common/src/generated-shop-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2101,6 +2101,7 @@ export type StringCustomFieldConfig = CustomField & {
__typename?: 'StringCustomFieldConfig';
name: Scalars['String'];
type: Scalars['String'];
length?: Maybe<Scalars['Int']>;
label?: Maybe<Array<LocalizedString>>;
description?: Maybe<Array<LocalizedString>>;
pattern?: Maybe<Scalars['String']>;
Expand Down
1 change: 1 addition & 0 deletions packages/common/src/generated-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3127,6 +3127,7 @@ export type StringCustomFieldConfig = CustomField & {
__typename?: 'StringCustomFieldConfig',
name: Scalars['String'],
type: Scalars['String'],
length?: Maybe<Scalars['Int']>,
label?: Maybe<Array<LocalizedString>>,
description?: Maybe<Array<LocalizedString>>,
pattern?: Maybe<Scalars['String']>,
Expand Down
24 changes: 24 additions & 0 deletions packages/core/e2e/custom-fields.e2e-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,10 @@ describe('Custom fields', () => {
defaultValue: 'ho!',
public: true,
},
{
name: 'longString',
type: 'string',
},
],
Facet: [
{
Expand Down Expand Up @@ -145,6 +149,7 @@ describe('Custom fields', () => {
{ name: 'stringWithOptions', type: 'string' },
{ name: 'nonPublic', type: 'string' },
{ name: 'public', type: 'string' },
{ name: 'longString', type: 'string' },
],
});
});
Expand Down Expand Up @@ -238,6 +243,25 @@ describe('Custom fields', () => {
}, 'NOT NULL constraint failed: product.customFieldsNotnullable'),
);

it('string length allows long strings', async () => {
const longString = Array.from({ length: 5000 }, v => 'hello there!').join(' ');
const result = await adminClient.query(
gql`
mutation($stringValue: String!) {
updateProduct(input: { id: "T_1", customFields: { longString: $stringValue } }) {
id
customFields {
longString
}
}
}
`,
{ stringValue: longString },
);

expect(result.updateProduct.customFields.longString).toBe(longString);
});

describe('validation', () => {
it(
'invalid string',
Expand Down
1 change: 1 addition & 0 deletions packages/core/e2e/graphql/generated-e2e-admin-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3026,6 +3026,7 @@ export type StringCustomFieldConfig = CustomField & {
__typename?: 'StringCustomFieldConfig';
name: Scalars['String'];
type: Scalars['String'];
length?: Maybe<Scalars['Int']>;
label?: Maybe<Array<LocalizedString>>;
description?: Maybe<Array<LocalizedString>>;
pattern?: Maybe<Scalars['String']>;
Expand Down
1 change: 1 addition & 0 deletions packages/core/e2e/graphql/generated-e2e-shop-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2101,6 +2101,7 @@ export type StringCustomFieldConfig = CustomField & {
__typename?: 'StringCustomFieldConfig';
name: Scalars['String'];
type: Scalars['String'];
length?: Maybe<Scalars['Int']>;
label?: Maybe<Array<LocalizedString>>;
description?: Maybe<Array<LocalizedString>>;
pattern?: Maybe<Scalars['String']>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ interface CustomField {
type StringCustomFieldConfig implements CustomField {
name: String!
type: String!
length: Int
label: [LocalizedString!]
description: [LocalizedString!]
pattern: String
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ export type CustomFieldConfig =
*
* * `pattern?: string`: A regex pattern which the field value must match
* * `options?: { value: string; label?: LocalizedString[]; };`: An array of pre-defined options for the field.
* * `length?: number`: The max length of the varchar created in the database. Defaults to 255. Maximum is 65,535.
*
* #### `localeString` type
*
Expand Down
25 changes: 21 additions & 4 deletions packages/core/src/entity/register-custom-entity-fields.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { CustomFieldType } from '@vendure/common/lib/shared-types';
import { assertNever } from '@vendure/common/lib/shared-utils';
import { Column, ColumnType, ConnectionOptions } from 'typeorm';
import { Column, ColumnOptions, ColumnType, ConnectionOptions } from 'typeorm';
import { DateUtils } from 'typeorm/util/DateUtils';

import { CustomFields } from '../config/custom-field/custom-field-types';
import { Logger } from '../config/logger/vendure-logger';
import { VendureConfig } from '../config/vendure-config';

import {
Expand All @@ -29,6 +30,11 @@ import {
CustomUserFields,
} from './custom-entity-fields';

/**
* The maximum length of the "length" argument of a MySQL varchar column.
*/
const MAX_STRING_LENGTH = 65535;

/**
* Dynamically add columns to the custom field entity based on the CustomFields config.
*/
Expand All @@ -44,14 +50,25 @@ function registerCustomFieldsForEntity(
if (customFields) {
for (const customField of customFields) {
const { name, type, defaultValue, nullable } = customField;
const registerColumn = () =>
Column({
const registerColumn = () => {
const options: ColumnOptions = {
type: getColumnType(dbEngine, type),
default:
type === 'datetime' ? formatDefaultDatetime(dbEngine, defaultValue) : defaultValue,
name,
nullable: nullable === false ? false : true,
})(new ctor(), name);
};
if (customField.type === 'string') {
const length = customField.length || 255;
if (MAX_STRING_LENGTH < length) {
throw new Error(
`ERROR: The "length" property of the custom field "${customField.name}" is greater than the maximum allowed value of ${MAX_STRING_LENGTH}`,
);
}
options.length = length;
}
Column(options)(new ctor(), name);
};

if (translation) {
if (type === 'localeString') {
Expand Down
2 changes: 1 addition & 1 deletion schema-admin.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion schema-shop.json

Large diffs are not rendered by default.

0 comments on commit fe360f5

Please sign in to comment.