@@ -54,3 +54,4 894b8239b953c0384cf32cab46cf41dac97ea03b | |||
|
54 | 54 | 63215d91ae4b711eeb2145b9685240e1afada904 v1.9.0-rc6 |
|
55 | 55 | af4f8424e83d56e89a64f39e19514ca10dbd43c6 v1.9.0 |
|
56 | 56 | 63f3ad8e6cffcf32fc5a555e55e8544227293d4c v1.10.0 |
|
57 | d9c99ae7dec87ef47aded05def6a094a892df0e6 v1.10.1 |
@@ -42,19 +42,32 export const query = <T, Q, O>(store: Qu | |||
|
42 | 42 | }; |
|
43 | 43 | }; |
|
44 | 44 | |
|
45 | /** | |
|
46 | * Wraps the query method of the store, the resulting method takes a query | |
|
47 | * expression and returns two observable sequences. The first sequence represents | |
|
48 | * the results of the query, the second sequence provides the updates to the | |
|
49 | * query results. | |
|
50 | * | |
|
51 | * @param store The store used to query data | |
|
52 | * @param includeUpdates The flag to include item updates not only additions and | |
|
53 | * deletions. By default this flag is set to true. | |
|
54 | * @returns Two observable sequences | |
|
55 | */ | |
|
45 | 56 | export const queryEx = <T, Q, O>(store: Queryable<T, Q, O>, includeUpdates = true) => |
|
46 | 57 | (query?: Q, options?: O): [data: QueryResults<T>, updates: QueryResults<T>] => { |
|
47 | 58 | |
|
48 | const pending: T[] = []; | |
|
49 | ||
|
50 |
let results: PromiseOrValue<T[]> = |
|
|
59 | /** count active observers */ | |
|
60 | let listeners = 0; | |
|
61 | let results: PromiseOrValue<T[]> = []; | |
|
51 | 62 | |
|
52 | 63 | const data = observe<OrderedUpdate<T>>(({ next, complete, error }) => { |
|
53 | 64 | const processResults = (items: T[]) => |
|
54 | 65 | items.forEach((item, newIndex) => next({ item, newIndex, prevIndex: -1 })); |
|
55 | 66 | |
|
56 | 67 | try { |
|
57 | if (results === pending) | |
|
68 | // is there are no active observers here, we need to query actual | |
|
69 | // data from the store. | |
|
70 | if (listeners === 0) | |
|
58 | 71 | results = store.query(query, options); |
|
59 | 72 | |
|
60 | 73 | if (isPromise(results)) { |
@@ -74,8 +87,14 export const queryEx = <T, Q, O>(store: | |||
|
74 | 87 | const updates = observe<OrderedUpdate<T>>(({ next, complete, error, isClosed }) => { |
|
75 | 88 | try { |
|
76 | 89 | if (!isClosed() && isDjObservableResults<T>(results)) { |
|
90 | // subscribe fot the changes | |
|
91 | listeners++; | |
|
77 | 92 | const h = results.observe((item, prevIndex, newIndex) => next({ item, prevIndex, newIndex }), includeUpdates); |
|
78 |
return () => |
|
|
93 | return () => { | |
|
94 | // unsubscribe from changes | |
|
95 | listeners--; | |
|
96 | h.remove(); | |
|
97 | }; | |
|
79 | 98 | } else { |
|
80 | 99 | complete(); |
|
81 | 100 | } |
@@ -144,30 +144,48 tap.test("of(...) tests", async t => { | |||
|
144 | 144 | "of(...) should terminate with error when a parameter is rejected" |
|
145 | 145 | ); |
|
146 | 146 | |
|
147 | t.same(await of(1,2,3).collect(), [1,2,3], ".collect() should return the collected sequence"); | |
|
148 | await t.rejects(of(1,2,3).collect(cancelled), ".collect() should support cancellation"); | |
|
147 | t.same(await of(1, 2, 3).collect(), [1, 2, 3], ".collect() should return the collected sequence"); | |
|
148 | await t.rejects(of(1, 2, 3).collect(cancelled), ".collect() should support cancellation"); | |
|
149 | 149 | |
|
150 | 150 | }).catch(() => { }); |
|
151 | 151 | |
|
152 | 152 | tap.test(".tap() tests", async t => { |
|
153 | 153 | const side: number[] = []; |
|
154 | 154 | |
|
155 | of(1,2) | |
|
156 | .tap({next: v => side.push(v), complete: () => side.push(0)}) | |
|
157 | .tap({next: v => side.push(v*v)}) | |
|
155 | of(1, 2) | |
|
156 | .tap({ next: v => side.push(v), complete: () => side.push(0) }) | |
|
157 | .tap({ next: v => side.push(v * v) }) | |
|
158 | 158 | .subscribe({}); |
|
159 | 159 | |
|
160 | t.same(side, [1,1,2,4,0], ".tap() should be called in the order of registration"); | |
|
160 | t.same(side, [1, 1, 2, 4, 0], ".tap() should be called in the order of registration"); | |
|
161 | 161 | |
|
162 | 162 | side.length = 0; |
|
163 | 163 | |
|
164 | 164 | await new Promise<void>(resolve => { |
|
165 | of(1,2,delay(1).then(() => 3)) | |
|
166 | .tap({next: v => side.push(v)}) | |
|
167 | .tap({ next: v => v === 1 && resolve()}) | |
|
165 | of(1, 2, delay(1).then(() => 3)) | |
|
166 | .tap({ next: v => side.push(v) }) | |
|
167 | .tap({ next: v => v === 1 && resolve() }) | |
|
168 | 168 | .subscribe({}); |
|
169 | 169 | }); |
|
170 | 170 | |
|
171 | t.same(side, [1,2], ".tap() should be processed synchronously"); | |
|
171 | t.same(side, [1, 2], ".tap() should be processed synchronously"); | |
|
172 | ||
|
173 | }).catch(() => { }); | |
|
174 | ||
|
175 | tap.test(".while() tests", async t => { | |
|
176 | ||
|
177 | const seq = of(1, 2, 3, 4).while(v => v <= 2); | |
|
178 | ||
|
179 | t.same(await seq.collect(), [1, 2], "Should collect only taken elements"); | |
|
172 | 180 | |
|
173 | }).catch(() => {}); No newline at end of file | |
|
181 | const data: number[] = []; | |
|
182 | let complete = 0; | |
|
183 | seq.subscribe({ | |
|
184 | next: v => data.push(v), | |
|
185 | complete: () => complete++ | |
|
186 | }); | |
|
187 | ||
|
188 | t.same(data, [1, 2], "Should receive only taken elements"); | |
|
189 | t.equal(complete, 1, "Complete should run once"); | |
|
190 | ||
|
191 | }).catch(() => { }); No newline at end of file |
General Comments 0
You need to be logged in to leave comments.
Login now