1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-03-23 00:16:25 +01:00

refactor: tag type service feature oriented architecture and tx support (#5489)

This commit is contained in:
Mateusz Kwasniewski 2023-11-29 11:44:56 +01:00 committed by GitHub
parent 5d0904f99d
commit 7a6cb0c527
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 124 additions and 51 deletions

View File

@ -11,7 +11,7 @@ import SettingStore from './setting-store';
import UserStore from './user-store'; import UserStore from './user-store';
import ProjectStore from './project-store'; import ProjectStore from './project-store';
import TagStore from './tag-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 AddonStore from './addon-store';
import { ApiTokenStore } from './api-token-store'; import { ApiTokenStore } from './api-token-store';
import SessionStore from './session-store'; import SessionStore from './session-store';

View File

@ -18,7 +18,6 @@ import {
ParentFeatureOptionsSchema, ParentFeatureOptionsSchema,
} from '../../openapi'; } from '../../openapi';
import { IAuthRequest } from '../../routes/unleash-types'; import { IAuthRequest } from '../../routes/unleash-types';
import { InvalidOperationError } from '../../error';
import { DependentFeaturesService } from './dependent-features-service'; import { DependentFeaturesService } from './dependent-features-service';
import { WithTransactional } from '../../db/transaction'; import { WithTransactional } from '../../db/transaction';

View File

@ -4,7 +4,7 @@ import ExportImportService from './export-import-service';
import { ImportTogglesStore } from './import-toggles-store'; import { ImportTogglesStore } from './import-toggles-store';
import FeatureToggleStore from '../feature-toggle/feature-toggle-store'; import FeatureToggleStore from '../feature-toggle/feature-toggle-store';
import TagStore from '../../db/tag-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 ProjectStore from '../../db/project-store';
import FeatureTagStore from '../../db/feature-tag-store'; import FeatureTagStore from '../../db/feature-tag-store';
import StrategyStore from '../../db/strategy-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 { FeatureEnvironmentStore } from '../../db/feature-environment-store';
import FakeFeatureToggleStore from '../feature-toggle/fakes/fake-feature-toggle-store'; import FakeFeatureToggleStore from '../feature-toggle/fakes/fake-feature-toggle-store';
import FakeTagStore from '../../../test/fixtures/fake-tag-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 FakeSegmentStore from '../../../test/fixtures/fake-segment-store';
import FakeProjectStore from '../../../test/fixtures/fake-project-store'; import FakeProjectStore from '../../../test/fixtures/fake-project-store';
import FakeFeatureTagStore from '../../../test/fixtures/fake-feature-tag-store'; import FakeFeatureTagStore from '../../../test/fixtures/fake-feature-tag-store';

View File

@ -1,7 +1,7 @@
import { IImportTogglesStore } from './import-toggles-store-type'; import { IImportTogglesStore } from './import-toggles-store-type';
import { AccessService, ContextService, TagTypeService } from '../../services'; import { AccessService, ContextService, TagTypeService } from '../../services';
import { ContextFieldSchema, ImportTogglesSchema } from '../../openapi'; 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 { IUser } from '../../types/user';
import { import {
CREATE_CONTEXT_FIELD, CREATE_CONTEXT_FIELD,

View File

@ -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);
};

View File

@ -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 { export default class FakeTagTypeStore implements ITagTypeStore {
tagTypes: ITagType[] = []; tagTypes: ITagType[] = [];

View File

@ -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 { import {
TAG_TYPE_CREATED, TAG_TYPE_CREATED,
TAG_TYPE_DELETED, TAG_TYPE_DELETED,
TAG_TYPE_UPDATED, TAG_TYPE_UPDATED,
} from '../types/events'; } from '../../types/events';
import { Logger } from '../logger'; import { Logger } from '../../logger';
import { ITagType, ITagTypeStore } from '../types/stores/tag-type-store'; import { ITagType, ITagTypeStore } from './tag-type-store-type';
import { IUnleashConfig } from '../types/option'; import { IUnleashConfig } from '../../types/option';
import EventService from './event-service'; import EventService from '../../services/event-service';
export default class TagTypeService { export default class TagTypeService {
private tagTypeStore: ITagTypeStore; private tagTypeStore: ITagTypeStore;

View File

@ -1,4 +1,4 @@
import { Store } from './store'; import { Store } from '../../types/stores/store';
export interface ITagType { export interface ITagType {
name: string; name: string;

View File

@ -1,10 +1,10 @@
import { EventEmitter } from 'events'; import { EventEmitter } from 'events';
import { LogProvider, Logger } from '../logger'; import { LogProvider, Logger } from '../../logger';
import { DB_TIME } from '../metric-events'; import { DB_TIME } from '../../metric-events';
import metricsHelper from '../util/metrics-helper'; import metricsHelper from '../../util/metrics-helper';
import NotFoundError from '../error/notfound-error'; import NotFoundError from '../../error/notfound-error';
import { ITagType, ITagTypeStore } from '../types/stores/tag-type-store'; import { ITagType, ITagTypeStore } from './tag-type-store-type';
import { Db } from './db'; import { Db } from '../../db/db';
const COLUMNS = ['name', 'description', 'icon']; const COLUMNS = ['name', 'description', 'icon'];
const TABLE = 'tag_types'; const TABLE = 'tag_types';

View File

@ -1,5 +1,5 @@
import { Request, Response } from 'express'; import { Request, Response } from 'express';
import Controller from '../controller'; import Controller from '../../routes/controller';
import { import {
CREATE_TAG_TYPE, CREATE_TAG_TYPE,
@ -10,9 +10,9 @@ import {
import { extractUsername } from '../../util/extract-user'; import { extractUsername } from '../../util/extract-user';
import { IUnleashConfig } from '../../types/option'; import { IUnleashConfig } from '../../types/option';
import { IUnleashServices } from '../../types/services'; import { IUnleashServices } from '../../types/services';
import TagTypeService from '../../services/tag-type-service'; import TagTypeService from './tag-type-service';
import { Logger } from '../../logger'; import { Logger } from '../../logger';
import { IAuthRequest } from '../unleash-types'; import { IAuthRequest } from '../../routes/unleash-types';
import { createRequestSchema } from '../../openapi/util/create-request-schema'; import { createRequestSchema } from '../../openapi/util/create-request-schema';
import { import {
createResponseSchema, createResponseSchema,
@ -30,26 +30,30 @@ import {
emptyResponse, emptyResponse,
getStandardResponses, getStandardResponses,
} from '../../openapi/util/standard-responses'; } from '../../openapi/util/standard-responses';
import { WithTransactional } from '../../db/transaction';
const version = 1; const version = 1;
class TagTypeController extends Controller { class TagTypeController extends Controller {
private logger: Logger; private logger: Logger;
private tagTypeService: TagTypeService; private tagTypeService: WithTransactional<TagTypeService>;
private openApiService: OpenApiService; private openApiService: OpenApiService;
constructor( constructor(
config: IUnleashConfig, config: IUnleashConfig,
{ {
tagTypeService, transactionalTagTypeService,
openApiService, openApiService,
}: Pick<IUnleashServices, 'tagTypeService' | 'openApiService'>, }: Pick<
IUnleashServices,
'transactionalTagTypeService' | 'openApiService'
>,
) { ) {
super(config); super(config);
this.logger = config.getLogger('/admin-api/tag-type.js'); this.logger = config.getLogger('/admin-api/tag-type.js');
this.tagTypeService = tagTypeService; this.tagTypeService = transactionalTagTypeService;
this.openApiService = openApiService; this.openApiService = openApiService;
this.route({ this.route({
method: 'get', method: 'get',
@ -198,9 +202,8 @@ class TagTypeController extends Controller {
res: Response, res: Response,
): Promise<void> { ): Promise<void> {
const userName = extractUsername(req); const userName = extractUsername(req);
const tagType = await this.tagTypeService.createTagType( const tagType = await this.tagTypeService.transactional((service) =>
req.body, service.createTagType(req.body, userName),
userName,
); );
res.status(201) res.status(201)
.header('location', `tag-types/${tagType.name}`) .header('location', `tag-types/${tagType.name}`)
@ -215,9 +218,8 @@ class TagTypeController extends Controller {
const { name } = req.params; const { name } = req.params;
const userName = extractUsername(req); const userName = extractUsername(req);
await this.tagTypeService.updateTagType( await this.tagTypeService.transactional((service) =>
{ name, description, icon }, service.updateTagType({ name, description, icon }, userName),
userName,
); );
res.status(200).end(); res.status(200).end();
} }
@ -232,9 +234,12 @@ class TagTypeController extends Controller {
async deleteTagType(req: IAuthRequest, res: Response): Promise<void> { async deleteTagType(req: IAuthRequest, res: Response): Promise<void> {
const { name } = req.params; const { name } = req.params;
const userName = extractUsername(req); const userName = extractUsername(req);
await this.tagTypeService.deleteTagType(name, userName); await this.tagTypeService.transactional((service) =>
service.deleteTagType(name, userName),
);
res.status(200).end(); res.status(200).end();
} }
} }
export default TagTypeController; export default TagTypeController;
module.exports = TagTypeController; module.exports = TagTypeController;

View File

@ -1,13 +1,26 @@
import dbInit from '../../helpers/database-init'; import dbInit from '../../../test/e2e/helpers/database-init';
import { setupApp } from '../../helpers/test-helper'; import {
import getLogger from '../../../fixtures/no-logger'; setupApp,
setupAppWithCustomConfig,
} from '../../../test/e2e/helpers/test-helper';
import getLogger from '../../../test/fixtures/no-logger';
let app; let app;
let db; let db;
beforeAll(async () => { beforeAll(async () => {
db = await dbInit('tag_types_api_serial', getLogger); 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 () => { afterAll(async () => {

View File

@ -13,7 +13,7 @@ import { ContextController } from './context';
import ClientMetricsController from './client-metrics'; import ClientMetricsController from './client-metrics';
import StateController from './state'; import StateController from './state';
import TagController from './tag'; import TagController from './tag';
import TagTypeController from './tag-type'; import TagTypeController from '../../features/tag-type/tag-type';
import AddonController from './addon'; import AddonController from './addon';
import { ApiTokenController } from './api-token'; import { ApiTokenController } from './api-token';
import UserAdminController from './user-admin'; import UserAdminController from './user-admin';

View File

@ -1,7 +1,7 @@
import { ValidationError } from 'joi'; import { ValidationError } from 'joi';
import getLogger from '../../test/fixtures/no-logger'; import getLogger from '../../test/fixtures/no-logger';
import TagTypeService from './tag-type-service'; import TagTypeService from '../features/tag-type/tag-type-service';
import { import {
ADDON_CONFIG_CREATED, ADDON_CONFIG_CREATED,
ADDON_CONFIG_DELETED, ADDON_CONFIG_DELETED,

View File

@ -6,7 +6,7 @@ import { addonSchema } from './addon-schema';
import NameExistsError from '../error/name-exists-error'; import NameExistsError from '../error/name-exists-error';
import { IFeatureToggleStore } from '../features/feature-toggle/types/feature-toggle-store-type'; import { IFeatureToggleStore } from '../features/feature-toggle/types/feature-toggle-store-type';
import { Logger } from '../logger'; 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 { IAddon, IAddonDto, IAddonStore } from '../types/stores/addon-store';
import { IUnleashStores, IUnleashConfig } from '../types'; import { IUnleashStores, IUnleashConfig } from '../types';
import { IAddonDefinition } from '../types/model'; import { IAddonDefinition } from '../types/model';

View File

@ -7,7 +7,7 @@ import ProjectService from './project-service';
import StateService from './state-service'; import StateService from './state-service';
import ClientInstanceService from './client-metrics/instance-service'; import ClientInstanceService from './client-metrics/instance-service';
import ClientMetricsServiceV2 from './client-metrics/metrics-service-v2'; 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 TagService from './tag-service';
import StrategyService from './strategy-service'; import StrategyService from './strategy-service';
import AddonService from './addon-service'; import AddonService from './addon-service';
@ -98,6 +98,10 @@ import {
createFakeFeatureSearchService, createFakeFeatureSearchService,
} from '../features/feature-search/createFeatureSearchService'; } from '../features/feature-search/createFeatureSearchService';
import { FeatureSearchService } from '../features/feature-search/feature-search-service'; import { FeatureSearchService } from '../features/feature-search/feature-search-service';
import {
createFakeTagTypeService,
createTagTypeService,
} from '../features/tag-type/createTagTypeService';
export const createServices = ( export const createServices = (
stores: IUnleashStores, stores: IUnleashStores,
@ -144,7 +148,10 @@ export const createServices = (
const stateService = new StateService(stores, config, eventService); const stateService = new StateService(stores, config, eventService);
const strategyService = new StrategyService(stores, config, eventService); const strategyService = new StrategyService(stores, config, eventService);
const tagService = new TagService(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( const addonService = new AddonService(
stores, stores,
config, config,
@ -321,6 +328,7 @@ export const createServices = (
stateService, stateService,
strategyService, strategyService,
tagTypeService, tagTypeService,
transactionalTagTypeService,
tagService, tagService,
clientInstanceService, clientInstanceService,
clientMetricsServiceV2, clientMetricsServiceV2,

View File

@ -37,7 +37,10 @@ import {
IFeatureTagStore, IFeatureTagStore,
} from '../types/stores/feature-tag-store'; } from '../types/stores/feature-tag-store';
import { IProjectStore } from '../types/stores/project-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 { ITagStore } from '../types/stores/tag-store';
import { IStrategy, IStrategyStore } from '../types/stores/strategy-store'; import { IStrategy, IStrategyStore } from '../types/stores/strategy-store';
import { IFeatureToggleStore } from '../features/feature-toggle/types/feature-toggle-store-type'; import { IFeatureToggleStore } from '../features/feature-toggle/types/feature-toggle-store-type';

View File

@ -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 { LogProvider } from '../logger';
import { IRole } from './stores/access-store'; import { IRole } from './stores/access-store';
import { IUser } from './user'; import { IUser } from './user';

View File

@ -3,7 +3,7 @@ import AddonService from '../services/addon-service';
import ProjectService from '../services/project-service'; import ProjectService from '../services/project-service';
import StateService from '../services/state-service'; import StateService from '../services/state-service';
import StrategyService from '../services/strategy-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 TagService from '../services/tag-service';
import ClientInstanceService from '../services/client-metrics/instance-service'; import ClientInstanceService from '../services/client-metrics/instance-service';
import ContextService from '../services/context-service'; import ContextService from '../services/context-service';
@ -83,6 +83,7 @@ export interface IUnleashServices {
strategyService: StrategyService; strategyService: StrategyService;
tagService: TagService; tagService: TagService;
tagTypeService: TagTypeService; tagTypeService: TagTypeService;
transactionalTagTypeService: WithTransactional<TagTypeService>;
userFeedbackService: UserFeedbackService; userFeedbackService: UserFeedbackService;
userService: UserService; userService: UserService;
versionService: VersionService; versionService: VersionService;

View File

@ -9,7 +9,7 @@ import { IContextFieldStore } from './stores/context-field-store';
import { ISettingStore } from './stores/settings-store'; import { ISettingStore } from './stores/settings-store';
import { ISessionStore } from './stores/session-store'; import { ISessionStore } from './stores/session-store';
import { ITagStore } from './stores/tag-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 { IFeatureTagStore } from './stores/feature-tag-store';
import { IUserStore } from './stores/user-store'; import { IUserStore } from './stores/user-store';
import { IAddonStore } from './stores/addon-store'; import { IAddonStore } from './stores/addon-store';

View File

@ -5,7 +5,7 @@ import AddonService from '../../../lib/services/addon-service';
import { IUnleashStores } from '../../../lib/types'; import { IUnleashStores } from '../../../lib/types';
import SimpleAddon from '../../../lib/services/addon-service-test-simple-addon'; 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 { FEATURE_CREATED } from '../../../lib/types/events';
import { EventService } from '../../../lib/services'; import { EventService } from '../../../lib/services';

View File

@ -3,7 +3,7 @@ import FakeClientInstanceStore from './fake-client-instance-store';
import FakeClientApplicationsStore from './fake-client-applications-store'; import FakeClientApplicationsStore from './fake-client-applications-store';
import FakeFeatureToggleStore from '../../lib/features/feature-toggle/fakes/fake-feature-toggle-store'; import FakeFeatureToggleStore from '../../lib/features/feature-toggle/fakes/fake-feature-toggle-store';
import FakeTagStore from './fake-tag-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 FakeEventStore from './fake-event-store';
import FakeContextFieldStore from './fake-context-field-store'; import FakeContextFieldStore from './fake-context-field-store';
import FakeSettingStore from './fake-setting-store'; import FakeSettingStore from './fake-setting-store';