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,
|
IGroupUserModel,
|
||||||
} from '../types/group';
|
} from '../types/group';
|
||||||
import Transaction = Knex.Transaction;
|
import Transaction = Knex.Transaction;
|
||||||
|
import { AbstractTransactional } from './transactional';
|
||||||
|
|
||||||
const T = {
|
const T = {
|
||||||
GROUPS: 'groups',
|
GROUPS: 'groups',
|
||||||
@ -60,10 +61,14 @@ const groupToRow = (group: IStoreGroup) => ({
|
|||||||
mappings_sso: JSON.stringify(group.mappingsSSO),
|
mappings_sso: JSON.stringify(group.mappingsSSO),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default class GroupStore implements IGroupStore {
|
export default class GroupStore
|
||||||
|
extends AbstractTransactional<GroupStore>
|
||||||
|
implements IGroupStore
|
||||||
|
{
|
||||||
private db: Knex;
|
private db: Knex;
|
||||||
|
|
||||||
constructor(db: Knex) {
|
constructor(db: Knex) {
|
||||||
|
super();
|
||||||
this.db = db;
|
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,
|
app,
|
||||||
config,
|
config,
|
||||||
version: serverVersion,
|
version: serverVersion,
|
||||||
|
db,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (config.import.file) {
|
if (config.import.file) {
|
||||||
|
@ -6,6 +6,7 @@ import User from './user';
|
|||||||
import { IUnleashConfig } from './option';
|
import { IUnleashConfig } from './option';
|
||||||
import { IUnleashStores } from './stores';
|
import { IUnleashStores } from './stores';
|
||||||
import { IUnleashServices } from './services';
|
import { IUnleashServices } from './services';
|
||||||
|
import { Knex } from 'knex';
|
||||||
|
|
||||||
export interface AuthedRequest extends Request {
|
export interface AuthedRequest extends Request {
|
||||||
user: User;
|
user: User;
|
||||||
@ -20,4 +21,5 @@ export interface IUnleash {
|
|||||||
services: IUnleashServices;
|
services: IUnleashServices;
|
||||||
stop: () => Promise<void>;
|
stop: () => Promise<void>;
|
||||||
version: string;
|
version: string;
|
||||||
|
db: Knex;
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ import Group, {
|
|||||||
IGroupUser,
|
IGroupUser,
|
||||||
IGroupUserModel,
|
IGroupUserModel,
|
||||||
} from '../group';
|
} from '../group';
|
||||||
|
import { Transactional } from './transactional';
|
||||||
|
|
||||||
export interface IStoreGroup {
|
export interface IStoreGroup {
|
||||||
name: string;
|
name: string;
|
||||||
@ -14,7 +15,9 @@ export interface IStoreGroup {
|
|||||||
mappingsSSO?: string[];
|
mappingsSSO?: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IGroupStore extends Store<IGroup, number> {
|
export interface IGroupStore
|
||||||
|
extends Store<IGroup, number>,
|
||||||
|
Transactional<IGroupStore> {
|
||||||
getGroupsForUser(userId: number): Promise<Group[]>;
|
getGroupsForUser(userId: number): Promise<Group[]>;
|
||||||
getOldGroupsForExternalUser(
|
getOldGroupsForExternalUser(
|
||||||
userId: number,
|
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 { IFeatureEnvironmentStore } from '../../../lib/types/stores/feature-environment-store';
|
||||||
import { DEFAULT_ENV } from '../../../lib/util/constants';
|
import { DEFAULT_ENV } from '../../../lib/util/constants';
|
||||||
import { IUnleashOptions } from 'lib/server-impl';
|
import { IUnleashOptions } from 'lib/server-impl';
|
||||||
|
import { Knex } from 'knex';
|
||||||
|
|
||||||
// require('db-migrate-shared').log.silence(false);
|
// require('db-migrate-shared').log.silence(false);
|
||||||
|
|
||||||
@ -73,6 +74,7 @@ async function setupDatabase(stores) {
|
|||||||
|
|
||||||
export interface ITestDb {
|
export interface ITestDb {
|
||||||
stores: IUnleashStores;
|
stores: IUnleashStores;
|
||||||
|
db: Knex;
|
||||||
reset: () => Promise<void>;
|
reset: () => Promise<void>;
|
||||||
destroy: () => Promise<void>;
|
destroy: () => Promise<void>;
|
||||||
}
|
}
|
||||||
@ -108,6 +110,7 @@ export default async function init(
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
stores,
|
stores,
|
||||||
|
db: testDb,
|
||||||
reset: async () => {
|
reset: async () => {
|
||||||
await resetDatabase(testDb);
|
await resetDatabase(testDb);
|
||||||
await setupDatabase(stores);
|
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,
|
IGroupUser,
|
||||||
IGroupUserModel,
|
IGroupUserModel,
|
||||||
} from '../../lib/types/group';
|
} from '../../lib/types/group';
|
||||||
|
import { Knex } from 'knex';
|
||||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||||
export default class FakeGroupStore implements IGroupStore {
|
export default class FakeGroupStore implements IGroupStore {
|
||||||
data: IGroup[];
|
data: IGroup[];
|
||||||
@ -109,4 +110,8 @@ export default class FakeGroupStore implements IGroupStore {
|
|||||||
getGroupsForUser(userId: number): Promise<Group[]> {
|
getGroupsForUser(userId: number): Promise<Group[]> {
|
||||||
throw new Error('Method not implemented.');
|
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