found a more clever way to do this which eliminates boilerplate

This commit is contained in:
Isaiah Becker-Mayer 2022-07-26 22:14:14 -07:00
parent 73b83fdab8
commit 70b68c5b16
8 changed files with 42 additions and 153 deletions

View File

@ -16,22 +16,17 @@ limitations under the License.
import {BaseObservableMap} from "./BaseObservableMap";
import {SubscriptionHandle} from "../BaseObservable";
import {BaseObservableMapDefaults, Mapper, Updater, Comparator, Filter} from "./BaseObservableMapDefaults";
import {JoinedMap} from "./JoinedMap";
import {MappedMap} from "./MappedMap";
import {FilteredMap} from "./FilteredMap";
import {SortedMapList} from "../list/SortedMapList.js";
import {BaseObservableMapDefaults} from "./BaseObservableMapDefaults";
export class ApplyMap<K, V> extends BaseObservableMap<K, V> {
private _defaults = new BaseObservableMapDefaults<K, V>();
private _source: BaseObservableMap<K, V>;
private _subscription?: SubscriptionHandle;
private _apply?: Apply<K, V>;
constructor(source: BaseObservableMap<K, V>, apply?: Apply<K, V>) {
super();
super(new BaseObservableMapDefaults<K, V>());
this._source = source;
this._apply = apply;
}
@ -103,23 +98,6 @@ export class ApplyMap<K, V> extends BaseObservableMap<K, V> {
get(key: K): V | undefined {
return this._source.get(key);
}
join(...otherMaps: Array<typeof this>): JoinedMap<K, V> {
return this._defaults.join(this, ...otherMaps);
}
mapValues(mapper: Mapper<V>, updater?: Updater<V>): MappedMap<K, V> {
return this._defaults.mapValues(this, mapper, updater);
}
sortValues(comparator: Comparator<V>): SortedMapList {
return this._defaults.sortValues(this, comparator);
}
filterValues(filter: Filter<K, V>): FilteredMap<K, V> {
return this._defaults.filterValues(this, filter);
}
}
type Apply<K, V> = (key: K, value: V, params?: any) => void;

View File

@ -19,7 +19,8 @@ import {JoinedMap} from "../map/JoinedMap";
import {MappedMap} from "../map/MappedMap";
import {FilteredMap} from "../map/FilteredMap";
import {SortedMapList} from "../list/SortedMapList.js";
import {Mapper, Updater, Comparator, Filter} from "./BaseObservableMapDefaults";
import type {BaseObservableMapDefaults, Mapper, Updater, Comparator, Filter} from "./BaseObservableMapDefaults";
export interface IMapObserver<K, V> {
onReset(): void;
@ -29,6 +30,13 @@ export interface IMapObserver<K, V> {
}
export abstract class BaseObservableMap<K, V> extends BaseObservable<IMapObserver<K, V>> {
private _defaults: BaseObservableMapDefaults<K, V>;
constructor(defaults: BaseObservableMapDefaults<K, V>) {
super();
this._defaults = defaults;
}
emitReset(): void {
for(let h of this._handlers) {
h.onReset();
@ -54,17 +62,22 @@ export abstract class BaseObservableMap<K, V> extends BaseObservable<IMapObserve
}
}
// The following group of functions have a default implementation
// in the neighboring `BaseObservableMapDefaults.ts`. See the comment
// in that file for the explanation for why the default implementation
// isn't defined here. See the neighboring `ObservableMap.ts` for an
// example of how to easily add the boilerplate for using the default
// implementations of these functions in a class that extends
// this one (which is most likely what you want to do).
abstract join(...otherMaps: Array<typeof this>): JoinedMap<K, V>;
abstract mapValues(mapper: Mapper<V>, updater?: Updater<V>): MappedMap<K, V>;
abstract sortValues(comparator: Comparator<V>): SortedMapList;
abstract filterValues(filter: Filter<K, V>): FilteredMap<K, V>;
join(...otherMaps: Array<typeof this>): JoinedMap<K, V> {
return this._defaults.join(this, ...otherMaps);
}
mapValues(mapper: Mapper<V>, updater?: Updater<V>): MappedMap<K, V> {
return this._defaults.mapValues(this, mapper, updater);
}
sortValues(comparator: Comparator<V>): SortedMapList {
return this._defaults.sortValues(this, comparator);
}
filterValues(filter: Filter<K, V>): FilteredMap<K, V> {
return this._defaults.filterValues(this, filter);
}
abstract [Symbol.iterator](): Iterator<[K, V]>;
abstract get size(): number;

View File

@ -13,15 +13,14 @@ 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 {BaseObservableMap} from "./BaseObservableMap";
import type {BaseObservableMap} from "./BaseObservableMap";
import {FilteredMap} from "./FilteredMap";
import {MappedMap} from "./MappedMap";
import {JoinedMap} from "./JoinedMap";
import {SortedMapList} from "../list/SortedMapList.js";
// This class is used as a default implementation of
// the respective abstract functions in BaseObservableMap.
// This class provides implementations of functions that are part of BaseObservableMap.
// It is kept as its own class in its own file in order to avoid a circular
// dependency between the classes that extend BaseObservableMap which are
// instantiated here (i.e. `new JoinedMap()`).

View File

@ -16,20 +16,17 @@ limitations under the License.
import {BaseObservableMap} from "./BaseObservableMap";
import {SubscriptionHandle} from "../BaseObservable";
import {BaseObservableMapDefaults, Mapper, Updater, Comparator, Filter} from "./BaseObservableMapDefaults";
import {JoinedMap} from "./JoinedMap";
import {MappedMap} from "./MappedMap";
import {SortedMapList} from "../list/SortedMapList.js";
import {BaseObservableMapDefaults, Filter} from "./BaseObservableMapDefaults";
export class FilteredMap<K, V> extends BaseObservableMap<K, V> {
private _defaults = new BaseObservableMapDefaults<K, V>();
private _source: BaseObservableMap<K, V>;
private _filter: Filter<K, V>;
private _included?: Map<K, boolean>;
private _subscription?: SubscriptionHandle;
constructor(source: BaseObservableMap<K, V>, filter: Filter<K, V>) {
super();
super(new BaseObservableMapDefaults<K, V>());
this._source = source;
this._filter = filter;
}
@ -162,22 +159,6 @@ export class FilteredMap<K, V> extends BaseObservableMap<K, V> {
return value;
}
}
join(...otherMaps: Array<typeof this>): JoinedMap<K, V> {
return this._defaults.join(this, ...otherMaps);
}
mapValues(mapper: Mapper<V>, updater?: Updater<V>): MappedMap<K, V>{
return this._defaults.mapValues(this, mapper, updater);
}
sortValues(comparator: Comparator<V>): SortedMapList {
return this._defaults.sortValues(this, comparator);
}
filterValues(filter: Filter<K, V>): FilteredMap<K, V> {
return this._defaults.filterValues(this, filter);
}
}
class FilterIterator<K, V> {

View File

@ -15,20 +15,16 @@ limitations under the License.
*/
import {BaseObservableMap} from "./BaseObservableMap";
import {BaseObservableMapDefaults, Mapper, Updater, Comparator, Filter} from "./BaseObservableMapDefaults";
import {FilteredMap} from "./FilteredMap";
import {MappedMap} from "./MappedMap";
import {SortedMapList} from "../list/SortedMapList.js";
import {BaseObservableMapDefaults} from "./BaseObservableMapDefaults";
import {SubscriptionHandle} from "../BaseObservable";
export class JoinedMap<K, V> extends BaseObservableMap<K, V> {
private _defaults = new BaseObservableMapDefaults<K, V>();
protected _sources: BaseObservableMap<K, V>[];
private _subscriptions?: SourceSubscriptionHandler<K, V>[];
constructor(sources: BaseObservableMap<K, V>[]) {
super();
super(new BaseObservableMapDefaults<K, V>());
this._sources = sources;
}
@ -133,23 +129,6 @@ export class JoinedMap<K, V> extends BaseObservableMap<K, V> {
}
return undefined;
}
join(...otherMaps: Array<typeof this>): JoinedMap<K, V> {
return this._defaults.join(this, ...otherMaps);
}
mapValues(mapper: Mapper<V>, updater?: Updater<V>): MappedMap<K, V> {
return this._defaults.mapValues(this, mapper, updater);
}
sortValues(comparator: Comparator<V>): SortedMapList {
return this._defaults.sortValues(this, comparator);
}
filterValues(filter: Filter<K, V>): FilteredMap<K, V> {
return this._defaults.filterValues(this, filter);
}
}
class JoinedIterator<K, V> implements Iterator<[K, V]> {

View File

@ -15,23 +15,19 @@ limitations under the License.
*/
import {BaseObservableMap} from "./BaseObservableMap";
import {BaseObservableMapDefaults, Mapper, Updater, Comparator, Filter} from "./BaseObservableMapDefaults";
import {FilteredMap} from "./FilteredMap";
import {MappedMap} from "./MappedMap";
import {JoinedMap} from "./JoinedMap";
import {SortedMapList} from "../list/SortedMapList.js";
import {BaseObservableMapDefaults} from "./BaseObservableMapDefaults";
import {SubscriptionHandle} from "../BaseObservable";
import {ILogItem, LabelOrValues} from "../../logging/types";
import {LogLevel} from "../../logging/LogFilter";
export class LogMap<K, V> extends BaseObservableMap<K, V> {
private _defaults = new BaseObservableMapDefaults<K, V>();
private _source: BaseObservableMap<K, V>;
private _subscription?: SubscriptionHandle;
private _log: ILogItem;
constructor(source: BaseObservableMap<K, V>, log: ILogItem) {
super();
super(new BaseObservableMapDefaults<K, V>());
this._source = source;
this._log = log;
}
@ -84,21 +80,4 @@ export class LogMap<K, V> extends BaseObservableMap<K, V> {
get(key: K): V | undefined{
return this._source.get(key);
}
join(...otherMaps: Array<typeof this>): JoinedMap<K, V> {
return this._defaults.join(this, ...otherMaps);
}
mapValues(mapper: Mapper<V>, updater?: Updater<V>): MappedMap<K, V> {
return this._defaults.mapValues(this, mapper, updater);
}
sortValues(comparator: Comparator<V>): SortedMapList {
return this._defaults.sortValues(this, comparator);
}
filterValues(filter: Filter<K, V>): FilteredMap<K, V> {
return this._defaults.filterValues(this, filter);
}
}

View File

@ -15,18 +15,15 @@ limitations under the License.
*/
import {BaseObservableMap} from "./BaseObservableMap";
import {BaseObservableMapDefaults, Mapper, Updater, Comparator, Filter} from "./BaseObservableMapDefaults";
import {JoinedMap} from "./JoinedMap";
import {FilteredMap} from "./FilteredMap";
import {SortedMapList} from "../list/SortedMapList.js";
import {BaseObservableMapDefaults, Mapper, Updater} from "./BaseObservableMapDefaults";
import {SubscriptionHandle} from "../BaseObservable";
/*
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?
*/
export class MappedMap<K, V> extends BaseObservableMap<K, V> {
private _defaults = new BaseObservableMapDefaults<K, V>();
private _source: BaseObservableMap<K, V>;
private _mapper: Mapper<V>;
private _updater?: Updater<V>;
@ -39,7 +36,7 @@ export class MappedMap<K, V> extends BaseObservableMap<K, V> {
mapper: Mapper<V>,
updater?: Updater<V>
) {
super();
super(new BaseObservableMapDefaults<K, V>());
this._source = source;
this._mapper = mapper;
this._updater = updater;
@ -113,20 +110,4 @@ export class MappedMap<K, V> extends BaseObservableMap<K, V> {
get(key: K): V | undefined {
return this._mappedValues.get(key);
}
join(...otherMaps: Array<typeof this>): JoinedMap<K, V> {
return this._defaults.join(this, ...otherMaps);
}
mapValues(mapper: Mapper<V>, updater?: Updater<V>): MappedMap<K, V>{
return this._defaults.mapValues(this, mapper, updater);
}
sortValues(comparator: Comparator<V>): SortedMapList {
return this._defaults.sortValues(this, comparator);
}
filterValues(filter: Filter<K, V>): FilteredMap<K, V> {
return this._defaults.filterValues(this, filter);
}
}

View File

@ -15,19 +15,14 @@ limitations under the License.
*/
import {BaseObservableMap} from "./BaseObservableMap";
import {BaseObservableMapDefaults, Mapper, Updater, Comparator, Filter} from "./BaseObservableMapDefaults";
import {JoinedMap} from "./JoinedMap";
import {MappedMap} from "./MappedMap";
import {FilteredMap} from "./FilteredMap";
import {SortedMapList} from "../list/SortedMapList.js";
import {BaseObservableMapDefaults} from "./BaseObservableMapDefaults";
export class ObservableMap<K, V> extends BaseObservableMap<K, V> {
private _defaults = new BaseObservableMapDefaults<K, V>();
private readonly _values: Map<K, V>;
constructor(initialValues?: (readonly [K, V])[]) {
super();
super(new BaseObservableMapDefaults<K, V>());
this._values = new Map(initialValues);
}
@ -98,22 +93,6 @@ export class ObservableMap<K, V> extends BaseObservableMap<K, V> {
keys(): Iterator<K> {
return this._values.keys();
}
join(...otherMaps: Array<typeof this>): JoinedMap<K, V> {
return this._defaults.join(this, ...otherMaps);
}
mapValues(mapper: Mapper<V>, updater?: Updater<V>): MappedMap<K, V> {
return this._defaults.mapValues(this, mapper, updater);
}
sortValues(comparator: Comparator<V>): SortedMapList {
return this._defaults.sortValues(this, comparator);
}
filterValues(filter: Filter<K, V>): FilteredMap<K, V> {
return this._defaults.filterValues(this, filter);
}
};
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type