0

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.

Francesco Borzi
  • 56,083
  • 47
  • 179
  • 252

2 Answers2

2

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);
      }
    })
  );
}
Kurt Hamilton
  • 12,490
  • 1
  • 24
  • 40
  • thanks @Kurt however I was hoping that there was some rxjs built in for that – Francesco Borzi Mar 14 '20 at 18:20
  • *Something* has to persist the values outside of the function - be it your own subject or an object. Any state stored in the function or reference to an observable created in the function is going to die once the observable returns. – Kurt Hamilton Mar 15 '20 at 07:08
  • also, as the `cache` object grows in size, I'm wondering if it will be more efficient at the end – Francesco Borzi Mar 15 '20 at 09:03
0

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];
}
Francesco Borzi
  • 56,083
  • 47
  • 179
  • 252