-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Auto abort the request for the entities based on the given parameters
- Loading branch information
Showing
7 changed files
with
238 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import { ContextualAbortController } from './contextual-abort-controller'; | ||
|
||
/** | ||
* @internal | ||
*/ | ||
class AbortControllers { | ||
private controllers = new Map<string, ContextualAbortController>(); | ||
|
||
public has(controller: ContextualAbortController): boolean { | ||
return this.controllers.has(controller.context()); | ||
} | ||
|
||
public add( | ||
controller: ContextualAbortController | ||
): ContextualAbortController { | ||
const context = controller.context(); | ||
|
||
this.controller(context)?.abort(); | ||
this.set(controller); | ||
|
||
return this.controller(context)!; | ||
} | ||
|
||
public delete(controller: ContextualAbortController): void { | ||
this.controllers.delete(controller.context()); | ||
} | ||
|
||
private set(controller: ContextualAbortController): void { | ||
this.controllers.set(controller.context(), controller); | ||
} | ||
|
||
private controller(context: string): ContextualAbortController | undefined { | ||
return this.controllers.get(context); | ||
} | ||
} | ||
|
||
export const abortControllers = new AbortControllers(); |
39 changes: 39 additions & 0 deletions
39
sources/client/src/services/contextual-abort-controller.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
/** | ||
* @internal | ||
*/ | ||
export class ContextualAbortController { | ||
#controller: AbortController; | ||
#context: string; | ||
#reason: string; | ||
|
||
constructor(context: string, reason: string) { | ||
if (context === '') { | ||
throw new Error('Abort Controllers, context cannot be empty'); | ||
} | ||
|
||
this.#controller = new AbortController(); | ||
this.#context = context; | ||
this.#reason = reason; | ||
} | ||
|
||
public context(): string { | ||
return this.#context; | ||
} | ||
|
||
public abort(): ContextualAbortController { | ||
this.#controller.abort(this.reason()); | ||
return this; | ||
} | ||
|
||
public signal(): AbortSignal { | ||
return this.#controller.signal; | ||
} | ||
|
||
public isAborted(): boolean { | ||
return this.#controller.signal.aborted; | ||
} | ||
|
||
private reason(): DOMException { | ||
return new DOMException(this.#reason, 'AbortError'); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import { it, jest, describe, expect, beforeEach } from '@jest/globals'; | ||
|
||
import { abortControllers } from '../../../../sources/client/src/services/abort-controllers'; | ||
import { ContextualAbortController } from '../../../../sources/client/src/services/contextual-abort-controller'; | ||
|
||
describe('AbortControllers', () => { | ||
let controller: ContextualAbortController; | ||
|
||
beforeEach(() => { | ||
controller = new ContextualAbortController('context', 'reason'); | ||
}); | ||
|
||
it('should add a controller', () => { | ||
abortControllers.add(controller); | ||
expect(abortControllers.has(controller)).toBe(true); | ||
}); | ||
|
||
it('should delete a controller', () => { | ||
abortControllers.add(controller); | ||
expect(abortControllers.has(controller)).toBe(true); | ||
|
||
abortControllers.delete(controller); | ||
expect(abortControllers.has(controller)).toBe(false); | ||
}); | ||
|
||
it('should abort a controller', () => { | ||
const spy = jest.spyOn(controller, 'abort'); | ||
abortControllers.add(controller); | ||
abortControllers.add(controller); | ||
expect(spy).toHaveBeenCalled(); | ||
}); | ||
}); |
45 changes: 45 additions & 0 deletions
45
tests/client/unit/services/contextual-abort-controller.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
import { afterEach, beforeEach, describe, it, expect } from '@jest/globals'; | ||
|
||
import { ContextualAbortController } from '../../../../sources/client/src/services/contextual-abort-controller'; | ||
|
||
describe('ContextualAbortController', () => { | ||
let controller: ContextualAbortController; | ||
|
||
beforeEach(() => { | ||
controller = new ContextualAbortController('testContext', 'testReason'); | ||
}); | ||
|
||
afterEach(() => { | ||
controller.abort(); | ||
}); | ||
|
||
it('should create a new instance of ContextualAbortController', () => { | ||
expect(controller).toBeInstanceOf(ContextualAbortController); | ||
}); | ||
|
||
it('should return the correct context', () => { | ||
expect(controller.context()).toBe('testContext'); | ||
}); | ||
|
||
it('should abort the controller', () => { | ||
controller.abort(); | ||
expect(controller.isAborted()).toBe(true); | ||
}); | ||
|
||
it('should return the correct signal', () => { | ||
const signal = controller.signal(); | ||
expect(signal).toBeInstanceOf(AbortSignal); | ||
}); | ||
|
||
it('should return the correct aborted state', () => { | ||
expect(controller.isAborted()).toBe(false); | ||
controller.abort(); | ||
expect(controller.isAborted()).toBe(true); | ||
}); | ||
|
||
it('should throw an error if the context is empty', () => { | ||
expect( | ||
() => new ContextualAbortController('', 'testReason') | ||
).toThrowError('Abort Controllers, context cannot be empty'); | ||
}); | ||
}); |