Francesco Borzi
Francesco Borzi

Reputation: 62024

Rxjs how to cache the result of an observable for a given argument?

In my app I use rxjs and I have a method that looks like this:

query<T extends TableRow>(queryString: string, silent = false): Observable<T[]> {
  return this.sqliteService.dbQuery<T>(queryString).pipe(
    tap(val => {
      if (this.configService.debugMode && !silent) {
        console.log(`\n${queryString}`);
        console.log(val);
      }
    })
  );
}

My query method interlly calls dbQuery that queries an sqlite database.

Also, the query method is called many times in my app. So I'd like to globally cache the result whenever the queryString is the same.

In other words, I'd like the query method to avoid calling again dbQuery when called with a queryString parameter that has been called before, by returning the previously-cached value.

Not sure if this is relevant: my query method lives in an Angular singleton service.

Upvotes: 1

Views: 2439

Answers (2)

Francesco Borzi
Francesco Borzi

Reputation: 62024

I ended up with the following solution:

private cache: Observable<string>[] = [];

getItem(id: number): Observable<string> {

  if (!this.cache[id]) {
    this.cache[id] = this.query<string>(
      `SELECT column FROM table WHERE id = ${id}`
    ).pipe(shareReplay());
  }

  return this.cache[id];
}

Upvotes: 1

Kurt Hamilton
Kurt Hamilton

Reputation: 13515

First time through, save the remote value to a local cache property with a key that is the query string.

On subsequent requests, return the existing property for the corresponding key.

private cache = {};

query<T extends TableRow>(queryString: string, silent = false): Observable<T[]> {
  if (this.cache.hasOwnProperty(queryString)) {
    return of(this.cache[queryString]);
  }

  return this.sqliteService.dbQuery<T>(queryString).pipe(
    tap(val => {
      this.cache[queryString] = val;

      if (this.configService.debugMode && !silent) {
        console.log(`\n${queryString}`);
        console.log(val);
      }
    })
  );
}

Upvotes: 3

Related Questions