dexie 4.0.4 → 4.0.7

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 CHANGED
@@ -1,83 +1,153 @@
1
- Dexie.js
2
- ========
1
+ # Dexie.js
3
2
 
4
3
  [![NPM Version][npm-image]][npm-url] ![Build Status](https://github.com/dexie/Dexie.js/actions/workflows/main.yml/badge.svg)
5
4
 
6
- Dexie.js is a wrapper library for indexedDB - the standard database in the browser. https://dexie.org
5
+ Dexie.js is a wrapper library for indexedDB - the standard database in the browser. https://dexie.org.
7
6
 
8
- #### Why?
9
- Dexie solves three main issues with the native IndexedDB API:
7
+ #### Why Dexie.js?
10
8
 
11
- 1. Ambiguous error handling
12
- 2. Poor queries
13
- 3. Code complexity
9
+ IndexedDB is the portable database for all browser engines. Dexie.js makes it fun and easy to work with.
14
10
 
15
- Dexie provides a neat database API with a well thought-through API design, robust error handling, extendability, change tracking awareness and extended KeyRange support (case insensitive search, set matches and OR operations).
11
+ But also:
12
+
13
+ * Dexie.js is widely used by 100,000 of web sites, apps and other projects and supports all browsers, Electron for Desktop apps, Capacitor for iOS / Android apps and of course pure PWAs.
14
+ * Dexie.js works around bugs in the IndexedDB implementations, giving a more stable user experience.
15
+ * It's an easy step to [make it sync](https://dexie.org/#sync).
16
16
 
17
17
  #### Hello World
18
18
 
19
19
  ```html
20
- <!doctype html>
20
+ <!DOCTYPE html>
21
21
  <html>
22
- <head>
23
- <script src="https://unpkg.com/dexie@latest/dist/dexie.js"></script>
24
- <script>
25
- //
26
- // Declare Database
27
- //
28
- var db = new Dexie("FriendDatabase");
29
- db.version(1).stores({
30
- friends: "++id,name,age"
31
- });
32
-
33
- //
34
- // Manipulate and Query Database
35
- //
36
- db.friends.add({name: "Josephine", age: 21}).then(function() {
37
- return db.friends.where("age").below(25).toArray();
38
- }).then(function (youngFriends) {
39
- alert ("My young friends: " + JSON.stringify(youngFriends));
40
- }).catch(function (e) {
41
- alert ("Error: " + (e.stack || e));
42
- });
43
- </script>
44
- </head>
22
+ <head>
23
+ <script src="https://unpkg.com/dexie/dist/dexie.js"></script>
24
+ <script>
25
+
26
+ //
27
+ // Declare Database
28
+ //
29
+ const db = new Dexie('FriendDatabase');
30
+ db.version(1).stores({
31
+ friends: '++id, age'
32
+ });
33
+
34
+ //
35
+ // Play with it
36
+ //
37
+ db.friends.add({ name: 'Alice', age: 21 }).then(() => {
38
+ return db.friends
39
+ .where('age')
40
+ .below(30)
41
+ .toArray();
42
+ }).then(youngFriends => {
43
+ alert (`My young friends: ${JSON.stringify(youngFriends)}`);
44
+ }).catch (e => {
45
+ alert(`Oops: ${e}`);
46
+ });
47
+
48
+ </script>
49
+ </head>
45
50
  </html>
46
51
  ```
47
- Yes, it's that simple.
48
52
 
49
- An equivalent modern version (works in all modern browsers):
53
+ Yes, it's that simple. Read [the docs](https://dexie.org/docs/) to get into the details.
54
+
55
+ #### Hello World (for modern browsers)
56
+
57
+ All modern browsers support ES modules and top-level awaits. No transipler needed. Here's the previous example in a modern flavour:
50
58
 
51
59
  ```html
52
- <!doctype html>
60
+ <!DOCTYPE html>
53
61
  <html>
54
- <head>
55
- <script type="module">
56
- import Dexie from "https://unpkg.com/dexie@latest/dist/modern/dexie.mjs";
57
- //
58
- // Declare Database
59
- //
60
- const db = new Dexie("FriendDatabase");
61
- db.version(1).stores({
62
- friends: "++id,name,age"
63
- });
64
-
65
- //
66
- // Manipulate and Query Database
67
- //
68
- try {
69
- await db.friends.add({name: "Josephine", age: 21});
70
- const youngFriends = await db.friends.where("age").below(25).toArray();
71
- alert (`My young friends: ${JSON.stringify(youngFriends)}`);
72
- } catch (e) {
73
- alert (`Error: ${e}`);
74
- }
75
- </script>
76
- </head>
62
+ <head>
63
+ <script type="module">
64
+ // Import Dexie
65
+ import { Dexie } from 'https://unpkg.com/dexie/dist/modern/dexie.mjs';
66
+
67
+ //
68
+ // Declare Database
69
+ //
70
+ const db = new Dexie('FriendDatabase');
71
+ db.version(1).stores({
72
+ friends: '++id, age'
73
+ });
74
+
75
+ //
76
+ // Play with it
77
+ //
78
+ try {
79
+ await db.friends.add({ name: 'Alice', age: 21 });
80
+
81
+ const youngFriends = await db.friends
82
+ .where('age')
83
+ .below(30)
84
+ .toArray();
85
+
86
+ alert(`My young friends: ${JSON.stringify(youngFriends)}`);
87
+ } catch (e) {
88
+ alert(`Oops: ${e}`);
89
+ }
90
+ </script>
91
+ </head>
77
92
  </html>
78
93
  ```
79
94
 
80
- [Tutorial](https://dexie.org/docs/Tutorial)
95
+ #### Hello World (React + Typescript)
96
+
97
+ Real-world apps are often built using components in various frameworks. Here's a version of Hello World written for React and Typescript. There are also links below this sample to more tutorials for different frameworks...
98
+
99
+ ```tsx
100
+ import React from 'react';
101
+ import { Dexie, type EntityTable } from 'dexie';
102
+ import { useLiveQuery } from 'dexie-react-hooks';
103
+
104
+ // Typing for your entities (hint is to move this to its own module)
105
+ export interface Friend {
106
+ id: number;
107
+ name: string;
108
+ age: number;
109
+ }
110
+
111
+ // Database declaration (move this to its own module also)
112
+ export const db = new Dexie('FriendDatabase') as Dexie & {
113
+ friends: EntityTable<Friend, 'id'>;
114
+ };
115
+ db.version(1).stores({
116
+ friends: '++id, age',
117
+ });
118
+
119
+ // Component:
120
+ export function MyDexieReactComponent() {
121
+ const youngFriends = useLiveQuery(() =>
122
+ db.friends
123
+ .where('age')
124
+ .below(30)
125
+ .toArray()
126
+ );
127
+
128
+ return (
129
+ <>
130
+ <h3>My young friends</h3>
131
+ <ul>
132
+ {youngFriends?.map((f) => (
133
+ <li key={f.id}>
134
+ Name: {f.name}, Age: {f.age}
135
+ </li>
136
+ ))}
137
+ </ul>
138
+ <button
139
+ onClick={() => {
140
+ db.friends.add({ name: 'Alice', age: 21 });
141
+ }}
142
+ >
143
+ Add another friend
144
+ </button>
145
+ </>
146
+ );
147
+ }
148
+ ```
149
+
150
+ [Tutorials for React, Svelte, Vue, Angular and vanilla JS](https://dexie.org/docs/Tutorial/Getting-started)
81
151
 
82
152
  [API Reference](https://dexie.org/docs/API-Reference)
83
153
 
@@ -85,9 +155,10 @@ An equivalent modern version (works in all modern browsers):
85
155
 
86
156
  ### Performance
87
157
 
88
- Dexie has kick-ass performance. Its [bulk methods](https://dexie.org/docs/Table/Table.bulkPut()) take advantage of a lesser-known feature in IndexedDB that makes it possible to store stuff without listening to every onsuccess event. This speeds up the performance to a maximum.
158
+ Dexie has kick-ass performance. Its [bulk methods](<https://dexie.org/docs/Table/Table.bulkPut()>) take advantage of a lesser-known feature in IndexedDB that makes it possible to store stuff without listening to every onsuccess event. This speeds up the performance to a maximum.
89
159
 
90
160
  #### Supported operations
161
+
91
162
  ```js
92
163
  above(key): Collection;
93
164
  aboveOrEqual(key): Collection;
@@ -139,113 +210,76 @@ uniqueKeys(): Promise;
139
210
  until(filter: (value) => boolean, includeStopEntry?: boolean): Collection;
140
211
  update(key: Key, changes: { [keyPath: string]: any }): Promise;
141
212
  ```
142
- This is a mix of methods from [WhereClause](https://dexie.org/docs/WhereClause/WhereClause), [Table](https://dexie.org/docs/Table/Table) and [Collection](https://dexie.org/docs/Collection/Collection). Dive into the [API reference](https://dexie.org/docs/API-Reference) to see the details.
143
-
144
- #### Hello World (Typescript)
145
-
146
- ```js
147
- import Dexie, { Table } from 'dexie';
148
213
 
149
- interface Friend {
150
- id?: number;
151
- name?: string;
152
- age?: number;
153
- }
154
-
155
- //
156
- // Declare Database
157
- //
158
- class FriendDatabase extends Dexie {
159
- public friends!: Table<Friend, number>; // id is number in this case
160
-
161
- public constructor() {
162
- super("FriendDatabase");
163
- this.version(1).stores({
164
- friends: "++id,name,age"
165
- });
166
- }
167
- }
214
+ This is a mix of methods from [WhereClause](https://dexie.org/docs/WhereClause/WhereClause), [Table](https://dexie.org/docs/Table/Table) and [Collection](https://dexie.org/docs/Collection/Collection). Dive into the [API reference](https://dexie.org/docs/API-Reference) to see the details.
168
215
 
169
- const db = new FriendDatabase();
216
+ ## Dexie Cloud
170
217
 
171
- db.transaction('rw', db.friends, async() => {
218
+ [Dexie Cloud](https://dexie.org/cloud/) is a commercial offering that can be used as an add-on to Dexie.js. It syncs a Dexie database with a server and enables developers to build apps without having to care about backend or database layer else than the frontend code with Dexie.js as the sole database layer.
172
219
 
173
- // Make sure we have something in DB:
174
- if ((await db.friends.where({name: 'Josephine'}).count()) === 0) {
175
- const id = await db.friends.add({name: "Josephine", age: 21});
176
- alert (`Addded friend with id ${id}`);
177
- }
220
+ Source for a sample Dexie Cloud app: [Dexie Cloud To-do app](https://github.com/dexie/Dexie.js/tree/master/samples/dexie-cloud-todo-app)
178
221
 
179
- // Query:
180
- const youngFriends = await db.friends.where("age").below(25).toArray();
222
+ See the sample Dexie Cloud app in action: https://dexie.github.io/Dexie.js/dexie-cloud-todo-app/
181
223
 
182
- // Show result:
183
- alert ("My young friends: " + JSON.stringify(youngFriends));
224
+ ## Samples
184
225
 
185
- }).catch(e => {
186
- alert(e.stack || e);
187
- });
188
- ```
189
-
190
- Samples
191
- -------
192
226
  https://dexie.org/docs/Samples
193
227
 
194
228
  https://github.com/dexie/Dexie.js/tree/master/samples
195
229
 
196
- Knowledge Base
197
- -----
230
+ ## Knowledge Base
231
+
198
232
  [https://dexie.org/docs/Questions-and-Answers](https://dexie.org/docs/Questions-and-Answers)
199
233
 
200
- Website
201
- -------
234
+ ## Website
235
+
202
236
  [https://dexie.org](https://dexie.org)
203
237
 
204
- Install over npm
205
- ----------------
238
+ ## Install via npm
239
+
206
240
  ```
207
241
  npm install dexie
208
242
  ```
209
243
 
244
+ ## Download
210
245
 
211
- Download
212
- --------
213
246
  For those who don't like package managers, here's the download links:
214
247
 
215
- ### Legacy:
248
+ ### UMD (for legacy script includes as well as commonjs require):
249
+
216
250
  https://unpkg.com/dexie@latest/dist/dexie.min.js
217
251
 
218
252
  https://unpkg.com/dexie@latest/dist/dexie.min.js.map
219
253
 
220
- ### Modern:
254
+ ### Modern (ES module):
255
+
221
256
  https://unpkg.com/dexie@latest/dist/modern/dexie.min.mjs
222
257
 
223
258
  https://unpkg.com/dexie@latest/dist/modern/dexie.min.mjs.map
224
259
 
225
260
  ### Typings:
226
- https://unpkg.com/dexie@latest/dist/dexie.d.ts
227
261
 
262
+ https://unpkg.com/dexie@latest/dist/dexie.d.ts
228
263
 
264
+ # Contributing
229
265
 
230
- Contributing
231
- ============
232
266
  See [CONTRIBUTING.md](CONTRIBUTING.md)
233
267
 
234
- Build
235
- -----
268
+ ## Build
269
+
236
270
  ```
237
271
  pnpm install
238
272
  pnpm run build
239
273
  ```
240
274
 
241
- Test
242
- ----
275
+ ## Test
276
+
243
277
  ```
244
278
  pnpm test
245
279
  ```
246
280
 
247
- Watch
248
- -----
281
+ ## Watch
282
+
249
283
  ```
250
284
  pnpm run watch
251
285
  ```
package/dist/dexie.d.ts CHANGED
@@ -4,7 +4,7 @@
4
4
  *
5
5
  * By David Fahlander, david.fahlander@gmail.com
6
6
  *
7
- * Version 4.0.4, Wed Apr 10 2024
7
+ * Version 4.0.7, Sun May 26 2024
8
8
  *
9
9
  * https://dexie.org
10
10
  *
@@ -63,6 +63,7 @@ export interface Transaction {
63
63
  db: Dexie;
64
64
  active: boolean;
65
65
  mode: IDBTransactionMode;
66
+ idbtrans: IDBTransaction;
66
67
  //tables: { [type: string]: Table<any, any> }; Deprecated since 2.0. Obsolete from v3.0.
67
68
  storeNames: Array<string>;
68
69
  explicit?: boolean;
@@ -72,6 +73,7 @@ export interface Transaction {
72
73
  table(tableName: string): Table<any, any>;
73
74
  table<T>(tableName: string): Table<T, any>;
74
75
  table<T, Key>(tableName: string): Table<T, Key>;
76
+ table<T, Key, TInsertType>(tableName: string): Table<T, Key, TInsertType>;
75
77
  }
76
78
  export interface CreatingHookContext<T, Key> {
77
79
  onsuccess?: (primKey: Key) => void;
@@ -369,6 +371,8 @@ export type PropModSpec = {
369
371
  string,
370
372
  string
371
373
  ];
374
+ add?: number | BigInt | Array<string | number>;
375
+ remove?: number | BigInt | Array<string | number>;
372
376
  };
373
377
  export class PropModification implements PropModSpec {
374
378
  [PropModSymbol]?: true;
@@ -376,6 +380,8 @@ export class PropModification implements PropModSpec {
376
380
  string,
377
381
  string
378
382
  ];
383
+ add?: number | BigInt | Array<string | number>;
384
+ remove?: number | BigInt | Array<string | number>;
379
385
  execute<T>(value: T): T;
380
386
  constructor(spec: PropModSpec);
381
387
  }
@@ -566,6 +572,7 @@ export interface DBCorePutRequest {
566
572
  changeSpec?: {
567
573
  [keyPath: string]: any;
568
574
  }; // Common changeSpec for each key
575
+ isAdditionalChunk?: boolean;
569
576
  updates?: {
570
577
  keys: any[];
571
578
  changeSpecs: {
@@ -584,6 +591,7 @@ export interface DBCoreDeleteRequest {
584
591
  index: string | null;
585
592
  range: DBCoreKeyRange;
586
593
  };
594
+ isAdditionalChunk?: boolean;
587
595
  }
588
596
  export interface DBCoreDeleteRangeRequest {
589
597
  type: "deleteRange";
@@ -810,7 +818,7 @@ export interface Dexie {
810
818
  version(versionNumber: number): Version;
811
819
  on: DbEvents;
812
820
  open(): PromiseExtended<Dexie>;
813
- table<T = any, TKey = IndexableType>(tableName: string): Table<T, TKey>;
821
+ table<T = any, TKey = IndexableType, TInsertType = T>(tableName: string): Table<T, TKey, TInsertType>;
814
822
  transaction<U>(mode: TransactionMode, tables: readonly (string | Table)[], scope: (trans: TXWithTables<this>) => PromiseLike<U> | U): PromiseExtended<U>;
815
823
  transaction<U>(mode: TransactionMode, table: string | Table, scope: (trans: TXWithTables<this>) => PromiseLike<U> | U): PromiseExtended<U>;
816
824
  transaction<U>(mode: TransactionMode, table: string | Table, table2: string | Table, scope: (trans: TXWithTables<this>) => PromiseLike<U> | U): PromiseExtended<U>;
@@ -1157,6 +1165,8 @@ export function mergeRanges(target: IntervalTree, newSet: IntervalTree): void;
1157
1165
  export function rangesOverlap(rangeSet1: IntervalTree, rangeSet2: IntervalTree): boolean;
1158
1166
  export function cmp(a: any, b: any): number;
1159
1167
  export function replacePrefix(a: string, b: string): PropModification;
1168
+ export function add(num: number | bigint | any[]): PropModification;
1169
+ export function remove(num: number | bigint | any[]): PropModification;
1160
1170
  /** Exporting 'Dexie' as the default export.
1161
1171
  **/
1162
1172
  export default Dexie;
package/dist/dexie.js CHANGED
@@ -4,7 +4,7 @@
4
4
  *
5
5
  * By David Fahlander, david.fahlander@gmail.com
6
6
  *
7
- * Version 4.0.4, Wed Apr 10 2024
7
+ * Version 4.0.7, Sun May 26 2024
8
8
  *
9
9
  * https://dexie.org
10
10
  *
@@ -1150,7 +1150,7 @@
1150
1150
  }
1151
1151
  }
1152
1152
 
1153
- var DEXIE_VERSION = '4.0.4';
1153
+ var DEXIE_VERSION = '4.0.7';
1154
1154
  var maxString = String.fromCharCode(65535);
1155
1155
  var minKey = -Infinity;
1156
1156
  var INVALID_KEY_ARGUMENT = "Invalid key provided. Keys must be of type string, number, Date or Array<string | number | Date>.";
@@ -1810,6 +1810,40 @@
1810
1810
  }
1811
1811
  PropModification.prototype.execute = function (value) {
1812
1812
  var _a;
1813
+ if (this.add !== undefined) {
1814
+ var term = this.add;
1815
+ if (isArray(term)) {
1816
+ return __spreadArray(__spreadArray([], (isArray(value) ? value : []), true), term, true).sort();
1817
+ }
1818
+ if (typeof term === 'number')
1819
+ return (Number(value) || 0) + term;
1820
+ if (typeof term === 'bigint') {
1821
+ try {
1822
+ return BigInt(value) + term;
1823
+ }
1824
+ catch (_b) {
1825
+ return BigInt(0) + term;
1826
+ }
1827
+ }
1828
+ throw new TypeError("Invalid term ".concat(term));
1829
+ }
1830
+ if (this.remove !== undefined) {
1831
+ var subtrahend_1 = this.remove;
1832
+ if (isArray(subtrahend_1)) {
1833
+ return isArray(value) ? value.filter(function (item) { return !subtrahend_1.includes(item); }).sort() : [];
1834
+ }
1835
+ if (typeof subtrahend_1 === 'number')
1836
+ return Number(value) - subtrahend_1;
1837
+ if (typeof subtrahend_1 === 'bigint') {
1838
+ try {
1839
+ return BigInt(value) - subtrahend_1;
1840
+ }
1841
+ catch (_c) {
1842
+ return BigInt(0) - subtrahend_1;
1843
+ }
1844
+ }
1845
+ throw new TypeError("Invalid subtrahend ".concat(subtrahend_1));
1846
+ }
1813
1847
  var prefixToReplace = (_a = this.replacePrefix) === null || _a === void 0 ? void 0 : _a[0];
1814
1848
  if (prefixToReplace && typeof value === 'string' && value.startsWith(prefixToReplace)) {
1815
1849
  return this.replacePrefix[1] + value.substring(prefixToReplace.length);
@@ -2120,6 +2154,12 @@
2120
2154
  }
2121
2155
  };
2122
2156
  return _this.clone().primaryKeys().then(function (keys) {
2157
+ var criteria = isPlainKeyRange(ctx) &&
2158
+ ctx.limit === Infinity &&
2159
+ (typeof changes !== 'function' || changes === deleteCallback) && {
2160
+ index: ctx.index,
2161
+ range: ctx.range
2162
+ };
2123
2163
  var nextChunk = function (offset) {
2124
2164
  var count = Math.min(limit, keys.length - offset);
2125
2165
  return coreTable.getMany({
@@ -2152,12 +2192,6 @@
2152
2192
  }
2153
2193
  }
2154
2194
  }
2155
- var criteria = isPlainKeyRange(ctx) &&
2156
- ctx.limit === Infinity &&
2157
- (typeof changes !== 'function' || changes === deleteCallback) && {
2158
- index: ctx.index,
2159
- range: ctx.range
2160
- };
2161
2195
  return Promise.resolve(addValues.length > 0 &&
2162
2196
  coreTable.mutate({ trans: trans, type: 'add', values: addValues })
2163
2197
  .then(function (res) {
@@ -2173,13 +2207,15 @@
2173
2207
  values: putValues,
2174
2208
  criteria: criteria,
2175
2209
  changeSpec: typeof changes !== 'function'
2176
- && changes
2210
+ && changes,
2211
+ isAdditionalChunk: offset > 0
2177
2212
  }).then(function (res) { return applyMutateResult(putValues.length, res); }); }).then(function () { return (deleteKeys.length > 0 || (criteria && changes === deleteCallback)) &&
2178
2213
  coreTable.mutate({
2179
2214
  trans: trans,
2180
2215
  type: 'delete',
2181
2216
  keys: deleteKeys,
2182
- criteria: criteria
2217
+ criteria: criteria,
2218
+ isAdditionalChunk: offset > 0
2183
2219
  }).then(function (res) { return applyMutateResult(deleteKeys.length, res); }); }).then(function () {
2184
2220
  return keys.length > offset + count && nextChunk(offset + limit);
2185
2221
  });
@@ -5822,6 +5858,14 @@
5822
5858
  });
5823
5859
  }
5824
5860
 
5861
+ function add(value) {
5862
+ return new PropModification({ add: value });
5863
+ }
5864
+
5865
+ function remove(value) {
5866
+ return new PropModification({ remove: value });
5867
+ }
5868
+
5825
5869
  function replacePrefix(a, b) {
5826
5870
  return new PropModification({ replacePrefix: [a, b] });
5827
5871
  }
@@ -5838,6 +5882,8 @@
5838
5882
  PropModSymbol: PropModSymbol,
5839
5883
  PropModification: PropModification,
5840
5884
  replacePrefix: replacePrefix,
5885
+ add: add,
5886
+ remove: remove,
5841
5887
  'default': Dexie$1,
5842
5888
  RangeSet: RangeSet,
5843
5889
  mergeRanges: mergeRanges,