@contember/bindx 0.1.0
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 +40 -0
- package/dist/adapter/ContemberAdapter.d.ts.map +1 -0
- package/dist/adapter/MockAdapter.d.ts +81 -0
- package/dist/adapter/MockAdapter.d.ts.map +1 -0
- package/dist/adapter/MockQueryEngine.d.ts +43 -0
- package/dist/adapter/MockQueryEngine.d.ts.map +1 -0
- package/dist/adapter/index.d.ts +5 -0
- package/dist/adapter/index.d.ts.map +1 -0
- package/dist/adapter/types.d.ts +184 -0
- package/dist/adapter/types.d.ts.map +1 -0
- package/dist/brand/ComponentBrand.d.ts +25 -0
- package/dist/brand/ComponentBrand.d.ts.map +1 -0
- package/dist/contember/index.d.ts +10 -0
- package/dist/contember/index.d.ts.map +1 -0
- package/dist/core/ActionDispatcher.d.ts +64 -0
- package/dist/core/ActionDispatcher.d.ts.map +1 -0
- package/dist/core/Disposable.d.ts +57 -0
- package/dist/core/Disposable.d.ts.map +1 -0
- package/dist/core/EntityLoader.d.ts +80 -0
- package/dist/core/EntityLoader.d.ts.map +1 -0
- package/dist/core/PersistenceManager.d.ts +126 -0
- package/dist/core/PersistenceManager.d.ts.map +1 -0
- package/dist/core/SelectionResolver.d.ts +21 -0
- package/dist/core/SelectionResolver.d.ts.map +1 -0
- package/dist/core/actionClassification.d.ts +48 -0
- package/dist/core/actionClassification.d.ts.map +1 -0
- package/dist/core/actions.d.ts +301 -0
- package/dist/core/actions.d.ts.map +1 -0
- package/dist/core/index.d.ts +4 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/dataview/filterHandlers.d.ts +18 -0
- package/dist/dataview/filterHandlers.d.ts.map +1 -0
- package/dist/dataview/index.d.ts +3 -0
- package/dist/dataview/index.d.ts.map +1 -0
- package/dist/dataview/types.d.ts +164 -0
- package/dist/dataview/types.d.ts.map +1 -0
- package/dist/errors/UnfetchedFieldError.d.ts +11 -0
- package/dist/errors/UnfetchedFieldError.d.ts.map +1 -0
- package/dist/errors/errorPathResolver.d.ts +52 -0
- package/dist/errors/errorPathResolver.d.ts.map +1 -0
- package/dist/errors/index.d.ts +5 -0
- package/dist/errors/index.d.ts.map +1 -0
- package/dist/errors/pathMapper.d.ts +42 -0
- package/dist/errors/pathMapper.d.ts.map +1 -0
- package/dist/errors/types.d.ts +131 -0
- package/dist/errors/types.d.ts.map +1 -0
- package/dist/events/EventEmitter.d.ts +97 -0
- package/dist/events/EventEmitter.d.ts.map +1 -0
- package/dist/events/eventFactory.d.ts +40 -0
- package/dist/events/eventFactory.d.ts.map +1 -0
- package/dist/events/index.d.ts +15 -0
- package/dist/events/index.d.ts.map +1 -0
- package/dist/events/types.d.ts +264 -0
- package/dist/events/types.d.ts.map +1 -0
- package/dist/handles/BaseHandle.d.ts +64 -0
- package/dist/handles/BaseHandle.d.ts.map +1 -0
- package/dist/handles/EntityHandle.d.ts +208 -0
- package/dist/handles/EntityHandle.d.ts.map +1 -0
- package/dist/handles/FieldHandle.d.ts +111 -0
- package/dist/handles/FieldHandle.d.ts.map +1 -0
- package/dist/handles/HasManyListHandle.d.ts +166 -0
- package/dist/handles/HasManyListHandle.d.ts.map +1 -0
- package/dist/handles/HasOneHandle.d.ts +168 -0
- package/dist/handles/HasOneHandle.d.ts.map +1 -0
- package/dist/handles/PlaceholderHandle.d.ts +117 -0
- package/dist/handles/PlaceholderHandle.d.ts.map +1 -0
- package/dist/handles/index.d.ts +8 -0
- package/dist/handles/index.d.ts.map +1 -0
- package/dist/handles/proxyFactory.d.ts +66 -0
- package/dist/handles/proxyFactory.d.ts.map +1 -0
- package/dist/handles/types.d.ts +430 -0
- package/dist/handles/types.d.ts.map +1 -0
- package/dist/index.d.ts +53 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/internal.d.ts +11 -0
- package/dist/internal.d.ts.map +1 -0
- package/dist/persistence/BatchPersister.d.ts +142 -0
- package/dist/persistence/BatchPersister.d.ts.map +1 -0
- package/dist/persistence/ChangeRegistry.d.ts +87 -0
- package/dist/persistence/ChangeRegistry.d.ts.map +1 -0
- package/dist/persistence/ContemberSchemaMutationAdapter.d.ts +16 -0
- package/dist/persistence/ContemberSchemaMutationAdapter.d.ts.map +1 -0
- package/dist/persistence/MutationCollector.d.ts +96 -0
- package/dist/persistence/MutationCollector.d.ts.map +1 -0
- package/dist/persistence/MutationSchemaProvider.d.ts +30 -0
- package/dist/persistence/MutationSchemaProvider.d.ts.map +1 -0
- package/dist/persistence/index.d.ts +7 -0
- package/dist/persistence/index.d.ts.map +1 -0
- package/dist/persistence/types.d.ts +189 -0
- package/dist/persistence/types.d.ts.map +1 -0
- package/dist/roles/RoleSchemaRegistry.d.ts +77 -0
- package/dist/roles/RoleSchemaRegistry.d.ts.map +1 -0
- package/dist/roles/index.d.ts +11 -0
- package/dist/roles/index.d.ts.map +1 -0
- package/dist/roles/types.d.ts +242 -0
- package/dist/roles/types.d.ts.map +1 -0
- package/dist/schema/ContemberSchema.d.ts +98 -0
- package/dist/schema/ContemberSchema.d.ts.map +1 -0
- package/dist/schema/SchemaLoader.d.ts +28 -0
- package/dist/schema/SchemaLoader.d.ts.map +1 -0
- package/dist/schema/SchemaRegistry.d.ts +95 -0
- package/dist/schema/SchemaRegistry.d.ts.map +1 -0
- package/dist/schema/index.d.ts +6 -0
- package/dist/schema/index.d.ts.map +1 -0
- package/dist/schema/roles.d.ts +62 -0
- package/dist/schema/roles.d.ts.map +1 -0
- package/dist/schema/types.d.ts +179 -0
- package/dist/schema/types.d.ts.map +1 -0
- package/dist/selection/SelectionMetaCollector.d.ts +32 -0
- package/dist/selection/SelectionMetaCollector.d.ts.map +1 -0
- package/dist/selection/SelectionScope.d.ts +77 -0
- package/dist/selection/SelectionScope.d.ts.map +1 -0
- package/dist/selection/buildQuery.d.ts +45 -0
- package/dist/selection/buildQuery.d.ts.map +1 -0
- package/dist/selection/createFragment.d.ts +29 -0
- package/dist/selection/createFragment.d.ts.map +1 -0
- package/dist/selection/createSelectionBuilder.d.ts +18 -0
- package/dist/selection/createSelectionBuilder.d.ts.map +1 -0
- package/dist/selection/index.d.ts +8 -0
- package/dist/selection/index.d.ts.map +1 -0
- package/dist/selection/queryTypes.d.ts +84 -0
- package/dist/selection/queryTypes.d.ts.map +1 -0
- package/dist/selection/types.d.ts +238 -0
- package/dist/selection/types.d.ts.map +1 -0
- package/dist/store/DirtyTracker.d.ts +26 -0
- package/dist/store/DirtyTracker.d.ts.map +1 -0
- package/dist/store/EntityMetaStore.d.ts +52 -0
- package/dist/store/EntityMetaStore.d.ts.map +1 -0
- package/dist/store/EntitySnapshotStore.d.ts +63 -0
- package/dist/store/EntitySnapshotStore.d.ts.map +1 -0
- package/dist/store/ErrorStore.d.ts +82 -0
- package/dist/store/ErrorStore.d.ts.map +1 -0
- package/dist/store/RelationStore.d.ts +175 -0
- package/dist/store/RelationStore.d.ts.map +1 -0
- package/dist/store/SnapshotStore.d.ts +143 -0
- package/dist/store/SnapshotStore.d.ts.map +1 -0
- package/dist/store/SubscriptionManager.d.ts +90 -0
- package/dist/store/SubscriptionManager.d.ts.map +1 -0
- package/dist/store/TouchedStore.d.ts +24 -0
- package/dist/store/TouchedStore.d.ts.map +1 -0
- package/dist/store/entityId.d.ts +29 -0
- package/dist/store/entityId.d.ts.map +1 -0
- package/dist/store/index.d.ts +1 -0
- package/dist/store/index.d.ts.map +1 -0
- package/dist/store/snapshots.d.ts +144 -0
- package/dist/store/snapshots.d.ts.map +1 -0
- package/dist/undo/UndoManager.d.ts +120 -0
- package/dist/undo/UndoManager.d.ts.map +1 -0
- package/dist/undo/index.d.ts +3 -0
- package/dist/undo/index.d.ts.map +1 -0
- package/dist/undo/types.d.ts +74 -0
- package/dist/undo/types.d.ts.map +1 -0
- package/dist/utils/aliasGenerator.d.ts +25 -0
- package/dist/utils/aliasGenerator.d.ts.map +1 -0
- package/dist/utils/deepEqual.d.ts +6 -0
- package/dist/utils/deepEqual.d.ts.map +1 -0
- package/dist/utils/index.d.ts +3 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/package.json +29 -0
- package/src/adapter/ContemberAdapter.ts +239 -0
- package/src/adapter/MockAdapter.ts +394 -0
- package/src/adapter/MockQueryEngine.ts +236 -0
- package/src/adapter/index.ts +21 -0
- package/src/adapter/types.ts +199 -0
- package/src/brand/ComponentBrand.ts +28 -0
- package/src/contember/index.ts +17 -0
- package/src/core/ActionDispatcher.ts +450 -0
- package/src/core/Disposable.ts +126 -0
- package/src/core/EntityLoader.ts +169 -0
- package/src/core/SelectionResolver.ts +78 -0
- package/src/core/actionClassification.ts +196 -0
- package/src/core/actions.ts +491 -0
- package/src/core/index.ts +20 -0
- package/src/dataview/filterHandlers.ts +443 -0
- package/src/dataview/index.ts +36 -0
- package/src/dataview/types.ts +220 -0
- package/src/errors/UnfetchedFieldError.ts +18 -0
- package/src/errors/errorPathResolver.ts +239 -0
- package/src/errors/index.ts +40 -0
- package/src/errors/pathMapper.ts +40 -0
- package/src/errors/types.ts +223 -0
- package/src/events/EventEmitter.ts +447 -0
- package/src/events/eventFactory.ts +430 -0
- package/src/events/index.ts +89 -0
- package/src/events/types.ts +374 -0
- package/src/handles/BaseHandle.ts +100 -0
- package/src/handles/EntityHandle.ts +538 -0
- package/src/handles/FieldHandle.ts +268 -0
- package/src/handles/HasManyListHandle.ts +500 -0
- package/src/handles/HasOneHandle.ts +500 -0
- package/src/handles/PlaceholderHandle.ts +321 -0
- package/src/handles/index.ts +37 -0
- package/src/handles/proxyFactory.ts +218 -0
- package/src/handles/types.ts +743 -0
- package/src/index.ts +384 -0
- package/src/internal.ts +19 -0
- package/src/persistence/BatchPersister.ts +911 -0
- package/src/persistence/ChangeRegistry.ts +150 -0
- package/src/persistence/ContemberSchemaMutationAdapter.ts +57 -0
- package/src/persistence/MutationCollector.ts +567 -0
- package/src/persistence/MutationSchemaProvider.ts +33 -0
- package/src/persistence/index.ts +23 -0
- package/src/persistence/types.ts +220 -0
- package/src/schema/ContemberSchema.ts +132 -0
- package/src/schema/SchemaLoader.ts +93 -0
- package/src/schema/SchemaRegistry.ts +286 -0
- package/src/schema/index.ts +51 -0
- package/src/schema/roles.ts +83 -0
- package/src/schema/types.ts +238 -0
- package/src/selection/SelectionMetaCollector.ts +122 -0
- package/src/selection/SelectionScope.ts +208 -0
- package/src/selection/buildQuery.ts +134 -0
- package/src/selection/createFragment.ts +50 -0
- package/src/selection/createSelectionBuilder.ts +283 -0
- package/src/selection/index.ts +31 -0
- package/src/selection/queryTypes.ts +135 -0
- package/src/selection/types.ts +320 -0
- package/src/store/DirtyTracker.ts +117 -0
- package/src/store/EntityMetaStore.ts +143 -0
- package/src/store/EntitySnapshotStore.ts +260 -0
- package/src/store/ErrorStore.ts +251 -0
- package/src/store/RelationStore.ts +696 -0
- package/src/store/SnapshotStore.ts +765 -0
- package/src/store/SubscriptionManager.ts +241 -0
- package/src/store/TouchedStore.ts +42 -0
- package/src/store/entityId.ts +43 -0
- package/src/store/index.ts +2 -0
- package/src/store/snapshots.ts +203 -0
- package/src/undo/UndoManager.ts +418 -0
- package/src/undo/index.ts +9 -0
- package/src/undo/types.ts +84 -0
- package/src/utils/aliasGenerator.ts +56 -0
- package/src/utils/deepEqual.ts +33 -0
- package/src/utils/index.ts +2 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"snapshots.d.ts","sourceRoot":"","sources":["../../src/store/snapshots.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAA;AAE9D;;GAEG;AACH,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,GAAG,WAAW,CAAA;AAE/E;;;GAGG;AACH,MAAM,WAAW,cAAc,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM;IACxD,gBAAgB;IAChB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,uBAAuB;IACvB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,oEAAoE;IACpE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAA;IAC1B,uEAAuE;IACvE,QAAQ,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAA;IAChC,uEAAuE;IACvE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa,CAAC,CAAC,GAAG,OAAO;IACzC,oBAAoB;IACpB,QAAQ,CAAC,KAAK,EAAE,CAAC,GAAG,IAAI,CAAA;IACxB,wCAAwC;IACxC,QAAQ,CAAC,WAAW,EAAE,CAAC,GAAG,IAAI,CAAA;IAC9B,0CAA0C;IAC1C,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM;IAChE,6BAA6B;IAC7B,QAAQ,CAAC,KAAK,EAAE,mBAAmB,CAAA;IACnC,0DAA0D;IAC1D,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IAChC,iDAAiD;IACjD,QAAQ,CAAC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAA;IACtC,4DAA4D;IAC5D,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC,CAAC,GAAG,IAAI,CAAA;IACzC,6CAA6C;IAC7C,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,mCAAmC;IACnC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM;IAC7D,0CAA0C;IAC1C,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,0BAA0B;IAC1B,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC,CAAC,CAAA;IAClC,4DAA4D;IAC5D,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM;IACzD,kCAAkC;IAClC,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,CAAA;IACrD,8CAA8C;IAC9C,QAAQ,CAAC,cAAc,EAAE,WAAW,CAAC,MAAM,CAAC,CAAA;IAC5C,4CAA4C;IAC5C,QAAQ,CAAC,SAAS,EAAE,WAAW,CAAC,MAAM,CAAC,CAAA;IACvC,8CAA8C;IAC9C,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC,MAAM,CAAC,CAAA;IACzC,yCAAyC;IACzC,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAA;IAC9B,6CAA6C;IAC7C,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,mCAAmC;IACnC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC5B,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAA;IAC1B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IAC1B,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAA;IACxB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAA;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC7B,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAA;IAC5B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,UAAU,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM;IACpD,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAA;IACxB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAC,CAAC,CAAA;CACpC;AAED;;GAEG;AACH,MAAM,MAAM,WAAW,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,IAC9C,YAAY,GACZ,UAAU,GACV,aAAa,GACb,UAAU,CAAC,CAAC,CAAC,CAAA;AAEhB;;GAEG;AACH,wBAAgB,YAAY,CAAC,CAAC,SAAS,MAAM,EAAE,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC,GAAG,KAAK,IAAI,UAAU,CAAC,CAAC,CAAC,CAE5F;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,CAAC,SAAS,MAAM,EAAE,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC,GAAG,KAAK,IAAI,YAAY,CAE7F;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,CAAC,SAAS,MAAM,EAAE,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC,GAAG,KAAK,IAAI,UAAU,CAEzF;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,SAAS,MAAM,EACpD,EAAE,EAAE,MAAM,EACV,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,CAAC,EACP,UAAU,EAAE,CAAC,EACb,OAAO,EAAE,MAAM,GACb,cAAc,CAAC,CAAC,CAAC,CAQnB;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,SAAS,MAAM,EACpD,QAAQ,EAAE,cAAc,CAAC,CAAC,CAAC,EAC3B,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,GACjB,cAAc,CAAC,CAAC,CAAC,CAMnB;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,EACpC,KAAK,EAAE,CAAC,GAAG,IAAI,EACf,WAAW,EAAE,CAAC,GAAG,IAAI,GACnB,aAAa,CAAC,CAAC,CAAC,CAMlB"}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import type { ActionMiddleware } from '../core/ActionDispatcher.js';
|
|
2
|
+
import type { SnapshotStore } from '../store/SnapshotStore.js';
|
|
3
|
+
import type { UndoManagerConfig, UndoState } from './types.js';
|
|
4
|
+
type Subscriber = () => void;
|
|
5
|
+
/**
|
|
6
|
+
* UndoManager provides undo/redo functionality for the Bindx store.
|
|
7
|
+
*
|
|
8
|
+
* Features:
|
|
9
|
+
* - Automatic debounced grouping of rapid changes
|
|
10
|
+
* - Manual grouping via beginGroup/endGroup
|
|
11
|
+
* - Configurable history size
|
|
12
|
+
* - Block/unblock during persist operations
|
|
13
|
+
* - React integration via subscribe/getState
|
|
14
|
+
*/
|
|
15
|
+
export declare class UndoManager {
|
|
16
|
+
private readonly store;
|
|
17
|
+
private undoStack;
|
|
18
|
+
private redoStack;
|
|
19
|
+
private pendingEntry;
|
|
20
|
+
private debounceTimer;
|
|
21
|
+
private isBlocked;
|
|
22
|
+
private manualGroupId;
|
|
23
|
+
private manualGroupLabel;
|
|
24
|
+
private subscribers;
|
|
25
|
+
private cachedState;
|
|
26
|
+
private readonly maxHistorySize;
|
|
27
|
+
private readonly debounceMs;
|
|
28
|
+
constructor(store: SnapshotStore, config?: UndoManagerConfig);
|
|
29
|
+
/**
|
|
30
|
+
* Creates middleware for ActionDispatcher.
|
|
31
|
+
* Must be added to dispatcher to enable undo tracking.
|
|
32
|
+
*/
|
|
33
|
+
createMiddleware(): ActionMiddleware;
|
|
34
|
+
/**
|
|
35
|
+
* Handles an action, capturing state for undo if trackable.
|
|
36
|
+
*/
|
|
37
|
+
private handleAction;
|
|
38
|
+
/**
|
|
39
|
+
* Handles action in manual group mode.
|
|
40
|
+
*/
|
|
41
|
+
private handleManualGroupAction;
|
|
42
|
+
/**
|
|
43
|
+
* Handles action in debounced auto-group mode.
|
|
44
|
+
*/
|
|
45
|
+
private handleDebouncedAction;
|
|
46
|
+
/**
|
|
47
|
+
* Gets keys that are in source but not in target.
|
|
48
|
+
*/
|
|
49
|
+
private getNewKeys;
|
|
50
|
+
/**
|
|
51
|
+
* Checks if keys object is empty.
|
|
52
|
+
*/
|
|
53
|
+
private isEmptyKeys;
|
|
54
|
+
/**
|
|
55
|
+
* Merges additional snapshot into target.
|
|
56
|
+
*/
|
|
57
|
+
private mergeSnapshots;
|
|
58
|
+
/**
|
|
59
|
+
* Starts the debounce timer.
|
|
60
|
+
*/
|
|
61
|
+
private startDebounceTimer;
|
|
62
|
+
/**
|
|
63
|
+
* Resets the debounce timer.
|
|
64
|
+
*/
|
|
65
|
+
private resetDebounceTimer;
|
|
66
|
+
/**
|
|
67
|
+
* Flushes pending entry to undo stack.
|
|
68
|
+
*/
|
|
69
|
+
private flushPendingEntry;
|
|
70
|
+
/**
|
|
71
|
+
* Trims history to max size.
|
|
72
|
+
*/
|
|
73
|
+
private trimHistory;
|
|
74
|
+
/**
|
|
75
|
+
* Starts a manual group. All actions until endGroup are grouped as one undo entry.
|
|
76
|
+
* Returns group ID that must be passed to endGroup.
|
|
77
|
+
*/
|
|
78
|
+
beginGroup(label?: string): string;
|
|
79
|
+
/**
|
|
80
|
+
* Ends a manual group and pushes to undo stack.
|
|
81
|
+
*/
|
|
82
|
+
endGroup(groupId: string): void;
|
|
83
|
+
/**
|
|
84
|
+
* Undoes the last entry.
|
|
85
|
+
*/
|
|
86
|
+
undo(): void;
|
|
87
|
+
/**
|
|
88
|
+
* Redoes the last undone entry.
|
|
89
|
+
*/
|
|
90
|
+
redo(): void;
|
|
91
|
+
/**
|
|
92
|
+
* Blocks undo/redo operations.
|
|
93
|
+
* Use during persist to prevent inconsistent state.
|
|
94
|
+
*/
|
|
95
|
+
block(): void;
|
|
96
|
+
/**
|
|
97
|
+
* Unblocks undo/redo operations.
|
|
98
|
+
*/
|
|
99
|
+
unblock(): void;
|
|
100
|
+
/**
|
|
101
|
+
* Clears all undo/redo history.
|
|
102
|
+
*/
|
|
103
|
+
clear(): void;
|
|
104
|
+
/**
|
|
105
|
+
* Subscribes to state changes.
|
|
106
|
+
* Returns unsubscribe function.
|
|
107
|
+
*/
|
|
108
|
+
subscribe(callback: Subscriber): () => void;
|
|
109
|
+
/**
|
|
110
|
+
* Gets current state for React integration.
|
|
111
|
+
* Returns a cached object to satisfy useSyncExternalStore's referential equality requirement.
|
|
112
|
+
*/
|
|
113
|
+
getState(): UndoState;
|
|
114
|
+
/**
|
|
115
|
+
* Notifies all subscribers of state change.
|
|
116
|
+
*/
|
|
117
|
+
private notifySubscribers;
|
|
118
|
+
}
|
|
119
|
+
export {};
|
|
120
|
+
//# sourceMappingURL=UndoManager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"UndoManager.d.ts","sourceRoot":"","sources":["../../src/undo/UndoManager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAA;AASnE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAA;AAC9D,OAAO,KAAK,EAIX,iBAAiB,EACjB,SAAS,EACT,MAAM,YAAY,CAAA;AAEnB,KAAK,UAAU,GAAG,MAAM,IAAI,CAAA;AAS5B;;;;;;;;;GASG;AACH,qBAAa,WAAW;IAetB,OAAO,CAAC,QAAQ,CAAC,KAAK;IAdvB,OAAO,CAAC,SAAS,CAAkB;IACnC,OAAO,CAAC,SAAS,CAAkB;IACnC,OAAO,CAAC,YAAY,CAAgC;IACpD,OAAO,CAAC,aAAa,CAA6C;IAClE,OAAO,CAAC,SAAS,CAAQ;IACzB,OAAO,CAAC,aAAa,CAAsB;IAC3C,OAAO,CAAC,gBAAgB,CAAgC;IACxD,OAAO,CAAC,WAAW,CAAwB;IAC3C,OAAO,CAAC,WAAW,CAAyB;IAE5C,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAQ;IACvC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAQ;gBAGjB,KAAK,EAAE,aAAa,EACrC,MAAM,GAAE,iBAAsB;IAM/B;;;OAGG;IACH,gBAAgB,IAAI,gBAAgB;IAQpC;;OAEG;IACH,OAAO,CAAC,YAAY;IAuBpB;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAsB/B;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAqC7B;;OAEG;IACH,OAAO,CAAC,UAAU;IAQlB;;OAEG;IACH,OAAO,CAAC,WAAW;IAInB;;OAEG;IACH,OAAO,CAAC,cAAc;IAuBtB;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAM1B;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAO1B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAqBzB;;OAEG;IACH,OAAO,CAAC,WAAW;IAMnB;;;OAGG;IACH,UAAU,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM;IAUlC;;OAEG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAW/B;;OAEG;IACH,IAAI,IAAI,IAAI;IA4BZ;;OAEG;IACH,IAAI,IAAI,IAAI;IAyBZ;;;OAGG;IACH,KAAK,IAAI,IAAI;IAOb;;OAEG;IACH,OAAO,IAAI,IAAI;IAKf;;OAEG;IACH,KAAK,IAAI,IAAI;IAab;;;OAGG;IACH,SAAS,CAAC,QAAQ,EAAE,UAAU,GAAG,MAAM,IAAI;IAO3C;;;OAGG;IACH,QAAQ,IAAI,SAAS;IAarB;;OAEG;IACH,OAAO,CAAC,iBAAiB;CAMzB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/undo/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAC9C,YAAY,EACX,oBAAoB,EACpB,gBAAgB,EAChB,SAAS,EACT,iBAAiB,EACjB,SAAS,EACT,iBAAiB,GACjB,MAAM,YAAY,CAAA"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import type { StoreAffectedKeys } from '../core/actionClassification.js';
|
|
2
|
+
import type { EntitySnapshot } from '../store/snapshots.js';
|
|
3
|
+
import type { StoredRelationState, StoredHasManyState, EntityMeta } from '../store/SnapshotStore.js';
|
|
4
|
+
/**
|
|
5
|
+
* Partial snapshot of store state.
|
|
6
|
+
* Contains only the data affected by an action or group of actions.
|
|
7
|
+
*/
|
|
8
|
+
export interface PartialStoreSnapshot {
|
|
9
|
+
/** Entity snapshots (frozen, immutable) */
|
|
10
|
+
entitySnapshots: Map<string, EntitySnapshot>;
|
|
11
|
+
/** Has-one relation states */
|
|
12
|
+
relationStates: Map<string, StoredRelationState>;
|
|
13
|
+
/** Has-many list states */
|
|
14
|
+
hasManyStates: Map<string, StoredHasManyState>;
|
|
15
|
+
/** Entity metadata (existsOnServer, deletion flags) */
|
|
16
|
+
entityMetas: Map<string, EntityMeta>;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* A single undo/redo entry.
|
|
20
|
+
* Contains the snapshot of state BEFORE the action(s) were applied.
|
|
21
|
+
*/
|
|
22
|
+
export interface UndoEntry {
|
|
23
|
+
/** Unique identifier for this entry */
|
|
24
|
+
id: string;
|
|
25
|
+
/** Optional human-readable label */
|
|
26
|
+
label?: string;
|
|
27
|
+
/** Snapshot of state BEFORE the action(s) */
|
|
28
|
+
beforeSnapshot: PartialStoreSnapshot;
|
|
29
|
+
/** Keys that were affected (for redo snapshot capture) */
|
|
30
|
+
affectedKeys: StoreAffectedKeys;
|
|
31
|
+
/** When this entry was created */
|
|
32
|
+
timestamp: number;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Pending entry during debounce window.
|
|
36
|
+
* Accumulates affected keys while waiting for debounce to complete.
|
|
37
|
+
*/
|
|
38
|
+
export interface PendingUndoEntry {
|
|
39
|
+
/** Snapshot captured before the first action in the group */
|
|
40
|
+
beforeSnapshot: PartialStoreSnapshot;
|
|
41
|
+
/** Accumulated affected keys */
|
|
42
|
+
affectedKeys: StoreAffectedKeys;
|
|
43
|
+
/** When the first action occurred */
|
|
44
|
+
timestamp: number;
|
|
45
|
+
/** Optional label for manual grouping */
|
|
46
|
+
label?: string;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Configuration options for UndoManager.
|
|
50
|
+
*/
|
|
51
|
+
export interface UndoManagerConfig {
|
|
52
|
+
/** Maximum number of undo entries to keep (default: 100) */
|
|
53
|
+
maxHistorySize?: number;
|
|
54
|
+
/** Debounce time in milliseconds for auto-grouping (default: 300) */
|
|
55
|
+
debounceMs?: number;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Current state of the undo manager.
|
|
59
|
+
* Used for React integration via useSyncExternalStore.
|
|
60
|
+
*/
|
|
61
|
+
export interface UndoState {
|
|
62
|
+
/** Whether undo is available */
|
|
63
|
+
canUndo: boolean;
|
|
64
|
+
/** Whether redo is available */
|
|
65
|
+
canRedo: boolean;
|
|
66
|
+
/** Whether undo/redo is currently blocked (e.g., during persist) */
|
|
67
|
+
isBlocked: boolean;
|
|
68
|
+
/** Number of entries in undo stack */
|
|
69
|
+
undoCount: number;
|
|
70
|
+
/** Number of entries in redo stack */
|
|
71
|
+
redoCount: number;
|
|
72
|
+
}
|
|
73
|
+
export type { StoreAffectedKeys } from '../core/actionClassification.js';
|
|
74
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/undo/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAA;AACxE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAC3D,OAAO,KAAK,EACX,mBAAmB,EACnB,kBAAkB,EAClB,UAAU,EACV,MAAM,2BAA2B,CAAA;AAElC;;;GAGG;AACH,MAAM,WAAW,oBAAoB;IACpC,2CAA2C;IAC3C,eAAe,EAAE,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CAAA;IAC5C,8BAA8B;IAC9B,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAA;IAChD,2BAA2B;IAC3B,aAAa,EAAE,GAAG,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAA;IAC9C,uDAAuD;IACvD,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAA;CACpC;AAED;;;GAGG;AACH,MAAM,WAAW,SAAS;IACzB,uCAAuC;IACvC,EAAE,EAAE,MAAM,CAAA;IACV,oCAAoC;IACpC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,6CAA6C;IAC7C,cAAc,EAAE,oBAAoB,CAAA;IACpC,0DAA0D;IAC1D,YAAY,EAAE,iBAAiB,CAAA;IAC/B,kCAAkC;IAClC,SAAS,EAAE,MAAM,CAAA;CACjB;AAED;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAChC,6DAA6D;IAC7D,cAAc,EAAE,oBAAoB,CAAA;IACpC,gCAAgC;IAChC,YAAY,EAAE,iBAAiB,CAAA;IAC/B,qCAAqC;IACrC,SAAS,EAAE,MAAM,CAAA;IACjB,yCAAyC;IACzC,KAAK,CAAC,EAAE,MAAM,CAAA;CACd;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IACjC,4DAA4D;IAC5D,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,qEAAqE;IACrE,UAAU,CAAC,EAAE,MAAM,CAAA;CACnB;AAED;;;GAGG;AACH,MAAM,WAAW,SAAS;IACzB,gCAAgC;IAChC,OAAO,EAAE,OAAO,CAAA;IAChB,gCAAgC;IAChC,OAAO,EAAE,OAAO,CAAA;IAChB,oEAAoE;IACpE,SAAS,EAAE,OAAO,CAAA;IAClB,sCAAsC;IACtC,SAAS,EAAE,MAAM,CAAA;IACjB,sCAAsC;IACtC,SAAS,EAAE,MAAM,CAAA;CACjB;AAGD,YAAY,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAA"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { HasManyParams } from '../selection/SelectionScope.js';
|
|
2
|
+
/**
|
|
3
|
+
* Generates an alias for a has-many relation based on field name and parameters.
|
|
4
|
+
*
|
|
5
|
+
* If no parameters are provided or all are undefined, returns the fieldName as-is.
|
|
6
|
+
* Otherwise, generates a deterministic alias by hashing the parameters.
|
|
7
|
+
*
|
|
8
|
+
* @param fieldName - The original field name
|
|
9
|
+
* @param params - Optional has-many parameters (filter, orderBy, limit, offset)
|
|
10
|
+
* @returns The alias to use for this has-many relation
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```ts
|
|
14
|
+
* // No params - returns fieldName
|
|
15
|
+
* generateHasManyAlias('tags') // => 'tags'
|
|
16
|
+
*
|
|
17
|
+
* // With filter - generates unique alias
|
|
18
|
+
* generateHasManyAlias('tags', { filter: { active: true } }) // => 'tags_a7x9k2'
|
|
19
|
+
*
|
|
20
|
+
* // Different params - different aliases
|
|
21
|
+
* generateHasManyAlias('tags', { filter: { active: false } }) // => 'tags_b3m1p8'
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export declare function generateHasManyAlias(fieldName: string, params?: HasManyParams): string;
|
|
25
|
+
//# sourceMappingURL=aliasGenerator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aliasGenerator.d.ts","sourceRoot":"","sources":["../../src/utils/aliasGenerator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAA;AAEnE;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,aAAa,GAAG,MAAM,CA+BtF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deepEqual.d.ts","sourceRoot":"","sources":["../../src/utils/deepEqual.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,GAAG,OAAO,CA4BzD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC1C,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAA"}
|
package/package.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@contember/bindx",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Type-safe data binding framework (core)",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./src/index.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": "./src/index.ts"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsc --build",
|
|
12
|
+
"typecheck": "tsc --build"
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist",
|
|
16
|
+
"src"
|
|
17
|
+
],
|
|
18
|
+
"license": "MIT",
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"@contember/client-content": "^2.1.0-alpha.30",
|
|
21
|
+
"@contember/graphql-builder": "^2.1.0-alpha.30",
|
|
22
|
+
"@contember/graphql-client": "^2.1.0-alpha.30"
|
|
23
|
+
},
|
|
24
|
+
"repository": {
|
|
25
|
+
"type": "git",
|
|
26
|
+
"url": "https://github.com/contember/bindx.git",
|
|
27
|
+
"directory": "packages/bindx"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
import { GraphQlClient } from '@contember/graphql-client'
|
|
2
|
+
import {
|
|
3
|
+
ContentClient,
|
|
4
|
+
ContentQueryBuilder,
|
|
5
|
+
ContentEntitySelection,
|
|
6
|
+
SchemaNames,
|
|
7
|
+
ContentQuery,
|
|
8
|
+
type EntitySelectionManyArgs,
|
|
9
|
+
type EntitySelectionOneArgs,
|
|
10
|
+
type EntitySelectionColumnArgs,
|
|
11
|
+
type ContentClientInput,
|
|
12
|
+
} from '@contember/client-content'
|
|
13
|
+
import { type Input } from '@contember/schema'
|
|
14
|
+
import type { QuerySpec, QueryFieldSpec } from '../selection/buildQuery.js'
|
|
15
|
+
import type { BackendAdapter, Query, QueryResult, QueryOptions, GetQuery, ListQuery, PersistResult, CreateResult, DeleteResult } from './types.js'
|
|
16
|
+
import type { ContemberMutationResult } from '../errors/pathMapper.js'
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Options for ContemberAdapter
|
|
20
|
+
*/
|
|
21
|
+
export interface ContemberAdapterOptions {
|
|
22
|
+
/** GraphQL client instance */
|
|
23
|
+
client: GraphQlClient
|
|
24
|
+
/** Contember schema names for query building */
|
|
25
|
+
schema: SchemaNames
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Backend adapter for Contember Content API.
|
|
30
|
+
* Uses @contember/client-content for type-safe GraphQL operations.
|
|
31
|
+
*/
|
|
32
|
+
export class ContemberAdapter implements BackendAdapter {
|
|
33
|
+
|
|
34
|
+
constructor(
|
|
35
|
+
private readonly contentClient: ContentClient,
|
|
36
|
+
private readonly queryBuilder: ContentQueryBuilder,
|
|
37
|
+
) {
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async query(queries: readonly Query[], options?: QueryOptions): Promise<QueryResult[]> {
|
|
41
|
+
if (queries.length === 0) return []
|
|
42
|
+
|
|
43
|
+
// Build ContentQuery for each query
|
|
44
|
+
const contentQueries: Record<string, ContentQuery<unknown>> = {}
|
|
45
|
+
|
|
46
|
+
for (let i = 0; i < queries.length; i++) {
|
|
47
|
+
const q = queries[i]!
|
|
48
|
+
const key = `q${i}`
|
|
49
|
+
|
|
50
|
+
if (q.type === 'get') {
|
|
51
|
+
contentQueries[key] = this.buildGetQuery(q)
|
|
52
|
+
} else {
|
|
53
|
+
contentQueries[key] = this.buildListQuery(q)
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Execute all queries in single request
|
|
58
|
+
const results = await this.contentClient.query(contentQueries, {
|
|
59
|
+
signal: options?.signal,
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
// Map results back to QueryResult array
|
|
63
|
+
// Content client transforms already unwrap paginateRelation → flat arrays
|
|
64
|
+
return queries.map((q, i) => {
|
|
65
|
+
const key = `q${i}`
|
|
66
|
+
const data = (results as Record<string, unknown>)[key]
|
|
67
|
+
|
|
68
|
+
if (q.type === 'get') {
|
|
69
|
+
return { type: 'get' as const, data: data as Record<string, unknown> | null }
|
|
70
|
+
} else {
|
|
71
|
+
return { type: 'list' as const, data: (data ?? []) as readonly Record<string, unknown>[] }
|
|
72
|
+
}
|
|
73
|
+
})
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
private buildGetQuery(query: GetQuery): ContentQuery<unknown> {
|
|
77
|
+
const selection = this.buildEntitySelection(query.spec)
|
|
78
|
+
return this.queryBuilder.get(query.entityType, { by: query.by }, selection)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
private buildListQuery(query: ListQuery): ContentQuery<unknown> {
|
|
82
|
+
const selection = this.buildEntitySelection(query.spec)
|
|
83
|
+
const args: ContentClientInput.AnyListQueryInput = {
|
|
84
|
+
filter: query.filter as Input.OptionalWhere | undefined,
|
|
85
|
+
orderBy: query.orderBy as ContentClientInput.AnyOrderBy | undefined,
|
|
86
|
+
limit: query.limit,
|
|
87
|
+
offset: query.offset,
|
|
88
|
+
}
|
|
89
|
+
return this.queryBuilder.list(query.entityType, args, selection)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
async persist(
|
|
93
|
+
entityType: string,
|
|
94
|
+
id: string,
|
|
95
|
+
changes: Record<string, unknown>,
|
|
96
|
+
): Promise<PersistResult> {
|
|
97
|
+
const mutation = this.queryBuilder.update(entityType, {
|
|
98
|
+
by: { id },
|
|
99
|
+
data: changes as Input.UpdateDataInput,
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
const result = await this.contentClient.mutate(mutation)
|
|
103
|
+
|
|
104
|
+
if (!result.ok) {
|
|
105
|
+
return {
|
|
106
|
+
ok: false,
|
|
107
|
+
errorMessage: result.errorMessage ?? `Failed to update ${entityType}:${id}`,
|
|
108
|
+
mutationResult: this.toMutationResult(result),
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return { ok: true }
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
async create(
|
|
116
|
+
entityType: string,
|
|
117
|
+
data: Record<string, unknown>,
|
|
118
|
+
): Promise<CreateResult> {
|
|
119
|
+
// Build selection to return created entity
|
|
120
|
+
const selection = (s: ContentEntitySelection) => s.$('id')
|
|
121
|
+
|
|
122
|
+
const mutation = this.queryBuilder.create(entityType, { data: data as Input.CreateDataInput }, selection)
|
|
123
|
+
const result = await this.contentClient.mutate(mutation)
|
|
124
|
+
|
|
125
|
+
if (!result.ok) {
|
|
126
|
+
return {
|
|
127
|
+
ok: false,
|
|
128
|
+
errorMessage: result.errorMessage ?? `Failed to create ${entityType}`,
|
|
129
|
+
mutationResult: this.toMutationResult(result),
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return {
|
|
134
|
+
ok: true,
|
|
135
|
+
data: result.node as Record<string, unknown>,
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
async delete(entityType: string, id: string): Promise<DeleteResult> {
|
|
140
|
+
const mutation = this.queryBuilder.delete(entityType, { by: { id } })
|
|
141
|
+
const result = await this.contentClient.mutate(mutation)
|
|
142
|
+
|
|
143
|
+
if (!result.ok) {
|
|
144
|
+
return {
|
|
145
|
+
ok: false,
|
|
146
|
+
errorMessage: result.errorMessage ?? `Failed to delete ${entityType}:${id}`,
|
|
147
|
+
mutationResult: this.toMutationResult(result),
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return { ok: true }
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Converts Contember mutation result to our ContemberMutationResult type.
|
|
156
|
+
*/
|
|
157
|
+
private toMutationResult(result: {
|
|
158
|
+
ok: boolean
|
|
159
|
+
errorMessage: string | null
|
|
160
|
+
errors: Array<{ paths: Array<Array<{ field: string } | { index: number; alias: string | null }>>; message: string; type: string }>
|
|
161
|
+
validation: { valid: boolean; errors: Array<{ path: Array<{ field: string } | { index: number; alias: string | null }>; message: { text: string } }> }
|
|
162
|
+
}): ContemberMutationResult {
|
|
163
|
+
return {
|
|
164
|
+
ok: result.ok,
|
|
165
|
+
errorMessage: result.errorMessage,
|
|
166
|
+
errors: result.errors.map(e => ({
|
|
167
|
+
paths: e.paths,
|
|
168
|
+
message: e.message,
|
|
169
|
+
type: e.type,
|
|
170
|
+
})),
|
|
171
|
+
validation: {
|
|
172
|
+
valid: result.validation.valid,
|
|
173
|
+
errors: result.validation.errors.map(e => ({
|
|
174
|
+
path: e.path,
|
|
175
|
+
message: { text: e.message.text },
|
|
176
|
+
})),
|
|
177
|
+
},
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Builds ContentEntitySelection from QuerySpec
|
|
183
|
+
*/
|
|
184
|
+
private buildEntitySelection(
|
|
185
|
+
query: QuerySpec,
|
|
186
|
+
): (selection: ContentEntitySelection) => ContentEntitySelection {
|
|
187
|
+
return (selection: ContentEntitySelection) => {
|
|
188
|
+
return this.applyFieldsToSelection(selection, query.fields)
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Recursively applies QueryFieldSpec[] to ContentEntitySelection
|
|
194
|
+
*/
|
|
195
|
+
private applyFieldsToSelection(
|
|
196
|
+
selection: ContentEntitySelection,
|
|
197
|
+
fields: QueryFieldSpec[],
|
|
198
|
+
): ContentEntitySelection {
|
|
199
|
+
let result = selection
|
|
200
|
+
|
|
201
|
+
for (const field of fields) {
|
|
202
|
+
const fieldName = field.sourcePath[0]
|
|
203
|
+
if (!fieldName) continue
|
|
204
|
+
|
|
205
|
+
if (field.nested) {
|
|
206
|
+
// Relation field (has-one or has-many)
|
|
207
|
+
const nestedCallback = (s: ContentEntitySelection) =>
|
|
208
|
+
this.applyFieldsToSelection(s, field.nested!.fields)
|
|
209
|
+
|
|
210
|
+
if (field.isArray) {
|
|
211
|
+
// has-many relation — always uses paginateRelation
|
|
212
|
+
const manyArgs: EntitySelectionManyArgs = {
|
|
213
|
+
...(field.name !== fieldName ? { as: field.name } : undefined),
|
|
214
|
+
...(field.filter !== undefined ? { filter: field.filter as Input.OptionalWhere } : undefined),
|
|
215
|
+
...(field.orderBy !== undefined ? { orderBy: field.orderBy as ContentClientInput.AnyOrderBy } : undefined),
|
|
216
|
+
...(field.limit !== undefined ? { limit: field.limit } : undefined),
|
|
217
|
+
...(field.offset !== undefined ? { offset: field.offset } : undefined),
|
|
218
|
+
...(field.totalCount ? { totalCount: true } : undefined),
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
result = result.$(fieldName, manyArgs, nestedCallback)
|
|
222
|
+
} else {
|
|
223
|
+
// has-one relation
|
|
224
|
+
const oneArgs: EntitySelectionOneArgs = {
|
|
225
|
+
...(field.name !== fieldName ? { as: field.name } : undefined),
|
|
226
|
+
}
|
|
227
|
+
result = result.$(fieldName, oneArgs, nestedCallback)
|
|
228
|
+
}
|
|
229
|
+
} else {
|
|
230
|
+
// Scalar field
|
|
231
|
+
const columnArgs: EntitySelectionColumnArgs | undefined =
|
|
232
|
+
field.name !== fieldName ? { as: field.name } : undefined
|
|
233
|
+
result = result.$(fieldName, columnArgs)
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
return result
|
|
238
|
+
}
|
|
239
|
+
}
|