Skip to content

Commit

Permalink
feat(trackedFunction):implement a re-callable trackedFunction
Browse files Browse the repository at this point in the history
  • Loading branch information
velrest committed Sep 29, 2022
1 parent b1c3911 commit e73f949
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 29 deletions.
86 changes: 58 additions & 28 deletions ember-resources/src/util/function.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { tracked } from '@glimmer/tracking';
import { assert } from '@ember/debug';
import { action } from '@ember/object';
import { waitForPromise } from '@ember/test-waiters';

import { resource } from '../core/function-based';
Expand Down Expand Up @@ -92,43 +93,61 @@ export function trackedFunction<Return>(...passedArgs: UseFunctionArgs<Return>)
fn = passedArgs[2];
}

return resource<State<Return>>(context, (hooks) => {
let state = new State(initialValue);
return resource<TrackedFunctionProperty<Return>>(context, (hooks) => {
const trackedFunctionProperty = new TrackedFunctionProperty(
fn,
hooks,
initialValue
);
return trackedFunctionProperty;
});
}

(async () => {
try {
let notQuiteValue = fn(hooks);
let promise = Promise.resolve(notQuiteValue);
export class TrackedFunctionProperty<Value> {
@tracked state: State<Value>;

waitForPromise(promise);
constructor(
private fn: ResourceFn<Value>,
private hooks: Hooks,
initialValue?: Value
) {
this.state = new State(initialValue);
this.getValue();
}

let result = await promise;
async getValue() {
try {
let notQuiteValue = this.fn(this.hooks);
let promise = Promise.resolve(notQuiteValue);

state.error = undefined;
state.resolvedValue = result;
} catch (e) {
state.error = e;
} finally {
state.isResolved = true;
}
})();
waitForPromise(promise);

return state;
});
}
let result = await promise;

/**
* State container that represents the asynchrony of a `trackedFunction`
*/
export class State<Value> {
@tracked isResolved = false;
@tracked resolvedValue?: Value;
@tracked error?: unknown;
this.state.error = undefined;
this.state.resolvedValue = result;
} catch (e) {
this.state.error = e;
} finally {
this.state.isResolved = true;
}
}

constructor(public initialValue?: Value) {}
@action
execute() {
this.state = new State(this.state.initialValue);
this.getValue();
return this.state;
}
get isResolved() {
return this.state.isResolved;
}
get error() {
return this.state.error;
}

get value() {
return this.resolvedValue || this.initialValue || null;
return this.state.resolvedValue || this.state.initialValue || null;
}

get isPending() {
Expand All @@ -144,6 +163,17 @@ export class State<Value> {
}
}

/**
* State container that represents the asynchrony of a `trackedFunction`
*/
export class State<Value> {
@tracked isResolved = false;
@tracked resolvedValue?: Value;
@tracked error?: unknown;

constructor(public initialValue?: Value) {}
}

/**
* @private
*
Expand Down
40 changes: 40 additions & 0 deletions testing/ember-app/tests/utils/function/js-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,4 +149,44 @@ module('Utils | trackedFunction | js', function (hooks) {

assert.strictEqual(foo.data.value, 2);
});

test("it can be reexecuted", async function (assert) {
const Store = {
data: [[{ id: 1 }], [{ id: 1 }, { id: 2 }], [{ id: 1 }], [{ id: 1 }]],
fetch(page: Number) {
const value = this.data.shift();
return value?.map((v) => ({ ...v, page }));
},
};
class Test {
store = Store;
@tracked page = 1;

@tracked data = trackedFunction(this, () => {
return this.store.fetch(this.page);
});
}

let foo = new Test();

foo.data.value;
await settled();
assert.deepEqual(foo.data.value, [{ id: 1, page: 1 }]);

foo.page = 2;
foo.data.value;
await settled();
assert.deepEqual(foo.data.value, [
{ id: 1, page: 2 },
{ id: 2, page: 2 },
]);

const value = await foo.data.execute();
await settled();
assert.deepEqual(value.resolvedValue, [{ id: 1, page: 2 }]);

await foo.data.execute();
await settled();
assert.deepEqual(foo.data.value, [{ id: 1, page: 2 }]);
});
});
2 changes: 1 addition & 1 deletion testing/ember-app/tests/utils/function/rendering-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,6 @@ module('Utils | trackedFunction | rendering', function (hooks) {
assert.dom('out').hasText('');

await settled();
assert.dom('out').hasText('4');
assert.dom("out").hasText("4");
});
});

0 comments on commit e73f949

Please sign in to comment.