import { removeFromArray } from "../utils"; import { CollectionField } from "./collection"; export interface CollectionInterface { new(relation: CollectionField, instance): BaseCollectionInterface } export abstract class BaseCollectionInterface { constructor( protected readonly relation: CollectionField, protected readonly instance: any, ) { } get collection() { return this.relation.access.get.call(this.instance); } abstract instanciate(initial: Iterable): any; abstract items(): Iterable; abstract storeItem(item: T): void; abstract unstoreItem(item: T): void; asSet() { return new Set(this.items()); } } export class ArrayInterface extends BaseCollectionInterface { constructor(relation: CollectionField, instance) { super(relation, instance); } instanciate(initial) { return [...initial]; } items(): Iterable { return this.collection; } storeItem(object: T): void { this.collection.push(object); } unstoreItem(object: T): void { removeFromArray(this.collection, object); } } export class SetInterface extends BaseCollectionInterface { constructor(relation: CollectionField, instance) { super(relation, instance); } instanciate(initial?) { return new Set(initial); } items(): Iterable { return this.collection; } storeItem(object: T): void { this.collection.add(object); } unstoreItem(object: T): void { this.collection.delete(object); } } export class ObjectInterface extends BaseCollectionInterface { constructor(relation: CollectionField, instance) { super(relation, instance); } instanciate(initial) { const value = {}; for (let item of initial) { value[this.getIndexKey(item)] = item; } return value; } protected getIndexKey(obj) { return obj[this.relation.options.indexBy || 'id']; } items(): Iterable { return Object.values(this.collection); } storeItem(object: T): void { this.collection[this.getIndexKey(object)] = object; } unstoreItem(object: T): void { delete this.collection[this.getIndexKey(object)]; } } export class MapInterface extends BaseCollectionInterface { constructor(relation: CollectionField, instance) { super(relation, instance); } instanciate(initial) { const value = new Map(); for (let item of initial) { value.set(this.getIndexKey(item), item); } return value; } protected getIndexKey(obj) { return obj[this.relation.options.indexBy || 'id']; } items(): Iterable { return this.collection.values(); } storeItem(object: T): void { this.collection.set(this.getIndexKey(object), object); } unstoreItem(object: T): void { this.collection.delete(this.getIndexKey(object)); } }