mirror of
https://github.com/Unleash/unleash.git
synced 2025-09-10 17:53:36 +02:00
small spike for service level transactions, implementing this at the store level for groups
This commit is contained in:
parent
c4d68110fc
commit
8c82e4d0a0
@ -10,6 +10,7 @@ import Group, {
|
||||
IGroupUserModel,
|
||||
} from '../types/group';
|
||||
import Transaction = Knex.Transaction;
|
||||
import { AbstractTransactional } from './transactional';
|
||||
|
||||
const T = {
|
||||
GROUPS: 'groups',
|
||||
@ -60,10 +61,14 @@ const groupToRow = (group: IStoreGroup) => ({
|
||||
mappings_sso: JSON.stringify(group.mappingsSSO),
|
||||
});
|
||||
|
||||
export default class GroupStore implements IGroupStore {
|
||||
export default class GroupStore
|
||||
extends AbstractTransactional<GroupStore>
|
||||
implements IGroupStore
|
||||
{
|
||||
private db: Knex;
|
||||
|
||||
constructor(db: Knex) {
|
||||
super();
|
||||
this.db = db;
|
||||
}
|
||||
|
||||
|
13
src/lib/db/transactional.ts
Normal file
13
src/lib/db/transactional.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import { Knex } from 'knex';
|
||||
import { Transactional } from 'lib/types/stores/transactional';
|
||||
|
||||
export abstract class AbstractTransactional<T> implements Transactional<T> {
|
||||
transactional(transaction: Knex.Transaction): T {
|
||||
let clone = new (this.constructor as { new (): any })();
|
||||
for (const attribute in this) {
|
||||
clone[attribute] = this[attribute];
|
||||
}
|
||||
clone.db = transaction;
|
||||
return clone as T;
|
||||
}
|
||||
}
|
@ -76,6 +76,7 @@ async function createApp(
|
||||
app,
|
||||
config,
|
||||
version: serverVersion,
|
||||
db,
|
||||
};
|
||||
|
||||
if (config.import.file) {
|
||||
|
@ -6,6 +6,7 @@ import User from './user';
|
||||
import { IUnleashConfig } from './option';
|
||||
import { IUnleashStores } from './stores';
|
||||
import { IUnleashServices } from './services';
|
||||
import { Knex } from 'knex';
|
||||
|
||||
export interface AuthedRequest extends Request {
|
||||
user: User;
|
||||
@ -20,4 +21,5 @@ export interface IUnleash {
|
||||
services: IUnleashServices;
|
||||
stop: () => Promise<void>;
|
||||
version: string;
|
||||
db: Knex;
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import Group, {
|
||||
IGroupUser,
|
||||
IGroupUserModel,
|
||||
} from '../group';
|
||||
import { Transactional } from './transactional';
|
||||
|
||||
export interface IStoreGroup {
|
||||
name: string;
|
||||
@ -14,7 +15,9 @@ export interface IStoreGroup {
|
||||
mappingsSSO?: string[];
|
||||
}
|
||||
|
||||
export interface IGroupStore extends Store<IGroup, number> {
|
||||
export interface IGroupStore
|
||||
extends Store<IGroup, number>,
|
||||
Transactional<IGroupStore> {
|
||||
getGroupsForUser(userId: number): Promise<Group[]>;
|
||||
getOldGroupsForExternalUser(
|
||||
userId: number,
|
||||
|
5
src/lib/types/stores/transactional.ts
Normal file
5
src/lib/types/stores/transactional.ts
Normal file
@ -0,0 +1,5 @@
|
||||
import { Knex } from 'knex';
|
||||
|
||||
export interface Transactional<T> {
|
||||
transactional(transaction: Knex.Transaction): T;
|
||||
}
|
@ -11,6 +11,7 @@ import { IUnleashStores } from '../../../lib/types';
|
||||
import { IFeatureEnvironmentStore } from '../../../lib/types/stores/feature-environment-store';
|
||||
import { DEFAULT_ENV } from '../../../lib/util/constants';
|
||||
import { IUnleashOptions } from 'lib/server-impl';
|
||||
import { Knex } from 'knex';
|
||||
|
||||
// require('db-migrate-shared').log.silence(false);
|
||||
|
||||
@ -73,6 +74,7 @@ async function setupDatabase(stores) {
|
||||
|
||||
export interface ITestDb {
|
||||
stores: IUnleashStores;
|
||||
db: Knex;
|
||||
reset: () => Promise<void>;
|
||||
destroy: () => Promise<void>;
|
||||
}
|
||||
@ -108,6 +110,7 @@ export default async function init(
|
||||
|
||||
return {
|
||||
stores,
|
||||
db: testDb,
|
||||
reset: async () => {
|
||||
await resetDatabase(testDb);
|
||||
await setupDatabase(stores);
|
||||
|
5
src/test/fixtures/fake-group-store.ts
vendored
5
src/test/fixtures/fake-group-store.ts
vendored
@ -7,6 +7,7 @@ import Group, {
|
||||
IGroupUser,
|
||||
IGroupUserModel,
|
||||
} from '../../lib/types/group';
|
||||
import { Knex } from 'knex';
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
export default class FakeGroupStore implements IGroupStore {
|
||||
data: IGroup[];
|
||||
@ -109,4 +110,8 @@ export default class FakeGroupStore implements IGroupStore {
|
||||
getGroupsForUser(userId: number): Promise<Group[]> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
transactional(transaction: Knex.Transaction<any, any[]>): IGroupStore {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
}
|
||||
|
63
src/test/transactional.test.ts
Normal file
63
src/test/transactional.test.ts
Normal file
@ -0,0 +1,63 @@
|
||||
import dbInit, { ITestDb } from './/e2e/helpers/database-init';
|
||||
import getLogger from './fixtures/no-logger';
|
||||
|
||||
let stores;
|
||||
let db: ITestDb;
|
||||
|
||||
beforeAll(async () => {
|
||||
db = await dbInit('group_service_serial', getLogger);
|
||||
stores = db.stores;
|
||||
|
||||
await stores.groupStore.create({
|
||||
name: 'dev_group',
|
||||
description: 'dev_group',
|
||||
mappingsSSO: ['dev'],
|
||||
});
|
||||
await stores.groupStore.create({
|
||||
name: 'maintainer_group',
|
||||
description: 'maintainer_group',
|
||||
mappingsSSO: ['maintainer'],
|
||||
});
|
||||
|
||||
await stores.groupStore.create({
|
||||
name: 'admin_group',
|
||||
description: 'admin_group',
|
||||
mappingsSSO: ['admin'],
|
||||
});
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await db.destroy();
|
||||
});
|
||||
|
||||
test('should actually do something transactional mode', async () => {
|
||||
await db.db.transaction(async (trx) => {
|
||||
await stores.groupStore.transactional(trx).create({
|
||||
name: 'some_other_group',
|
||||
description: 'admin_group',
|
||||
mappingsSSO: ['admin'],
|
||||
});
|
||||
});
|
||||
|
||||
const groups = await stores.groupStore.getAll();
|
||||
const createdGroup = groups.find((group) => {
|
||||
return group.name === 'some_other_group';
|
||||
});
|
||||
expect(createdGroup).toBeDefined();
|
||||
});
|
||||
|
||||
test('should actually do something transactional mode', async () => {
|
||||
await db.db.transaction(async (trx) => {
|
||||
await stores.groupStore.transactional(trx).create({
|
||||
name: 'some_other_group',
|
||||
description: 'admin_group',
|
||||
mappingsSSO: ['admin'],
|
||||
});
|
||||
});
|
||||
|
||||
const groups = await stores.groupStore.getAll();
|
||||
const createdGroup = groups.find((group) => {
|
||||
return group.name === 'some_other_group';
|
||||
});
|
||||
expect(createdGroup).toBeDefined();
|
||||
});
|
Loading…
Reference in New Issue
Block a user