From 3029564304a82e4143f4289da897d371397ad0b6 Mon Sep 17 00:00:00 2001 From: Fredrik Strand Oseberg Date: Mon, 31 Oct 2022 10:35:59 +0100 Subject: [PATCH] Feat/enterprise stores (#2289) * feat: add capabilities for stores in enterprise * fix: remove unused files --- src/lib/app.ts | 6 +- src/lib/db/index.ts | 2 - src/lib/db/suggest-change-store.ts | 277 ------------------ src/lib/server-impl.ts | 2 +- src/lib/types/stores.ts | 2 - src/lib/types/stores/suggest-change-store.ts | 44 --- .../fixtures/fake-suggest-change-store.ts | 114 ------- src/test/fixtures/store.ts | 2 - 8 files changed, 5 insertions(+), 444 deletions(-) delete mode 100644 src/lib/db/suggest-change-store.ts delete mode 100644 src/lib/types/stores/suggest-change-store.ts delete mode 100644 src/test/fixtures/fake-suggest-change-store.ts diff --git a/src/lib/app.ts b/src/lib/app.ts index 879ddc0688d..68b5d3b718a 100644 --- a/src/lib/app.ts +++ b/src/lib/app.ts @@ -24,12 +24,14 @@ import { loadIndexHTML } from './util/load-index-html'; import { findPublicFolder } from './util/findPublicFolder'; import { conditionalMiddleware } from './middleware/conditional-middleware'; import patMiddleware from './middleware/pat-middleware'; +import { Knex } from 'knex'; export default async function getApp( config: IUnleashConfig, stores: IUnleashStores, services: IUnleashServices, unleashSession?: RequestHandler, + db?: Knex, ): Promise { const app = express(); @@ -48,7 +50,7 @@ export default async function getApp( app.use(requestLogger(config)); if (typeof config.preHook === 'function') { - config.preHook(app, config, services); + config.preHook(app, config, services, db); } app.use(compression()); @@ -137,7 +139,7 @@ export default async function getApp( ); if (typeof config.preRouterHook === 'function') { - config.preRouterHook(app, config, services, stores); + config.preRouterHook(app, config, services, stores, db); } // Setup API routes diff --git a/src/lib/db/index.ts b/src/lib/db/index.ts index 4d2e3d1bc75..693b77a0713 100644 --- a/src/lib/db/index.ts +++ b/src/lib/db/index.ts @@ -32,7 +32,6 @@ import SegmentStore from './segment-store'; import GroupStore from './group-store'; import PatStore from './pat-store'; import { PublicSignupTokenStore } from './public-signup-token-store'; -import { SuggestChangeStore } from './suggest-change-store'; export const createStores = ( config: IUnleashConfig, @@ -93,7 +92,6 @@ export const createStores = ( getLogger, ), patStore: new PatStore(db, getLogger), - suggestChangeStore: new SuggestChangeStore(db, eventBus, getLogger), }; }; diff --git a/src/lib/db/suggest-change-store.ts b/src/lib/db/suggest-change-store.ts deleted file mode 100644 index f778a92f3fe..00000000000 --- a/src/lib/db/suggest-change-store.ts +++ /dev/null @@ -1,277 +0,0 @@ -import { ISuggestChangeStore } from '../types/stores/suggest-change-store'; -import { Logger, LogProvider } from '../logger'; -import EventEmitter from 'events'; -import { Knex } from 'knex'; -import { PartialSome } from '../types/partial'; -import { - ISuggestChange, - ISuggestChangeset, - SuggestChangeAction, - SuggestChangesetState, -} from '../types/model'; - -const T = { - SUGGEST_CHANGE: 'suggest_change', - SUGGEST_CHANGE_SET: 'suggest_change_set', -}; - -interface ISuggestChangesetRow { - id: number; - state: SuggestChangesetState; - environment: string; - project: string; - created_at: Date; - created_by: number; - changeSetUsername: string; - changeSetAvatar: string; - changeId: number; - changeFeature: string; - changeAction: SuggestChangeAction; - changePayload: any; - changeCreatedAt: Date; - changeCreatedBy: number; - changeCreatedByUsername: string; - changeCreatedByAvatar: string; -} - -const suggestChangeRowReducer = ( - acc: Record, - suggestChangeRow: ISuggestChangesetRow, -): Record => { - const { - changeId, - changeAction, - changePayload, - changeFeature, - changeCreatedByUsername, - changeCreatedByAvatar, - changeCreatedAt, - changeCreatedBy, - ...suggestChangeSet - } = suggestChangeRow; - if (!acc[suggestChangeRow.id]) { - acc[suggestChangeRow.id] = { - id: suggestChangeSet.id, - environment: suggestChangeSet.environment, - state: suggestChangeSet.state, - project: suggestChangeSet.project, - createdBy: { - id: suggestChangeSet.created_by, - username: suggestChangeSet.changeSetUsername, - imageUrl: suggestChangeSet.changeSetAvatar, - }, - createdAt: suggestChangeSet.created_at, - features: [], - }; - } - const currentSuggestChangeSet = acc[suggestChangeSet.id]; - - if (changeId) { - const featureObject = currentSuggestChangeSet.features.find( - (feature) => feature.name === changeFeature, - ); - const change = { - id: changeId, - action: changeAction, - payload: changePayload, - createdAt: changeCreatedAt, - createdBy: { - id: changeCreatedBy, - username: changeCreatedByUsername, - imageUrl: changeCreatedByAvatar, - }, - }; - if (featureObject) { - featureObject.changes.push(change); - } else { - currentSuggestChangeSet.features.push({ - name: changeFeature, - changes: [change], - }); - } - } - return acc; -}; - -export class SuggestChangeStore implements ISuggestChangeStore { - private logger: Logger; - - private eventBus: EventEmitter; - - private db: Knex; - - constructor(db: Knex, eventBus: EventEmitter, getLogger: LogProvider) { - this.db = db; - this.eventBus = eventBus; - this.logger = getLogger('lib/db/suggest-change-store.ts'); - } - - private buildSuggestChangeSetChangesQuery = () => { - return this.db( - `${T.SUGGEST_CHANGE_SET} as changeSet`, - ) - .leftJoin( - `users as changeSetUser`, - 'changeSet.created_by', - 'changeSetUser.id', - ) - .leftJoin(`projects`, 'projects.id', 'changeSet.project') - .leftJoin( - `${T.SUGGEST_CHANGE} as change`, - 'changeSet.id', - 'change.suggest_change_set_id', - ) - .leftJoin( - `users as changeUser`, - 'change.created_by', - 'changeUser.id', - ) - .select( - 'changeSet.state', - 'changeSet.id', - 'changeSet.environment', - 'projects.name as project', - 'changeSet.created_at', - 'changeSet.created_by', - 'changeSetUser.username as changeSetUsername', - 'changeSetUser.image_url as changeSetAvatar', - 'change.id as changeId', - 'change.feature as changeFeature', - 'change.action as changeAction', - 'change.payload as changePayload', - 'change.created_at as changeCreatedAt', - 'change.created_by as changeCreatedBy', - 'changeUser.username as changeCreatedByUsername', - 'changeUser.image_url as changeCreatedByAvatar', - ); - }; - - getAll = async (): Promise => { - const rows = await this.buildSuggestChangeSetChangesQuery(); - return this.mapRows(rows); - }; - - getForProject = async (project: string): Promise => { - const rows = await this.buildSuggestChangeSetChangesQuery() - .where({ - project, - }) - .whereNot('state', SuggestChangesetState.DRAFT); - return this.mapRows(rows); - }; - - getDraftsForUser = async ( - userId: number, - project: string, - ): Promise => { - const rows = await this.buildSuggestChangeSetChangesQuery().where({ - 'changeSet.created_by': userId, - state: SuggestChangesetState.DRAFT, - project: project, - }); - const changesets = this.mapRows(rows); - return changesets; - }; - - getForEnvironment = async ( - environment: string, - ): Promise => { - const rows = await this.buildSuggestChangeSetChangesQuery().where({ - environment, - }); - - return this.mapRows(rows); - }; - - get = async (id: number): Promise => { - const rows = await this.buildSuggestChangeSetChangesQuery().where({ - 'changeSet.id': id, - }); - - return this.mapRows(rows)[0]; - }; - - create = async ( - suggestChangeSet: PartialSome< - ISuggestChangeset, - 'id' | 'createdBy' | 'createdAt' - >, - userId: number, - ): Promise => { - const [{ id }] = await this.db(T.SUGGEST_CHANGE_SET) - .insert({ - environment: suggestChangeSet.environment, - state: suggestChangeSet.state, - project: suggestChangeSet.project, - created_by: userId, - }) - .returning('id'); - - suggestChangeSet.features.forEach((feature) => { - feature.changes.forEach((change) => { - this.addChangeToSet(change, feature.name, id, userId); - }); - }); - - return this.get(id); - }; - - addChangeToSet = async ( - change: ISuggestChange, - feature: string, - changeSetID: number, - userId: number, - ): Promise => { - await this.db(T.SUGGEST_CHANGE) - .insert({ - action: change.action, - feature: feature, - payload: change.payload, - suggest_change_set_id: changeSetID, - created_by: userId, - }) - .onConflict(['action', 'suggest_change_set_id', 'feature']) - .merge() - .returning('id'); - }; - - delete = (id: number): Promise => { - return this.db(T.SUGGEST_CHANGE_SET).where({ id }).del(); - }; - - deleteChange = (id: number): Promise => { - return this.db(T.SUGGEST_CHANGE).where({ id }).del(); - }; - - deleteAll = (): Promise => { - return this.db(T.SUGGEST_CHANGE_SET).del(); - }; - - exists = async (id: number): Promise => { - const result = await this.db.raw( - `SELECT EXISTS(SELECT 1 FROM ${T.SUGGEST_CHANGE_SET} WHERE id = ?) AS present`, - [id], - ); - - return result.rows[0].present; - }; - - mapRows = (rows?: ISuggestChangesetRow[]): ISuggestChangeset[] => { - const suggestChangeSets = rows.reduce< - Record - >(suggestChangeRowReducer, {}); - return Object.values(suggestChangeSets); - }; - - destroy(): void {} - - async updateState( - id: number, - state: SuggestChangesetState, - ): Promise { - await this.db(T.SUGGEST_CHANGE_SET) - .update('state', state) - .where({ id }); - return this.get(id); - } -} diff --git a/src/lib/server-impl.ts b/src/lib/server-impl.ts index 514898c430c..4fec90857ff 100644 --- a/src/lib/server-impl.ts +++ b/src/lib/server-impl.ts @@ -57,7 +57,7 @@ async function createApp( // eslint-disable-next-line no-param-reassign config.server.secret = secret; } - const app = await getApp(config, stores, services, unleashSession); + const app = await getApp(config, stores, services, unleashSession, db); if (typeof config.eventHook === 'function') { addEventHook(config.eventHook, stores.eventStore); diff --git a/src/lib/types/stores.ts b/src/lib/types/stores.ts index 45237b25878..0d49d40af63 100644 --- a/src/lib/types/stores.ts +++ b/src/lib/types/stores.ts @@ -28,7 +28,6 @@ import { ISegmentStore } from './stores/segment-store'; import { IGroupStore } from './stores/group-store'; import { IPatStore } from './stores/pat-store'; import { IPublicSignupTokenStore } from './stores/public-signup-token-store'; -import { ISuggestChangeStore } from './stores/suggest-change-store'; export interface IUnleashStores { accessStore: IAccessStore; @@ -61,5 +60,4 @@ export interface IUnleashStores { segmentStore: ISegmentStore; patStore: IPatStore; publicSignupTokenStore: IPublicSignupTokenStore; - suggestChangeStore: ISuggestChangeStore; } diff --git a/src/lib/types/stores/suggest-change-store.ts b/src/lib/types/stores/suggest-change-store.ts deleted file mode 100644 index f50deefa6b3..00000000000 --- a/src/lib/types/stores/suggest-change-store.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { Store } from './store'; -import { - ISuggestChange, - ISuggestChangeset, - SuggestChangesetState, -} from '../model'; -import { PartialSome } from '../partial'; - -export interface ISuggestChangeStore extends Store { - create( - suggestChangeSet: PartialSome< - ISuggestChangeset, - 'id' | 'createdBy' | 'createdAt' - >, - userId: number, - ): Promise; - - addChangeToSet( - change: PartialSome, - feature: string, - changeSetID: number, - userId: number, - ): Promise; - - get(id: number): Promise; - - deleteChange(changeId: number): Promise; - - updateState( - id: number, - state: SuggestChangesetState, - ): Promise; - - getAll(): Promise; - - getForProject(project: string): Promise; - - getDraftsForUser( - userId: number, - project: string, - ): Promise; - - getForEnvironment(environment: string): Promise; -} diff --git a/src/test/fixtures/fake-suggest-change-store.ts b/src/test/fixtures/fake-suggest-change-store.ts deleted file mode 100644 index c37d2c60810..00000000000 --- a/src/test/fixtures/fake-suggest-change-store.ts +++ /dev/null @@ -1,114 +0,0 @@ -import { ISuggestChangeStore } from '../../lib/types/stores/suggest-change-store'; -import { - ISuggestChange, - ISuggestChangeset, - SuggestChangesetState, -} from '../../lib/types/model'; -import { PartialSome } from '../../lib/types/partial'; - -export default class FakeSuggestChangeStore implements ISuggestChangeStore { - suggestChanges: ISuggestChangeset[] = []; - - async get(id: number): Promise { - const change = this.suggestChanges.find((c) => c.id === id); - return Promise.resolve(change); - } - - async count(): Promise { - return Promise.resolve(0); - } - - // eslint-disable-next-line no-unused-vars,@typescript-eslint/no-unused-vars - async delete(id: number): Promise { - return Promise.resolve(undefined); - } - - // eslint-disable-next-line no-unused-vars,@typescript-eslint/no-unused-vars - async deleteChange(id: number): Promise { - return Promise.resolve(undefined); - } - - addChangeToSet( - change: ISuggestChange, - feature: string, - changeSetID: number, - userId: number, - ): Promise { - const changeSet = this.suggestChanges.find((s) => s.id === changeSetID); - changeSet.features.push({ - name: feature, - changes: [ - { - createdBy: { id: userId, username: '', imageUrl: '' }, - ...change, - }, - ], - }); - - return Promise.resolve(); - } - - getForEnvironment(environment: string): Promise { - return Promise.resolve( - this.suggestChanges.filter( - (changeSet) => changeSet.environment === environment, - ), - ); - } - - getDraftsForUser( - userId: number, - project: string, - ): Promise { - return Promise.resolve( - this.suggestChanges.filter( - (changeSet) => - changeSet.project === project && - changeSet.createdBy.id === userId, - ), - ); - } - - getForProject(project: string): Promise { - return Promise.resolve( - this.suggestChanges.filter( - (changeSet) => changeSet.project === project, - ), - ); - } - - create( - suggestChangeSet: PartialSome, - userId: number, - ): Promise { - this.suggestChanges.push({ - id: 1, - ...suggestChangeSet, - createdBy: { id: userId, username: '', imageUrl: '' }, - }); - return Promise.resolve(undefined); - } - - getAll(): Promise { - return Promise.resolve([]); - } - - deleteAll(): Promise { - return Promise.resolve(undefined); - } - - destroy(): void {} - - exists(key: number): Promise { - return Promise.resolve(Boolean(key)); - } - - updateState( - id: number, - state: SuggestChangesetState, - ): Promise { - const changeSet = this.suggestChanges.find((s) => s.id === id); - changeSet.state = state; - return Promise.resolve(undefined); - } -} diff --git a/src/test/fixtures/store.ts b/src/test/fixtures/store.ts index 17f5c4b80f3..e5506cabdf2 100644 --- a/src/test/fixtures/store.ts +++ b/src/test/fixtures/store.ts @@ -29,7 +29,6 @@ import FakeSegmentStore from './fake-segment-store'; import FakeGroupStore from './fake-group-store'; import FakePatStore from './fake-pat-store'; import FakePublicSignupStore from './fake-public-signup-store'; -import FakeSuggestChangeStore from './fake-suggest-change-store'; const createStores: () => IUnleashStores = () => { const db = { @@ -70,7 +69,6 @@ const createStores: () => IUnleashStores = () => { groupStore: new FakeGroupStore(), patStore: new FakePatStore(), publicSignupTokenStore: new FakePublicSignupStore(), - suggestChangeStore: new FakeSuggestChangeStore(), }; };