applesauce-core
Advanced tools
Comparing version 0.0.0-next-20250213191824 to 0.0.0-next-20250213194606
import { Observable } from "rxjs"; | ||
import { Filter, NostrEvent } from "nostr-tools"; | ||
import { EventStore } from "../event-store/event-store.js"; | ||
import { LRU } from "../helpers/lru.js"; | ||
import * as Queries from "../queries/index.js"; | ||
import { AddressPointer, EventPointer } from "nostr-tools/nip19"; | ||
export type Query<T extends unknown> = { | ||
/** | ||
* A unique key for this query. this is used to detect duplicate queries | ||
*/ | ||
/** A unique key for this query. this is used to detect duplicate queries */ | ||
key: string; | ||
/** | ||
* The meat of the query, this should return an Observables that subscribes to the eventStore in some way | ||
*/ | ||
/** The meat of the query, this should return an Observables that subscribes to the eventStore in some way */ | ||
run: (events: EventStore, store: QueryStore) => Observable<T>; | ||
@@ -22,14 +17,7 @@ }; | ||
constructor(store: EventStore); | ||
queries: LRU<Query<any>>; | ||
observables: WeakMap<Query<any>, Observable<any>>; | ||
queries: Map<QueryConstructor<any, any[]>, Map<string, Observable<any>>>; | ||
/** Creates a cached query */ | ||
createQuery<T extends unknown, Args extends Array<any>>(queryConstructor: (...args: Args) => { | ||
key: string; | ||
run: (events: EventStore, store: QueryStore) => Observable<T>; | ||
}, ...args: Args): Observable<T | undefined>; | ||
createQuery<T extends unknown, Args extends Array<any>>(queryConstructor: QueryConstructor<T, Args>, ...args: Args): Observable<T | undefined>; | ||
/** Creates a query and waits for the next value */ | ||
executeQuery<T extends unknown, Args extends Array<any>>(queryConstructor: (...args: Args) => { | ||
key: string; | ||
run: (events: EventStore, store: QueryStore) => Observable<T>; | ||
}, ...args: Args): Promise<T>; | ||
executeQuery<T extends unknown, Args extends Array<any>>(queryConstructor: QueryConstructor<T, Args>, ...args: Args): Promise<T>; | ||
/** Creates a SingleEventQuery */ | ||
@@ -36,0 +24,0 @@ event(id: string): Observable<import("nostr-tools").Event | undefined>; |
@@ -1,3 +0,3 @@ | ||
import { filter, ReplaySubject, share, startWith, timer } from "rxjs"; | ||
import { LRU } from "../helpers/lru.js"; | ||
import { filter, finalize, ReplaySubject, share, startWith, timer } from "rxjs"; | ||
import hash_sum from "hash-sum"; | ||
import * as Queries from "../queries/index.js"; | ||
@@ -13,20 +13,29 @@ import { getObservableValue } from "../observable/get-observable-value.js"; | ||
} | ||
queries = new LRU(); | ||
observables = new WeakMap(); | ||
queries = new Map(); | ||
/** Creates a cached query */ | ||
createQuery(queryConstructor, ...args) { | ||
const tempQuery = queryConstructor(...args); | ||
const key = queryConstructor.name + "|" + tempQuery.key; | ||
let query = this.queries.get(key); | ||
if (!query) { | ||
query = tempQuery; | ||
this.queries.set(key, tempQuery); | ||
let observables = this.queries.get(queryConstructor); | ||
if (!observables) { | ||
observables = new Map(); | ||
this.queries.set(queryConstructor, observables); | ||
} | ||
let observable = this.observables.get(query); | ||
const key = hash_sum(args); | ||
let observable = observables.get(key); | ||
if (!observable) { | ||
const observable = query | ||
const cleanup = () => { | ||
if (observables.get(key) === observable) | ||
observables.delete(key); | ||
}; | ||
observable = queryConstructor(...args) | ||
.run(this.store, this) | ||
.pipe(startWith(undefined), share({ connector: () => new ReplaySubject(1), resetOnComplete: () => timer(60_000) })); | ||
this.observables.set(query, observable); | ||
return observable; | ||
.pipe( | ||
// always emit undefined so the observable is sync | ||
startWith(undefined), | ||
// remove the observable when its subscribed | ||
finalize(cleanup), | ||
// only create a single observable for all components | ||
share({ connector: () => new ReplaySubject(1), resetOnComplete: () => timer(60_000) })); | ||
// set debug fields | ||
Reflect.set(observable, "queryArgs", args); | ||
observables.set(key, observable); | ||
} | ||
@@ -33,0 +42,0 @@ return observable; |
{ | ||
"name": "applesauce-core", | ||
"version": "0.0.0-next-20250213191824", | ||
"version": "0.0.0-next-20250213194606", | ||
"description": "", | ||
@@ -5,0 +5,0 @@ "type": "module", |
196875
4748