@contember/bindx 0.1.5 → 0.1.8
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/adapter/ContemberAdapter.d.ts +11 -14
- package/dist/adapter/ContemberAdapter.d.ts.map +1 -1
- package/dist/brand/ComponentBrand.d.ts +1 -24
- package/dist/brand/ComponentBrand.d.ts.map +1 -1
- package/dist/contember/index.d.ts +1 -2
- package/dist/contember/index.d.ts.map +1 -1
- package/dist/handles/EntityHandle.d.ts +18 -29
- package/dist/handles/EntityHandle.d.ts.map +1 -1
- package/dist/handles/FieldHandle.d.ts +5 -3
- package/dist/handles/FieldHandle.d.ts.map +1 -1
- package/dist/handles/HasManyListHandle.d.ts +4 -3
- package/dist/handles/HasManyListHandle.d.ts.map +1 -1
- package/dist/handles/HasOneHandle.d.ts +33 -36
- package/dist/handles/HasOneHandle.d.ts.map +1 -1
- package/dist/handles/PlaceholderHandle.d.ts +9 -19
- package/dist/handles/PlaceholderHandle.d.ts.map +1 -1
- package/dist/handles/proxyFactory.d.ts +9 -37
- package/dist/handles/proxyFactory.d.ts.map +1 -1
- package/dist/handles/types.d.ts +4 -0
- package/dist/handles/types.d.ts.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/persistence/ContemberSchemaMutationAdapter.d.ts +24 -1
- package/dist/persistence/ContemberSchemaMutationAdapter.d.ts.map +1 -1
- package/dist/schema/ContemberSchema.d.ts +1 -97
- package/dist/schema/ContemberSchema.d.ts.map +1 -1
- package/dist/schema/SchemaLoader.d.ts +1 -27
- package/dist/schema/SchemaLoader.d.ts.map +1 -1
- package/dist/schema/SchemaRegistry.d.ts +1 -94
- package/dist/schema/SchemaRegistry.d.ts.map +1 -1
- package/dist/schema/roles.d.ts +1 -61
- package/dist/schema/roles.d.ts.map +1 -1
- package/dist/schema/types.d.ts +1 -178
- package/dist/schema/types.d.ts.map +1 -1
- package/dist/selection/SelectionMetaCollector.d.ts +1 -31
- package/dist/selection/SelectionMetaCollector.d.ts.map +1 -1
- package/dist/selection/SelectionScope.d.ts +1 -76
- package/dist/selection/SelectionScope.d.ts.map +1 -1
- package/dist/selection/buildQuery.d.ts +1 -44
- package/dist/selection/buildQuery.d.ts.map +1 -1
- package/dist/selection/createFragment.d.ts +1 -28
- package/dist/selection/createFragment.d.ts.map +1 -1
- package/dist/selection/createSelectionBuilder.d.ts +1 -17
- package/dist/selection/createSelectionBuilder.d.ts.map +1 -1
- package/dist/selection/queryTypes.d.ts +1 -83
- package/dist/selection/queryTypes.d.ts.map +1 -1
- package/dist/selection/types.d.ts +1 -237
- package/dist/selection/types.d.ts.map +1 -1
- package/dist/utils/aliasGenerator.d.ts +1 -24
- package/dist/utils/aliasGenerator.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/adapter/ContemberAdapter.ts +193 -123
- package/src/brand/ComponentBrand.ts +1 -28
- package/src/contember/index.ts +1 -8
- package/src/handles/EntityHandle.ts +131 -61
- package/src/handles/FieldHandle.ts +19 -3
- package/src/handles/HasManyListHandle.ts +15 -12
- package/src/handles/HasOneHandle.ts +98 -66
- package/src/handles/PlaceholderHandle.ts +26 -24
- package/src/handles/proxyFactory.ts +29 -128
- package/src/handles/types.ts +6 -0
- package/src/index.ts +22 -3
- package/src/persistence/ContemberSchemaMutationAdapter.ts +19 -1
- package/src/schema/ContemberSchema.ts +14 -132
- package/src/schema/SchemaLoader.ts +1 -93
- package/src/schema/SchemaRegistry.ts +1 -286
- package/src/schema/roles.ts +10 -83
- package/src/schema/types.ts +21 -238
- package/src/selection/SelectionMetaCollector.ts +1 -122
- package/src/selection/SelectionScope.ts +1 -208
- package/src/selection/buildQuery.ts +1 -134
- package/src/selection/createFragment.ts +1 -50
- package/src/selection/createSelectionBuilder.ts +1 -283
- package/src/selection/queryTypes.ts +8 -135
- package/src/selection/types.ts +13 -320
- package/src/utils/aliasGenerator.ts +1 -56
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
clearEntityErrors,
|
|
12
12
|
clearAllErrors as clearAllErrorsAction,
|
|
13
13
|
} from '../core/actions.js'
|
|
14
|
-
import { type
|
|
14
|
+
import { type FieldRef, type HasOneAccessor, type HasManyRef, type SelectedEntityFields, type Unsubscribe, type EntityAccessor } from './types.js'
|
|
15
15
|
import { deepEqual } from '../utils/deepEqual.js'
|
|
16
16
|
import { createClientError, type ErrorInput, type FieldError } from '../errors/types.js'
|
|
17
17
|
import type {
|
|
@@ -25,12 +25,21 @@ import type {
|
|
|
25
25
|
} from '../events/types.js'
|
|
26
26
|
import { HasOneHandle } from './HasOneHandle.js'
|
|
27
27
|
import { HasManyListHandle } from './HasManyListHandle.js'
|
|
28
|
-
import { createHandleProxy
|
|
28
|
+
import { createHandleProxy } from './proxyFactory.js'
|
|
29
29
|
import type { SelectionMeta } from '../selection/types.js'
|
|
30
30
|
import { UnfetchedFieldError } from '../errors/UnfetchedFieldError.js'
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
interface CachedHandle<TRaw, TProxy> {
|
|
33
|
+
readonly raw: TRaw
|
|
34
|
+
readonly proxy: TProxy
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** Minimal internal interface for cached relation handles that need reset/dispose.
|
|
38
|
+
* At runtime, the proxied handles satisfy this through delegation, even if the public type doesn't expose dispose(). */
|
|
39
|
+
interface RelationHandleRaw {
|
|
40
|
+
reset(): void
|
|
41
|
+
dispose(): void
|
|
42
|
+
}
|
|
34
43
|
|
|
35
44
|
/**
|
|
36
45
|
* EntityHandle provides stable access to an entity.
|
|
@@ -49,35 +58,16 @@ type RelationHandle = HasOneHandle<object> | HasManyListHandle<object>
|
|
|
49
58
|
* @typeParam T - The full entity type
|
|
50
59
|
* @typeParam TSelected - The selected subset of fields (defaults to T for backwards compatibility)
|
|
51
60
|
*/
|
|
52
|
-
export class EntityHandle<T extends object = object, TSelected = T> extends EntityRelatedHandle
|
|
61
|
+
export class EntityHandle<T extends object = object, TSelected = T> extends EntityRelatedHandle {
|
|
53
62
|
/** Cache for field handles to ensure stable identity */
|
|
54
|
-
private readonly fieldHandleCache = new Map<string, FieldHandle<unknown
|
|
63
|
+
private readonly fieldHandleCache = new Map<string, CachedHandle<FieldHandle<unknown>, FieldRef<unknown>>>()
|
|
55
64
|
|
|
56
65
|
/** Cache for relation handles */
|
|
57
|
-
private readonly relationHandleCache = new Map<string,
|
|
66
|
+
private readonly relationHandleCache = new Map<string, CachedHandle<RelationHandleRaw, HasOneAccessor<object> | HasManyRef<object>>>()
|
|
58
67
|
|
|
59
68
|
/** Runtime brand symbols for validation */
|
|
60
69
|
readonly __brands?: Set<symbol>
|
|
61
70
|
|
|
62
|
-
/** Type brand for schema - placeholder at runtime */
|
|
63
|
-
declare readonly __schema: Record<string, object>
|
|
64
|
-
|
|
65
|
-
// $ aliases - handled by proxy at runtime, declared for TypeScript
|
|
66
|
-
declare readonly $fields: SelectedEntityFields<T, TSelected>
|
|
67
|
-
declare readonly $data: TSelected | null
|
|
68
|
-
declare readonly $isDirty: boolean
|
|
69
|
-
declare readonly $persistedId: string | null
|
|
70
|
-
declare readonly $isNew: boolean
|
|
71
|
-
declare readonly $errors: readonly FieldError[]
|
|
72
|
-
declare readonly $hasError: boolean
|
|
73
|
-
declare $addError: (error: ErrorInput) => void
|
|
74
|
-
declare $clearErrors: () => void
|
|
75
|
-
declare $clearAllErrors: () => void
|
|
76
|
-
declare $on: <E extends AfterEventTypes>(eventType: E, listener: EventListener<EventTypeMap[E]>) => Unsubscribe
|
|
77
|
-
declare $intercept: <E extends BeforeEventTypes>(eventType: E, interceptor: Interceptor<EventTypeMap[E]>) => Unsubscribe
|
|
78
|
-
declare $onPersisted: (listener: EventListener<EntityPersistedEvent>) => Unsubscribe
|
|
79
|
-
declare $interceptPersisting: (interceptor: Interceptor<EntityPersistingEvent>) => Unsubscribe
|
|
80
|
-
|
|
81
71
|
private constructor(
|
|
82
72
|
id: string,
|
|
83
73
|
entityType: string,
|
|
@@ -99,11 +89,24 @@ export class EntityHandle<T extends object = object, TSelected = T> extends Enti
|
|
|
99
89
|
schema: SchemaRegistry,
|
|
100
90
|
brands?: Set<symbol>,
|
|
101
91
|
selection?: SelectionMeta,
|
|
92
|
+
): EntityAccessor<T, TSelected> {
|
|
93
|
+
return EntityHandle.wrapProxy(new EntityHandle<T, TSelected>(id, entityType, store, dispatcher, schema, brands, selection))
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
static createRaw<T extends object = object, TSelected = T>(
|
|
97
|
+
id: string,
|
|
98
|
+
entityType: string,
|
|
99
|
+
store: SnapshotStore,
|
|
100
|
+
dispatcher: ActionDispatcher,
|
|
101
|
+
schema: SchemaRegistry,
|
|
102
|
+
brands?: Set<symbol>,
|
|
103
|
+
selection?: SelectionMeta,
|
|
102
104
|
): EntityHandle<T, TSelected> {
|
|
103
|
-
return
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
105
|
+
return new EntityHandle<T, TSelected>(id, entityType, store, dispatcher, schema, brands, selection)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
static wrapProxy<T extends object, TSelected>(handle: EntityHandle<T, TSelected>): EntityAccessor<T, TSelected> {
|
|
109
|
+
return createHandleProxy<EntityHandle<T, TSelected>, EntityAccessor<T, TSelected>>(handle, (target) => target.fields)
|
|
107
110
|
}
|
|
108
111
|
|
|
109
112
|
/**
|
|
@@ -113,13 +116,6 @@ export class EntityHandle<T extends object = object, TSelected = T> extends Enti
|
|
|
113
116
|
return this.entityId
|
|
114
117
|
}
|
|
115
118
|
|
|
116
|
-
/**
|
|
117
|
-
* Gets the entity type.
|
|
118
|
-
*/
|
|
119
|
-
get type(): string {
|
|
120
|
-
return this.entityType
|
|
121
|
-
}
|
|
122
|
-
|
|
123
119
|
/**
|
|
124
120
|
* Gets the current entity snapshot.
|
|
125
121
|
*/
|
|
@@ -201,18 +197,18 @@ export class EntityHandle<T extends object = object, TSelected = T> extends Enti
|
|
|
201
197
|
const relationType = this.schema.getRelationType(this.entityType, fieldName)
|
|
202
198
|
|
|
203
199
|
if (relationType === 'hasOne') {
|
|
204
|
-
const
|
|
200
|
+
const rawHandle = this.getHasOneHandleRaw(fieldName)
|
|
205
201
|
// Check if the relation itself is dirty (connect/disconnect)
|
|
206
|
-
if (
|
|
202
|
+
if (rawHandle.isDirty) {
|
|
207
203
|
return true
|
|
208
204
|
}
|
|
209
205
|
// Check if the target entity has dirty fields
|
|
210
|
-
if (
|
|
206
|
+
if (rawHandle.entityRaw.isDirty) {
|
|
211
207
|
return true
|
|
212
208
|
}
|
|
213
209
|
} else if (relationType === 'hasMany') {
|
|
214
|
-
const
|
|
215
|
-
if (
|
|
210
|
+
const rawHandle = this.getHasManyHandleRaw(fieldName)
|
|
211
|
+
if (rawHandle.isDirty) {
|
|
216
212
|
return true
|
|
217
213
|
}
|
|
218
214
|
}
|
|
@@ -240,17 +236,17 @@ export class EntityHandle<T extends object = object, TSelected = T> extends Enti
|
|
|
240
236
|
* Gets a field handle for a specific field.
|
|
241
237
|
* Returns cached handle to ensure stable identity.
|
|
242
238
|
*/
|
|
243
|
-
field<K extends keyof T>(fieldName: K):
|
|
239
|
+
field<K extends keyof T>(fieldName: K): FieldRef<T[K]> {
|
|
244
240
|
const cacheKey = String(fieldName)
|
|
245
241
|
const cached = this.fieldHandleCache.get(cacheKey)
|
|
246
242
|
|
|
247
243
|
if (cached) {
|
|
248
|
-
return cached as
|
|
244
|
+
return cached.proxy as FieldRef<T[K]>
|
|
249
245
|
}
|
|
250
246
|
|
|
251
247
|
const enumName = this.schema.getEnumName(this.entityType, cacheKey)
|
|
252
248
|
const columnType = this.schema.getColumnType(this.entityType, cacheKey)
|
|
253
|
-
const
|
|
249
|
+
const raw = FieldHandle.createRaw<T[K]>(
|
|
254
250
|
this.entityType,
|
|
255
251
|
this.entityId,
|
|
256
252
|
[cacheKey],
|
|
@@ -259,20 +255,21 @@ export class EntityHandle<T extends object = object, TSelected = T> extends Enti
|
|
|
259
255
|
enumName,
|
|
260
256
|
columnType,
|
|
261
257
|
)
|
|
262
|
-
|
|
258
|
+
const proxy = FieldHandle.wrapProxy(raw)
|
|
259
|
+
this.fieldHandleCache.set(cacheKey, { raw, proxy } as CachedHandle<FieldHandle<unknown>, FieldRef<unknown>>)
|
|
263
260
|
|
|
264
|
-
return
|
|
261
|
+
return proxy
|
|
265
262
|
}
|
|
266
263
|
|
|
267
264
|
/**
|
|
268
265
|
* Gets a has-one relation handle.
|
|
269
266
|
*/
|
|
270
|
-
hasOne<TRelated extends object>(fieldName: string, nestedSelection?: SelectionMeta):
|
|
267
|
+
hasOne<TRelated extends object>(fieldName: string, nestedSelection?: SelectionMeta): HasOneAccessor<TRelated> {
|
|
271
268
|
const cacheKey = `hasOne:${fieldName}`
|
|
272
269
|
const cached = this.relationHandleCache.get(cacheKey)
|
|
273
270
|
|
|
274
271
|
if (cached) {
|
|
275
|
-
return cached as
|
|
272
|
+
return cached.proxy as HasOneAccessor<TRelated>
|
|
276
273
|
}
|
|
277
274
|
|
|
278
275
|
const targetType = this.schema.getRelationTarget(this.entityType, fieldName)
|
|
@@ -282,7 +279,7 @@ export class EntityHandle<T extends object = object, TSelected = T> extends Enti
|
|
|
282
279
|
)
|
|
283
280
|
}
|
|
284
281
|
|
|
285
|
-
const
|
|
282
|
+
const raw = HasOneHandle.createRaw<TRelated>(
|
|
286
283
|
this.entityType,
|
|
287
284
|
this.entityId,
|
|
288
285
|
fieldName,
|
|
@@ -293,9 +290,10 @@ export class EntityHandle<T extends object = object, TSelected = T> extends Enti
|
|
|
293
290
|
undefined,
|
|
294
291
|
nestedSelection,
|
|
295
292
|
)
|
|
296
|
-
|
|
293
|
+
const proxy = HasOneHandle.wrapProxy(raw)
|
|
294
|
+
this.relationHandleCache.set(cacheKey, { raw, proxy } as unknown as CachedHandle<RelationHandleRaw, HasOneAccessor<object> | HasManyRef<object>>)
|
|
297
295
|
|
|
298
|
-
return
|
|
296
|
+
return proxy
|
|
299
297
|
}
|
|
300
298
|
|
|
301
299
|
/**
|
|
@@ -304,13 +302,13 @@ export class EntityHandle<T extends object = object, TSelected = T> extends Enti
|
|
|
304
302
|
* @param alias - Optional alias for the relation. When the same field is used multiple times
|
|
305
303
|
* with different parameters (filter, orderBy, limit), each needs a unique alias.
|
|
306
304
|
*/
|
|
307
|
-
hasMany<TItem extends object>(fieldName: string, alias?: string, nestedSelection?: SelectionMeta):
|
|
305
|
+
hasMany<TItem extends object>(fieldName: string, alias?: string, nestedSelection?: SelectionMeta): HasManyRef<TItem> {
|
|
308
306
|
const effectiveAlias = alias ?? fieldName
|
|
309
307
|
const cacheKey = `hasMany:${effectiveAlias}`
|
|
310
308
|
const cached = this.relationHandleCache.get(cacheKey)
|
|
311
309
|
|
|
312
310
|
if (cached) {
|
|
313
|
-
return cached as
|
|
311
|
+
return cached.proxy as HasManyRef<TItem>
|
|
314
312
|
}
|
|
315
313
|
|
|
316
314
|
const targetType = this.schema.getRelationTarget(this.entityType, fieldName)
|
|
@@ -332,7 +330,79 @@ export class EntityHandle<T extends object = object, TSelected = T> extends Enti
|
|
|
332
330
|
effectiveAlias,
|
|
333
331
|
nestedSelection,
|
|
334
332
|
)
|
|
335
|
-
this.relationHandleCache.set(cacheKey, handle as
|
|
333
|
+
this.relationHandleCache.set(cacheKey, { raw: handle, proxy: handle } as unknown as CachedHandle<RelationHandleRaw, HasOneAccessor<object> | HasManyRef<object>>)
|
|
334
|
+
|
|
335
|
+
return handle
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* Gets a raw (unproxied) has-one relation handle from cache.
|
|
340
|
+
* Creates the handle if not cached yet.
|
|
341
|
+
*/
|
|
342
|
+
private getHasOneHandleRaw(fieldName: string): HasOneHandle<object> {
|
|
343
|
+
const cacheKey = `hasOne:${fieldName}`
|
|
344
|
+
const cached = this.relationHandleCache.get(cacheKey)
|
|
345
|
+
|
|
346
|
+
if (cached) {
|
|
347
|
+
return cached.raw as HasOneHandle<object>
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
const targetType = this.schema.getRelationTarget(this.entityType, fieldName)
|
|
351
|
+
if (!targetType) {
|
|
352
|
+
throw new Error(
|
|
353
|
+
`Field "${fieldName}" is not a relation on entity "${this.entityType}"`,
|
|
354
|
+
)
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
const raw = HasOneHandle.createRaw(
|
|
358
|
+
this.entityType,
|
|
359
|
+
this.entityId,
|
|
360
|
+
fieldName,
|
|
361
|
+
targetType,
|
|
362
|
+
this.store,
|
|
363
|
+
this.dispatcher,
|
|
364
|
+
this.schema,
|
|
365
|
+
undefined,
|
|
366
|
+
undefined,
|
|
367
|
+
)
|
|
368
|
+
const proxy = HasOneHandle.wrapProxy(raw)
|
|
369
|
+
this.relationHandleCache.set(cacheKey, { raw, proxy } as unknown as CachedHandle<RelationHandleRaw, HasOneAccessor<object> | HasManyRef<object>>)
|
|
370
|
+
|
|
371
|
+
return raw
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* Gets a raw (unproxied) has-many relation handle from cache.
|
|
376
|
+
* Creates the handle if not cached yet.
|
|
377
|
+
*/
|
|
378
|
+
private getHasManyHandleRaw(fieldName: string): HasManyRef<object> {
|
|
379
|
+
const cacheKey = `hasMany:${fieldName}`
|
|
380
|
+
const cached = this.relationHandleCache.get(cacheKey)
|
|
381
|
+
|
|
382
|
+
if (cached) {
|
|
383
|
+
return cached.proxy as HasManyRef<object>
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
const targetType = this.schema.getRelationTarget(this.entityType, fieldName)
|
|
387
|
+
if (!targetType) {
|
|
388
|
+
throw new Error(
|
|
389
|
+
`Field "${fieldName}" is not a relation on entity "${this.entityType}"`,
|
|
390
|
+
)
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
const handle = HasManyListHandle.create(
|
|
394
|
+
this.entityType,
|
|
395
|
+
this.entityId,
|
|
396
|
+
fieldName,
|
|
397
|
+
targetType,
|
|
398
|
+
this.store,
|
|
399
|
+
this.dispatcher,
|
|
400
|
+
this.schema,
|
|
401
|
+
this.__brands,
|
|
402
|
+
fieldName,
|
|
403
|
+
undefined,
|
|
404
|
+
)
|
|
405
|
+
this.relationHandleCache.set(cacheKey, { raw: handle, proxy: handle } as unknown as CachedHandle<RelationHandleRaw, HasOneAccessor<object> | HasManyRef<object>>)
|
|
336
406
|
|
|
337
407
|
return handle
|
|
338
408
|
}
|
|
@@ -346,8 +416,8 @@ export class EntityHandle<T extends object = object, TSelected = T> extends Enti
|
|
|
346
416
|
this.dispatcher.dispatch(resetEntity(this.entityType, this.entityId))
|
|
347
417
|
|
|
348
418
|
// Reset all cached relation handles
|
|
349
|
-
for (const
|
|
350
|
-
|
|
419
|
+
for (const { raw } of this.relationHandleCache.values()) {
|
|
420
|
+
raw.reset()
|
|
351
421
|
}
|
|
352
422
|
}
|
|
353
423
|
|
|
@@ -365,13 +435,13 @@ export class EntityHandle<T extends object = object, TSelected = T> extends Enti
|
|
|
365
435
|
override dispose(): void {
|
|
366
436
|
super.dispose()
|
|
367
437
|
|
|
368
|
-
for (const
|
|
369
|
-
|
|
438
|
+
for (const { raw } of this.fieldHandleCache.values()) {
|
|
439
|
+
raw.dispose()
|
|
370
440
|
}
|
|
371
441
|
this.fieldHandleCache.clear()
|
|
372
442
|
|
|
373
|
-
for (const
|
|
374
|
-
|
|
443
|
+
for (const { raw } of this.relationHandleCache.values()) {
|
|
444
|
+
raw.dispose()
|
|
375
445
|
}
|
|
376
446
|
this.relationHandleCache.clear()
|
|
377
447
|
}
|
|
@@ -23,7 +23,7 @@ import { createAliasProxy } from './proxyFactory.js'
|
|
|
23
23
|
* - Provides inputProps for form integration
|
|
24
24
|
* - Implements FieldRef interface for JSX compatibility
|
|
25
25
|
*/
|
|
26
|
-
export class FieldHandle<T = unknown> extends EntityRelatedHandle
|
|
26
|
+
export class FieldHandle<T = unknown> extends EntityRelatedHandle {
|
|
27
27
|
private _cachedInputProps: InputProps<T> | null = null
|
|
28
28
|
private _cachedInputPropsValue: T | null | undefined = undefined
|
|
29
29
|
|
|
@@ -49,8 +49,24 @@ export class FieldHandle<T = unknown> extends EntityRelatedHandle implements Fie
|
|
|
49
49
|
dispatcher: ActionDispatcher,
|
|
50
50
|
enumName?: string,
|
|
51
51
|
columnType?: string,
|
|
52
|
+
): FieldRef<T> {
|
|
53
|
+
return createAliasProxy<FieldHandle<T>, FieldRef<T>>(new FieldHandle<T>(entityType, entityId, fieldPath, store, dispatcher, enumName, columnType))
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
static createRaw<T = unknown>(
|
|
57
|
+
entityType: string,
|
|
58
|
+
entityId: string,
|
|
59
|
+
fieldPath: string[],
|
|
60
|
+
store: SnapshotStore,
|
|
61
|
+
dispatcher: ActionDispatcher,
|
|
62
|
+
enumName?: string,
|
|
63
|
+
columnType?: string,
|
|
52
64
|
): FieldHandle<T> {
|
|
53
|
-
return
|
|
65
|
+
return new FieldHandle<T>(entityType, entityId, fieldPath, store, dispatcher, enumName, columnType)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
static wrapProxy<T>(handle: FieldHandle<T>): FieldRef<T> {
|
|
69
|
+
return createAliasProxy<FieldHandle<T>, FieldRef<T>>(handle)
|
|
54
70
|
}
|
|
55
71
|
|
|
56
72
|
/**
|
|
@@ -204,7 +220,7 @@ export class FieldHandle<T = unknown> extends EntityRelatedHandle implements Fie
|
|
|
204
220
|
*/
|
|
205
221
|
nested<K extends keyof NonNullable<T>>(
|
|
206
222
|
key: K,
|
|
207
|
-
):
|
|
223
|
+
): FieldRef<NonNullable<T>[K]> {
|
|
208
224
|
return FieldHandle.create<NonNullable<T>[K]>(
|
|
209
225
|
this.entityType,
|
|
210
226
|
this.entityId,
|
|
@@ -27,8 +27,9 @@ import { createAliasProxy } from './proxyFactory.js'
|
|
|
27
27
|
* @typeParam TEntity - The full entity type of items in the relation
|
|
28
28
|
* @typeParam TSelected - The selected subset of fields (defaults to TEntity for backwards compatibility)
|
|
29
29
|
*/
|
|
30
|
-
export class HasManyListHandle<TEntity extends object = object, TSelected = TEntity> extends EntityRelatedHandle
|
|
31
|
-
private
|
|
30
|
+
export class HasManyListHandle<TEntity extends object = object, TSelected = TEntity> extends EntityRelatedHandle {
|
|
31
|
+
private itemHandleCacheRaw = new Map<string, EntityHandle<TEntity, TSelected>>()
|
|
32
|
+
private itemHandleCacheProxy = new Map<string, EntityAccessor<TEntity, TSelected>>()
|
|
32
33
|
|
|
33
34
|
/** Runtime brand symbols for validation */
|
|
34
35
|
readonly __brands?: Set<symbol>
|
|
@@ -84,8 +85,8 @@ export class HasManyListHandle<TEntity extends object = object, TSelected = TEnt
|
|
|
84
85
|
brands?: Set<symbol>,
|
|
85
86
|
alias?: string,
|
|
86
87
|
selection?: SelectionMeta,
|
|
87
|
-
):
|
|
88
|
-
return createAliasProxy(new HasManyListHandle<TEntity, TSelected>(parentEntityType, parentEntityId, fieldName, itemType, store, dispatcher, schema, brands, alias, selection))
|
|
88
|
+
): HasManyRef<TEntity, TSelected> {
|
|
89
|
+
return createAliasProxy<HasManyListHandle<TEntity, TSelected>, HasManyRef<TEntity, TSelected>>(new HasManyListHandle<TEntity, TSelected>(parentEntityType, parentEntityId, fieldName, itemType, store, dispatcher, schema, brands, alias, selection))
|
|
89
90
|
}
|
|
90
91
|
|
|
91
92
|
/**
|
|
@@ -221,10 +222,10 @@ export class HasManyListHandle<TEntity extends object = object, TSelected = TEnt
|
|
|
221
222
|
* Returns selection-aware EntityAccessor that supports direct field access.
|
|
222
223
|
*/
|
|
223
224
|
getItemHandle(itemId: string): EntityAccessor<TEntity, TSelected> {
|
|
224
|
-
let
|
|
225
|
+
let proxy = this.itemHandleCacheProxy.get(itemId)
|
|
225
226
|
|
|
226
|
-
if (!
|
|
227
|
-
|
|
227
|
+
if (!proxy) {
|
|
228
|
+
const raw = EntityHandle.createRaw<TEntity, TSelected>(
|
|
228
229
|
itemId,
|
|
229
230
|
this.itemType,
|
|
230
231
|
this.store,
|
|
@@ -233,11 +234,12 @@ export class HasManyListHandle<TEntity extends object = object, TSelected = TEnt
|
|
|
233
234
|
this.__brands,
|
|
234
235
|
this.selection,
|
|
235
236
|
)
|
|
236
|
-
|
|
237
|
+
proxy = EntityHandle.wrapProxy(raw)
|
|
238
|
+
this.itemHandleCacheRaw.set(itemId, raw)
|
|
239
|
+
this.itemHandleCacheProxy.set(itemId, proxy)
|
|
237
240
|
}
|
|
238
241
|
|
|
239
|
-
|
|
240
|
-
return handle as unknown as EntityAccessor<TEntity, TSelected>
|
|
242
|
+
return proxy
|
|
241
243
|
}
|
|
242
244
|
|
|
243
245
|
/**
|
|
@@ -391,10 +393,11 @@ export class HasManyListHandle<TEntity extends object = object, TSelected = TEnt
|
|
|
391
393
|
override dispose(): void {
|
|
392
394
|
super.dispose()
|
|
393
395
|
|
|
394
|
-
for (const handle of this.
|
|
396
|
+
for (const handle of this.itemHandleCacheRaw.values()) {
|
|
395
397
|
handle.dispose()
|
|
396
398
|
}
|
|
397
|
-
this.
|
|
399
|
+
this.itemHandleCacheRaw.clear()
|
|
400
|
+
this.itemHandleCacheProxy.clear()
|
|
398
401
|
}
|
|
399
402
|
|
|
400
403
|
/**
|