Просмотр исходного кода

refactor(core): Split custom fields functions into separate files

Michael Bromley 6 лет назад
Родитель
Сommit
090758c48e

+ 1 - 1
packages/core/mock-data/clear-all-tables.ts

@@ -1,7 +1,7 @@
 import { createConnection } from 'typeorm';
 
 import { isTestEnvironment } from '../e2e/utils/test-environment';
-import { registerCustomEntityFields } from '../src/entity/custom-entity-fields';
+import { registerCustomEntityFields } from '../src/entity/register-custom-entity-fields';
 
 // tslint:disable:no-console
 // tslint:disable:no-floating-promises

+ 1 - 1
packages/core/src/app.module.ts

@@ -6,7 +6,7 @@ import { ApiModule } from './api/api.module';
 import { ConfigModule } from './config/config.module';
 import { ConfigService } from './config/config.service';
 import { Logger } from './config/logger/vendure-logger';
-import { validateCustomFieldsConfig } from './entity/custom-entity-fields';
+import { validateCustomFieldsConfig } from './entity/validate-custom-fields-config';
 import { I18nModule } from './i18n/i18n.module';
 import { I18nService } from './i18n/i18n.service';
 

+ 1 - 1
packages/core/src/bootstrap.ts

@@ -10,7 +10,7 @@ import { getConfig, setConfig } from './config/config-helpers';
 import { DefaultLogger } from './config/logger/default-logger';
 import { Logger } from './config/logger/vendure-logger';
 import { VendureConfig } from './config/vendure-config';
-import { registerCustomEntityFields } from './entity/custom-entity-fields';
+import { registerCustomEntityFields } from './entity/register-custom-entity-fields';
 import { logProxyMiddlewares } from './plugin/plugin-utils';
 
 export type VendureBootstrapFunction = (config: VendureConfig) => Promise<INestApplication>;

+ 0 - 158
packages/core/src/entity/custom-entity-fields.ts

@@ -1,12 +1,3 @@
-import { CustomFieldType, Type } from '@vendure/common/lib/shared-types';
-import { assertNever } from '@vendure/common/lib/shared-utils';
-import { Column, ColumnType, Connection, ConnectionOptions, getConnection } from 'typeorm';
-
-import { CustomFieldConfig, CustomFields } from '../config/custom-field/custom-field-types';
-import { VendureConfig } from '../config/vendure-config';
-
-import { VendureEntity } from './base/base.entity';
-
 export class CustomAddressFields {}
 export class CustomFacetFields {}
 export class CustomFacetFieldsTranslation {}
@@ -26,152 +17,3 @@ export class CustomProductVariantFields {}
 export class CustomProductVariantFieldsTranslation {}
 export class CustomUserFields {}
 export class CustomGlobalSettingsFields {}
-
-/**
- * Dynamically add columns to the custom field entity based on the CustomFields config.
- */
-function registerCustomFieldsForEntity(
-    config: VendureConfig,
-    entityName: keyof CustomFields,
-    // tslint:disable-next-line:callable-types
-    ctor: { new (): any },
-    translation = false,
-) {
-    const customFields = config.customFields && config.customFields[entityName];
-    const dbEngine = config.dbConnectionOptions.type;
-    if (customFields) {
-        for (const customField of customFields) {
-            const { name, type } = customField;
-            const registerColumn = () =>
-                Column({ type: getColumnType(dbEngine, type), name, nullable: true })(new ctor(), name);
-
-            if (translation) {
-                if (type === 'localeString') {
-                    registerColumn();
-                }
-            } else {
-                if (type !== 'localeString') {
-                    registerColumn();
-                }
-            }
-        }
-    }
-}
-
-function getColumnType(dbEngine: ConnectionOptions['type'], type: CustomFieldType): ColumnType {
-    switch (type) {
-        case 'string':
-        case 'localeString':
-            return 'varchar';
-        case 'boolean':
-            return dbEngine === 'mysql' ? 'tinyint' : 'bool';
-        case 'int':
-            return 'int';
-        case 'float':
-            return 'double';
-        case 'datetime':
-            return dbEngine === 'mysql' ? 'datetime' : 'timestamp';
-        default:
-            assertNever(type);
-    }
-    return 'varchar';
-}
-
-function validateCustomFieldsForEntity(
-    connection: Connection,
-    entity: Type<VendureEntity>,
-    customFields: CustomFieldConfig[],
-): void {
-    const metadata = connection.getMetadata(entity);
-    const { relations } = metadata;
-
-    const translationRelation = relations.find(r => r.propertyName === 'translations');
-    if (translationRelation) {
-        const translationEntity = translationRelation.type;
-        const translationPropMap = connection.getMetadata(translationEntity).createPropertiesMap();
-        const localeStringFields = customFields.filter(field => field.type === 'localeString');
-        assertNoNameConflicts(entity.name, translationPropMap, localeStringFields);
-    } else {
-        assertNoLocaleStringFields(entity, customFields);
-    }
-
-    const nonLocaleStringFields = customFields.filter(field => field.type !== 'localeString');
-    const propMap = metadata.createPropertiesMap();
-    assertNoNameConflicts(entity.name, propMap, nonLocaleStringFields);
-}
-
-/**
- * Assert that none of the custom field names conflict with existing properties of the entity, as provided
- * by the TypeORM PropertiesMap object.
- */
-function assertNoNameConflicts(entityName: string, propMap: object, customFields: CustomFieldConfig[]): void {
-    for (const customField of customFields) {
-        if (propMap.hasOwnProperty(customField.name)) {
-            const message = `Custom field name conflict: the "${entityName}" entity already has a built-in property "${
-                customField.name
-            }".`;
-            throw new Error(message);
-        }
-    }
-}
-
-/**
- * For entities which are not localized (Address, Customer), we assert that none of the custom fields
- * have a type "localeString".
- */
-function assertNoLocaleStringFields(entity: Type<any>, customFields: CustomFieldConfig[]): void {
-    if (!!customFields.find(f => f.type === 'localeString')) {
-        const message = `Custom field type error: the "${
-            entity.name
-        }" entity does not support the "localeString" type.`;
-        throw new Error(message);
-    }
-}
-
-/**
- * Dynamically registers any custom fields with TypeORM. This function should be run at the bootstrap
- * stage of the app lifecycle, before the AppModule is initialized.
- */
-export function registerCustomEntityFields(config: VendureConfig) {
-    registerCustomFieldsForEntity(config, 'Address', CustomAddressFields);
-    registerCustomFieldsForEntity(config, 'Collection', CustomCollectionFields);
-    registerCustomFieldsForEntity(config, 'Collection', CustomCollectionFieldsTranslation, true);
-    registerCustomFieldsForEntity(config, 'Customer', CustomCustomerFields);
-    registerCustomFieldsForEntity(config, 'Facet', CustomFacetFields);
-    registerCustomFieldsForEntity(config, 'Facet', CustomFacetFieldsTranslation, true);
-    registerCustomFieldsForEntity(config, 'FacetValue', CustomFacetValueFields);
-    registerCustomFieldsForEntity(config, 'FacetValue', CustomFacetValueFieldsTranslation, true);
-    registerCustomFieldsForEntity(config, 'OrderLine', CustomOrderLineFields);
-    registerCustomFieldsForEntity(config, 'Product', CustomProductFields);
-    registerCustomFieldsForEntity(config, 'Product', CustomProductFieldsTranslation, true);
-    registerCustomFieldsForEntity(config, 'ProductOption', CustomProductOptionFields);
-    registerCustomFieldsForEntity(config, 'ProductOption', CustomProductOptionFieldsTranslation, true);
-    registerCustomFieldsForEntity(config, 'ProductOptionGroup', CustomProductOptionGroupFields);
-    registerCustomFieldsForEntity(
-        config,
-        'ProductOptionGroup',
-        CustomProductOptionGroupFieldsTranslation,
-        true,
-    );
-    registerCustomFieldsForEntity(config, 'ProductVariant', CustomProductVariantFields);
-    registerCustomFieldsForEntity(config, 'ProductVariant', CustomProductVariantFieldsTranslation, true);
-    registerCustomFieldsForEntity(config, 'User', CustomUserFields);
-    registerCustomFieldsForEntity(config, 'GlobalSettings', CustomGlobalSettingsFields);
-}
-
-/**
- * Validates the custom fields config, e.g. by ensuring that there are no naming conflicts with the built-in fields
- * of each entity.
- */
-export async function validateCustomFieldsConfig(customFieldConfig: CustomFields) {
-    const connection = getConnection();
-    // dynamic import to avoid bootstrap-time order of loading issues
-    const { coreEntitiesMap } = await import('./entities');
-
-    for (const key of Object.keys(customFieldConfig)) {
-        const entityName = key as keyof CustomFields;
-        const customEntityFields = customFieldConfig[entityName] || [];
-        const entity = coreEntitiesMap[entityName];
-        validateCustomFieldsForEntity(connection, entity, customEntityFields);
-    }
-}

+ 110 - 0
packages/core/src/entity/register-custom-entity-fields.ts

@@ -0,0 +1,110 @@
+import { CustomFieldType } from '@vendure/common/lib/shared-types';
+import { assertNever } from '@vendure/common/lib/shared-utils';
+import { Column, ColumnType, ConnectionOptions } from 'typeorm';
+
+import { CustomFields } from '../config/custom-field/custom-field-types';
+import { VendureConfig } from '../config/vendure-config';
+
+import {
+    CustomAddressFields,
+    CustomCollectionFields,
+    CustomCollectionFieldsTranslation,
+    CustomCustomerFields,
+    CustomFacetFields,
+    CustomFacetFieldsTranslation,
+    CustomFacetValueFields,
+    CustomFacetValueFieldsTranslation,
+    CustomGlobalSettingsFields,
+    CustomOrderLineFields,
+    CustomProductFields,
+    CustomProductFieldsTranslation,
+    CustomProductOptionFields,
+    CustomProductOptionFieldsTranslation,
+    CustomProductOptionGroupFields,
+    CustomProductOptionGroupFieldsTranslation,
+    CustomProductVariantFields,
+    CustomProductVariantFieldsTranslation,
+    CustomUserFields,
+} from './custom-entity-fields';
+
+/**
+ * Dynamically add columns to the custom field entity based on the CustomFields config.
+ */
+function registerCustomFieldsForEntity(
+    config: VendureConfig,
+    entityName: keyof CustomFields,
+    // tslint:disable-next-line:callable-types
+    ctor: { new (): any },
+    translation = false,
+) {
+    const customFields = config.customFields && config.customFields[entityName];
+    const dbEngine = config.dbConnectionOptions.type;
+    if (customFields) {
+        for (const customField of customFields) {
+            const { name, type } = customField;
+            const registerColumn = () =>
+                Column({ type: getColumnType(dbEngine, type), name, nullable: true })(new ctor(), name);
+
+            if (translation) {
+                if (type === 'localeString') {
+                    registerColumn();
+                }
+            } else {
+                if (type !== 'localeString') {
+                    registerColumn();
+                }
+            }
+        }
+    }
+}
+
+function getColumnType(dbEngine: ConnectionOptions['type'], type: CustomFieldType): ColumnType {
+    switch (type) {
+        case 'string':
+        case 'localeString':
+            return 'varchar';
+        case 'boolean':
+            return dbEngine === 'mysql' ? 'tinyint' : 'bool';
+        case 'int':
+            return 'int';
+        case 'float':
+            return 'double';
+        case 'datetime':
+            return dbEngine === 'mysql' ? 'datetime' : 'timestamp';
+        default:
+            assertNever(type);
+    }
+    return 'varchar';
+}
+
+/**
+ * Dynamically registers any custom fields with TypeORM. This function should be run at the bootstrap
+ * stage of the app lifecycle, before the AppModule is initialized.
+ */
+export function registerCustomEntityFields(config: VendureConfig) {
+    registerCustomFieldsForEntity(config, 'Address', CustomAddressFields);
+    registerCustomFieldsForEntity(config, 'Collection', CustomCollectionFields);
+    registerCustomFieldsForEntity(config, 'Collection', CustomCollectionFieldsTranslation, true);
+    registerCustomFieldsForEntity(config, 'Customer', CustomCustomerFields);
+    registerCustomFieldsForEntity(config, 'Facet', CustomFacetFields);
+    registerCustomFieldsForEntity(config, 'Facet', CustomFacetFieldsTranslation, true);
+    registerCustomFieldsForEntity(config, 'FacetValue', CustomFacetValueFields);
+    registerCustomFieldsForEntity(config, 'FacetValue', CustomFacetValueFieldsTranslation, true);
+    registerCustomFieldsForEntity(config, 'OrderLine', CustomOrderLineFields);
+    registerCustomFieldsForEntity(config, 'Product', CustomProductFields);
+    registerCustomFieldsForEntity(config, 'Product', CustomProductFieldsTranslation, true);
+    registerCustomFieldsForEntity(config, 'ProductOption', CustomProductOptionFields);
+    registerCustomFieldsForEntity(config, 'ProductOption', CustomProductOptionFieldsTranslation, true);
+    registerCustomFieldsForEntity(config, 'ProductOptionGroup', CustomProductOptionGroupFields);
+    registerCustomFieldsForEntity(
+        config,
+        'ProductOptionGroup',
+        CustomProductOptionGroupFieldsTranslation,
+        true,
+    );
+    registerCustomFieldsForEntity(config, 'ProductVariant', CustomProductVariantFields);
+    registerCustomFieldsForEntity(config, 'ProductVariant', CustomProductVariantFieldsTranslation, true);
+    registerCustomFieldsForEntity(config, 'User', CustomUserFields);
+    registerCustomFieldsForEntity(config, 'GlobalSettings', CustomGlobalSettingsFields);
+}
+

+ 74 - 0
packages/core/src/entity/validate-custom-fields-config.ts

@@ -0,0 +1,74 @@
+import { Connection, getConnection } from 'typeorm';
+
+import { Type } from '../../../common/lib/shared-types';
+import { CustomFieldConfig, CustomFields } from '../config/custom-field/custom-field-types';
+
+import { VendureEntity } from './base/base.entity';
+
+function validateCustomFieldsForEntity(
+    connection: Connection,
+    entity: Type<VendureEntity>,
+    customFields: CustomFieldConfig[],
+): void {
+    const metadata = connection.getMetadata(entity);
+    const {relations} = metadata;
+
+    const translationRelation = relations.find(r => r.propertyName === 'translations');
+    if (translationRelation) {
+        const translationEntity = translationRelation.type;
+        const translationPropMap = connection.getMetadata(translationEntity).createPropertiesMap();
+        const localeStringFields = customFields.filter(field => field.type === 'localeString');
+        assertNoNameConflicts(entity.name, translationPropMap, localeStringFields);
+    } else {
+        assertNoLocaleStringFields(entity, customFields);
+    }
+
+    const nonLocaleStringFields = customFields.filter(field => field.type !== 'localeString');
+    const propMap = metadata.createPropertiesMap();
+    assertNoNameConflicts(entity.name, propMap, nonLocaleStringFields);
+}
+
+/**
+ * Assert that none of the custom field names conflict with existing properties of the entity, as provided
+ * by the TypeORM PropertiesMap object.
+ */
+function assertNoNameConflicts(entityName: string, propMap: object, customFields: CustomFieldConfig[]): void {
+    for (const customField of customFields) {
+        if (propMap.hasOwnProperty(customField.name)) {
+            const message = `Custom field name conflict: the "${entityName}" entity already has a built-in property "${
+                customField.name
+                }".`;
+            throw new Error(message);
+        }
+    }
+}
+
+/**
+ * For entities which are not localized (Address, Customer), we assert that none of the custom fields
+ * have a type "localeString".
+ */
+function assertNoLocaleStringFields(entity: Type<any>, customFields: CustomFieldConfig[]): void {
+    if (!!customFields.find(f => f.type === 'localeString')) {
+        const message = `Custom field type error: the "${
+            entity.name
+            }" entity does not support the "localeString" type.`;
+        throw new Error(message);
+    }
+}
+
+/**
+ * Validates the custom fields config, e.g. by ensuring that there are no naming conflicts with the built-in fields
+ * of each entity.
+ */
+export async function validateCustomFieldsConfig(customFieldConfig: CustomFields) {
+    const connection = getConnection();
+    // dynamic import to avoid bootstrap-time order of loading issues
+    const {coreEntitiesMap} = await import('./entities');
+
+    for (const key of Object.keys(customFieldConfig)) {
+        const entityName = key as keyof CustomFields;
+        const customEntityFields = customFieldConfig[entityName] || [];
+        const entity = coreEntitiesMap[entityName];
+        validateCustomFieldsForEntity(connection, entity, customEntityFields);
+    }
+}