@celerity-sdk/datastore 0.3.1 → 0.4.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/README.md +5 -5
- package/dist/index.cjs +657 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +381 -1
- package/dist/index.d.ts +381 -1
- package/dist/index.js +631 -0
- package/dist/index.js.map +1 -1
- package/package.json +18 -7
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/types.ts","../src/providers/dynamodb/dynamodb-datastore-client.ts","../src/providers/dynamodb/dynamodb-datastore.ts","../src/errors.ts","../src/providers/dynamodb/dynamodb-item-listing.ts","../src/providers/dynamodb/expressions.ts","../src/providers/dynamodb/errors.ts","../src/providers/dynamodb/config.ts","../src/factory.ts","../src/decorators.ts","../src/helpers.ts","../src/layer.ts"],"sourcesContent":["import type { Closeable } from \"@celerity-sdk/types\";\n\nexport const DatastoreClient = Symbol.for(\"DatastoreClient\");\n\n/**\n * A data store client abstraction for NoSQL databases. Provides access to named\n * data stores (tables/collections), each representing a logical container for items.\n */\nexport interface DatastoreClient extends Closeable {\n /**\n * Retrieves a datastore instance by its logical name. The returned datastore\n * is a lightweight handle — no network calls are made until an operation is invoked.\n *\n * @param name The name of the datastore (table/collection).\n */\n datastore(name: string): Datastore;\n}\n\n/**\n * A datastore represents a logical container (table/collection) for items in a\n * NoSQL data store. It provides methods for performing CRUD operations, queries,\n * scans, and batch operations within the data store.\n */\nexport interface Datastore {\n /**\n * Retrieve an item from the data store by its primary key. Returns `null` if the\n * item does not exist.\n *\n * @param key The primary key attributes identifying the item.\n * @param options Optional parameters such as consistent read.\n * @returns A promise that resolves to the item, or `null` if not found.\n */\n getItem<T = Record<string, unknown>>(key: ItemKey, options?: GetItemOptions): Promise<T | null>;\n\n /**\n * Store an item in the data store. If an item with the same primary key already\n * exists, it is replaced entirely (upsert semantics).\n *\n * @param item The item to store. Must include all primary key attributes.\n * @param options Optional parameters such as condition expressions.\n */\n putItem(item: Record<string, unknown>, options?: PutItemOptions): Promise<void>;\n\n /**\n * Delete an item from the data store by its primary key. This operation is\n * idempotent — deleting a non-existent key does not throw.\n *\n * @param key The primary key attributes identifying the item to delete.\n * @param options Optional parameters such as condition expressions.\n */\n deleteItem(key: ItemKey, options?: DeleteItemOptions): Promise<void>;\n\n /**\n * Query items by primary key with optional range conditions. Returns an\n * {@link ItemListing} that handles pagination transparently, allowing the caller\n * to iterate over all matching items without managing page tokens.\n *\n * @param options Query parameters including key condition, range conditions,\n * filters, and pagination controls.\n * @returns An item listing that yields items and exposes a cursor for resuming.\n */\n query<T = Record<string, unknown>>(options: QueryOptions): ItemListing<T>;\n\n /**\n * Perform a full scan of the data store. Returns an {@link ItemListing} that\n * handles pagination transparently. Scans read every item in the table and\n * should be used sparingly.\n *\n * @param options Optional scan parameters such as filters and pagination controls.\n * @returns An item listing that yields items and exposes a cursor for resuming.\n */\n scan<T = Record<string, unknown>>(options?: ScanOptions): ItemListing<T>;\n\n /**\n * Retrieve multiple items by their primary keys in a single batch operation.\n * The batch may be split into multiple requests if it exceeds provider limits.\n *\n * @param keys The primary keys of the items to retrieve.\n * @param options Optional parameters such as consistent read.\n * @returns A promise that resolves to the batch get result, including retrieved\n * items and any unprocessed keys.\n */\n batchGetItems<T = Record<string, unknown>>(\n keys: ItemKey[],\n options?: BatchGetItemsOptions,\n ): Promise<BatchGetResult<T>>;\n\n /**\n * Perform multiple put and delete operations in a single batch. The batch may\n * be split into multiple requests if it exceeds provider limits.\n *\n * @param operations The batch of put and delete operations to execute.\n * @returns A promise that resolves to the batch write result, including any\n * unprocessed operations.\n */\n batchWriteItems(operations: BatchWriteOperation[]): Promise<BatchWriteResult>;\n}\n\n/**\n * Primary key attributes for an item. Keys can be string or number values\n * corresponding to primary key and optional range key attributes.\n */\nexport type ItemKey = Record<string, string | number>;\n\n/**\n * A condition on the primary key — always an equality match.\n */\nexport type KeyCondition = {\n /** The attribute name of the primary key. */\n name: string;\n /** The primary key value to match. */\n value: string | number;\n};\n\n/**\n * A condition on the range key. Supports equality, comparison, range,\n * and prefix matching operations.\n */\nexport type RangeCondition = {\n /** The attribute name of the range key. */\n name: string;\n} & (\n | { operator: \"eq\"; value: string | number }\n | { operator: \"lt\"; value: string | number }\n | { operator: \"le\"; value: string | number }\n | { operator: \"gt\"; value: string | number }\n | { operator: \"ge\"; value: string | number }\n | { operator: \"between\"; low: string | number; high: string | number }\n | { operator: \"startsWith\"; value: string }\n);\n\n/**\n * A filter condition on an item attribute. Used for post-read filtering\n * in queries and scans, and for conditional writes.\n *\n * Only includes operators that map cleanly across all target providers\n * (DynamoDB, Firestore, Cosmos DB). The `not_exists` operator is\n * provider-specific and available through the concrete provider classes.\n */\nexport type Condition = {\n /** The attribute name to evaluate. */\n name: string;\n} & (\n | { operator: \"eq\"; value: unknown }\n | { operator: \"ne\"; value: unknown }\n | { operator: \"lt\"; value: string | number }\n | { operator: \"le\"; value: string | number }\n | { operator: \"gt\"; value: string | number }\n | { operator: \"ge\"; value: string | number }\n | { operator: \"between\"; low: string | number; high: string | number }\n | { operator: \"startsWith\"; value: string }\n | { operator: \"contains\"; value: string | number }\n | { operator: \"exists\" }\n);\n\n/**\n * One or more conditions AND'd together. A single {@link Condition} or an array\n * of Conditions — when multiple are provided, all must be true.\n */\nexport type ConditionExpression = Condition | Condition[];\n\n/**\n * Options for the getItem operation.\n */\nexport type GetItemOptions = {\n /** When true, performs a strongly consistent read. Default is eventually consistent. */\n consistentRead?: boolean;\n};\n\n/**\n * Options for the putItem operation.\n */\nexport type PutItemOptions = {\n /**\n * Condition that must be met for the put to succeed. Throws\n * {@link ConditionalCheckFailedError} if the condition is not met.\n */\n condition?: ConditionExpression;\n};\n\n/**\n * Options for the deleteItem operation.\n */\nexport type DeleteItemOptions = {\n /**\n * Condition that must be met for the delete to succeed. Throws\n * {@link ConditionalCheckFailedError} if the condition is not met.\n */\n condition?: ConditionExpression;\n};\n\n/**\n * Options for the query operation.\n */\nexport type QueryOptions = {\n /** The primary key condition (required for queries). */\n key: KeyCondition;\n /** Optional range key condition to narrow the query range. */\n range?: RangeCondition;\n /** Optional filter conditions applied after the query read (does not reduce read capacity). */\n filter?: ConditionExpression;\n /** Query an index instead of the base table. */\n indexName?: string;\n /** When true, results are returned in ascending key order (default). Set to false for descending. */\n sortAscending?: boolean;\n /** Maximum number of items to return per internal page fetch. */\n maxResults?: number;\n /** Opaque cursor token to resume a previous query from where it left off. */\n cursor?: string;\n /** When true, performs a strongly consistent read (not supported on secondary indexes). */\n consistentRead?: boolean;\n};\n\n/**\n * Options for the scan operation.\n */\nexport type ScanOptions = {\n /** Optional filter conditions applied after the scan read. */\n filter?: ConditionExpression;\n /** Scan an index instead of the base table. */\n indexName?: string;\n /** Maximum number of items to return per internal page fetch. */\n maxResults?: number;\n /** Opaque cursor token to resume a previous scan from where it left off. */\n cursor?: string;\n /** When true, performs a strongly consistent read. */\n consistentRead?: boolean;\n};\n\n/**\n * An async iterable of items that also exposes a cursor token for resuming\n * iteration from the current position. The cursor is updated as pages are fetched\n * and encodes enough state to resume from the exact position across all providers.\n */\nexport interface ItemListing<T> extends AsyncIterable<T> {\n /**\n * A cursor token representing the current position in the listing. This token\n * can be passed to a subsequent query or scan call to resume iteration from\n * this position. The value is `undefined` before iteration begins or after all\n * items have been yielded.\n */\n readonly cursor: string | undefined;\n}\n\n/**\n * Options for the batchGetItems operation.\n */\nexport type BatchGetItemsOptions = {\n /** When true, performs strongly consistent reads for all items. */\n consistentRead?: boolean;\n};\n\n/**\n * The result of a batch get operation.\n */\nexport type BatchGetResult<T> = {\n /** The successfully retrieved items. */\n items: T[];\n /** Keys that could not be processed in this batch (caller should retry). */\n unprocessedKeys: ItemKey[];\n};\n\n/**\n * A single operation in a batch write request.\n */\nexport type BatchWriteOperation =\n | { type: \"put\"; item: Record<string, unknown> }\n | { type: \"delete\"; key: ItemKey };\n\n/**\n * The result of a batch write operation.\n */\nexport type BatchWriteResult = {\n /** Operations that could not be processed in this batch (caller should retry). */\n unprocessedOperations: BatchWriteOperation[];\n};\n","import { DynamoDBClient } from \"@aws-sdk/client-dynamodb\";\nimport { DynamoDBDocumentClient } from \"@aws-sdk/lib-dynamodb\";\nimport type { CelerityTracer } from \"@celerity-sdk/types\";\nimport type { DatastoreClient, Datastore } from \"../../types\";\nimport { DynamoDBDatastore } from \"./dynamodb-datastore\";\nimport type { DynamoDBDatastoreConfig } from \"./types\";\nimport { captureDynamoDBConfig } from \"./config\";\n\nexport class DynamoDBDatastoreClient implements DatastoreClient {\n private client: DynamoDBClient | null = null;\n private docClient: DynamoDBDocumentClient | null = null;\n private readonly config: DynamoDBDatastoreConfig;\n\n constructor(\n config?: DynamoDBDatastoreConfig,\n private readonly tracer?: CelerityTracer,\n ) {\n this.config = config ?? captureDynamoDBConfig();\n }\n\n datastore(name: string): Datastore {\n return new DynamoDBDatastore(name, this.getDocClient(), this.tracer);\n }\n\n close(): void {\n this.docClient?.destroy();\n this.client?.destroy();\n this.docClient = null;\n this.client = null;\n }\n\n private getDocClient(): DynamoDBDocumentClient {\n if (!this.docClient) {\n this.client = new DynamoDBClient({\n region: this.config.region,\n endpoint: this.config.endpoint,\n credentials: this.config.credentials,\n });\n this.docClient = DynamoDBDocumentClient.from(this.client, {\n marshallOptions: { removeUndefinedValues: true },\n });\n }\n return this.docClient;\n }\n}\n","import createDebug from \"debug\";\nimport {\n GetCommand,\n PutCommand,\n DeleteCommand,\n BatchGetCommand,\n BatchWriteCommand,\n type DynamoDBDocumentClient,\n} from \"@aws-sdk/lib-dynamodb\";\nimport type { CelerityTracer, CeleritySpan } from \"@celerity-sdk/types\";\nimport type {\n Datastore,\n ItemKey,\n GetItemOptions,\n PutItemOptions,\n DeleteItemOptions,\n QueryOptions,\n ScanOptions,\n ItemListing,\n BatchGetItemsOptions,\n BatchGetResult,\n BatchWriteOperation,\n BatchWriteResult,\n} from \"../../types\";\nimport { DatastoreError, ConditionalCheckFailedError } from \"../../errors\";\nimport { DynamoDBItemListing } from \"./dynamodb-item-listing\";\nimport { buildFilterExpression } from \"./expressions\";\nimport { isConditionalCheckFailedError } from \"./errors\";\n\nconst debug = createDebug(\"celerity:datastore:dynamodb\");\n\nexport class DynamoDBDatastore implements Datastore {\n constructor(\n private readonly tableName: string,\n private readonly client: DynamoDBDocumentClient,\n private readonly tracer?: CelerityTracer,\n ) {}\n\n async getItem<T = Record<string, unknown>>(\n key: ItemKey,\n options?: GetItemOptions,\n ): Promise<T | null> {\n debug(\"getItem %s %o\", this.tableName, key);\n return this.traced(\n \"celerity.datastore.get_item\",\n { \"datastore.table\": this.tableName },\n async () => {\n try {\n const response = await this.client.send(\n new GetCommand({\n TableName: this.tableName,\n Key: key,\n ConsistentRead: options?.consistentRead,\n }),\n );\n return (response.Item as T) ?? null;\n } catch (error) {\n throw new DatastoreError(\n `Failed to get item from table \"${this.tableName}\"`,\n this.tableName,\n { cause: error },\n );\n }\n },\n );\n }\n\n async putItem(item: Record<string, unknown>, options?: PutItemOptions): Promise<void> {\n debug(\"putItem %s\", this.tableName);\n return this.traced(\n \"celerity.datastore.put_item\",\n { \"datastore.table\": this.tableName },\n async () => {\n try {\n const conditionParams = options?.condition\n ? buildFilterExpression(options.condition)\n : undefined;\n\n await this.client.send(\n new PutCommand({\n TableName: this.tableName,\n Item: item,\n ConditionExpression: conditionParams?.expression,\n ExpressionAttributeNames: conditionParams?.names,\n ExpressionAttributeValues: conditionParams?.values,\n }),\n );\n } catch (error) {\n if (isConditionalCheckFailedError(error)) {\n throw new ConditionalCheckFailedError(this.tableName, { cause: error });\n }\n throw new DatastoreError(\n `Failed to put item in table \"${this.tableName}\"`,\n this.tableName,\n { cause: error },\n );\n }\n },\n );\n }\n\n async deleteItem(key: ItemKey, options?: DeleteItemOptions): Promise<void> {\n debug(\"deleteItem %s %o\", this.tableName, key);\n return this.traced(\n \"celerity.datastore.delete_item\",\n { \"datastore.table\": this.tableName },\n async () => {\n try {\n const conditionParams = options?.condition\n ? buildFilterExpression(options.condition)\n : undefined;\n\n await this.client.send(\n new DeleteCommand({\n TableName: this.tableName,\n Key: key,\n ConditionExpression: conditionParams?.expression,\n ExpressionAttributeNames: conditionParams?.names,\n ExpressionAttributeValues: conditionParams?.values,\n }),\n );\n } catch (error) {\n if (isConditionalCheckFailedError(error)) {\n throw new ConditionalCheckFailedError(this.tableName, { cause: error });\n }\n throw new DatastoreError(\n `Failed to delete item from table \"${this.tableName}\"`,\n this.tableName,\n { cause: error },\n );\n }\n },\n );\n }\n\n query<T = Record<string, unknown>>(options: QueryOptions): ItemListing<T> {\n debug(\"query %s pk=%s\", this.tableName, options.key.name);\n return new DynamoDBItemListing<T>(this.client, this.tableName, \"query\", options, this.tracer);\n }\n\n scan<T = Record<string, unknown>>(options?: ScanOptions): ItemListing<T> {\n debug(\"scan %s\", this.tableName);\n return new DynamoDBItemListing<T>(\n this.client,\n this.tableName,\n \"scan\",\n options ?? {},\n this.tracer,\n );\n }\n\n async batchGetItems<T = Record<string, unknown>>(\n keys: ItemKey[],\n options?: BatchGetItemsOptions,\n ): Promise<BatchGetResult<T>> {\n debug(\"batchGetItems %s count=%d\", this.tableName, keys.length);\n return this.traced(\n \"celerity.datastore.batch_get_items\",\n { \"datastore.table\": this.tableName, \"datastore.batch_size\": keys.length },\n async () => {\n try {\n const response = await this.client.send(\n new BatchGetCommand({\n RequestItems: {\n [this.tableName]: {\n Keys: keys,\n ConsistentRead: options?.consistentRead,\n },\n },\n }),\n );\n\n const items = (response.Responses?.[this.tableName] ?? []) as T[];\n const unprocessedKeys = (response.UnprocessedKeys?.[this.tableName]?.Keys ??\n []) as ItemKey[];\n\n return { items, unprocessedKeys };\n } catch (error) {\n throw new DatastoreError(\n `Failed to batch get items from table \"${this.tableName}\"`,\n this.tableName,\n { cause: error },\n );\n }\n },\n );\n }\n\n async batchWriteItems(operations: BatchWriteOperation[]): Promise<BatchWriteResult> {\n debug(\"batchWriteItems %s count=%d\", this.tableName, operations.length);\n return this.traced(\n \"celerity.datastore.batch_write_items\",\n { \"datastore.table\": this.tableName, \"datastore.batch_size\": operations.length },\n async () => {\n try {\n const writeRequests = operations.map((op) => {\n if (op.type === \"put\") {\n return { PutRequest: { Item: op.item } };\n }\n return { DeleteRequest: { Key: op.key } };\n });\n\n const response = await this.client.send(\n new BatchWriteCommand({\n RequestItems: { [this.tableName]: writeRequests },\n }),\n );\n\n const unprocessedRequests = response.UnprocessedItems?.[this.tableName] ?? [];\n const unprocessedOperations: BatchWriteOperation[] = unprocessedRequests.map((req) => {\n if (req.PutRequest) {\n return { type: \"put\" as const, item: req.PutRequest.Item! };\n }\n return { type: \"delete\" as const, key: req.DeleteRequest!.Key! as ItemKey };\n });\n\n return { unprocessedOperations };\n } catch (error) {\n throw new DatastoreError(\n `Failed to batch write items to table \"${this.tableName}\"`,\n this.tableName,\n { cause: error },\n );\n }\n },\n );\n }\n\n private traced<T>(\n name: string,\n attributes: Record<string, string | number | boolean>,\n fn: (span?: CeleritySpan) => Promise<T>,\n ): Promise<T> {\n if (!this.tracer) return fn();\n return this.tracer.withSpan(name, (span) => fn(span), attributes);\n }\n}\n","export class DatastoreError extends Error {\n constructor(\n message: string,\n public readonly table: string,\n options?: { cause?: unknown },\n ) {\n super(message, options);\n this.name = \"DatastoreError\";\n }\n}\n\nexport class ConditionalCheckFailedError extends DatastoreError {\n constructor(table: string, options?: { cause?: unknown }) {\n super(`Conditional check failed on table \"${table}\"`, table, options);\n this.name = \"ConditionalCheckFailedError\";\n }\n}\n","import createDebug from \"debug\";\nimport { QueryCommand, ScanCommand, type DynamoDBDocumentClient } from \"@aws-sdk/lib-dynamodb\";\nimport type { CelerityTracer } from \"@celerity-sdk/types\";\nimport type { ItemListing, QueryOptions, ScanOptions } from \"../../types\";\nimport { DatastoreError } from \"../../errors\";\nimport { buildKeyConditionExpression, buildFilterExpression } from \"./expressions\";\n\nconst debug = createDebug(\"celerity:datastore:dynamodb\");\n\ntype CursorState = {\n lastEvaluatedKey: Record<string, unknown>;\n};\n\nfunction encodeCursor(lastEvaluatedKey: Record<string, unknown>): string {\n const state: CursorState = { lastEvaluatedKey };\n return Buffer.from(JSON.stringify(state)).toString(\"base64url\");\n}\n\nfunction decodeCursor(cursor: string): CursorState {\n return JSON.parse(Buffer.from(cursor, \"base64url\").toString(\"utf-8\")) as CursorState;\n}\n\nexport class DynamoDBItemListing<T> implements ItemListing<T> {\n private _cursor: string | undefined;\n\n constructor(\n private readonly client: DynamoDBDocumentClient,\n private readonly tableName: string,\n private readonly mode: \"query\" | \"scan\",\n private readonly options: QueryOptions | ScanOptions,\n private readonly tracer?: CelerityTracer,\n ) {\n this._cursor = options.cursor;\n }\n\n get cursor(): string | undefined {\n return this._cursor;\n }\n\n async *[Symbol.asyncIterator](): AsyncIterator<T> {\n const cursorState = this._cursor ? decodeCursor(this._cursor) : undefined;\n let exclusiveStartKey: Record<string, unknown> | undefined = cursorState?.lastEvaluatedKey;\n\n do {\n debug(\"%s page %s key=%o\", this.mode, this.tableName, exclusiveStartKey ?? \"(start)\");\n\n const response = await this.fetchPage(exclusiveStartKey);\n\n for (const item of response.Items ?? []) {\n yield item as T;\n }\n\n exclusiveStartKey = response.LastEvaluatedKey as Record<string, unknown> | undefined;\n\n if (exclusiveStartKey) {\n this._cursor = encodeCursor(exclusiveStartKey);\n } else {\n this._cursor = undefined;\n }\n } while (exclusiveStartKey);\n }\n\n private async fetchPage(exclusiveStartKey?: Record<string, unknown>) {\n const command =\n this.mode === \"query\"\n ? this.buildQueryCommand(exclusiveStartKey)\n : this.buildScanCommand(exclusiveStartKey);\n\n const doFetch = async () => {\n try {\n return await this.client.send(command);\n } catch (error) {\n throw new DatastoreError(\n `Failed to ${this.mode} table \"${this.tableName}\"`,\n this.tableName,\n { cause: error },\n );\n }\n };\n\n if (!this.tracer) return doFetch();\n return this.tracer.withSpan(`celerity.datastore.${this.mode}_page`, () => doFetch(), {\n \"datastore.table\": this.tableName,\n });\n }\n\n private buildQueryCommand(exclusiveStartKey?: Record<string, unknown>) {\n const opts = this.options as QueryOptions;\n const keyExpr = buildKeyConditionExpression(opts.key, opts.range);\n\n const filterExpr = opts.filter ? buildFilterExpression(opts.filter) : undefined;\n\n return new QueryCommand({\n TableName: this.tableName,\n IndexName: opts.indexName,\n KeyConditionExpression: keyExpr.expression,\n FilterExpression: filterExpr?.expression,\n ExpressionAttributeNames: { ...keyExpr.names, ...filterExpr?.names },\n ExpressionAttributeValues: { ...keyExpr.values, ...filterExpr?.values },\n ScanIndexForward: opts.sortAscending,\n Limit: opts.maxResults,\n ExclusiveStartKey: exclusiveStartKey,\n ConsistentRead: opts.consistentRead,\n });\n }\n\n private buildScanCommand(exclusiveStartKey?: Record<string, unknown>) {\n const opts = this.options as ScanOptions;\n\n const filterExpr = opts.filter ? buildFilterExpression(opts.filter) : undefined;\n\n return new ScanCommand({\n TableName: this.tableName,\n IndexName: opts.indexName,\n FilterExpression: filterExpr?.expression,\n ExpressionAttributeNames:\n filterExpr?.names && Object.keys(filterExpr.names).length > 0\n ? filterExpr.names\n : undefined,\n ExpressionAttributeValues:\n filterExpr?.values && Object.keys(filterExpr.values).length > 0\n ? filterExpr.values\n : undefined,\n Limit: opts.maxResults,\n ExclusiveStartKey: exclusiveStartKey,\n ConsistentRead: opts.consistentRead,\n });\n }\n}\n","import type { KeyCondition, RangeCondition, ConditionExpression } from \"../../types\";\n\nexport type ExpressionResult = {\n expression: string;\n names: Record<string, string>;\n values: Record<string, unknown>;\n};\n\nconst COMPARISON_OPERATORS = {\n eq: \"=\",\n ne: \"<>\",\n lt: \"<\",\n le: \"<=\",\n gt: \">\",\n ge: \">=\",\n} as const;\n\n/**\n * Builds a DynamoDB KeyConditionExpression from a key condition and optional range condition.\n * Uses `#k`/`:k` prefixed placeholders to avoid collision with filter placeholders.\n */\nexport function buildKeyConditionExpression(\n key: KeyCondition,\n range?: RangeCondition,\n): ExpressionResult {\n const names: Record<string, string> = {};\n const values: Record<string, unknown> = {};\n let counter = 0;\n\n const pkName = `#k${counter}`;\n const pkValue = `:k${counter}`;\n names[pkName] = key.name;\n values[pkValue] = key.value;\n counter++;\n\n let expression = `${pkName} = ${pkValue}`;\n\n if (range) {\n const skName = `#k${counter}`;\n names[skName] = range.name;\n\n switch (range.operator) {\n case \"eq\":\n case \"lt\":\n case \"le\":\n case \"gt\":\n case \"ge\": {\n const skValue = `:k${counter}`;\n values[skValue] = range.value;\n expression += ` AND ${skName} ${COMPARISON_OPERATORS[range.operator]} ${skValue}`;\n break;\n }\n case \"between\": {\n const lowVal = `:k${counter}a`;\n const highVal = `:k${counter}b`;\n values[lowVal] = range.low;\n values[highVal] = range.high;\n expression += ` AND ${skName} BETWEEN ${lowVal} AND ${highVal}`;\n break;\n }\n case \"startsWith\": {\n const skValue = `:k${counter}`;\n values[skValue] = range.value;\n expression += ` AND begins_with(${skName}, ${skValue})`;\n break;\n }\n }\n }\n\n return { expression, names, values };\n}\n\n/**\n * Builds a DynamoDB FilterExpression (or ConditionExpression for writes)\n * from one or more Condition objects. Conditions are AND'd together.\n * Uses `#f`/`:f` prefixed placeholders to avoid collision with key placeholders.\n */\nexport function buildFilterExpression(conditions: ConditionExpression): ExpressionResult {\n const condArray = Array.isArray(conditions) ? conditions : [conditions];\n const names: Record<string, string> = {};\n const values: Record<string, unknown> = {};\n const parts: string[] = [];\n let counter = 0;\n\n for (const cond of condArray) {\n const attrName = `#f${counter}`;\n names[attrName] = cond.name;\n\n switch (cond.operator) {\n case \"eq\":\n case \"ne\":\n case \"lt\":\n case \"le\":\n case \"gt\":\n case \"ge\": {\n const valKey = `:f${counter}`;\n values[valKey] = cond.value;\n parts.push(`${attrName} ${COMPARISON_OPERATORS[cond.operator]} ${valKey}`);\n break;\n }\n case \"between\": {\n const lowVal = `:f${counter}a`;\n const highVal = `:f${counter}b`;\n values[lowVal] = cond.low;\n values[highVal] = cond.high;\n parts.push(`${attrName} BETWEEN ${lowVal} AND ${highVal}`);\n break;\n }\n case \"startsWith\":\n case \"contains\": {\n const valKey = `:f${counter}`;\n values[valKey] = cond.value;\n const fnName = cond.operator === \"startsWith\" ? \"begins_with\" : \"contains\";\n parts.push(`${fnName}(${attrName}, ${valKey})`);\n break;\n }\n case \"exists\":\n parts.push(`attribute_exists(${attrName})`);\n break;\n }\n\n counter++;\n }\n\n return { expression: parts.join(\" AND \"), names, values };\n}\n","/**\n * Checks if an error is a DynamoDB ConditionalCheckFailedException.\n */\nexport function isConditionalCheckFailedError(error: unknown): boolean {\n if (!(error instanceof Error)) return false;\n return (error as { name?: string }).name === \"ConditionalCheckFailedException\";\n}\n","import type { DynamoDBDatastoreConfig } from \"./types\";\n\n/**\n * Captures DynamoDB configuration from environment variables.\n * This is the only place that reads `process.env` for DynamoDB config.\n */\nexport function captureDynamoDBConfig(): DynamoDBDatastoreConfig {\n return {\n region: process.env.AWS_REGION ?? process.env.AWS_DEFAULT_REGION,\n endpoint: process.env.AWS_ENDPOINT_URL,\n credentials:\n process.env.AWS_ACCESS_KEY_ID && process.env.AWS_SECRET_ACCESS_KEY\n ? {\n accessKeyId: process.env.AWS_ACCESS_KEY_ID,\n secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,\n }\n : undefined,\n };\n}\n","import { resolveConfig } from \"@celerity-sdk/config\";\nimport type { CelerityTracer } from \"@celerity-sdk/types\";\nimport type { DatastoreClient } from \"./types\";\nimport type { DynamoDBDatastoreConfig } from \"./providers/dynamodb/types\";\nimport { captureDynamoDBConfig } from \"./providers/dynamodb/config\";\nimport { DynamoDBDatastoreClient } from \"./providers/dynamodb/dynamodb-datastore-client\";\n\nexport type CreateDatastoreClientOptions = {\n /** Override provider selection. If omitted, derived from platform config. */\n provider?: \"aws\" | \"local\" | \"gcp\" | \"azure\";\n /** Cloud deploy target for local environments (e.g. \"aws\", \"gcloud\", \"azure\"). */\n deployTarget?: string;\n /** DynamoDB-specific configuration overrides. */\n aws?: DynamoDBDatastoreConfig;\n /** Optional tracer for Celerity-level span instrumentation. */\n tracer?: CelerityTracer;\n};\n\nexport function createDatastoreClient(options?: CreateDatastoreClientOptions): DatastoreClient {\n const resolved = resolveConfig(\"datastore\");\n const provider = options?.provider ?? resolved.provider;\n\n switch (provider) {\n case \"aws\":\n return new DynamoDBDatastoreClient(options?.aws, options?.tracer);\n case \"local\":\n return createLocalClient(options);\n default:\n throw new Error(`Unsupported datastore provider: \"${provider}\"`);\n }\n}\n\nfunction createLocalClient(options?: CreateDatastoreClientOptions): DatastoreClient {\n const deployTarget = options?.deployTarget?.toLowerCase();\n\n switch (deployTarget) {\n case \"aws\":\n case \"aws-serverless\":\n case undefined: {\n // DynamoDB Local (v0 default when no deploy target is specified)\n const localConfig: DynamoDBDatastoreConfig = {\n ...captureDynamoDBConfig(),\n ...options?.aws,\n };\n return new DynamoDBDatastoreClient(localConfig, options?.tracer);\n }\n // case \"gcloud\":\n // case \"gcloud-serverless\":\n // v1: Firestore emulator\n // case \"azure\":\n // case \"azure-serverless\":\n // v1: Cosmos DB emulator\n default:\n throw new Error(\n `Unsupported local datastore deploy target: \"${deployTarget}\". Only AWS is supported in v0.`,\n );\n }\n}\n","import \"reflect-metadata\";\nimport { INJECT_METADATA, USE_RESOURCE_METADATA } from \"@celerity-sdk/common\";\nimport type { Datastore as DatastoreType } from \"./types\";\n\n// Re-declare as interface so the type merges with the decorator function below.\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type\nexport interface Datastore extends DatastoreType {}\n\nexport function datastoreToken(resourceName: string): symbol {\n return Symbol.for(`celerity:datastore:${resourceName}`);\n}\n\nexport const DEFAULT_DATASTORE_TOKEN = Symbol.for(\"celerity:datastore:default\");\n\n/**\n * Parameter decorator that injects a {@link Datastore} instance for the given\n * blueprint resource. Writes both DI injection metadata and CLI resource-ref\n * metadata using well-known `Symbol.for()` keys (no dependency on core).\n *\n * When `resourceName` is omitted, the default datastore token is used — this\n * auto-resolves when exactly one datastore resource exists.\n *\n * @example\n * ```ts\n * @Controller(\"/users\")\n * class UserController {\n * constructor(@Datastore(\"usersTable\") private users: Datastore) {}\n * }\n * ```\n */\nexport function Datastore(resourceName?: string): ParameterDecorator {\n return (target, _propertyKey, parameterIndex) => {\n const token = resourceName ? datastoreToken(resourceName) : DEFAULT_DATASTORE_TOKEN;\n const existing: Map<number, unknown> =\n Reflect.getOwnMetadata(INJECT_METADATA, target) ?? new Map();\n existing.set(parameterIndex, token);\n Reflect.defineMetadata(INJECT_METADATA, existing, target);\n\n if (resourceName) {\n const resources: string[] = Reflect.getOwnMetadata(USE_RESOURCE_METADATA, target) ?? [];\n if (!resources.includes(resourceName)) {\n Reflect.defineMetadata(USE_RESOURCE_METADATA, [...resources, resourceName], target);\n }\n }\n };\n}\n","import type { ServiceContainer } from \"@celerity-sdk/types\";\nimport type { Datastore } from \"./types\";\nimport { datastoreToken, DEFAULT_DATASTORE_TOKEN } from \"./decorators\";\n\n/**\n * Resolves a {@link Datastore} instance from the DI container.\n * For function-based handlers where parameter decorators aren't available.\n *\n * @param container - The service container (typically `context.container`).\n * @param resourceName - The blueprint resource name. Omit when exactly one\n * datastore resource exists to use the default.\n *\n * @example\n * ```ts\n * const handler = createHttpHandler(async (req, ctx) => {\n * const users = await getDatastore(ctx.container, \"usersTable\");\n * const user = await users.getItem({ pk: req.pathParameters.userId });\n * });\n * ```\n */\nexport function getDatastore(\n container: ServiceContainer,\n resourceName?: string,\n): Promise<Datastore> {\n const token = resourceName ? datastoreToken(resourceName) : DEFAULT_DATASTORE_TOKEN;\n return container.resolve<Datastore>(token);\n}\n","import createDebug from \"debug\";\nimport type { CelerityLayer, BaseHandlerContext, CelerityTracer } from \"@celerity-sdk/types\";\nimport { TRACER_TOKEN, CONFIG_SERVICE_TOKEN } from \"@celerity-sdk/common\";\nimport {\n type ConfigService,\n captureResourceLinks,\n getLinksOfType,\n RESOURCE_CONFIG_NAMESPACE,\n} from \"@celerity-sdk/config\";\nimport { createDatastoreClient } from \"./factory\";\nimport { datastoreToken, DEFAULT_DATASTORE_TOKEN } from \"./decorators\";\n\nconst debug = createDebug(\"celerity:datastore\");\n\n/**\n * System layer that auto-registers {@link DatastoreClient} and per-resource\n * {@link Datastore} handles in the DI container.\n *\n * Reads resource link topology from `CELERITY_RESOURCE_LINKS` and resolves\n * actual table/collection names from the ConfigService \"resources\" namespace.\n * Must run after ConfigLayer in the layer pipeline.\n */\ntype DatastoreLayerConfig = {\n deployTarget: string | undefined;\n};\n\nfunction captureDatastoreLayerConfig(): DatastoreLayerConfig {\n return {\n deployTarget: process.env.CELERITY_DEPLOY_TARGET,\n };\n}\n\nexport class DatastoreLayer implements CelerityLayer<BaseHandlerContext> {\n private initialized = false;\n private config: DatastoreLayerConfig | null = null;\n\n async handle(context: BaseHandlerContext, next: () => Promise<unknown>): Promise<unknown> {\n if (!this.initialized) {\n this.config = captureDatastoreLayerConfig();\n\n const tracer = context.container.has(TRACER_TOKEN)\n ? await context.container.resolve<CelerityTracer>(TRACER_TOKEN)\n : undefined;\n\n const client = createDatastoreClient({\n tracer,\n deployTarget: this.config.deployTarget,\n });\n debug(\"registering DatastoreClient\");\n context.container.register(\"DatastoreClient\", { useValue: client });\n\n const links = captureResourceLinks();\n const datastoreLinks = getLinksOfType(links, \"datastore\");\n\n if (datastoreLinks.size > 0) {\n const configService = await context.container.resolve<ConfigService>(CONFIG_SERVICE_TOKEN);\n const resourceConfig = configService.namespace(RESOURCE_CONFIG_NAMESPACE);\n\n for (const [resourceName, configKey] of datastoreLinks) {\n const actualName = await resourceConfig.getOrThrow(configKey);\n debug(\"registered datastore resource %s → %s\", resourceName, actualName);\n context.container.register(datastoreToken(resourceName), {\n useValue: client.datastore(actualName),\n });\n }\n\n if (datastoreLinks.size === 1) {\n const [, configKey] = [...datastoreLinks.entries()][0];\n const actualName = await resourceConfig.getOrThrow(configKey);\n debug(\"registered default datastore → %s\", actualName);\n context.container.register(DEFAULT_DATASTORE_TOKEN, {\n useValue: client.datastore(actualName),\n });\n }\n }\n\n this.initialized = true;\n }\n\n return next();\n }\n}\n"],"mappings":"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","names":["DatastoreClient","Symbol","for","DynamoDBClient","DynamoDBDocumentClient","createDebug","GetCommand","PutCommand","DeleteCommand","BatchGetCommand","BatchWriteCommand","DatastoreError","Error","message","table","options","name","ConditionalCheckFailedError","createDebug","QueryCommand","ScanCommand","COMPARISON_OPERATORS","eq","ne","lt","le","gt","ge","buildKeyConditionExpression","key","range","names","values","counter","pkName","pkValue","name","value","expression","skName","operator","skValue","lowVal","highVal","low","high","buildFilterExpression","conditions","condArray","Array","isArray","parts","cond","attrName","valKey","push","fnName","join","debug","createDebug","encodeCursor","lastEvaluatedKey","state","Buffer","from","JSON","stringify","toString","decodeCursor","cursor","parse","DynamoDBItemListing","_cursor","client","tableName","mode","options","tracer","Symbol","asyncIterator","cursorState","undefined","exclusiveStartKey","response","fetchPage","item","Items","LastEvaluatedKey","command","buildQueryCommand","buildScanCommand","doFetch","send","error","DatastoreError","cause","withSpan","opts","keyExpr","buildKeyConditionExpression","key","range","filterExpr","filter","buildFilterExpression","QueryCommand","TableName","IndexName","indexName","KeyConditionExpression","expression","FilterExpression","ExpressionAttributeNames","names","ExpressionAttributeValues","values","ScanIndexForward","sortAscending","Limit","maxResults","ExclusiveStartKey","ConsistentRead","consistentRead","ScanCommand","Object","keys","length","isConditionalCheckFailedError","error","Error","name","debug","createDebug","DynamoDBDatastore","tableName","client","tracer","getItem","key","options","traced","response","send","GetCommand","TableName","Key","ConsistentRead","consistentRead","Item","error","DatastoreError","cause","putItem","item","conditionParams","condition","buildFilterExpression","undefined","PutCommand","ConditionExpression","expression","ExpressionAttributeNames","names","ExpressionAttributeValues","values","isConditionalCheckFailedError","ConditionalCheckFailedError","deleteItem","DeleteCommand","query","name","DynamoDBItemListing","scan","batchGetItems","keys","length","BatchGetCommand","RequestItems","Keys","items","Responses","unprocessedKeys","UnprocessedKeys","batchWriteItems","operations","writeRequests","map","op","type","PutRequest","DeleteRequest","BatchWriteCommand","unprocessedRequests","UnprocessedItems","unprocessedOperations","req","attributes","fn","withSpan","span","captureDynamoDBConfig","region","process","env","AWS_REGION","AWS_DEFAULT_REGION","endpoint","AWS_ENDPOINT_URL","credentials","AWS_ACCESS_KEY_ID","AWS_SECRET_ACCESS_KEY","accessKeyId","secretAccessKey","undefined","DynamoDBDatastoreClient","client","docClient","config","tracer","captureDynamoDBConfig","datastore","name","DynamoDBDatastore","getDocClient","close","destroy","DynamoDBClient","region","endpoint","credentials","DynamoDBDocumentClient","from","marshallOptions","removeUndefinedValues","resolveConfig","createDatastoreClient","options","resolved","resolveConfig","provider","DynamoDBDatastoreClient","aws","tracer","createLocalClient","Error","deployTarget","toLowerCase","undefined","localConfig","captureDynamoDBConfig","INJECT_METADATA","USE_RESOURCE_METADATA","datastoreToken","resourceName","Symbol","for","DEFAULT_DATASTORE_TOKEN","Datastore","target","_propertyKey","parameterIndex","token","existing","Reflect","getOwnMetadata","INJECT_METADATA","Map","set","defineMetadata","resources","USE_RESOURCE_METADATA","includes","getDatastore","container","resourceName","token","datastoreToken","DEFAULT_DATASTORE_TOKEN","resolve","createDebug","TRACER_TOKEN","CONFIG_SERVICE_TOKEN","captureResourceLinks","getLinksOfType","RESOURCE_CONFIG_NAMESPACE","debug","createDebug","captureDatastoreLayerConfig","deployTarget","process","env","CELERITY_DEPLOY_TARGET","DatastoreLayer","initialized","config","handle","context","next","tracer","container","has","TRACER_TOKEN","resolve","undefined","client","createDatastoreClient","register","useValue","links","captureResourceLinks","datastoreLinks","getLinksOfType","size","configService","CONFIG_SERVICE_TOKEN","resourceConfig","namespace","RESOURCE_CONFIG_NAMESPACE","resourceName","configKey","actualName","getOrThrow","datastoreToken","datastore","entries","DEFAULT_DATASTORE_TOKEN"]}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@celerity-sdk/datastore",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "NoSQL data store abstraction for the Celerity Node SDK (DynamoDB / Cloud
|
|
3
|
+
"version": "0.4.0",
|
|
4
|
+
"description": "NoSQL data store abstraction for the Celerity Node SDK (DynamoDB / Cloud Firestore / Cosmos DB)",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -31,14 +31,22 @@
|
|
|
31
31
|
"node": ">=22.0.0"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"
|
|
35
|
-
"@celerity-sdk/config": "^0.
|
|
34
|
+
"debug": "^4.4.0",
|
|
35
|
+
"@celerity-sdk/config": "^0.4.0",
|
|
36
|
+
"@celerity-sdk/types": "^0.4.0",
|
|
37
|
+
"@celerity-sdk/common": "^0.4.0"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@aws-sdk/client-dynamodb": "^3.750.0",
|
|
41
|
+
"@aws-sdk/lib-dynamodb": "^3.750.0",
|
|
42
|
+
"reflect-metadata": "^0.2.0"
|
|
36
43
|
},
|
|
37
44
|
"peerDependencies": {
|
|
38
45
|
"@aws-sdk/client-dynamodb": "^3.0.0",
|
|
39
46
|
"@aws-sdk/lib-dynamodb": "^3.0.0",
|
|
40
|
-
"@google-cloud/
|
|
41
|
-
"@azure/cosmos": "^4.0.0"
|
|
47
|
+
"@google-cloud/firestore": "^7.0.0",
|
|
48
|
+
"@azure/cosmos": "^4.0.0",
|
|
49
|
+
"reflect-metadata": "^0.2.0"
|
|
42
50
|
},
|
|
43
51
|
"peerDependenciesMeta": {
|
|
44
52
|
"@aws-sdk/client-dynamodb": {
|
|
@@ -47,11 +55,14 @@
|
|
|
47
55
|
"@aws-sdk/lib-dynamodb": {
|
|
48
56
|
"optional": true
|
|
49
57
|
},
|
|
50
|
-
"@google-cloud/
|
|
58
|
+
"@google-cloud/firestore": {
|
|
51
59
|
"optional": true
|
|
52
60
|
},
|
|
53
61
|
"@azure/cosmos": {
|
|
54
62
|
"optional": true
|
|
63
|
+
},
|
|
64
|
+
"reflect-metadata": {
|
|
65
|
+
"optional": true
|
|
55
66
|
}
|
|
56
67
|
},
|
|
57
68
|
"publishConfig": {
|