@cratis/chronicle 0.2.0 → 0.2.1
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/EventStore.ts +8 -0
- package/IEventStore.ts +8 -0
- package/compliance/ComplianceContracts.ts +63 -0
- package/compliance/ComplianceMetadata.ts +19 -0
- package/compliance/ComplianceMetadataResolver.ts +51 -0
- package/compliance/ComplianceMetadataType.ts +36 -0
- package/compliance/index.ts +7 -0
- package/compliance/pii.ts +115 -0
- package/connection/ChronicleConnection.ts +19 -1
- package/connection/ChronicleServices.ts +6 -0
- package/dist/EventStore.d.ts +4 -0
- package/dist/EventStore.d.ts.map +1 -1
- package/dist/EventStore.js +6 -0
- package/dist/EventStore.js.map +1 -1
- package/dist/IEventStore.d.ts +6 -0
- package/dist/IEventStore.d.ts.map +1 -1
- package/dist/compliance/ComplianceContracts.d.ts +56 -0
- package/dist/compliance/ComplianceContracts.d.ts.map +1 -0
- package/dist/compliance/ComplianceContracts.js +25 -0
- package/dist/compliance/ComplianceContracts.js.map +1 -0
- package/dist/compliance/ComplianceMetadata.d.ts +15 -0
- package/dist/compliance/ComplianceMetadata.d.ts.map +1 -0
- package/dist/compliance/ComplianceMetadata.js +4 -0
- package/dist/compliance/ComplianceMetadata.js.map +1 -0
- package/dist/compliance/ComplianceMetadataResolver.d.ts +27 -0
- package/dist/compliance/ComplianceMetadataResolver.d.ts.map +1 -0
- package/dist/compliance/ComplianceMetadataResolver.js +45 -0
- package/dist/compliance/ComplianceMetadataResolver.js.map +1 -0
- package/dist/compliance/ComplianceMetadataType.d.ts +24 -0
- package/dist/compliance/ComplianceMetadataType.d.ts.map +1 -0
- package/dist/compliance/ComplianceMetadataType.js +32 -0
- package/dist/compliance/ComplianceMetadataType.js.map +1 -0
- package/dist/compliance/index.d.ts +5 -0
- package/dist/compliance/index.d.ts.map +1 -0
- package/dist/compliance/index.js +6 -0
- package/dist/compliance/index.js.map +1 -0
- package/dist/compliance/pii.d.ts +69 -0
- package/dist/compliance/pii.d.ts.map +1 -0
- package/dist/compliance/pii.js +106 -0
- package/dist/compliance/pii.js.map +1 -0
- package/dist/connection/ChronicleConnection.d.ts +3 -0
- package/dist/connection/ChronicleConnection.d.ts.map +1 -1
- package/dist/connection/ChronicleConnection.js +16 -2
- package/dist/connection/ChronicleConnection.js.map +1 -1
- package/dist/connection/ChronicleServices.d.ts +6 -1
- package/dist/connection/ChronicleServices.d.ts.map +1 -1
- package/dist/eventSequences/EventSequence.js +3 -3
- package/dist/eventSequences/EventSequence.js.map +1 -1
- package/dist/eventStoreSubscriptions/EventStoreSubscriptionBuilder.d.ts +20 -0
- package/dist/eventStoreSubscriptions/EventStoreSubscriptionBuilder.d.ts.map +1 -0
- package/dist/eventStoreSubscriptions/EventStoreSubscriptionBuilder.js +41 -0
- package/dist/eventStoreSubscriptions/EventStoreSubscriptionBuilder.js.map +1 -0
- package/dist/eventStoreSubscriptions/EventStoreSubscriptionDefinition.d.ts +12 -0
- package/dist/eventStoreSubscriptions/EventStoreSubscriptionDefinition.d.ts.map +1 -0
- package/dist/eventStoreSubscriptions/EventStoreSubscriptionDefinition.js +16 -0
- package/dist/eventStoreSubscriptions/EventStoreSubscriptionDefinition.js.map +1 -0
- package/dist/eventStoreSubscriptions/EventStoreSubscriptionId.d.ts +10 -0
- package/dist/eventStoreSubscriptions/EventStoreSubscriptionId.d.ts.map +1 -0
- package/dist/eventStoreSubscriptions/EventStoreSubscriptionId.js +16 -0
- package/dist/eventStoreSubscriptions/EventStoreSubscriptionId.js.map +1 -0
- package/dist/eventStoreSubscriptions/EventStoreSubscriptions.d.ts +21 -0
- package/dist/eventStoreSubscriptions/EventStoreSubscriptions.d.ts.map +1 -0
- package/dist/eventStoreSubscriptions/EventStoreSubscriptions.js +60 -0
- package/dist/eventStoreSubscriptions/EventStoreSubscriptions.js.map +1 -0
- package/dist/eventStoreSubscriptions/IEventStoreSubscriptionBuilder.d.ts +20 -0
- package/dist/eventStoreSubscriptions/IEventStoreSubscriptionBuilder.d.ts.map +1 -0
- package/dist/eventStoreSubscriptions/IEventStoreSubscriptionBuilder.js +4 -0
- package/dist/eventStoreSubscriptions/IEventStoreSubscriptionBuilder.js.map +1 -0
- package/dist/eventStoreSubscriptions/IEventStoreSubscriptions.d.ts +21 -0
- package/dist/eventStoreSubscriptions/IEventStoreSubscriptions.d.ts.map +1 -0
- package/dist/eventStoreSubscriptions/IEventStoreSubscriptions.js +4 -0
- package/dist/eventStoreSubscriptions/IEventStoreSubscriptions.js.map +1 -0
- package/dist/eventStoreSubscriptions/contracts.d.ts +71 -0
- package/dist/eventStoreSubscriptions/contracts.d.ts.map +1 -0
- package/dist/eventStoreSubscriptions/contracts.js +310 -0
- package/dist/eventStoreSubscriptions/contracts.js.map +1 -0
- package/dist/eventStoreSubscriptions/index.d.ts +7 -0
- package/dist/eventStoreSubscriptions/index.d.ts.map +1 -0
- package/dist/eventStoreSubscriptions/index.js +7 -0
- package/dist/eventStoreSubscriptions/index.js.map +1 -0
- package/dist/events/constraints/IUniqueConstraintBuilder.d.ts +3 -2
- package/dist/events/constraints/IUniqueConstraintBuilder.d.ts.map +1 -1
- package/dist/events/constraints/UniqueConstraintBuilder.d.ts +2 -8
- package/dist/events/constraints/UniqueConstraintBuilder.d.ts.map +1 -1
- package/dist/events/constraints/UniqueConstraintBuilder.js +4 -15
- package/dist/events/constraints/UniqueConstraintBuilder.js.map +1 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/reactors/Reactors.js +1 -1
- package/dist/reactors/Reactors.js.map +1 -1
- package/dist/readModels/IMaterializedReadModels.d.ts +23 -0
- package/dist/readModels/IMaterializedReadModels.d.ts.map +1 -0
- package/dist/readModels/IMaterializedReadModels.js +4 -0
- package/dist/readModels/IMaterializedReadModels.js.map +1 -0
- package/dist/readModels/IReadModels.d.ts +75 -0
- package/dist/readModels/IReadModels.d.ts.map +1 -0
- package/dist/readModels/IReadModels.js +4 -0
- package/dist/readModels/IReadModels.js.map +1 -0
- package/dist/readModels/MaterializedReadModels.d.ts +25 -0
- package/dist/readModels/MaterializedReadModels.d.ts.map +1 -0
- package/dist/readModels/MaterializedReadModels.js +125 -0
- package/dist/readModels/MaterializedReadModels.js.map +1 -0
- package/dist/readModels/ReadModelChangeset.d.ts +14 -0
- package/dist/readModels/ReadModelChangeset.d.ts.map +1 -0
- package/dist/readModels/ReadModelChangeset.js +4 -0
- package/dist/readModels/ReadModelChangeset.js.map +1 -0
- package/dist/readModels/ReadModelSnapshot.d.ts +15 -0
- package/dist/readModels/ReadModelSnapshot.d.ts.map +1 -0
- package/dist/readModels/ReadModelSnapshot.js +4 -0
- package/dist/readModels/ReadModelSnapshot.js.map +1 -0
- package/dist/readModels/ReadModels.d.ts +42 -0
- package/dist/readModels/ReadModels.d.ts.map +1 -0
- package/dist/readModels/ReadModels.js +270 -0
- package/dist/readModels/ReadModels.js.map +1 -0
- package/dist/readModels/index.d.ts +6 -0
- package/dist/readModels/index.d.ts.map +1 -1
- package/dist/readModels/index.js +2 -0
- package/dist/readModels/index.js.map +1 -1
- package/dist/readModels/readModel.d.ts.map +1 -1
- package/dist/readModels/readModel.js +0 -20
- package/dist/readModels/readModel.js.map +1 -1
- package/dist/reducers/Reducers.d.ts +1 -0
- package/dist/reducers/Reducers.d.ts.map +1 -1
- package/dist/reducers/Reducers.js +10 -3
- package/dist/reducers/Reducers.js.map +1 -1
- package/dist/schemas/JsonSchemaGenerator.d.ts +9 -0
- package/dist/schemas/JsonSchemaGenerator.d.ts.map +1 -1
- package/dist/schemas/JsonSchemaGenerator.js +53 -1
- package/dist/schemas/JsonSchemaGenerator.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types/TypeIntrospector.d.ts +11 -1
- package/dist/types/TypeIntrospector.d.ts.map +1 -1
- package/dist/types/TypeIntrospector.js +29 -3
- package/dist/types/TypeIntrospector.js.map +1 -1
- package/eventSequences/EventSequence.ts +3 -3
- package/eventStoreSubscriptions/EventStoreSubscriptionBuilder.ts +52 -0
- package/eventStoreSubscriptions/EventStoreSubscriptionDefinition.ts +16 -0
- package/eventStoreSubscriptions/EventStoreSubscriptionId.ts +14 -0
- package/eventStoreSubscriptions/EventStoreSubscriptions.ts +74 -0
- package/eventStoreSubscriptions/IEventStoreSubscriptionBuilder.ts +24 -0
- package/eventStoreSubscriptions/IEventStoreSubscriptions.ts +29 -0
- package/eventStoreSubscriptions/contracts.ts +372 -0
- package/eventStoreSubscriptions/index.ts +9 -0
- package/events/constraints/IUniqueConstraintBuilder.ts +3 -2
- package/events/constraints/UniqueConstraintBuilder.ts +5 -17
- package/index.ts +6 -0
- package/package.json +17 -7
- package/reactors/Reactors.ts +1 -1
- package/readModels/IMaterializedReadModels.ts +27 -0
- package/readModels/IReadModels.ts +87 -0
- package/readModels/MaterializedReadModels.ts +151 -0
- package/readModels/ReadModelChangeset.ts +19 -0
- package/readModels/ReadModelSnapshot.ts +21 -0
- package/readModels/ReadModels.ts +333 -0
- package/readModels/index.ts +6 -0
- package/readModels/readModel.ts +0 -22
- package/reducers/Reducers.ts +12 -3
- package/schemas/JsonSchemaGenerator.ts +61 -1
- package/types/TypeIntrospector.ts +32 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cratis/chronicle",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "TypeScript idiomatic client for Cratis Chronicle",
|
|
5
5
|
"author": "Cratis",
|
|
6
6
|
"license": "MIT",
|
|
@@ -36,6 +36,16 @@
|
|
|
36
36
|
"import": "./dist/eventSequences/index.js",
|
|
37
37
|
"default": "./dist/eventSequences/index.js"
|
|
38
38
|
},
|
|
39
|
+
"./eventStoreSubscriptions": {
|
|
40
|
+
"types": "./dist/eventStoreSubscriptions/index.d.ts",
|
|
41
|
+
"import": "./dist/eventStoreSubscriptions/index.js",
|
|
42
|
+
"default": "./dist/eventStoreSubscriptions/index.js"
|
|
43
|
+
},
|
|
44
|
+
"./compliance": {
|
|
45
|
+
"types": "./dist/compliance/index.d.ts",
|
|
46
|
+
"import": "./dist/compliance/index.js",
|
|
47
|
+
"default": "./dist/compliance/index.js"
|
|
48
|
+
},
|
|
39
49
|
"./reactors": {
|
|
40
50
|
"types": "./dist/reactors/index.d.ts",
|
|
41
51
|
"import": "./dist/reactors/index.js",
|
|
@@ -124,16 +134,16 @@
|
|
|
124
134
|
},
|
|
125
135
|
"dependencies": {
|
|
126
136
|
"@bufbuild/protobuf": "^2.12.0",
|
|
127
|
-
"@cratis/chronicle.contracts": "
|
|
128
|
-
"@cratis/fundamentals": "
|
|
129
|
-
"@grpc/grpc-js": "^1.14.
|
|
137
|
+
"@cratis/chronicle.contracts": "15.33.3",
|
|
138
|
+
"@cratis/fundamentals": "7.14.0",
|
|
139
|
+
"@grpc/grpc-js": "^1.14.4",
|
|
130
140
|
"@opentelemetry/api": "^1.9.1",
|
|
131
|
-
"nice-grpc": "^2.1.
|
|
132
|
-
"nice-grpc-common": "^2.0.
|
|
141
|
+
"nice-grpc": "^2.1.16",
|
|
142
|
+
"nice-grpc-common": "^2.0.3",
|
|
133
143
|
"reflect-metadata": "^0.2.2"
|
|
134
144
|
},
|
|
135
145
|
"devDependencies": {
|
|
136
|
-
"@types/node": "^25.
|
|
146
|
+
"@types/node": "^25.9.1",
|
|
137
147
|
"typescript": "^6.0.3"
|
|
138
148
|
}
|
|
139
149
|
}
|
package/reactors/Reactors.ts
CHANGED
|
@@ -250,7 +250,7 @@ export class Reactors implements IReactors {
|
|
|
250
250
|
this._logger.info('Invoking reactor handler', {
|
|
251
251
|
reactorId: id,
|
|
252
252
|
method: entry.methodName,
|
|
253
|
-
sequenceNumber: event.Context!.SequenceNumber,
|
|
253
|
+
sequenceNumber: event.Context!.SequenceNumber.toString(),
|
|
254
254
|
eventTypeId
|
|
255
255
|
});
|
|
256
256
|
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// Copyright (c) Cratis. All rights reserved.
|
|
2
|
+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
3
|
+
|
|
4
|
+
import type { Constructor } from '@cratis/fundamentals';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Defines a system for working with materialized read model instances stored in the sink.
|
|
8
|
+
*/
|
|
9
|
+
export interface IMaterializedReadModels {
|
|
10
|
+
/**
|
|
11
|
+
* Gets paginated instances of a read model from the sink.
|
|
12
|
+
* @param readModelType - The read model type to retrieve.
|
|
13
|
+
* @param skip - Number of instances to skip. Defaults to zero.
|
|
14
|
+
* @param take - Number of instances to retrieve. Defaults to 50.
|
|
15
|
+
* @returns Collection of read model instances.
|
|
16
|
+
*/
|
|
17
|
+
getInstances<TReadModel>(readModelType: Constructor<TReadModel>, skip?: number, take?: number): Promise<TReadModel[]>;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Observes changes for a paginated window of read model instances from the sink.
|
|
21
|
+
* @param readModelType - The read model type to observe.
|
|
22
|
+
* @param skip - Number of instances to skip. Defaults to zero.
|
|
23
|
+
* @param take - Number of instances to observe. Defaults to 50.
|
|
24
|
+
* @returns An async iterable of read model instance collections.
|
|
25
|
+
*/
|
|
26
|
+
observeInstances<TReadModel>(readModelType: Constructor<TReadModel>, skip?: number, take?: number): AsyncIterable<TReadModel[]>;
|
|
27
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
// Copyright (c) Cratis. All rights reserved.
|
|
2
|
+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
3
|
+
|
|
4
|
+
import type { Constructor } from '@cratis/fundamentals';
|
|
5
|
+
import type { IMaterializedReadModels } from './IMaterializedReadModels';
|
|
6
|
+
import type { ReadModelChangeset } from './ReadModelChangeset';
|
|
7
|
+
import type { ReadModelSnapshot } from './ReadModelSnapshot';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Defines a system that works with read models in the event store.
|
|
11
|
+
*/
|
|
12
|
+
export interface IReadModels {
|
|
13
|
+
/**
|
|
14
|
+
* Gets the {@link IMaterializedReadModels} for working with materialized read model instances from the sink.
|
|
15
|
+
*/
|
|
16
|
+
readonly materialized: IMaterializedReadModels;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Registers all discovered read models.
|
|
20
|
+
* @returns A promise that resolves when registration completes.
|
|
21
|
+
*/
|
|
22
|
+
register(): Promise<void>;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Registers a specific read model type.
|
|
26
|
+
* @param readModelType - The read model type to register.
|
|
27
|
+
* @returns A promise that resolves when registration completes.
|
|
28
|
+
*/
|
|
29
|
+
register<TReadModel>(readModelType: Constructor<TReadModel>): Promise<void>;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Gets a read model instance by key.
|
|
33
|
+
* @param readModelType - The read model type to retrieve.
|
|
34
|
+
* @param key - The read model key.
|
|
35
|
+
* @param sessionId - Optional session identifier.
|
|
36
|
+
* @returns The read model instance.
|
|
37
|
+
*/
|
|
38
|
+
getInstanceById<TReadModel>(readModelType: Constructor<TReadModel>, key: string, sessionId?: string): Promise<TReadModel>;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Gets all instances of a read model.
|
|
42
|
+
* @param readModelType - The read model type to retrieve.
|
|
43
|
+
* @param eventCount - Optional maximum number of events to process.
|
|
44
|
+
* @returns The read model instances.
|
|
45
|
+
*/
|
|
46
|
+
getInstances<TReadModel>(readModelType: Constructor<TReadModel>, eventCount?: bigint): Promise<TReadModel[]>;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Gets snapshots for a read model instance by key.
|
|
50
|
+
* @param readModelType - The read model type to retrieve snapshots for.
|
|
51
|
+
* @param key - The read model key.
|
|
52
|
+
* @returns The read model snapshots.
|
|
53
|
+
*/
|
|
54
|
+
getSnapshotsById<TReadModel>(readModelType: Constructor<TReadModel>, key: string): Promise<ReadModelSnapshot<TReadModel>[]>;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Watches changes for a specific read model type.
|
|
58
|
+
* @param readModelType - The read model type to observe.
|
|
59
|
+
* @returns An async iterable of read model changes.
|
|
60
|
+
*/
|
|
61
|
+
watch<TReadModel>(readModelType: Constructor<TReadModel>): AsyncIterable<ReadModelChangeset<TReadModel>>;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Dehydrates a read model session.
|
|
65
|
+
* @param sessionId - The session identifier to dehydrate.
|
|
66
|
+
* @param readModelType - The read model type.
|
|
67
|
+
* @param key - The read model key.
|
|
68
|
+
* @returns A promise that resolves when dehydration completes.
|
|
69
|
+
*/
|
|
70
|
+
dehydrateSession<TReadModel>(sessionId: string, readModelType: Constructor<TReadModel>, key: string): Promise<void>;
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Releases (decrypts) PII properties in a read model instance.
|
|
74
|
+
* @param readModelType - The read model type.
|
|
75
|
+
* @param instance - The read model instance with encrypted PII.
|
|
76
|
+
* @returns The read model instance with decrypted PII values.
|
|
77
|
+
*/
|
|
78
|
+
release<TReadModel>(readModelType: Constructor<TReadModel>, instance: TReadModel): Promise<TReadModel>;
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Releases (decrypts) PII properties in multiple read model instances.
|
|
82
|
+
* @param readModelType - The read model type.
|
|
83
|
+
* @param instances - The read model instances with encrypted PII.
|
|
84
|
+
* @returns The read model instances with decrypted PII values.
|
|
85
|
+
*/
|
|
86
|
+
releaseMany<TReadModel>(readModelType: Constructor<TReadModel>, instances: TReadModel[]): Promise<TReadModel[]>;
|
|
87
|
+
}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
// Copyright (c) Cratis. All rights reserved.
|
|
2
|
+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
3
|
+
|
|
4
|
+
import type { Constructor } from '@cratis/fundamentals';
|
|
5
|
+
import { JsonSerializer } from '@cratis/fundamentals';
|
|
6
|
+
import { ChronicleConnection } from '../connection';
|
|
7
|
+
import { JsonSchemaGenerator } from '../schemas';
|
|
8
|
+
import { getReadModelMetadata } from './readModel';
|
|
9
|
+
import type { IMaterializedReadModels } from './IMaterializedReadModels';
|
|
10
|
+
|
|
11
|
+
const defaultTake = 50;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Implements {@link IMaterializedReadModels} by working with the Chronicle materialized read model gRPC service.
|
|
15
|
+
*/
|
|
16
|
+
export class MaterializedReadModels implements IMaterializedReadModels {
|
|
17
|
+
constructor(
|
|
18
|
+
private readonly _eventStore: string,
|
|
19
|
+
private readonly _namespace: string,
|
|
20
|
+
private readonly _connection: ChronicleConnection
|
|
21
|
+
) {}
|
|
22
|
+
|
|
23
|
+
/** @inheritdoc */
|
|
24
|
+
async getInstances<TReadModel>(readModelType: Constructor<TReadModel>, skip: number = 0, take: number = defaultTake): Promise<TReadModel[]> {
|
|
25
|
+
const readModelIdentifier = this.resolveIdentifier(readModelType);
|
|
26
|
+
const { page, pageSize, skipWithinPage } = this.toPageParams(skip, take);
|
|
27
|
+
|
|
28
|
+
const response = await this._connection.materializedReadModels.getInstances({
|
|
29
|
+
EventStore: this._eventStore,
|
|
30
|
+
Namespace: this._namespace,
|
|
31
|
+
ReadModel: readModelIdentifier,
|
|
32
|
+
Page: page,
|
|
33
|
+
PageSize: pageSize
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
let instances = response.Instances.map(json => this.deserialize(readModelType, json));
|
|
37
|
+
|
|
38
|
+
if (skipWithinPage > 0) {
|
|
39
|
+
instances = instances.slice(skipWithinPage);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return this.releaseInstances(readModelType, instances);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** @inheritdoc */
|
|
46
|
+
async *observeInstances<TReadModel>(readModelType: Constructor<TReadModel>, skip: number = 0, take: number = defaultTake): AsyncIterable<TReadModel[]> {
|
|
47
|
+
const readModelIdentifier = this.resolveIdentifier(readModelType);
|
|
48
|
+
const { page, pageSize, skipWithinPage } = this.toPageParams(skip, take);
|
|
49
|
+
|
|
50
|
+
for await (const response of this._connection.materializedReadModels.observeInstances({
|
|
51
|
+
EventStore: this._eventStore,
|
|
52
|
+
Namespace: this._namespace,
|
|
53
|
+
ReadModel: readModelIdentifier,
|
|
54
|
+
Page: page,
|
|
55
|
+
PageSize: pageSize
|
|
56
|
+
})) {
|
|
57
|
+
let instances = response.Instances.map(json => this.deserialize(readModelType, json));
|
|
58
|
+
|
|
59
|
+
if (skipWithinPage > 0) {
|
|
60
|
+
instances = instances.slice(skipWithinPage);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
yield await this.releaseInstances(readModelType, instances);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
private resolveIdentifier<TReadModel>(readModelType: Constructor<TReadModel>): string {
|
|
68
|
+
const metadata = getReadModelMetadata(readModelType);
|
|
69
|
+
return metadata?.id.value ?? readModelType.name;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
private toPageParams(skip: number, take: number): { page: number; pageSize: number; skipWithinPage: number } {
|
|
73
|
+
if (take <= 0) {
|
|
74
|
+
return { page: 0, pageSize: Number.MAX_SAFE_INTEGER, skipWithinPage: 0 };
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const page = skip > 0 ? Math.floor(skip / take) : 0;
|
|
78
|
+
const skipWithinPage = skip % take;
|
|
79
|
+
|
|
80
|
+
return { page, pageSize: take, skipWithinPage };
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
private deserialize<TReadModel>(readModelType: Constructor<TReadModel>, json: string): TReadModel {
|
|
84
|
+
if (!json) {
|
|
85
|
+
return Object.create(readModelType.prototype) as TReadModel;
|
|
86
|
+
}
|
|
87
|
+
return JsonSerializer.deserialize(readModelType as Constructor<object>, json) as TReadModel;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
private async releaseInstances<TReadModel>(readModelType: Constructor<TReadModel>, instances: TReadModel[]): Promise<TReadModel[]> {
|
|
91
|
+
const schema = this.getSchema(readModelType);
|
|
92
|
+
if (!this.schemaHasComplianceMetadata(schema)) {
|
|
93
|
+
return instances;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return Promise.all(instances.map(instance => this.releaseInstance(readModelType, instance, schema)));
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
private async releaseInstance<TReadModel>(readModelType: Constructor<TReadModel>, instance: TReadModel, schema: string): Promise<TReadModel> {
|
|
100
|
+
const subject = this.extractSubject(instance);
|
|
101
|
+
if (!subject) {
|
|
102
|
+
return instance;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const payload = JsonSerializer.serialize(instance);
|
|
106
|
+
const response = await this._connection.compliance.release({
|
|
107
|
+
EventStore: this._eventStore,
|
|
108
|
+
Namespace: this._namespace,
|
|
109
|
+
Subject: subject,
|
|
110
|
+
Schema: schema,
|
|
111
|
+
Payload: payload
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
if (response.HasError) {
|
|
115
|
+
return instance;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return this.deserialize(readModelType, response.Payload);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
private getSchema<TReadModel>(readModelType: Constructor<TReadModel>): string {
|
|
122
|
+
const metadata = getReadModelMetadata(readModelType);
|
|
123
|
+
if (metadata) {
|
|
124
|
+
return JSON.stringify(metadata.schema);
|
|
125
|
+
}
|
|
126
|
+
return JSON.stringify(JsonSchemaGenerator.generate(readModelType) ?? JsonSchemaGenerator.createEmptySchema(readModelType.name));
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
private schemaHasComplianceMetadata(schema: string): boolean {
|
|
130
|
+
try {
|
|
131
|
+
const parsed = JSON.parse(schema) as Record<string, unknown>;
|
|
132
|
+
const properties = parsed.properties as Record<string, Record<string, unknown>> | undefined;
|
|
133
|
+
if (!properties) {
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
return Object.values(properties).some(
|
|
137
|
+
property => Array.isArray(property.compliance) && (property.compliance as unknown[]).length > 0
|
|
138
|
+
);
|
|
139
|
+
} catch {
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
private extractSubject<TReadModel>(instance: TReadModel): string | undefined {
|
|
145
|
+
const anyInstance = instance as Record<string, unknown>;
|
|
146
|
+
if (anyInstance.id !== undefined && anyInstance.id !== null) {
|
|
147
|
+
return String(anyInstance.id);
|
|
148
|
+
}
|
|
149
|
+
return undefined;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// Copyright (c) Cratis. All rights reserved.
|
|
2
|
+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Represents a change observed for a read model.
|
|
6
|
+
*/
|
|
7
|
+
export interface ReadModelChangeset<TReadModel> {
|
|
8
|
+
/** The namespace the change belongs to. */
|
|
9
|
+
readonly namespace: string;
|
|
10
|
+
|
|
11
|
+
/** The read model key. */
|
|
12
|
+
readonly key: string;
|
|
13
|
+
|
|
14
|
+
/** The current read model state. */
|
|
15
|
+
readonly readModel: TReadModel;
|
|
16
|
+
|
|
17
|
+
/** Whether the read model was removed. */
|
|
18
|
+
readonly removed: boolean;
|
|
19
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// Copyright (c) Cratis. All rights reserved.
|
|
2
|
+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
3
|
+
|
|
4
|
+
import type { AppendedEvent, Guid as ContractsGuid } from '@cratis/chronicle.contracts';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Represents a read model snapshot together with the events that produced it.
|
|
8
|
+
*/
|
|
9
|
+
export interface ReadModelSnapshot<TReadModel> {
|
|
10
|
+
/** The read model state at the snapshot. */
|
|
11
|
+
readonly readModel: TReadModel;
|
|
12
|
+
|
|
13
|
+
/** The events that were applied to reach the snapshot. */
|
|
14
|
+
readonly events: AppendedEvent[];
|
|
15
|
+
|
|
16
|
+
/** When the snapshot occurred. */
|
|
17
|
+
readonly occurred: Date | undefined;
|
|
18
|
+
|
|
19
|
+
/** The correlation identifier for the snapshot, when available. */
|
|
20
|
+
readonly correlationId: ContractsGuid | undefined;
|
|
21
|
+
}
|