@tanstack/db 0.5.8 → 0.5.10
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/cjs/collection/index.cjs.map +1 -1
- package/dist/cjs/collection/index.d.cts +18 -6
- package/dist/cjs/collection/mutations.cjs +3 -1
- package/dist/cjs/collection/mutations.cjs.map +1 -1
- package/dist/cjs/indexes/base-index.cjs.map +1 -1
- package/dist/cjs/indexes/reverse-index.cjs.map +1 -1
- package/dist/cjs/local-only.cjs.map +1 -1
- package/dist/cjs/proxy.cjs +26 -15
- package/dist/cjs/proxy.cjs.map +1 -1
- package/dist/esm/collection/index.d.ts +18 -6
- package/dist/esm/collection/index.js.map +1 -1
- package/dist/esm/collection/mutations.js +3 -1
- package/dist/esm/collection/mutations.js.map +1 -1
- package/dist/esm/indexes/base-index.js.map +1 -1
- package/dist/esm/indexes/reverse-index.js.map +1 -1
- package/dist/esm/local-only.js.map +1 -1
- package/dist/esm/proxy.js +26 -15
- package/dist/esm/proxy.js.map +1 -1
- package/package.json +2 -2
- package/src/collection/index.ts +75 -12
- package/src/collection/mutations.ts +4 -2
- package/src/indexes/base-index.ts +3 -3
- package/src/indexes/reverse-index.ts +3 -3
- package/src/local-only.ts +3 -3
- package/src/proxy.ts +49 -34
- package/src/query/builder/types.ts +5 -5
- package/src/types.ts +7 -5
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanstack/db",
|
|
3
3
|
"description": "A reactive client store for building super fast apps on sync",
|
|
4
|
-
"version": "0.5.
|
|
4
|
+
"version": "0.5.10",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@standard-schema/spec": "^1.0.0",
|
|
7
7
|
"@tanstack/pacer-lite": "^0.1.0",
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"devDependencies": {
|
|
11
11
|
"@vitest/coverage-istanbul": "^3.2.4",
|
|
12
12
|
"arktype": "^2.1.27",
|
|
13
|
-
"superjson": "^2.2.
|
|
13
|
+
"superjson": "^2.2.6",
|
|
14
14
|
"temporal-polyfill": "^0.3.0"
|
|
15
15
|
},
|
|
16
16
|
"exports": {
|
package/src/collection/index.ts
CHANGED
|
@@ -127,32 +127,85 @@ export interface Collection<
|
|
|
127
127
|
*
|
|
128
128
|
*/
|
|
129
129
|
|
|
130
|
-
// Overload for when schema is provided
|
|
130
|
+
// Overload for when schema is provided and utils is required (not optional)
|
|
131
|
+
// We can't infer the Utils type from the CollectionConfig because it will always be optional
|
|
132
|
+
// So we omit it from that type and instead infer it from the extension `& { utils: TUtils }`
|
|
133
|
+
// such that we have the real, non-optional Utils type
|
|
131
134
|
export function createCollection<
|
|
132
135
|
T extends StandardSchemaV1,
|
|
133
|
-
TKey extends string | number
|
|
134
|
-
TUtils extends UtilsRecord
|
|
136
|
+
TKey extends string | number,
|
|
137
|
+
TUtils extends UtilsRecord,
|
|
135
138
|
>(
|
|
136
|
-
options:
|
|
139
|
+
options: Omit<
|
|
140
|
+
CollectionConfig<InferSchemaOutput<T>, TKey, T, TUtils>,
|
|
141
|
+
`utils`
|
|
142
|
+
> & {
|
|
137
143
|
schema: T
|
|
138
|
-
utils
|
|
144
|
+
utils: TUtils // Required utils
|
|
139
145
|
} & NonSingleResult
|
|
140
146
|
): Collection<InferSchemaOutput<T>, TKey, TUtils, T, InferSchemaInput<T>> &
|
|
141
147
|
NonSingleResult
|
|
142
148
|
|
|
149
|
+
// Overload for when schema is provided and utils is optional
|
|
150
|
+
// In this case we can simply infer the Utils type from the CollectionConfig type
|
|
151
|
+
export function createCollection<
|
|
152
|
+
T extends StandardSchemaV1,
|
|
153
|
+
TKey extends string | number,
|
|
154
|
+
TUtils extends UtilsRecord,
|
|
155
|
+
>(
|
|
156
|
+
options: CollectionConfig<InferSchemaOutput<T>, TKey, T, TUtils> & {
|
|
157
|
+
schema: T
|
|
158
|
+
} & NonSingleResult
|
|
159
|
+
): Collection<
|
|
160
|
+
InferSchemaOutput<T>,
|
|
161
|
+
TKey,
|
|
162
|
+
Exclude<TUtils, undefined>,
|
|
163
|
+
T,
|
|
164
|
+
InferSchemaInput<T>
|
|
165
|
+
> &
|
|
166
|
+
NonSingleResult
|
|
167
|
+
|
|
168
|
+
// Overload for when schema is provided, singleResult is true, and utils is required
|
|
169
|
+
export function createCollection<
|
|
170
|
+
T extends StandardSchemaV1,
|
|
171
|
+
TKey extends string | number,
|
|
172
|
+
TUtils extends UtilsRecord,
|
|
173
|
+
>(
|
|
174
|
+
options: Omit<
|
|
175
|
+
CollectionConfig<InferSchemaOutput<T>, TKey, T, TUtils>,
|
|
176
|
+
`utils`
|
|
177
|
+
> & {
|
|
178
|
+
schema: T
|
|
179
|
+
utils: TUtils // Required utils
|
|
180
|
+
} & SingleResult
|
|
181
|
+
): Collection<InferSchemaOutput<T>, TKey, TUtils, T, InferSchemaInput<T>> &
|
|
182
|
+
SingleResult
|
|
183
|
+
|
|
143
184
|
// Overload for when schema is provided and singleResult is true
|
|
144
185
|
export function createCollection<
|
|
145
186
|
T extends StandardSchemaV1,
|
|
146
|
-
TKey extends string | number
|
|
147
|
-
TUtils extends UtilsRecord
|
|
187
|
+
TKey extends string | number,
|
|
188
|
+
TUtils extends UtilsRecord,
|
|
148
189
|
>(
|
|
149
190
|
options: CollectionConfig<InferSchemaOutput<T>, TKey, T, TUtils> & {
|
|
150
191
|
schema: T
|
|
151
|
-
utils?: TUtils
|
|
152
192
|
} & SingleResult
|
|
153
193
|
): Collection<InferSchemaOutput<T>, TKey, TUtils, T, InferSchemaInput<T>> &
|
|
154
194
|
SingleResult
|
|
155
195
|
|
|
196
|
+
// Overload for when no schema is provided and utils is required
|
|
197
|
+
// the type T needs to be passed explicitly unless it can be inferred from the getKey function in the config
|
|
198
|
+
export function createCollection<
|
|
199
|
+
T extends object,
|
|
200
|
+
TKey extends string | number,
|
|
201
|
+
TUtils extends UtilsRecord,
|
|
202
|
+
>(
|
|
203
|
+
options: Omit<CollectionConfig<T, TKey, never, TUtils>, `utils`> & {
|
|
204
|
+
schema?: never // prohibit schema if an explicit type is provided
|
|
205
|
+
utils: TUtils // Required utils
|
|
206
|
+
} & NonSingleResult
|
|
207
|
+
): Collection<T, TKey, TUtils, never, T> & NonSingleResult
|
|
208
|
+
|
|
156
209
|
// Overload for when no schema is provided
|
|
157
210
|
// the type T needs to be passed explicitly unless it can be inferred from the getKey function in the config
|
|
158
211
|
export function createCollection<
|
|
@@ -162,10 +215,22 @@ export function createCollection<
|
|
|
162
215
|
>(
|
|
163
216
|
options: CollectionConfig<T, TKey, never, TUtils> & {
|
|
164
217
|
schema?: never // prohibit schema if an explicit type is provided
|
|
165
|
-
utils?: TUtils
|
|
166
218
|
} & NonSingleResult
|
|
167
219
|
): Collection<T, TKey, TUtils, never, T> & NonSingleResult
|
|
168
220
|
|
|
221
|
+
// Overload for when no schema is provided, singleResult is true, and utils is required
|
|
222
|
+
// the type T needs to be passed explicitly unless it can be inferred from the getKey function in the config
|
|
223
|
+
export function createCollection<
|
|
224
|
+
T extends object,
|
|
225
|
+
TKey extends string | number = string | number,
|
|
226
|
+
TUtils extends UtilsRecord = UtilsRecord,
|
|
227
|
+
>(
|
|
228
|
+
options: Omit<CollectionConfig<T, TKey, never, TUtils>, `utils`> & {
|
|
229
|
+
schema?: never // prohibit schema if an explicit type is provided
|
|
230
|
+
utils: TUtils // Required utils
|
|
231
|
+
} & SingleResult
|
|
232
|
+
): Collection<T, TKey, TUtils, never, T> & SingleResult
|
|
233
|
+
|
|
169
234
|
// Overload for when no schema is provided and singleResult is true
|
|
170
235
|
// the type T needs to be passed explicitly unless it can be inferred from the getKey function in the config
|
|
171
236
|
export function createCollection<
|
|
@@ -175,15 +240,13 @@ export function createCollection<
|
|
|
175
240
|
>(
|
|
176
241
|
options: CollectionConfig<T, TKey, never, TUtils> & {
|
|
177
242
|
schema?: never // prohibit schema if an explicit type is provided
|
|
178
|
-
utils?: TUtils
|
|
179
243
|
} & SingleResult
|
|
180
244
|
): Collection<T, TKey, TUtils, never, T> & SingleResult
|
|
181
245
|
|
|
182
246
|
// Implementation
|
|
183
247
|
export function createCollection(
|
|
184
|
-
options: CollectionConfig<any, string | number, any> & {
|
|
248
|
+
options: CollectionConfig<any, string | number, any, UtilsRecord> & {
|
|
185
249
|
schema?: StandardSchemaV1
|
|
186
|
-
utils?: UtilsRecord
|
|
187
250
|
}
|
|
188
251
|
): Collection<any, string | number, UtilsRecord, any, any> {
|
|
189
252
|
const collection = new CollectionImpl<any, string | number, any, any, any>(
|
|
@@ -163,17 +163,19 @@ export class CollectionMutationsManager<
|
|
|
163
163
|
|
|
164
164
|
const items = Array.isArray(data) ? data : [data]
|
|
165
165
|
const mutations: Array<PendingMutation<TOutput>> = []
|
|
166
|
+
const keysInCurrentBatch = new Set<TKey>()
|
|
166
167
|
|
|
167
168
|
// Create mutations for each item
|
|
168
169
|
items.forEach((item) => {
|
|
169
170
|
// Validate the data against the schema if one exists
|
|
170
171
|
const validatedData = this.validateData(item, `insert`)
|
|
171
172
|
|
|
172
|
-
// Check if an item with this ID already exists in the collection
|
|
173
|
+
// Check if an item with this ID already exists in the collection or in the current batch
|
|
173
174
|
const key = this.config.getKey(validatedData)
|
|
174
|
-
if (this.state.has(key)) {
|
|
175
|
+
if (this.state.has(key) || keysInCurrentBatch.has(key)) {
|
|
175
176
|
throw new DuplicateKeyError(key)
|
|
176
177
|
}
|
|
178
|
+
keysInCurrentBatch.add(key)
|
|
177
179
|
const globalKey = this.generateGlobalKey(key, item)
|
|
178
180
|
|
|
179
181
|
const mutation: PendingMutation<TOutput, `insert`> = {
|
|
@@ -73,9 +73,9 @@ export interface IndexInterface<
|
|
|
73
73
|
/**
|
|
74
74
|
* Base abstract class that all index types extend
|
|
75
75
|
*/
|
|
76
|
-
export abstract class BaseIndex<
|
|
77
|
-
|
|
78
|
-
{
|
|
76
|
+
export abstract class BaseIndex<
|
|
77
|
+
TKey extends string | number = string | number,
|
|
78
|
+
> implements IndexInterface<TKey> {
|
|
79
79
|
public readonly id: number
|
|
80
80
|
public readonly name?: string
|
|
81
81
|
public readonly expression: BasicExpression
|
|
@@ -3,9 +3,9 @@ import type { OrderByDirection } from "../query/ir"
|
|
|
3
3
|
import type { IndexInterface, IndexOperation, IndexStats } from "./base-index"
|
|
4
4
|
import type { RangeQueryOptions } from "./btree-index"
|
|
5
5
|
|
|
6
|
-
export class ReverseIndex<
|
|
7
|
-
|
|
8
|
-
{
|
|
6
|
+
export class ReverseIndex<
|
|
7
|
+
TKey extends string | number,
|
|
8
|
+
> implements IndexInterface<TKey> {
|
|
9
9
|
private originalIndex: IndexInterface<TKey>
|
|
10
10
|
|
|
11
11
|
constructor(index: IndexInterface<TKey>) {
|
package/src/local-only.ts
CHANGED
|
@@ -24,9 +24,9 @@ export interface LocalOnlyCollectionConfig<
|
|
|
24
24
|
TSchema extends StandardSchemaV1 = never,
|
|
25
25
|
TKey extends string | number = string | number,
|
|
26
26
|
> extends Omit<
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
BaseCollectionConfig<T, TKey, TSchema, LocalOnlyCollectionUtils>,
|
|
28
|
+
`gcTime` | `startSync`
|
|
29
|
+
> {
|
|
30
30
|
/**
|
|
31
31
|
* Optional initial data to populate the collection with on creation
|
|
32
32
|
* This data will be applied during the initial sync process
|
package/src/proxy.ts
CHANGED
|
@@ -994,21 +994,31 @@ export function createChangeProxy<
|
|
|
994
994
|
return true
|
|
995
995
|
},
|
|
996
996
|
|
|
997
|
-
defineProperty(
|
|
998
|
-
//
|
|
999
|
-
//
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
// )
|
|
1003
|
-
// if (result) {
|
|
1004
|
-
if (`value` in descriptor) {
|
|
997
|
+
defineProperty(ptarget, prop, descriptor) {
|
|
998
|
+
// Forward the defineProperty to the target to maintain Proxy invariants
|
|
999
|
+
// This allows Object.seal() and Object.freeze() to work on the proxy
|
|
1000
|
+
const result = Reflect.defineProperty(ptarget, prop, descriptor)
|
|
1001
|
+
if (result && `value` in descriptor) {
|
|
1005
1002
|
changeTracker.copy_[prop as keyof T] = deepClone(descriptor.value)
|
|
1006
1003
|
changeTracker.assigned_[prop.toString()] = true
|
|
1007
1004
|
markChanged(changeTracker)
|
|
1008
1005
|
}
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1006
|
+
return result
|
|
1007
|
+
},
|
|
1008
|
+
|
|
1009
|
+
getOwnPropertyDescriptor(ptarget, prop) {
|
|
1010
|
+
// Forward to target to maintain Proxy invariants for seal/freeze
|
|
1011
|
+
return Reflect.getOwnPropertyDescriptor(ptarget, prop)
|
|
1012
|
+
},
|
|
1013
|
+
|
|
1014
|
+
preventExtensions(ptarget) {
|
|
1015
|
+
// Forward to target to allow Object.seal() and Object.preventExtensions()
|
|
1016
|
+
return Reflect.preventExtensions(ptarget)
|
|
1017
|
+
},
|
|
1018
|
+
|
|
1019
|
+
isExtensible(ptarget) {
|
|
1020
|
+
// Forward to target to maintain consistency
|
|
1021
|
+
return Reflect.isExtensible(ptarget)
|
|
1012
1022
|
},
|
|
1013
1023
|
|
|
1014
1024
|
deleteProperty(dobj, prop) {
|
|
@@ -1020,33 +1030,36 @@ export function createChangeProxy<
|
|
|
1020
1030
|
const hadPropertyInOriginal =
|
|
1021
1031
|
stringProp in changeTracker.originalObject
|
|
1022
1032
|
|
|
1023
|
-
//
|
|
1024
|
-
//
|
|
1025
|
-
|
|
1033
|
+
// Forward the delete to the target using Reflect
|
|
1034
|
+
// This respects Object.seal/preventExtensions constraints
|
|
1035
|
+
const result = Reflect.deleteProperty(dobj, prop)
|
|
1026
1036
|
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1037
|
+
if (result) {
|
|
1038
|
+
// If the property didn't exist in the original object, removing it
|
|
1039
|
+
// should revert to the original state
|
|
1040
|
+
if (!hadPropertyInOriginal) {
|
|
1041
|
+
delete changeTracker.assigned_[stringProp]
|
|
1032
1042
|
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1043
|
+
// If this is the last change and we're not a nested object,
|
|
1044
|
+
// mark the object as unmodified
|
|
1045
|
+
if (
|
|
1046
|
+
Object.keys(changeTracker.assigned_).length === 0 &&
|
|
1047
|
+
Object.getOwnPropertySymbols(changeTracker.assigned_).length ===
|
|
1048
|
+
0
|
|
1049
|
+
) {
|
|
1050
|
+
changeTracker.modified = false
|
|
1051
|
+
} else {
|
|
1052
|
+
// We still have changes, keep as modified
|
|
1053
|
+
changeTracker.modified = true
|
|
1054
|
+
}
|
|
1040
1055
|
} else {
|
|
1041
|
-
//
|
|
1042
|
-
changeTracker.
|
|
1056
|
+
// Mark this property as deleted
|
|
1057
|
+
changeTracker.assigned_[stringProp] = false
|
|
1058
|
+
markChanged(changeTracker)
|
|
1043
1059
|
}
|
|
1044
|
-
} else {
|
|
1045
|
-
// Mark this property as deleted
|
|
1046
|
-
changeTracker.assigned_[stringProp] = false
|
|
1047
|
-
changeTracker.copy_[stringProp as keyof T] = undefined as T[keyof T]
|
|
1048
|
-
markChanged(changeTracker)
|
|
1049
1060
|
}
|
|
1061
|
+
|
|
1062
|
+
return result
|
|
1050
1063
|
}
|
|
1051
1064
|
|
|
1052
1065
|
return true
|
|
@@ -1060,7 +1073,9 @@ export function createChangeProxy<
|
|
|
1060
1073
|
}
|
|
1061
1074
|
|
|
1062
1075
|
// Create a proxy for the target object
|
|
1063
|
-
|
|
1076
|
+
// Use the unfrozen copy_ as the proxy target to avoid Proxy invariant violations
|
|
1077
|
+
// when the original target is frozen (e.g., from Immer)
|
|
1078
|
+
const proxy = createObjectProxy(changeTracker.copy_ as unknown as T)
|
|
1064
1079
|
|
|
1065
1080
|
// Return the proxy and a function to get the changes
|
|
1066
1081
|
return {
|
|
@@ -371,11 +371,11 @@ export type RefsForContext<TContext extends Context> = {
|
|
|
371
371
|
> extends true
|
|
372
372
|
? IsNonExactNullable<TContext[`schema`][K]> extends true
|
|
373
373
|
? // T is both non-exact optional and non-exact nullable (e.g., string | null | undefined)
|
|
374
|
-
|
|
375
|
-
|
|
374
|
+
// Extract the non-undefined and non-null part and place undefined outside
|
|
375
|
+
Ref<NonNullable<TContext[`schema`][K]>> | undefined
|
|
376
376
|
: // T is optional (T | undefined) but not exactly undefined, and not nullable
|
|
377
|
-
|
|
378
|
-
|
|
377
|
+
// Extract the non-undefined part and place undefined outside
|
|
378
|
+
Ref<NonUndefined<TContext[`schema`][K]>> | undefined
|
|
379
379
|
: IsNonExactNullable<TContext[`schema`][K]> extends true
|
|
380
380
|
? // T is nullable (T | null) but not exactly null, and not optional
|
|
381
381
|
// Extract the non-null part and place null outside
|
|
@@ -612,7 +612,7 @@ export type ApplyJoinOptionalityToMergedSchema<
|
|
|
612
612
|
// Apply optionality to new schema based on join type
|
|
613
613
|
[K in keyof TNewSchema]: TJoinType extends `left` | `full`
|
|
614
614
|
? // New table becomes optional for left and full joins
|
|
615
|
-
|
|
615
|
+
TNewSchema[K] | undefined
|
|
616
616
|
: // New table is required for inner and right joins
|
|
617
617
|
TNewSchema[K]
|
|
618
618
|
}
|
package/src/types.ts
CHANGED
|
@@ -13,9 +13,9 @@ export interface CollectionLike<
|
|
|
13
13
|
T extends object = Record<string, unknown>,
|
|
14
14
|
TKey extends string | number = string | number,
|
|
15
15
|
> extends Pick<
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
Collection<T, TKey>,
|
|
17
|
+
`get` | `has` | `entries` | `indexes` | `id` | `compareOptions`
|
|
18
|
+
> {}
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
21
|
* StringSortOpts - Options for string sorting behavior
|
|
@@ -727,8 +727,10 @@ export interface SubscribeChangesOptions {
|
|
|
727
727
|
whereExpression?: BasicExpression<boolean>
|
|
728
728
|
}
|
|
729
729
|
|
|
730
|
-
export interface SubscribeChangesSnapshotOptions
|
|
731
|
-
|
|
730
|
+
export interface SubscribeChangesSnapshotOptions extends Omit<
|
|
731
|
+
SubscribeChangesOptions,
|
|
732
|
+
`includeInitialState`
|
|
733
|
+
> {
|
|
732
734
|
orderBy?: OrderBy
|
|
733
735
|
limit?: number
|
|
734
736
|
}
|