mirror of
https://github.com/coracle-social/coracle.git
synced 2024-10-03 02:10:57 +00:00
Get generics to flow through store
This commit is contained in:
parent
64a36f6b2a
commit
479f9d6681
@ -5,12 +5,12 @@ type Derivable = Readable<any> | Readable<any>[]
|
|||||||
type Unsubscriber = () => void
|
type Unsubscriber = () => void
|
||||||
type Subscriber = <T>(v: T) => void | Unsubscriber
|
type Subscriber = <T>(v: T) => void | Unsubscriber
|
||||||
type R = Record<string, any>
|
type R = Record<string, any>
|
||||||
type M = Map<string, R>
|
type M<T> = Map<string, T>
|
||||||
|
|
||||||
export interface Readable<T> {
|
export interface Readable<T> {
|
||||||
get: () => T | undefined
|
get: () => T | undefined
|
||||||
subscribe: (f: Subscriber) => () => void
|
subscribe: (f: Subscriber) => () => void
|
||||||
derived: <U>(f: <T>(v: T) => U) => Readable<U>
|
derived: <U>(f: (v: T) => U) => Readable<U>
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Writable<T> implements Readable<T> {
|
export class Writable<T> implements Readable<T> {
|
||||||
@ -72,7 +72,7 @@ export class Derived<T> implements Readable<T> {
|
|||||||
this.callerSubs.forEach(f => f(this.get()))
|
this.callerSubs.forEach(f => f(this.get()))
|
||||||
}
|
}
|
||||||
|
|
||||||
get() {
|
get(): T {
|
||||||
const isMulti = is(Array, this.stores)
|
const isMulti = is(Array, this.stores)
|
||||||
const inputs = ensurePlural(this.stores).map(s => s.get())
|
const inputs = ensurePlural(this.stores).map(s => s.get())
|
||||||
|
|
||||||
@ -106,13 +106,13 @@ export class Derived<T> implements Readable<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Key implements Readable<R> {
|
export class Key<T extends R> implements Readable<T> {
|
||||||
readonly pk: string
|
readonly pk: string
|
||||||
readonly key: string
|
readonly key: string
|
||||||
private base: Writable<M>
|
private base: Writable<M<T>>
|
||||||
private store: Readable<R>
|
private store: Readable<T>
|
||||||
|
|
||||||
constructor(base: Writable<M>, pk: string, key: string) {
|
constructor(base: Writable<M<T>>, pk: string, key: string) {
|
||||||
if (!is(Map, base.get())) {
|
if (!is(Map, base.get())) {
|
||||||
throw new Error("`key` can only be used on map collections")
|
throw new Error("`key` can only be used on map collections")
|
||||||
}
|
}
|
||||||
@ -120,38 +120,38 @@ export class Key implements Readable<R> {
|
|||||||
this.pk = pk
|
this.pk = pk
|
||||||
this.key = key
|
this.key = key
|
||||||
this.base = base
|
this.base = base
|
||||||
this.store = base.derived<R>(m => m.get(key) as R)
|
this.store = base.derived<T>(m => m.get(key) as T)
|
||||||
}
|
}
|
||||||
|
|
||||||
get = () => this.base.get().get(this.key)
|
get = () => this.base.get().get(this.key)
|
||||||
|
|
||||||
subscribe = (f: Subscriber) => this.store.subscribe(f)
|
subscribe = (f: Subscriber) => this.store.subscribe(f)
|
||||||
|
|
||||||
derived = <U>(f: <V>(v: V) => U) => this.store.derived<U>(f)
|
derived = <U>(f: (v: T) => U) => this.store.derived<U>(f)
|
||||||
|
|
||||||
exists = () => this.base.get().has(this.key)
|
exists = () => this.base.get().has(this.key)
|
||||||
|
|
||||||
update = (f: (v: R) => R) =>
|
update = (f: (v: T) => T) =>
|
||||||
this.base.update((m: M) => {
|
this.base.update((m: M<T>) => {
|
||||||
if (!this.key) {
|
if (!this.key) {
|
||||||
throw new Error(`Cannot set key: "${this.key}"`)
|
throw new Error(`Cannot set key: "${this.key}"`)
|
||||||
}
|
}
|
||||||
|
|
||||||
const v = f(m.get(this.key) as R) as Record<string, any>
|
const v = f(m.get(this.key) as T) as Record<string, any>
|
||||||
|
|
||||||
// Make sure the pk always get set on the record
|
// Make sure the pk always get set on the record
|
||||||
if (v) {
|
if (v) {
|
||||||
v[this.pk] = this.key
|
v[this.pk] = this.key
|
||||||
|
|
||||||
m.set(this.key, v as R)
|
m.set(this.key, v as T)
|
||||||
}
|
}
|
||||||
|
|
||||||
return m
|
return m
|
||||||
})
|
})
|
||||||
|
|
||||||
set = (v: R) => this.update(() => v)
|
set = (v: T) => this.update(() => v)
|
||||||
|
|
||||||
merge = (d: R) => this.update(v => ({...v, ...d}))
|
merge = (d: T) => this.update(v => ({...v, ...d}))
|
||||||
|
|
||||||
remove = () =>
|
remove = () =>
|
||||||
this.base.update(m => {
|
this.base.update(m => {
|
||||||
@ -161,15 +161,15 @@ export class Key implements Readable<R> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Collection implements Readable<R[]> {
|
export class Collection<T extends R> implements Readable<T[]> {
|
||||||
readonly pk: string
|
readonly pk: string
|
||||||
#map: Writable<M>
|
#map: Writable<M<T>>
|
||||||
#list: Readable<R[]>
|
#list: Readable<T[]>
|
||||||
|
|
||||||
constructor(pk: string) {
|
constructor(pk: string) {
|
||||||
this.pk = pk
|
this.pk = pk
|
||||||
this.#map = writable(new Map())
|
this.#map = writable(new Map())
|
||||||
this.#list = this.#map.derived<R[]>((m: M) => Array.from(m.values()))
|
this.#list = this.#map.derived<T[]>((m: M<T>) => Array.from(m.values()))
|
||||||
}
|
}
|
||||||
|
|
||||||
get = () => this.#list.get()
|
get = () => this.#list.get()
|
||||||
@ -178,27 +178,27 @@ export class Collection implements Readable<R[]> {
|
|||||||
|
|
||||||
subscribe = (f: Subscriber) => this.#list.subscribe(f)
|
subscribe = (f: Subscriber) => this.#list.subscribe(f)
|
||||||
|
|
||||||
derived = <U>(f: <V>(v: V) => U) => this.#list.derived<U>(f)
|
derived = <U>(f: (v: T[]) => U) => this.#list.derived<U>(f)
|
||||||
|
|
||||||
key = (k: string) => new Key(this.#map, this.pk, k)
|
key = (k: string) => new Key(this.#map, this.pk, k)
|
||||||
|
|
||||||
set = (xs: R[]) => this.#map.set(new Map(xs.map(x => [x[this.pk], x])))
|
set = (xs: T[]) => this.#map.set(new Map(xs.map(x => [x[this.pk], x])))
|
||||||
|
|
||||||
update = (f: (v: R[]) => R[]) =>
|
update = (f: (v: T[]) => T[]) =>
|
||||||
this.#map.update(m => new Map(f(Array.from(m.values())).map(x => [x[this.pk], x])))
|
this.#map.update(m => new Map(f(Array.from(m.values())).map(x => [x[this.pk], x])))
|
||||||
|
|
||||||
reject = (f: (v: R) => boolean) => this.update(reject(f))
|
reject = (f: (v: T) => boolean) => this.update(reject(f))
|
||||||
|
|
||||||
filter = (f: (v: R) => boolean) => this.update(filter(f))
|
filter = (f: (v: T) => boolean) => this.update(filter(f))
|
||||||
|
|
||||||
map = (f: (v: R) => R) => this.update(map(f))
|
map = (f: (v: T) => T) => this.update(map(f))
|
||||||
}
|
}
|
||||||
|
|
||||||
export const writable = <T>(v: T) => new Writable(v)
|
export const writable = <T>(v: T) => new Writable(v)
|
||||||
|
|
||||||
export const derived = <U>(stores: Derivable, getValue: (values: any) => U) =>
|
export const derived = <T>(stores: Derivable, getValue: (values: any) => T) =>
|
||||||
new Derived(stores, getValue) as Readable<U>
|
new Derived(stores, getValue) as Readable<T>
|
||||||
|
|
||||||
export const key = (base: Writable<M>, pk: string, key: string) => new Key(base, pk, key)
|
export const key = <T extends R>(base: Writable<M<T>>, pk: string, key: string) => new Key<T>(base, pk, key)
|
||||||
|
|
||||||
export const collection = (pk: string) => new Collection(pk)
|
export const collection = <T extends R>(pk: string) => new Collection<T>(pk)
|
||||||
|
Loading…
Reference in New Issue
Block a user