@firtoz/drizzle-indexeddb 0.5.0 → 0.5.1

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # @firtoz/drizzle-indexeddb
2
2
 
3
+ ## 0.5.1
4
+
5
+ ### Patch Changes
6
+
7
+ - [`8abab0a`](https://github.com/firtoz/fullstack-toolkit/commit/8abab0ae7a99320a4254cb128c0fd823726e58e0) Thanks [@firtoz](https://github.com/firtoz)! - Add cursor-based and offset-based pagination support to `loadSubset` operations, enabling efficient navigation through large datasets with consistent behavior across collection backends.
8
+
9
+ - Updated dependencies [[`8abab0a`](https://github.com/firtoz/fullstack-toolkit/commit/8abab0ae7a99320a4254cb128c0fd823726e58e0)]:
10
+ - @firtoz/drizzle-utils@0.3.1
11
+
3
12
  ## 0.5.0
4
13
 
5
14
  ### Minor Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@firtoz/drizzle-indexeddb",
3
- "version": "0.5.0",
3
+ "version": "0.5.1",
4
4
  "description": "IndexedDB migrations powered by Drizzle ORM",
5
5
  "main": "./src/index.ts",
6
6
  "module": "./src/index.ts",
@@ -68,20 +68,20 @@
68
68
  "access": "public"
69
69
  },
70
70
  "peerDependencies": {
71
- "@firtoz/drizzle-utils": ">=0.3.0",
72
- "@tanstack/db": ">=0.5.0",
73
- "drizzle-orm": ">=0.44.0",
71
+ "@firtoz/drizzle-utils": ">=0.3.1",
72
+ "@tanstack/db": ">=0.5.15",
73
+ "drizzle-orm": ">=0.45.1",
74
74
  "drizzle-valibot": ">=0.4.0",
75
- "react": ">=18.0.0",
75
+ "react": ">=19.2.3",
76
76
  "valibot": ">=1.0.0"
77
77
  },
78
78
  "devDependencies": {
79
- "@firtoz/drizzle-utils": "^0.3.0",
80
- "@tanstack/db": "^0.5.11",
79
+ "@firtoz/drizzle-utils": "^0.3.1",
80
+ "@tanstack/db": "^0.5.15",
81
81
  "@types/react": "^19.2.7",
82
- "drizzle-orm": "^0.45.0",
82
+ "drizzle-orm": "^0.45.1",
83
83
  "drizzle-valibot": "^0.4.2",
84
- "react": "^19.2.1",
84
+ "react": "^19.2.3",
85
85
  "valibot": "^1.2.0"
86
86
  },
87
87
  "dependencies": {
@@ -381,14 +381,30 @@ export function indexedDBCollectionOptions<const TTable extends Table>(
381
381
 
382
382
  let items: IndexedDBSyncItem[];
383
383
 
384
+ // Combine where with cursor expressions if present
385
+ // The cursor.whereFrom gives us rows after the cursor position
386
+ let combinedWhere = options.where;
387
+ if (options.cursor?.whereFrom) {
388
+ if (combinedWhere) {
389
+ // Combine main where with cursor expression using AND
390
+ combinedWhere = {
391
+ type: "func",
392
+ name: "and",
393
+ args: [combinedWhere, options.cursor.whereFrom],
394
+ } as IR.Func;
395
+ } else {
396
+ combinedWhere = options.cursor.whereFrom;
397
+ }
398
+ }
399
+
384
400
  // Try to use an index for efficient querying
385
- const indexedQuery = options.where
386
- ? tryExtractIndexedQuery(options.where, discoveredIndexes, config.debug)
401
+ const indexedQuery = combinedWhere
402
+ ? tryExtractIndexedQuery(combinedWhere, discoveredIndexes, config.debug)
387
403
  : null;
388
404
 
389
405
  if (indexedQuery) {
390
406
  // Use indexed query for better performance
391
-
407
+ // Index returns exact results for single-field queries, no additional filtering needed
392
408
  items = await db.getAllByIndex<IndexedDBSyncItem>(
393
409
  config.storeName,
394
410
  indexedQuery.indexName,
@@ -398,9 +414,9 @@ export function indexedDBCollectionOptions<const TTable extends Table>(
398
414
  // Fall back to getting all items
399
415
  items = await db.getAll<IndexedDBSyncItem>(config.storeName);
400
416
 
401
- // Apply where filter in memory
402
- if (options.where) {
403
- const whereExpression = options.where;
417
+ // Apply combined where filter in memory
418
+ if (combinedWhere) {
419
+ const whereExpression = combinedWhere;
404
420
  items = items.filter((item) =>
405
421
  evaluateExpression(
406
422
  whereExpression,
@@ -436,6 +452,11 @@ export function indexedDBCollectionOptions<const TTable extends Table>(
436
452
  });
437
453
  }
438
454
 
455
+ // Apply offset (skip first N items for pagination)
456
+ if (options.offset !== undefined && options.offset > 0) {
457
+ items = items.slice(options.offset);
458
+ }
459
+
439
460
  // Apply limit
440
461
  if (options.limit !== undefined) {
441
462
  items = items.slice(0, options.limit);
@@ -251,8 +251,8 @@ export function createStandaloneCollection<TTable extends Table>(
251
251
  if (debug) {
252
252
  console.log(`[StandaloneCollection] Database "${dbName}" initialized`);
253
253
  }
254
- // biome-ignore lint/style/noNonNullAssertion: resolveReady is set in promise constructor
255
- resolveReady!();
254
+
255
+ resolveReady();
256
256
  } catch (error) {
257
257
  console.error(
258
258
  `[StandaloneCollection] Failed to initialize database "${dbName}":`,
@@ -294,16 +294,15 @@ export function createStandaloneCollection<TTable extends Table>(
294
294
  const ready = Promise.all([readyPromise, collectionReady]).then(() => {});
295
295
 
296
296
  // Helper to wait for transaction to persist
297
- const waitForPersist = (
298
- // biome-ignore lint/suspicious/noExplicitAny: Transaction types are complex, runtime is correct
299
- transaction: any,
300
- // biome-ignore lint/suspicious/noExplicitAny: Transaction types are complex, runtime is correct
301
- callback?: (transaction: any) => void,
297
+ const waitForPersist = async (
298
+ transaction: MutationTransaction<TTable>,
299
+ callback?: (transaction: MutationTransaction<TTable>) => void,
302
300
  ): Promise<MutationTransaction<TTable>> => {
303
301
  if (callback) {
304
302
  callback(transaction);
305
303
  }
306
- return transaction.isPersisted.promise.then(() => transaction);
304
+ await transaction.isPersisted.promise;
305
+ return transaction;
307
306
  };
308
307
 
309
308
  return {
@@ -325,9 +324,12 @@ export function createStandaloneCollection<TTable extends Table>(
325
324
  data: InsertInput<TTable> | InsertInput<TTable>[],
326
325
  callback?: (transaction: MutationTransaction<TTable>) => void,
327
326
  ): Promise<MutationTransaction<TTable>> {
328
- const items = Array.isArray(data) ? data : [data];
329
- // @ts-expect-error - Type inference is complex here but runtime is correct
330
- const transaction = collection.insert(...items);
327
+ const items = (Array.isArray(data) ? data : [data]) as InferSchemaOutput<
328
+ SelectSchema<TTable>
329
+ >;
330
+ const transaction = collection.insert(
331
+ items,
332
+ ) as MutationTransaction<TTable>;
331
333
  return waitForPersist(transaction, callback);
332
334
  },
333
335
 
@@ -338,8 +340,8 @@ export function createStandaloneCollection<TTable extends Table>(
338
340
  ): Promise<MutationTransaction<TTable>> {
339
341
  const transaction = collection.update(
340
342
  key,
341
- updater as (draft: any) => void,
342
- );
343
+ updater,
344
+ ) as MutationTransaction<TTable>;
343
345
  return waitForPersist(transaction, callback);
344
346
  },
345
347