Skip to content

Commit

Permalink
feat(repository): add TransactionRepo Interface
Browse files Browse the repository at this point in the history
Co-authored-by: Miroslav Bajtoš <[email protected]>
  • Loading branch information
Biniam Admikew and bajtos committed Jul 19, 2019
1 parent e31bb26 commit 2bd6344
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 23 deletions.
13 changes: 6 additions & 7 deletions packages/repository-tests/src/transaction/transactions.suite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,23 @@
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT

import {Entity, model, property} from '@loopback/repository';
import {Entity, juggler, model, property} from '@loopback/repository';
import {TransactionRepository} from '@loopback/repository/src';
import {expect, skipIf, toJSON} from '@loopback/testlab';
import {Transaction} from 'loopback-datasource-juggler';
import {Suite} from 'mocha';
import {EntityCrudRepository} from '../../../repository/src';
import {withCrudCtx} from '../helpers.repository-tests';
import {
CrudConnectorFeatures,
CrudRepositoryCtor,
CrudTestContext,
DataSourceOptions,
TransactionRepositoryCtor,
} from '../types.repository-tests';

// Core scenarios around creating new model instances and retrieving them back
// Please keep this file short, put any advanced scenarios to other files
export function transactionSuite(
dataSourceOptions: DataSourceOptions,
repositoryClass: CrudRepositoryCtor,
repositoryClass: TransactionRepositoryCtor,
connectorFeatures: CrudConnectorFeatures,
) {
skipIf<[(this: Suite) => void], void>(
Expand All @@ -47,7 +46,7 @@ export function transactionSuite(
}

describe('create-retrieve within transaction', () => {
let repo: EntityCrudRepository<Product, typeof Product.prototype.id>;
let repo: TransactionRepository<Product, typeof Product.prototype.id>;
before(
withCrudCtx(async function setupRepository(ctx: CrudTestContext) {
repo = new repositoryClass(Product, ctx.dataSource);
Expand All @@ -56,7 +55,7 @@ export function transactionSuite(
);

it('retrieves a newly created model in a transaction', async () => {
const tx: Transaction = await repo.beginTransaction!({
const tx: juggler.Transaction = await repo.beginTransaction({
isolationLevel: 'READ COMMITTED',
});
const created = await repo.create(
Expand Down
14 changes: 14 additions & 0 deletions packages/repository-tests/src/types.repository-tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
juggler,
Options,
} from '@loopback/repository';
import {TransactionRepository} from '@loopback/repository/src';

/**
* DataSource configuration (connector name, connection string, etc.).
Expand Down Expand Up @@ -62,6 +63,19 @@ export type CrudRepositoryCtor = new <
dataSource: juggler.DataSource,
) => EntityCrudRepository<T, ID, Relations>;

/**
* A constructor of a class implementing CrudRepository interface,
* accepting the Entity class (constructor) and a dataSource instance.
*/
export type TransactionRepositoryCtor = new <
T extends Entity,
ID,
Relations extends object
>(
entityClass: typeof Entity & {prototype: T},
dataSource: juggler.DataSource,
) => TransactionRepository<T, ID, Relations>;

/**
* Additional properties added to Mocha TestContext/SuiteContext.
* @internal
Expand Down
11 changes: 6 additions & 5 deletions packages/repository/src/repositories/legacy-juggler-bridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import {Getter} from '@loopback/context';
import * as assert from 'assert';
import * as legacy from 'loopback-datasource-juggler';
import {IsolationLevel, Transaction} from 'loopback-datasource-juggler';
import {
AnyObject,
Command,
Expand All @@ -31,7 +30,7 @@ import {
HasOneRepositoryFactory,
} from '../relations';
import {isTypeResolver, resolveType} from '../type-resolver';
import {EntityCrudRepository} from './repository';
import {EntityCrudRepository, TransactionRepository} from './repository';

export namespace juggler {
/* eslint-disable @typescript-eslint/no-unused-vars */
Expand All @@ -41,6 +40,8 @@ export namespace juggler {
export import PersistedModel = legacy.PersistedModel;
export import KeyValueModel = legacy.KeyValueModel;
export import PersistedModelClass = legacy.PersistedModelClass;
export import Transaction = legacy.Transaction;
export import IsolationLevel = legacy.IsolationLevel;
}

function isModelClass(
Expand Down Expand Up @@ -90,7 +91,7 @@ export class DefaultCrudRepository<
T extends Entity,
ID,
Relations extends object = {}
> implements EntityCrudRepository<T, ID, Relations> {
> implements TransactionRepository<T, ID, Relations> {
modelClass: juggler.PersistedModelClass;

/**
Expand Down Expand Up @@ -438,8 +439,8 @@ export class DefaultCrudRepository<
}

async beginTransaction(
options: IsolationLevel | Options,
): Promise<void | Transaction> {
options?: juggler.IsolationLevel | Options,
): Promise<juggler.Transaction> {
return await this.dataSource.beginTransaction(options);
}

Expand Down
26 changes: 15 additions & 11 deletions packages/repository/src/repositories/repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT

import {IsolationLevel, Transaction} from 'loopback-datasource-juggler';
import {
AnyObject,
Command,
Expand All @@ -18,6 +17,7 @@ import {DataSource} from '../datasource';
import {EntityNotFoundError} from '../errors';
import {Entity, Model, ValueObject} from '../model';
import {Filter, Where} from '../query';
import {IsolationLevel, Transaction} from '../transaction';

/* eslint-disable @typescript-eslint/no-unused-vars */

Expand All @@ -38,6 +38,20 @@ export interface ExecutableRepository<T extends Model> extends Repository<T> {
): Promise<AnyObject>;
}

export interface TransactionRepository<
T extends Entity,
ID,
Relations extends object = {}
> extends EntityCrudRepository<T, ID, Relations> {
/**
* Begin a new Transaction
* @param options - Options for the operations
* @returns Promise<true> if an entity exists for the id, otherwise
* Promise<false>
*/
beginTransaction(options?: IsolationLevel | Options): Promise<Transaction>;
}

/**
* Basic CRUD operations for ValueObject and Entity. No ID is required.
*/
Expand Down Expand Up @@ -194,16 +208,6 @@ export interface EntityCrudRepository<
* Promise<false>
*/
exists(id: ID, options?: Options): Promise<boolean>;

/**
* Begin a new Transaction
* @param options - Options for the operations
* @returns Promise<true> if an entity exists for the id, otherwise
* Promise<false>
*/
beginTransaction?(
options?: IsolationLevel | Options,
): Promise<void | Transaction>;
}

/**
Expand Down
32 changes: 32 additions & 0 deletions packages/repository/src/transaction.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright IBM Corp. 2019. All Rights Reserved.
// Node module: @loopback/repository
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT

import {Callback} from './common-types';

/**
* Local transaction
*/
export interface Transaction {
/**
* Commit the transaction
* @param callback
*/
commit(callback?: Callback<any>): void;
/**
* Rollback the transaction
* @param callback
*/
rollback(callback?: Callback<any>): void;
}

/**
* Isolation level
*/
export enum IsolationLevel {
READ_COMMITTED = 'READ COMMITTED', // default
READ_UNCOMMITTED = 'READ UNCOMMITTED',
SERIALIZABLE = 'SERIALIZABLE',
REPEATABLE_READ = 'REPEATABLE READ',
}

0 comments on commit 2bd6344

Please sign in to comment.