@lafken/dynamo 0.14.1 → 0.14.3
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.
|
@@ -27,6 +27,13 @@ interface IndexBase<T extends Function> {
|
|
|
27
27
|
*/
|
|
28
28
|
projection?: (keyof T['prototype'])[] | 'ALL';
|
|
29
29
|
}
|
|
30
|
+
/**
|
|
31
|
+
* Filter expression for a single DynamoDB attribute.
|
|
32
|
+
*
|
|
33
|
+
* Supports exact matches, `anything-but`, `exists`, `prefix`, and empty-string
|
|
34
|
+
* conditions. Values can be provided as a single value, an array of values,
|
|
35
|
+
* or null.
|
|
36
|
+
*/
|
|
30
37
|
type AttributeFilter<T> = {
|
|
31
38
|
[key in keyof T]?: (T[key] | {
|
|
32
39
|
'anything-but': T[key][];
|
|
@@ -359,18 +366,47 @@ export interface ExternalTableMetadata extends Omit<ExternalTableProps<any>, 'na
|
|
|
359
366
|
name: string;
|
|
360
367
|
}
|
|
361
368
|
export type TableMetadata = InternalTableMetadata | ExternalTableMetadata;
|
|
369
|
+
/**
|
|
370
|
+
* Base properties for a DynamoDB table field definition.
|
|
371
|
+
*/
|
|
362
372
|
export interface FieldProps {
|
|
373
|
+
/** The TypeScript constructor that determines the field's DynamoDB type. */
|
|
363
374
|
type?: StringConstructor | NumberConstructor | BooleanConstructor | [Function] | Function;
|
|
364
375
|
}
|
|
376
|
+
/**
|
|
377
|
+
* Resolved metadata for a DynamoDB table field after the `@Field`
|
|
378
|
+
* decorator is processed.
|
|
379
|
+
*/
|
|
365
380
|
export interface FieldMetadata {
|
|
381
|
+
/** Property name as declared on the class. */
|
|
366
382
|
name: string;
|
|
383
|
+
/** Resolved DynamoDB type (e.g. `'string'`, `'number'`, `'boolean'`). */
|
|
367
384
|
type: FieldTypes;
|
|
368
385
|
}
|
|
386
|
+
/**
|
|
387
|
+
* Map of property names to their resolved DynamoDB field metadata.
|
|
388
|
+
*/
|
|
369
389
|
export type FieldsMetadata = Record<string, FieldMetadata>;
|
|
390
|
+
/**
|
|
391
|
+
* Sentinel type used internally to mark DynamoDB partition key properties.
|
|
392
|
+
* Properties typed with `PrimaryPartition<T>` are recognized as partition
|
|
393
|
+
* key candidates during table metadata resolution.
|
|
394
|
+
*/
|
|
370
395
|
type Partition = {
|
|
371
396
|
__special: unknown;
|
|
372
397
|
};
|
|
398
|
+
/**
|
|
399
|
+
* Marks a type as a DynamoDB partition key candidate.
|
|
400
|
+
*
|
|
401
|
+
* @typeParam T - The type to mark as a partition key.
|
|
402
|
+
*/
|
|
373
403
|
export type PrimaryPartition<T = never> = T | (T & Partition);
|
|
404
|
+
/**
|
|
405
|
+
* Extracts only the partition key properties from a DynamoDB table class.
|
|
406
|
+
*
|
|
407
|
+
* Filters the keys of `T` to include only those whose type includes the
|
|
408
|
+
* {@link Partition} sentinel, giving the list of valid partition key fields.
|
|
409
|
+
*/
|
|
374
410
|
export type TablePartition<T> = {
|
|
375
411
|
[K in keyof T as [Extract<T[K], Partition>] extends [never] ? never : K]: T[K];
|
|
376
412
|
};
|
|
@@ -12,7 +12,8 @@ export type OperationExpression<E> = OnlyOne<{
|
|
|
12
12
|
greaterOrEqualThan: E;
|
|
13
13
|
between: [E, E];
|
|
14
14
|
}>;
|
|
15
|
-
|
|
15
|
+
type UnwrapBigInt<T> = NonNullable<T> extends BigInt ? bigint : NonNullable<T>;
|
|
16
|
+
export type InExpression<E extends string | number | bigint> = {
|
|
16
17
|
in: E[];
|
|
17
18
|
};
|
|
18
19
|
export type NullExpression = OnlyOne<{
|
|
@@ -30,7 +31,7 @@ export type CommonExpression<E> = OnlyOne<{
|
|
|
30
31
|
notEqual: E;
|
|
31
32
|
} & NullExpression>;
|
|
32
33
|
export type Filter<E> = {
|
|
33
|
-
[key in keyof E]?: NonNullable<E[key]> extends PrimaryPartition<number> ?
|
|
34
|
+
[key in keyof E]?: NonNullable<E[key]> extends PrimaryPartition<number | bigint | BigInt> ? UnwrapBigInt<E[key]> | OnlyOne<OperationExpression<number | bigint> & CommonExpression<number | bigint> & InExpression<number | bigint>> : NonNullable<E[key]> extends PrimaryPartition<string> ? NonNullable<E[key]> | OnlyOne<StringExpression & StringFilterExpression & CommonExpression<string> & InExpression<string>> : NonNullable<E[key]> extends string | number | bigint | BigInt | boolean | Date | null ? UnwrapBigInt<E[key]> | (NonNullable<E[key]> extends number | bigint | BigInt ? OnlyOne<OperationExpression<number | bigint> & CommonExpression<number | bigint> & InExpression<number | bigint>> : NonNullable<E[key]> extends boolean ? CommonExpression<boolean> : NonNullable<E[key]> extends null ? NullExpression : OnlyOne<StringExpression & StringFilterExpression & CommonExpression<string> & InExpression<string>>) : DeepPartial<Filter<E[key]>>;
|
|
34
35
|
};
|
|
35
36
|
export type OrFilter<E> = {
|
|
36
37
|
OR: Array<Filter<E> | AndFilter<E>>;
|
|
@@ -42,7 +43,7 @@ export type SortDirectionType = 'asc' | 'desc';
|
|
|
42
43
|
export type KeyCondition<E> = {
|
|
43
44
|
partition: Partial<OnlyNumberString<E>>;
|
|
44
45
|
sort?: {
|
|
45
|
-
[key in keyof E as E[key] extends number | string ? key : never]?: E[key] extends PrimaryPartition<number> ? E[key] | OperationExpression<E[key]
|
|
46
|
+
[key in keyof E as E[key] extends number | string | bigint | BigInt ? key : never]?: E[key] extends PrimaryPartition<number | bigint | BigInt> ? UnwrapBigInt<E[key]> | OperationExpression<UnwrapBigInt<E[key]>> : E[key] extends PrimaryPartition<string> ? UnwrapBigInt<E[key]> | OnlyOne<OperationExpression<UnwrapBigInt<E[key]>> & StringExpression> : UnwrapBigInt<E[key]> | (E[key] extends number | bigint | BigInt ? OperationExpression<UnwrapBigInt<E[key]>> : OnlyOne<OperationExpression<UnwrapBigInt<E[key]>> | StringExpression>);
|
|
46
47
|
};
|
|
47
48
|
};
|
|
48
49
|
export type Item<E extends Function> = {
|
|
@@ -138,16 +139,16 @@ export interface QueryResponse<E extends Function> {
|
|
|
138
139
|
cursor?: Cursor<E['prototype']>;
|
|
139
140
|
}
|
|
140
141
|
export type ObjectToBoolean<T> = {
|
|
141
|
-
[K in keyof T]?: T[K] extends number | string | boolean | Array<any> | Date ? true : ObjectToBoolean<T[K]> | true;
|
|
142
|
+
[K in keyof T]?: T[K] extends number | string | bigint | BigInt | boolean | Array<any> | Date ? true : ObjectToBoolean<T[K]> | true;
|
|
142
143
|
};
|
|
143
144
|
interface ExistValue<T> {
|
|
144
145
|
ifNotExistValue: T;
|
|
145
146
|
}
|
|
146
147
|
interface NumericValues<T> extends ExistValue<T> {
|
|
147
|
-
incrementValue?: number;
|
|
148
|
-
decrementValue?: number;
|
|
148
|
+
incrementValue?: number | bigint;
|
|
149
|
+
decrementValue?: number | bigint;
|
|
149
150
|
}
|
|
150
|
-
export type NumericOrExist<T> = T extends number ?
|
|
151
|
+
export type NumericOrExist<T> = NonNullable<T> extends number | bigint | BigInt ? UnwrapBigInt<T> | OnlyOne<NumericValues<UnwrapBigInt<T>>> : T extends string | boolean | Array<any> | Date ? T | ExistValue<T> : (T & {
|
|
151
152
|
ifNotExistValue?: never;
|
|
152
153
|
}) | (ExistValue<T> & {
|
|
153
154
|
[K in keyof T]?: never;
|
|
@@ -156,7 +157,7 @@ export type ReplaceValue<T> = {
|
|
|
156
157
|
[K in keyof T]?: NumericOrExist<T[K]>;
|
|
157
158
|
};
|
|
158
159
|
export type DeepReplaceValue<T> = {
|
|
159
|
-
[K in keyof T]?: T[K] extends number | string | boolean | Array<any> | Date ? NumericOrExist<T[K]> : ExistValue<T[K]> | DeepReplaceValue<T[K]>;
|
|
160
|
+
[K in keyof T]?: NonNullable<T[K]> extends number | string | bigint | BigInt | boolean | Array<any> | Date ? NumericOrExist<T[K]> : ExistValue<T[K]> | DeepReplaceValue<T[K]>;
|
|
160
161
|
};
|
|
161
162
|
export type ReturnValueOption = 'all_new' | 'updated_new' | 'all_old' | 'none';
|
|
162
163
|
export type UpdateReturnType<E extends Function, R extends ReturnValueOption | undefined> = R extends 'all_new' | 'all_old' ? Item<E> : R extends 'updated_new' ? Partial<Item<E>> : undefined;
|
|
@@ -5,6 +5,25 @@ const client_dynamodb_1 = require("@aws-sdk/client-dynamodb");
|
|
|
5
5
|
const util_dynamodb_1 = require("@aws-sdk/util-dynamodb");
|
|
6
6
|
const base_1 = require("../base/base");
|
|
7
7
|
const update_utils_1 = require("./update.utils");
|
|
8
|
+
/**
|
|
9
|
+
* Recursively removes undefined values from an object.
|
|
10
|
+
* This prevents DynamoDB expression errors when undefined values
|
|
11
|
+
* are passed in setValues or replaceValues.
|
|
12
|
+
*/
|
|
13
|
+
function removeUndefinedValues(obj) {
|
|
14
|
+
const result = {};
|
|
15
|
+
for (const key in obj) {
|
|
16
|
+
if (obj[key] !== undefined) {
|
|
17
|
+
if (typeof obj[key] === 'object' && obj[key] !== null && !Array.isArray(obj[key])) {
|
|
18
|
+
result[key] = removeUndefinedValues(obj[key]);
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
result[key] = obj[key];
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return result;
|
|
26
|
+
}
|
|
8
27
|
class UpdateBuilder extends base_1.QueryBuilderBase {
|
|
9
28
|
queryOptions;
|
|
10
29
|
command;
|
|
@@ -30,17 +49,21 @@ class UpdateBuilder extends base_1.QueryBuilderBase {
|
|
|
30
49
|
}
|
|
31
50
|
prepare() {
|
|
32
51
|
const { removeValues = {}, replaceValues = {}, setValues = {}, condition, } = this.queryOptions.inputProps;
|
|
52
|
+
// Remove undefined values from setValues and replaceValues to prevent
|
|
53
|
+
// DynamoDB expression errors when undefined values are passed
|
|
54
|
+
const filteredSetValues = removeUndefinedValues(setValues);
|
|
55
|
+
const filteredReplaceValues = removeUndefinedValues(replaceValues);
|
|
33
56
|
if (Object.keys(removeValues).length > 0 &&
|
|
34
|
-
Object.keys(
|
|
35
|
-
Object.keys(
|
|
57
|
+
Object.keys(filteredReplaceValues).length > 0 &&
|
|
58
|
+
Object.keys(filteredSetValues).length > 0) {
|
|
36
59
|
throw new Error('You must assign a value to update');
|
|
37
60
|
}
|
|
38
61
|
let setExpression = '';
|
|
39
|
-
if (Object.keys(
|
|
40
|
-
setExpression = this.setValues(
|
|
62
|
+
if (Object.keys(filteredSetValues).length > 0) {
|
|
63
|
+
setExpression = this.setValues(filteredSetValues, true, [], this.expressionGroupCounter++);
|
|
41
64
|
}
|
|
42
|
-
if (Object.keys(
|
|
43
|
-
setExpression += `${setExpression ? ',' : ''} ${this.setValues(
|
|
65
|
+
if (Object.keys(filteredReplaceValues).length > 0) {
|
|
66
|
+
setExpression += `${setExpression ? ',' : ''} ${this.setValues(filteredReplaceValues, false, [], this.expressionGroupCounter++)}`;
|
|
44
67
|
}
|
|
45
68
|
const removeExpression = this.removeValues(removeValues);
|
|
46
69
|
const keyCondition = this.queryOptions.inputProps.keyCondition;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lafken/dynamo",
|
|
3
|
-
"version": "0.14.
|
|
3
|
+
"version": "0.14.3",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Define DynamoDB tables using TypeScript decorators - type-safe, declarative infrastructure with Lafken",
|
|
6
6
|
"keywords": [
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
"@aws-sdk/client-dynamodb": "^3.1106.0",
|
|
60
60
|
"@aws-sdk/util-dynamodb": "^3.996.7",
|
|
61
61
|
"reflect-metadata": "^0.2.2",
|
|
62
|
-
"@lafken/resolver": "0.14.
|
|
62
|
+
"@lafken/resolver": "0.14.3"
|
|
63
63
|
},
|
|
64
64
|
"devDependencies": {
|
|
65
65
|
"@cdktn/provider-aws": "^25.0.0",
|
|
@@ -73,13 +73,13 @@
|
|
|
73
73
|
"typescript": "7.0.2",
|
|
74
74
|
"unplugin-swc": "^1.5.10",
|
|
75
75
|
"vitest": "^4.1.10",
|
|
76
|
-
"@lafken/common": "0.14.
|
|
76
|
+
"@lafken/common": "0.14.3"
|
|
77
77
|
},
|
|
78
78
|
"peerDependencies": {
|
|
79
79
|
"@cdktn/provider-aws": ">=23.0.0",
|
|
80
80
|
"cdktn": ">=0.22.0",
|
|
81
81
|
"constructs": ">=10.7.0",
|
|
82
|
-
"@lafken/common": "0.14.
|
|
82
|
+
"@lafken/common": "0.14.3"
|
|
83
83
|
},
|
|
84
84
|
"engines": {
|
|
85
85
|
"node": ">=20.19"
|