dexie-relationships icon indicating copy to clipboard operation
dexie-relationships copied to clipboard

Loading relationships with `get()`?

Open nybblr opened this issue 7 years ago • 3 comments

The current use case (AFAICT) for with() is to use it where you would call .toArray().

However, I'd like to use it on .get() queries and in places where I don't want to invoke .toArray(). Implicitly invoking toArray() limits query building scenarios.

Rail's ActiveRecord handles this by "queueing up" query filters, then having an evaluate method (similar to toArray()). Is there a similar way to do this, so with() will work with get(), plus enable some more complex query builders such as the following use cases:

Use Case 1: Executing a scalar query

let song = await db.songs.with({ album: 'albumId' }).get(3);

Use Case 2: Composing a collection query

let findSongs = (albumId) => {
  let query = db.songs
      .where('albumId')
      .equals(albumId)
      .with({ album: 'albumId' });

  return query;
};

let page = (query, number, limit) => {
  return query.offset(number*limit).limit(limit);
};

let songs = await page(findSongs(3), 2, 10)).toArray();

Use Case 3: Composing queries that are "doubly" async

let intersect = async (table, queries) => {
  let results = await Promise.all(
    queries.map(q => q.primaryKeys()));

  let reduced = results
    .reduce((a, b) => {
      let set = new Set(b);
      return a.filter(k => set.has(k));
    });

  return table.where(':id').anyOf(reduced);
};

let query1 = db.songs
    .where('albumId')
    .equals(3)
    .with({ album: 'albumId' });

let query2 = db.songs
    .where('genreId')
    .equals(5)
    .with({ album: 'albumId' });

let aggregateQuery = await intersect(query1, query2);
let songs = await aggregateQuery.toArray();

If the answer is "yes" or @dfahlander has some pointers on how to do this, I'm :100: to write a PR!

nybblr avatar Apr 17 '17 17:04 nybblr

I agree fully. Problem right now is that Dexie needs to change it's core loop to handle this. I've started a rewrite in typescript at https://github.com/dfahlander/Dexie.js/tree/next-expression-engine/src/dexie-next. This new branch is a rewrite of quite much. It will support chained where clauses in combination with orderBy() and support lazy mapping like what you are requesting. It will also support asynchronous hooks. Many of the features mentioned here will be supported.

I would very much appreciate any help with completing this branch later on when it comes to a stage where it is functional and testable. I find myself with too little time this spring to work on it right now. But hope to get it going again later this year (August and forth). Probably too undocumented to jump into right away though. (does not even compile right now)

If you find an easier way to accomplish it based on current Dexie master branch, feel free to implement it and PR it. You will then need PRs for both Dexie and dexie-relationships. As long as all the unit tests pass, I'm fine with it.

dfahlander avatar Apr 17 '17 20:04 dfahlander

Oh, nice (re. rewrite)! Hmm, so this sounds like two action items:

  1. For now, I'll try to crunch out a very specific solution for the .get() use case which works with the current Dexie version; I'm working on some bootcamp code so I'd love to have something I can use now.
  2. I use Dexie a fair bit, so definitely ping me when it would help to have help! Tests/refactors/code review, just let me know.
  3. Would it be a safe guess to say "relationships" could become first class in Dexie, or would it continue to live on as an addon?

nybblr avatar Apr 17 '17 20:04 nybblr

Thanks! I'll ping you as I move forward. Just the knowledge of that there are people wanting to help further on is good.

Relationships addon is already part of the CI tests of Dexie, as other addons may be too, too verify a new Dexie version never will break first class addons. It may continue as an addon to save the library size though.

dfahlander avatar Apr 17 '17 21:04 dfahlander