effect-dynamodb 1.26.0 → 1.28.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/Entity.d.ts.map +1 -1
- package/dist/Entity.js +4 -2
- package/dist/Entity.js.map +1 -1
- package/dist/EventStore.d.ts +332 -58
- package/dist/EventStore.d.ts.map +1 -1
- package/dist/EventStore.js +440 -100
- package/dist/EventStore.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/internal/EntityOps.d.ts +6 -1
- package/dist/internal/EntityOps.d.ts.map +1 -1
- package/dist/internal/EntityOps.js.map +1 -1
- package/dist/internal/EventProjection.d.ts +597 -0
- package/dist/internal/EventProjection.d.ts.map +1 -0
- package/dist/internal/EventProjection.js +695 -0
- package/dist/internal/EventProjection.js.map +1 -0
- package/package.json +2 -2
package/dist/EventStore.d.ts
CHANGED
|
@@ -15,13 +15,20 @@
|
|
|
15
15
|
* - Stream indexes (`makeStream({ indexes })`): sub-streams ordered by a key
|
|
16
16
|
* derived from each event, on an LSI or GSI, each projecting all of the
|
|
17
17
|
* event, all but its metadata, or only its keys — `readIndex`,
|
|
18
|
-
* `query.index`, and `indexDefinitions` for the `CreateTable` fragments
|
|
18
|
+
* `query.index`, and `indexDefinitions` for the `CreateTable` fragments.
|
|
19
|
+
* A GSI may derive its partition too, so several streams share one
|
|
20
|
+
* partition of it, snapshots included (#149)
|
|
19
21
|
* - `fold` / `foldFrom` helpers for state reconstruction
|
|
20
22
|
* - Packed storage (`makeStream({ storedAs: { data } })`, `snapshot.storedAs`):
|
|
21
23
|
* event data and snapshot state as one JSON string, optionally compressed —
|
|
22
24
|
* read by the stored form, so a stream may mix native, JSON and compressed
|
|
23
25
|
* items; `measureAppend` / `measureSnapshot` for caller-side size planning,
|
|
24
26
|
* and `decodeStreamImage` for DynamoDB Streams records
|
|
27
|
+
* - Change-feed projections (#151): `projection` folds a stream into a
|
|
28
|
+
* read-model entity in version order, filling gaps from the store instead of
|
|
29
|
+
* waiting for delivery (`applyBatch`, `apply`, `catchUp`, `rebuild`,
|
|
30
|
+
* `processBatch`, `bindProjection`), plus `decoder`, `eventFilterPattern`
|
|
31
|
+
* and `batchResponse` for the change feed itself
|
|
25
32
|
*
|
|
26
33
|
* Built on the existing library primitives (DynamoSchema, KeyComposer, Query,
|
|
27
34
|
* DynamoClient, Marshaller).
|
|
@@ -32,6 +39,7 @@ import * as DynamoSchema from "@effect-dynamodb/schema/DynamoSchema.js";
|
|
|
32
39
|
import { AdditionalItemConditionFailed, AppendTooLarge, type ConcurrentModification, DuplicateCommand, type OptimisticLockError, TransactionCancelled, type UniqueConstraintViolation, ValidationError, VersionConflict } from "@effect-dynamodb/schema/Errors.js";
|
|
33
40
|
import { DateTime, type Duration, Effect, Option, Pipeable, Schedule, Schema } from "effect";
|
|
34
41
|
import { DynamoClient, type DynamoClientError } from "./DynamoClient.js";
|
|
42
|
+
import { type EventProjection } from "./internal/EventProjection.js";
|
|
35
43
|
import { type StreamImage } from "./internal/Packed.js";
|
|
36
44
|
import { type TransactWriteOp } from "./internal/TransactWriteOps.js";
|
|
37
45
|
import * as Query from "./Query.js";
|
|
@@ -397,6 +405,14 @@ export type AppendError = VersionConflict | DuplicateCommand | AdditionalItemCon
|
|
|
397
405
|
export interface ReadOptions {
|
|
398
406
|
readonly consistentRead?: boolean | undefined;
|
|
399
407
|
}
|
|
408
|
+
/**
|
|
409
|
+
* Options accepted by {@link EventStream.readFrom}: {@link ReadOptions} plus
|
|
410
|
+
* `toVersion`, the last version to read (inclusive) — the key condition stops
|
|
411
|
+
* there, so nothing past it is read or paid for. Default: the stream's head.
|
|
412
|
+
*/
|
|
413
|
+
export interface ReadFromOptions extends ReadOptions {
|
|
414
|
+
readonly toVersion?: number | undefined;
|
|
415
|
+
}
|
|
400
416
|
/**
|
|
401
417
|
* Options accepted by {@link EventStream.readLatest}: {@link ReadOptions} plus
|
|
402
418
|
* `verifySnapshot`.
|
|
@@ -444,20 +460,27 @@ export interface LatestState<TState, TEvent, M = Record<string, unknown> | undef
|
|
|
444
460
|
readonly events: ReadonlyArray<StreamEvent<TEvent, M>>;
|
|
445
461
|
readonly version: number;
|
|
446
462
|
}
|
|
463
|
+
/**
|
|
464
|
+
* The stream id as a stream's index functions receive it: the value of each
|
|
465
|
+
* `streamId.composite` field, by name.
|
|
466
|
+
*/
|
|
467
|
+
export type StreamIndexStreamId = {
|
|
468
|
+
readonly [field: string]: string;
|
|
469
|
+
};
|
|
447
470
|
/**
|
|
448
471
|
* Derives an event's key in a stream index from the domain event (before it is
|
|
449
|
-
* encoded)
|
|
472
|
+
* encoded), the version it is appended at — its version in the stream — and
|
|
473
|
+
* the stream id it is appended to.
|
|
450
474
|
*
|
|
451
475
|
* - A string is the event's sort key in the index. It is stored **raw**: no
|
|
452
476
|
* casing and no prefixing is applied, so compose it to sort the way you
|
|
453
477
|
* query (zero-pad numbers, for example).
|
|
454
478
|
* - `undefined` leaves the event out of the index (a sparse index).
|
|
455
|
-
* -
|
|
456
|
-
* `ValidationError` before anything is written
|
|
457
|
-
*
|
|
458
|
-
*
|
|
459
|
-
*
|
|
460
|
-
* is written.
|
|
479
|
+
* - Any other value, or a `key` that throws, fails the append with
|
|
480
|
+
* `ValidationError` before anything is written. An empty string or a key
|
|
481
|
+
* over DynamoDB's 1024-byte sort-key limit is sent and rejected by
|
|
482
|
+
* DynamoDB; the append then fails with `ValidationError` naming the index
|
|
483
|
+
* and the event (#144), and nothing is written.
|
|
461
484
|
*
|
|
462
485
|
* The key is derived only when an event is appended. Events are never
|
|
463
486
|
* rewritten, so changing `key` later leaves events already stored under their
|
|
@@ -467,7 +490,60 @@ export interface LatestState<TState, TEvent, M = Record<string, unknown> | undef
|
|
|
467
490
|
* existing events is the application's decision (see `indexes` on
|
|
468
491
|
* {@link makeStream}).
|
|
469
492
|
*/
|
|
470
|
-
export type StreamIndexKey<TEvent> = (event: TEvent, version: number) => string | undefined;
|
|
493
|
+
export type StreamIndexKey<TEvent, TStreamId = StreamIndexStreamId> = (event: TEvent, version: number, streamId: TStreamId) => string | undefined;
|
|
494
|
+
/**
|
|
495
|
+
* Derives an event's partition in a GSI stream index (`partition` on a
|
|
496
|
+
* {@link GlobalStreamIndexConfig}, #149) from the domain event, the version it
|
|
497
|
+
* is appended at and the stream id — the arguments of the index's `key`, in
|
|
498
|
+
* the same order. Called for every appended event, with `key`.
|
|
499
|
+
*
|
|
500
|
+
* - A string is the event's partition key in the index, stored **raw** (no
|
|
501
|
+
* casing, no prefix) in the index's `pk` attribute. Several streams may
|
|
502
|
+
* derive the same value, so one query of the index reads a group of
|
|
503
|
+
* streams — `ORDER#<orderId>` for an order's line, payment and shipment
|
|
504
|
+
* streams, say.
|
|
505
|
+
* - `undefined` leaves the event out of the index, as an `undefined` `key`
|
|
506
|
+
* does. An event is indexed only when both return a string.
|
|
507
|
+
* - Within one append, every event whose partition is a string must have the
|
|
508
|
+
* same one, and so must the inline snapshot's entry (see
|
|
509
|
+
* {@link StreamIndexSnapshotEntry}); otherwise the append fails with
|
|
510
|
+
* `ValidationError` and nothing is written. Another value, or a function
|
|
511
|
+
* that throws, fails it the same way. An empty string, or one over
|
|
512
|
+
* DynamoDB's 2048-byte partition-key limit, is DynamoDB's to reject: the
|
|
513
|
+
* rejection is reported as a `ValidationError` naming the index and the
|
|
514
|
+
* event.
|
|
515
|
+
*/
|
|
516
|
+
export type StreamIndexPartition<TEvent, TStreamId = StreamIndexStreamId> = (event: TEvent, version: number, streamId: TStreamId) => string | undefined;
|
|
517
|
+
/**
|
|
518
|
+
* Puts a stream's snapshot in a GSI stream index with a derived partition
|
|
519
|
+
* (`snapshot` on a {@link GlobalStreamIndexConfig}, #149): from the state
|
|
520
|
+
* being written (before it is encoded), the snapshot's `asOfVersion` and the
|
|
521
|
+
* stream id — in the order of the events' `key` and `partition` — the
|
|
522
|
+
* snapshot item's partition and sort key in the index —
|
|
523
|
+
* both stored **raw** — or `undefined` to leave it out.
|
|
524
|
+
*
|
|
525
|
+
* Every snapshot write derives it — `writeSnapshot`, the inline snapshot of
|
|
526
|
+
* `append` and `commandHandler` (`mode: "inline"` or `"after-append"`) — and
|
|
527
|
+
* the attributes are part of the snapshot item itself, so an inline snapshot
|
|
528
|
+
* enters the index in the append's own transaction. The snapshot `Put`
|
|
529
|
+
* replaces the whole item, so returning `undefined` takes a snapshot already
|
|
530
|
+
* in the index out of it.
|
|
531
|
+
*
|
|
532
|
+
* The inline snapshot of an append must have the partition of the append's
|
|
533
|
+
* events in the index (when they have one); a standalone `writeSnapshot` has
|
|
534
|
+
* no events to compare with. Another value than an object of two strings, or
|
|
535
|
+
* a function that throws, fails the write with `ValidationError` before
|
|
536
|
+
* anything is written.
|
|
537
|
+
*
|
|
538
|
+
* A snapshot is the state **as of** `asOfVersion`: it is current after every
|
|
539
|
+
* append only with `snapshot: { mode: "inline" }` and no `every`. A reader of
|
|
540
|
+
* the index that needs the head folds the stream's indexed events after
|
|
541
|
+
* `asOfVersion` onto it.
|
|
542
|
+
*/
|
|
543
|
+
export type StreamIndexSnapshotEntry<TState, TStreamId = StreamIndexStreamId> = (state: TState, asOfVersion: number, streamId: TStreamId) => {
|
|
544
|
+
readonly partition: string;
|
|
545
|
+
readonly key: string;
|
|
546
|
+
} | undefined;
|
|
471
547
|
/**
|
|
472
548
|
* A stream index on a **local** secondary index (the default `type`). An LSI
|
|
473
549
|
* shares the table's partition key (`pk`), so its items are exactly the
|
|
@@ -484,13 +560,17 @@ export type StreamIndexKey<TEvent> = (event: TEvent, version: number) => string
|
|
|
484
560
|
* the index copies from each event is its `projection` — see
|
|
485
561
|
* {@link StreamIndexProjection}.
|
|
486
562
|
*/
|
|
487
|
-
export interface LocalStreamIndexConfig<TEvent> {
|
|
563
|
+
export interface LocalStreamIndexConfig<TEvent, TStreamId = StreamIndexStreamId> {
|
|
488
564
|
readonly type?: "lsi" | undefined;
|
|
489
565
|
readonly index: string;
|
|
490
566
|
readonly sk: string;
|
|
491
567
|
/** An LSI uses the table partition key; supplying `pk` is refused (`[EDD-9063]`). */
|
|
492
568
|
readonly pk?: undefined;
|
|
493
|
-
readonly key: StreamIndexKey<TEvent>;
|
|
569
|
+
readonly key: StreamIndexKey<TEvent, TStreamId>;
|
|
570
|
+
/** An LSI's partition is the stream's; supplying `partition` is refused (`[EDD-9063]`). */
|
|
571
|
+
readonly partition?: undefined;
|
|
572
|
+
/** Only a GSI with a derived `partition` indexes snapshots (`[EDD-9063]`). */
|
|
573
|
+
readonly snapshot?: undefined;
|
|
494
574
|
/**
|
|
495
575
|
* What the index copies from each event — see {@link StreamIndexProjection}.
|
|
496
576
|
* Default `"all"`. Must match the deployed index.
|
|
@@ -498,30 +578,56 @@ export interface LocalStreamIndexConfig<TEvent> {
|
|
|
498
578
|
readonly projection?: StreamIndexProjection | undefined;
|
|
499
579
|
}
|
|
500
580
|
/**
|
|
501
|
-
* A stream index on a **global** secondary index. `append` writes
|
|
502
|
-
* partition key value into the `pk` attribute of each indexed
|
|
503
|
-
* index is scoped to the same stream: the eventually consistent
|
|
504
|
-
* an LSI, without the LSI's 10 GB item-collection cap. DynamoDB
|
|
505
|
-
* strongly consistent read of it, diagnosed as a `ValidationError`
|
|
506
|
-
* index.
|
|
581
|
+
* A stream index on a **global** secondary index. By default `append` writes
|
|
582
|
+
* the stream's partition key value into the `pk` attribute of each indexed
|
|
583
|
+
* event, so the index is scoped to the same stream: the eventually consistent
|
|
584
|
+
* equivalent of an LSI, without the LSI's 10 GB item-collection cap. DynamoDB
|
|
585
|
+
* rejects a strongly consistent read of it, diagnosed as a `ValidationError`
|
|
586
|
+
* naming the index.
|
|
587
|
+
*
|
|
588
|
+
* With `partition` (#149), the partition is derived instead — see
|
|
589
|
+
* {@link StreamIndexPartition} — and stored raw, so several streams can write
|
|
590
|
+
* the same partition of one GSI they all declare, and one query of it reads
|
|
591
|
+
* the whole group (an order's line, payment and shipment streams under
|
|
592
|
+
* `ORDER#<orderId>`, say). {@link indexDefinitions} emits a physical index
|
|
593
|
+
* the streams declare alike once. With `snapshot` as well, each stream's
|
|
594
|
+
* snapshot item is in the index too — see {@link StreamIndexSnapshotEntry}.
|
|
595
|
+
* {@link EventStream.readIndex} then takes the partition to read, and
|
|
596
|
+
* returns the given stream's events in it.
|
|
507
597
|
*
|
|
508
598
|
* Unlike an LSI, the GSI itself can be added to an existing table
|
|
509
|
-
* (`UpdateTable`), but that does not index the stream's existing
|
|
510
|
-
* index attributes are written only by `append
|
|
511
|
-
* the index is declared are in it — see
|
|
599
|
+
* (`UpdateTable`), but that does not index the stream's existing items: the
|
|
600
|
+
* index attributes are written only by `append` (and snapshot writes), so only
|
|
601
|
+
* events appended after the index is declared are in it — see
|
|
602
|
+
* {@link StreamIndexKey}.
|
|
512
603
|
*
|
|
513
604
|
* - `index` — the physical GSI name.
|
|
514
|
-
* - `pk` — the attribute carrying the
|
|
605
|
+
* - `pk` — the attribute carrying the partition (the GSI's HASH key): the
|
|
606
|
+
* stream's partition key, or the derived `partition`.
|
|
515
607
|
* - `sk` — the attribute carrying the derived key (the GSI's RANGE key).
|
|
516
608
|
* - `key` — see {@link StreamIndexKey}.
|
|
609
|
+
* - `partition` — optional, see {@link StreamIndexPartition}.
|
|
610
|
+
* - `snapshot` — optional, requires `partition` and a stream `snapshot`
|
|
611
|
+
* config; see {@link StreamIndexSnapshotEntry}.
|
|
517
612
|
* - `projection` — see {@link StreamIndexProjection}.
|
|
613
|
+
*
|
|
614
|
+
* Write `type: "gsi"` in the entry itself. TypeScript infers the parameter
|
|
615
|
+
* types of `partition` and `snapshot` from the GSI member of the entry union,
|
|
616
|
+
* which it selects by the literal `type`: an entry whose `type` comes from an
|
|
617
|
+
* object spread (`{ ...shared, partition: (event) => … }`) gets implicit-`any`
|
|
618
|
+
* parameters there, although `key` still infers. Annotate them, or give the
|
|
619
|
+
* shared fragment a {@link GlobalStreamIndexConfig} type.
|
|
518
620
|
*/
|
|
519
|
-
export interface GlobalStreamIndexConfig<TEvent> {
|
|
621
|
+
export interface GlobalStreamIndexConfig<TEvent, TStreamId = StreamIndexStreamId, TState = unknown> {
|
|
520
622
|
readonly type: "gsi";
|
|
521
623
|
readonly index: string;
|
|
522
624
|
readonly pk: string;
|
|
523
625
|
readonly sk: string;
|
|
524
|
-
readonly key: StreamIndexKey<TEvent>;
|
|
626
|
+
readonly key: StreamIndexKey<TEvent, TStreamId>;
|
|
627
|
+
/** The derived partition — see {@link StreamIndexPartition}. */
|
|
628
|
+
readonly partition?: StreamIndexPartition<TEvent, TStreamId> | undefined;
|
|
629
|
+
/** The snapshot's entry — see {@link StreamIndexSnapshotEntry}. Requires `partition`. */
|
|
630
|
+
readonly snapshot?: StreamIndexSnapshotEntry<TState, TStreamId> | undefined;
|
|
525
631
|
/**
|
|
526
632
|
* What the index copies from each event — see {@link StreamIndexProjection}.
|
|
527
633
|
* Default `"all"`. Must match the deployed index.
|
|
@@ -533,7 +639,7 @@ export interface GlobalStreamIndexConfig<TEvent> {
|
|
|
533
639
|
* ordered by a key derived from each event. See {@link LocalStreamIndexConfig}
|
|
534
640
|
* and {@link GlobalStreamIndexConfig}.
|
|
535
641
|
*/
|
|
536
|
-
export type StreamIndexConfig<TEvent> = LocalStreamIndexConfig<TEvent> | GlobalStreamIndexConfig<TEvent>;
|
|
642
|
+
export type StreamIndexConfig<TEvent, TStreamId = StreamIndexStreamId, TState = unknown> = LocalStreamIndexConfig<TEvent, TStreamId> | GlobalStreamIndexConfig<TEvent, TStreamId, TState>;
|
|
537
643
|
/**
|
|
538
644
|
* What a stream index copies from each event (`projection` on an entry of
|
|
539
645
|
* `makeStream({ indexes })`). {@link indexDefinitions} emits the matching
|
|
@@ -542,7 +648,7 @@ export type StreamIndexConfig<TEvent> = LocalStreamIndexConfig<TEvent> | GlobalS
|
|
|
542
648
|
* | Value | Emitted `Projection` | Read |
|
|
543
649
|
* |---|---|---|
|
|
544
650
|
* | `"all"` (default) | `ALL` | one query |
|
|
545
|
-
* | `"withoutMetadata"` | `INCLUDE` of every event attribute except `metadata` | one query; `metadata` is `undefined` (and typed so) |
|
|
651
|
+
* | `"withoutMetadata"` | `INCLUDE` of every event attribute except `metadata` (plus the snapshot's `asOfVersion` and `state` when a stream indexes its snapshot in it) | one query; `metadata` is `undefined` (and typed so) |
|
|
546
652
|
* | `"keys"` | `INCLUDE ["__edd_e__"]` — **not** `KEYS_ONLY` | LSI: one query with `Select: ALL_ATTRIBUTES` (DynamoDB fetches each event from the table). GSI: the query, then `BatchGetItem` for the events of each page, in index order |
|
|
547
653
|
*
|
|
548
654
|
* `__edd_e__` is always projected because every read filters on it, and
|
|
@@ -575,6 +681,18 @@ export interface StreamIndexSettings {
|
|
|
575
681
|
readonly pk: string;
|
|
576
682
|
readonly sk: string;
|
|
577
683
|
readonly projection: StreamIndexProjection;
|
|
684
|
+
/**
|
|
685
|
+
* Where the index's partition comes from: `"stream"` — the stream's own
|
|
686
|
+
* partition key (every LSI, and a GSI without `partition`) — or
|
|
687
|
+
* `"derived"`, a GSI's `partition` function (#149). A stream always sets
|
|
688
|
+
* it; absent (a settings object built by hand) reads as `"stream"`.
|
|
689
|
+
*/
|
|
690
|
+
readonly partition?: "stream" | "derived" | undefined;
|
|
691
|
+
/**
|
|
692
|
+
* Whether the stream's snapshot is in the index (a GSI's `snapshot`, #149).
|
|
693
|
+
* A stream always sets it; absent reads as `false`.
|
|
694
|
+
*/
|
|
695
|
+
readonly snapshot?: boolean | undefined;
|
|
578
696
|
}
|
|
579
697
|
/**
|
|
580
698
|
* The `metadata` type of an event read through a stream index of projection
|
|
@@ -595,6 +713,16 @@ type ProjectionOf<C> = C extends {
|
|
|
595
713
|
export type IndexProjectionsOf<TIndexes> = {
|
|
596
714
|
readonly [K in keyof TIndexes & string]: ProjectionOf<TIndexes[K]>;
|
|
597
715
|
};
|
|
716
|
+
/**
|
|
717
|
+
* The names of the indexes of a `makeStream({ indexes })` config that derive
|
|
718
|
+
* their partition (`partition`, #149) — those {@link EventStream.readIndex}
|
|
719
|
+
* and `query.index` read with an explicit `partition`.
|
|
720
|
+
*/
|
|
721
|
+
export type PartitionedIndexesOf<TIndexes> = {
|
|
722
|
+
readonly [K in keyof TIndexes & string]: TIndexes[K] extends {
|
|
723
|
+
readonly partition: (...args: ReadonlyArray<any>) => unknown;
|
|
724
|
+
} ? K : never;
|
|
725
|
+
}[keyof TIndexes & string];
|
|
598
726
|
/** @internal The members a stream index entry may declare. */
|
|
599
727
|
type StreamIndexConfigKey = keyof LocalStreamIndexConfig<unknown> | keyof GlobalStreamIndexConfig<unknown>;
|
|
600
728
|
/**
|
|
@@ -604,8 +732,8 @@ type StreamIndexConfigKey = keyof LocalStreamIndexConfig<unknown> | keyof Global
|
|
|
604
732
|
* `TIndexes` from the entries turns off TypeScript's own excess-property check,
|
|
605
733
|
* which would otherwise catch it.
|
|
606
734
|
*/
|
|
607
|
-
export type StreamIndexesConfig<TIndexes, TEvent> = {
|
|
608
|
-
readonly [K in keyof TIndexes]: StreamIndexConfig<TEvent> & {
|
|
735
|
+
export type StreamIndexesConfig<TIndexes, TEvent, TStreamId = StreamIndexStreamId, TState = unknown> = {
|
|
736
|
+
readonly [K in keyof TIndexes]: StreamIndexConfig<TEvent, TStreamId, TState> & {
|
|
609
737
|
readonly [P in Exclude<keyof TIndexes[K], StreamIndexConfigKey>]: never;
|
|
610
738
|
};
|
|
611
739
|
};
|
|
@@ -623,6 +751,9 @@ export type StreamIndexesConfig<TIndexes, TEvent> = {
|
|
|
623
751
|
* - `consistentRead` — strongly consistent read. DynamoDB rejects it on a
|
|
624
752
|
* GSI-backed index, which it reads only eventually consistently: the read
|
|
625
753
|
* fails with a `ValidationError` naming the index.
|
|
754
|
+
*
|
|
755
|
+
* An index that derives its partition (#149) also takes `partition` — see
|
|
756
|
+
* {@link ReadIndexArgs}.
|
|
626
757
|
*/
|
|
627
758
|
export type ReadIndexOptions = {
|
|
628
759
|
readonly reverse?: boolean | undefined;
|
|
@@ -635,9 +766,47 @@ export type ReadIndexOptions = {
|
|
|
635
766
|
readonly between?: readonly [string, string] | undefined;
|
|
636
767
|
readonly beginsWith?: undefined;
|
|
637
768
|
});
|
|
638
|
-
|
|
769
|
+
/**
|
|
770
|
+
* The options argument of {@link EventStream.readIndex} for index `N`. An
|
|
771
|
+
* index that derives its partition (`partition`, #149) is read one partition
|
|
772
|
+
* at a time, so `partition` — the value to read, as the index's `partition`
|
|
773
|
+
* function returns it — is required, and the read returns the events of the
|
|
774
|
+
* given stream in it. Any other index is scoped to the stream already: a
|
|
775
|
+
* `partition` passed for it fails the read with `ValidationError` (it stays
|
|
776
|
+
* in the type so that a stream whose indexes derive their partition remains
|
|
777
|
+
* assignable to one whose indexes do not, as every stream is to
|
|
778
|
+
* `EventStream<E, F, M, S>`).
|
|
779
|
+
*/
|
|
780
|
+
export type ReadIndexArgs<N extends string, TPartitionedIndexName extends string> = [
|
|
781
|
+
TPartitionedIndexName
|
|
782
|
+
] extends [never] ? [
|
|
783
|
+
options?: (ReadIndexOptions & {
|
|
784
|
+
readonly partition?: string | undefined;
|
|
785
|
+
}) | undefined
|
|
786
|
+
] : [N] extends [TPartitionedIndexName] ? [options: ReadIndexOptions & {
|
|
787
|
+
readonly partition: string;
|
|
788
|
+
}] : [options?: (ReadIndexOptions & {
|
|
789
|
+
readonly partition?: string | undefined;
|
|
790
|
+
}) | undefined];
|
|
791
|
+
/**
|
|
792
|
+
* The options argument of `query.index` for index `N` — `partition`, required
|
|
793
|
+
* for an index that derives its partition, as for {@link ReadIndexArgs}; on
|
|
794
|
+
* any other index, one passed throws `[EDD-9080]`.
|
|
795
|
+
*/
|
|
796
|
+
export type IndexQueryArgs<N extends string, TPartitionedIndexName extends string> = [
|
|
797
|
+
TPartitionedIndexName
|
|
798
|
+
] extends [never] ? [options?: {
|
|
799
|
+
readonly partition?: string | undefined;
|
|
800
|
+
} | undefined] : [N] extends [TPartitionedIndexName] ? [options: {
|
|
801
|
+
readonly partition: string;
|
|
802
|
+
}] : [options?: {
|
|
803
|
+
readonly partition?: string | undefined;
|
|
804
|
+
} | undefined];
|
|
805
|
+
export type StreamIdInput<T extends ReadonlyArray<string>> = {
|
|
639
806
|
readonly [K in T[number]]: string;
|
|
640
807
|
};
|
|
808
|
+
/** @internal The state type of a `makeStream({ snapshot })` config; `never` without one. */
|
|
809
|
+
type SnapshotStateOf<TSnapshot> = TSnapshot extends SnapshotConfig<infer TStateSchema> ? Schema.Schema.Type<TStateSchema> : never;
|
|
641
810
|
declare const EventStreamTypeId: unique symbol;
|
|
642
811
|
export type EventStreamTypeId = typeof EventStreamTypeId;
|
|
643
812
|
/**
|
|
@@ -651,15 +820,32 @@ export type EventStreamTypeId = typeof EventStreamTypeId;
|
|
|
651
820
|
* `query.index` only accept a declared name. `TIndexProjections` is each
|
|
652
821
|
* index's {@link StreamIndexProjection} by name, so an event read through a
|
|
653
822
|
* `"withoutMetadata"` index has `metadata: undefined`.
|
|
823
|
+
* `TPartitionedIndexName` names the indexes that derive their partition
|
|
824
|
+
* (#149), which are read with an explicit `partition`.
|
|
654
825
|
*/
|
|
655
826
|
export interface EventStream<TEvent, TStreamIdFields extends ReadonlyArray<string>, TMetadata, TState = never, TIndexName extends string = never, TIndexProjections extends {
|
|
656
827
|
readonly [K in TIndexName]: StreamIndexProjection;
|
|
657
828
|
} = {
|
|
658
829
|
readonly [K in TIndexName]: "all";
|
|
659
|
-
}> extends Pipeable.Pipeable {
|
|
830
|
+
}, TPartitionedIndexName extends string = never> extends Pipeable.Pipeable {
|
|
660
831
|
readonly [EventStreamTypeId]: EventStreamTypeId;
|
|
661
832
|
readonly streamName: string;
|
|
662
833
|
readonly eventSchema: Schema.Top;
|
|
834
|
+
/** The stream id's composite fields, in declaration order (`makeStream({ streamId })`). */
|
|
835
|
+
readonly streamIdFields: TStreamIdFields;
|
|
836
|
+
/**
|
|
837
|
+
* The `__edd_e__` value of the stream's event items (`<streamname>.event`,
|
|
838
|
+
* lower-cased) — what a change-feed filter or {@link decoder} matches on.
|
|
839
|
+
*/
|
|
840
|
+
readonly eventMarker: string;
|
|
841
|
+
/**
|
|
842
|
+
* Recover the structured stream id from a {@link StreamEvent.streamId} —
|
|
843
|
+
* the composites joined with `#`, in declaration order. A single-field id is
|
|
844
|
+
* the whole string. A multi-field id is split on `#`; a part count other
|
|
845
|
+
* than the field count (a value that itself contains `#`) is ambiguous and
|
|
846
|
+
* fails with `ValidationError`.
|
|
847
|
+
*/
|
|
848
|
+
parseStreamId(streamId: string): Effect.Effect<StreamIdInput<TStreamIdFields>, ValidationError, never>;
|
|
663
849
|
/**
|
|
664
850
|
* The stream's indexes (`makeStream({ indexes })`) by name — their physical
|
|
665
851
|
* index and key attributes. Empty for a stream without indexes.
|
|
@@ -719,10 +905,11 @@ export interface EventStream<TEvent, TStreamIdFields extends ReadonlyArray<strin
|
|
|
719
905
|
*/
|
|
720
906
|
read(streamId: StreamIdInput<TStreamIdFields>, options?: ReadOptions | undefined): Effect.Effect<ReadonlyArray<StreamEvent<TEvent, StreamMetadata<TMetadata>>>, DynamoClientError | ValidationError, DynamoClient | TableConfig>;
|
|
721
907
|
/**
|
|
722
|
-
* Read the events after `afterVersion` (exclusive), ascending
|
|
723
|
-
* `{ consistentRead: true }` for
|
|
908
|
+
* Read the events after `afterVersion` (exclusive), ascending — up to
|
|
909
|
+
* `toVersion` (inclusive) when given. Pass `{ consistentRead: true }` for
|
|
910
|
+
* read-your-writes — see {@link ReadFromOptions}.
|
|
724
911
|
*/
|
|
725
|
-
readFrom(streamId: StreamIdInput<TStreamIdFields>, afterVersion: number, options?:
|
|
912
|
+
readFrom(streamId: StreamIdInput<TStreamIdFields>, afterVersion: number, options?: ReadFromOptions | undefined): Effect.Effect<ReadonlyArray<StreamEvent<TEvent, StreamMetadata<TMetadata>>>, DynamoClientError | ValidationError, DynamoClient | TableConfig>;
|
|
726
913
|
/**
|
|
727
914
|
* The version of the stream's newest event (`0` for an empty stream), in one
|
|
728
915
|
* request. Pass `{ consistentRead: true }` for read-your-writes — see
|
|
@@ -769,8 +956,14 @@ export interface EventStream<TEvent, TStreamIdFields extends ReadonlyArray<strin
|
|
|
769
956
|
* `metadata: undefined`, as the type says); for `"keys"`, one query with
|
|
770
957
|
* `Select: ALL_ATTRIBUTES` on an LSI, or the query followed by `BatchGetItem`
|
|
771
958
|
* (unprocessed keys retried, index order kept) on a GSI.
|
|
959
|
+
*
|
|
960
|
+
* An index that derives its partition (`partition`, #149) is read one
|
|
961
|
+
* partition at a time: pass the partition as `options.partition` (required
|
|
962
|
+
* by the types — see {@link ReadIndexArgs}). The read keeps the events of
|
|
963
|
+
* `streamId` in it — not the other streams sharing the partition, nor any
|
|
964
|
+
* snapshot — by filtering on the table's `pk`, which every index projects.
|
|
772
965
|
*/
|
|
773
|
-
readIndex<N extends TIndexName>(name: N, streamId: StreamIdInput<TStreamIdFields>, options
|
|
966
|
+
readIndex<N extends TIndexName>(name: N, streamId: StreamIdInput<TStreamIdFields>, ...options: ReadIndexArgs<N, TPartitionedIndexName>): Effect.Effect<ReadonlyArray<StreamEvent<TEvent, IndexEventMetadata<TMetadata, TIndexProjections[N]>>>, DynamoClientError | ValidationError, DynamoClient | TableConfig>;
|
|
774
967
|
/**
|
|
775
968
|
* The bytes {@link EventStream.append} would write for these arguments, by
|
|
776
969
|
* DynamoDB's own size accounting — for planning chunks against the 400 KB
|
|
@@ -845,8 +1038,12 @@ export interface EventStream<TEvent, TStreamIdFields extends ReadonlyArray<strin
|
|
|
845
1038
|
* counts index entries and fetches nothing. On a `"keys"` or
|
|
846
1039
|
* `"withoutMetadata"` index, a `Query.filter` on an attribute the index
|
|
847
1040
|
* does not project is refused by DynamoDB — use `Query.filterBy`.
|
|
1041
|
+
*
|
|
1042
|
+
* An index that derives its partition (#149) takes the partition to read
|
|
1043
|
+
* as `options.partition` (see {@link IndexQueryArgs}), and the query keeps
|
|
1044
|
+
* `streamId`'s events in it, as {@link EventStream.readIndex} does.
|
|
848
1045
|
*/
|
|
849
|
-
index<N extends TIndexName>(name: N, streamId: StreamIdInput<TStreamIdFields>): Query.Query<StreamEvent<TEvent, IndexEventMetadata<TMetadata, TIndexProjections[N]>>>;
|
|
1046
|
+
index<N extends TIndexName>(name: N, streamId: StreamIdInput<TStreamIdFields>, ...options: IndexQueryArgs<N, TPartitionedIndexName>): Query.Query<StreamEvent<TEvent, IndexEventMetadata<TMetadata, TIndexProjections[N]>>>;
|
|
850
1047
|
};
|
|
851
1048
|
}
|
|
852
1049
|
/**
|
|
@@ -906,11 +1103,20 @@ export interface EventStream<TEvent, TStreamIdFields extends ReadonlyArray<strin
|
|
|
906
1103
|
* `indexes` declares sub-streams ordered by a key derived from each event
|
|
907
1104
|
* (#140), on a local (default) or global secondary index. `append` writes each
|
|
908
1105
|
* event's derived key (and, for a GSI, the stream's partition key) on the
|
|
909
|
-
* event item
|
|
910
|
-
*
|
|
911
|
-
* `query.index`, and create the
|
|
912
|
-
* index's `projection` (default
|
|
913
|
-
* and how it is read — see
|
|
1106
|
+
* event item. Idempotency sentinels never carry them; snapshots carry an
|
|
1107
|
+
* entry only in a GSI that derives its partition and declares `snapshot`.
|
|
1108
|
+
* Read with {@link EventStream.readIndex} or `query.index`, and create the
|
|
1109
|
+
* indexes with {@link indexDefinitions}. Each index's `projection` (default
|
|
1110
|
+
* `"all"`) sets what it copies from each event and how it is read — see
|
|
1111
|
+
* {@link StreamIndexProjection}.
|
|
1112
|
+
*
|
|
1113
|
+
* A GSI's `partition` (#149) derives the partition from the stream id and the
|
|
1114
|
+
* event instead, stored raw, so several streams declaring the same GSI write
|
|
1115
|
+
* one partition of it — an order's line, payment and shipment streams under
|
|
1116
|
+
* `ORDER#<orderId>`, read by one query — and its `snapshot` puts each stream's
|
|
1117
|
+
* snapshot item in that partition too, in the same `Put` (so an inline
|
|
1118
|
+
* snapshot enters the index in the append's own transaction). See
|
|
1119
|
+
* {@link GlobalStreamIndexConfig}.
|
|
914
1120
|
*
|
|
915
1121
|
* Index attributes are written only at append time and events are never
|
|
916
1122
|
* rewritten. Declaring an index on a stream that already holds events, or
|
|
@@ -922,6 +1128,36 @@ export interface EventStream<TEvent, TStreamIdFields extends ReadonlyArray<strin
|
|
|
922
1128
|
*
|
|
923
1129
|
* @example
|
|
924
1130
|
* ```typescript
|
|
1131
|
+
* // Lines and payments of an order share `gsi1` under `ORDER#<orderId>`.
|
|
1132
|
+
* const OrderLines = EventStore.makeStream({
|
|
1133
|
+
* table: EventsTable,
|
|
1134
|
+
* streamName: "OrderLine",
|
|
1135
|
+
* events: [LineAdded, LineRemoved],
|
|
1136
|
+
* streamId: { composite: ["orderId", "lineId"] },
|
|
1137
|
+
* snapshot: { schema: LineState, mode: "inline" },
|
|
1138
|
+
* indexes: {
|
|
1139
|
+
* byOrder: {
|
|
1140
|
+
* type: "gsi",
|
|
1141
|
+
* index: "gsi1",
|
|
1142
|
+
* pk: "gsi1pk",
|
|
1143
|
+
* sk: "gsi1sk",
|
|
1144
|
+
* partition: (_event, _version, streamId) => `ORDER#${streamId.orderId}`,
|
|
1145
|
+
* key: (_event, version, streamId) => `LINE#${streamId.lineId}#EVT#${pad(version)}`,
|
|
1146
|
+
* snapshot: (_state, _asOfVersion, streamId) => ({
|
|
1147
|
+
* partition: `ORDER#${streamId.orderId}`,
|
|
1148
|
+
* key: `LINE#${streamId.lineId}#STATE`,
|
|
1149
|
+
* }),
|
|
1150
|
+
* },
|
|
1151
|
+
* },
|
|
1152
|
+
* })
|
|
1153
|
+
*
|
|
1154
|
+
* const lineEvents = yield* OrderLines.readIndex("byOrder", { orderId, lineId }, {
|
|
1155
|
+
* partition: `ORDER#${orderId}`,
|
|
1156
|
+
* })
|
|
1157
|
+
* ```
|
|
1158
|
+
*
|
|
1159
|
+
* @example
|
|
1160
|
+
* ```typescript
|
|
925
1161
|
* const Entries = EventStore.makeStream({
|
|
926
1162
|
* table: EventsTable,
|
|
927
1163
|
* streamName: "Ledger",
|
|
@@ -946,10 +1182,12 @@ export interface EventStream<TEvent, TStreamIdFields extends ReadonlyArray<strin
|
|
|
946
1182
|
* @throws `[EDD-9062]` when `snapshot.mode` is neither `"after-append"` nor
|
|
947
1183
|
* `"inline"`.
|
|
948
1184
|
* @throws `[EDD-9063]` for a malformed index: a `type` other than `"lsi"` /
|
|
949
|
-
* `"gsi"`, a `gsi` without `pk`, an `lsi` with `pk`,
|
|
950
|
-
*
|
|
951
|
-
* `
|
|
952
|
-
*
|
|
1185
|
+
* `"gsi"`, a `gsi` without `pk`, an `lsi` with `pk`, `partition` or
|
|
1186
|
+
* `snapshot`, an empty `index` / `sk` / `pk`, a `key` / `partition` /
|
|
1187
|
+
* `snapshot` that is not a function, a `snapshot` without `partition` or on
|
|
1188
|
+
* a stream without a `snapshot` config, a `projection` other than `"all"` /
|
|
1189
|
+
* `"withoutMetadata"` / `"keys"`, or a member an index entry does not
|
|
1190
|
+
* declare (such as a misspelled `projection`, also a type error).
|
|
953
1191
|
* @throws `[EDD-9064]` when an index attribute is one the stream writes itself
|
|
954
1192
|
* (`pk`, `sk`, `__edd_e__`, `streamId`, `version`, `eventType`, `data`,
|
|
955
1193
|
* `metadata`, `timestamp`, `asOfVersion`, `state`, `commandId`, or the
|
|
@@ -973,7 +1211,7 @@ export interface EventStream<TEvent, TStreamIdFields extends ReadonlyArray<strin
|
|
|
973
1211
|
*/
|
|
974
1212
|
export declare const makeStream: <const TEvents extends ReadonlyArray<Schema.Top>, TTable extends Table, const TStreamName extends string, const TStreamId extends {
|
|
975
1213
|
readonly composite: ReadonlyArray<string>;
|
|
976
|
-
}, TMetadata extends Schema.Top | undefined = undefined, TSnapshot extends SnapshotConfig | undefined = undefined, const TIndexes extends { readonly [K in keyof TIndexes]: StreamIndexConfig<Schema.Schema.Type<TEvents[number]>>; } = {}>(config: {
|
|
1214
|
+
}, TMetadata extends Schema.Top | undefined = undefined, TSnapshot extends SnapshotConfig | undefined = undefined, const TIndexes extends { readonly [K in keyof TIndexes]: StreamIndexConfig<Schema.Schema.Type<TEvents[number]>, StreamIdInput<TStreamId["composite"]>, SnapshotStateOf<TSnapshot>>; } = {}>(config: {
|
|
977
1215
|
readonly table: TTable;
|
|
978
1216
|
readonly streamName: TStreamName;
|
|
979
1217
|
readonly events: TEvents;
|
|
@@ -981,10 +1219,10 @@ export declare const makeStream: <const TEvents extends ReadonlyArray<Schema.Top
|
|
|
981
1219
|
readonly metadata?: TMetadata;
|
|
982
1220
|
readonly snapshot?: TSnapshot;
|
|
983
1221
|
readonly casing?: DynamoSchema.Casing | undefined;
|
|
984
|
-
readonly indexes?: TIndexes & StreamIndexesConfig<TIndexes, Schema.Schema.Type<TEvents[number]>>;
|
|
1222
|
+
readonly indexes?: TIndexes & StreamIndexesConfig<TIndexes, Schema.Schema.Type<TEvents[number]>, StreamIdInput<TStreamId["composite"]>, SnapshotStateOf<TSnapshot>>;
|
|
985
1223
|
/** How event `data` is stored — see {@link StreamStorageConfig}. */
|
|
986
1224
|
readonly storedAs?: StreamStorageConfig | undefined;
|
|
987
|
-
}) => EventStream<Schema.Schema.Type<TEvents[number]>, TStreamId["composite"], TMetadata extends Schema.Top ? Schema.Schema.Type<TMetadata> : undefined, TSnapshot
|
|
1225
|
+
}) => EventStream<Schema.Schema.Type<TEvents[number]>, TStreamId["composite"], TMetadata extends Schema.Top ? Schema.Schema.Type<TMetadata> : undefined, SnapshotStateOf<TSnapshot>, keyof TIndexes & string, IndexProjectionsOf<TIndexes>, PartitionedIndexesOf<TIndexes>>;
|
|
988
1226
|
/**
|
|
989
1227
|
* An EventStream whose operations have `DynamoClient` and `TableConfig` already
|
|
990
1228
|
* resolved, so all methods return `Effect<A, E, never>`.
|
|
@@ -1009,10 +1247,16 @@ export interface BoundEventStream<TEvent, TStreamIdFields extends ReadonlyArray<
|
|
|
1009
1247
|
readonly [K in TIndexName]: StreamIndexProjection;
|
|
1010
1248
|
} = {
|
|
1011
1249
|
readonly [K in TIndexName]: "all";
|
|
1012
|
-
}> extends Pipeable.Pipeable {
|
|
1250
|
+
}, TPartitionedIndexName extends string = never> extends Pipeable.Pipeable {
|
|
1013
1251
|
readonly [EventStreamTypeId]: EventStreamTypeId;
|
|
1014
1252
|
readonly streamName: string;
|
|
1015
1253
|
readonly eventSchema: Schema.Top;
|
|
1254
|
+
/** See {@link EventStream.streamIdFields}. */
|
|
1255
|
+
readonly streamIdFields: TStreamIdFields;
|
|
1256
|
+
/** See {@link EventStream.eventMarker}. */
|
|
1257
|
+
readonly eventMarker: string;
|
|
1258
|
+
/** See {@link EventStream.parseStreamId}. */
|
|
1259
|
+
parseStreamId(streamId: string): Effect.Effect<StreamIdInput<TStreamIdFields>, ValidationError, never>;
|
|
1016
1260
|
/** See {@link EventStream.snapshotConfig}. */
|
|
1017
1261
|
readonly snapshotConfig: SnapshotSettings | undefined;
|
|
1018
1262
|
/** See {@link EventStream.storedAs}. */
|
|
@@ -1030,13 +1274,13 @@ export interface BoundEventStream<TEvent, TStreamIdFields extends ReadonlyArray<
|
|
|
1030
1274
|
/** See {@link EventStream.read}. */
|
|
1031
1275
|
read(streamId: StreamIdInput<TStreamIdFields>, options?: ReadOptions | undefined): Effect.Effect<ReadonlyArray<StreamEvent<TEvent, StreamMetadata<TMetadata>>>, DynamoClientError | ValidationError, never>;
|
|
1032
1276
|
/** See {@link EventStream.readFrom}. */
|
|
1033
|
-
readFrom(streamId: StreamIdInput<TStreamIdFields>, afterVersion: number, options?:
|
|
1277
|
+
readFrom(streamId: StreamIdInput<TStreamIdFields>, afterVersion: number, options?: ReadFromOptions | undefined): Effect.Effect<ReadonlyArray<StreamEvent<TEvent, StreamMetadata<TMetadata>>>, DynamoClientError | ValidationError, never>;
|
|
1034
1278
|
/** See {@link EventStream.currentVersion}. */
|
|
1035
1279
|
currentVersion(streamId: StreamIdInput<TStreamIdFields>, options?: ReadOptions | undefined): Effect.Effect<number, DynamoClientError | ValidationError, never>;
|
|
1036
1280
|
/** See {@link EventStream.readLatest}. */
|
|
1037
1281
|
readLatest(streamId: StreamIdInput<TStreamIdFields>, options?: ReadLatestOptions | undefined): Effect.Effect<LatestState<TState, TEvent, StreamMetadata<TMetadata>>, DynamoClientError | ValidationError, never>;
|
|
1038
1282
|
/** See {@link EventStream.readIndex}. */
|
|
1039
|
-
readIndex<N extends TIndexName>(name: N, streamId: StreamIdInput<TStreamIdFields>, options
|
|
1283
|
+
readIndex<N extends TIndexName>(name: N, streamId: StreamIdInput<TStreamIdFields>, ...options: ReadIndexArgs<N, TPartitionedIndexName>): Effect.Effect<ReadonlyArray<StreamEvent<TEvent, IndexEventMetadata<TMetadata, TIndexProjections[N]>>>, DynamoClientError | ValidationError, never>;
|
|
1040
1284
|
/** See {@link EventStream.measureAppend}. */
|
|
1041
1285
|
measureAppend(streamId: StreamIdInput<TStreamIdFields>, events: ReadonlyArray<TEvent>, expectedVersion: number, options?: MeasureAppendOptions<TMetadata, TState> | undefined): Effect.Effect<AppendMeasurement, ValidationError, never>;
|
|
1042
1286
|
/** See {@link EventStream.measureSnapshot}. */
|
|
@@ -1056,7 +1300,7 @@ export interface BoundEventStream<TEvent, TStreamIdFields extends ReadonlyArray<
|
|
|
1056
1300
|
readonly query: {
|
|
1057
1301
|
events(streamId: StreamIdInput<TStreamIdFields>): Query.Query<StreamEvent<TEvent, StreamMetadata<TMetadata>>>;
|
|
1058
1302
|
/** See `EventStream.query.index`. */
|
|
1059
|
-
index<N extends TIndexName>(name: N, streamId: StreamIdInput<TStreamIdFields>): Query.Query<StreamEvent<TEvent, IndexEventMetadata<TMetadata, TIndexProjections[N]>>>;
|
|
1303
|
+
index<N extends TIndexName>(name: N, streamId: StreamIdInput<TStreamIdFields>, ...options: IndexQueryArgs<N, TPartitionedIndexName>): Query.Query<StreamEvent<TEvent, IndexEventMetadata<TMetadata, TIndexProjections[N]>>>;
|
|
1060
1304
|
};
|
|
1061
1305
|
/** Escape hatch: provide DynamoClient | TableConfig to an arbitrary effect. */
|
|
1062
1306
|
readonly provide: <A, E>(effect: Effect.Effect<A, E, DynamoClient | TableConfig>) => Effect.Effect<A, E, never>;
|
|
@@ -1075,7 +1319,7 @@ export interface BoundEventStream<TEvent, TStreamIdFields extends ReadonlyArray<
|
|
|
1075
1319
|
* yield* stream.append({ matchId: "m-1" }, [event], 0) // R = never
|
|
1076
1320
|
* ```
|
|
1077
1321
|
*/
|
|
1078
|
-
export declare const bind: <TEvent, TStreamIdFields extends ReadonlyArray<string>, TMetadata, TState, TIndexName extends string = never, TIndexProjections extends { readonly [K in TIndexName]: StreamIndexProjection; } = { readonly [K in TIndexName]: "all"; }>(stream: EventStream<TEvent, TStreamIdFields, TMetadata, TState, TIndexName, TIndexProjections>) => Effect.Effect<BoundEventStream<TEvent, TStreamIdFields, TMetadata, TState, TIndexName, TIndexProjections>, never, DynamoClient | TableConfig>;
|
|
1322
|
+
export declare const bind: <TEvent, TStreamIdFields extends ReadonlyArray<string>, TMetadata, TState, TIndexName extends string = never, TIndexProjections extends { readonly [K in TIndexName]: StreamIndexProjection; } = { readonly [K in TIndexName]: "all"; }, TPartitionedIndexName extends string = never>(stream: EventStream<TEvent, TStreamIdFields, TMetadata, TState, TIndexName, TIndexProjections, TPartitionedIndexName>) => Effect.Effect<BoundEventStream<TEvent, TStreamIdFields, TMetadata, TState, TIndexName, TIndexProjections, TPartitionedIndexName>, never, DynamoClient | TableConfig>;
|
|
1079
1323
|
/**
|
|
1080
1324
|
* `CreateTable` fragments for the stream indexes of one or more streams — see
|
|
1081
1325
|
* {@link indexDefinitions}. The lists are absent when empty, because
|
|
@@ -1101,7 +1345,7 @@ export interface StreamIndexDefinitions {
|
|
|
1101
1345
|
* | `projection` | `Projection` |
|
|
1102
1346
|
* |---|---|
|
|
1103
1347
|
* | `"all"` (default) | `{ ProjectionType: "ALL" }` |
|
|
1104
|
-
* | `"withoutMetadata"` | `{ ProjectionType: "INCLUDE", NonKeyAttributes: ["__edd_e__", "data", "eventType", "streamId", "timestamp", "version"] }` |
|
|
1348
|
+
* | `"withoutMetadata"` | `{ ProjectionType: "INCLUDE", NonKeyAttributes: ["__edd_e__", "data", "eventType", "streamId", "timestamp", "version"] }` — plus `"asOfVersion"` and `"state"` when a stream declaring the index puts its snapshot in it (#149) |
|
|
1105
1349
|
* | `"keys"` | `{ ProjectionType: "INCLUDE", NonKeyAttributes: ["__edd_e__"] }` — not `KEYS_ONLY`: every read filters on `__edd_e__` |
|
|
1106
1350
|
*
|
|
1107
1351
|
* The deployed index must project what is declared — copy `Projection` from
|
|
@@ -1112,7 +1356,12 @@ export interface StreamIndexDefinitions {
|
|
|
1112
1356
|
* table over the limit).
|
|
1113
1357
|
*
|
|
1114
1358
|
* An index shared by several streams with the same definition is emitted
|
|
1115
|
-
* once
|
|
1359
|
+
* once — the way several streams write one GSI whose partition they derive
|
|
1360
|
+
* (`partition`, #149): an order's line, payment and shipment streams under
|
|
1361
|
+
* `ORDER#<orderId>`, say. Whether each declaration derives its partition or
|
|
1362
|
+
* indexes its snapshot is not part of the definition: the index's key schema
|
|
1363
|
+
* and projection kind are. Lists are sorted by index name, attributes by
|
|
1364
|
+
* attribute name.
|
|
1116
1365
|
*
|
|
1117
1366
|
* - An LSI can only be created with the table, and caps the item collection
|
|
1118
1367
|
* of every partition key value in the table at 10 GB — entity partitions
|
|
@@ -1140,13 +1389,19 @@ export interface StreamIndexDefinitions {
|
|
|
1140
1389
|
*
|
|
1141
1390
|
* @throws `[EDD-9067]` when two streams define the same physical index
|
|
1142
1391
|
* differently (another type, other key attributes, or another projection).
|
|
1392
|
+
* Whether a declaration derives its partition or indexes its snapshot is not
|
|
1393
|
+
* part of the index's definition: streams that differ only there share it.
|
|
1143
1394
|
*/
|
|
1144
1395
|
export declare const indexDefinitions: (...streams: ReadonlyArray<{
|
|
1145
1396
|
readonly streamName: string;
|
|
1146
1397
|
readonly indexes: {
|
|
1147
|
-
readonly [name: string]: Omit<StreamIndexSettings, "projection"> & {
|
|
1398
|
+
readonly [name: string]: Omit<StreamIndexSettings, "projection" | "partition" | "snapshot"> & {
|
|
1148
1399
|
/** Read as `"all"` when absent (a hand-built settings object). */
|
|
1149
1400
|
readonly projection?: StreamIndexProjection | undefined;
|
|
1401
|
+
/** Read as `"stream"` when absent (a hand-built settings object). */
|
|
1402
|
+
readonly partition?: "stream" | "derived" | undefined;
|
|
1403
|
+
/** Read as `false` when absent (a hand-built settings object). */
|
|
1404
|
+
readonly snapshot?: boolean | undefined;
|
|
1150
1405
|
};
|
|
1151
1406
|
};
|
|
1152
1407
|
}>) => StreamIndexDefinitions;
|
|
@@ -1507,7 +1762,7 @@ type BoundCommandHandler<State, Command, TEvent, E, TStreamIdFields extends Read
|
|
|
1507
1762
|
* stream is also structurally an `EventStream`), a {@link CommandHandler}
|
|
1508
1763
|
* otherwise.
|
|
1509
1764
|
*/
|
|
1510
|
-
type CommandHandlerFor<S, State, Command, TEvent, E, TConfig extends CommandHandlerOptions | undefined> = S extends BoundEventStream<any, infer TStreamIdFields, infer TMetadata, any, any> ? BoundCommandHandler<State, Command, TEvent, E, TStreamIdFields, TMetadata, TConfig> : S extends EventStream<any, infer TStreamIdFields, infer TMetadata, any, any> ? CommandHandler<State, Command, TEvent, E, TStreamIdFields, TMetadata, TConfig> : never;
|
|
1765
|
+
type CommandHandlerFor<S, State, Command, TEvent, E, TConfig extends CommandHandlerOptions | undefined> = S extends BoundEventStream<any, infer TStreamIdFields, infer TMetadata, any, any, any, any> ? BoundCommandHandler<State, Command, TEvent, E, TStreamIdFields, TMetadata, TConfig> : S extends EventStream<any, infer TStreamIdFields, infer TMetadata, any, any, any, any> ? CommandHandler<State, Command, TEvent, E, TStreamIdFields, TMetadata, TConfig> : never;
|
|
1511
1766
|
/**
|
|
1512
1767
|
* Create a command handler that reads, decides, and appends atomically.
|
|
1513
1768
|
*
|
|
@@ -1607,13 +1862,13 @@ type CommandHandlerFor<S, State, Command, TEvent, E, TConfig extends CommandHand
|
|
|
1607
1862
|
* `EventStreamTypeId` brand of the second argument.
|
|
1608
1863
|
*/
|
|
1609
1864
|
export declare const commandHandler: {
|
|
1610
|
-
<State, Command, TEvent, E, const TConfig extends CommandHandlerOptions | undefined = undefined>(decider: Decider<State, Command, TEvent, E>, options?: TConfig): <S extends BoundEventStream<TEvent, any, any, State, any, any> | EventStream<TEvent, ReadonlyArray<string>, any, State, any, any>>(stream: S) => CommandHandlerFor<S, State, Command, TEvent, E, TConfig>;
|
|
1865
|
+
<State, Command, TEvent, E, const TConfig extends CommandHandlerOptions | undefined = undefined>(decider: Decider<State, Command, TEvent, E>, options?: TConfig): <S extends BoundEventStream<TEvent, any, any, State, any, any, any> | EventStream<TEvent, ReadonlyArray<string>, any, State, any, any, any>>(stream: S) => CommandHandlerFor<S, State, Command, TEvent, E, TConfig>;
|
|
1611
1866
|
<State, Command, TEvent, E, TStreamIdFields extends ReadonlyArray<string>, TMetadata, TState extends State, TIndexName extends string, TIndexProjections extends {
|
|
1612
1867
|
readonly [K in TIndexName]: StreamIndexProjection;
|
|
1613
|
-
}, const TConfig extends CommandHandlerOptions | undefined = undefined>(decider: Decider<State, Command, TEvent, E>, stream: BoundEventStream<TEvent, TStreamIdFields, TMetadata, TState, TIndexName, TIndexProjections>, options?: TConfig): BoundCommandHandler<State, Command, TEvent, E, TStreamIdFields, TMetadata, TConfig>;
|
|
1868
|
+
}, TPartitionedIndexName extends string, const TConfig extends CommandHandlerOptions | undefined = undefined>(decider: Decider<State, Command, TEvent, E>, stream: BoundEventStream<TEvent, TStreamIdFields, TMetadata, TState, TIndexName, TIndexProjections, TPartitionedIndexName>, options?: TConfig): BoundCommandHandler<State, Command, TEvent, E, TStreamIdFields, TMetadata, TConfig>;
|
|
1614
1869
|
<State, Command, TEvent, E, TStreamIdFields extends ReadonlyArray<string>, TMetadata, TState extends State, TIndexName extends string, TIndexProjections extends {
|
|
1615
1870
|
readonly [K in TIndexName]: StreamIndexProjection;
|
|
1616
|
-
}, const TConfig extends CommandHandlerOptions | undefined = undefined>(decider: Decider<State, Command, TEvent, E>, stream: EventStream<TEvent, TStreamIdFields, TMetadata, TState, TIndexName, TIndexProjections>, options?: TConfig): CommandHandler<State, Command, TEvent, E, TStreamIdFields, TMetadata, TConfig>;
|
|
1871
|
+
}, TPartitionedIndexName extends string, const TConfig extends CommandHandlerOptions | undefined = undefined>(decider: Decider<State, Command, TEvent, E>, stream: EventStream<TEvent, TStreamIdFields, TMetadata, TState, TIndexName, TIndexProjections, TPartitionedIndexName>, options?: TConfig): CommandHandler<State, Command, TEvent, E, TStreamIdFields, TMetadata, TConfig>;
|
|
1617
1872
|
};
|
|
1618
1873
|
/**
|
|
1619
1874
|
* Reconstruct state from events by folding through a decider's `evolve` function.
|
|
@@ -1633,4 +1888,23 @@ export declare const foldFrom: {
|
|
|
1633
1888
|
<A>(startState: unknown, events: ReadonlyArray<StreamEvent<A>>): <S, C, E>(decider: Decider<S, C, A, E>) => S;
|
|
1634
1889
|
<S, C, A, E>(decider: Decider<S, C, A, E>, startState: S, events: ReadonlyArray<StreamEvent<A>>): S;
|
|
1635
1890
|
};
|
|
1891
|
+
export { type AnyEventProjection, type ApplyBatchOptions, type BatchItemFailuresResponse, type BatchResponseSource, batchResponse, type CheckpointField, type DecodableStream, type DecodedStreamEvent, decoder, type EventFilterPattern, type EventProjection, type EventProjectionTypeId, eventFilterPattern, type IdentifyBySource, type IdentifyWith, type ProcessBatchesResult, type ProcessBatchOptions, type ProcessBatchResult, type ProjectionApplied, type ProjectionBatchResult, type ProjectionCaughtUp, type ProjectionCheckpoint, type ProjectionConfig, type ProjectionError, type ProjectionKey, type ProjectionOutcome, type ProjectionOutcomesOf, type ProjectionReadModel, type ProjectionReadModelError, type ProjectionRebuilt, type ProjectionRebuiltRow, type ProjectionRejected, type ProjectionRequirementsOf, type ProjectionState, processBatch, projection, type StreamRecord, } from "./internal/EventProjection.js";
|
|
1892
|
+
/**
|
|
1893
|
+
* Bind a projection to the services its operations need — `DynamoClient`,
|
|
1894
|
+
* the `TableConfig`s of the stream's table and the read model's, `evolve`'s
|
|
1895
|
+
* requirements, and a `Compression` registry for packed event data — so every
|
|
1896
|
+
* operation has `R = never`. Like {@link bind}, it checks the registry holds
|
|
1897
|
+
* the codecs the stream's `storedAs` names (`[EDD-9078]`).
|
|
1898
|
+
*
|
|
1899
|
+
* @example
|
|
1900
|
+
* ```ts
|
|
1901
|
+
* const summaries = yield* EventStore.bindProjection(OrderSummaryProjection)
|
|
1902
|
+
* export const handler = (event: { Records: Array<EventStore.StreamRecord> }) =>
|
|
1903
|
+
* summaries.processBatch(event.Records, { source: "lambda" }).pipe(
|
|
1904
|
+
* Effect.map((result) => result.response),
|
|
1905
|
+
* Effect.runPromise,
|
|
1906
|
+
* )
|
|
1907
|
+
* ```
|
|
1908
|
+
*/
|
|
1909
|
+
export declare const bindProjection: <S, A, TStreamIdFields extends ReadonlyArray<string>, M, Err, R, K, E, I extends boolean>(projection: EventProjection<S, A, TStreamIdFields, M, Err, R, K, E, I>) => Effect.Effect<EventProjection<S, A, TStreamIdFields, M, Err, never, K, E, I>, never, R>;
|
|
1636
1910
|
//# sourceMappingURL=EventStore.d.ts.map
|