Merge pull request #702 from vector-im/bwindels/observablemapts

convert (Base)ObservableMap to typescript
This commit is contained in:
Bruno Windels 2022-03-09 11:53:59 +01:00 committed by GitHub
commit ca211f929b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 69 additions and 55 deletions

View file

@ -13,7 +13,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import {ObservableMap} from "../../../../observable/map/ObservableMap.js";
import {ObservableMap} from "../../../../observable/map/ObservableMap";
export class ReactionsViewModel {
constructor(parentTile) {

View file

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import {ObservableMap} from "../../../observable/map/ObservableMap.js";
import {ObservableMap} from "../../../observable/map/ObservableMap";
import {RetainedValue} from "../../../utils/RetainedValue";
export class MemberList extends RetainedValue {

View file

@ -18,14 +18,14 @@ import {SortedMapList} from "./list/SortedMapList.js";
import {FilteredMap} from "./map/FilteredMap.js";
import {MappedMap} from "./map/MappedMap.js";
import {JoinedMap} from "./map/JoinedMap.js";
import {BaseObservableMap} from "./map/BaseObservableMap.js";
import {BaseObservableMap} from "./map/BaseObservableMap";
// re-export "root" (of chain) collections
export { ObservableArray } from "./list/ObservableArray";
export { SortedArray } from "./list/SortedArray";
export { MappedList } from "./list/MappedList";
export { AsyncMappedList } from "./list/AsyncMappedList";
export { ConcatList } from "./list/ConcatList";
export { ObservableMap } from "./map/ObservableMap.js";
export { ObservableMap } from "./map/ObservableMap";
// avoid circular dependency between these classes
// and BaseObservableMap (as they extend it)

View file

@ -133,7 +133,7 @@ export class SortedMapList extends BaseObservableList {
}
}
import {ObservableMap} from "../map/ObservableMap.js";
import {ObservableMap} from "../map/ObservableMap";
export function tests() {
return {

View file

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import {BaseObservableMap} from "./BaseObservableMap.js";
import {BaseObservableMap} from "./BaseObservableMap";
export class ApplyMap extends BaseObservableMap {
constructor(source, apply) {

View file

@ -16,7 +16,14 @@ limitations under the License.
import {BaseObservable} from "../BaseObservable";
export class BaseObservableMap extends BaseObservable {
export interface IMapObserver<K, V> {
onReset(): void;
onAdd(key: K, value:V): void;
onUpdate(key: K, value: V, params: any): void;
onRemove(key: K, value: V): void
}
export abstract class BaseObservableMap<K, V> extends BaseObservable<IMapObserver<K, V>> {
emitReset() {
for(let h of this._handlers) {
h.onReset();
@ -24,15 +31,15 @@ export class BaseObservableMap extends BaseObservable {
}
// we need batch events, mostly on index based collection though?
// maybe we should get started without?
emitAdd(key, value) {
emitAdd(key: K, value: V) {
for(let h of this._handlers) {
h.onAdd(key, value);
}
}
emitUpdate(key, value, ...params) {
emitUpdate(key, value, params) {
for(let h of this._handlers) {
h.onUpdate(key, value, ...params);
h.onUpdate(key, value, params);
}
}
@ -42,16 +49,7 @@ export class BaseObservableMap extends BaseObservable {
}
}
[Symbol.iterator]() {
throw new Error("unimplemented");
}
get size() {
throw new Error("unimplemented");
}
// eslint-disable-next-line no-unused-vars
get(key) {
throw new Error("unimplemented");
}
abstract [Symbol.iterator](): Iterator<[K, V]>;
abstract get size(): number;
abstract get(key: K): V | undefined;
}

View file

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import {BaseObservableMap} from "./BaseObservableMap.js";
import {BaseObservableMap} from "./BaseObservableMap";
export class FilteredMap extends BaseObservableMap {
constructor(source, filter) {
@ -166,7 +166,7 @@ class FilterIterator {
}
}
import {ObservableMap} from "./ObservableMap.js";
import {ObservableMap} from "./ObservableMap";
export function tests() {
return {
"filter preloaded list": assert => {

View file

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import {BaseObservableMap} from "./BaseObservableMap.js";
import {BaseObservableMap} from "./BaseObservableMap";
export class JoinedMap extends BaseObservableMap {
constructor(sources) {
@ -191,7 +191,7 @@ class SourceSubscriptionHandler {
}
import { ObservableMap } from "./ObservableMap.js";
import { ObservableMap } from "./ObservableMap";
export function tests() {

View file

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import {BaseObservableMap} from "./BaseObservableMap.js";
import {BaseObservableMap} from "./BaseObservableMap";
export class LogMap extends BaseObservableMap {
constructor(source, log) {

View file

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import {BaseObservableMap} from "./BaseObservableMap.js";
import {BaseObservableMap} from "./BaseObservableMap";
/*
so a mapped value can emit updates on it's own with this._emitSpontaneousUpdate that is passed in the mapping function
how should the mapped value be notified of an update though? and can it then decide to not propagate the update?

View file

@ -14,15 +14,17 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import {BaseObservableMap} from "./BaseObservableMap.js";
import {BaseObservableMap} from "./BaseObservableMap";
export class ObservableMap extends BaseObservableMap {
constructor(initialValues) {
export class ObservableMap<K, V> extends BaseObservableMap<K, V> {
private readonly _values: Map<K, V>;
constructor(initialValues?: (readonly [K, V])[]) {
super();
this._values = new Map(initialValues);
}
update(key, params) {
update(key: K, params?: any): boolean {
const value = this._values.get(key);
if (value !== undefined) {
// could be the same value, so it's already updated
@ -34,7 +36,7 @@ export class ObservableMap extends BaseObservableMap {
return false; // or return existing value?
}
add(key, value) {
add(key: K, value: V): boolean {
if (!this._values.has(key)) {
this._values.set(key, value);
this.emitAdd(key, value);
@ -43,7 +45,7 @@ export class ObservableMap extends BaseObservableMap {
return false; // or return existing value?
}
remove(key) {
remove(key: K): boolean {
const value = this._values.get(key);
if (value !== undefined) {
this._values.delete(key);
@ -54,39 +56,39 @@ export class ObservableMap extends BaseObservableMap {
}
}
set(key, value) {
set(key: K, value: V): boolean {
if (this._values.has(key)) {
// We set the value here because update only supports inline updates
this._values.set(key, value);
return this.update(key);
return this.update(key, undefined);
}
else {
return this.add(key, value);
}
}
reset() {
reset(): void {
this._values.clear();
this.emitReset();
}
get(key) {
get(key: K): V | undefined {
return this._values.get(key);
}
get size() {
get size(): number {
return this._values.size;
}
[Symbol.iterator]() {
[Symbol.iterator](): Iterator<[K, V]> {
return this._values.entries();
}
values() {
values(): Iterator<V> {
return this._values.values();
}
keys() {
keys(): Iterator<K> {
return this._values.keys();
}
}
@ -105,13 +107,16 @@ export function tests() {
test_add(assert) {
let fired = 0;
const map = new ObservableMap();
const map = new ObservableMap<number, {value: number}>();
map.subscribe({
onAdd(key, value) {
fired += 1;
assert.equal(key, 1);
assert.deepEqual(value, {value: 5});
}
},
onUpdate() {},
onRemove() {},
onReset() {}
});
map.add(1, {value: 5});
assert.equal(map.size, 1);
@ -120,7 +125,7 @@ export function tests() {
test_update(assert) {
let fired = 0;
const map = new ObservableMap();
const map = new ObservableMap<number, {number: number}>();
const value = {number: 5};
map.add(1, value);
map.subscribe({
@ -129,7 +134,10 @@ export function tests() {
assert.equal(key, 1);
assert.deepEqual(value, {number: 6});
assert.equal(params, "test");
}
},
onAdd() {},
onRemove() {},
onReset() {}
});
value.number = 6;
map.update(1, "test");
@ -138,9 +146,12 @@ export function tests() {
test_update_unknown(assert) {
let fired = 0;
const map = new ObservableMap();
const map = new ObservableMap<number, {number: number}>();
map.subscribe({
onUpdate() { fired += 1; }
onUpdate() { fired += 1; },
onAdd() {},
onRemove() {},
onReset() {}
});
const result = map.update(1);
assert.equal(fired, 0);
@ -149,7 +160,7 @@ export function tests() {
test_set(assert) {
let add_fired = 0, update_fired = 0;
const map = new ObservableMap();
const map = new ObservableMap<number, {value: number}>();
map.subscribe({
onAdd(key, value) {
add_fired += 1;
@ -160,7 +171,9 @@ export function tests() {
update_fired += 1;
assert.equal(key, 1);
assert.deepEqual(value, {value: 7});
}
},
onRemove() {},
onReset() {}
});
// Add
map.set(1, {value: 5});
@ -174,7 +187,7 @@ export function tests() {
test_remove(assert) {
let fired = 0;
const map = new ObservableMap();
const map = new ObservableMap<number, {value: number}>();
const value = {value: 5};
map.add(1, value);
map.subscribe({
@ -182,7 +195,10 @@ export function tests() {
fired += 1;
assert.equal(key, 1);
assert.deepEqual(value, {value: 5});
}
},
onAdd() {},
onUpdate() {},
onReset() {}
});
map.remove(1);
assert.equal(map.size, 0);
@ -190,8 +206,8 @@ export function tests() {
},
test_iterate(assert) {
const results = [];
const map = new ObservableMap();
const results: any[] = [];
const map = new ObservableMap<number, {number: number}>();
map.add(1, {number: 5});
map.add(2, {number: 6});
map.add(3, {number: 7});
@ -204,7 +220,7 @@ export function tests() {
assert.equal(results.find(([key]) => key === 3)[1].number, 7);
},
test_size(assert) {
const map = new ObservableMap();
const map = new ObservableMap<number, {number: number}>();
map.add(1, {number: 5});
map.add(2, {number: 6});
assert.equal(map.size, 2);