Skip to content

Commit

Permalink
feat!: implement base async links
Browse files Browse the repository at this point in the history
  • Loading branch information
César Alberca committed Dec 2, 2021
1 parent ed02032 commit 15e6541
Show file tree
Hide file tree
Showing 14 changed files with 58 additions and 36 deletions.
2 changes: 1 addition & 1 deletion packages/arch/src/runner/links/base-link.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@ export abstract class BaseLink {
return this
}

abstract next(context: Context): void
abstract next(context: Context): Promise<void>
}
41 changes: 29 additions & 12 deletions packages/arch/src/runner/links/cache-link.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,69 +9,80 @@ import { InvalidationPolicy } from '../../cache/invalidation-policy'
import { Command } from '../../use-case/command'

describe('CacheLink', () => {
it('should use the cache', () => {
it('should use the cache', async () => {
const { link, cacheManager, cacheLink } = setup()
when(cacheManager.isCached(anything(), anything())).thenReturn(false)

class MockUseCase extends UseCase<unknown, unknown> {
readonly = true

async internalExecute(): Promise<void> {}
}

const context = Context.create({
useCase: new MockUseCase(),
param: undefined,
executionOptions: { inlineError: false }
})
cacheLink.setNext(instance(link))

cacheLink.next(context)
await cacheLink.next(context)

verify(link.next(anything())).once()
})

it('should break the link if it is cached', () => {
it('should break the link if it is cached', async () => {
const { link, cacheManager, cacheLink } = setup()
when(cacheManager.isCached(anything(), anything())).thenReturn(true)

class MockUseCase extends UseCase<unknown, unknown> {
readonly = true

async internalExecute(): Promise<void> {}
}

const context = Context.create({
useCase: new MockUseCase(),
param: undefined,
executionOptions: { inlineError: false }
})
cacheLink.setNext(instance(link))

cacheLink.next(context)
await cacheLink.next(context)

verify(link.next(anything())).never()
})

it('should not cache commands', () => {
it('should not cache commands', async () => {
const { link, cacheManager, cacheLink } = setup()
when(cacheManager.isCached(anything(), anything())).thenReturn(false)

class MockUseCase extends Command<unknown, unknown> {
async internalExecute(): Promise<void> {}
}

const context = Context.create({
useCase: new MockUseCase(),
param: undefined,
executionOptions: { inlineError: false }
})
cacheLink.setNext(instance(link))

cacheLink.next(context)
await cacheLink.next(context)

verify(cacheManager.cache(anything(), anything())).never()
})

it('should invalidate using no cache policy', () => {
it('should invalidate using no cache policy', async () => {
const { link, cacheManager, cacheLink } = setup()
when(cacheManager.isCached(anything(), anything())).thenReturn(true)

class MockUseCase extends UseCase<unknown, unknown> {
readonly = true

async internalExecute(): Promise<void> {}
}

CacheInvalidations.set(MockUseCase.name, [InvalidationPolicy.NO_CACHE])
const context = Context.create({
useCase: new MockUseCase(),
Expand All @@ -80,19 +91,22 @@ describe('CacheLink', () => {
})
cacheLink.setNext(instance(link))

cacheLink.next(context)
await cacheLink.next(context)

verify(cacheManager.invalidateCache(MockUseCase.name)).once()
CacheInvalidations.clear()
})

it('should invalidate using all cache policy', () => {
it('should invalidate using all cache policy', async () => {
const { link, cacheManager, cacheLink } = setup()
when(cacheManager.isCached(anything(), anything())).thenReturn(true)

class MockUseCase extends UseCase<unknown, unknown> {
readonly = true

async internalExecute(): Promise<void> {}
}

CacheInvalidations.set(MockUseCase.name, [InvalidationPolicy.ALL])
const context = Context.create({
useCase: new MockUseCase(),
Expand All @@ -101,19 +115,22 @@ describe('CacheLink', () => {
})
cacheLink.setNext(instance(link))

cacheLink.next(context)
await cacheLink.next(context)

verify(cacheManager.invalidateCaches()).once()
CacheInvalidations.clear()
})

it('should invalidate using all cache policy', () => {
it('should invalidate using all cache policy', async () => {
const { link, cacheManager, cacheLink } = setup()
when(cacheManager.isCached(anything(), anything())).thenReturn(true)

class MockUseCase extends UseCase<unknown, unknown> {
readonly = true

async internalExecute(): Promise<void> {}
}

CacheInvalidations.set(MockUseCase.name, ['Foo'])
CacheInvalidations.set('Foo', ['Bar'])
const context = Context.create({
Expand All @@ -123,7 +140,7 @@ describe('CacheLink', () => {
})
cacheLink.setNext(instance(link))

cacheLink.next(context)
await cacheLink.next(context)

verify(cacheManager.invalidateCache('Foo')).once()
verify(cacheManager.invalidateCache('Bar')).once()
Expand Down
2 changes: 1 addition & 1 deletion packages/arch/src/runner/links/cache-link.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export class CacheLink extends BaseLink {
super()
}

next(context: Context): void {
async next(context: Context): Promise<void> {
const name = context.useCase.constructor.name

if (!this.cacheManager.isCached(name, [context.param])) {
Expand Down
2 changes: 1 addition & 1 deletion packages/arch/src/runner/links/empty-link.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ export class EmptyLink implements Link {
return this
}

next(_context: Context) {}
async next(_context: Context) {}
}
8 changes: 4 additions & 4 deletions packages/arch/src/runner/links/executor-link.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,26 @@ import { UseCase } from '../../use-case/use-case'
import { Link } from './link'

describe('ExecutorLink', () => {
it('should execute', () => {
it('should execute', async () => {
const { context, nextLink, executorLink } = setup()
const useCase = mock<UseCase<unknown, unknown>>()
when(context.useCase).thenReturn(instance(useCase))
when(context.param).thenReturn(undefined)
executorLink.setNext(instance(nextLink))

executorLink.next(instance(context))
await executorLink.next(instance(context))

verify(useCase.internalExecute(anything())).once()
})

it('should call next link', () => {
it('should call next link', async () => {
const { context, nextLink, executorLink } = setup()
const useCase = mock<UseCase<unknown, unknown>>()
when(context.useCase).thenReturn(instance(useCase))
when(context.param).thenReturn(undefined)
executorLink.setNext(instance(nextLink))

executorLink.next(instance(context))
await executorLink.next(instance(context))

verify(nextLink.next(anything())).once()
})
Expand Down
2 changes: 1 addition & 1 deletion packages/arch/src/runner/links/executor-link.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { BaseLink } from './base-link'
import { Context } from '../context'

export class ExecutorLink extends BaseLink {
next(context: Context): void {
async next(context: Context): Promise<void> {
context.result = context.useCase.internalExecute(context.param)
this.nextLink.next(context)
}
Expand Down
2 changes: 1 addition & 1 deletion packages/arch/src/runner/links/link.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ import { Context } from '../context'

export interface Link {
setNext(link: Link): Link
next(context: Context): void
next(context: Context): Promise<void>
}
2 changes: 1 addition & 1 deletion packages/arch/src/runner/links/logger-link.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export class LoggerLink extends BaseLink {
super()
}

next(context: Context): void {
async next(context: Context): Promise<void> {
context.result = context.result?.then(x => {
this.logger.log(
`[${Datetime.now().toIso()}] ${context.useCase.constructor.name} / Params: ${
Expand Down
6 changes: 3 additions & 3 deletions packages/arch/src/runner/links/notification-link.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ describe.skip('NotificationLink', () => {
})
context.result = mockUseCase.internalExecute()

notificationLink.next(instance(context))
await notificationLink.next(instance(context))
await context.result
} catch (e) {
expect(e).toEqual({
Expand Down Expand Up @@ -55,7 +55,7 @@ describe.skip('NotificationLink', () => {

context.result = mockUseCase.internalExecute()
try {
notificationLink.next(instance(context))
await notificationLink.next(instance(context))
await context.result
} catch (e) {
verify(link.next(deepEqual(context))).once()
Expand All @@ -82,7 +82,7 @@ describe.skip('NotificationLink', () => {

context.result = mockUseCase.internalExecute()
try {
notificationLink.next(instance(context))
await notificationLink.next(instance(context))
await context.result
} catch (e) {
verify(link.next(deepEqual(context))).never()
Expand Down
5 changes: 3 additions & 2 deletions packages/arch/src/runner/links/notification-link.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@ export class NotificationLink extends BaseLink {
super()
}

next(context: Context): void {
async next(context: Context): Promise<void> {
context.result = context.result?.catch(e => {
if (!context.executionOptions.inlineError) {
this.notificationCenter.new({ message: e.error?.message ?? 'Error' })
}
console.error(e)
throw e
})
this.nextLink.next(context)
await this.nextLink.next(context)
return
}
}
4 changes: 2 additions & 2 deletions packages/arch/src/runner/links/null-link.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ import { Context } from '../context'
import { ChainError } from '../chain-error'

describe('NullLink', () => {
it('should throw chain error', () => {
it('should throw chain error', async () => {
const nullLink = new NullLink()
const context = mock(Context)

try {
nullLink.next(instance(context))
await nullLink.next(instance(context))
} catch (e) {
expect(e).toEqual(new ChainError())
}
Expand Down
2 changes: 1 addition & 1 deletion packages/arch/src/runner/links/null-link.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { ChainError } from '../chain-error'
import { BaseLink } from './base-link'

export class NullLink extends BaseLink {
next(_context: Context) {
async next(_context: Context) {
throw new ChainError()
}
}
8 changes: 4 additions & 4 deletions packages/arch/src/runner/runner.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ import { Link } from './links/link'
import { anything, instance, mock, verify } from 'ts-mockito'
import { UseCase } from '../use-case/use-case'

describe.skip('Runner', () => {
it('should run the runner', () => {
describe('Runner', () => {
it('should run the runner', async () => {
const link = mock<Link>()
Runner.createChain([link])
Runner.createChain([instance(link)])
const useCase = mock<UseCase<unknown, unknown>>()

Runner.run(instance(useCase), { inlineError: false })
await Runner.run(instance(useCase), { inlineError: false })

verify(link.next(anything())).once()
})
Expand Down
8 changes: 6 additions & 2 deletions packages/arch/src/runner/runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,13 @@ import { NullLink } from './links/null-link'
export class Runner {
private static chain: Link = new NullLink()

static run(useCase: UseCase<unknown, unknown>, executionOptions: ExecutionOptions, param?: unknown): unknown {
static async run(
useCase: UseCase<unknown, unknown>,
executionOptions: ExecutionOptions,
param?: unknown
): Promise<unknown> {
const context = Context.create({ useCase, param, executionOptions })
this.chain.next(context)
await this.chain.next(context)
return context.result
}

Expand Down

0 comments on commit 15e6541

Please sign in to comment.