diff --git a/src/lib/db/index.ts b/src/lib/db/index.ts index 315faf4313..24d7ca757b 100644 --- a/src/lib/db/index.ts +++ b/src/lib/db/index.ts @@ -11,7 +11,7 @@ import SettingStore from './setting-store'; import UserStore from './user-store'; import ProjectStore from './project-store'; import TagStore from './tag-store'; -import TagTypeStore from './tag-type-store'; +import TagTypeStore from '../features/tag-type/tag-type-store'; import AddonStore from './addon-store'; import { ApiTokenStore } from './api-token-store'; import SessionStore from './session-store'; diff --git a/src/lib/features/dependent-features/dependent-features-controller.ts b/src/lib/features/dependent-features/dependent-features-controller.ts index 2faa9187bd..b2e58d5317 100644 --- a/src/lib/features/dependent-features/dependent-features-controller.ts +++ b/src/lib/features/dependent-features/dependent-features-controller.ts @@ -18,7 +18,6 @@ import { ParentFeatureOptionsSchema, } from '../../openapi'; import { IAuthRequest } from '../../routes/unleash-types'; -import { InvalidOperationError } from '../../error'; import { DependentFeaturesService } from './dependent-features-service'; import { WithTransactional } from '../../db/transaction'; diff --git a/src/lib/features/export-import-toggles/createExportImportService.ts b/src/lib/features/export-import-toggles/createExportImportService.ts index b34bf419e6..da24c9e1a8 100644 --- a/src/lib/features/export-import-toggles/createExportImportService.ts +++ b/src/lib/features/export-import-toggles/createExportImportService.ts @@ -4,7 +4,7 @@ import ExportImportService from './export-import-service'; import { ImportTogglesStore } from './import-toggles-store'; import FeatureToggleStore from '../feature-toggle/feature-toggle-store'; import TagStore from '../../db/tag-store'; -import TagTypeStore from '../../db/tag-type-store'; +import TagTypeStore from '../tag-type/tag-type-store'; import ProjectStore from '../../db/project-store'; import FeatureTagStore from '../../db/feature-tag-store'; import StrategyStore from '../../db/strategy-store'; @@ -29,7 +29,7 @@ import SegmentStore from '../../db/segment-store'; import { FeatureEnvironmentStore } from '../../db/feature-environment-store'; import FakeFeatureToggleStore from '../feature-toggle/fakes/fake-feature-toggle-store'; import FakeTagStore from '../../../test/fixtures/fake-tag-store'; -import FakeTagTypeStore from '../../../test/fixtures/fake-tag-type-store'; +import FakeTagTypeStore from '../tag-type/fake-tag-type-store'; import FakeSegmentStore from '../../../test/fixtures/fake-segment-store'; import FakeProjectStore from '../../../test/fixtures/fake-project-store'; import FakeFeatureTagStore from '../../../test/fixtures/fake-feature-tag-store'; diff --git a/src/lib/features/export-import-toggles/import-permissions-service.ts b/src/lib/features/export-import-toggles/import-permissions-service.ts index ddf54f9a32..678ecdcbaf 100644 --- a/src/lib/features/export-import-toggles/import-permissions-service.ts +++ b/src/lib/features/export-import-toggles/import-permissions-service.ts @@ -1,7 +1,7 @@ import { IImportTogglesStore } from './import-toggles-store-type'; import { AccessService, ContextService, TagTypeService } from '../../services'; import { ContextFieldSchema, ImportTogglesSchema } from '../../openapi'; -import { ITagType } from '../../types/stores/tag-type-store'; +import { ITagType } from '../tag-type/tag-type-store-type'; import { IUser } from '../../types/user'; import { CREATE_CONTEXT_FIELD, diff --git a/src/lib/features/tag-type/createTagTypeService.ts b/src/lib/features/tag-type/createTagTypeService.ts new file mode 100644 index 0000000000..dc49ba70b7 --- /dev/null +++ b/src/lib/features/tag-type/createTagTypeService.ts @@ -0,0 +1,44 @@ +import { Db } from '../../db/db'; +import EventStore from '../../db/event-store'; +import { IUnleashConfig } from '../../types'; +import { EventService } from '../../services'; +import FeatureTagStore from '../../db/feature-tag-store'; +import FakeEventStore from '../../../test/fixtures/fake-event-store'; +import FakeFeatureTagStore from '../../../test/fixtures/fake-feature-tag-store'; +import TagTypeService from './tag-type-service'; +import TagTypeStore from './tag-type-store'; +import FakeTagTypeStore from './fake-tag-type-store'; + +export const createTagTypeService = + (config: IUnleashConfig) => + (db: Db): TagTypeService => { + const { getLogger, eventBus } = config; + const eventStore = new EventStore(db, getLogger); + const featureTagStore = new FeatureTagStore(db, eventBus, getLogger); + const eventService = new EventService( + { + eventStore, + featureTagStore, + }, + config, + ); + const tagTypeStore = new TagTypeStore(db, eventBus, getLogger); + return new TagTypeService({ tagTypeStore }, config, eventService); + }; + +export const createFakeTagTypeService = ( + config: IUnleashConfig, +): TagTypeService => { + const eventStore = new FakeEventStore(); + const featureTagStore = new FakeFeatureTagStore(); + const eventService = new EventService( + { + eventStore, + featureTagStore, + }, + config, + ); + const tagTypeStore = new FakeTagTypeStore(); + + return new TagTypeService({ tagTypeStore }, config, eventService); +}; diff --git a/src/test/fixtures/fake-tag-type-store.ts b/src/lib/features/tag-type/fake-tag-type-store.ts similarity index 89% rename from src/test/fixtures/fake-tag-type-store.ts rename to src/lib/features/tag-type/fake-tag-type-store.ts index 3935fa2cb7..49a981702e 100644 --- a/src/test/fixtures/fake-tag-type-store.ts +++ b/src/lib/features/tag-type/fake-tag-type-store.ts @@ -1,6 +1,6 @@ -import { ITagType, ITagTypeStore } from '../../lib/types/stores/tag-type-store'; +import { ITagType, ITagTypeStore } from './tag-type-store-type'; -const NotFoundError = require('../../lib/error/notfound-error'); +const NotFoundError = require('../../error/notfound-error'); export default class FakeTagTypeStore implements ITagTypeStore { tagTypes: ITagType[] = []; diff --git a/src/lib/services/tag-type-service.ts b/src/lib/features/tag-type/tag-type-service.ts similarity index 86% rename from src/lib/services/tag-type-service.ts rename to src/lib/features/tag-type/tag-type-service.ts index 91a531a1e4..e04464db0f 100644 --- a/src/lib/services/tag-type-service.ts +++ b/src/lib/features/tag-type/tag-type-service.ts @@ -1,18 +1,18 @@ -import NameExistsError from '../error/name-exists-error'; +import NameExistsError from '../../error/name-exists-error'; -import { tagTypeSchema } from './tag-type-schema'; +import { tagTypeSchema } from '../../services/tag-type-schema'; -import { IUnleashStores } from '../types/stores'; +import { IUnleashStores } from '../../types/stores'; import { TAG_TYPE_CREATED, TAG_TYPE_DELETED, TAG_TYPE_UPDATED, -} from '../types/events'; +} from '../../types/events'; -import { Logger } from '../logger'; -import { ITagType, ITagTypeStore } from '../types/stores/tag-type-store'; -import { IUnleashConfig } from '../types/option'; -import EventService from './event-service'; +import { Logger } from '../../logger'; +import { ITagType, ITagTypeStore } from './tag-type-store-type'; +import { IUnleashConfig } from '../../types/option'; +import EventService from '../../services/event-service'; export default class TagTypeService { private tagTypeStore: ITagTypeStore; diff --git a/src/lib/types/stores/tag-type-store.ts b/src/lib/features/tag-type/tag-type-store-type.ts similarity index 87% rename from src/lib/types/stores/tag-type-store.ts rename to src/lib/features/tag-type/tag-type-store-type.ts index 8058fc0e03..1aae875bce 100644 --- a/src/lib/types/stores/tag-type-store.ts +++ b/src/lib/features/tag-type/tag-type-store-type.ts @@ -1,4 +1,4 @@ -import { Store } from './store'; +import { Store } from '../../types/stores/store'; export interface ITagType { name: string; diff --git a/src/lib/db/tag-type-store.ts b/src/lib/features/tag-type/tag-type-store.ts similarity index 90% rename from src/lib/db/tag-type-store.ts rename to src/lib/features/tag-type/tag-type-store.ts index c2c20b812b..1973779abb 100644 --- a/src/lib/db/tag-type-store.ts +++ b/src/lib/features/tag-type/tag-type-store.ts @@ -1,10 +1,10 @@ import { EventEmitter } from 'events'; -import { LogProvider, Logger } from '../logger'; -import { DB_TIME } from '../metric-events'; -import metricsHelper from '../util/metrics-helper'; -import NotFoundError from '../error/notfound-error'; -import { ITagType, ITagTypeStore } from '../types/stores/tag-type-store'; -import { Db } from './db'; +import { LogProvider, Logger } from '../../logger'; +import { DB_TIME } from '../../metric-events'; +import metricsHelper from '../../util/metrics-helper'; +import NotFoundError from '../../error/notfound-error'; +import { ITagType, ITagTypeStore } from './tag-type-store-type'; +import { Db } from '../../db/db'; const COLUMNS = ['name', 'description', 'icon']; const TABLE = 'tag_types'; diff --git a/src/lib/routes/admin-api/tag-type.ts b/src/lib/features/tag-type/tag-type.ts similarity index 89% rename from src/lib/routes/admin-api/tag-type.ts rename to src/lib/features/tag-type/tag-type.ts index ffb2eaa155..157484223f 100644 --- a/src/lib/routes/admin-api/tag-type.ts +++ b/src/lib/features/tag-type/tag-type.ts @@ -1,5 +1,5 @@ import { Request, Response } from 'express'; -import Controller from '../controller'; +import Controller from '../../routes/controller'; import { CREATE_TAG_TYPE, @@ -10,9 +10,9 @@ import { import { extractUsername } from '../../util/extract-user'; import { IUnleashConfig } from '../../types/option'; import { IUnleashServices } from '../../types/services'; -import TagTypeService from '../../services/tag-type-service'; +import TagTypeService from './tag-type-service'; import { Logger } from '../../logger'; -import { IAuthRequest } from '../unleash-types'; +import { IAuthRequest } from '../../routes/unleash-types'; import { createRequestSchema } from '../../openapi/util/create-request-schema'; import { createResponseSchema, @@ -30,26 +30,30 @@ import { emptyResponse, getStandardResponses, } from '../../openapi/util/standard-responses'; +import { WithTransactional } from '../../db/transaction'; const version = 1; class TagTypeController extends Controller { private logger: Logger; - private tagTypeService: TagTypeService; + private tagTypeService: WithTransactional; private openApiService: OpenApiService; constructor( config: IUnleashConfig, { - tagTypeService, + transactionalTagTypeService, openApiService, - }: Pick, + }: Pick< + IUnleashServices, + 'transactionalTagTypeService' | 'openApiService' + >, ) { super(config); this.logger = config.getLogger('/admin-api/tag-type.js'); - this.tagTypeService = tagTypeService; + this.tagTypeService = transactionalTagTypeService; this.openApiService = openApiService; this.route({ method: 'get', @@ -198,9 +202,8 @@ class TagTypeController extends Controller { res: Response, ): Promise { const userName = extractUsername(req); - const tagType = await this.tagTypeService.createTagType( - req.body, - userName, + const tagType = await this.tagTypeService.transactional((service) => + service.createTagType(req.body, userName), ); res.status(201) .header('location', `tag-types/${tagType.name}`) @@ -215,9 +218,8 @@ class TagTypeController extends Controller { const { name } = req.params; const userName = extractUsername(req); - await this.tagTypeService.updateTagType( - { name, description, icon }, - userName, + await this.tagTypeService.transactional((service) => + service.updateTagType({ name, description, icon }, userName), ); res.status(200).end(); } @@ -232,9 +234,12 @@ class TagTypeController extends Controller { async deleteTagType(req: IAuthRequest, res: Response): Promise { const { name } = req.params; const userName = extractUsername(req); - await this.tagTypeService.deleteTagType(name, userName); + await this.tagTypeService.transactional((service) => + service.deleteTagType(name, userName), + ); res.status(200).end(); } } + export default TagTypeController; module.exports = TagTypeController; diff --git a/src/test/e2e/api/admin/tag-types.e2e.test.ts b/src/lib/features/tag-type/tag-types.e2e.test.ts similarity index 92% rename from src/test/e2e/api/admin/tag-types.e2e.test.ts rename to src/lib/features/tag-type/tag-types.e2e.test.ts index 2134ea0191..8c40b95eaf 100644 --- a/src/test/e2e/api/admin/tag-types.e2e.test.ts +++ b/src/lib/features/tag-type/tag-types.e2e.test.ts @@ -1,13 +1,26 @@ -import dbInit from '../../helpers/database-init'; -import { setupApp } from '../../helpers/test-helper'; -import getLogger from '../../../fixtures/no-logger'; +import dbInit from '../../../test/e2e/helpers/database-init'; +import { + setupApp, + setupAppWithCustomConfig, +} from '../../../test/e2e/helpers/test-helper'; +import getLogger from '../../../test/fixtures/no-logger'; let app; let db; beforeAll(async () => { db = await dbInit('tag_types_api_serial', getLogger); - app = await setupApp(db.stores); + app = await setupAppWithCustomConfig( + db.stores, + { + experimental: { + flags: { + strictSchemaValidation: true, + }, + }, + }, + db.rawDatabase, + ); }); afterAll(async () => { diff --git a/src/lib/routes/admin-api/index.ts b/src/lib/routes/admin-api/index.ts index 6efbdf6fb2..abc4873cf7 100644 --- a/src/lib/routes/admin-api/index.ts +++ b/src/lib/routes/admin-api/index.ts @@ -13,7 +13,7 @@ import { ContextController } from './context'; import ClientMetricsController from './client-metrics'; import StateController from './state'; import TagController from './tag'; -import TagTypeController from './tag-type'; +import TagTypeController from '../../features/tag-type/tag-type'; import AddonController from './addon'; import { ApiTokenController } from './api-token'; import UserAdminController from './user-admin'; diff --git a/src/lib/services/addon-service.test.ts b/src/lib/services/addon-service.test.ts index 5ee506a238..8c7451500e 100644 --- a/src/lib/services/addon-service.test.ts +++ b/src/lib/services/addon-service.test.ts @@ -1,7 +1,7 @@ import { ValidationError } from 'joi'; import getLogger from '../../test/fixtures/no-logger'; -import TagTypeService from './tag-type-service'; +import TagTypeService from '../features/tag-type/tag-type-service'; import { ADDON_CONFIG_CREATED, ADDON_CONFIG_DELETED, diff --git a/src/lib/services/addon-service.ts b/src/lib/services/addon-service.ts index c802adb802..622c34afa6 100644 --- a/src/lib/services/addon-service.ts +++ b/src/lib/services/addon-service.ts @@ -6,7 +6,7 @@ import { addonSchema } from './addon-schema'; import NameExistsError from '../error/name-exists-error'; import { IFeatureToggleStore } from '../features/feature-toggle/types/feature-toggle-store-type'; import { Logger } from '../logger'; -import TagTypeService from './tag-type-service'; +import TagTypeService from '../features/tag-type/tag-type-service'; import { IAddon, IAddonDto, IAddonStore } from '../types/stores/addon-store'; import { IUnleashStores, IUnleashConfig } from '../types'; import { IAddonDefinition } from '../types/model'; diff --git a/src/lib/services/index.ts b/src/lib/services/index.ts index a5c61d1670..18d524c5c1 100644 --- a/src/lib/services/index.ts +++ b/src/lib/services/index.ts @@ -7,7 +7,7 @@ import ProjectService from './project-service'; import StateService from './state-service'; import ClientInstanceService from './client-metrics/instance-service'; import ClientMetricsServiceV2 from './client-metrics/metrics-service-v2'; -import TagTypeService from './tag-type-service'; +import TagTypeService from '../features/tag-type/tag-type-service'; import TagService from './tag-service'; import StrategyService from './strategy-service'; import AddonService from './addon-service'; @@ -98,6 +98,10 @@ import { createFakeFeatureSearchService, } from '../features/feature-search/createFeatureSearchService'; import { FeatureSearchService } from '../features/feature-search/feature-search-service'; +import { + createFakeTagTypeService, + createTagTypeService, +} from '../features/tag-type/createTagTypeService'; export const createServices = ( stores: IUnleashStores, @@ -144,7 +148,10 @@ export const createServices = ( const stateService = new StateService(stores, config, eventService); const strategyService = new StrategyService(stores, config, eventService); const tagService = new TagService(stores, config, eventService); - const tagTypeService = new TagTypeService(stores, config, eventService); + const transactionalTagTypeService = db + ? withTransactional(createTagTypeService(config), db) + : withFakeTransactional(createFakeTagTypeService(config)); + const tagTypeService = transactionalTagTypeService; const addonService = new AddonService( stores, config, @@ -321,6 +328,7 @@ export const createServices = ( stateService, strategyService, tagTypeService, + transactionalTagTypeService, tagService, clientInstanceService, clientMetricsServiceV2, diff --git a/src/lib/services/state-service.ts b/src/lib/services/state-service.ts index da0a835a00..94541a45e3 100644 --- a/src/lib/services/state-service.ts +++ b/src/lib/services/state-service.ts @@ -37,7 +37,10 @@ import { IFeatureTagStore, } from '../types/stores/feature-tag-store'; import { IProjectStore } from '../types/stores/project-store'; -import { ITagType, ITagTypeStore } from '../types/stores/tag-type-store'; +import { + ITagType, + ITagTypeStore, +} from '../features/tag-type/tag-type-store-type'; import { ITagStore } from '../types/stores/tag-store'; import { IStrategy, IStrategyStore } from '../types/stores/strategy-store'; import { IFeatureToggleStore } from '../features/feature-toggle/types/feature-toggle-store-type'; diff --git a/src/lib/types/model.ts b/src/lib/types/model.ts index e2d5043b3a..4b3b45c766 100644 --- a/src/lib/types/model.ts +++ b/src/lib/types/model.ts @@ -1,4 +1,4 @@ -import { ITagType } from './stores/tag-type-store'; +import { ITagType } from '../features/tag-type/tag-type-store-type'; import { LogProvider } from '../logger'; import { IRole } from './stores/access-store'; import { IUser } from './user'; diff --git a/src/lib/types/services.ts b/src/lib/types/services.ts index f42043d82b..80b0e1069c 100644 --- a/src/lib/types/services.ts +++ b/src/lib/types/services.ts @@ -3,7 +3,7 @@ import AddonService from '../services/addon-service'; import ProjectService from '../services/project-service'; import StateService from '../services/state-service'; import StrategyService from '../services/strategy-service'; -import TagTypeService from '../services/tag-type-service'; +import TagTypeService from '../features/tag-type/tag-type-service'; import TagService from '../services/tag-service'; import ClientInstanceService from '../services/client-metrics/instance-service'; import ContextService from '../services/context-service'; @@ -83,6 +83,7 @@ export interface IUnleashServices { strategyService: StrategyService; tagService: TagService; tagTypeService: TagTypeService; + transactionalTagTypeService: WithTransactional; userFeedbackService: UserFeedbackService; userService: UserService; versionService: VersionService; diff --git a/src/lib/types/stores.ts b/src/lib/types/stores.ts index 52b8a4a59c..f5b30feece 100644 --- a/src/lib/types/stores.ts +++ b/src/lib/types/stores.ts @@ -9,7 +9,7 @@ import { IContextFieldStore } from './stores/context-field-store'; import { ISettingStore } from './stores/settings-store'; import { ISessionStore } from './stores/session-store'; import { ITagStore } from './stores/tag-store'; -import { ITagTypeStore } from './stores/tag-type-store'; +import { ITagTypeStore } from '../features/tag-type/tag-type-store-type'; import { IFeatureTagStore } from './stores/feature-tag-store'; import { IUserStore } from './stores/user-store'; import { IAddonStore } from './stores/addon-store'; diff --git a/src/test/e2e/services/addon-service.e2e.test.ts b/src/test/e2e/services/addon-service.e2e.test.ts index 20406d07f8..085c90b8df 100644 --- a/src/test/e2e/services/addon-service.e2e.test.ts +++ b/src/test/e2e/services/addon-service.e2e.test.ts @@ -5,7 +5,7 @@ import AddonService from '../../../lib/services/addon-service'; import { IUnleashStores } from '../../../lib/types'; import SimpleAddon from '../../../lib/services/addon-service-test-simple-addon'; -import TagTypeService from '../../../lib/services/tag-type-service'; +import TagTypeService from '../../../lib/features/tag-type/tag-type-service'; import { FEATURE_CREATED } from '../../../lib/types/events'; import { EventService } from '../../../lib/services'; diff --git a/src/test/fixtures/store.ts b/src/test/fixtures/store.ts index 61228b9632..5d022810e5 100644 --- a/src/test/fixtures/store.ts +++ b/src/test/fixtures/store.ts @@ -3,7 +3,7 @@ import FakeClientInstanceStore from './fake-client-instance-store'; import FakeClientApplicationsStore from './fake-client-applications-store'; import FakeFeatureToggleStore from '../../lib/features/feature-toggle/fakes/fake-feature-toggle-store'; import FakeTagStore from './fake-tag-store'; -import FakeTagTypeStore from './fake-tag-type-store'; +import FakeTagTypeStore from '../../lib/features/tag-type/fake-tag-type-store'; import FakeEventStore from './fake-event-store'; import FakeContextFieldStore from './fake-context-field-store'; import FakeSettingStore from './fake-setting-store';