locality-idb 1.1.0 → 1.1.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/README.md +49 -10
- package/dist/index.cjs +9 -5
- package/dist/index.d.cts +2 -1
- package/dist/index.d.mts +2 -1
- package/dist/index.iife.js +9 -5
- package/dist/index.mjs +9 -5
- package/dist/index.umd.js +9 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -467,7 +467,7 @@ const names = await db
|
|
|
467
467
|
.findAll();
|
|
468
468
|
```
|
|
469
469
|
|
|
470
|
-
> **Note:** `sortByIndex()` uses IndexedDB cursor iteration for optimal performance when
|
|
470
|
+
> **Note:** `sortByIndex()` uses IndexedDB cursor iteration for optimal performance when `where()` filter is applied without index.
|
|
471
471
|
|
|
472
472
|
#### Chain Multiple Methods
|
|
473
473
|
|
|
@@ -787,6 +787,32 @@ Filters rows based on a predicate function.
|
|
|
787
787
|
db.from('users').where((user) => user.age >= 18)
|
|
788
788
|
```
|
|
789
789
|
|
|
790
|
+
##### `where<IdxKey>(indexName: IdxKey, query: T[IdxKey] | IDBKeyRange): SelectQuery`
|
|
791
|
+
|
|
792
|
+
Filters rows using an indexed field.
|
|
793
|
+
|
|
794
|
+
```typescript
|
|
795
|
+
db.from('users').where('age', IDBKeyRange.bound(18, 30))
|
|
796
|
+
```
|
|
797
|
+
|
|
798
|
+
##### `sortByIndex<IdxKey>(indexName: IdxKey, dir?: 'asc' | 'desc'): SelectQuery`
|
|
799
|
+
|
|
800
|
+
Sorts results by an indexed field using IndexedDB cursor iteration (avoiding in-memory sorting).
|
|
801
|
+
|
|
802
|
+
**Type Safety:** `indexName` must be a field with an index.
|
|
803
|
+
|
|
804
|
+
**Performance:** Uses IndexedDB's cursor for optimized sorting. For large datasets, this is significantly more efficient than in-memory sorting.
|
|
805
|
+
|
|
806
|
+
> For sorting on non-indexed fields, use [`orderBy()`](#orderbykeykey-key-direction-asc--desc-selectquery) which performs in-memory sorting.
|
|
807
|
+
|
|
808
|
+
```typescript
|
|
809
|
+
// Optimized cursor-based sort
|
|
810
|
+
const sorted = await db.from('users').sortByIndex('age', 'desc').findAll();
|
|
811
|
+
|
|
812
|
+
// Efficient pagination
|
|
813
|
+
const page = await db.from('users').sortByIndex('createdAt', 'desc').limit(20).findAll();
|
|
814
|
+
```
|
|
815
|
+
|
|
790
816
|
##### `orderBy<Key>(key: Key, direction?: 'asc' | 'desc'): SelectQuery`
|
|
791
817
|
|
|
792
818
|
Orders results by a specified key. Supports nested keys using dot notation.
|
|
@@ -796,6 +822,8 @@ db.from('users').orderBy('name', 'asc')
|
|
|
796
822
|
db.from('users').orderBy('profile.age', 'desc')
|
|
797
823
|
```
|
|
798
824
|
|
|
825
|
+
> **Note:** This method performs in-memory sorting. For large datasets, consider using [`sortByIndex()`](#sortbyindexidxkeyindexname-idxkey-dir-asc--desc-selectquery) with an indexed field for better performance.
|
|
826
|
+
|
|
799
827
|
##### `limit(count: number): SelectQuery`
|
|
800
828
|
|
|
801
829
|
Limits the number of results.
|
|
@@ -852,22 +880,31 @@ const adults = await db.from('users').findByIndex('age', IDBKeyRange.bound(18, 6
|
|
|
852
880
|
> - Unique columns are automatically indexed.
|
|
853
881
|
> - Unique indexes are recommended for this method to ensure a single result.
|
|
854
882
|
|
|
855
|
-
##### `
|
|
883
|
+
##### `count(): Promise<number>`
|
|
856
884
|
|
|
857
|
-
|
|
885
|
+
Counts the number of matching records.
|
|
858
886
|
|
|
859
|
-
|
|
887
|
+
```typescript
|
|
888
|
+
const userCount = await db.from('users').where((user) => user.isActive).count()
|
|
889
|
+
```
|
|
860
890
|
|
|
861
|
-
**
|
|
891
|
+
> **Note:**
|
|
892
|
+
>
|
|
893
|
+
> - This method internally uses IndexedDB's `count()` for optimal performance.
|
|
894
|
+
> - If a `where()` filter is applied without index, it falls back to in-memory counting.
|
|
862
895
|
|
|
863
|
-
|
|
864
|
-
// Optimized cursor-based sort
|
|
865
|
-
const sorted = await db.from('users').sortByIndex('age', 'desc').findAll();
|
|
896
|
+
##### `exists(): Promise<boolean>`
|
|
866
897
|
|
|
867
|
-
|
|
868
|
-
|
|
898
|
+
Checks if any matching records exist.
|
|
899
|
+
|
|
900
|
+
```typescript
|
|
901
|
+
const hasAdmins = await db.from('users').where((user) => user.role === 'admin').exists()
|
|
869
902
|
```
|
|
870
903
|
|
|
904
|
+
> **Note:** This method internally uses [`count()`](#count-promisenumber) for checking existence.
|
|
905
|
+
|
|
906
|
+
---
|
|
907
|
+
|
|
871
908
|
#### InsertQuery Methods
|
|
872
909
|
|
|
873
910
|
##### `values<T>(data: T | T[]): InsertQuery`
|
|
@@ -913,6 +950,8 @@ Executes the update query and returns the number of updated records.
|
|
|
913
950
|
const count = await db.update('users').set({ name: 'Jane' }).run()
|
|
914
951
|
```
|
|
915
952
|
|
|
953
|
+
---
|
|
954
|
+
|
|
916
955
|
#### DeleteQuery Methods
|
|
917
956
|
|
|
918
957
|
##### `where(predicate: (row: T) => boolean): DeleteQuery`
|
package/dist/index.cjs
CHANGED
|
@@ -487,6 +487,7 @@ var SelectQuery = class {
|
|
|
487
487
|
#isPrimaryKey(store) {
|
|
488
488
|
return isNonEmptyString(this.#whereIndexName) && store.keyPath === this.#whereIndexName;
|
|
489
489
|
}
|
|
490
|
+
/** @internal Build indexed store (primary key or index) for where queries */
|
|
490
491
|
#buildIndexedStore(store, reject) {
|
|
491
492
|
const isPK = this.#isPrimaryKey(store);
|
|
492
493
|
const isIndex = this.#isIndexKey(store);
|
|
@@ -523,13 +524,13 @@ var SelectQuery = class {
|
|
|
523
524
|
this[Selected] = cols;
|
|
524
525
|
return this;
|
|
525
526
|
}
|
|
526
|
-
where(
|
|
527
|
-
if (isFunction(
|
|
528
|
-
this.#whereCondition =
|
|
527
|
+
where(condition, query) {
|
|
528
|
+
if (isFunction(condition)) {
|
|
529
|
+
this.#whereCondition = condition;
|
|
529
530
|
this.#whereIndexName = void 0;
|
|
530
531
|
this.#whereIndexQuery = void 0;
|
|
531
|
-
} else if (isNonEmptyString(
|
|
532
|
-
this.#whereIndexName =
|
|
532
|
+
} else if (isNonEmptyString(condition) && !isUndefined(query)) {
|
|
533
|
+
this.#whereIndexName = condition;
|
|
533
534
|
this.#whereIndexQuery = query;
|
|
534
535
|
this.#whereCondition = void 0;
|
|
535
536
|
}
|
|
@@ -731,6 +732,9 @@ var SelectQuery = class {
|
|
|
731
732
|
request.onerror = () => reject(request.error);
|
|
732
733
|
});
|
|
733
734
|
}
|
|
735
|
+
async exists() {
|
|
736
|
+
return await this.count() > 0;
|
|
737
|
+
}
|
|
734
738
|
};
|
|
735
739
|
/** @class Insert query builder. */
|
|
736
740
|
var InsertQuery = class {
|
package/dist/index.d.cts
CHANGED
|
@@ -384,7 +384,7 @@ declare class SelectQuery<T extends GenericObject, S extends Partial<Record<stri
|
|
|
384
384
|
* @param indexName Name of the index/primary key to query
|
|
385
385
|
* @param query Key value or {@link IDBKeyRange} to search for
|
|
386
386
|
*/
|
|
387
|
-
where<IdxKey extends $InferPrimaryKey<Tbl['columns']> | $InferIndex<Tbl['columns']>>(indexName: IdxKey, query: IDBKeyRange | T[
|
|
387
|
+
where<IdxKey extends $InferPrimaryKey<Tbl['columns']> | $InferIndex<Tbl['columns']>>(indexName: IdxKey, query: IDBKeyRange | T[IdxKey]): this;
|
|
388
388
|
/**
|
|
389
389
|
* @instance Order results by specified key and direction
|
|
390
390
|
* @param key Key to order by
|
|
@@ -442,6 +442,7 @@ declare class SelectQuery<T extends GenericObject, S extends Partial<Record<stri
|
|
|
442
442
|
findByIndex<IdxKey extends $InferIndex<Tbl['columns']> & keyof T & string>(indexName: IdxKey, query: T[IdxKey] | IDBKeyRange): Promise<S extends null ? T[] : S extends Partial<Record<keyof T, boolean>> ? SelectFields<T, S>[] : never>;
|
|
443
443
|
/** @instance Count matching records */
|
|
444
444
|
count(): Promise<number>;
|
|
445
|
+
exists(): Promise<boolean>;
|
|
445
446
|
}
|
|
446
447
|
/** @class Insert query builder. */
|
|
447
448
|
declare class InsertQuery<Raw extends GenericObject, Inserted extends Raw | Raw[], Data extends GenericObject, Return extends (Inserted extends Array<infer _> ? Data[] : Data)> {
|
package/dist/index.d.mts
CHANGED
|
@@ -384,7 +384,7 @@ declare class SelectQuery<T extends GenericObject, S extends Partial<Record<stri
|
|
|
384
384
|
* @param indexName Name of the index/primary key to query
|
|
385
385
|
* @param query Key value or {@link IDBKeyRange} to search for
|
|
386
386
|
*/
|
|
387
|
-
where<IdxKey extends $InferPrimaryKey<Tbl['columns']> | $InferIndex<Tbl['columns']>>(indexName: IdxKey, query: IDBKeyRange | T[
|
|
387
|
+
where<IdxKey extends $InferPrimaryKey<Tbl['columns']> | $InferIndex<Tbl['columns']>>(indexName: IdxKey, query: IDBKeyRange | T[IdxKey]): this;
|
|
388
388
|
/**
|
|
389
389
|
* @instance Order results by specified key and direction
|
|
390
390
|
* @param key Key to order by
|
|
@@ -442,6 +442,7 @@ declare class SelectQuery<T extends GenericObject, S extends Partial<Record<stri
|
|
|
442
442
|
findByIndex<IdxKey extends $InferIndex<Tbl['columns']> & keyof T & string>(indexName: IdxKey, query: T[IdxKey] | IDBKeyRange): Promise<S extends null ? T[] : S extends Partial<Record<keyof T, boolean>> ? SelectFields<T, S>[] : never>;
|
|
443
443
|
/** @instance Count matching records */
|
|
444
444
|
count(): Promise<number>;
|
|
445
|
+
exists(): Promise<boolean>;
|
|
445
446
|
}
|
|
446
447
|
/** @class Insert query builder. */
|
|
447
448
|
declare class InsertQuery<Raw extends GenericObject, Inserted extends Raw | Raw[], Data extends GenericObject, Return extends (Inserted extends Array<infer _> ? Data[] : Data)> {
|
package/dist/index.iife.js
CHANGED
|
@@ -489,6 +489,7 @@ var LocalityIDB = (function(exports) {
|
|
|
489
489
|
#isPrimaryKey(store) {
|
|
490
490
|
return isNonEmptyString(this.#whereIndexName) && store.keyPath === this.#whereIndexName;
|
|
491
491
|
}
|
|
492
|
+
/** @internal Build indexed store (primary key or index) for where queries */
|
|
492
493
|
#buildIndexedStore(store, reject) {
|
|
493
494
|
const isPK = this.#isPrimaryKey(store);
|
|
494
495
|
const isIndex = this.#isIndexKey(store);
|
|
@@ -525,13 +526,13 @@ var LocalityIDB = (function(exports) {
|
|
|
525
526
|
this[Selected] = cols;
|
|
526
527
|
return this;
|
|
527
528
|
}
|
|
528
|
-
where(
|
|
529
|
-
if (isFunction(
|
|
530
|
-
this.#whereCondition =
|
|
529
|
+
where(condition, query) {
|
|
530
|
+
if (isFunction(condition)) {
|
|
531
|
+
this.#whereCondition = condition;
|
|
531
532
|
this.#whereIndexName = void 0;
|
|
532
533
|
this.#whereIndexQuery = void 0;
|
|
533
|
-
} else if (isNonEmptyString(
|
|
534
|
-
this.#whereIndexName =
|
|
534
|
+
} else if (isNonEmptyString(condition) && !isUndefined(query)) {
|
|
535
|
+
this.#whereIndexName = condition;
|
|
535
536
|
this.#whereIndexQuery = query;
|
|
536
537
|
this.#whereCondition = void 0;
|
|
537
538
|
}
|
|
@@ -733,6 +734,9 @@ var LocalityIDB = (function(exports) {
|
|
|
733
734
|
request.onerror = () => reject(request.error);
|
|
734
735
|
});
|
|
735
736
|
}
|
|
737
|
+
async exists() {
|
|
738
|
+
return await this.count() > 0;
|
|
739
|
+
}
|
|
736
740
|
};
|
|
737
741
|
/** @class Insert query builder. */
|
|
738
742
|
var InsertQuery = class {
|
package/dist/index.mjs
CHANGED
|
@@ -486,6 +486,7 @@ var SelectQuery = class {
|
|
|
486
486
|
#isPrimaryKey(store) {
|
|
487
487
|
return isNonEmptyString(this.#whereIndexName) && store.keyPath === this.#whereIndexName;
|
|
488
488
|
}
|
|
489
|
+
/** @internal Build indexed store (primary key or index) for where queries */
|
|
489
490
|
#buildIndexedStore(store, reject) {
|
|
490
491
|
const isPK = this.#isPrimaryKey(store);
|
|
491
492
|
const isIndex = this.#isIndexKey(store);
|
|
@@ -522,13 +523,13 @@ var SelectQuery = class {
|
|
|
522
523
|
this[Selected] = cols;
|
|
523
524
|
return this;
|
|
524
525
|
}
|
|
525
|
-
where(
|
|
526
|
-
if (isFunction(
|
|
527
|
-
this.#whereCondition =
|
|
526
|
+
where(condition, query) {
|
|
527
|
+
if (isFunction(condition)) {
|
|
528
|
+
this.#whereCondition = condition;
|
|
528
529
|
this.#whereIndexName = void 0;
|
|
529
530
|
this.#whereIndexQuery = void 0;
|
|
530
|
-
} else if (isNonEmptyString(
|
|
531
|
-
this.#whereIndexName =
|
|
531
|
+
} else if (isNonEmptyString(condition) && !isUndefined(query)) {
|
|
532
|
+
this.#whereIndexName = condition;
|
|
532
533
|
this.#whereIndexQuery = query;
|
|
533
534
|
this.#whereCondition = void 0;
|
|
534
535
|
}
|
|
@@ -730,6 +731,9 @@ var SelectQuery = class {
|
|
|
730
731
|
request.onerror = () => reject(request.error);
|
|
731
732
|
});
|
|
732
733
|
}
|
|
734
|
+
async exists() {
|
|
735
|
+
return await this.count() > 0;
|
|
736
|
+
}
|
|
733
737
|
};
|
|
734
738
|
/** @class Insert query builder. */
|
|
735
739
|
var InsertQuery = class {
|
package/dist/index.umd.js
CHANGED
|
@@ -492,6 +492,7 @@
|
|
|
492
492
|
#isPrimaryKey(store) {
|
|
493
493
|
return isNonEmptyString(this.#whereIndexName) && store.keyPath === this.#whereIndexName;
|
|
494
494
|
}
|
|
495
|
+
/** @internal Build indexed store (primary key or index) for where queries */
|
|
495
496
|
#buildIndexedStore(store, reject) {
|
|
496
497
|
const isPK = this.#isPrimaryKey(store);
|
|
497
498
|
const isIndex = this.#isIndexKey(store);
|
|
@@ -528,13 +529,13 @@
|
|
|
528
529
|
this[Selected] = cols;
|
|
529
530
|
return this;
|
|
530
531
|
}
|
|
531
|
-
where(
|
|
532
|
-
if (isFunction(
|
|
533
|
-
this.#whereCondition =
|
|
532
|
+
where(condition, query) {
|
|
533
|
+
if (isFunction(condition)) {
|
|
534
|
+
this.#whereCondition = condition;
|
|
534
535
|
this.#whereIndexName = void 0;
|
|
535
536
|
this.#whereIndexQuery = void 0;
|
|
536
|
-
} else if (isNonEmptyString(
|
|
537
|
-
this.#whereIndexName =
|
|
537
|
+
} else if (isNonEmptyString(condition) && !isUndefined(query)) {
|
|
538
|
+
this.#whereIndexName = condition;
|
|
538
539
|
this.#whereIndexQuery = query;
|
|
539
540
|
this.#whereCondition = void 0;
|
|
540
541
|
}
|
|
@@ -736,6 +737,9 @@
|
|
|
736
737
|
request.onerror = () => reject(request.error);
|
|
737
738
|
});
|
|
738
739
|
}
|
|
740
|
+
async exists() {
|
|
741
|
+
return await this.count() > 0;
|
|
742
|
+
}
|
|
739
743
|
};
|
|
740
744
|
/** @class Insert query builder. */
|
|
741
745
|
var InsertQuery = class {
|