Skip to content

Commit

Permalink
fix: Compatibility with Immer.js (#22)
Browse files Browse the repository at this point in the history
  • Loading branch information
mnasyrov committed Feb 26, 2023
1 parent beba04b commit aabea83
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 53 deletions.
59 changes: 23 additions & 36 deletions packages/rx-effects/src/compute.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ import {
compute,
createComputationNode,
createComputationQuery,
getComputationNode,
getQueryValue,
isComputationQuery,
makeColdNode,
nextNodeVersion,
nextVersion,
Expand Down Expand Up @@ -225,8 +225,8 @@ describe('compute()', () => {

const query1 = compute(() => source.get() + 1, [source]);
const query2 = compute(() => query1.get() * 2, [query1]);
const node1 = getComputationNode(query1);
const node2 = getComputationNode(query2);
const node1 = getNode(query1);
const node2 = getNode(query2);

const subject1 = new Subject();
const subject2 = new Subject();
Expand Down Expand Up @@ -272,8 +272,8 @@ describe('compute()', () => {

const query1 = compute(() => source.get() + 1, [source]);
const query2 = compute(() => query1.get() * 2, [query1]);
const node1 = getComputationNode(query1);
const node2 = getComputationNode(query2);
const node1 = getNode(query1);
const node2 = getNode(query2);

const subject1 = new Subject();
const subject2 = new Subject();
Expand Down Expand Up @@ -477,27 +477,12 @@ describe('createComputationNode()', () => {
});
});

describe('isComputationQuery()', () => {
it('should return "true" if value is ComputationQuery', () => {
const node = createComputationNode(() => 1);
const query = createComputationQuery(node);

expect(isComputationQuery(query)).toBe(true);
});

it('should return "false" if value is not ComputationQuery', () => {
const query = createStore(1);

expect(isComputationQuery(query)).toBe(false);
});
});

describe('createComputationQuery()', () => {
it('should return ComputationQuery', async () => {
const node = createComputationNode(() => 1);
const query = createComputationQuery(node);

expect(isComputationQuery(query)).toBe(true);
expect(getComputationNode(query)).toBe(node);
expect(query.get()).toBe(1);
expect(await firstValueFrom(query.value$)).toBe(1);
});
Expand Down Expand Up @@ -576,10 +561,10 @@ describe('addValueObserver()', () => {
const source = createStore(1);

const query1 = compute(() => 1, [source]);
const node1 = getComputationNode(query1);
const node1 = getNode(query1);

const query2 = compute(() => 1, [query1]);
const node2 = getComputationNode(query2);
const node2 = getNode(query2);

expect(node1.observers).toBeUndefined();
expect(node1.children?.length).toBeUndefined();
Expand Down Expand Up @@ -646,10 +631,10 @@ describe('removeValueObserver()', () => {
const source = createStore(1);

const query1 = compute(() => 1, [source]);
const node1 = getComputationNode(query1);
const node1 = getNode(query1);

const query2 = compute(() => 1, [query1]);
const node2 = getComputationNode(query2);
const node2 = getNode(query2);

const subject1 = new Subject();
const subject2 = new Subject();
Expand Down Expand Up @@ -682,10 +667,10 @@ describe('onSourceError()', () => {
const source = createStore(1);

const query1 = compute(() => source.get() + 1, [source]);
const node1 = getComputationNode(query1);
const node1 = getNode(query1);

const query2 = compute(() => query1.get() * 2, [query1]);
const node2 = getComputationNode(query2);
const node2 = getNode(query2);

const subject1 = new Subject();
const subject2 = new Subject();
Expand Down Expand Up @@ -737,7 +722,7 @@ describe('onSourceError()', () => {
describe('makeColdNode()', () => {
it('should not fail if a node has initial state', () => {
const query = compute(() => 1);
const node = getComputationNode(query);
const node = getNode(query);

expect(() => {
makeColdNode(node);
Expand All @@ -747,9 +732,9 @@ describe('makeColdNode()', () => {
it('should not fail if a parent node has incorrect state', () => {
const query = compute(() => 1);

const parent = getComputationNode(query);
const parent = getNode(query);

const node = getComputationNode(query);
const node = getNode(query);
node.parents = [];
node.parents.push(parent);

Expand All @@ -764,10 +749,10 @@ describe('onSourceComplete()', () => {
const source = createStore(1);

const query1 = compute(() => source.get() + 1, [source]);
const node1 = getComputationNode(query1);
const node1 = getNode(query1);

const query2 = compute(() => query1.get() * 2, [query1]);
const node2 = getComputationNode(query2);
const node2 = getNode(query2);

const subject1 = new Subject();
const subject2 = new Subject();
Expand Down Expand Up @@ -855,11 +840,11 @@ describe('recompute()', () => {
it('should compute if only a subtree has an indirect observer', () => {
const calc1 = jest.fn(() => 1);
const query1 = compute(calc1);
const node1 = getComputationNode(query1);
const node1 = getNode(query1);

const calc2 = jest.fn((get) => get(query1) + 1);
const query2 = compute(calc2);
const node2 = getComputationNode(query2);
const node2 = getNode(query2);

addChildNode(node1, node2);

Expand Down Expand Up @@ -950,8 +935,10 @@ describe('calculateValue()', () => {
});
});

function getComputationNode<T>(query: Query<T>): Node<T> {
if (isComputationQuery(query)) return query._node;
function getNode<T>(query: Query<T>): Node<T> {
const node = getComputationNode(query);

if (node) return node;

throw new Error('Not ComputationQuery');
}
37 changes: 20 additions & 17 deletions packages/rx-effects/src/compute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,14 +81,6 @@ export const compute: {

/// INTERNAL

type ComputationQuery<T> = Query<T> & Readonly<{ _node: Node<T> }>;

export function isComputationQuery<T>(
value: Query<T>,
): value is ComputationQuery<T> {
return '_node' in value;
}

type ValueRef<T> = { value: T; params?: Array<unknown>; version?: number };

/** @internal */
Expand All @@ -106,6 +98,8 @@ export type Node<T> = {
children?: Node<any>[];
};

const NODES = new WeakMap<Query<any>, Node<any>>();

/** @internal */
export function createComputationNode<T>(
computation: Computation<T>,
Expand All @@ -122,10 +116,9 @@ export function createComputationNode<T>(
};
}

export function createComputationQuery<T>(node: Node<T>): ComputationQuery<T> {
return {
_node: node,

/** @internal */
export function createComputationQuery<T>(node: Node<T>): Query<T> {
const query = {
get: () => getQueryValue(node),

value$: new Observable<T>((observer) => {
Expand All @@ -134,6 +127,15 @@ export function createComputationQuery<T>(node: Node<T>): ComputationQuery<T> {
return () => removeValueObserver(node, observer);
}),
};

NODES.set(query, node);

return query;
}

/** @internal */
export function getComputationNode<T>(query: Query<T>): Node<T> | undefined {
return NODES.get(query);
}

/// COMPUTATION ENGINE
Expand Down Expand Up @@ -251,14 +253,15 @@ function makeHotNode<T>(node: Node<T>, observer?: Observer<T>) {
}

for (let i = 0; i < dependencies.length; i++) {
const parent = dependencies[i];
const parentQuery = dependencies[i];

if (!parent) {
if (!parentQuery) {
throw new TypeError('Incorrect dependency');
}

if (isComputationQuery(parent)) {
addChildNode(parent._node, node);
const parentNode = NODES.get(parentQuery);
if (parentNode) {
addChildNode(parentNode, node);
} else {
if (!depObserver) {
depObserver = {
Expand All @@ -268,7 +271,7 @@ function makeHotNode<T>(node: Node<T>, observer?: Observer<T>) {
};
}

const subscription = parent.value$.subscribe(depObserver);
const subscription = parentQuery.value$.subscribe(depObserver);

depsSubscriptions.push(() => subscription.unsubscribe());
}
Expand Down

0 comments on commit aabea83

Please sign in to comment.