effect-dynamodb 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +69 -0
- package/dist/Aggregate.d.ts +210 -0
- package/dist/Aggregate.d.ts.map +1 -0
- package/dist/Aggregate.js +1169 -0
- package/dist/Aggregate.js.map +1 -0
- package/dist/Batch.d.ts +62 -0
- package/dist/Batch.d.ts.map +1 -0
- package/dist/Batch.js +218 -0
- package/dist/Batch.js.map +1 -0
- package/dist/Collection.d.ts +58 -0
- package/dist/Collection.d.ts.map +1 -0
- package/dist/Collection.js +195 -0
- package/dist/Collection.js.map +1 -0
- package/dist/Collections.d.ts +121 -0
- package/dist/Collections.d.ts.map +1 -0
- package/dist/Collections.js +121 -0
- package/dist/Collections.js.map +1 -0
- package/dist/DynamoClient.d.ts +317 -0
- package/dist/DynamoClient.d.ts.map +1 -0
- package/dist/DynamoClient.js +653 -0
- package/dist/DynamoClient.js.map +1 -0
- package/dist/DynamoModel.d.ts +278 -0
- package/dist/DynamoModel.d.ts.map +1 -0
- package/dist/DynamoModel.js +453 -0
- package/dist/DynamoModel.js.map +1 -0
- package/dist/DynamoSchema.d.ts +137 -0
- package/dist/DynamoSchema.d.ts.map +1 -0
- package/dist/DynamoSchema.js +188 -0
- package/dist/DynamoSchema.js.map +1 -0
- package/dist/Entity.d.ts +628 -0
- package/dist/Entity.d.ts.map +1 -0
- package/dist/Entity.js +2371 -0
- package/dist/Entity.js.map +1 -0
- package/dist/Errors.d.ts +227 -0
- package/dist/Errors.d.ts.map +1 -0
- package/dist/Errors.js +93 -0
- package/dist/Errors.js.map +1 -0
- package/dist/EventStore.d.ts +208 -0
- package/dist/EventStore.d.ts.map +1 -0
- package/dist/EventStore.js +333 -0
- package/dist/EventStore.js.map +1 -0
- package/dist/Expression.d.ts +50 -0
- package/dist/Expression.d.ts.map +1 -0
- package/dist/Expression.js +170 -0
- package/dist/Expression.js.map +1 -0
- package/dist/KeyComposer.d.ts +125 -0
- package/dist/KeyComposer.d.ts.map +1 -0
- package/dist/KeyComposer.js +257 -0
- package/dist/KeyComposer.js.map +1 -0
- package/dist/Marshaller.d.ts +30 -0
- package/dist/Marshaller.d.ts.map +1 -0
- package/dist/Marshaller.js +115 -0
- package/dist/Marshaller.js.map +1 -0
- package/dist/Projection.d.ts +28 -0
- package/dist/Projection.d.ts.map +1 -0
- package/dist/Projection.js +39 -0
- package/dist/Projection.js.map +1 -0
- package/dist/Query.d.ts +214 -0
- package/dist/Query.d.ts.map +1 -0
- package/dist/Query.js +397 -0
- package/dist/Query.js.map +1 -0
- package/dist/Table.d.ts +178 -0
- package/dist/Table.d.ts.map +1 -0
- package/dist/Table.js +211 -0
- package/dist/Table.js.map +1 -0
- package/dist/Transaction.d.ts +79 -0
- package/dist/Transaction.d.ts.map +1 -0
- package/dist/Transaction.js +215 -0
- package/dist/Transaction.js.map +1 -0
- package/dist/_AggregateCursor.d.ts +44 -0
- package/dist/_AggregateCursor.d.ts.map +1 -0
- package/dist/_AggregateCursor.js +18 -0
- package/dist/_AggregateCursor.js.map +1 -0
- package/dist/_AggregateEdges.d.ts +77 -0
- package/dist/_AggregateEdges.d.ts.map +1 -0
- package/dist/_AggregateEdges.js +41 -0
- package/dist/_AggregateEdges.js.map +1 -0
- package/dist/_AggregateSchemas.d.ts +69 -0
- package/dist/_AggregateSchemas.d.ts.map +1 -0
- package/dist/_AggregateSchemas.js +194 -0
- package/dist/_AggregateSchemas.js.map +1 -0
- package/dist/_AggregateTypes.d.ts +94 -0
- package/dist/_AggregateTypes.d.ts.map +1 -0
- package/dist/_AggregateTypes.js +7 -0
- package/dist/_AggregateTypes.js.map +1 -0
- package/dist/_EntityCombinators.d.ts +155 -0
- package/dist/_EntityCombinators.d.ts.map +1 -0
- package/dist/_EntityCombinators.js +158 -0
- package/dist/_EntityCombinators.js.map +1 -0
- package/dist/_EntityConfig.d.ts +100 -0
- package/dist/_EntityConfig.d.ts.map +1 -0
- package/dist/_EntityConfig.js +7 -0
- package/dist/_EntityConfig.js.map +1 -0
- package/dist/_EntityOps.d.ts +205 -0
- package/dist/_EntityOps.d.ts.map +1 -0
- package/dist/_EntityOps.js +137 -0
- package/dist/_EntityOps.js.map +1 -0
- package/dist/_EntitySchemas.d.ts +57 -0
- package/dist/_EntitySchemas.d.ts.map +1 -0
- package/dist/_EntitySchemas.js +298 -0
- package/dist/_EntitySchemas.js.map +1 -0
- package/dist/_EntityTypes.d.ts +81 -0
- package/dist/_EntityTypes.d.ts.map +1 -0
- package/dist/_EntityTypes.js +7 -0
- package/dist/_EntityTypes.js.map +1 -0
- package/dist/_sparse_check.d.ts +2 -0
- package/dist/_sparse_check.d.ts.map +1 -0
- package/dist/_sparse_check.js +193 -0
- package/dist/_sparse_check.js.map +1 -0
- package/dist/index.d.ts +35 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/internal/AggregateCursor.d.ts +44 -0
- package/dist/internal/AggregateCursor.d.ts.map +1 -0
- package/dist/internal/AggregateCursor.js +18 -0
- package/dist/internal/AggregateCursor.js.map +1 -0
- package/dist/internal/AggregateEdges.d.ts +77 -0
- package/dist/internal/AggregateEdges.d.ts.map +1 -0
- package/dist/internal/AggregateEdges.js +41 -0
- package/dist/internal/AggregateEdges.js.map +1 -0
- package/dist/internal/AggregateSchemas.d.ts +69 -0
- package/dist/internal/AggregateSchemas.d.ts.map +1 -0
- package/dist/internal/AggregateSchemas.js +193 -0
- package/dist/internal/AggregateSchemas.js.map +1 -0
- package/dist/internal/AggregateTypes.d.ts +94 -0
- package/dist/internal/AggregateTypes.d.ts.map +1 -0
- package/dist/internal/AggregateTypes.js +7 -0
- package/dist/internal/AggregateTypes.js.map +1 -0
- package/dist/internal/BoundQuery.d.ts +107 -0
- package/dist/internal/BoundQuery.d.ts.map +1 -0
- package/dist/internal/BoundQuery.js +111 -0
- package/dist/internal/BoundQuery.js.map +1 -0
- package/dist/internal/EntityCombinators.d.ts +173 -0
- package/dist/internal/EntityCombinators.d.ts.map +1 -0
- package/dist/internal/EntityCombinators.js +183 -0
- package/dist/internal/EntityCombinators.js.map +1 -0
- package/dist/internal/EntityConfig.d.ts +100 -0
- package/dist/internal/EntityConfig.d.ts.map +1 -0
- package/dist/internal/EntityConfig.js +7 -0
- package/dist/internal/EntityConfig.js.map +1 -0
- package/dist/internal/EntityOps.d.ts +268 -0
- package/dist/internal/EntityOps.d.ts.map +1 -0
- package/dist/internal/EntityOps.js +153 -0
- package/dist/internal/EntityOps.js.map +1 -0
- package/dist/internal/EntitySchemas.d.ts +57 -0
- package/dist/internal/EntitySchemas.d.ts.map +1 -0
- package/dist/internal/EntitySchemas.js +299 -0
- package/dist/internal/EntitySchemas.js.map +1 -0
- package/dist/internal/EntityTypes.d.ts +128 -0
- package/dist/internal/EntityTypes.d.ts.map +1 -0
- package/dist/internal/EntityTypes.js +7 -0
- package/dist/internal/EntityTypes.js.map +1 -0
- package/dist/internal/Expr.d.ts +141 -0
- package/dist/internal/Expr.d.ts.map +1 -0
- package/dist/internal/Expr.js +332 -0
- package/dist/internal/Expr.js.map +1 -0
- package/dist/internal/PathBuilder.d.ts +88 -0
- package/dist/internal/PathBuilder.d.ts.map +1 -0
- package/dist/internal/PathBuilder.js +100 -0
- package/dist/internal/PathBuilder.js.map +1 -0
- package/dist/internal/TransactableOps.d.ts +25 -0
- package/dist/internal/TransactableOps.d.ts.map +1 -0
- package/dist/internal/TransactableOps.js +58 -0
- package/dist/internal/TransactableOps.js.map +1 -0
- package/dist/internal/sparse_check.d.ts +2 -0
- package/dist/internal/sparse_check.d.ts.map +1 -0
- package/dist/internal/sparse_check.js +196 -0
- package/dist/internal/sparse_check.js.map +1 -0
- package/package.json +71 -0
package/dist/Entity.d.ts
ADDED
|
@@ -0,0 +1,628 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Entity — Binds a domain model to a Table with ElectroDB-style index definitions,
|
|
3
|
+
* system field configuration, unique constraints, and CRUD operations.
|
|
4
|
+
*
|
|
5
|
+
* Entity.make() returns a definition + operations namespace. The Entity object
|
|
6
|
+
* carries derived schemas for 7 type extractors (Model, Record, Input, Update,
|
|
7
|
+
* Key, Item, Marshalled).
|
|
8
|
+
*/
|
|
9
|
+
import type { AttributeValue } from "@aws-sdk/client-dynamodb";
|
|
10
|
+
import { Effect, Schema, Stream } from "effect";
|
|
11
|
+
import { DynamoClient, type DynamoClientError } from "./DynamoClient.js";
|
|
12
|
+
import { type ConfiguredModel, type ExtractIdentifier } from "./DynamoModel.js";
|
|
13
|
+
import * as DynamoSchema from "./DynamoSchema.js";
|
|
14
|
+
import { ConditionalCheckFailed, ItemNotFound, OptimisticLockError, UniqueConstraintViolation, ValidationError } from "./Errors.js";
|
|
15
|
+
import type { GsiConfig, IndexDefinition, KeyPart } from "./KeyComposer.js";
|
|
16
|
+
import * as Query from "./Query.js";
|
|
17
|
+
import type { TableConfig } from "./Table.js";
|
|
18
|
+
export type { CascadeIndexConfig, RefValue, SoftDeleteConfig, TimestampFieldConfig, TimestampsConfig, UniqueConfig, UniqueConstraintDef, UniqueFieldsDef, VersionedConfig, } from "./internal/EntityConfig.js";
|
|
19
|
+
export { type CascadeConfig, type CascadeTarget, type DecodeMode, type EntityBase, type EntityDelete, EntityDeleteImpl, EntityDeleteTypeId, type EntityGet, EntityGetImpl, type EntityGetOpts, type EntityOp, EntityOpTypeId, type EntityPut, EntityPutImpl, type EntityUpdate, EntityUpdateImpl, EntityUpdateTypeId, emptyUpdateState, type ReturnValuesMode, returnValuesMap, type UpdateState, } from "./internal/EntityOps.js";
|
|
20
|
+
import { type EntityDelete, type EntityGet, type EntityPut, type EntityUpdate } from "./internal/EntityOps.js";
|
|
21
|
+
export { add, append, asItem, asModel, asNative, asRecord, cascade, consistentRead, deleteFromSet, expectedVersion, pathAdd, pathAppend, pathDelete, pathIfNotExists, pathPrepend, pathRemove, pathSet, pathSubtract, project, remove, returnValues, set, subtract, } from "./internal/EntityCombinators.js";
|
|
22
|
+
import type { CascadeIndexConfig, SoftDeleteConfig, TimestampsConfig, UniqueConfig, VersionedConfig } from "./internal/EntityConfig.js";
|
|
23
|
+
/** A ref config object: the entity and optional cascade index config. */
|
|
24
|
+
interface AnyRefValue {
|
|
25
|
+
readonly entity: Entity<any, any, any, any, any, any, any, any, any>;
|
|
26
|
+
readonly cascade?: CascadeIndexConfig;
|
|
27
|
+
}
|
|
28
|
+
import { type DerivedSchemas, type ResolvedSystemFields } from "./internal/EntitySchemas.js";
|
|
29
|
+
import type { EntityInputType, EntityKeyType, EntityRecordType, EntityRefCreateType, EntityRefInputType, EntityRefUpdateType, EntityUpdateType, IndexPkInput, ModelType, PrimaryKeyComposites, RefErrors } from "./internal/EntityTypes.js";
|
|
30
|
+
export type { IndexDefinition, KeyPart };
|
|
31
|
+
/**
|
|
32
|
+
* An Entity binds a domain model to a DynamoDB Table with index definitions,
|
|
33
|
+
* system field configuration, unique constraints, and CRUD operations.
|
|
34
|
+
*
|
|
35
|
+
* Created via {@link make}. Returns a definition with descriptor builders.
|
|
36
|
+
* Table association and binding happen via `DynamoClient.make()`.
|
|
37
|
+
*
|
|
38
|
+
* @typeParam TModel - Effect Schema defining the domain model
|
|
39
|
+
* @typeParam TEntityType - Literal string discriminator stored as `__edd_e__`
|
|
40
|
+
* @typeParam TIndexes - Index definitions (primary + GSIs)
|
|
41
|
+
* @typeParam TTimestamps - Timestamp configuration
|
|
42
|
+
* @typeParam TVersioned - Optimistic locking configuration
|
|
43
|
+
* @typeParam TSoftDelete - Soft-delete configuration
|
|
44
|
+
* @typeParam TUnique - Unique constraint definitions
|
|
45
|
+
* @typeParam TIdentifier - Identifier field name (auto-generated, omitted from Create type)
|
|
46
|
+
*/
|
|
47
|
+
export interface Entity<TModel extends Schema.Top = Schema.Top, TEntityType extends string = string, TIndexes extends globalThis.Record<string, IndexDefinition> = globalThis.Record<string, IndexDefinition>, TTimestamps extends TimestampsConfig | undefined = TimestampsConfig | undefined, TVersioned extends VersionedConfig | undefined = VersionedConfig | undefined, TSoftDelete extends SoftDeleteConfig | undefined = SoftDeleteConfig | undefined, TUnique extends UniqueConfig | undefined = UniqueConfig | undefined, TRefs extends globalThis.Record<string, AnyRefValue> | undefined = undefined, TIdentifier extends string | undefined = undefined> {
|
|
48
|
+
readonly _tag: "Entity";
|
|
49
|
+
readonly model: TModel;
|
|
50
|
+
readonly entityType: TEntityType;
|
|
51
|
+
readonly indexes: TIndexes;
|
|
52
|
+
readonly timestamps: TTimestamps;
|
|
53
|
+
readonly versioned: TVersioned;
|
|
54
|
+
readonly softDelete: TSoftDelete;
|
|
55
|
+
readonly unique: TUnique;
|
|
56
|
+
readonly identifier: TIdentifier;
|
|
57
|
+
/** @internal Resolved ref metadata — used by cascade to inspect target entities */
|
|
58
|
+
readonly _resolvedRefs: ReadonlyArray<{
|
|
59
|
+
readonly fieldName: string;
|
|
60
|
+
readonly idFieldName: string;
|
|
61
|
+
readonly identifierField: string;
|
|
62
|
+
readonly refEntityType: string;
|
|
63
|
+
}>;
|
|
64
|
+
/** @internal Full decode pipeline: rename + date deser + schema decode. Used by Batch/Aggregate. */
|
|
65
|
+
readonly _decodeRecord: (raw: globalThis.Record<string, unknown>) => Effect.Effect<any, ValidationError>;
|
|
66
|
+
/** @internal Attach model class prototype to a decoded plain object (no-op for Schema.Struct models). */
|
|
67
|
+
readonly _attachPrototype: (decoded: any) => any;
|
|
68
|
+
/**
|
|
69
|
+
* @internal Configure the entity with table schema and tag.
|
|
70
|
+
* Called by DynamoClient.make() when binding entities to a table.
|
|
71
|
+
*/
|
|
72
|
+
readonly _configure: (schema: DynamoSchema.DynamoSchema, tableTag: import("effect").Context.Service<TableConfig, TableConfig>) => void;
|
|
73
|
+
/**
|
|
74
|
+
* @internal Inject a GSI index definition into this entity.
|
|
75
|
+
* Called by Collections binding or DynamoClient.make() to add collection-owned indexes.
|
|
76
|
+
* The injected index becomes available to all entity operations (put, update, etc.)
|
|
77
|
+
* for key composition.
|
|
78
|
+
*/
|
|
79
|
+
readonly _injectIndex: (name: string, def: IndexDefinition) => void;
|
|
80
|
+
/** @internal Injected DynamoSchema — available after _configure(). Used by cascade. */
|
|
81
|
+
readonly _schema: DynamoSchema.DynamoSchema;
|
|
82
|
+
/** @internal Injected TableConfig tag — available after _configure(). Used by cascade. */
|
|
83
|
+
readonly _tableTag: import("effect").Context.Service<TableConfig, TableConfig>;
|
|
84
|
+
/** Resolved system field names */
|
|
85
|
+
readonly systemFields: ResolvedSystemFields;
|
|
86
|
+
/** Derived schemas for type extraction */
|
|
87
|
+
readonly schemas: DerivedSchemas;
|
|
88
|
+
/**
|
|
89
|
+
* Typed input schema. Ref-aware: ref fields are replaced with branded ID fields.
|
|
90
|
+
* Use in HttpApiEndpoint payloads or for validation.
|
|
91
|
+
*
|
|
92
|
+
* @example
|
|
93
|
+
* ```ts
|
|
94
|
+
* HttpApiEndpoint.post("create", "/squads", {
|
|
95
|
+
* payload: SquadSelections.inputSchema,
|
|
96
|
+
* })
|
|
97
|
+
* ```
|
|
98
|
+
*/
|
|
99
|
+
readonly inputSchema: Schema.Codec<EntityRefInputType<TModel, TRefs>>;
|
|
100
|
+
/**
|
|
101
|
+
* Typed create schema. Input fields minus primary key composites — the common
|
|
102
|
+
* "create" payload where IDs are auto-generated.
|
|
103
|
+
*
|
|
104
|
+
* @example
|
|
105
|
+
* ```ts
|
|
106
|
+
* HttpApiEndpoint.post("create", "/teams", {
|
|
107
|
+
* payload: Teams.createSchema,
|
|
108
|
+
* success: Team,
|
|
109
|
+
* })
|
|
110
|
+
* ```
|
|
111
|
+
*/
|
|
112
|
+
readonly createSchema: Schema.Codec<EntityRefCreateType<TModel, TIndexes, TRefs, TIdentifier>>;
|
|
113
|
+
/**
|
|
114
|
+
* Typed update schema. Partial fields minus primary key composites and immutable fields.
|
|
115
|
+
* Ref fields are replaced with optional branded ID fields.
|
|
116
|
+
*/
|
|
117
|
+
readonly updateSchema: Schema.Codec<EntityRefUpdateType<TModel, TIndexes, TRefs>>;
|
|
118
|
+
/** Fetch an item by primary key. Returns a lazy {@link EntityGet} intermediate. */
|
|
119
|
+
readonly get: (key: EntityKeyType<TModel, TIndexes>) => EntityGet<ModelType<TModel>, EntityRecordType<TModel, TTimestamps, TVersioned>, ItemNotFound | DynamoClientError | ValidationError, DynamoClient | TableConfig>;
|
|
120
|
+
/** Create or replace an item. Returns a lazy {@link EntityPut} intermediate. */
|
|
121
|
+
readonly put: (input: EntityRefInputType<TModel, TRefs>) => EntityPut<ModelType<TModel>, EntityRecordType<TModel, TTimestamps, TVersioned>, DynamoClientError | ValidationError | UniqueConstraintViolation | RefErrors<TRefs>, DynamoClient | TableConfig>;
|
|
122
|
+
/**
|
|
123
|
+
* Begin an update operation on an existing item. Returns a lazy {@link EntityUpdate} intermediate.
|
|
124
|
+
* Pipe to {@link set} to provide update fields and {@link expectedVersion} for optimistic locking.
|
|
125
|
+
*/
|
|
126
|
+
readonly update: (key: EntityKeyType<TModel, TIndexes>) => EntityUpdate<ModelType<TModel>, EntityRecordType<TModel, TTimestamps, TVersioned>, EntityRefUpdateType<TModel, TIndexes, TRefs>, DynamoClientError | ItemNotFound | OptimisticLockError | UniqueConstraintViolation | ValidationError | RefErrors<TRefs>, DynamoClient | TableConfig>;
|
|
127
|
+
/** Delete an item by primary key. Returns a lazy {@link EntityDelete} intermediate. */
|
|
128
|
+
readonly delete: (key: EntityKeyType<TModel, TIndexes>) => EntityDelete<DynamoClientError | ItemNotFound, DynamoClient | TableConfig>;
|
|
129
|
+
/**
|
|
130
|
+
* Create a new item. Fails with `ConditionalCheckFailed` if an item with the same
|
|
131
|
+
* primary key already exists. Equivalent to `put(input)` with an `attribute_not_exists` condition.
|
|
132
|
+
*/
|
|
133
|
+
readonly create: (input: EntityRefInputType<TModel, TRefs>) => EntityPut<ModelType<TModel>, EntityRecordType<TModel, TTimestamps, TVersioned>, DynamoClientError | ValidationError | UniqueConstraintViolation | ConditionalCheckFailed | RefErrors<TRefs>, DynamoClient | TableConfig>;
|
|
134
|
+
/**
|
|
135
|
+
* Update an existing item. Fails with `ConditionalCheckFailed` if the item doesn't exist.
|
|
136
|
+
* Equivalent to `update(key)` with an automatic `attribute_exists` condition on the PK field.
|
|
137
|
+
*/
|
|
138
|
+
readonly patch: (key: EntityKeyType<TModel, TIndexes>) => EntityUpdate<ModelType<TModel>, EntityRecordType<TModel, TTimestamps, TVersioned>, EntityRefUpdateType<TModel, TIndexes, TRefs>, DynamoClientError | ItemNotFound | OptimisticLockError | UniqueConstraintViolation | ValidationError | ConditionalCheckFailed | RefErrors<TRefs>, DynamoClient | TableConfig>;
|
|
139
|
+
/**
|
|
140
|
+
* Delete an existing item. Fails with `ConditionalCheckFailed` if the item doesn't exist.
|
|
141
|
+
* Equivalent to `delete(key)` with an automatic `attribute_exists` condition on the PK field.
|
|
142
|
+
*/
|
|
143
|
+
readonly deleteIfExists: (key: EntityKeyType<TModel, TIndexes>) => EntityDelete<DynamoClientError | ItemNotFound | ConditionalCheckFailed, DynamoClient | TableConfig>;
|
|
144
|
+
/**
|
|
145
|
+
* Create or update an item atomically. Uses DynamoDB UpdateItem with `if_not_exists()`
|
|
146
|
+
* for immutable fields and createdAt so they're only set on first creation.
|
|
147
|
+
* Version is incremented atomically: `if_not_exists(version, 0) + 1`.
|
|
148
|
+
* Returns the full record (ReturnValues: ALL_NEW).
|
|
149
|
+
*
|
|
150
|
+
* Does NOT support unique constraints or retain (cannot determine if item existed).
|
|
151
|
+
*/
|
|
152
|
+
readonly upsert: (input: EntityRefInputType<TModel, TRefs>) => EntityPut<ModelType<TModel>, EntityRecordType<TModel, TTimestamps, TVersioned>, DynamoClientError | ValidationError | ItemNotFound | ConditionalCheckFailed | RefErrors<TRefs>, DynamoClient | TableConfig>;
|
|
153
|
+
/** Fetch a specific version snapshot by version number. */
|
|
154
|
+
readonly getVersion: (key: EntityKeyType<TModel, TIndexes>, version: number) => EntityGet<ModelType<TModel>, EntityRecordType<TModel, TTimestamps, TVersioned>, ItemNotFound | DynamoClientError | ValidationError, DynamoClient | TableConfig>;
|
|
155
|
+
/** Query version history for an item. Returns a Query for piping with limit, reverse, collect. */
|
|
156
|
+
readonly versions: (key: EntityKeyType<TModel, TIndexes>) => Query.Query<EntityRecordType<TModel, TTimestamps, TVersioned>>;
|
|
157
|
+
/** Restore a soft-deleted item. Recomposes index keys and re-establishes unique sentinels. */
|
|
158
|
+
readonly restore: (key: EntityKeyType<TModel, TIndexes>) => EntityGet<ModelType<TModel>, EntityRecordType<TModel, TTimestamps, TVersioned>, ItemNotFound | DynamoClientError | ValidationError | UniqueConstraintViolation, DynamoClient | TableConfig>;
|
|
159
|
+
/** Permanently remove an item plus all version history and sentinels. */
|
|
160
|
+
readonly purge: (key: EntityKeyType<TModel, TIndexes>) => EntityDelete<DynamoClientError | ValidationError, DynamoClient | TableConfig>;
|
|
161
|
+
/** Soft-deleted item accessors. */
|
|
162
|
+
readonly deleted: {
|
|
163
|
+
/** Get a specific soft-deleted item. */
|
|
164
|
+
readonly get: (key: EntityKeyType<TModel, TIndexes>) => EntityGet<ModelType<TModel>, EntityRecordType<TModel, TTimestamps, TVersioned>, ItemNotFound | DynamoClientError | ValidationError, DynamoClient | TableConfig>;
|
|
165
|
+
/** List soft-deleted items within a partition. */
|
|
166
|
+
readonly list: (key: EntityKeyType<TModel, TIndexes>) => Query.Query<EntityRecordType<TModel, TTimestamps, TVersioned>>;
|
|
167
|
+
};
|
|
168
|
+
/**
|
|
169
|
+
* Set combinator pre-bound to this entity's update type.
|
|
170
|
+
*
|
|
171
|
+
* GSI all-or-none composites are enforced at runtime via `ValidationError`.
|
|
172
|
+
*
|
|
173
|
+
* @example
|
|
174
|
+
* ```typescript
|
|
175
|
+
* // data-last
|
|
176
|
+
* yield* Users.update({ userId: "u-1" }).pipe(
|
|
177
|
+
* Users.set({ tenantId: "t-3", region: "us-east-1" }),
|
|
178
|
+
* )
|
|
179
|
+
*
|
|
180
|
+
* // data-first
|
|
181
|
+
* Entity.set(Users.update({ userId: "u-1" }), { tenantId: "t-3", region: "us-east-1" })
|
|
182
|
+
* ```
|
|
183
|
+
*/
|
|
184
|
+
readonly set: {
|
|
185
|
+
(updates: EntityRefUpdateType<TModel, TIndexes, TRefs>): <A, Rec, U, E, R>(self: EntityUpdate<A, Rec, U, E, R>) => EntityUpdate<A, Rec, U, E, R>;
|
|
186
|
+
<A, Rec, U, E, R>(self: EntityUpdate<A, Rec, U, E, R>, updates: EntityRefUpdateType<TModel, TIndexes, TRefs>): EntityUpdate<A, Rec, U, E, R>;
|
|
187
|
+
};
|
|
188
|
+
/**
|
|
189
|
+
* Set expected version for optimistic locking.
|
|
190
|
+
* Entity-scoped for consistent pipe chains with {@link Entity.set}.
|
|
191
|
+
*/
|
|
192
|
+
readonly expectedVersion: {
|
|
193
|
+
(version: number): <A, Rec, U, E, R>(self: EntityUpdate<A, Rec, U, E, R>) => EntityUpdate<A, Rec, U, E, R>;
|
|
194
|
+
<A, Rec, U, E, R>(self: EntityUpdate<A, Rec, U, E, R>, version: number): EntityUpdate<A, Rec, U, E, R>;
|
|
195
|
+
};
|
|
196
|
+
/** Index query accessors. Each non-primary index becomes a method that accepts PK composites and returns a {@link Query.Query}. */
|
|
197
|
+
readonly query: {
|
|
198
|
+
readonly [K in Exclude<keyof TIndexes, "primary">]: (pk: IndexPkInput<TModel, TIndexes, K, TRefs>) => Query.Query<ModelType<TModel>>;
|
|
199
|
+
};
|
|
200
|
+
/** Scan all items of this entity type. Returns a {@link Query.Query} that uses DynamoDB Scan. */
|
|
201
|
+
readonly scan: () => Query.Query<ModelType<TModel>>;
|
|
202
|
+
/**
|
|
203
|
+
* Build a condition expression combinator.
|
|
204
|
+
* Callback receives `(t, ops)` where `t` is a PathBuilder and `ops` provides comparison functions.
|
|
205
|
+
* Shorthand accepts a simple object for AND-equality conditions.
|
|
206
|
+
*
|
|
207
|
+
* @example
|
|
208
|
+
* ```typescript
|
|
209
|
+
* // Callback
|
|
210
|
+
* Teams.condition((t, { eq }) => eq(t.status, "active"))
|
|
211
|
+
* // Shorthand
|
|
212
|
+
* Teams.condition({ status: "active" })
|
|
213
|
+
* ```
|
|
214
|
+
*/
|
|
215
|
+
readonly condition: {
|
|
216
|
+
(cb: (t: import("./internal/PathBuilder.js").PathBuilder<ModelType<TModel>, ModelType<TModel>>, ops: import("./internal/Expr.js").ConditionOps<ModelType<TModel>>) => import("./internal/Expr.js").Expr): <T extends EntityPut<any, any, any, any> | EntityUpdate<any, any, any, any, any> | EntityDelete<any, any>>(self: T) => T;
|
|
217
|
+
(shorthand: globalThis.Record<string, unknown>): <T extends EntityPut<any, any, any, any> | EntityUpdate<any, any, any, any, any> | EntityDelete<any, any>>(self: T) => T;
|
|
218
|
+
};
|
|
219
|
+
/**
|
|
220
|
+
* Build a filter expression for query/scan operations.
|
|
221
|
+
* Same API as `condition()` — callback or shorthand.
|
|
222
|
+
*
|
|
223
|
+
* @example
|
|
224
|
+
* ```typescript
|
|
225
|
+
* teams.collect(Teams.query.byAll(pk), Teams.filter((t, { gt }) => gt(t.wins, 10)))
|
|
226
|
+
* ```
|
|
227
|
+
*/
|
|
228
|
+
readonly filter: {
|
|
229
|
+
(cb: (t: import("./internal/PathBuilder.js").PathBuilder<ModelType<TModel>, ModelType<TModel>>, ops: import("./internal/Expr.js").ConditionOps<ModelType<TModel>>) => import("./internal/Expr.js").Expr): <A>(self: Query.Query<A>) => Query.Query<A>;
|
|
230
|
+
(shorthand: globalThis.Record<string, unknown>): <A>(self: Query.Query<A>) => Query.Query<A>;
|
|
231
|
+
};
|
|
232
|
+
/**
|
|
233
|
+
* Build a select (projection) combinator for get/query/scan operations.
|
|
234
|
+
* Callback receives `t` — a PathBuilder. Returns an array of paths to project.
|
|
235
|
+
* String array shorthand for top-level only projections.
|
|
236
|
+
*
|
|
237
|
+
* @example
|
|
238
|
+
* ```typescript
|
|
239
|
+
* Teams.select((t) => [t.name, t.address.city])
|
|
240
|
+
* Teams.select(["name", "status"])
|
|
241
|
+
* ```
|
|
242
|
+
*/
|
|
243
|
+
readonly select: {
|
|
244
|
+
(cb: (t: import("./internal/PathBuilder.js").PathBuilder<ModelType<TModel>, ModelType<TModel>>) => ReadonlyArray<import("./internal/PathBuilder.js").Path<ModelType<TModel>, any>>): (self: Query.Query<any>) => Query.Query<any>;
|
|
245
|
+
(attributes: ReadonlyArray<string>): (self: Query.Query<any>) => Query.Query<any>;
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* An Entity whose CRUD operations have `DynamoClient` and `TableConfig` already
|
|
250
|
+
* resolved, so all methods return `Effect<A, E, never>`.
|
|
251
|
+
*
|
|
252
|
+
* Created via {@link bind}. Use in service layers to avoid leaking infrastructure
|
|
253
|
+
* requirements through service method signatures.
|
|
254
|
+
*
|
|
255
|
+
* @example
|
|
256
|
+
* ```typescript
|
|
257
|
+
* export class TeamService extends Context.Service<TeamService>()("TeamService", {
|
|
258
|
+
* make: Effect.gen(function* () {
|
|
259
|
+
* const db = yield* DynamoClient.make({ entities: { Teams }, tables: { MainTable } })
|
|
260
|
+
* const teams = db.entities.Teams
|
|
261
|
+
* return {
|
|
262
|
+
* get: (id: TeamId) => teams.get({ id }), // R = never
|
|
263
|
+
* create: (input) => teams.create({ ...input }), // R = never
|
|
264
|
+
* list: (filter) => teams.byAll(filter).collect(), // R = never
|
|
265
|
+
* }
|
|
266
|
+
* }),
|
|
267
|
+
* }) {}
|
|
268
|
+
* ```
|
|
269
|
+
*/
|
|
270
|
+
/** Combinator that transforms a put/create/upsert operation. */
|
|
271
|
+
export type PutCombinator<M> = (op: EntityPut<M, any, any, any>) => EntityPut<M, any, any, any>;
|
|
272
|
+
/** Combinator that transforms an update/patch operation. */
|
|
273
|
+
export type UpdateCombinator<M> = (op: EntityUpdate<M, any, any, any, any>) => EntityUpdate<M, any, any, any, any>;
|
|
274
|
+
/** Combinator that transforms a delete operation. */
|
|
275
|
+
export type DeleteCombinator = (op: EntityDelete<any, any>) => EntityDelete<any, any>;
|
|
276
|
+
export interface BoundEntity<TModel extends Schema.Top, TIndexes extends globalThis.Record<string, IndexDefinition>, TRefs extends globalThis.Record<string, AnyRefValue> | undefined, TKey = EntityKeyType<TModel, TIndexes>> {
|
|
277
|
+
/** Fetch an item by primary key. Returns an Effect that resolves to the model type. */
|
|
278
|
+
readonly get: (key: TKey) => Effect.Effect<ModelType<TModel>, ItemNotFound | DynamoClientError | ValidationError, never>;
|
|
279
|
+
/** Create or replace an item. Accepts optional combinators (e.g. `Entity.condition(...)`). */
|
|
280
|
+
readonly put: (input: EntityRefInputType<TModel, TRefs>, ...combinators: ReadonlyArray<PutCombinator<ModelType<TModel>>>) => Effect.Effect<ModelType<TModel>, DynamoClientError | ValidationError | UniqueConstraintViolation | RefErrors<TRefs>, never>;
|
|
281
|
+
/** Create a new item. Fails if primary key already exists. Accepts optional combinators. */
|
|
282
|
+
readonly create: (input: EntityRefInputType<TModel, TRefs>, ...combinators: ReadonlyArray<PutCombinator<ModelType<TModel>>>) => Effect.Effect<ModelType<TModel>, DynamoClientError | ValidationError | UniqueConstraintViolation | ConditionalCheckFailed | RefErrors<TRefs>, never>;
|
|
283
|
+
/**
|
|
284
|
+
* Update an existing item. Applies combinators and returns an Effect.
|
|
285
|
+
*
|
|
286
|
+
* ```ts
|
|
287
|
+
* yield* teams.update({ id }, Entity.set(updates), Entity.expectedVersion(3))
|
|
288
|
+
* ```
|
|
289
|
+
*/
|
|
290
|
+
readonly update: (key: TKey, ...combinators: ReadonlyArray<UpdateCombinator<ModelType<TModel>>>) => Effect.Effect<ModelType<TModel>, DynamoClientError | ItemNotFound | OptimisticLockError | UniqueConstraintViolation | ValidationError | RefErrors<TRefs>, never>;
|
|
291
|
+
/** Delete an item by primary key. Accepts optional combinators (e.g. `Entity.condition(...)`). */
|
|
292
|
+
readonly delete: (key: TKey, ...combinators: ReadonlyArray<DeleteCombinator>) => Effect.Effect<void, DynamoClientError | ItemNotFound, never>;
|
|
293
|
+
/**
|
|
294
|
+
* Create or update an item atomically. Uses DynamoDB UpdateItem with `if_not_exists()`
|
|
295
|
+
* for immutable fields and createdAt so they're only set on first creation.
|
|
296
|
+
* Accepts optional combinators.
|
|
297
|
+
*/
|
|
298
|
+
readonly upsert: (input: EntityRefInputType<TModel, TRefs>, ...combinators: ReadonlyArray<PutCombinator<ModelType<TModel>>>) => Effect.Effect<ModelType<TModel>, DynamoClientError | ValidationError | ItemNotFound | ConditionalCheckFailed | RefErrors<TRefs>, never>;
|
|
299
|
+
/**
|
|
300
|
+
* Update an existing item. Fails with `ConditionalCheckFailed` if the item doesn't exist.
|
|
301
|
+
* Applies combinators and returns an Effect.
|
|
302
|
+
*
|
|
303
|
+
* ```ts
|
|
304
|
+
* yield* teams.patch({ id }, Entity.set(updates))
|
|
305
|
+
* ```
|
|
306
|
+
*/
|
|
307
|
+
readonly patch: (key: TKey, ...combinators: ReadonlyArray<UpdateCombinator<ModelType<TModel>>>) => Effect.Effect<ModelType<TModel>, DynamoClientError | ItemNotFound | OptimisticLockError | UniqueConstraintViolation | ValidationError | ConditionalCheckFailed | RefErrors<TRefs>, never>;
|
|
308
|
+
/** Delete an existing item, fails if not found. Accepts optional combinators. */
|
|
309
|
+
readonly deleteIfExists: (key: TKey, ...combinators: ReadonlyArray<DeleteCombinator>) => Effect.Effect<void, DynamoClientError | ItemNotFound | ConditionalCheckFailed, never>;
|
|
310
|
+
/** Fetch a specific version snapshot by version number. */
|
|
311
|
+
readonly getVersion: (key: TKey, version: number) => Effect.Effect<ModelType<TModel>, ItemNotFound | DynamoClientError | ValidationError, never>;
|
|
312
|
+
/**
|
|
313
|
+
* List all version snapshots for an item as a fluent BoundQuery.
|
|
314
|
+
* Requires `versioned: { retain: true }` on the entity definition.
|
|
315
|
+
*
|
|
316
|
+
* ```ts
|
|
317
|
+
* const all = yield* db.entities.Users.versions({ userId: "u-1" }).collect()
|
|
318
|
+
* const last5 = yield* db.entities.Users
|
|
319
|
+
* .versions({ userId: "u-1" })
|
|
320
|
+
* .reverse()
|
|
321
|
+
* .limit(5)
|
|
322
|
+
* .collect()
|
|
323
|
+
* ```
|
|
324
|
+
*/
|
|
325
|
+
readonly versions: (key: TKey) => import("./internal/BoundQuery.js").BoundQuery<ModelType<TModel>, never, ModelType<TModel>>;
|
|
326
|
+
/** Restore a soft-deleted item. */
|
|
327
|
+
readonly restore: (key: TKey) => Effect.Effect<ModelType<TModel>, ItemNotFound | DynamoClientError | ValidationError | UniqueConstraintViolation, never>;
|
|
328
|
+
/** Permanently remove an item plus all version history and sentinels. */
|
|
329
|
+
readonly purge: (key: TKey) => Effect.Effect<void, DynamoClientError | ValidationError, never>;
|
|
330
|
+
/** Soft-deleted item accessors. */
|
|
331
|
+
readonly deleted: {
|
|
332
|
+
/** Get a specific soft-deleted item. */
|
|
333
|
+
readonly get: (key: TKey) => Effect.Effect<ModelType<TModel>, ItemNotFound | DynamoClientError | ValidationError, never>;
|
|
334
|
+
/**
|
|
335
|
+
* List all soft-deleted items in this partition as a fluent BoundQuery.
|
|
336
|
+
* Requires `softDelete` on the entity definition.
|
|
337
|
+
*
|
|
338
|
+
* ```ts
|
|
339
|
+
* const tombstones = yield* db.entities.Employees.deleted
|
|
340
|
+
* .list({ employeeId: "e-1" })
|
|
341
|
+
* .collect()
|
|
342
|
+
* ```
|
|
343
|
+
*/
|
|
344
|
+
readonly list: (key: TKey) => import("./internal/BoundQuery.js").BoundQuery<ModelType<TModel>, never, ModelType<TModel>>;
|
|
345
|
+
};
|
|
346
|
+
/**
|
|
347
|
+
* Execute a query and return a lazy Stream of items. Automatically paginates through all pages.
|
|
348
|
+
* Accepts optional query combinators (e.g. `Query.limit(...)`, `Query.reverse`).
|
|
349
|
+
*
|
|
350
|
+
* ```ts
|
|
351
|
+
* const stream = teams.paginate(Teams.query.byRole({ role: "admin" }), Query.limit(10))
|
|
352
|
+
* ```
|
|
353
|
+
*/
|
|
354
|
+
readonly paginate: <A>(query: Query.Query<A>, ...combinators: ReadonlyArray<(q: Query.Query<A>) => Query.Query<A>>) => Stream.Stream<A, DynamoClientError | ValidationError, never>;
|
|
355
|
+
/**
|
|
356
|
+
* Execute a query and collect all pages into a single array.
|
|
357
|
+
* Accepts optional query combinators (e.g. `Query.limit(...)`, `Query.reverse`).
|
|
358
|
+
*
|
|
359
|
+
* ```ts
|
|
360
|
+
* const items = yield* teams.collect(Teams.query.byRole({ role: "admin" }), Query.limit(10))
|
|
361
|
+
* ```
|
|
362
|
+
*/
|
|
363
|
+
readonly collect: <A>(query: Query.Query<A>, ...combinators: ReadonlyArray<(q: Query.Query<A>) => Query.Query<A>>) => Effect.Effect<Array<A>, DynamoClientError | ValidationError, never>;
|
|
364
|
+
/**
|
|
365
|
+
* Execute a single DynamoDB page and return a {@link Query.Page} with an opaque cursor.
|
|
366
|
+
* Use `Query.startFrom(cursor)` to iterate through subsequent pages.
|
|
367
|
+
* Accepts optional query combinators (e.g. `Query.limit(...)`, `Query.reverse`).
|
|
368
|
+
*
|
|
369
|
+
* ```ts
|
|
370
|
+
* const page = yield* teams.fetch(Teams.query.byRole({ role: "admin" }), Query.limit(25))
|
|
371
|
+
* if (page.cursor) {
|
|
372
|
+
* const next = yield* teams.fetch(Teams.query.byRole({ role: "admin" }), Query.limit(25), Query.startFrom(page.cursor))
|
|
373
|
+
* }
|
|
374
|
+
* ```
|
|
375
|
+
*/
|
|
376
|
+
readonly fetch: <A>(query: Query.Query<A>, ...combinators: ReadonlyArray<(q: Query.Query<A>) => Query.Query<A>>) => Effect.Effect<Query.Page<A>, DynamoClientError | ValidationError, never>;
|
|
377
|
+
/**
|
|
378
|
+
* Execute a single DynamoDB scan page and return a {@link Query.Page} with an opaque cursor.
|
|
379
|
+
* Convenience for `fetch(Entity.scan(), ...)`. Use `Query.startFrom(cursor)` for subsequent pages.
|
|
380
|
+
* Accepts optional query combinators (e.g. `Query.limit(...)`, `Query.filter(...)`).
|
|
381
|
+
*
|
|
382
|
+
* ```ts
|
|
383
|
+
* const page = yield* teams.scanFetch(Query.limit(25))
|
|
384
|
+
* if (page.cursor) {
|
|
385
|
+
* const next = yield* teams.scanFetch(Query.limit(25), Query.startFrom(page.cursor))
|
|
386
|
+
* }
|
|
387
|
+
* ```
|
|
388
|
+
*/
|
|
389
|
+
readonly scanFetch: (...combinators: ReadonlyArray<(q: Query.Query<ModelType<TModel>>) => Query.Query<ModelType<TModel>>>) => Effect.Effect<Query.Page<ModelType<TModel>>, DynamoClientError | ValidationError, never>;
|
|
390
|
+
}
|
|
391
|
+
/**
|
|
392
|
+
* Create a new Entity — binding a domain model to a Table with index definitions
|
|
393
|
+
* and optional system field configuration.
|
|
394
|
+
*
|
|
395
|
+
* @param config - Entity configuration
|
|
396
|
+
* @param config.model - Effect Schema class or struct defining the domain model
|
|
397
|
+
* @param config.entityType - Literal string discriminator stored as `__edd_e__`
|
|
398
|
+
* @param config.indexes - ElectroDB-style composite key definitions (must include `primary`)
|
|
399
|
+
* @param config.timestamps - Automatic `createdAt` / `updatedAt` fields
|
|
400
|
+
* @param config.versioned - Optimistic locking via auto-incrementing version field
|
|
401
|
+
* @param config.softDelete - Soft-delete behavior
|
|
402
|
+
* @param config.unique - Named unique constraints enforced via transaction sentinels
|
|
403
|
+
* @returns An {@link Entity} with typed CRUD operations and index query accessors
|
|
404
|
+
*
|
|
405
|
+
* @example
|
|
406
|
+
* ```typescript
|
|
407
|
+
* const Users = Entity.make({
|
|
408
|
+
* model: User,
|
|
409
|
+
* table: MainTable,
|
|
410
|
+
* entityType: "User",
|
|
411
|
+
* indexes: {
|
|
412
|
+
* primary: { pk: { field: "pk", composite: ["userId"] }, sk: { field: "sk", composite: [] } },
|
|
413
|
+
* byEmail: { index: "gsi1", pk: { field: "gsi1pk", composite: ["email"] }, sk: { field: "gsi1sk", composite: [] } },
|
|
414
|
+
* },
|
|
415
|
+
* timestamps: true,
|
|
416
|
+
* versioned: true,
|
|
417
|
+
* })
|
|
418
|
+
* ```
|
|
419
|
+
*/
|
|
420
|
+
/** Compute the normalized indexes type from primaryKey + optional GSI configs. */
|
|
421
|
+
type NormalizedIndexes<TPrimaryKey extends PrimaryKeyDef, TGsiIndexes extends globalThis.Record<string, GsiConfig>> = keyof TGsiIndexes extends never ? {
|
|
422
|
+
readonly primary: TPrimaryKey;
|
|
423
|
+
} : {
|
|
424
|
+
readonly primary: TPrimaryKey;
|
|
425
|
+
} & {
|
|
426
|
+
readonly [K in keyof TGsiIndexes & string]: IndexDefinition & {
|
|
427
|
+
readonly collection: TGsiIndexes[K]["collection"];
|
|
428
|
+
readonly pk: {
|
|
429
|
+
readonly composite: TGsiIndexes[K]["pk"]["composite"];
|
|
430
|
+
};
|
|
431
|
+
readonly sk: {
|
|
432
|
+
readonly composite: TGsiIndexes[K]["sk"]["composite"];
|
|
433
|
+
};
|
|
434
|
+
};
|
|
435
|
+
};
|
|
436
|
+
/** Primary key definition — used in the new `primaryKey` config form. */
|
|
437
|
+
type PrimaryKeyDef = IndexDefinition & ({
|
|
438
|
+
readonly pk: {
|
|
439
|
+
readonly composite: readonly [string, ...string[]];
|
|
440
|
+
};
|
|
441
|
+
} | {
|
|
442
|
+
readonly sk: {
|
|
443
|
+
readonly composite: readonly [string, ...string[]];
|
|
444
|
+
};
|
|
445
|
+
});
|
|
446
|
+
/**
|
|
447
|
+
* Create an Entity definition.
|
|
448
|
+
*
|
|
449
|
+
* `primaryKey` defines the table's primary key. `indexes` optionally defines GSI
|
|
450
|
+
* access patterns. GSIs with a `collection` property are auto-discovered as
|
|
451
|
+
* cross-entity collections by `DynamoClient.make()`.
|
|
452
|
+
*
|
|
453
|
+
* @example
|
|
454
|
+
* ```typescript
|
|
455
|
+
* const Tasks = Entity.make({
|
|
456
|
+
* model: Task,
|
|
457
|
+
* entityType: "Task",
|
|
458
|
+
* primaryKey: {
|
|
459
|
+
* pk: { field: "pk", composite: ["taskId"] },
|
|
460
|
+
* sk: { field: "sk", composite: [] },
|
|
461
|
+
* },
|
|
462
|
+
* indexes: {
|
|
463
|
+
* byProject: {
|
|
464
|
+
* name: "gsi1",
|
|
465
|
+
* pk: { field: "gsi1pk", composite: ["projectId"] },
|
|
466
|
+
* sk: { field: "gsi1sk", composite: ["status"] },
|
|
467
|
+
* },
|
|
468
|
+
* assigned: {
|
|
469
|
+
* collection: "assignments",
|
|
470
|
+
* name: "gsi2",
|
|
471
|
+
* pk: { field: "gsi2pk", composite: ["employee"] },
|
|
472
|
+
* sk: { field: "gsi2sk", composite: ["project"] },
|
|
473
|
+
* },
|
|
474
|
+
* },
|
|
475
|
+
* })
|
|
476
|
+
* ```
|
|
477
|
+
*/
|
|
478
|
+
export declare const make: <TModel extends Schema.Top, const TEntityType extends string, const TPrimaryKey extends PrimaryKeyDef, const TGsiIndexes extends globalThis.Record<string, GsiConfig> = {}, const TTimestamps extends TimestampsConfig | undefined = undefined, const TVersioned extends VersionedConfig | undefined = undefined, const TSoftDelete extends SoftDeleteConfig | undefined = undefined, const TUnique extends UniqueConfig | undefined = undefined, const TRefs extends globalThis.Record<string, AnyRefValue> | undefined = undefined, const TAttrs extends {} = {}>(config: {
|
|
479
|
+
readonly model: TModel | ConfiguredModel<TModel, TAttrs>;
|
|
480
|
+
readonly entityType: TEntityType;
|
|
481
|
+
readonly primaryKey: TPrimaryKey;
|
|
482
|
+
readonly indexes?: TGsiIndexes;
|
|
483
|
+
readonly timestamps?: TTimestamps;
|
|
484
|
+
readonly versioned?: TVersioned;
|
|
485
|
+
readonly softDelete?: TSoftDelete;
|
|
486
|
+
readonly unique?: TUnique;
|
|
487
|
+
readonly refs?: TRefs;
|
|
488
|
+
}) => Entity<TModel, TEntityType, NormalizedIndexes<TPrimaryKey, TGsiIndexes>, TTimestamps, TVersioned, TSoftDelete, TUnique, TRefs, ExtractIdentifier<ConfiguredModel<TModel, TAttrs>>>;
|
|
489
|
+
/**
|
|
490
|
+
* Bind an Entity to resolved `DynamoClient` and `TableConfig` services.
|
|
491
|
+
* Returns a {@link BoundEntity} where all operations have `R = never`.
|
|
492
|
+
*
|
|
493
|
+
* @internal Used by `DynamoClient.make()` to bind entities.
|
|
494
|
+
*/
|
|
495
|
+
export declare const bind: <TModel extends Schema.Top, TEntityType extends string, TIndexes extends globalThis.Record<string, IndexDefinition>, TTimestamps extends TimestampsConfig | undefined, TVersioned extends VersionedConfig | undefined, TSoftDelete extends SoftDeleteConfig | undefined, TUnique extends UniqueConfig | undefined, TRefs extends globalThis.Record<string, AnyRefValue> | undefined, TIdentifier extends string | undefined>(entity: Entity<TModel, TEntityType, TIndexes, TTimestamps, TVersioned, TSoftDelete, TUnique, TRefs, TIdentifier>) => Effect.Effect<BoundEntity<TModel, TIndexes, TRefs>, never, DynamoClient | TableConfig>;
|
|
496
|
+
export interface TransactableInfo {
|
|
497
|
+
readonly opType: "get" | "put" | "update" | "delete";
|
|
498
|
+
readonly entity: Entity;
|
|
499
|
+
readonly key?: globalThis.Record<string, unknown> | undefined;
|
|
500
|
+
readonly input?: globalThis.Record<string, unknown> | undefined;
|
|
501
|
+
}
|
|
502
|
+
/**
|
|
503
|
+
* Extract transactable metadata from an Entity operation intermediate.
|
|
504
|
+
* Returns undefined if the value is not a recognized entity operation.
|
|
505
|
+
*/
|
|
506
|
+
export declare const extractTransactable: (op: unknown) => TransactableInfo | undefined;
|
|
507
|
+
/**
|
|
508
|
+
* Extract the pure model type from an Entity.
|
|
509
|
+
*
|
|
510
|
+
* `Entity.Model<typeof Users>` = `{ userId: string, email: string, ... }`
|
|
511
|
+
*/
|
|
512
|
+
export type Model<E extends {
|
|
513
|
+
readonly model: Schema.Top;
|
|
514
|
+
}> = ModelType<E["model"]>;
|
|
515
|
+
/**
|
|
516
|
+
* Extract the record type (model + system fields) from an Entity.
|
|
517
|
+
*
|
|
518
|
+
* `Entity.Record<typeof Users>` = model fields + createdAt, updatedAt, version
|
|
519
|
+
*/
|
|
520
|
+
export type Record<E extends {
|
|
521
|
+
readonly model: Schema.Top;
|
|
522
|
+
readonly timestamps: any;
|
|
523
|
+
readonly versioned: any;
|
|
524
|
+
}> = EntityRecordType<E["model"], E["timestamps"], E["versioned"]>;
|
|
525
|
+
/**
|
|
526
|
+
* Extract the input type from an Entity. Ref-aware: when refs are present,
|
|
527
|
+
* ref fields are replaced with `${field}Id: string`.
|
|
528
|
+
*
|
|
529
|
+
* `Entity.Input<typeof Users>` = model fields only
|
|
530
|
+
* `Entity.Input<typeof TeamPlayerSelection>` = `{ teamId: string, playerId: string, ... }`
|
|
531
|
+
*/
|
|
532
|
+
export type Input<E extends {
|
|
533
|
+
readonly model: Schema.Top;
|
|
534
|
+
}> = E extends Entity<infer M extends Schema.Top, any, any, any, any, any, any, infer R, any> ? EntityRefInputType<M, R> : EntityInputType<E["model"]>;
|
|
535
|
+
/**
|
|
536
|
+
* Extract the create type from an Entity — input fields minus the identifier.
|
|
537
|
+
* Uses the `identifier` config to determine which field to omit.
|
|
538
|
+
* Falls back to omitting all primary key composites when no identifier is set.
|
|
539
|
+
*
|
|
540
|
+
* `Entity.Create<typeof Teams>` = `{ name: string, gender: Gender, league: League }`
|
|
541
|
+
*/
|
|
542
|
+
export type Create<E extends {
|
|
543
|
+
readonly model: Schema.Top;
|
|
544
|
+
readonly indexes: any;
|
|
545
|
+
}> = E extends Entity<infer M extends Schema.Top, any, infer I, any, any, any, any, infer R, infer Id> ? EntityRefCreateType<M, I, R, Id extends string ? Id : undefined> : Omit<EntityInputType<E["model"]>, PrimaryKeyComposites<E["indexes"]>>;
|
|
546
|
+
/**
|
|
547
|
+
* Extract the update type from an Entity. Ref-aware: when refs are present,
|
|
548
|
+
* ref fields are replaced with optional `${field}Id?: string`.
|
|
549
|
+
*
|
|
550
|
+
* `Entity.Update<typeof Users>` = `{ email?: string, displayName?: string, ... }`
|
|
551
|
+
*/
|
|
552
|
+
export type Update<E extends {
|
|
553
|
+
readonly model: Schema.Top;
|
|
554
|
+
readonly indexes: any;
|
|
555
|
+
}> = E extends Entity<infer M extends Schema.Top, any, infer I, any, any, any, any, infer R, any> ? EntityRefUpdateType<M, I, R> : EntityUpdateType<E["model"], E["indexes"]>;
|
|
556
|
+
/**
|
|
557
|
+
* Extract the key type from an Entity.
|
|
558
|
+
* Primary index pk + sk composite attributes only.
|
|
559
|
+
*
|
|
560
|
+
* `Entity.Key<typeof Users>` = `{ userId: string }`
|
|
561
|
+
*/
|
|
562
|
+
export type Key<E extends {
|
|
563
|
+
readonly model: Schema.Top;
|
|
564
|
+
readonly indexes: any;
|
|
565
|
+
}> = EntityKeyType<E["model"], E["indexes"]>;
|
|
566
|
+
/**
|
|
567
|
+
* Extract the full DynamoDB item type (unmarshalled).
|
|
568
|
+
* Record + key attributes + __edd_e__.
|
|
569
|
+
*
|
|
570
|
+
* `Entity.Item<typeof Users>` = record + pk, sk, gsi1pk, etc. + __edd_e__
|
|
571
|
+
*/
|
|
572
|
+
export type Item<E extends {
|
|
573
|
+
readonly schemas: DerivedSchemas;
|
|
574
|
+
}> = Schema.Schema.Type<E["schemas"]["itemSchema"]>;
|
|
575
|
+
/**
|
|
576
|
+
* Marshalled DynamoDB item (AttributeValue format).
|
|
577
|
+
* For now, a simple record type. Full typing comes in Group 5.
|
|
578
|
+
*/
|
|
579
|
+
export type Marshalled<_E> = globalThis.Record<string, {
|
|
580
|
+
readonly S?: string;
|
|
581
|
+
readonly N?: string;
|
|
582
|
+
readonly BOOL?: boolean;
|
|
583
|
+
readonly NULL?: boolean;
|
|
584
|
+
readonly L?: ReadonlyArray<unknown>;
|
|
585
|
+
readonly M?: globalThis.Record<string, unknown>;
|
|
586
|
+
}>;
|
|
587
|
+
/** Minimal structural type for utility accessors (avoids Entity invariance issues). */
|
|
588
|
+
interface EntityLike {
|
|
589
|
+
readonly indexes: globalThis.Record<string, IndexDefinition>;
|
|
590
|
+
}
|
|
591
|
+
/**
|
|
592
|
+
* Get the names of all primary key composite attributes for an entity.
|
|
593
|
+
*/
|
|
594
|
+
export declare const keyAttributes: (entity: EntityLike) => ReadonlyArray<string>;
|
|
595
|
+
/**
|
|
596
|
+
* Get the names of all key field attributes (pk, sk, gsi1pk, etc.) for an entity.
|
|
597
|
+
*/
|
|
598
|
+
export declare const keyFieldNames: (entity: EntityLike) => ReadonlyArray<string>;
|
|
599
|
+
/**
|
|
600
|
+
* Get the names of all composite attributes across all indexes.
|
|
601
|
+
*/
|
|
602
|
+
export declare const compositeAttributes: (entity: EntityLike) => ReadonlyArray<string>;
|
|
603
|
+
/** Minimal structural type for schema accessors. */
|
|
604
|
+
interface EntityWithSchemas {
|
|
605
|
+
readonly schemas: DerivedSchemas;
|
|
606
|
+
readonly _attachPrototype?: (decoded: any) => any;
|
|
607
|
+
}
|
|
608
|
+
/**
|
|
609
|
+
* Get the item schema for an entity.
|
|
610
|
+
*
|
|
611
|
+
* Returns a Schema that decodes unmarshalled DynamoDB items (plain JS objects
|
|
612
|
+
* from `Marshaller.fromAttributeMap`) into Entity.Record instances.
|
|
613
|
+
*
|
|
614
|
+
* Useful for consuming DynamoDB Streams or working with raw query results.
|
|
615
|
+
*/
|
|
616
|
+
export declare const itemSchema: (entity: EntityWithSchemas) => Schema.Codec<any>;
|
|
617
|
+
/**
|
|
618
|
+
* Decode a marshalled DynamoDB item (AttributeValue format) into a typed Entity.Record.
|
|
619
|
+
*
|
|
620
|
+
* Unmarshalls the AttributeValue map to plain JS, then decodes via the entity's item schema.
|
|
621
|
+
* Useful for consuming DynamoDB Streams events or raw SDK responses.
|
|
622
|
+
*
|
|
623
|
+
* Returns an Effect that fails with `ValidationError` if the item doesn't match the schema.
|
|
624
|
+
*/
|
|
625
|
+
export declare const decodeMarshalledItem: (entity: EntityWithSchemas & {
|
|
626
|
+
readonly entityType: string;
|
|
627
|
+
}, marshalledItem: globalThis.Record<string, AttributeValue>) => Effect.Effect<unknown, ValidationError>;
|
|
628
|
+
//# sourceMappingURL=Entity.d.ts.map
|