applesauce-core 0.0.0-next-20250213191824 → 0.0.0-next-20250213194606

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,17 +1,12 @@
1
1
  import { Observable } from "rxjs";
2
2
  import { Filter, NostrEvent } from "nostr-tools";
3
3
  import { EventStore } from "../event-store/event-store.js";
4
- import { LRU } from "../helpers/lru.js";
5
4
  import * as Queries from "../queries/index.js";
6
5
  import { AddressPointer, EventPointer } from "nostr-tools/nip19";
7
6
  export type Query<T extends unknown> = {
8
- /**
9
- * A unique key for this query. this is used to detect duplicate queries
10
- */
7
+ /** A unique key for this query. this is used to detect duplicate queries */
11
8
  key: string;
12
- /**
13
- * The meat of the query, this should return an Observables that subscribes to the eventStore in some way
14
- */
9
+ /** The meat of the query, this should return an Observables that subscribes to the eventStore in some way */
15
10
  run: (events: EventStore, store: QueryStore) => Observable<T>;
16
11
  };
17
12
  export type QueryConstructor<T extends unknown, Args extends Array<any>> = (...args: Args) => Query<T>;
@@ -19,18 +14,11 @@ export declare class QueryStore {
19
14
  static Queries: typeof Queries;
20
15
  store: EventStore;
21
16
  constructor(store: EventStore);
22
- queries: LRU<Query<any>>;
23
- observables: WeakMap<Query<any>, Observable<any>>;
17
+ queries: Map<QueryConstructor<any, any[]>, Map<string, Observable<any>>>;
24
18
  /** Creates a cached query */
25
- createQuery<T extends unknown, Args extends Array<any>>(queryConstructor: (...args: Args) => {
26
- key: string;
27
- run: (events: EventStore, store: QueryStore) => Observable<T>;
28
- }, ...args: Args): Observable<T | undefined>;
19
+ createQuery<T extends unknown, Args extends Array<any>>(queryConstructor: QueryConstructor<T, Args>, ...args: Args): Observable<T | undefined>;
29
20
  /** Creates a query and waits for the next value */
30
- executeQuery<T extends unknown, Args extends Array<any>>(queryConstructor: (...args: Args) => {
31
- key: string;
32
- run: (events: EventStore, store: QueryStore) => Observable<T>;
33
- }, ...args: Args): Promise<T>;
21
+ executeQuery<T extends unknown, Args extends Array<any>>(queryConstructor: QueryConstructor<T, Args>, ...args: Args): Promise<T>;
34
22
  /** Creates a SingleEventQuery */
35
23
  event(id: string): Observable<import("nostr-tools").Event | undefined>;
36
24
  /** Creates a MultipleEventsQuery */
@@ -1,5 +1,5 @@
1
- import { filter, ReplaySubject, share, startWith, timer } from "rxjs";
2
- import { LRU } from "../helpers/lru.js";
1
+ import { filter, finalize, ReplaySubject, share, startWith, timer } from "rxjs";
2
+ import hash_sum from "hash-sum";
3
3
  import * as Queries from "../queries/index.js";
4
4
  import { getObservableValue } from "../observable/get-observable-value.js";
5
5
  export class QueryStore {
@@ -10,24 +10,33 @@ export class QueryStore {
10
10
  throw new Error("EventStore required");
11
11
  this.store = store;
12
12
  }
13
- queries = new LRU();
14
- observables = new WeakMap();
13
+ queries = new Map();
15
14
  /** Creates a cached query */
16
15
  createQuery(queryConstructor, ...args) {
17
- const tempQuery = queryConstructor(...args);
18
- const key = queryConstructor.name + "|" + tempQuery.key;
19
- let query = this.queries.get(key);
20
- if (!query) {
21
- query = tempQuery;
22
- this.queries.set(key, tempQuery);
16
+ let observables = this.queries.get(queryConstructor);
17
+ if (!observables) {
18
+ observables = new Map();
19
+ this.queries.set(queryConstructor, observables);
23
20
  }
24
- let observable = this.observables.get(query);
21
+ const key = hash_sum(args);
22
+ let observable = observables.get(key);
25
23
  if (!observable) {
26
- const observable = query
24
+ const cleanup = () => {
25
+ if (observables.get(key) === observable)
26
+ observables.delete(key);
27
+ };
28
+ observable = queryConstructor(...args)
27
29
  .run(this.store, this)
28
- .pipe(startWith(undefined), share({ connector: () => new ReplaySubject(1), resetOnComplete: () => timer(60_000) }));
29
- this.observables.set(query, observable);
30
- return observable;
30
+ .pipe(
31
+ // always emit undefined so the observable is sync
32
+ startWith(undefined),
33
+ // remove the observable when its subscribed
34
+ finalize(cleanup),
35
+ // only create a single observable for all components
36
+ share({ connector: () => new ReplaySubject(1), resetOnComplete: () => timer(60_000) }));
37
+ // set debug fields
38
+ Reflect.set(observable, "queryArgs", args);
39
+ observables.set(key, observable);
31
40
  }
32
41
  return observable;
33
42
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "applesauce-core",
3
- "version": "0.0.0-next-20250213191824",
3
+ "version": "0.0.0-next-20250213194606",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",