1
0
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:
sighphyre 2022-10-20 08:35:40 +02:00
parent c4d68110fc
commit 8c82e4d0a0
9 changed files with 102 additions and 2 deletions

View File

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

View 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;
}
}

View File

@ -76,6 +76,7 @@ async function createApp(
app,
config,
version: serverVersion,
db,
};
if (config.import.file) {

View 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;
}

View File

@ -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,

View File

@ -0,0 +1,5 @@
import { Knex } from 'knex';
export interface Transactional<T> {
transactional(transaction: Knex.Transaction): T;
}

View File

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

View File

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

View 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();
});