Skip to content

Commit

Permalink
feat(task): adds 2 new Task methods
Browse files Browse the repository at this point in the history
- `Task.run`: like `Task.fork`, but doesn't require a resolver object
- `Task.run_sync`: like `Task.run`, but for synchronous tasks
  • Loading branch information
alexsasharegan committed Sep 19, 2018
1 parent e88bccf commit e7f0b61
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 1 deletion.
12 changes: 12 additions & 0 deletions flow-typed/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -641,6 +641,18 @@ declare export class Task<T, E> {
* _`resolver.Err<F> => Promise<Err<F>>`_
*/
fork<U, F>(resolver: TaskResolver<T, E, U, F>): Promise<Result<U, F>>;
/**
* `run` begins execution of the Task and returns a Promise resolving with a
* `Result` that contains the success or error value of the Task.
*/
run(): Promise<Result<T, E>>;
/**
* `run_sync` executes the Task synchronously and returns a `Result` that
* contains the success or error value of the Task.
*
* _NOTE: throws an Error if a callback is not invoked synchronously._
*/
run_sync(): Result<T, E>;
/**
* `map` returns a new Task with the success value mapped according to the
* map function given. `map` should be a synchronous operation.
Expand Down
2 changes: 2 additions & 0 deletions src/__snapshots__/task.test.ts.snap
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Task should toString 1`] = `"[object Task]"`;

exports[`Task task.run_sync (no sync callback Error) 1`] = `"Task.run_sync expects the executor to resolve synchronously."`;
41 changes: 41 additions & 0 deletions src/task.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,47 @@ describe("Task", async () => {
expect(r).toEqual(Result.Err(value));
});

it("task.run (success)", async () => {
const final = "success";
expect(await Task.from<string, void>(r => r.Ok(final)).run()).toEqual(
Result.Ok(final)
);
});

it("task.run (error)", async () => {
const final = "error";
expect(await Task.from<void, string>(r => r.Err(final)).run()).toEqual(
Result.Err(final)
);
});

it("task.run_sync (success)", async () => {
const final = "success";
expect(Task.from<string, void>(r => r.Ok(final)).run_sync()).toEqual(
Result.Ok(final)
);
});

it("task.run_sync (error)", async () => {
const final = "error";
expect(Task.from<void, string>(r => r.Err(final)).run_sync()).toEqual(
Result.Err(final)
);
});

it("task.run_sync (no sync callback Error)", async () => {
let task_bomb = Task.from<string, void>(async r => {
await new Promise(r => setTimeout(r, 10));
r.Ok("#boom");
});

const fn = () => {
task_bomb.run_sync();
};

expect(fn).toThrowErrorMatchingSnapshot();
});

it("Task.map", async () => {
const a = "a test";
let t = Task.from<string, string>(r => r.Ok(a)).map(s => s.toUpperCase());
Expand Down
44 changes: 43 additions & 1 deletion src/task.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Mapper } from "./utils";
import { Mapper, identity } from "./utils";
import { Result } from "./result";

/**
Expand Down Expand Up @@ -54,6 +54,48 @@ export class Task<T, E> {
);
}

/**
* `run` begins execution of the Task and returns a Promise resolving with a
* `Result` that contains the success or error value of the Task.
*/
public run(): Promise<Result<T, E>> {
return this.fork({
Err: identity,
Ok: identity,
});
}

/**
* `run_sync` executes the Task synchronously and returns a `Result` that
* contains the success or error value of the Task.
*
* _NOTE: throws an Error if a callback is not invoked synchronously._
*/
public run_sync(): Result<T, E> {
let r: Result<T, E>;

// The executor is not guaranteed to return anything.
// We need to use the callbacks to assign our Result.
this.executor({
Ok(value) {
r = Result.Ok(value);
},
Err(err) {
r = Result.Err(err);
},
});

// The first bang `!` is for logical not, the second for definite assignment
if (!r!) {
throw new Error(
`Task.run_sync expects the executor to resolve synchronously.`
);
}

// We've asserted that `r` is definitely assigned
return r!;
}

/**
* `map` returns a new Task with the success value mapped according to the
* map function given. `map` should be a synchronous operation.
Expand Down

0 comments on commit e7f0b61

Please sign in to comment.