@effect/platform-browser 4.0.0-beta.42 → 4.0.0-beta.43
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/dist/IndexedDb.d.ts +50 -0
- package/dist/IndexedDb.d.ts.map +1 -0
- package/dist/IndexedDb.js +65 -0
- package/dist/IndexedDb.js.map +1 -0
- package/dist/IndexedDbDatabase.d.ts +100 -0
- package/dist/IndexedDbDatabase.d.ts.map +1 -0
- package/dist/IndexedDbDatabase.js +299 -0
- package/dist/IndexedDbDatabase.js.map +1 -0
- package/dist/IndexedDbQueryBuilder.d.ts +284 -0
- package/dist/IndexedDbQueryBuilder.d.ts.map +1 -0
- package/dist/IndexedDbQueryBuilder.js +862 -0
- package/dist/IndexedDbQueryBuilder.js.map +1 -0
- package/dist/IndexedDbTable.d.ts +110 -0
- package/dist/IndexedDbTable.d.ts.map +1 -0
- package/dist/IndexedDbTable.js +36 -0
- package/dist/IndexedDbTable.js.map +1 -0
- package/dist/IndexedDbVersion.d.ts +50 -0
- package/dist/IndexedDbVersion.d.ts.map +1 -0
- package/dist/IndexedDbVersion.js +23 -0
- package/dist/IndexedDbVersion.js.map +1 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -1
- package/package.json +4 -3
- package/src/IndexedDb.ts +97 -0
- package/src/IndexedDbDatabase.ts +598 -0
- package/src/IndexedDbQueryBuilder.ts +1895 -0
- package/src/IndexedDbTable.ts +205 -0
- package/src/IndexedDbVersion.ts +89 -0
- package/src/index.ts +25 -0
|
@@ -0,0 +1,1895 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @since 4.0.0
|
|
3
|
+
*/
|
|
4
|
+
import type { NonEmptyReadonlyArray } from "effect/Array"
|
|
5
|
+
import * as Data from "effect/Data"
|
|
6
|
+
import * as Effect from "effect/Effect"
|
|
7
|
+
import type { Inspectable } from "effect/Inspectable"
|
|
8
|
+
import { BaseProto } from "effect/Inspectable"
|
|
9
|
+
import * as Pipeable from "effect/Pipeable"
|
|
10
|
+
import type * as Queue from "effect/Queue"
|
|
11
|
+
import type * as Record from "effect/Record"
|
|
12
|
+
import * as Schema from "effect/Schema"
|
|
13
|
+
import * as SchemaIssue from "effect/SchemaIssue"
|
|
14
|
+
import * as SchemaParser from "effect/SchemaParser"
|
|
15
|
+
import type * as Scope from "effect/Scope"
|
|
16
|
+
import type * as Stream from "effect/Stream"
|
|
17
|
+
import type * as Reactivity from "effect/unstable/reactivity/Reactivity"
|
|
18
|
+
import * as Utils from "effect/Utils"
|
|
19
|
+
import type * as IndexedDb from "./IndexedDb.ts"
|
|
20
|
+
import type * as IndexedDbDatabase from "./IndexedDbDatabase.ts"
|
|
21
|
+
import type * as IndexedDbTable from "./IndexedDbTable.ts"
|
|
22
|
+
import type * as IndexedDbVersion from "./IndexedDbVersion.ts"
|
|
23
|
+
|
|
24
|
+
const ErrorTypeId = "~@effect/platform-browser/IndexedDbQueryBuilder/IndexedDbQueryError"
|
|
25
|
+
|
|
26
|
+
const CommonProto = {
|
|
27
|
+
[Symbol.iterator]() {
|
|
28
|
+
return new Utils.SingleShotGen(this) as any
|
|
29
|
+
},
|
|
30
|
+
...Pipeable.Prototype,
|
|
31
|
+
...BaseProto,
|
|
32
|
+
toJSON(this: any) {
|
|
33
|
+
return {
|
|
34
|
+
_id: "IndexedDbQueryBuilder"
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* @since 4.0.0
|
|
41
|
+
* @category errors
|
|
42
|
+
*/
|
|
43
|
+
export type ErrorReason =
|
|
44
|
+
| "NotFoundError"
|
|
45
|
+
| "UnknownError"
|
|
46
|
+
| "DecodeError"
|
|
47
|
+
| "EncodeError"
|
|
48
|
+
| "TransactionError"
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* @since 4.0.0
|
|
52
|
+
* @category errors
|
|
53
|
+
*/
|
|
54
|
+
export class IndexedDbQueryError extends Data.TaggedError(
|
|
55
|
+
"IndexedDbQueryError"
|
|
56
|
+
)<{
|
|
57
|
+
reason: ErrorReason
|
|
58
|
+
cause: unknown
|
|
59
|
+
}> {
|
|
60
|
+
/**
|
|
61
|
+
* @since 4.0.0
|
|
62
|
+
*/
|
|
63
|
+
readonly [ErrorTypeId]: typeof ErrorTypeId = ErrorTypeId
|
|
64
|
+
|
|
65
|
+
override readonly message = this.reason
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* @since 4.0.0
|
|
70
|
+
* @category models
|
|
71
|
+
*/
|
|
72
|
+
export interface IndexedDbQueryBuilder<
|
|
73
|
+
Source extends IndexedDbVersion.AnyWithProps
|
|
74
|
+
> extends Pipeable.Pipeable, Inspectable {
|
|
75
|
+
readonly tables: ReadonlyMap<string, IndexedDbVersion.Tables<Source>>
|
|
76
|
+
readonly database: globalThis.IDBDatabase
|
|
77
|
+
readonly reactivity: Reactivity.Reactivity["Service"]
|
|
78
|
+
readonly IDBKeyRange: typeof globalThis.IDBKeyRange
|
|
79
|
+
readonly IDBTransaction: globalThis.IDBTransaction | undefined
|
|
80
|
+
|
|
81
|
+
readonly use: <A = unknown>(
|
|
82
|
+
f: (database: globalThis.IDBDatabase) => Promise<A>
|
|
83
|
+
) => Effect.Effect<A, IndexedDbQueryError>
|
|
84
|
+
|
|
85
|
+
readonly from: <
|
|
86
|
+
const Name extends IndexedDbTable.TableName<
|
|
87
|
+
IndexedDbVersion.Tables<Source>
|
|
88
|
+
>
|
|
89
|
+
>(
|
|
90
|
+
table: Name
|
|
91
|
+
) => IndexedDbQuery.From<IndexedDbVersion.TableWithName<Source, Name>>
|
|
92
|
+
|
|
93
|
+
readonly clearAll: Effect.Effect<void, IndexedDbQueryError>
|
|
94
|
+
|
|
95
|
+
readonly transaction: <
|
|
96
|
+
Tables extends NonEmptyReadonlyArray<
|
|
97
|
+
IndexedDbTable.TableName<IndexedDbVersion.Tables<Source>>
|
|
98
|
+
>,
|
|
99
|
+
Mode extends "readonly" | "readwrite",
|
|
100
|
+
E,
|
|
101
|
+
R
|
|
102
|
+
>(
|
|
103
|
+
tables: Tables,
|
|
104
|
+
mode: Mode,
|
|
105
|
+
callback: (api: {
|
|
106
|
+
readonly from: <Name extends Tables[number]>(
|
|
107
|
+
table: Name
|
|
108
|
+
) => Mode extends "readwrite" ? IndexedDbQuery.From<IndexedDbVersion.TableWithName<Source, Name>>
|
|
109
|
+
: Omit<
|
|
110
|
+
IndexedDbQuery.From<IndexedDbVersion.TableWithName<Source, Name>>,
|
|
111
|
+
"insert" | "insertAll" | "upsert" | "upsertAll" | "clear" | "delete"
|
|
112
|
+
>
|
|
113
|
+
}) => Effect.Effect<void, E, R>,
|
|
114
|
+
options?: globalThis.IDBTransactionOptions
|
|
115
|
+
) => Effect.Effect<void, never, R>
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* @since 4.0.0
|
|
120
|
+
* @category models
|
|
121
|
+
*/
|
|
122
|
+
export type KeyPath<TableSchema extends IndexedDbTable.AnySchemaStruct> =
|
|
123
|
+
| IndexedDbValidKeys<TableSchema>
|
|
124
|
+
| NonEmptyReadonlyArray<IndexedDbValidKeys<TableSchema>>
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* @since 4.0.0
|
|
128
|
+
* @category models
|
|
129
|
+
*/
|
|
130
|
+
export type KeyPathNumber<TableSchema extends IndexedDbTable.AnySchemaStruct> =
|
|
131
|
+
| IndexedDbValidNumberKeys<TableSchema>
|
|
132
|
+
| NonEmptyReadonlyArray<IndexedDbValidNumberKeys<TableSchema>>
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* @since 4.0.0
|
|
136
|
+
* @category models
|
|
137
|
+
*/
|
|
138
|
+
export declare namespace IndexedDbQuery {
|
|
139
|
+
/**
|
|
140
|
+
* @since 4.0.0
|
|
141
|
+
* @category models
|
|
142
|
+
*/
|
|
143
|
+
export type SourceTableSelectSchemaType<
|
|
144
|
+
Table extends IndexedDbTable.AnyWithProps
|
|
145
|
+
> = [IndexedDbTable.KeyPath<Table>] extends [undefined] ? IndexedDbTable.TableSchema<Table>["Type"] & {
|
|
146
|
+
readonly key: (typeof IndexedDb.IDBValidKey)["Type"]
|
|
147
|
+
} :
|
|
148
|
+
IndexedDbTable.TableSchema<Table>["Type"]
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* @since 4.0.0
|
|
152
|
+
* @category models
|
|
153
|
+
*/
|
|
154
|
+
export type SourceTableModifySchemaType<
|
|
155
|
+
Table extends IndexedDbTable.AnyWithProps
|
|
156
|
+
> =
|
|
157
|
+
& (IndexedDbTable.AutoIncrement<Table> extends true ?
|
|
158
|
+
& {
|
|
159
|
+
[
|
|
160
|
+
key in keyof Schema.Struct.MakeIn<
|
|
161
|
+
Omit<
|
|
162
|
+
IndexedDbTable.TableSchema<Table>["fields"],
|
|
163
|
+
IndexedDbTable.KeyPath<Table>
|
|
164
|
+
>
|
|
165
|
+
>
|
|
166
|
+
]: key extends keyof Schema.Struct.MakeIn<
|
|
167
|
+
IndexedDbTable.TableSchema<Table>["fields"]
|
|
168
|
+
> ? Schema.Struct.MakeIn<
|
|
169
|
+
IndexedDbTable.TableSchema<Table>["fields"]
|
|
170
|
+
>[key]
|
|
171
|
+
: never
|
|
172
|
+
}
|
|
173
|
+
& {
|
|
174
|
+
[key in IndexedDbTable.KeyPath<Table>]?: number | undefined
|
|
175
|
+
}
|
|
176
|
+
: Schema.Struct.MakeIn<IndexedDbTable.TableSchema<Table>["fields"]>)
|
|
177
|
+
& ([IndexedDbTable.KeyPath<Table>] extends [undefined] ? {
|
|
178
|
+
key: IDBValidKey
|
|
179
|
+
}
|
|
180
|
+
: {})
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* @since 4.0.0
|
|
184
|
+
* @category models
|
|
185
|
+
*/
|
|
186
|
+
export type ExtractIndexType<
|
|
187
|
+
Table extends IndexedDbTable.AnyWithProps,
|
|
188
|
+
Index extends IndexedDbDatabase.IndexFromTable<Table>
|
|
189
|
+
> = [Index] extends [never] ? Schema.Schema.Type<
|
|
190
|
+
IndexedDbTable.TableSchema<Table>
|
|
191
|
+
>[IndexedDbTable.KeyPath<Table>]
|
|
192
|
+
: Schema.Schema.Type<
|
|
193
|
+
IndexedDbTable.TableSchema<Table>
|
|
194
|
+
>[IndexedDbTable.Indexes<Table>[Index]]
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* @since 4.0.0
|
|
198
|
+
* @category models
|
|
199
|
+
*/
|
|
200
|
+
export type ModifyWithKey<Table extends IndexedDbTable.AnyWithProps> = SourceTableModifySchemaType<Table>
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* @since 4.0.0
|
|
204
|
+
* @category models
|
|
205
|
+
*/
|
|
206
|
+
export interface From<Table extends IndexedDbTable.AnyWithProps> {
|
|
207
|
+
readonly table: Table
|
|
208
|
+
readonly database: globalThis.IDBDatabase
|
|
209
|
+
readonly IDBKeyRange: typeof globalThis.IDBKeyRange
|
|
210
|
+
readonly transaction?: globalThis.IDBTransaction
|
|
211
|
+
readonly reactivity: Reactivity.Reactivity["Service"]
|
|
212
|
+
|
|
213
|
+
readonly clear: Effect.Effect<void, IndexedDbQueryError>
|
|
214
|
+
|
|
215
|
+
readonly select: {
|
|
216
|
+
<Index extends IndexedDbDatabase.IndexFromTable<Table>>(
|
|
217
|
+
index: Index
|
|
218
|
+
): Select<Table, Index>
|
|
219
|
+
(): Select<Table, never>
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
readonly count: {
|
|
223
|
+
<Index extends IndexedDbDatabase.IndexFromTable<Table>>(
|
|
224
|
+
index: Index
|
|
225
|
+
): Count<Table, Index>
|
|
226
|
+
(): Count<Table, never>
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
readonly delete: {
|
|
230
|
+
<Index extends IndexedDbDatabase.IndexFromTable<Table>>(
|
|
231
|
+
index: Index
|
|
232
|
+
): DeletePartial<Table, Index>
|
|
233
|
+
(): DeletePartial<Table, never>
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
readonly insert: (value: ModifyWithKey<Table>) => Modify<Table>
|
|
237
|
+
readonly insertAll: (
|
|
238
|
+
values: Array<ModifyWithKey<Table>>
|
|
239
|
+
) => ModifyAll<Table>
|
|
240
|
+
readonly upsert: (value: ModifyWithKey<Table>) => Modify<Table>
|
|
241
|
+
readonly upsertAll: (
|
|
242
|
+
values: Array<ModifyWithKey<Table>>
|
|
243
|
+
) => ModifyAll<Table>
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* @since 4.0.0
|
|
248
|
+
* @category models
|
|
249
|
+
*/
|
|
250
|
+
export interface Clear<
|
|
251
|
+
Table extends IndexedDbTable.AnyWithProps
|
|
252
|
+
> extends Pipeable.Pipeable, Effect.YieldableClass<void, IndexedDbQueryError> {
|
|
253
|
+
readonly from: From<Table>
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* @since 4.0.0
|
|
258
|
+
* @category models
|
|
259
|
+
*/
|
|
260
|
+
export interface Count<
|
|
261
|
+
Table extends IndexedDbTable.AnyWithProps,
|
|
262
|
+
Index extends IndexedDbDatabase.IndexFromTable<Table>
|
|
263
|
+
> extends Pipeable.Pipeable, Effect.YieldableClass<number, IndexedDbQueryError> {
|
|
264
|
+
readonly from: From<Table>
|
|
265
|
+
readonly index?: Index
|
|
266
|
+
readonly only?: ExtractIndexType<Table, Index>
|
|
267
|
+
readonly lowerBound?: ExtractIndexType<Table, Index>
|
|
268
|
+
readonly upperBound?: ExtractIndexType<Table, Index>
|
|
269
|
+
readonly excludeLowerBound?: boolean
|
|
270
|
+
readonly excludeUpperBound?: boolean
|
|
271
|
+
readonly limitValue?: number | undefined
|
|
272
|
+
|
|
273
|
+
readonly equals: (
|
|
274
|
+
value: ExtractIndexType<Table, Index>
|
|
275
|
+
) => Omit<
|
|
276
|
+
Count<Table, Index>,
|
|
277
|
+
"equals" | "gte" | "lte" | "gt" | "lt" | "between"
|
|
278
|
+
>
|
|
279
|
+
|
|
280
|
+
readonly gte: (
|
|
281
|
+
value: ExtractIndexType<Table, Index>
|
|
282
|
+
) => Omit<
|
|
283
|
+
Count<Table, Index>,
|
|
284
|
+
"equals" | "gte" | "lte" | "gt" | "lt" | "between"
|
|
285
|
+
>
|
|
286
|
+
|
|
287
|
+
readonly lte: (
|
|
288
|
+
value: ExtractIndexType<Table, Index>
|
|
289
|
+
) => Omit<
|
|
290
|
+
Count<Table, Index>,
|
|
291
|
+
"equals" | "gte" | "lte" | "gt" | "lt" | "between"
|
|
292
|
+
>
|
|
293
|
+
|
|
294
|
+
readonly gt: (
|
|
295
|
+
value: ExtractIndexType<Table, Index>
|
|
296
|
+
) => Omit<
|
|
297
|
+
Count<Table, Index>,
|
|
298
|
+
"equals" | "gte" | "lte" | "gt" | "lt" | "between"
|
|
299
|
+
>
|
|
300
|
+
|
|
301
|
+
readonly lt: (
|
|
302
|
+
value: ExtractIndexType<Table, Index>
|
|
303
|
+
) => Omit<
|
|
304
|
+
Count<Table, Index>,
|
|
305
|
+
"equals" | "gte" | "lte" | "gt" | "lt" | "between"
|
|
306
|
+
>
|
|
307
|
+
|
|
308
|
+
readonly between: (
|
|
309
|
+
lowerBound: ExtractIndexType<Table, Index>,
|
|
310
|
+
upperBound: ExtractIndexType<Table, Index>,
|
|
311
|
+
options?: { excludeLowerBound?: boolean; excludeUpperBound?: boolean }
|
|
312
|
+
) => Omit<
|
|
313
|
+
Count<Table, Index>,
|
|
314
|
+
"equals" | "gte" | "lte" | "gt" | "lt" | "between"
|
|
315
|
+
>
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* @since 4.0.0
|
|
320
|
+
* @category models
|
|
321
|
+
*/
|
|
322
|
+
export interface DeletePartial<
|
|
323
|
+
Table extends IndexedDbTable.AnyWithProps,
|
|
324
|
+
Index extends IndexedDbDatabase.IndexFromTable<Table>
|
|
325
|
+
> {
|
|
326
|
+
readonly from: From<Table>
|
|
327
|
+
readonly index?: Index
|
|
328
|
+
|
|
329
|
+
readonly equals: (
|
|
330
|
+
value: ExtractIndexType<Table, Index>
|
|
331
|
+
) => Omit<
|
|
332
|
+
Delete<Table, Index>,
|
|
333
|
+
"equals" | "gte" | "lte" | "gt" | "lt" | "between"
|
|
334
|
+
>
|
|
335
|
+
|
|
336
|
+
readonly gte: (
|
|
337
|
+
value: ExtractIndexType<Table, Index>
|
|
338
|
+
) => Omit<
|
|
339
|
+
Delete<Table, Index>,
|
|
340
|
+
"equals" | "gte" | "lte" | "gt" | "lt" | "between"
|
|
341
|
+
>
|
|
342
|
+
|
|
343
|
+
readonly lte: (
|
|
344
|
+
value: ExtractIndexType<Table, Index>
|
|
345
|
+
) => Omit<
|
|
346
|
+
Delete<Table, Index>,
|
|
347
|
+
"equals" | "gte" | "lte" | "gt" | "lt" | "between"
|
|
348
|
+
>
|
|
349
|
+
|
|
350
|
+
readonly gt: (
|
|
351
|
+
value: ExtractIndexType<Table, Index>
|
|
352
|
+
) => Omit<
|
|
353
|
+
Delete<Table, Index>,
|
|
354
|
+
"equals" | "gte" | "lte" | "gt" | "lt" | "between"
|
|
355
|
+
>
|
|
356
|
+
|
|
357
|
+
readonly lt: (
|
|
358
|
+
value: ExtractIndexType<Table, Index>
|
|
359
|
+
) => Omit<
|
|
360
|
+
Delete<Table, Index>,
|
|
361
|
+
"equals" | "gte" | "lte" | "gt" | "lt" | "between"
|
|
362
|
+
>
|
|
363
|
+
|
|
364
|
+
readonly between: (
|
|
365
|
+
lowerBound: ExtractIndexType<Table, Index>,
|
|
366
|
+
upperBound: ExtractIndexType<Table, Index>,
|
|
367
|
+
options?: { excludeLowerBound?: boolean; excludeUpperBound?: boolean }
|
|
368
|
+
) => Omit<
|
|
369
|
+
Delete<Table, Index>,
|
|
370
|
+
"equals" | "gte" | "lte" | "gt" | "lt" | "between"
|
|
371
|
+
>
|
|
372
|
+
|
|
373
|
+
readonly limit: (
|
|
374
|
+
limit: number
|
|
375
|
+
) => Omit<
|
|
376
|
+
Delete<Table, Index>,
|
|
377
|
+
"limit" | "equals" | "gte" | "lte" | "gt" | "lt" | "between"
|
|
378
|
+
>
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* @since 4.0.0
|
|
383
|
+
* @category models
|
|
384
|
+
*/
|
|
385
|
+
export interface Delete<
|
|
386
|
+
Table extends IndexedDbTable.AnyWithProps,
|
|
387
|
+
Index extends IndexedDbDatabase.IndexFromTable<Table>
|
|
388
|
+
> extends Pipeable.Pipeable, Effect.YieldableClass<void, IndexedDbQueryError> {
|
|
389
|
+
readonly delete: DeletePartial<Table, Index>
|
|
390
|
+
readonly index?: Index
|
|
391
|
+
readonly limitValue?: number
|
|
392
|
+
readonly only?: ExtractIndexType<Table, Index>
|
|
393
|
+
readonly lowerBound?: ExtractIndexType<Table, Index>
|
|
394
|
+
readonly upperBound?: ExtractIndexType<Table, Index>
|
|
395
|
+
readonly excludeLowerBound?: boolean
|
|
396
|
+
readonly excludeUpperBound?: boolean
|
|
397
|
+
readonly predicate?: (item: IndexedDbTable.Encoded<Table>) => boolean
|
|
398
|
+
|
|
399
|
+
readonly equals: (
|
|
400
|
+
value: ExtractIndexType<Table, Index>
|
|
401
|
+
) => Omit<
|
|
402
|
+
Delete<Table, Index>,
|
|
403
|
+
"equals" | "gte" | "lte" | "gt" | "lt" | "between"
|
|
404
|
+
>
|
|
405
|
+
|
|
406
|
+
readonly gte: (
|
|
407
|
+
value: ExtractIndexType<Table, Index>
|
|
408
|
+
) => Omit<
|
|
409
|
+
Delete<Table, Index>,
|
|
410
|
+
"equals" | "gte" | "lte" | "gt" | "lt" | "between"
|
|
411
|
+
>
|
|
412
|
+
|
|
413
|
+
readonly lte: (
|
|
414
|
+
value: ExtractIndexType<Table, Index>
|
|
415
|
+
) => Omit<
|
|
416
|
+
Delete<Table, Index>,
|
|
417
|
+
"equals" | "gte" | "lte" | "gt" | "lt" | "between"
|
|
418
|
+
>
|
|
419
|
+
|
|
420
|
+
readonly gt: (
|
|
421
|
+
value: ExtractIndexType<Table, Index>
|
|
422
|
+
) => Omit<
|
|
423
|
+
Delete<Table, Index>,
|
|
424
|
+
"equals" | "gte" | "lte" | "gt" | "lt" | "between"
|
|
425
|
+
>
|
|
426
|
+
|
|
427
|
+
readonly lt: (
|
|
428
|
+
value: ExtractIndexType<Table, Index>
|
|
429
|
+
) => Omit<
|
|
430
|
+
Delete<Table, Index>,
|
|
431
|
+
"equals" | "gte" | "lte" | "gt" | "lt" | "between"
|
|
432
|
+
>
|
|
433
|
+
|
|
434
|
+
readonly between: (
|
|
435
|
+
lowerBound: ExtractIndexType<Table, Index>,
|
|
436
|
+
upperBound: ExtractIndexType<Table, Index>,
|
|
437
|
+
options?: { excludeLowerBound?: boolean; excludeUpperBound?: boolean }
|
|
438
|
+
) => Omit<
|
|
439
|
+
Delete<Table, Index>,
|
|
440
|
+
"equals" | "gte" | "lte" | "gt" | "lt" | "between"
|
|
441
|
+
>
|
|
442
|
+
|
|
443
|
+
readonly limit: (
|
|
444
|
+
limit: number
|
|
445
|
+
) => Omit<
|
|
446
|
+
Delete<Table, Index>,
|
|
447
|
+
"limit" | "equals" | "gte" | "lte" | "gt" | "lt" | "between"
|
|
448
|
+
>
|
|
449
|
+
|
|
450
|
+
readonly filter: (
|
|
451
|
+
f: (value: IndexedDbTable.Encoded<Table>) => boolean
|
|
452
|
+
) => Delete<Table, Index>
|
|
453
|
+
|
|
454
|
+
readonly invalidate: (
|
|
455
|
+
keys: ReadonlyArray<unknown> | Record.ReadonlyRecord<string, ReadonlyArray<unknown>>
|
|
456
|
+
) => Effect.Effect<void, IndexedDbQueryError, IndexedDbTable.Context<Table>>
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
/**
|
|
460
|
+
* @since 4.0.0
|
|
461
|
+
* @category models
|
|
462
|
+
*/
|
|
463
|
+
export interface Select<
|
|
464
|
+
Table extends IndexedDbTable.AnyWithProps,
|
|
465
|
+
Index extends IndexedDbDatabase.IndexFromTable<Table>
|
|
466
|
+
> extends
|
|
467
|
+
Pipeable.Pipeable,
|
|
468
|
+
Effect.YieldableClass<
|
|
469
|
+
Array<SourceTableSelectSchemaType<Table>>,
|
|
470
|
+
IndexedDbQueryError,
|
|
471
|
+
IndexedDbTable.Context<Table>
|
|
472
|
+
>
|
|
473
|
+
{
|
|
474
|
+
readonly from: From<Table>
|
|
475
|
+
readonly index?: Index
|
|
476
|
+
readonly limitValue?: number
|
|
477
|
+
readonly only?: ExtractIndexType<Table, Index>
|
|
478
|
+
readonly lowerBound?: ExtractIndexType<Table, Index>
|
|
479
|
+
readonly upperBound?: ExtractIndexType<Table, Index>
|
|
480
|
+
readonly excludeLowerBound?: boolean
|
|
481
|
+
readonly excludeUpperBound?: boolean
|
|
482
|
+
readonly predicate?: (item: IndexedDbTable.Encoded<Table>) => boolean
|
|
483
|
+
|
|
484
|
+
readonly equals: (
|
|
485
|
+
value: ExtractIndexType<Table, Index>
|
|
486
|
+
) => Omit<
|
|
487
|
+
Select<Table, Index>,
|
|
488
|
+
"equals" | "gte" | "lte" | "gt" | "lt" | "between"
|
|
489
|
+
>
|
|
490
|
+
|
|
491
|
+
readonly gte: (
|
|
492
|
+
value: ExtractIndexType<Table, Index>
|
|
493
|
+
) => Omit<
|
|
494
|
+
Select<Table, Index>,
|
|
495
|
+
"equals" | "gte" | "lte" | "gt" | "lt" | "between"
|
|
496
|
+
>
|
|
497
|
+
|
|
498
|
+
readonly lte: (
|
|
499
|
+
value: ExtractIndexType<Table, Index>
|
|
500
|
+
) => Omit<
|
|
501
|
+
Select<Table, Index>,
|
|
502
|
+
"equals" | "gte" | "lte" | "gt" | "lt" | "between"
|
|
503
|
+
>
|
|
504
|
+
|
|
505
|
+
readonly gt: (
|
|
506
|
+
value: ExtractIndexType<Table, Index>
|
|
507
|
+
) => Omit<
|
|
508
|
+
Select<Table, Index>,
|
|
509
|
+
"equals" | "gte" | "lte" | "gt" | "lt" | "between"
|
|
510
|
+
>
|
|
511
|
+
|
|
512
|
+
readonly lt: (
|
|
513
|
+
value: ExtractIndexType<Table, Index>
|
|
514
|
+
) => Omit<
|
|
515
|
+
Select<Table, Index>,
|
|
516
|
+
"equals" | "gte" | "lte" | "gt" | "lt" | "between"
|
|
517
|
+
>
|
|
518
|
+
|
|
519
|
+
readonly between: (
|
|
520
|
+
lowerBound: ExtractIndexType<Table, Index>,
|
|
521
|
+
upperBound: ExtractIndexType<Table, Index>,
|
|
522
|
+
options?: { excludeLowerBound?: boolean; excludeUpperBound?: boolean }
|
|
523
|
+
) => Omit<
|
|
524
|
+
Select<Table, Index>,
|
|
525
|
+
"equals" | "gte" | "lte" | "gt" | "lt" | "between"
|
|
526
|
+
>
|
|
527
|
+
|
|
528
|
+
readonly limit: (
|
|
529
|
+
limit: number
|
|
530
|
+
) => Omit<
|
|
531
|
+
Select<Table, Index>,
|
|
532
|
+
"limit" | "equals" | "gte" | "lte" | "gt" | "lt" | "between" | "first"
|
|
533
|
+
>
|
|
534
|
+
|
|
535
|
+
readonly filter: (
|
|
536
|
+
f: (value: IndexedDbTable.Encoded<Table>) => boolean
|
|
537
|
+
) => Select<Table, Index>
|
|
538
|
+
|
|
539
|
+
readonly first: () => First<Table, Index>
|
|
540
|
+
|
|
541
|
+
readonly reactive: (
|
|
542
|
+
keys: ReadonlyArray<unknown> | Record.ReadonlyRecord<string, ReadonlyArray<unknown>>
|
|
543
|
+
) => Stream.Stream<
|
|
544
|
+
Array<SourceTableSelectSchemaType<Table>>,
|
|
545
|
+
IndexedDbQueryError,
|
|
546
|
+
IndexedDbTable.Context<Table>
|
|
547
|
+
>
|
|
548
|
+
readonly reactiveQueue: (
|
|
549
|
+
keys: ReadonlyArray<unknown> | Record.ReadonlyRecord<string, ReadonlyArray<unknown>>
|
|
550
|
+
) => Effect.Effect<
|
|
551
|
+
Queue.Dequeue<Array<SourceTableSelectSchemaType<Table>>, IndexedDbQueryError>,
|
|
552
|
+
never,
|
|
553
|
+
Scope.Scope | IndexedDbTable.Context<Table>
|
|
554
|
+
>
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
/**
|
|
558
|
+
* @since 4.0.0
|
|
559
|
+
* @category models
|
|
560
|
+
*/
|
|
561
|
+
export interface First<
|
|
562
|
+
Table extends IndexedDbTable.AnyWithProps,
|
|
563
|
+
Index extends IndexedDbDatabase.IndexFromTable<Table>
|
|
564
|
+
> extends
|
|
565
|
+
Pipeable.Pipeable,
|
|
566
|
+
Effect.YieldableClass<
|
|
567
|
+
SourceTableSelectSchemaType<Table>,
|
|
568
|
+
IndexedDbQueryError,
|
|
569
|
+
IndexedDbTable.Context<Table>
|
|
570
|
+
>
|
|
571
|
+
{
|
|
572
|
+
readonly select: Select<Table, Index>
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
/**
|
|
576
|
+
* @since 4.0.0
|
|
577
|
+
* @category models
|
|
578
|
+
*/
|
|
579
|
+
export interface Filter<
|
|
580
|
+
Table extends IndexedDbTable.AnyWithProps,
|
|
581
|
+
Index extends IndexedDbDatabase.IndexFromTable<Table>
|
|
582
|
+
> extends
|
|
583
|
+
Pipeable.Pipeable,
|
|
584
|
+
Effect.YieldableClass<
|
|
585
|
+
Array<SourceTableSelectSchemaType<Table>>,
|
|
586
|
+
IndexedDbQueryError,
|
|
587
|
+
IndexedDbTable.Context<Table>
|
|
588
|
+
>
|
|
589
|
+
{
|
|
590
|
+
readonly select: Select<Table, Index>
|
|
591
|
+
readonly predicate: (item: IndexedDbTable.Encoded<Table>) => boolean
|
|
592
|
+
readonly filter: (
|
|
593
|
+
f: (value: IndexedDbTable.Encoded<Table>) => boolean
|
|
594
|
+
) => Filter<Table, Index>
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
/**
|
|
598
|
+
* @since 4.0.0
|
|
599
|
+
* @category models
|
|
600
|
+
*/
|
|
601
|
+
export interface Modify<
|
|
602
|
+
Table extends IndexedDbTable.AnyWithProps
|
|
603
|
+
> extends
|
|
604
|
+
Pipeable.Pipeable,
|
|
605
|
+
Effect.YieldableClass<
|
|
606
|
+
globalThis.IDBValidKey,
|
|
607
|
+
IndexedDbQueryError,
|
|
608
|
+
IndexedDbTable.Context<Table>
|
|
609
|
+
>
|
|
610
|
+
{
|
|
611
|
+
readonly operation: "add" | "put"
|
|
612
|
+
readonly from: From<Table>
|
|
613
|
+
readonly value: ModifyWithKey<Table>
|
|
614
|
+
readonly invalidate: (
|
|
615
|
+
keys: ReadonlyArray<unknown> | Record.ReadonlyRecord<string, ReadonlyArray<unknown>>
|
|
616
|
+
) => Effect.Effect<globalThis.IDBValidKey, IndexedDbQueryError, IndexedDbTable.Context<Table>>
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
/**
|
|
620
|
+
* @since 4.0.0
|
|
621
|
+
* @category models
|
|
622
|
+
*/
|
|
623
|
+
export interface ModifyAll<
|
|
624
|
+
Table extends IndexedDbTable.AnyWithProps
|
|
625
|
+
> extends
|
|
626
|
+
Pipeable.Pipeable,
|
|
627
|
+
Effect.YieldableClass<
|
|
628
|
+
Array<globalThis.IDBValidKey>,
|
|
629
|
+
IndexedDbQueryError,
|
|
630
|
+
IndexedDbTable.Context<Table>
|
|
631
|
+
>
|
|
632
|
+
{
|
|
633
|
+
readonly operation: "add" | "put"
|
|
634
|
+
readonly from: From<Table>
|
|
635
|
+
readonly values: Array<ModifyWithKey<Table>>
|
|
636
|
+
readonly invalidate: (
|
|
637
|
+
keys: ReadonlyArray<unknown> | Record.ReadonlyRecord<string, ReadonlyArray<unknown>>
|
|
638
|
+
) => Effect.Effect<Array<globalThis.IDBValidKey>, IndexedDbQueryError, IndexedDbTable.Context<Table>>
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
// -----------------------------------------------------------------------------
|
|
643
|
+
// internal
|
|
644
|
+
// -----------------------------------------------------------------------------
|
|
645
|
+
|
|
646
|
+
type IndexedDbValidKeys<TableSchema extends IndexedDbTable.AnySchemaStruct> = keyof TableSchema["Encoded"] extends
|
|
647
|
+
infer K ? K extends keyof TableSchema["Encoded"] ? TableSchema["Encoded"][K] extends Readonly<IDBValidKey> ? K
|
|
648
|
+
: never
|
|
649
|
+
: never
|
|
650
|
+
: never
|
|
651
|
+
|
|
652
|
+
type IndexedDbValidNumberKeys<
|
|
653
|
+
TableSchema extends IndexedDbTable.AnySchemaStruct
|
|
654
|
+
> = keyof TableSchema["Encoded"] extends infer K
|
|
655
|
+
? K extends keyof TableSchema["Encoded"] ? [TableSchema["Encoded"][K]] extends [number | undefined] ? K
|
|
656
|
+
: never
|
|
657
|
+
: never
|
|
658
|
+
: never
|
|
659
|
+
|
|
660
|
+
const applyDelete = (query: IndexedDbQuery.Delete<any, never>) =>
|
|
661
|
+
Effect.callback<any, IndexedDbQueryError>((resume) => {
|
|
662
|
+
const database = query.delete.from.database
|
|
663
|
+
const IDBKeyRange = query.delete.from.IDBKeyRange
|
|
664
|
+
let transaction = query.delete.from.transaction
|
|
665
|
+
transaction ??= database.transaction([query.delete.from.table.tableName], "readwrite")
|
|
666
|
+
const objectStore = transaction.objectStore(query.delete.from.table.tableName)
|
|
667
|
+
const predicate = query.predicate
|
|
668
|
+
|
|
669
|
+
let keyRange: globalThis.IDBKeyRange | undefined = undefined
|
|
670
|
+
|
|
671
|
+
if (query.only !== undefined) {
|
|
672
|
+
keyRange = IDBKeyRange.only(query.only)
|
|
673
|
+
} else if (
|
|
674
|
+
query.lowerBound !== undefined &&
|
|
675
|
+
query.upperBound !== undefined
|
|
676
|
+
) {
|
|
677
|
+
keyRange = IDBKeyRange.bound(
|
|
678
|
+
query.lowerBound,
|
|
679
|
+
query.upperBound,
|
|
680
|
+
query.excludeLowerBound,
|
|
681
|
+
query.excludeUpperBound
|
|
682
|
+
)
|
|
683
|
+
} else if (query.lowerBound !== undefined) {
|
|
684
|
+
keyRange = IDBKeyRange.lowerBound(
|
|
685
|
+
query.lowerBound,
|
|
686
|
+
query.excludeLowerBound
|
|
687
|
+
)
|
|
688
|
+
} else if (query.upperBound !== undefined) {
|
|
689
|
+
keyRange = IDBKeyRange.upperBound(
|
|
690
|
+
query.upperBound,
|
|
691
|
+
query.excludeUpperBound
|
|
692
|
+
)
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
let request: globalThis.IDBRequest
|
|
696
|
+
|
|
697
|
+
if (query.limitValue !== undefined || predicate) {
|
|
698
|
+
const cursorRequest = objectStore.openCursor()
|
|
699
|
+
let count = 0
|
|
700
|
+
|
|
701
|
+
cursorRequest.onerror = () => {
|
|
702
|
+
resume(
|
|
703
|
+
Effect.fail(
|
|
704
|
+
new IndexedDbQueryError({
|
|
705
|
+
reason: "TransactionError",
|
|
706
|
+
cause: cursorRequest.error
|
|
707
|
+
})
|
|
708
|
+
)
|
|
709
|
+
)
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
cursorRequest.onsuccess = () => {
|
|
713
|
+
const cursor = cursorRequest.result
|
|
714
|
+
if (cursor === null) {
|
|
715
|
+
return resume(Effect.void)
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
if (predicate === undefined || predicate(cursor.value)) {
|
|
719
|
+
const deleteRequest = cursor.delete()
|
|
720
|
+
deleteRequest.onerror = () => {
|
|
721
|
+
resume(
|
|
722
|
+
Effect.fail(
|
|
723
|
+
new IndexedDbQueryError({
|
|
724
|
+
reason: "TransactionError",
|
|
725
|
+
cause: deleteRequest.error
|
|
726
|
+
})
|
|
727
|
+
)
|
|
728
|
+
)
|
|
729
|
+
}
|
|
730
|
+
count += 1
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
if (query.limitValue === undefined || count < query.limitValue) {
|
|
734
|
+
return cursor.continue()
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
resume(Effect.void)
|
|
738
|
+
}
|
|
739
|
+
} else if (keyRange !== undefined) {
|
|
740
|
+
request = objectStore.delete(keyRange)
|
|
741
|
+
|
|
742
|
+
request.onerror = (event) => {
|
|
743
|
+
resume(
|
|
744
|
+
Effect.fail(
|
|
745
|
+
new IndexedDbQueryError({
|
|
746
|
+
reason: "TransactionError",
|
|
747
|
+
cause: event
|
|
748
|
+
})
|
|
749
|
+
)
|
|
750
|
+
)
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
request.onsuccess = () => {
|
|
754
|
+
resume(Effect.succeed(request.result))
|
|
755
|
+
}
|
|
756
|
+
} else {
|
|
757
|
+
resume(
|
|
758
|
+
Effect.die(new Error("No key range provided for delete operation"))
|
|
759
|
+
)
|
|
760
|
+
}
|
|
761
|
+
})
|
|
762
|
+
|
|
763
|
+
const getReadonlyObjectStore = (
|
|
764
|
+
query: IndexedDbQuery.Select<any, never> | IndexedDbQuery.Count<any, never>
|
|
765
|
+
) => {
|
|
766
|
+
const database = query.from.database
|
|
767
|
+
const IDBKeyRange = query.from.IDBKeyRange
|
|
768
|
+
const transaction = query.from.transaction ?? database.transaction([query.from.table.tableName], "readonly")
|
|
769
|
+
const objectStore = transaction.objectStore(query.from.table.tableName)
|
|
770
|
+
|
|
771
|
+
let keyRange: globalThis.IDBKeyRange | undefined = undefined
|
|
772
|
+
let store: globalThis.IDBObjectStore | globalThis.IDBIndex
|
|
773
|
+
|
|
774
|
+
if (query.only !== undefined) {
|
|
775
|
+
keyRange = IDBKeyRange.only(query.only)
|
|
776
|
+
} else if (query.lowerBound !== undefined && query.upperBound !== undefined) {
|
|
777
|
+
keyRange = IDBKeyRange.bound(
|
|
778
|
+
query.lowerBound,
|
|
779
|
+
query.upperBound,
|
|
780
|
+
query.excludeLowerBound,
|
|
781
|
+
query.excludeUpperBound
|
|
782
|
+
)
|
|
783
|
+
} else if (query.lowerBound !== undefined) {
|
|
784
|
+
keyRange = IDBKeyRange.lowerBound(
|
|
785
|
+
query.lowerBound,
|
|
786
|
+
query.excludeLowerBound
|
|
787
|
+
)
|
|
788
|
+
} else if (query.upperBound !== undefined) {
|
|
789
|
+
keyRange = IDBKeyRange.upperBound(
|
|
790
|
+
query.upperBound,
|
|
791
|
+
query.excludeUpperBound
|
|
792
|
+
)
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
if (query.index !== undefined) {
|
|
796
|
+
store = objectStore.index(query.index)
|
|
797
|
+
} else {
|
|
798
|
+
store = objectStore
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
return { store, keyRange }
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
const getSelect = Effect.fnUntraced(function*(
|
|
805
|
+
query: IndexedDbQuery.Select<any, never>
|
|
806
|
+
) {
|
|
807
|
+
const keyPath = query.from.table.keyPath
|
|
808
|
+
const predicate = query.predicate
|
|
809
|
+
|
|
810
|
+
const data = predicate || keyPath === undefined ?
|
|
811
|
+
yield* Effect.callback<any, IndexedDbQueryError>((resume) => {
|
|
812
|
+
const { keyRange, store } = getReadonlyObjectStore(query)
|
|
813
|
+
|
|
814
|
+
const cursorRequest = store.openCursor(keyRange)
|
|
815
|
+
const results: Array<any> = []
|
|
816
|
+
let count = 0
|
|
817
|
+
|
|
818
|
+
cursorRequest.onerror = () => {
|
|
819
|
+
resume(
|
|
820
|
+
Effect.fail(
|
|
821
|
+
new IndexedDbQueryError({
|
|
822
|
+
reason: "TransactionError",
|
|
823
|
+
cause: cursorRequest.error
|
|
824
|
+
})
|
|
825
|
+
)
|
|
826
|
+
)
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
cursorRequest.onsuccess = () => {
|
|
830
|
+
const cursor = cursorRequest.result
|
|
831
|
+
if (cursor === null) {
|
|
832
|
+
return resume(Effect.succeed(results))
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
if (predicate === undefined || predicate(cursor.value)) {
|
|
836
|
+
results.push(
|
|
837
|
+
keyPath === undefined
|
|
838
|
+
? { ...cursor.value, key: cursor.key }
|
|
839
|
+
: cursor.value
|
|
840
|
+
)
|
|
841
|
+
count += 1
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
if (query.limitValue === undefined || count < query.limitValue) {
|
|
845
|
+
return cursor.continue()
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
resume(Effect.succeed(results))
|
|
849
|
+
}
|
|
850
|
+
}) :
|
|
851
|
+
yield* Effect.callback<any, IndexedDbQueryError>((resume) => {
|
|
852
|
+
const { keyRange, store } = getReadonlyObjectStore(query)
|
|
853
|
+
const request = store.getAll(keyRange, query.limitValue)
|
|
854
|
+
request.onerror = (event) => {
|
|
855
|
+
resume(
|
|
856
|
+
Effect.fail(
|
|
857
|
+
new IndexedDbQueryError({
|
|
858
|
+
reason: "TransactionError",
|
|
859
|
+
cause: event
|
|
860
|
+
})
|
|
861
|
+
)
|
|
862
|
+
)
|
|
863
|
+
}
|
|
864
|
+
request.onsuccess = () => {
|
|
865
|
+
resume(Effect.succeed(request.result))
|
|
866
|
+
}
|
|
867
|
+
})
|
|
868
|
+
|
|
869
|
+
const tableSchema = (query.from.table as IndexedDbTable.AnyWithProps).arraySchema
|
|
870
|
+
|
|
871
|
+
return yield* Schema.decodeUnknownEffect(tableSchema)(data).pipe(
|
|
872
|
+
Effect.mapError(
|
|
873
|
+
(error) =>
|
|
874
|
+
new IndexedDbQueryError({
|
|
875
|
+
reason: "DecodeError",
|
|
876
|
+
cause: error
|
|
877
|
+
})
|
|
878
|
+
)
|
|
879
|
+
)
|
|
880
|
+
})
|
|
881
|
+
|
|
882
|
+
const getFirst = Effect.fnUntraced(function*(
|
|
883
|
+
query: IndexedDbQuery.First<any, never>
|
|
884
|
+
) {
|
|
885
|
+
const keyPath = query.select.from.table.keyPath
|
|
886
|
+
|
|
887
|
+
const data = yield* Effect.callback<any, IndexedDbQueryError>((resume) => {
|
|
888
|
+
const { keyRange, store } = getReadonlyObjectStore(query.select)
|
|
889
|
+
|
|
890
|
+
if (keyRange !== undefined) {
|
|
891
|
+
const request = store.get(keyRange)
|
|
892
|
+
|
|
893
|
+
request.onerror = (event) => {
|
|
894
|
+
resume(
|
|
895
|
+
Effect.fail(
|
|
896
|
+
new IndexedDbQueryError({
|
|
897
|
+
reason: "TransactionError",
|
|
898
|
+
cause: event
|
|
899
|
+
})
|
|
900
|
+
)
|
|
901
|
+
)
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
request.onsuccess = () => {
|
|
905
|
+
resume(Effect.succeed(request.result))
|
|
906
|
+
}
|
|
907
|
+
} else {
|
|
908
|
+
const request = store.openCursor()
|
|
909
|
+
|
|
910
|
+
request.onerror = (event) => {
|
|
911
|
+
resume(
|
|
912
|
+
Effect.fail(
|
|
913
|
+
new IndexedDbQueryError({
|
|
914
|
+
reason: "TransactionError",
|
|
915
|
+
cause: event
|
|
916
|
+
})
|
|
917
|
+
)
|
|
918
|
+
)
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
request.onsuccess = () => {
|
|
922
|
+
const value = request.result?.value
|
|
923
|
+
const key = request.result?.key
|
|
924
|
+
|
|
925
|
+
if (value === undefined) {
|
|
926
|
+
resume(
|
|
927
|
+
Effect.fail(
|
|
928
|
+
new IndexedDbQueryError({
|
|
929
|
+
reason: "NotFoundError",
|
|
930
|
+
cause: request.error
|
|
931
|
+
})
|
|
932
|
+
)
|
|
933
|
+
)
|
|
934
|
+
} else {
|
|
935
|
+
resume(
|
|
936
|
+
Effect.succeed(keyPath === undefined ? { ...value, key } : value)
|
|
937
|
+
)
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
}
|
|
941
|
+
})
|
|
942
|
+
|
|
943
|
+
return yield* Schema.decodeUnknownEffect(query.select.from.table.readSchema)(
|
|
944
|
+
data
|
|
945
|
+
).pipe(
|
|
946
|
+
Effect.mapError(
|
|
947
|
+
(error) =>
|
|
948
|
+
new IndexedDbQueryError({
|
|
949
|
+
reason: "DecodeError",
|
|
950
|
+
cause: error
|
|
951
|
+
})
|
|
952
|
+
)
|
|
953
|
+
)
|
|
954
|
+
})
|
|
955
|
+
|
|
956
|
+
const applyModify = Effect.fnUntraced(function*({
|
|
957
|
+
query,
|
|
958
|
+
value
|
|
959
|
+
}: {
|
|
960
|
+
query: IndexedDbQuery.Modify<any>
|
|
961
|
+
value: any
|
|
962
|
+
}) {
|
|
963
|
+
const autoIncrement = query.from.table.autoIncrement as boolean
|
|
964
|
+
const keyPath = query.from.table.keyPath
|
|
965
|
+
const table = query.from.table
|
|
966
|
+
const schema = autoIncrement && value[keyPath] === undefined
|
|
967
|
+
? table.autoincrementSchema
|
|
968
|
+
: table.tableSchema
|
|
969
|
+
|
|
970
|
+
const encodedValue = yield* SchemaParser.makeEffect(
|
|
971
|
+
autoIncrement && value[keyPath] === undefined
|
|
972
|
+
? table.autoincrementSchema
|
|
973
|
+
: table.tableSchema
|
|
974
|
+
)(value).pipe(
|
|
975
|
+
Effect.flatMap(Schema.encodeUnknownEffect(schema)),
|
|
976
|
+
Effect.mapError(
|
|
977
|
+
(error) =>
|
|
978
|
+
new IndexedDbQueryError({
|
|
979
|
+
reason: "EncodeError",
|
|
980
|
+
cause: error
|
|
981
|
+
})
|
|
982
|
+
)
|
|
983
|
+
)
|
|
984
|
+
|
|
985
|
+
return yield* Effect.callback<any, IndexedDbQueryError>((resume) => {
|
|
986
|
+
const database = query.from.database
|
|
987
|
+
const transaction = query.from.transaction ?? database.transaction([query.from.table.tableName], "readwrite")
|
|
988
|
+
const objectStore = transaction.objectStore(query.from.table.tableName)
|
|
989
|
+
|
|
990
|
+
let request: globalThis.IDBRequest<IDBValidKey>
|
|
991
|
+
|
|
992
|
+
if (query.operation === "add") {
|
|
993
|
+
request = objectStore.add(
|
|
994
|
+
encodedValue,
|
|
995
|
+
keyPath === undefined ? value["key"] : undefined
|
|
996
|
+
)
|
|
997
|
+
} else if (query.operation === "put") {
|
|
998
|
+
request = objectStore.put(
|
|
999
|
+
encodedValue,
|
|
1000
|
+
keyPath === undefined ? value["key"] : undefined
|
|
1001
|
+
)
|
|
1002
|
+
} else {
|
|
1003
|
+
return resume(Effect.die(new Error("Invalid modify operation")))
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
request.onerror = (event) => {
|
|
1007
|
+
resume(
|
|
1008
|
+
Effect.fail(
|
|
1009
|
+
new IndexedDbQueryError({
|
|
1010
|
+
reason: "TransactionError",
|
|
1011
|
+
cause: event
|
|
1012
|
+
})
|
|
1013
|
+
)
|
|
1014
|
+
)
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
request.onsuccess = () => {
|
|
1018
|
+
resume(Effect.succeed(request.result))
|
|
1019
|
+
}
|
|
1020
|
+
})
|
|
1021
|
+
})
|
|
1022
|
+
|
|
1023
|
+
const applyModifyAll = Effect.fnUntraced(
|
|
1024
|
+
function*({
|
|
1025
|
+
query,
|
|
1026
|
+
values
|
|
1027
|
+
}: {
|
|
1028
|
+
query: IndexedDbQuery.ModifyAll<any>
|
|
1029
|
+
values: Array<any>
|
|
1030
|
+
}) {
|
|
1031
|
+
const autoIncrement = query.from.table.autoIncrement as boolean
|
|
1032
|
+
const keyPath = query.from.table.keyPath
|
|
1033
|
+
const schema = query.from.table.tableSchema
|
|
1034
|
+
const encodedValues = new Array(values.length)
|
|
1035
|
+
const makeValue = SchemaParser.makeEffect(schema)
|
|
1036
|
+
const encodeValue = SchemaParser.encodeUnknownEffect(schema)
|
|
1037
|
+
const makeValueAutoincrement = SchemaParser.makeEffect(query.from.table.autoincrementSchema)
|
|
1038
|
+
const encodeValueAutoincrement = SchemaParser.encodeUnknownEffect(query.from.table.autoincrementSchema)
|
|
1039
|
+
|
|
1040
|
+
for (let i = 0; i < values.length; i++) {
|
|
1041
|
+
const value = values[i]
|
|
1042
|
+
if (autoIncrement && value[keyPath] === undefined) {
|
|
1043
|
+
encodedValues[i] = yield* encodeValueAutoincrement(yield* makeValueAutoincrement(value))
|
|
1044
|
+
} else {
|
|
1045
|
+
encodedValues[i] = yield* encodeValue(yield* makeValue(value))
|
|
1046
|
+
}
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
return yield* Effect.callback<
|
|
1050
|
+
Array<globalThis.IDBValidKey>,
|
|
1051
|
+
IndexedDbQueryError
|
|
1052
|
+
>((resume) => {
|
|
1053
|
+
const database = query.from.database
|
|
1054
|
+
const transaction = query.from.transaction
|
|
1055
|
+
const objectStore = (
|
|
1056
|
+
transaction ??
|
|
1057
|
+
database.transaction([query.from.table.tableName], "readwrite")
|
|
1058
|
+
).objectStore(query.from.table.tableName)
|
|
1059
|
+
|
|
1060
|
+
const results: Array<globalThis.IDBValidKey> = []
|
|
1061
|
+
|
|
1062
|
+
if (query.operation === "add") {
|
|
1063
|
+
for (let i = 0; i < encodedValues.length; i++) {
|
|
1064
|
+
const request = objectStore.add(
|
|
1065
|
+
encodedValues[i],
|
|
1066
|
+
keyPath === undefined ? values[i]["key"] : undefined
|
|
1067
|
+
)
|
|
1068
|
+
|
|
1069
|
+
request.onerror = () => {
|
|
1070
|
+
resume(
|
|
1071
|
+
Effect.fail(
|
|
1072
|
+
new IndexedDbQueryError({
|
|
1073
|
+
reason: "TransactionError",
|
|
1074
|
+
cause: request.error
|
|
1075
|
+
})
|
|
1076
|
+
)
|
|
1077
|
+
)
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1080
|
+
request.onsuccess = () => {
|
|
1081
|
+
results.push(request.result)
|
|
1082
|
+
}
|
|
1083
|
+
}
|
|
1084
|
+
} else if (query.operation === "put") {
|
|
1085
|
+
for (let i = 0; i < encodedValues.length; i++) {
|
|
1086
|
+
const request = objectStore.put(
|
|
1087
|
+
encodedValues[i],
|
|
1088
|
+
keyPath === undefined ? values[i]["key"] : undefined
|
|
1089
|
+
)
|
|
1090
|
+
|
|
1091
|
+
request.onerror = () => {
|
|
1092
|
+
resume(
|
|
1093
|
+
Effect.fail(
|
|
1094
|
+
new IndexedDbQueryError({
|
|
1095
|
+
reason: "TransactionError",
|
|
1096
|
+
cause: request.error
|
|
1097
|
+
})
|
|
1098
|
+
)
|
|
1099
|
+
)
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
request.onsuccess = () => {
|
|
1103
|
+
results.push(request.result)
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
1106
|
+
} else {
|
|
1107
|
+
return resume(Effect.die(new Error("Invalid modify all operation")))
|
|
1108
|
+
}
|
|
1109
|
+
|
|
1110
|
+
objectStore.transaction.onerror = () => {
|
|
1111
|
+
resume(
|
|
1112
|
+
Effect.fail(
|
|
1113
|
+
new IndexedDbQueryError({
|
|
1114
|
+
reason: "TransactionError",
|
|
1115
|
+
cause: objectStore.transaction.error
|
|
1116
|
+
})
|
|
1117
|
+
)
|
|
1118
|
+
)
|
|
1119
|
+
}
|
|
1120
|
+
|
|
1121
|
+
objectStore.transaction.oncomplete = () => {
|
|
1122
|
+
resume(Effect.succeed(results))
|
|
1123
|
+
}
|
|
1124
|
+
})
|
|
1125
|
+
},
|
|
1126
|
+
Effect.catchIf(
|
|
1127
|
+
SchemaIssue.isIssue,
|
|
1128
|
+
(issue) => Effect.fail(new IndexedDbQueryError({ reason: "EncodeError", cause: new Schema.SchemaError(issue) }))
|
|
1129
|
+
)
|
|
1130
|
+
)
|
|
1131
|
+
|
|
1132
|
+
const applyClear = (options: {
|
|
1133
|
+
readonly database: globalThis.IDBDatabase
|
|
1134
|
+
readonly transaction: globalThis.IDBTransaction | undefined
|
|
1135
|
+
readonly table: string
|
|
1136
|
+
}) =>
|
|
1137
|
+
Effect.callback<void, IndexedDbQueryError>((resume) => {
|
|
1138
|
+
const database = options.database
|
|
1139
|
+
const transaction = options.transaction ?? database.transaction([options.table], "readwrite")
|
|
1140
|
+
const objectStore = transaction.objectStore(options.table)
|
|
1141
|
+
|
|
1142
|
+
const request = objectStore.clear()
|
|
1143
|
+
|
|
1144
|
+
request.onerror = (event) => {
|
|
1145
|
+
resume(
|
|
1146
|
+
Effect.fail(
|
|
1147
|
+
new IndexedDbQueryError({
|
|
1148
|
+
reason: "TransactionError",
|
|
1149
|
+
cause: event
|
|
1150
|
+
})
|
|
1151
|
+
)
|
|
1152
|
+
)
|
|
1153
|
+
}
|
|
1154
|
+
|
|
1155
|
+
request.onsuccess = () => {
|
|
1156
|
+
resume(Effect.void)
|
|
1157
|
+
}
|
|
1158
|
+
})
|
|
1159
|
+
|
|
1160
|
+
const applyClearAll = (options: {
|
|
1161
|
+
readonly database: globalThis.IDBDatabase
|
|
1162
|
+
readonly transaction: globalThis.IDBTransaction | undefined
|
|
1163
|
+
}) =>
|
|
1164
|
+
Effect.callback<void, IndexedDbQueryError>((resume) => {
|
|
1165
|
+
const database = options.database
|
|
1166
|
+
const tables = database.objectStoreNames
|
|
1167
|
+
const transaction = options.transaction ?? database.transaction([...tables], "readwrite")
|
|
1168
|
+
|
|
1169
|
+
for (let t = 0; t < tables.length; t++) {
|
|
1170
|
+
const objectStore = transaction.objectStore(tables[t])
|
|
1171
|
+
const request = objectStore.clear()
|
|
1172
|
+
|
|
1173
|
+
request.onerror = () => {
|
|
1174
|
+
resume(
|
|
1175
|
+
Effect.fail(
|
|
1176
|
+
new IndexedDbQueryError({
|
|
1177
|
+
reason: "TransactionError",
|
|
1178
|
+
cause: request.error
|
|
1179
|
+
})
|
|
1180
|
+
)
|
|
1181
|
+
)
|
|
1182
|
+
}
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
transaction.onerror = () => {
|
|
1186
|
+
resume(
|
|
1187
|
+
Effect.fail(
|
|
1188
|
+
new IndexedDbQueryError({
|
|
1189
|
+
reason: "TransactionError",
|
|
1190
|
+
cause: transaction.error
|
|
1191
|
+
})
|
|
1192
|
+
)
|
|
1193
|
+
)
|
|
1194
|
+
}
|
|
1195
|
+
|
|
1196
|
+
transaction.oncomplete = () => {
|
|
1197
|
+
resume(Effect.void)
|
|
1198
|
+
}
|
|
1199
|
+
})
|
|
1200
|
+
|
|
1201
|
+
const getCount = (query: IndexedDbQuery.Count<any, never>) =>
|
|
1202
|
+
Effect.callback<number, IndexedDbQueryError>((resume) => {
|
|
1203
|
+
const { keyRange, store } = getReadonlyObjectStore(query)
|
|
1204
|
+
|
|
1205
|
+
const request = store.count(keyRange)
|
|
1206
|
+
|
|
1207
|
+
request.onerror = (event) => {
|
|
1208
|
+
resume(
|
|
1209
|
+
Effect.fail(
|
|
1210
|
+
new IndexedDbQueryError({
|
|
1211
|
+
reason: "TransactionError",
|
|
1212
|
+
cause: event
|
|
1213
|
+
})
|
|
1214
|
+
)
|
|
1215
|
+
)
|
|
1216
|
+
}
|
|
1217
|
+
|
|
1218
|
+
request.onsuccess = () => {
|
|
1219
|
+
resume(Effect.succeed(request.result))
|
|
1220
|
+
}
|
|
1221
|
+
})
|
|
1222
|
+
|
|
1223
|
+
const FromProto: Omit<
|
|
1224
|
+
IndexedDbQuery.From<any>,
|
|
1225
|
+
| "table"
|
|
1226
|
+
| "database"
|
|
1227
|
+
| "IDBKeyRange"
|
|
1228
|
+
| "transaction"
|
|
1229
|
+
| "reactivity"
|
|
1230
|
+
> = {
|
|
1231
|
+
...CommonProto,
|
|
1232
|
+
select<Index extends IndexedDbDatabase.IndexFromTable<any>>(
|
|
1233
|
+
this: IndexedDbQuery.From<any>,
|
|
1234
|
+
index?: Index
|
|
1235
|
+
) {
|
|
1236
|
+
return makeSelect({
|
|
1237
|
+
from: this,
|
|
1238
|
+
index
|
|
1239
|
+
}) as any
|
|
1240
|
+
},
|
|
1241
|
+
count<Index extends IndexedDbDatabase.IndexFromTable<any>>(
|
|
1242
|
+
this: IndexedDbQuery.From<any>,
|
|
1243
|
+
index?: Index
|
|
1244
|
+
) {
|
|
1245
|
+
return makeCount({
|
|
1246
|
+
from: this,
|
|
1247
|
+
index
|
|
1248
|
+
}) as any
|
|
1249
|
+
},
|
|
1250
|
+
delete<Index extends IndexedDbDatabase.IndexFromTable<any>>(
|
|
1251
|
+
this: IndexedDbQuery.From<any>,
|
|
1252
|
+
index?: Index
|
|
1253
|
+
) {
|
|
1254
|
+
return makeDeletePartial({
|
|
1255
|
+
from: this,
|
|
1256
|
+
index
|
|
1257
|
+
}) as any
|
|
1258
|
+
},
|
|
1259
|
+
insert(this: IndexedDbQuery.From<any>, value: any) {
|
|
1260
|
+
return makeModify({ from: this, value, operation: "add" })
|
|
1261
|
+
},
|
|
1262
|
+
upsert(this: IndexedDbQuery.From<any>, value: any) {
|
|
1263
|
+
return makeModify({ from: this, value, operation: "put" })
|
|
1264
|
+
},
|
|
1265
|
+
insertAll(this: IndexedDbQuery.From<any>, values: Array<any>) {
|
|
1266
|
+
return makeModifyAll({ from: this, values, operation: "add" })
|
|
1267
|
+
},
|
|
1268
|
+
upsertAll(this: IndexedDbQuery.From<any>, values: Array<any>) {
|
|
1269
|
+
return makeModifyAll({ from: this, values, operation: "put" })
|
|
1270
|
+
},
|
|
1271
|
+
get clear() {
|
|
1272
|
+
const self = this as IndexedDbQuery.From<any>
|
|
1273
|
+
return applyClear({
|
|
1274
|
+
database: self.database,
|
|
1275
|
+
transaction: self.transaction,
|
|
1276
|
+
table: self.table.tableName
|
|
1277
|
+
})
|
|
1278
|
+
}
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1281
|
+
const makeFrom = <
|
|
1282
|
+
const Table extends IndexedDbTable.AnyWithProps
|
|
1283
|
+
>(options: {
|
|
1284
|
+
readonly table: Table
|
|
1285
|
+
readonly database: globalThis.IDBDatabase
|
|
1286
|
+
readonly IDBKeyRange: typeof globalThis.IDBKeyRange
|
|
1287
|
+
readonly transaction: globalThis.IDBTransaction | undefined
|
|
1288
|
+
readonly reactivity: Reactivity.Reactivity["Service"]
|
|
1289
|
+
}): IndexedDbQuery.From<Table> => {
|
|
1290
|
+
const self = Object.create(FromProto)
|
|
1291
|
+
self.table = options.table
|
|
1292
|
+
self.database = options.database
|
|
1293
|
+
self.IDBKeyRange = options.IDBKeyRange
|
|
1294
|
+
self.transaction = options.transaction
|
|
1295
|
+
self.reactivity = options.reactivity
|
|
1296
|
+
return self
|
|
1297
|
+
}
|
|
1298
|
+
|
|
1299
|
+
const DeletePartialProto: Omit<
|
|
1300
|
+
IndexedDbQuery.DeletePartial<any, never>,
|
|
1301
|
+
| "from"
|
|
1302
|
+
| "index"
|
|
1303
|
+
> = {
|
|
1304
|
+
...CommonProto,
|
|
1305
|
+
limit(this: IndexedDbQuery.DeletePartial<any, never>, limit: number) {
|
|
1306
|
+
return makeDelete({
|
|
1307
|
+
delete: this as any,
|
|
1308
|
+
limitValue: limit
|
|
1309
|
+
})
|
|
1310
|
+
},
|
|
1311
|
+
equals(this: IndexedDbQuery.DeletePartial<any, never>, value: IndexedDbQuery.ExtractIndexType<any, never>) {
|
|
1312
|
+
return makeDelete({
|
|
1313
|
+
delete: this as any,
|
|
1314
|
+
only: value
|
|
1315
|
+
})
|
|
1316
|
+
},
|
|
1317
|
+
gte(this: IndexedDbQuery.DeletePartial<any, never>, value: IndexedDbQuery.ExtractIndexType<any, never>) {
|
|
1318
|
+
return makeDelete({
|
|
1319
|
+
delete: this as any,
|
|
1320
|
+
lowerBound: value,
|
|
1321
|
+
excludeLowerBound: false
|
|
1322
|
+
})
|
|
1323
|
+
},
|
|
1324
|
+
lte(this: IndexedDbQuery.DeletePartial<any, never>, value: IndexedDbQuery.ExtractIndexType<any, never>) {
|
|
1325
|
+
return makeDelete({
|
|
1326
|
+
delete: this as any,
|
|
1327
|
+
upperBound: value,
|
|
1328
|
+
excludeUpperBound: false
|
|
1329
|
+
})
|
|
1330
|
+
},
|
|
1331
|
+
gt(this: IndexedDbQuery.DeletePartial<any, never>, value: IndexedDbQuery.ExtractIndexType<any, never>) {
|
|
1332
|
+
return makeDelete({
|
|
1333
|
+
delete: this as any,
|
|
1334
|
+
lowerBound: value,
|
|
1335
|
+
excludeLowerBound: true
|
|
1336
|
+
})
|
|
1337
|
+
},
|
|
1338
|
+
lt(this: IndexedDbQuery.DeletePartial<any, never>, value: IndexedDbQuery.ExtractIndexType<any, never>) {
|
|
1339
|
+
return makeDelete({
|
|
1340
|
+
delete: this as any,
|
|
1341
|
+
upperBound: value,
|
|
1342
|
+
excludeUpperBound: true
|
|
1343
|
+
})
|
|
1344
|
+
},
|
|
1345
|
+
between(
|
|
1346
|
+
this: IndexedDbQuery.DeletePartial<any, never>,
|
|
1347
|
+
lowerBound: IndexedDbQuery.ExtractIndexType<any, never>,
|
|
1348
|
+
upperBound: IndexedDbQuery.ExtractIndexType<any, never>,
|
|
1349
|
+
queryOptions?: { excludeLowerBound?: boolean; excludeUpperBound?: boolean }
|
|
1350
|
+
) {
|
|
1351
|
+
return makeDelete({
|
|
1352
|
+
delete: this as any,
|
|
1353
|
+
lowerBound,
|
|
1354
|
+
upperBound,
|
|
1355
|
+
excludeLowerBound: queryOptions?.excludeLowerBound ?? false,
|
|
1356
|
+
excludeUpperBound: queryOptions?.excludeUpperBound ?? false
|
|
1357
|
+
})
|
|
1358
|
+
}
|
|
1359
|
+
}
|
|
1360
|
+
|
|
1361
|
+
const makeDeletePartial = <
|
|
1362
|
+
Table extends IndexedDbTable.AnyWithProps,
|
|
1363
|
+
Index extends IndexedDbDatabase.IndexFromTable<Table>
|
|
1364
|
+
>(options: {
|
|
1365
|
+
readonly from: IndexedDbQuery.From<Table>
|
|
1366
|
+
readonly index: Index | undefined
|
|
1367
|
+
}): IndexedDbQuery.DeletePartial<Table, Index> => {
|
|
1368
|
+
const self = Object.create(DeletePartialProto)
|
|
1369
|
+
self.from = options.from
|
|
1370
|
+
self.index = options.index
|
|
1371
|
+
return self as any
|
|
1372
|
+
}
|
|
1373
|
+
|
|
1374
|
+
const DeleteProto: Omit<
|
|
1375
|
+
IndexedDbQuery.Delete<any, never>,
|
|
1376
|
+
| "delete"
|
|
1377
|
+
| "limitValue"
|
|
1378
|
+
| "only"
|
|
1379
|
+
| "lowerBound"
|
|
1380
|
+
| "upperBound"
|
|
1381
|
+
| "excludeLowerBound"
|
|
1382
|
+
| "excludeUpperBound"
|
|
1383
|
+
| "predicate"
|
|
1384
|
+
> = {
|
|
1385
|
+
...CommonProto,
|
|
1386
|
+
asEffect(this: IndexedDbQuery.Delete<any, never>) {
|
|
1387
|
+
return applyDelete(this) as any
|
|
1388
|
+
},
|
|
1389
|
+
limit(this: IndexedDbQuery.Delete<any, never>, limit: number) {
|
|
1390
|
+
return makeDelete({
|
|
1391
|
+
delete: this.delete,
|
|
1392
|
+
only: this.only,
|
|
1393
|
+
lowerBound: this.lowerBound,
|
|
1394
|
+
upperBound: this.upperBound,
|
|
1395
|
+
excludeLowerBound: this.excludeLowerBound ?? false,
|
|
1396
|
+
excludeUpperBound: this.excludeUpperBound ?? false,
|
|
1397
|
+
limitValue: limit
|
|
1398
|
+
})
|
|
1399
|
+
},
|
|
1400
|
+
equals(this: IndexedDbQuery.Delete<any, never>, value: IndexedDbQuery.ExtractIndexType<any, never>) {
|
|
1401
|
+
return makeDelete({
|
|
1402
|
+
delete: this.delete,
|
|
1403
|
+
only: value,
|
|
1404
|
+
limitValue: this.limitValue
|
|
1405
|
+
})
|
|
1406
|
+
},
|
|
1407
|
+
gte(this: IndexedDbQuery.Delete<any, never>, value: IndexedDbQuery.ExtractIndexType<any, never>) {
|
|
1408
|
+
return makeDelete({
|
|
1409
|
+
delete: this.delete,
|
|
1410
|
+
lowerBound: value,
|
|
1411
|
+
excludeLowerBound: false,
|
|
1412
|
+
limitValue: this.limitValue
|
|
1413
|
+
})
|
|
1414
|
+
},
|
|
1415
|
+
lte(this: IndexedDbQuery.Delete<any, never>, value: IndexedDbQuery.ExtractIndexType<any, never>) {
|
|
1416
|
+
return makeDelete({
|
|
1417
|
+
delete: this.delete,
|
|
1418
|
+
upperBound: value,
|
|
1419
|
+
excludeUpperBound: false,
|
|
1420
|
+
limitValue: this.limitValue
|
|
1421
|
+
})
|
|
1422
|
+
},
|
|
1423
|
+
gt(this: IndexedDbQuery.Delete<any, never>, value: IndexedDbQuery.ExtractIndexType<any, never>) {
|
|
1424
|
+
return makeDelete({
|
|
1425
|
+
delete: this.delete,
|
|
1426
|
+
lowerBound: value,
|
|
1427
|
+
excludeLowerBound: true,
|
|
1428
|
+
limitValue: this.limitValue
|
|
1429
|
+
})
|
|
1430
|
+
},
|
|
1431
|
+
lt(this: IndexedDbQuery.Delete<any, never>, value: IndexedDbQuery.ExtractIndexType<any, never>) {
|
|
1432
|
+
return makeDelete({
|
|
1433
|
+
delete: this.delete,
|
|
1434
|
+
upperBound: value,
|
|
1435
|
+
excludeUpperBound: true,
|
|
1436
|
+
limitValue: this.limitValue
|
|
1437
|
+
})
|
|
1438
|
+
},
|
|
1439
|
+
between(
|
|
1440
|
+
this: IndexedDbQuery.Delete<any, never>,
|
|
1441
|
+
lowerBound: IndexedDbQuery.ExtractIndexType<any, never>,
|
|
1442
|
+
upperBound: IndexedDbQuery.ExtractIndexType<any, never>,
|
|
1443
|
+
queryOptions?: { excludeLowerBound?: boolean; excludeUpperBound?: boolean }
|
|
1444
|
+
) {
|
|
1445
|
+
return makeDelete({
|
|
1446
|
+
delete: this.delete,
|
|
1447
|
+
lowerBound,
|
|
1448
|
+
upperBound,
|
|
1449
|
+
excludeLowerBound: queryOptions?.excludeLowerBound ?? false,
|
|
1450
|
+
excludeUpperBound: queryOptions?.excludeUpperBound ?? false,
|
|
1451
|
+
limitValue: this.limitValue
|
|
1452
|
+
})
|
|
1453
|
+
},
|
|
1454
|
+
filter(this: IndexedDbQuery.Delete<any, never>, filter: (value: IndexedDbTable.Encoded<any>) => boolean) {
|
|
1455
|
+
const prev = this.predicate
|
|
1456
|
+
return makeDelete({
|
|
1457
|
+
delete: this.delete,
|
|
1458
|
+
predicate: prev ? (item) => prev(item) && filter(item) : filter
|
|
1459
|
+
})
|
|
1460
|
+
},
|
|
1461
|
+
invalidate(
|
|
1462
|
+
this: IndexedDbQuery.Delete<any, never>,
|
|
1463
|
+
keys: ReadonlyArray<unknown> | Record.ReadonlyRecord<string, ReadonlyArray<unknown>>
|
|
1464
|
+
) {
|
|
1465
|
+
return this.delete.from.reactivity.mutation(keys, this.asEffect())
|
|
1466
|
+
}
|
|
1467
|
+
}
|
|
1468
|
+
|
|
1469
|
+
const makeDelete = <
|
|
1470
|
+
Table extends IndexedDbTable.AnyWithProps,
|
|
1471
|
+
Index extends IndexedDbDatabase.IndexFromTable<Table>
|
|
1472
|
+
>(options: {
|
|
1473
|
+
readonly delete: IndexedDbQuery.DeletePartial<Table, Index>
|
|
1474
|
+
readonly limitValue?: number | undefined
|
|
1475
|
+
readonly only?: IndexedDbQuery.ExtractIndexType<Table, Index> | undefined
|
|
1476
|
+
readonly lowerBound?:
|
|
1477
|
+
| IndexedDbQuery.ExtractIndexType<Table, Index>
|
|
1478
|
+
| undefined
|
|
1479
|
+
readonly upperBound?:
|
|
1480
|
+
| IndexedDbQuery.ExtractIndexType<Table, Index>
|
|
1481
|
+
| undefined
|
|
1482
|
+
readonly excludeLowerBound?: boolean | undefined
|
|
1483
|
+
readonly excludeUpperBound?: boolean | undefined
|
|
1484
|
+
readonly predicate?: ((item: IndexedDbTable.Encoded<Table>) => boolean) | undefined
|
|
1485
|
+
}): IndexedDbQuery.Delete<Table, Index> => {
|
|
1486
|
+
const self = Object.create(DeleteProto)
|
|
1487
|
+
self.delete = options.delete
|
|
1488
|
+
self.limitValue = options.limitValue
|
|
1489
|
+
self.only = options.only
|
|
1490
|
+
self.lowerBound = options.lowerBound
|
|
1491
|
+
self.upperBound = options.upperBound
|
|
1492
|
+
self.excludeLowerBound = options.excludeLowerBound
|
|
1493
|
+
self.excludeUpperBound = options.excludeUpperBound
|
|
1494
|
+
self.predicate = options.predicate
|
|
1495
|
+
return self
|
|
1496
|
+
}
|
|
1497
|
+
|
|
1498
|
+
const CountProto: Omit<
|
|
1499
|
+
IndexedDbQuery.Count<any, never>,
|
|
1500
|
+
| "from"
|
|
1501
|
+
| "index"
|
|
1502
|
+
| "only"
|
|
1503
|
+
| "lowerBound"
|
|
1504
|
+
| "upperBound"
|
|
1505
|
+
| "excludeLowerBound"
|
|
1506
|
+
| "excludeUpperBound"
|
|
1507
|
+
> = {
|
|
1508
|
+
...CommonProto,
|
|
1509
|
+
asEffect(this: IndexedDbQuery.Count<any, never>) {
|
|
1510
|
+
return getCount(this) as any
|
|
1511
|
+
},
|
|
1512
|
+
equals(this: IndexedDbQuery.Count<any, never>, value: IndexedDbQuery.ExtractIndexType<any, never>) {
|
|
1513
|
+
return makeCount({
|
|
1514
|
+
from: this.from,
|
|
1515
|
+
index: this.index,
|
|
1516
|
+
only: value,
|
|
1517
|
+
limitValue: this.limitValue
|
|
1518
|
+
})
|
|
1519
|
+
},
|
|
1520
|
+
gte(this: IndexedDbQuery.Count<any, never>, value: IndexedDbQuery.ExtractIndexType<any, never>) {
|
|
1521
|
+
return makeCount({
|
|
1522
|
+
from: this.from,
|
|
1523
|
+
index: this.index,
|
|
1524
|
+
lowerBound: value,
|
|
1525
|
+
excludeLowerBound: false,
|
|
1526
|
+
limitValue: this.limitValue
|
|
1527
|
+
})
|
|
1528
|
+
},
|
|
1529
|
+
lte(this: IndexedDbQuery.Count<any, never>, value: IndexedDbQuery.ExtractIndexType<any, never>) {
|
|
1530
|
+
return makeCount({
|
|
1531
|
+
from: this.from,
|
|
1532
|
+
index: this.index,
|
|
1533
|
+
upperBound: value,
|
|
1534
|
+
excludeUpperBound: false,
|
|
1535
|
+
limitValue: this.limitValue
|
|
1536
|
+
})
|
|
1537
|
+
},
|
|
1538
|
+
gt(this: IndexedDbQuery.Count<any, never>, value: IndexedDbQuery.ExtractIndexType<any, never>) {
|
|
1539
|
+
return makeCount({
|
|
1540
|
+
from: this.from,
|
|
1541
|
+
index: this.index,
|
|
1542
|
+
lowerBound: value,
|
|
1543
|
+
excludeLowerBound: true,
|
|
1544
|
+
limitValue: this.limitValue
|
|
1545
|
+
})
|
|
1546
|
+
},
|
|
1547
|
+
lt(this: IndexedDbQuery.Count<any, never>, value: IndexedDbQuery.ExtractIndexType<any, never>) {
|
|
1548
|
+
return makeCount({
|
|
1549
|
+
from: this.from,
|
|
1550
|
+
index: this.index,
|
|
1551
|
+
upperBound: value,
|
|
1552
|
+
excludeUpperBound: true,
|
|
1553
|
+
limitValue: this.limitValue
|
|
1554
|
+
})
|
|
1555
|
+
},
|
|
1556
|
+
between(
|
|
1557
|
+
this: IndexedDbQuery.Count<any, never>,
|
|
1558
|
+
lowerBound: IndexedDbQuery.ExtractIndexType<any, never>,
|
|
1559
|
+
upperBound: IndexedDbQuery.ExtractIndexType<any, never>,
|
|
1560
|
+
queryOptions?: { excludeLowerBound?: boolean; excludeUpperBound?: boolean }
|
|
1561
|
+
) {
|
|
1562
|
+
return makeCount({
|
|
1563
|
+
from: this.from,
|
|
1564
|
+
index: this.index,
|
|
1565
|
+
lowerBound,
|
|
1566
|
+
upperBound,
|
|
1567
|
+
excludeLowerBound: queryOptions?.excludeLowerBound ?? false,
|
|
1568
|
+
excludeUpperBound: queryOptions?.excludeUpperBound ?? false,
|
|
1569
|
+
limitValue: this.limitValue
|
|
1570
|
+
})
|
|
1571
|
+
}
|
|
1572
|
+
}
|
|
1573
|
+
|
|
1574
|
+
const makeCount = <
|
|
1575
|
+
Table extends IndexedDbTable.AnyWithProps,
|
|
1576
|
+
Index extends IndexedDbDatabase.IndexFromTable<Table>
|
|
1577
|
+
>(options: {
|
|
1578
|
+
readonly from: IndexedDbQuery.From<Table>
|
|
1579
|
+
readonly index: Index | undefined
|
|
1580
|
+
readonly limitValue?: number | undefined
|
|
1581
|
+
readonly only?: IndexedDbQuery.ExtractIndexType<Table, Index> | undefined
|
|
1582
|
+
readonly lowerBound?:
|
|
1583
|
+
| IndexedDbQuery.ExtractIndexType<Table, Index>
|
|
1584
|
+
| undefined
|
|
1585
|
+
readonly upperBound?:
|
|
1586
|
+
| IndexedDbQuery.ExtractIndexType<Table, Index>
|
|
1587
|
+
| undefined
|
|
1588
|
+
readonly excludeLowerBound?: boolean | undefined
|
|
1589
|
+
readonly excludeUpperBound?: boolean | undefined
|
|
1590
|
+
}): IndexedDbQuery.Count<Table, Index> => {
|
|
1591
|
+
const self = Object.create(CountProto)
|
|
1592
|
+
self.from = options.from
|
|
1593
|
+
self.index = options.index
|
|
1594
|
+
self.only = options.only
|
|
1595
|
+
self.limitValue = options.limitValue
|
|
1596
|
+
self.lowerBound = options.lowerBound
|
|
1597
|
+
self.upperBound = options.upperBound
|
|
1598
|
+
self.excludeLowerBound = options.excludeLowerBound
|
|
1599
|
+
self.excludeUpperBound = options.excludeUpperBound
|
|
1600
|
+
return self
|
|
1601
|
+
}
|
|
1602
|
+
|
|
1603
|
+
const SelectProto: Omit<
|
|
1604
|
+
IndexedDbQuery.Select<any, never>,
|
|
1605
|
+
| "from"
|
|
1606
|
+
| "index"
|
|
1607
|
+
| "limitValue"
|
|
1608
|
+
| "only"
|
|
1609
|
+
| "lowerBound"
|
|
1610
|
+
| "upperBound"
|
|
1611
|
+
| "excludeLowerBound"
|
|
1612
|
+
| "excludeUpperBound"
|
|
1613
|
+
> = {
|
|
1614
|
+
...CommonProto,
|
|
1615
|
+
limit(this: IndexedDbQuery.Select<any, never>, limit: number) {
|
|
1616
|
+
return makeSelect({
|
|
1617
|
+
...this,
|
|
1618
|
+
limitValue: limit
|
|
1619
|
+
})
|
|
1620
|
+
},
|
|
1621
|
+
equals(this: IndexedDbQuery.Select<any, never>, value: IndexedDbQuery.ExtractIndexType<any, never>) {
|
|
1622
|
+
return makeSelect({
|
|
1623
|
+
...this,
|
|
1624
|
+
only: value
|
|
1625
|
+
})
|
|
1626
|
+
},
|
|
1627
|
+
gte(this: IndexedDbQuery.Select<any, never>, value: IndexedDbQuery.ExtractIndexType<any, never>) {
|
|
1628
|
+
return makeSelect({
|
|
1629
|
+
...this,
|
|
1630
|
+
lowerBound: value,
|
|
1631
|
+
excludeLowerBound: false
|
|
1632
|
+
})
|
|
1633
|
+
},
|
|
1634
|
+
lte(this: IndexedDbQuery.Select<any, never>, value: IndexedDbQuery.ExtractIndexType<any, never>) {
|
|
1635
|
+
return makeSelect({
|
|
1636
|
+
...this,
|
|
1637
|
+
upperBound: value,
|
|
1638
|
+
excludeUpperBound: false
|
|
1639
|
+
})
|
|
1640
|
+
},
|
|
1641
|
+
gt(this: IndexedDbQuery.Select<any, never>, value: IndexedDbQuery.ExtractIndexType<any, never>) {
|
|
1642
|
+
return makeSelect({
|
|
1643
|
+
...this,
|
|
1644
|
+
lowerBound: value,
|
|
1645
|
+
excludeLowerBound: true
|
|
1646
|
+
})
|
|
1647
|
+
},
|
|
1648
|
+
lt(this: IndexedDbQuery.Select<any, never>, value: IndexedDbQuery.ExtractIndexType<any, never>) {
|
|
1649
|
+
return makeSelect({
|
|
1650
|
+
...this,
|
|
1651
|
+
upperBound: value,
|
|
1652
|
+
excludeUpperBound: true
|
|
1653
|
+
})
|
|
1654
|
+
},
|
|
1655
|
+
between(
|
|
1656
|
+
this: IndexedDbQuery.Select<any, never>,
|
|
1657
|
+
lowerBound: IndexedDbQuery.ExtractIndexType<any, never>,
|
|
1658
|
+
upperBound: IndexedDbQuery.ExtractIndexType<any, never>,
|
|
1659
|
+
queryOptions?: { excludeLowerBound?: boolean; excludeUpperBound?: boolean }
|
|
1660
|
+
) {
|
|
1661
|
+
return makeSelect({
|
|
1662
|
+
...this,
|
|
1663
|
+
lowerBound,
|
|
1664
|
+
upperBound,
|
|
1665
|
+
excludeLowerBound: queryOptions?.excludeLowerBound ?? false,
|
|
1666
|
+
excludeUpperBound: queryOptions?.excludeUpperBound ?? false
|
|
1667
|
+
})
|
|
1668
|
+
},
|
|
1669
|
+
first(this: IndexedDbQuery.Select<any, never>) {
|
|
1670
|
+
return makeFirst({ select: this })
|
|
1671
|
+
},
|
|
1672
|
+
filter(this: IndexedDbQuery.Select<any, never>, filter: (value: IndexedDbTable.Encoded<any>) => boolean) {
|
|
1673
|
+
const prev = this.predicate
|
|
1674
|
+
return makeSelect({
|
|
1675
|
+
...this,
|
|
1676
|
+
predicate: prev ? (item) => prev(item) && filter(item) : filter
|
|
1677
|
+
})
|
|
1678
|
+
},
|
|
1679
|
+
asEffect(this: IndexedDbQuery.Select<any, never>) {
|
|
1680
|
+
return getSelect(this) as any
|
|
1681
|
+
},
|
|
1682
|
+
reactive(
|
|
1683
|
+
this: IndexedDbQuery.Select<any, never>,
|
|
1684
|
+
keys: ReadonlyArray<unknown> | Record.ReadonlyRecord<string, ReadonlyArray<unknown>>
|
|
1685
|
+
) {
|
|
1686
|
+
return this.from.reactivity.stream(keys, this.asEffect())
|
|
1687
|
+
},
|
|
1688
|
+
reactiveQueue(
|
|
1689
|
+
this: IndexedDbQuery.Select<any, never>,
|
|
1690
|
+
keys: ReadonlyArray<unknown> | Record.ReadonlyRecord<string, ReadonlyArray<unknown>>
|
|
1691
|
+
) {
|
|
1692
|
+
return this.from.reactivity.query(keys, this.asEffect())
|
|
1693
|
+
}
|
|
1694
|
+
}
|
|
1695
|
+
|
|
1696
|
+
const makeSelect = <
|
|
1697
|
+
Table extends IndexedDbTable.AnyWithProps,
|
|
1698
|
+
Index extends IndexedDbDatabase.IndexFromTable<Table>
|
|
1699
|
+
>(options: {
|
|
1700
|
+
readonly from: IndexedDbQuery.From<Table>
|
|
1701
|
+
readonly index?: Index | undefined
|
|
1702
|
+
readonly limitValue?: number | undefined
|
|
1703
|
+
readonly only?: IndexedDbQuery.ExtractIndexType<Table, Index> | undefined
|
|
1704
|
+
readonly lowerBound?:
|
|
1705
|
+
| IndexedDbQuery.ExtractIndexType<Table, Index>
|
|
1706
|
+
| undefined
|
|
1707
|
+
readonly upperBound?:
|
|
1708
|
+
| IndexedDbQuery.ExtractIndexType<Table, Index>
|
|
1709
|
+
| undefined
|
|
1710
|
+
readonly excludeLowerBound?: boolean | undefined
|
|
1711
|
+
readonly excludeUpperBound?: boolean | undefined
|
|
1712
|
+
readonly predicate?: ((item: IndexedDbTable.Encoded<Table>) => boolean) | undefined
|
|
1713
|
+
}): IndexedDbQuery.Select<Table, Index> => {
|
|
1714
|
+
const self = Object.create(SelectProto)
|
|
1715
|
+
self.from = options.from
|
|
1716
|
+
self.index = options.index
|
|
1717
|
+
self.only = options.only
|
|
1718
|
+
self.limitValue = options.limitValue
|
|
1719
|
+
self.lowerBound = options.lowerBound
|
|
1720
|
+
self.upperBound = options.upperBound
|
|
1721
|
+
self.excludeLowerBound = options.excludeLowerBound
|
|
1722
|
+
self.excludeUpperBound = options.excludeUpperBound
|
|
1723
|
+
self.predicate = options.predicate
|
|
1724
|
+
return self as any
|
|
1725
|
+
}
|
|
1726
|
+
|
|
1727
|
+
const FirstProto: Omit<
|
|
1728
|
+
IndexedDbQuery.First<any, never>,
|
|
1729
|
+
"select"
|
|
1730
|
+
> = {
|
|
1731
|
+
...CommonProto,
|
|
1732
|
+
asEffect(this: IndexedDbQuery.First<any, never>) {
|
|
1733
|
+
return getFirst(this) as any
|
|
1734
|
+
}
|
|
1735
|
+
}
|
|
1736
|
+
|
|
1737
|
+
const makeFirst = <
|
|
1738
|
+
Table extends IndexedDbTable.AnyWithProps,
|
|
1739
|
+
Index extends IndexedDbDatabase.IndexFromTable<Table>
|
|
1740
|
+
>(options: {
|
|
1741
|
+
readonly select: IndexedDbQuery.Select<Table, Index>
|
|
1742
|
+
}): IndexedDbQuery.First<Table, Index> => {
|
|
1743
|
+
const self = Object.create(FirstProto)
|
|
1744
|
+
self.select = options.select
|
|
1745
|
+
return self as any
|
|
1746
|
+
}
|
|
1747
|
+
|
|
1748
|
+
const ModifyProto: Omit<
|
|
1749
|
+
IndexedDbQuery.Modify<any>,
|
|
1750
|
+
| "from"
|
|
1751
|
+
| "value"
|
|
1752
|
+
| "operation"
|
|
1753
|
+
> = {
|
|
1754
|
+
...CommonProto,
|
|
1755
|
+
asEffect(this: IndexedDbQuery.Modify<any>) {
|
|
1756
|
+
return applyModify({ query: this, value: this.value }) as any
|
|
1757
|
+
},
|
|
1758
|
+
invalidate(
|
|
1759
|
+
this: IndexedDbQuery.Modify<any>,
|
|
1760
|
+
keys: ReadonlyArray<unknown> | Record.ReadonlyRecord<string, ReadonlyArray<unknown>>
|
|
1761
|
+
) {
|
|
1762
|
+
return this.from.reactivity.mutation(keys, this.asEffect())
|
|
1763
|
+
}
|
|
1764
|
+
}
|
|
1765
|
+
|
|
1766
|
+
const makeModify = <Table extends IndexedDbTable.AnyWithProps>(options: {
|
|
1767
|
+
readonly from: IndexedDbQuery.From<Table>
|
|
1768
|
+
readonly value: IndexedDbTable.TableSchema<Table>["Type"]
|
|
1769
|
+
readonly operation: "add" | "put"
|
|
1770
|
+
}): IndexedDbQuery.Modify<Table> => {
|
|
1771
|
+
const self = Object.create(ModifyProto)
|
|
1772
|
+
self.from = options.from
|
|
1773
|
+
self.value = options.value
|
|
1774
|
+
self.operation = options.operation
|
|
1775
|
+
return self as any
|
|
1776
|
+
}
|
|
1777
|
+
|
|
1778
|
+
const ModifyAllProto: Omit<
|
|
1779
|
+
IndexedDbQuery.ModifyAll<any>,
|
|
1780
|
+
| "from"
|
|
1781
|
+
| "values"
|
|
1782
|
+
| "operation"
|
|
1783
|
+
> = {
|
|
1784
|
+
...CommonProto,
|
|
1785
|
+
asEffect(this: IndexedDbQuery.ModifyAll<any>) {
|
|
1786
|
+
return applyModifyAll({ query: this, values: this.values }) as any
|
|
1787
|
+
},
|
|
1788
|
+
invalidate(
|
|
1789
|
+
this: IndexedDbQuery.ModifyAll<any>,
|
|
1790
|
+
keys: ReadonlyArray<unknown> | Record.ReadonlyRecord<string, ReadonlyArray<unknown>>
|
|
1791
|
+
) {
|
|
1792
|
+
return this.from.reactivity.mutation(keys, this.asEffect())
|
|
1793
|
+
}
|
|
1794
|
+
}
|
|
1795
|
+
|
|
1796
|
+
const makeModifyAll = <
|
|
1797
|
+
Table extends IndexedDbTable.AnyWithProps
|
|
1798
|
+
>(options: {
|
|
1799
|
+
readonly from: IndexedDbQuery.From<Table>
|
|
1800
|
+
readonly values: Array<IndexedDbTable.TableSchema<Table>["Type"]>
|
|
1801
|
+
readonly operation: "add" | "put"
|
|
1802
|
+
}): IndexedDbQuery.ModifyAll<Table> => {
|
|
1803
|
+
const self = Object.create(ModifyAllProto)
|
|
1804
|
+
self.from = options.from
|
|
1805
|
+
self.values = options.values
|
|
1806
|
+
self.operation = options.operation
|
|
1807
|
+
return self as any
|
|
1808
|
+
}
|
|
1809
|
+
|
|
1810
|
+
const QueryBuilderProto: Omit<
|
|
1811
|
+
IndexedDbQueryBuilder<any>,
|
|
1812
|
+
| "tables"
|
|
1813
|
+
| "database"
|
|
1814
|
+
| "IDBKeyRange"
|
|
1815
|
+
| "IDBTransaction"
|
|
1816
|
+
| "reactivity"
|
|
1817
|
+
> = {
|
|
1818
|
+
...CommonProto,
|
|
1819
|
+
use(this: IndexedDbQueryBuilder<any>, f: (database: globalThis.IDBDatabase) => Promise<any>) {
|
|
1820
|
+
return Effect.tryPromise({
|
|
1821
|
+
try: () => f(this.database),
|
|
1822
|
+
catch: (error) =>
|
|
1823
|
+
new IndexedDbQueryError({
|
|
1824
|
+
reason: "UnknownError",
|
|
1825
|
+
cause: error
|
|
1826
|
+
})
|
|
1827
|
+
})
|
|
1828
|
+
},
|
|
1829
|
+
from(this: IndexedDbQueryBuilder<any>, table: any) {
|
|
1830
|
+
return makeFrom({
|
|
1831
|
+
database: this.database,
|
|
1832
|
+
IDBKeyRange: this.IDBKeyRange,
|
|
1833
|
+
table: this.tables.get(table)!,
|
|
1834
|
+
transaction: this.IDBTransaction,
|
|
1835
|
+
reactivity: this.reactivity
|
|
1836
|
+
}) as any
|
|
1837
|
+
},
|
|
1838
|
+
get clearAll() {
|
|
1839
|
+
const self = this as IndexedDbQueryBuilder<any>
|
|
1840
|
+
return applyClearAll({ database: self.database, transaction: self.IDBTransaction })
|
|
1841
|
+
},
|
|
1842
|
+
transaction: Effect.fnUntraced(function*<E, R>(
|
|
1843
|
+
this: IndexedDbQueryBuilder<any>,
|
|
1844
|
+
transactionTables: Array<
|
|
1845
|
+
IndexedDbTable.TableName<IndexedDbVersion.Tables<any>>
|
|
1846
|
+
>,
|
|
1847
|
+
mode: globalThis.IDBTransactionMode,
|
|
1848
|
+
callback: (api: {
|
|
1849
|
+
readonly from: <
|
|
1850
|
+
Name extends IndexedDbTable.TableName<IndexedDbVersion.Tables<any>>
|
|
1851
|
+
>(
|
|
1852
|
+
table: Name
|
|
1853
|
+
) => IndexedDbQuery.From<IndexedDbVersion.TableWithName<any, Name>>
|
|
1854
|
+
}) => Effect.Effect<void, E, R>,
|
|
1855
|
+
options?: globalThis.IDBTransactionOptions
|
|
1856
|
+
) {
|
|
1857
|
+
const transaction = this.database.transaction(transactionTables, mode, options)
|
|
1858
|
+
return yield* callback({
|
|
1859
|
+
from: (table) =>
|
|
1860
|
+
makeFrom({
|
|
1861
|
+
database: this.database,
|
|
1862
|
+
IDBKeyRange: this.IDBKeyRange,
|
|
1863
|
+
table: this.tables.get(table) as any,
|
|
1864
|
+
transaction,
|
|
1865
|
+
reactivity: this.reactivity
|
|
1866
|
+
})
|
|
1867
|
+
})
|
|
1868
|
+
}) as any
|
|
1869
|
+
}
|
|
1870
|
+
|
|
1871
|
+
/**
|
|
1872
|
+
* @since 4.0.0
|
|
1873
|
+
* @category constructors
|
|
1874
|
+
*/
|
|
1875
|
+
export const make = <Source extends IndexedDbVersion.AnyWithProps>({
|
|
1876
|
+
IDBKeyRange,
|
|
1877
|
+
database,
|
|
1878
|
+
tables,
|
|
1879
|
+
transaction,
|
|
1880
|
+
reactivity
|
|
1881
|
+
}: {
|
|
1882
|
+
readonly database: globalThis.IDBDatabase
|
|
1883
|
+
readonly IDBKeyRange: typeof globalThis.IDBKeyRange
|
|
1884
|
+
readonly tables: ReadonlyMap<string, IndexedDbVersion.Tables<Source>>
|
|
1885
|
+
readonly transaction: globalThis.IDBTransaction | undefined
|
|
1886
|
+
readonly reactivity: Reactivity.Reactivity["Service"]
|
|
1887
|
+
}): IndexedDbQueryBuilder<Source> => {
|
|
1888
|
+
const self = Object.create(QueryBuilderProto)
|
|
1889
|
+
self.tables = tables
|
|
1890
|
+
self.database = database
|
|
1891
|
+
self.reactivity = reactivity
|
|
1892
|
+
self.IDBKeyRange = IDBKeyRange
|
|
1893
|
+
self.IDBTransaction = transaction
|
|
1894
|
+
return self
|
|
1895
|
+
}
|