@castore/event-storage-adapter-dynamodb

中文文档
2.4.2发布于 2025/04/18MITTypeScriptESM + CJS近 30 天下载 4975

DRY Castore EventStorageAdapter 使用 DynamoDB 执行程序

中文使用文档
文档目录15 节
  1. * 安装
  2. 目录
  3. DynamoDBSingleTableEventStorageAdapter
  4. 使用量
  5. 如何运作
  6. 实例
  7. 活动组
  8. ——————————————
  9. 📸 ImageParser
  10. 遗产 DynamoDBEventStorageAdapter
  11. 使用量
  12. 如何运作
  13. 实例
  14. 活动组
  15. ——————————————

DynamoDB 事件存储适应器

德里·卡斯托尔 EventStorageAdapter 使用 AWS 迪纳摩DB。 。 。 .

* 安装

# npm
npm install @castore/event-storage-adapter-dynamodb

# yarn
yarn add @castore/event-storage-adapter-dynamodb

这个软件包 @castore/core 财务报告和审定财务报表 @aws-sdk/client-dynamodb (以上 v3) 作为对等依赖, 您也必须安装它们 :

# npm
npm install @castore/core @aws-sdk/client-dynamodb

# yarn
yarn add @castore/core @aws-sdk/client-dynamodb

目录

这个图书馆暴露出两个适配器:

  • DynamoDBSingleTableEventStorageAdapter 它可以将多个事件存储器插到单个的DynamoDB表格上.
  • (单位:千美元)已贬值(中文(简体) ) DynamoDBEventStorageAdapter 它需要一个DynamoDB表 每个事件商店.

遗产 DynamoDBEventStorageAdapter 仍然暴露在后向兼容性中。 它会被腐烂并重新命名 LegacyDynamoDBEventStorageAdapter 在v2中,最终去掉在v3中.

联合国

DynamoDBSingleTableEventStorageAdapter

使用量

import { DynamoDBClient } from '@aws-sdk/client-dynamodb';

import { DynamoDBSingleTableEventStorageAdapter } from '@castore/event-storage-adapter-dynamodb';

const dynamoDBClient = new DynamoDBClient({});

const pokemonsEventStorageAdapter = new DynamoDBSingleTableEventStorageAdapter(
  {
    tableName: 'my-table-name',
    dynamoDBClient,
  },
);

// 👇 Alternatively, provide a getter
const pokemonsEventStorageAdapter =
  new DynamoDBSingleTableEventStorageAdapter({
    tableName: () => process.env.MY_TABLE_NAME,
    dynamoDBClient,
  });

const pokemonsEventStore = new EventStore({
  ...
  eventStorageAdapter: pokemonsEventStorageAdapter,
});

这将直接将您的事件Store 插入 DynamoDB QQ

如何运作

此适配器在 单独的分区: 当某一事件持续存在时 aggregateId,前缀为 eventStoreId,用作分区键(字符串 属性)及其属性 version 用作排序键( e)编号 属性).

A 类 全球二级指数 也要求有效取回事件存储集合id(listAggregateIds 操作)。 仅是初始事件(version = 1预测数。 A 类 KEYS_ONLY 投影类型已经足够.

// 👇 Initial event
{
  "aggregateId": "POKEMONS#123", // <= Partition key
  "version": 1, // <= Sort key
  "eventStoreId": "POKEMONS", // <= initialEvents index partition key
  "timestamp": "2022-01-01T00:00:00.000Z", // <= initialEvents index sort key
  "type": "POKEMON_APPEARED",
  "payload": { "name": "Pikachu", "level": 42 },
  "metadata": { "trigger": "random" }
}

// 👇 Non-initial event
{
  "aggregateId": "POKEMONS#123",
  "version": 2,
  // Event is not projected on initialEvents index (to limit costs)
  "timestamp": "2023-01-01T00:00:00.000Z",
  "type": "POKEMON_LEVELED_UP"
}

这个 getEvents 方法(用于 getAggregate 财务报告和审定财务报表 getExistingAggregate 工作方法 EventStore 使用一致的读取,同样 始终一致。 。 。 .

这个 pushEvent 方法是一种写操作,所以 始终一致以避免种族条件为条件,如: 卡斯托尔规格。 。 。 .

根据设计 listAggregateIds 操作只能是 最终一致 (通用读取不能一致).

实例

请注意,如果您在 TypeScript 中将您的基础设施定义为代码,您可以直接使用此软件包,而不是硬编码以下数值:

import {
  EVENT_TABLE_PK, // => aggregateId
  EVENT_TABLE_SK, // => version
  EVENT_TABLE_INITIAL_EVENT_INDEX_NAME, // => initialEvents
  EVENT_TABLE_EVENT_STORE_ID_KEY, // => eventStoreId
  EVENT_TABLE_TIMESTAMP_KEY, // => timestamp
} from '@castore/event-storage-adapter-dynamodb';

云阵

{
  "Type": "AWS::DynamoDB::Table",
  "Properties": {
    "AttributeDefinitions": [
      { "AttributeName": "aggregateId", "AttributeType": "S" },
      { "AttributeName": "version", "AttributeType": "N" }
      { "AttributeName": "eventStoreId", "AttributeType": "S" },
      { "AttributeName": "timestamp", "AttributeType": "S" }
    ],
    "KeySchema": [
      { "AttributeName": "aggregateId", "KeyType": "HASH" },
      { "AttributeName": "version", "KeyType": "RANGE" }
    ],
    "GlobalSecondaryIndexes": [
      {
        "IndexName": "initialEvents",
        "KeySchema": [
          { "AttributeName": "eventStoreId", "KeyType": "HASH" },
          { "AttributeName": "timestamp", "KeyType": "RANGE" }
        ],
        "Projection": "KEYS_ONLY"
      }
    ]
  }
}

光盘

import { Table, AttributeType, ProjectionType } from 'aws-cdk-lib/aws-dynamodb';

const { STRING, NUMBER } = AttributeType;
const { KEYS_ONLY } = ProjectionType;

const pokemonsEventsTable = new Table(scope, 'PokemonEvents', {
  partitionKey: {
    name: 'aggregateId',
    type: STRING,
  },
  sortKey: {
    name: 'version',
    type: NUMBER,
  },
});

pokemonsEventsTable.addGlobalSecondaryIndex({
  indexName: 'initialEvents',
  partitionKey: {
    name: 'eventStoreId',
    type: STRING,
  },
  sortKey: {
    name: 'timestamp',
    type: STRING,
  },
  projectionType: KEYS_ONLY,
});

地形

resource "aws_dynamodb_table" "pokemons-events-table" {
  hash_key       = "aggregateId"
  range_key      = "version"

  attribute {
    name = "aggregateId"
    type = "S"
  }

  attribute {
    name = "version"
    type = "N"
  }

  attribute {
    name = "eventStoreId"
    type = "S"
  }

  attribute {
    name = "timestamp"
    type = "S"
  }

  global_secondary_index {
    name               = "initialEvents"
    hash_key           = "eventStoreId"
    range_key          = "timestamp"
    projection_type    = "KEYS_ONLY"
  }
}

活动组

此适配器执行 事件组 使用 DynamoDB 交易 API数字 :

import { EventStore } from '@castore/core';

// 👇 TransactWriteItems N events simultaneously
await EventStore.pushEventGroup(
  // events are correctly typed 🙌
  eventStoreA.groupEvent(eventA1),
  eventStoreA.groupEvent(eventA2),
  eventStoreB.groupEvent(eventB),
  ...
);

注意:

  • 交易所涉的所有事件商店都需要使用 DynamoDBSingleTableEventStorageAdapter
  • 此工具继承 TransactWriteItem API 密码 限制 : 它可以在同一AWS账户和同一区域的一个或多个DynamoDB表格中针对多达100个不同事件.

——————————————

每次操作所需的 IAM 权限 :

  • getEvents (+ 数) getAggregate, (中文(简体) ), getExistingAggregate: dynamodb:Query
  • pushEvent数字 : dynamodb:PutItem
  • listAggregateIds数字 : dynamodb:Query 编辑 initialEvents 指数

📸 ImageParser

这个图书馆也暴露了一个有用的 ImageParser 要解析的类 迪纳摩DB流 图像来自 a DynamoDBSingleTableEventStorageAdapter。它将构建一个正确的键入 NotificationMessage 流出图像的 uf, 解析它, 删除前缀 aggregateId 并验证 eventStoreId数字 :

import { ImageParser } from '@castore/event-storage-adapter-dynamodb';

const imageParser = new ImageParser({
  sourceEventStores: [pokemonsEventStore, trainersEventStore],
});

// 🙌 Typed as EventStoreNotificationMessage<
//  typeof pokemonsEventStore
//  | typeof trainersEventStore...
// >
const notificationMessage = imageParser.parseImage(
  streamImage,
  // 👇 Optional options
  unmarshallOptions,
);

遗产 DynamoDBEventStorageAdapter

页:1

使用量

import { DynamoDBClient } from '@aws-sdk/client-dynamodb';

import { DynamoDBEventStorageAdapter } from '@castore/event-storage-adapter-dynamodb';

const dynamoDBClient = new DynamoDBClient({});

const pokemonsEventStorageAdapter = new DynamoDBEventStorageAdapter({
  tableName: 'my-table-name',
  dynamoDBClient,
});

// 👇 Alternatively, provide a getter
const pokemonsEventStorageAdapter = new DynamoDBEventStorageAdapter({
  tableName: () => process.env.MY_TABLE_NAME,
  dynamoDBClient,
});

const pokemonsEventStore = new EventStore({
  ...
  eventStorageAdapter: pokemonsEventStorageAdapter
})

这将直接将您的事件Store 插入 DynamoDB QQ

如何运作

此适配器在 单独的分区: 当某一事件持续存在时 aggregateId 用作分区键( e)字符串 属性)及其属性 version 用作排序键( e)编号 属性).

A 类 全球二级指数 也要求有效取回事件存储集合id(listAggregateIds 操作)。 仅是初始事件(version = 1预测数。 A 类 KEYS_ONLY 投影类型已经足够.

// 👇 Initial event
{
  "aggregateId": "123", // <= Partition key
  "version": 1, // <= Sort key
  "isInitialEvent": 1, // <= initialEvents index partition key
  "timestamp": "2022-01-01T00:00:00.000Z", // <= initialEvents index sort key
  "type": "POKEMON_APPEARED",
  "payload": { "name": "Pikachu", "level": 42 },
  "metadata": { "trigger": "random" }
}

// 👇 Non-initial event
{
  "aggregateId": "123",
  "version": 2,
  // Event is not projected on initialEvents index (to limit costs)
  "timestamp": "2023-01-01T00:00:00.000Z",
  "type": "POKEMON_LEVELED_UP"
}

这个 getEvents 方法(用于 getAggregate 财务报告和审定财务报表 getExistingAggregate 工作方法 EventStore 使用一致的读取,同样 始终一致。 。 。 .

这个 pushEvent 方法是一种写操作,所以 始终一致以避免种族条件为条件,如: 卡斯托尔规格。 。 。 .

根据设计 listAggregateIds 操作只能是 最终一致 (通用读取不能一致).

实例

请注意,如果您在 TypeScript 中将您的基础设施定义为代码,您可以直接使用此软件包,而不是硬编码以下数值:

import {
  EVENT_TABLE_PK, // => aggregateId
  EVENT_TABLE_SK, // => version
  EVENT_TABLE_INITIAL_EVENT_INDEX_NAME, // => initialEvents
  EVENT_TABLE_IS_INITIAL_EVENT_KEY, // => isInitialEvent
  EVENT_TABLE_TIMESTAMP_KEY, // => timestamp
} from '@castore/event-storage-adapter-dynamodb';

云阵

{
  "Type": "AWS::DynamoDB::Table",
  "Properties": {
    "AttributeDefinitions": [
      { "AttributeName": "aggregateId", "AttributeType": "S" },
      { "AttributeName": "version", "AttributeType": "N" }
      { "AttributeName": "isInitialEvent", "AttributeType": "N" },
      { "AttributeName": "timestamp", "AttributeType": "S" }
    ],
    "KeySchema": [
      { "AttributeName": "aggregateId", "KeyType": "HASH" },
      { "AttributeName": "version", "KeyType": "RANGE" }
    ],
    "GlobalSecondaryIndexes": [
      {
        "IndexName": "initialEvents",
        "KeySchema": [
          { "AttributeName": "isInitialEvent", "KeyType": "HASH" },
          { "AttributeName": "timestamp", "KeyType": "RANGE" }
        ],
        "Projection": "KEYS_ONLY"
      }
    ]
  }
}

光盘

import { Table, AttributeType, ProjectionType } from 'aws-cdk-lib/aws-dynamodb';

const { STRING, NUMBER } = AttributeType;
const { KEYS_ONLY } = ProjectionType;

const pokemonsEventsTable = new Table(scope, 'PokemonEvents', {
  partitionKey: {
    name: 'aggregateId',
    type: STRING,
  },
  sortKey: {
    name: 'version',
    type: NUMBER,
  },
});

pokemonsEventsTable.addGlobalSecondaryIndex({
  indexName: 'initialEvents',
  partitionKey: {
    name: 'isInitialEvent',
    type: NUMBER,
  },
  sortKey: {
    name: 'timestamp',
    type: STRING,
  },
  projectionType: KEYS_ONLY,
});

地形

resource "aws_dynamodb_table" "pokemons-events-table" {
  hash_key       = "aggregateId"
  range_key      = "version"

  attribute {
    name = "aggregateId"
    type = "S"
  }

  attribute {
    name = "version"
    type = "N"
  }

  attribute {
    name = "isInitialEvent"
    type = "N"
  }

  attribute {
    name = "timestamp"
    type = "S"
  }

  global_secondary_index {
    name               = "initialEvents"
    hash_key           = "isInitialEvent"
    range_key          = "timestamp"
    projection_type    = "KEYS_ONLY"
  }
}

活动组

此适配器执行 事件组 使用 DynamoDB 交易 API数字 :

import { EventStore } from '@castore/core';

// 👇 TransactWriteItems N events simultaneously
await EventStore.pushEventGroup(
  // events are correctly typed 🙌
  eventStoreA.groupEvent(eventA1),
  eventStoreA.groupEvent(eventA2),
  eventStoreB.groupEvent(eventB),
  ...
);

注意:

  • 交易所涉的所有事件商店都需要使用 DynamoDBEventStorageAdapter
  • 此工具继承 TransactWriteItem API 密码 限制 : 它可以在同一AWS账户和同一区域的一个或多个DynamoDB表格中针对多达100个不同事件.

——————————————

每次操作所需的 IAM 权限 :

  • getEvents (+ 数) getAggregate, (中文(简体) ), getExistingAggregate: dynamodb:Query
  • pushEvent数字 : dynamodb:PutItem
  • listAggregateIds数字 : dynamodb:Query 编辑 initialEvents 指数

版本与发布记录

@castore/event-storage-adapter-dynamodb 共发布 8 个版本,首次发布于 2023/10/28;过去 12 个月发布了 0 个版本。

版本发布日期距今
2.4.2latest2025/04/181.6 年前
2.4.12025/02/251.7 年前
2.4.02025/02/181.7 年前
2.3.12024/04/252 年前
2.3.02024/03/212 年前
2.2.02024/01/172 年前

关于 @castore/event-storage-adapter-dynamodb 的常见问题

@castore/event-storage-adapter-dynamodb 是什么?

DRY Castore EventStorageAdapter 使用 DynamoDB 执行程序

如何安装 @castore/event-storage-adapter-dynamodb?

在项目目录运行 npm install @castore/event-storage-adapter-dynamodb,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:@aws-sdk/client-dynamodb(^3.0.0)、@castore/core(^2.0.0)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@castore/event-storage-adapter-dynamodb 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@castore/event-storage-adapter-dynamodb 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@castore/event-storage-adapter-dynamodb 可以商用吗?

@castore/event-storage-adapter-dynamodb 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@castore/event-storage-adapter-dynamodb 的下载量有多少?

根据 npm 官方下载统计,@castore/event-storage-adapter-dynamodb 在 2026/10/09 – 2026/11/07 这 30 天内被下载 4,975 次,日均约 166 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@castore/event-storage-adapter-dynamodb 还在维护吗?

最新版本 2.4.2 发布于 2025/04/18(1.6 年前);至今共发布 8 个版本,其中过去 12 个月发布了 0 个;首次发布于 2023/10/28。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。