@event-driven-io/emmett-mongodb 0.23.0-alpha.9 → 0.24.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/index.cjs +315 -23
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +52 -21
- package/dist/index.d.ts +52 -21
- package/dist/index.js +303 -11
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.d.ts
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import { Event,
|
|
1
|
+
import { Event, ProjectionHandler, TypedProjectionDefinition, ReadEvent, CanHandle, ThenThrows, ReadEventMetadataWithoutGlobalPosition, ProjectionRegistration, DefaultEventStoreOptions, EventStore, Closeable } from '@event-driven-io/emmett';
|
|
2
2
|
import { UpdateFilter, Collection, Document, MongoClient, MongoClientOptions, Filter } from 'mongodb';
|
|
3
3
|
|
|
4
4
|
declare const MongoDBDefaultInlineProjectionName = "_default";
|
|
5
|
-
type MongoDBProjectionInlineHandlerContext<EventType extends Event = Event, EventMetaDataType extends
|
|
5
|
+
type MongoDBProjectionInlineHandlerContext<EventType extends Event = Event, EventMetaDataType extends MongoDBReadEventMetadata = MongoDBReadEventMetadata> = {
|
|
6
6
|
document: MongoDBReadModel | null;
|
|
7
7
|
streamId: string;
|
|
8
8
|
updates: UpdateFilter<EventStream<EventType, EventMetaDataType>>;
|
|
9
9
|
collection: Collection<EventStream<EventType, EventMetaDataType>>;
|
|
10
10
|
};
|
|
11
|
-
type MongoDBInlineProjectionHandler<EventType extends Event = Event, EventMetaDataType extends
|
|
12
|
-
type MongoDBInlineProjectionDefinition<EventType extends Event = Event, EventMetaDataType extends
|
|
11
|
+
type MongoDBInlineProjectionHandler<EventType extends Event = Event, EventMetaDataType extends MongoDBReadEventMetadata = MongoDBReadEventMetadata> = ProjectionHandler<EventType, EventMetaDataType, MongoDBProjectionInlineHandlerContext>;
|
|
12
|
+
type MongoDBInlineProjectionDefinition<EventType extends Event = Event, EventMetaDataType extends MongoDBReadEventMetadata = MongoDBReadEventMetadata> = TypedProjectionDefinition<EventType, EventMetaDataType, MongoDBProjectionInlineHandlerContext> & {
|
|
13
13
|
name: string;
|
|
14
14
|
};
|
|
15
|
-
type InlineProjectionHandlerOptions<EventType extends Event = Event, EventMetaDataType extends
|
|
15
|
+
type InlineProjectionHandlerOptions<EventType extends Event = Event, EventMetaDataType extends MongoDBReadEventMetadata = MongoDBReadEventMetadata> = {
|
|
16
16
|
readModels: Record<string, MongoDBReadModel>;
|
|
17
17
|
events: Array<ReadEvent<EventType, EventMetaDataType>>;
|
|
18
18
|
projections: MongoDBInlineProjectionDefinition<EventType, EventMetaDataType>[];
|
|
@@ -21,14 +21,10 @@ type InlineProjectionHandlerOptions<EventType extends Event = Event, EventMetaDa
|
|
|
21
21
|
updates: UpdateFilter<EventStream<Event>>;
|
|
22
22
|
client: {};
|
|
23
23
|
};
|
|
24
|
-
declare const handleInlineProjections: <EventType extends Event = Event, EventMetaDataType extends
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
}> & object>(options: InlineProjectionHandlerOptions<EventType, EventMetaDataType>) => Promise<void>;
|
|
29
|
-
type MongoDBWithNotNullDocumentEvolve<Doc extends Document, EventType extends Event, EventMetaDataType extends EventMetaDataOf<EventType> & MongoDBReadEventMetadata = EventMetaDataOf<EventType> & MongoDBReadEventMetadata> = ((document: Doc, event: ReadEvent<EventType, EventMetaDataType>) => Doc | null) | ((document: Doc, event: ReadEvent<EventType>) => Promise<Doc | null>);
|
|
30
|
-
type MongoDBWithNullableDocumentEvolve<Doc extends Document, EventType extends Event, EventMetaDataType extends EventMetaDataOf<EventType> & MongoDBReadEventMetadata = EventMetaDataOf<EventType> & MongoDBReadEventMetadata> = ((document: Doc | null, event: ReadEvent<EventType, EventMetaDataType>) => Doc | null) | ((document: Doc | null, event: ReadEvent<EventType>) => Promise<Doc | null>);
|
|
31
|
-
type MongoDBInlineProjectionOptions<Doc extends Document, EventType extends Event, EventMetaDataType extends EventMetaDataOf<EventType> & MongoDBReadEventMetadata = EventMetaDataOf<EventType> & MongoDBReadEventMetadata> = {
|
|
24
|
+
declare const handleInlineProjections: <EventType extends Event = Event, EventMetaDataType extends MongoDBReadEventMetadata = MongoDBReadEventMetadata>(options: InlineProjectionHandlerOptions<EventType, EventMetaDataType>) => Promise<void>;
|
|
25
|
+
type MongoDBWithNotNullDocumentEvolve<Doc extends Document, EventType extends Event, EventMetaDataType extends MongoDBReadEventMetadata = MongoDBReadEventMetadata> = ((document: Doc, event: ReadEvent<EventType, EventMetaDataType>) => Doc | null) | ((document: Doc, event: ReadEvent<EventType>) => Promise<Doc | null>);
|
|
26
|
+
type MongoDBWithNullableDocumentEvolve<Doc extends Document, EventType extends Event, EventMetaDataType extends MongoDBReadEventMetadata = MongoDBReadEventMetadata> = ((document: Doc | null, event: ReadEvent<EventType, EventMetaDataType>) => Doc | null) | ((document: Doc | null, event: ReadEvent<EventType>) => Promise<Doc | null>);
|
|
27
|
+
type MongoDBInlineProjectionOptions<Doc extends Document, EventType extends Event, EventMetaDataType extends MongoDBReadEventMetadata = MongoDBReadEventMetadata> = {
|
|
32
28
|
name?: string;
|
|
33
29
|
schemaVersion?: number;
|
|
34
30
|
canHandle: CanHandle<EventType>;
|
|
@@ -38,11 +34,45 @@ type MongoDBInlineProjectionOptions<Doc extends Document, EventType extends Even
|
|
|
38
34
|
evolve: MongoDBWithNotNullDocumentEvolve<Doc, EventType, EventMetaDataType>;
|
|
39
35
|
initialState: () => Doc;
|
|
40
36
|
});
|
|
41
|
-
declare const mongoDBInlineProjection: <Doc extends Document, EventType extends Event, EventMetaDataType extends
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
streamName:
|
|
45
|
-
|
|
37
|
+
declare const mongoDBInlineProjection: <Doc extends Document, EventType extends Event, EventMetaDataType extends MongoDBReadEventMetadata = MongoDBReadEventMetadata>(options: MongoDBInlineProjectionOptions<Doc, EventType, EventMetaDataType>) => MongoDBInlineProjectionDefinition;
|
|
38
|
+
|
|
39
|
+
type MongoDBInlineProjectionSpecGivenEvents<StreamNameType extends StreamName, EventType extends Event> = {
|
|
40
|
+
streamName: StreamNameType;
|
|
41
|
+
events: EventType[];
|
|
42
|
+
};
|
|
43
|
+
type MongoDBInlineProjectionAssertOptions<StreamNameType extends StreamName = StreamName> = {
|
|
44
|
+
streamName: StreamNameType;
|
|
45
|
+
eventStore: MongoDBEventStore;
|
|
46
|
+
};
|
|
47
|
+
type MongoDBInlineProjectionAssert<StreamNameType extends StreamName = StreamName> = (options: MongoDBInlineProjectionAssertOptions<StreamNameType>) => Promise<void | boolean>;
|
|
48
|
+
type MongoDBInlineProjectionSpecOptions = {
|
|
49
|
+
projection: MongoDBInlineProjectionDefinition;
|
|
50
|
+
} & MongoDBEventStoreConnectionOptions;
|
|
51
|
+
type MongoDBInlineProjectionSpec<StreamNameType extends StreamName, EventType extends Event> = (givenStream: MongoDBInlineProjectionSpecGivenEvents<StreamNameType, EventType>) => {
|
|
52
|
+
when: (events: EventType[]) => {
|
|
53
|
+
then: (assert: MongoDBInlineProjectionAssert, message?: string) => Promise<void>;
|
|
54
|
+
thenThrows: <ErrorType extends Error = Error>(...args: Parameters<ThenThrows<ErrorType>>) => Promise<void>;
|
|
55
|
+
};
|
|
56
|
+
};
|
|
57
|
+
declare const MongoDBInlineProjectionSpec: {
|
|
58
|
+
for: <StreamNameType extends StreamName, EventType extends Event>(options: MongoDBInlineProjectionSpecOptions) => MongoDBInlineProjectionSpec<StreamNameType, EventType>;
|
|
59
|
+
};
|
|
60
|
+
declare const eventInStream: <StreamNameType extends StreamName, EventType extends Event>(streamName: StreamNameType, event: EventType) => MongoDBInlineProjectionSpecGivenEvents<StreamNameType, EventType>;
|
|
61
|
+
declare const eventsInStream: <StreamNameType extends StreamName, EventType extends Event>(streamName: StreamNameType, events: EventType[]) => MongoDBInlineProjectionSpecGivenEvents<StreamNameType, EventType>;
|
|
62
|
+
declare const expectInlineReadModel: {
|
|
63
|
+
toHave: <Doc extends Document, StreamNameType extends StreamName = `${string}:${string}`>(expected: Partial<MongoDBReadModel<Doc>> | null) => MongoDBInlineProjectionAssert<StreamNameType>;
|
|
64
|
+
toDeepEquals: <Doc extends Document, StreamNameType extends StreamName = `${string}:${string}`>(expected: MongoDBReadModel<Doc> | null) => MongoDBInlineProjectionAssert<StreamNameType>;
|
|
65
|
+
toMatch: <Doc extends Document, StreamNameType extends StreamName = `${string}:${string}`>(match: (readModel: MongoDBReadModel<Doc> | null) => boolean) => MongoDBInlineProjectionAssert<StreamNameType>;
|
|
66
|
+
notToExist: <StreamNameType extends StreamName = `${string}:${string}`>() => MongoDBInlineProjectionAssert<StreamNameType>;
|
|
67
|
+
toExist: () => MongoDBInlineProjectionAssert;
|
|
68
|
+
withName: (name: string) => {
|
|
69
|
+
toHave: <Doc extends Document, StreamNameType extends StreamName = `${string}:${string}`>(expected: Partial<MongoDBReadModel<Doc>> | null) => MongoDBInlineProjectionAssert<StreamNameType>;
|
|
70
|
+
toDeepEquals: <Doc extends Document, StreamNameType extends StreamName = `${string}:${string}`>(expected: MongoDBReadModel<Doc> | null) => MongoDBInlineProjectionAssert<StreamNameType>;
|
|
71
|
+
toMatch: <Doc extends Document, StreamNameType extends StreamName = `${string}:${string}`>(match: (readModel: MongoDBReadModel<Doc> | null) => boolean) => MongoDBInlineProjectionAssert<StreamNameType>;
|
|
72
|
+
notToExist: <StreamNameType extends StreamName = `${string}:${string}`>() => MongoDBInlineProjectionAssert<StreamNameType>;
|
|
73
|
+
toExist: () => MongoDBInlineProjectionAssert;
|
|
74
|
+
};
|
|
75
|
+
};
|
|
46
76
|
|
|
47
77
|
type MongoDBEventStoreCollectionPerStreamTypeStorageOptions = {
|
|
48
78
|
/**
|
|
@@ -106,7 +136,7 @@ type MongoDBReadModelMetadata = {
|
|
|
106
136
|
type MongoDBReadModel<Doc extends Document = Document> = Doc & {
|
|
107
137
|
_metadata: MongoDBReadModelMetadata;
|
|
108
138
|
};
|
|
109
|
-
interface EventStream<EventType extends Event = Event, EventMetaDataType extends
|
|
139
|
+
interface EventStream<EventType extends Event = Event, EventMetaDataType extends MongoDBReadEventMetadata = MongoDBReadEventMetadata> {
|
|
110
140
|
streamName: string;
|
|
111
141
|
messages: Array<ReadEvent<EventType, EventMetaDataType>>;
|
|
112
142
|
metadata: {
|
|
@@ -187,10 +217,11 @@ type MongoDBEventStoreConnectionStringOptions = {
|
|
|
187
217
|
connectionString: string;
|
|
188
218
|
clientOptions?: MongoClientOptions;
|
|
189
219
|
};
|
|
220
|
+
type MongoDBEventStoreConnectionOptions = MongoDBEventStoreClientOptions | MongoDBEventStoreConnectionStringOptions;
|
|
190
221
|
type MongoDBEventStoreOptions = {
|
|
191
222
|
projections?: ProjectionRegistration<'inline', MongoDBReadEventMetadata, MongoDBProjectionInlineHandlerContext>[];
|
|
192
223
|
storage?: MongoDBEventStoreStorageOptions;
|
|
193
|
-
} &
|
|
224
|
+
} & MongoDBEventStoreConnectionOptions & DefaultEventStoreOptions<MongoDBEventStore>;
|
|
194
225
|
type MongoDBEventStore = EventStore<MongoDBReadEventMetadata> & {
|
|
195
226
|
projections: ProjectionQueries<StreamType>;
|
|
196
227
|
collectionFor: <EventType extends Event>(streamType: StreamType) => Promise<Collection<EventStream<EventType>>>;
|
|
@@ -226,4 +257,4 @@ declare function toStreamCollectionName<T extends StreamType>(streamType: T): St
|
|
|
226
257
|
*/
|
|
227
258
|
declare function fromStreamCollectionName<T extends StreamType>(streamCollectionName: StreamCollectionName<T>): StreamCollectionNameParts<T>;
|
|
228
259
|
|
|
229
|
-
export { DefaultMongoDBEventStoreCollectionName, DefaultMongoDBEventStoreStorageOptions, type EventStream, type InlineProjectionHandlerOptions, MongoDBDefaultInlineProjectionName, type MongoDBEventStore, type MongoDBEventStoreCollectionPerStreamTypeStorageOptions, type MongoDBEventStoreCollectionResolution, type MongoDBEventStoreCustomStorageOptions, MongoDBEventStoreDefaultStreamVersion, type MongoDBEventStoreOptions, type MongoDBEventStoreSingleCollectionStorageOptions, type MongoDBEventStoreStorage, type MongoDBEventStoreStorageOptions, type MongoDBInlineProjectionDefinition, type MongoDBInlineProjectionHandler, type MongoDBInlineProjectionOptions, type MongoDBProjectionInlineHandlerContext, type MongoDBReadEvent, type MongoDBReadEventMetadata, type MongoDBReadModel, type MongoDBReadModelMetadata, type MongoDBWithNotNullDocumentEvolve, type MongoDBWithNullableDocumentEvolve, type StreamCollectionName, type StreamCollectionNameParts, type StreamName, type StreamNameParts, type StreamType, fromStreamCollectionName, fromStreamName, getMongoDBEventStore, handleInlineProjections, mongoDBEventStoreStorage, mongoDBInlineProjection, prependMongoFilterWithProjectionPrefix, toStreamCollectionName, toStreamName };
|
|
260
|
+
export { DefaultMongoDBEventStoreCollectionName, DefaultMongoDBEventStoreStorageOptions, type EventStream, type InlineProjectionHandlerOptions, MongoDBDefaultInlineProjectionName, type MongoDBEventStore, type MongoDBEventStoreClientOptions, type MongoDBEventStoreCollectionPerStreamTypeStorageOptions, type MongoDBEventStoreCollectionResolution, type MongoDBEventStoreConnectionOptions, type MongoDBEventStoreConnectionStringOptions, type MongoDBEventStoreCustomStorageOptions, MongoDBEventStoreDefaultStreamVersion, type MongoDBEventStoreOptions, type MongoDBEventStoreSingleCollectionStorageOptions, type MongoDBEventStoreStorage, type MongoDBEventStoreStorageOptions, type MongoDBInlineProjectionAssert, type MongoDBInlineProjectionAssertOptions, type MongoDBInlineProjectionDefinition, type MongoDBInlineProjectionHandler, type MongoDBInlineProjectionOptions, MongoDBInlineProjectionSpec, type MongoDBInlineProjectionSpecGivenEvents, type MongoDBInlineProjectionSpecOptions, type MongoDBProjectionInlineHandlerContext, type MongoDBReadEvent, type MongoDBReadEventMetadata, type MongoDBReadModel, type MongoDBReadModelMetadata, type MongoDBWithNotNullDocumentEvolve, type MongoDBWithNullableDocumentEvolve, type StreamCollectionName, type StreamCollectionNameParts, type StreamName, type StreamNameParts, type StreamType, eventInStream, eventsInStream, expectInlineReadModel, fromStreamCollectionName, fromStreamName, getMongoDBEventStore, handleInlineProjections, mongoDBEventStoreStorage, mongoDBInlineProjection, prependMongoFilterWithProjectionPrefix, toStreamCollectionName, toStreamName };
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
|
-
// ../emmett/dist/chunk-
|
|
1
|
+
// ../emmett/dist/chunk-4E7QLAH5.js
|
|
2
2
|
var isNumber = (val) => typeof val === "number" && val === val;
|
|
3
3
|
var isString = (val) => typeof val === "string";
|
|
4
|
+
var isErrorConstructor = (expect) => {
|
|
5
|
+
return typeof expect === "function" && expect.prototype && // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
6
|
+
expect.prototype.constructor === expect;
|
|
7
|
+
};
|
|
4
8
|
var EmmettError = class _EmmettError extends Error {
|
|
5
9
|
errorCode;
|
|
6
10
|
constructor(options) {
|
|
@@ -43,6 +47,16 @@ import { TransformStream as TransformStream8 } from "web-streams-polyfill";
|
|
|
43
47
|
import { TransformStream as TransformStream9 } from "web-streams-polyfill";
|
|
44
48
|
import { TransformStream as TransformStream10 } from "web-streams-polyfill";
|
|
45
49
|
import { TransformStream as TransformStream11 } from "web-streams-polyfill";
|
|
50
|
+
async function tryPublishMessagesAfterCommit(messages, options, context) {
|
|
51
|
+
if (options?.onAfterCommit === void 0) return false;
|
|
52
|
+
try {
|
|
53
|
+
await options?.onAfterCommit(messages, context);
|
|
54
|
+
return true;
|
|
55
|
+
} catch (error2) {
|
|
56
|
+
console.error(`Error in on after commit hook`, error2);
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
46
60
|
var STREAM_EXISTS = "STREAM_EXISTS";
|
|
47
61
|
var STREAM_DOES_NOT_EXIST = "STREAM_DOES_NOT_EXIST";
|
|
48
62
|
var NO_CONCURRENCY_CHECK = "NO_CONCURRENCY_CHECK";
|
|
@@ -101,6 +115,72 @@ var NotifyAboutNoActiveReadersStream = class extends TransformStream2 {
|
|
|
101
115
|
}
|
|
102
116
|
}
|
|
103
117
|
};
|
|
118
|
+
var hasDuplicates = (array, predicate) => {
|
|
119
|
+
const mapped = array.map(predicate);
|
|
120
|
+
const uniqueValues = new Set(mapped);
|
|
121
|
+
return uniqueValues.size < mapped.length;
|
|
122
|
+
};
|
|
123
|
+
var getDuplicates = (array, predicate) => {
|
|
124
|
+
const map2 = /* @__PURE__ */ new Map();
|
|
125
|
+
for (let i = 0; i < array.length; i++) {
|
|
126
|
+
const item = array[i];
|
|
127
|
+
const key = predicate(item, i, array);
|
|
128
|
+
if (!map2.has(key)) {
|
|
129
|
+
map2.set(key, []);
|
|
130
|
+
}
|
|
131
|
+
map2.get(key).push(item);
|
|
132
|
+
}
|
|
133
|
+
return Array.from(map2.values()).filter((group) => group.length > 1).flat();
|
|
134
|
+
};
|
|
135
|
+
var merge = (array, item, where, onExisting, onNotFound = () => void 0) => {
|
|
136
|
+
let wasFound = false;
|
|
137
|
+
const result = array.map((p) => {
|
|
138
|
+
if (!where(p)) return p;
|
|
139
|
+
wasFound = true;
|
|
140
|
+
return onExisting(p);
|
|
141
|
+
}).filter((p) => p !== void 0).map((p) => {
|
|
142
|
+
if (!p) throw Error("That should not happen");
|
|
143
|
+
return p;
|
|
144
|
+
});
|
|
145
|
+
if (!wasFound) {
|
|
146
|
+
const result2 = onNotFound();
|
|
147
|
+
if (result2 !== void 0) return [...array, item];
|
|
148
|
+
}
|
|
149
|
+
return result;
|
|
150
|
+
};
|
|
151
|
+
var arrayUtils = {
|
|
152
|
+
merge,
|
|
153
|
+
hasDuplicates,
|
|
154
|
+
getDuplicates
|
|
155
|
+
};
|
|
156
|
+
var deepEquals = (left, right) => {
|
|
157
|
+
if (isEquatable(left)) {
|
|
158
|
+
return left.equals(right);
|
|
159
|
+
}
|
|
160
|
+
if (Array.isArray(left)) {
|
|
161
|
+
return Array.isArray(right) && left.length === right.length && left.every((val, index) => deepEquals(val, right[index]));
|
|
162
|
+
}
|
|
163
|
+
if (typeof left !== "object" || typeof right !== "object" || left === null || right === null) {
|
|
164
|
+
return left === right;
|
|
165
|
+
}
|
|
166
|
+
if (Array.isArray(right)) return false;
|
|
167
|
+
const keys1 = Object.keys(left);
|
|
168
|
+
const keys2 = Object.keys(right);
|
|
169
|
+
if (keys1.length !== keys2.length || !keys1.every((key) => keys2.includes(key)))
|
|
170
|
+
return false;
|
|
171
|
+
for (const key in left) {
|
|
172
|
+
if (left[key] instanceof Function && right[key] instanceof Function)
|
|
173
|
+
continue;
|
|
174
|
+
const isEqual = deepEquals(left[key], right[key]);
|
|
175
|
+
if (!isEqual) {
|
|
176
|
+
return false;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
return true;
|
|
180
|
+
};
|
|
181
|
+
var isEquatable = (left) => {
|
|
182
|
+
return left && typeof left === "object" && "equals" in left && typeof left["equals"] === "function";
|
|
183
|
+
};
|
|
104
184
|
var asyncRetry = async (fn, opts) => {
|
|
105
185
|
if (opts === void 0 || opts.retries === 0) return fn();
|
|
106
186
|
return retry(
|
|
@@ -117,6 +197,47 @@ var asyncRetry = async (fn, opts) => {
|
|
|
117
197
|
opts ?? { retries: 0 }
|
|
118
198
|
);
|
|
119
199
|
};
|
|
200
|
+
var ParseError = class extends Error {
|
|
201
|
+
constructor(text) {
|
|
202
|
+
super(`Cannot parse! ${text}`);
|
|
203
|
+
}
|
|
204
|
+
};
|
|
205
|
+
var JSONParser = {
|
|
206
|
+
stringify: (value, options) => {
|
|
207
|
+
return JSON.stringify(
|
|
208
|
+
options?.map ? options.map(value) : value,
|
|
209
|
+
//TODO: Consider adding support to DateTime and adding specific format to mark that's a bigint
|
|
210
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
|
211
|
+
(_, v) => typeof v === "bigint" ? v.toString() : v
|
|
212
|
+
);
|
|
213
|
+
},
|
|
214
|
+
parse: (text, options) => {
|
|
215
|
+
const parsed = JSON.parse(text, options?.reviver);
|
|
216
|
+
if (options?.typeCheck && !options?.typeCheck(parsed))
|
|
217
|
+
throw new ParseError(text);
|
|
218
|
+
return options?.map ? options.map(parsed) : parsed;
|
|
219
|
+
}
|
|
220
|
+
};
|
|
221
|
+
var filterProjections = (type, projections2) => {
|
|
222
|
+
const inlineProjections2 = projections2.filter((projection2) => projection2.type === type).map(({ projection: projection2 }) => projection2);
|
|
223
|
+
const duplicateRegistrations = arrayUtils.getDuplicates(
|
|
224
|
+
inlineProjections2,
|
|
225
|
+
(proj) => proj.name
|
|
226
|
+
);
|
|
227
|
+
if (duplicateRegistrations.length > 0) {
|
|
228
|
+
throw new EmmettError(`You cannot register multiple projections with the same name (or without the name).
|
|
229
|
+
Ensure that:
|
|
230
|
+
${JSONParser.stringify(duplicateRegistrations)}
|
|
231
|
+
have different names`);
|
|
232
|
+
}
|
|
233
|
+
return inlineProjections2;
|
|
234
|
+
};
|
|
235
|
+
var inlineProjections = (definitions) => definitions.map((projection2) => ({ type: "inline", projection: projection2 }));
|
|
236
|
+
var asyncProjections = (definitions) => definitions.map((projection2) => ({ type: "async", projection: projection2 }));
|
|
237
|
+
var projections = {
|
|
238
|
+
inline: inlineProjections,
|
|
239
|
+
async: asyncProjections
|
|
240
|
+
};
|
|
120
241
|
var filter = (filter2) => new TransformStream3({
|
|
121
242
|
transform(chunk, controller) {
|
|
122
243
|
if (filter2(chunk)) {
|
|
@@ -258,14 +379,41 @@ var streamTransformations = {
|
|
|
258
379
|
waitAtMost
|
|
259
380
|
};
|
|
260
381
|
var { retry: retry2 } = streamTransformations;
|
|
382
|
+
var AssertionError = class extends Error {
|
|
383
|
+
constructor(message) {
|
|
384
|
+
super(message);
|
|
385
|
+
}
|
|
386
|
+
};
|
|
387
|
+
var isSubset = (superObj, subObj) => {
|
|
388
|
+
const sup = superObj;
|
|
389
|
+
const sub = subObj;
|
|
390
|
+
assertOk(sup);
|
|
391
|
+
assertOk(sub);
|
|
392
|
+
return Object.keys(sub).every((ele) => {
|
|
393
|
+
if (typeof sub[ele] == "object") {
|
|
394
|
+
return isSubset(sup[ele], sub[ele]);
|
|
395
|
+
}
|
|
396
|
+
return sub[ele] === sup[ele];
|
|
397
|
+
});
|
|
398
|
+
};
|
|
399
|
+
var assertFails = (message) => {
|
|
400
|
+
throw new AssertionError(message ?? "That should not ever happened, right?");
|
|
401
|
+
};
|
|
402
|
+
function assertTrue(condition, message) {
|
|
403
|
+
if (condition !== true)
|
|
404
|
+
throw new AssertionError(message ?? `Condition is false`);
|
|
405
|
+
}
|
|
406
|
+
function assertOk(obj, message) {
|
|
407
|
+
if (!obj) throw new AssertionError(message ?? `Condition is not truthy`);
|
|
408
|
+
}
|
|
261
409
|
|
|
262
410
|
// src/eventStore/mongoDBEventStore.ts
|
|
263
411
|
import {
|
|
264
|
-
MongoClient
|
|
412
|
+
MongoClient as MongoClient2
|
|
265
413
|
} from "mongodb";
|
|
266
414
|
import { v4 as uuid4 } from "uuid";
|
|
267
415
|
|
|
268
|
-
// src/eventStore/projections/
|
|
416
|
+
// src/eventStore/projections/mongoDBInlineProjection.ts
|
|
269
417
|
var MongoDBDefaultInlineProjectionName = "_default";
|
|
270
418
|
var handleInlineProjections = async (options) => {
|
|
271
419
|
const {
|
|
@@ -277,10 +425,10 @@ var handleInlineProjections = async (options) => {
|
|
|
277
425
|
readModels
|
|
278
426
|
} = options;
|
|
279
427
|
const eventTypes = events.map((e) => e.type);
|
|
280
|
-
const
|
|
428
|
+
const projections2 = allProjections.filter(
|
|
281
429
|
(p) => p.canHandle.some((type) => eventTypes.includes(type))
|
|
282
430
|
);
|
|
283
|
-
for (const projection of
|
|
431
|
+
for (const projection of projections2) {
|
|
284
432
|
await projection.handle(events, {
|
|
285
433
|
document: readModels[projection.name] ?? null,
|
|
286
434
|
streamId,
|
|
@@ -318,6 +466,135 @@ var mongoDBInlineProjection = (options) => {
|
|
|
318
466
|
};
|
|
319
467
|
};
|
|
320
468
|
|
|
469
|
+
// src/eventStore/projections/mongoDBInlineProjectionSpec.ts
|
|
470
|
+
import { MongoClient } from "mongodb";
|
|
471
|
+
var MongoDBInlineProjectionSpec = {
|
|
472
|
+
for: (options) => {
|
|
473
|
+
{
|
|
474
|
+
const { projection, ...connectionOptions } = options;
|
|
475
|
+
return (givenStream) => {
|
|
476
|
+
const { streamName, events: givenEvents } = givenStream;
|
|
477
|
+
return {
|
|
478
|
+
when: (events) => {
|
|
479
|
+
const allEvents = [...givenEvents, ...events];
|
|
480
|
+
const run = (eventStore) => eventStore.appendToStream(streamName, allEvents);
|
|
481
|
+
return {
|
|
482
|
+
then: async (assert, message) => {
|
|
483
|
+
const client = "client" in connectionOptions && connectionOptions.client ? connectionOptions.client : new MongoClient(
|
|
484
|
+
connectionOptions.connectionString,
|
|
485
|
+
connectionOptions.clientOptions
|
|
486
|
+
);
|
|
487
|
+
const eventStore = getMongoDBEventStore({
|
|
488
|
+
projections: projections.inline([projection]),
|
|
489
|
+
client
|
|
490
|
+
});
|
|
491
|
+
try {
|
|
492
|
+
await run(eventStore);
|
|
493
|
+
const succeeded = await assert({ eventStore, streamName });
|
|
494
|
+
if (succeeded !== void 0 && succeeded === false)
|
|
495
|
+
assertFails(
|
|
496
|
+
message ?? "Projection specification didn't match the criteria"
|
|
497
|
+
);
|
|
498
|
+
} finally {
|
|
499
|
+
await client.close();
|
|
500
|
+
}
|
|
501
|
+
},
|
|
502
|
+
thenThrows: async (...args) => {
|
|
503
|
+
const client = "client" in connectionOptions && connectionOptions.client ? connectionOptions.client : new MongoClient(
|
|
504
|
+
connectionOptions.connectionString,
|
|
505
|
+
connectionOptions.clientOptions
|
|
506
|
+
);
|
|
507
|
+
const eventStore = getMongoDBEventStore({
|
|
508
|
+
projections: projections.inline([projection]),
|
|
509
|
+
client
|
|
510
|
+
});
|
|
511
|
+
try {
|
|
512
|
+
await run(eventStore);
|
|
513
|
+
throw new AssertionError("Handler did not fail as expected");
|
|
514
|
+
} catch (error) {
|
|
515
|
+
if (error instanceof AssertionError) throw error;
|
|
516
|
+
if (args.length === 0) return;
|
|
517
|
+
if (!isErrorConstructor(args[0])) {
|
|
518
|
+
assertTrue(
|
|
519
|
+
args[0](error),
|
|
520
|
+
`Error didn't match the error condition: ${error?.toString()}`
|
|
521
|
+
);
|
|
522
|
+
return;
|
|
523
|
+
}
|
|
524
|
+
assertTrue(
|
|
525
|
+
error instanceof args[0],
|
|
526
|
+
`Caught error is not an instance of the expected type: ${error?.toString()}`
|
|
527
|
+
);
|
|
528
|
+
if (args[1]) {
|
|
529
|
+
assertTrue(
|
|
530
|
+
args[1](error),
|
|
531
|
+
`Error didn't match the error condition: ${error?.toString()}`
|
|
532
|
+
);
|
|
533
|
+
}
|
|
534
|
+
} finally {
|
|
535
|
+
await client.close();
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
};
|
|
539
|
+
}
|
|
540
|
+
};
|
|
541
|
+
};
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
};
|
|
545
|
+
var eventInStream = (streamName, event) => ({
|
|
546
|
+
streamName,
|
|
547
|
+
events: [event]
|
|
548
|
+
});
|
|
549
|
+
var eventsInStream = (streamName, events) => ({
|
|
550
|
+
streamName,
|
|
551
|
+
events
|
|
552
|
+
});
|
|
553
|
+
var expectReadModelToMatch = async (options) => {
|
|
554
|
+
const { streamName, projectionName, eventStore, match } = options;
|
|
555
|
+
const readModel = await eventStore.projections.inline.findOne({
|
|
556
|
+
streamName,
|
|
557
|
+
projectionName
|
|
558
|
+
});
|
|
559
|
+
return match(readModel);
|
|
560
|
+
};
|
|
561
|
+
var expectInlineReadModelWithName = (projectionName) => ({
|
|
562
|
+
toHave: (expected) => ({ eventStore, streamName }) => expectReadModelToMatch({
|
|
563
|
+
eventStore,
|
|
564
|
+
streamName,
|
|
565
|
+
projectionName,
|
|
566
|
+
match: (readModel) => isSubset(readModel, expected)
|
|
567
|
+
}),
|
|
568
|
+
toDeepEquals: (expected) => ({ eventStore, streamName }) => expectReadModelToMatch({
|
|
569
|
+
eventStore,
|
|
570
|
+
streamName,
|
|
571
|
+
projectionName,
|
|
572
|
+
match: (readModel) => deepEquals(readModel, expected)
|
|
573
|
+
}),
|
|
574
|
+
toMatch: (match) => ({ eventStore, streamName }) => expectReadModelToMatch({
|
|
575
|
+
eventStore,
|
|
576
|
+
streamName,
|
|
577
|
+
projectionName,
|
|
578
|
+
match
|
|
579
|
+
}),
|
|
580
|
+
notToExist: () => ({ eventStore, streamName }) => expectReadModelToMatch({
|
|
581
|
+
eventStore,
|
|
582
|
+
streamName,
|
|
583
|
+
projectionName,
|
|
584
|
+
match: (readModel) => readModel === null
|
|
585
|
+
}),
|
|
586
|
+
toExist: () => ({ eventStore, streamName }) => expectReadModelToMatch({
|
|
587
|
+
eventStore,
|
|
588
|
+
streamName,
|
|
589
|
+
projectionName,
|
|
590
|
+
match: (readModel) => readModel !== null
|
|
591
|
+
})
|
|
592
|
+
});
|
|
593
|
+
var expectInlineReadModel = {
|
|
594
|
+
withName: (name) => expectInlineReadModelWithName(name),
|
|
595
|
+
...expectInlineReadModelWithName(MongoDBDefaultInlineProjectionName)
|
|
596
|
+
};
|
|
597
|
+
|
|
321
598
|
// src/eventStore/storage/mongoDBEventStoreStorage.ts
|
|
322
599
|
var DefaultMongoDBEventStoreStorageOptions = "COLLECTION_PER_STREAM_TYPE";
|
|
323
600
|
var DefaultMongoDBEventStoreCollectionName = "emt:streams";
|
|
@@ -393,20 +670,23 @@ var mongoDBEventStoreStorage = (options) => {
|
|
|
393
670
|
var MongoDBEventStoreDefaultStreamVersion = 0n;
|
|
394
671
|
var MongoDBEventStoreImplementation = class {
|
|
395
672
|
client;
|
|
396
|
-
shouldManageClientLifetime;
|
|
397
673
|
inlineProjections;
|
|
674
|
+
shouldManageClientLifetime;
|
|
398
675
|
isClosed = false;
|
|
399
|
-
projections;
|
|
400
676
|
storage;
|
|
677
|
+
options;
|
|
678
|
+
projections;
|
|
401
679
|
constructor(options) {
|
|
402
|
-
this.
|
|
680
|
+
this.options = options;
|
|
681
|
+
this.client = "client" in options && options.client ? options.client : new MongoClient2(options.connectionString, options.clientOptions);
|
|
403
682
|
this.shouldManageClientLifetime = !("client" in options);
|
|
404
683
|
this.storage = mongoDBEventStoreStorage({
|
|
405
684
|
storage: options.storage,
|
|
406
685
|
getConnectedClient: () => this.getConnectedClient()
|
|
407
686
|
});
|
|
408
|
-
this.inlineProjections = (
|
|
409
|
-
|
|
687
|
+
this.inlineProjections = filterProjections(
|
|
688
|
+
"inline",
|
|
689
|
+
options.projections ?? []
|
|
410
690
|
);
|
|
411
691
|
this.projections = {
|
|
412
692
|
inline: {
|
|
@@ -499,7 +779,7 @@ var MongoDBEventStoreImplementation = class {
|
|
|
499
779
|
data: event.data,
|
|
500
780
|
metadata: {
|
|
501
781
|
...metadata,
|
|
502
|
-
...event.metadata ?? {}
|
|
782
|
+
..."metadata" in event ? event.metadata ?? {} : {}
|
|
503
783
|
}
|
|
504
784
|
};
|
|
505
785
|
});
|
|
@@ -542,6 +822,14 @@ var MongoDBEventStoreImplementation = class {
|
|
|
542
822
|
options?.expectedStreamVersion ?? 0n
|
|
543
823
|
);
|
|
544
824
|
}
|
|
825
|
+
await tryPublishMessagesAfterCommit(
|
|
826
|
+
// @ts-expect-error Issues with `globalPosition` not being present causing the type for metadata to expect `never`
|
|
827
|
+
eventsToAppend,
|
|
828
|
+
this.options.hooks
|
|
829
|
+
// {
|
|
830
|
+
// TODO: same context as InlineProjectionHandlerContext for mongodb?
|
|
831
|
+
// },
|
|
832
|
+
);
|
|
545
833
|
return {
|
|
546
834
|
nextExpectedStreamVersion: currentStreamVersion + BigInt(eventsToAppend.length),
|
|
547
835
|
createdNewStream: currentStreamVersion === MongoDBEventStoreDefaultStreamVersion
|
|
@@ -757,6 +1045,10 @@ export {
|
|
|
757
1045
|
DefaultMongoDBEventStoreStorageOptions,
|
|
758
1046
|
MongoDBDefaultInlineProjectionName,
|
|
759
1047
|
MongoDBEventStoreDefaultStreamVersion,
|
|
1048
|
+
MongoDBInlineProjectionSpec,
|
|
1049
|
+
eventInStream,
|
|
1050
|
+
eventsInStream,
|
|
1051
|
+
expectInlineReadModel,
|
|
760
1052
|
fromStreamCollectionName,
|
|
761
1053
|
fromStreamName,
|
|
762
1054
|
getMongoDBEventStore,
|