@kensio/yulin 1.21.13 → 1.21.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/service/dynamodb/command/authorize/sim-dynamodb-attributes.d.ts +27 -0
- package/dist/service/dynamodb/command/authorize/sim-dynamodb-attributes.js +35 -0
- package/dist/service/dynamodb/command/authorize/sim-dynamodb-authorizer.d.ts +2 -1
- package/dist/service/dynamodb/command/authorize/sim-dynamodb-authorizer.js +5 -18
- package/dist/service/dynamodb/command/authorize/sim-dynamodb-reached.d.ts +17 -0
- package/dist/service/dynamodb/command/authorize/sim-dynamodb-reached.js +11 -0
- package/dist/service/dynamodb/command/batch/sim-dynamodb-batch-get-item.js +4 -1
- package/dist/service/dynamodb/command/batch/sim-dynamodb-batch-read-limit.d.ts +6 -0
- package/dist/service/dynamodb/command/batch/sim-dynamodb-batch-read-limit.js +16 -0
- package/dist/service/dynamodb/command/batch/sim-dynamodb-batch-reads.d.ts +2 -0
- package/dist/service/dynamodb/command/batch/sim-dynamodb-batch-reads.js +14 -22
- package/dist/service/dynamodb/command/batch/sim-dynamodb-batch-tables.d.ts +5 -5
- package/dist/service/dynamodb/command/batch/sim-dynamodb-batch-tables.js +1 -1
- package/dist/service/dynamodb/command/batch/sim-dynamodb-batch-write-item.js +5 -1
- package/dist/service/dynamodb/command/item/sim-dynamodb-condition-check.d.ts +5 -1
- package/dist/service/dynamodb/command/item/sim-dynamodb-condition-check.js +9 -2
- package/dist/service/dynamodb/command/item/sim-dynamodb-delete-item.js +7 -1
- package/dist/service/dynamodb/command/item/sim-dynamodb-get-item.js +9 -2
- package/dist/service/dynamodb/command/item/sim-dynamodb-put-item.js +5 -1
- package/dist/service/dynamodb/command/item/sim-dynamodb-update-expressions.d.ts +2 -0
- package/dist/service/dynamodb/command/item/sim-dynamodb-update-expressions.js +1 -1
- package/dist/service/dynamodb/command/item/sim-dynamodb-update-item.js +7 -1
- package/dist/service/dynamodb/command/item/sim-dynamodb-update-plan.d.ts +8 -6
- package/dist/service/dynamodb/command/item/sim-dynamodb-update-plan.js +14 -13
- package/dist/service/dynamodb/command/item/sim-dynamodb-update-touched.d.ts +10 -0
- package/dist/service/dynamodb/command/item/sim-dynamodb-update-touched.js +16 -0
- package/dist/service/dynamodb/command/query/sim-dynamodb-query-expressions.d.ts +2 -0
- package/dist/service/dynamodb/command/query/sim-dynamodb-query-expressions.js +6 -1
- package/dist/service/dynamodb/command/query/sim-dynamodb-query.js +5 -2
- package/dist/service/dynamodb/command/scan/sim-dynamodb-scan-expressions.d.ts +2 -0
- package/dist/service/dynamodb/command/scan/sim-dynamodb-scan-expressions.js +2 -2
- package/dist/service/dynamodb/command/scan/sim-dynamodb-scan.js +1 -1
- package/dist/service/dynamodb/command/table/sim-dynamodb-table-access.d.ts +3 -3
- package/dist/service/dynamodb/command/table/sim-dynamodb-table-access.js +5 -21
- package/dist/service/dynamodb/command/table/sim-dynamodb-table-reach.d.ts +25 -0
- package/dist/service/dynamodb/command/table/sim-dynamodb-table-reach.js +27 -0
- package/dist/service/dynamodb/command/transact/sim-dynamodb-transact-gets.js +1 -1
- package/dist/service/dynamodb/expression/condition/sim-dynamodb-condition-expression.d.ts +9 -1
- package/dist/service/dynamodb/expression/condition/sim-dynamodb-condition-expression.js +2 -2
- package/dist/service/dynamodb/expression/condition/sim-dynamodb-condition-grammar.js +1 -1
- package/dist/service/dynamodb/expression/condition/sim-dynamodb-condition-operand-parser.d.ts +3 -2
- package/dist/service/dynamodb/expression/condition/sim-dynamodb-condition-operand-parser.js +3 -3
- package/dist/service/dynamodb/expression/condition/sim-dynamodb-condition-parser.d.ts +2 -1
- package/dist/service/dynamodb/expression/condition/sim-dynamodb-condition-parser.js +1 -1
- package/dist/service/dynamodb/expression/key-condition/sim-dynamodb-key-condition-expression.js +1 -1
- package/dist/service/dynamodb/expression/key-condition/sim-dynamodb-key-condition-operands.d.ts +3 -2
- package/dist/service/dynamodb/expression/key-condition/sim-dynamodb-key-condition-operands.js +8 -6
- package/dist/service/dynamodb/expression/key-condition/sim-dynamodb-key-condition-parser.d.ts +2 -1
- package/dist/service/dynamodb/expression/key-condition/sim-dynamodb-key-condition-parser.js +1 -1
- package/dist/service/dynamodb/expression/projection/sim-dynamodb-projection-expression.d.ts +9 -1
- package/dist/service/dynamodb/expression/projection/sim-dynamodb-projection-expression.js +5 -5
- package/dist/service/dynamodb/expression/sim-dynamodb-document-path-parser.d.ts +3 -3
- package/dist/service/dynamodb/expression/sim-dynamodb-document-path-parser.js +8 -4
- package/dist/service/dynamodb/expression/sim-dynamodb-expression-attributes.d.ts +33 -0
- package/dist/service/dynamodb/expression/sim-dynamodb-expression-attributes.js +40 -0
- package/dist/service/dynamodb/expression/sim-dynamodb-expression-parameters.d.ts +6 -0
- package/dist/service/dynamodb/expression/sim-dynamodb-expression-parameters.js +7 -0
- package/dist/service/dynamodb/expression/update/sim-dynamodb-update-clause.d.ts +3 -3
- package/dist/service/dynamodb/expression/update/sim-dynamodb-update-clause.js +3 -3
- package/dist/service/dynamodb/expression/update/sim-dynamodb-update-expression.js +1 -1
- package/dist/service/dynamodb/expression/update/sim-dynamodb-update-operand-parser.d.ts +3 -2
- package/dist/service/dynamodb/expression/update/sim-dynamodb-update-operand-parser.js +3 -3
- package/dist/service/dynamodb/expression/update/sim-dynamodb-update-parser.d.ts +2 -1
- package/dist/service/iam/authorize/match/condition/negated/sim-iam-negated-for-all-values-string-operator.d.ts +4 -1
- package/dist/service/iam/authorize/match/condition/negated/sim-iam-negated-for-all-values-string-operator.js +6 -1
- package/dist/service/iam/authorize/match/condition/negated/sim-iam-negated-for-any-value-string-operator.d.ts +4 -1
- package/dist/service/iam/authorize/match/condition/negated/sim-iam-negated-for-any-value-string-operator.js +6 -1
- package/dist/service/iam/authorize/match/condition/negated/sim-iam-negated-scalar-string-operator.d.ts +4 -1
- package/dist/service/iam/authorize/match/condition/negated/sim-iam-negated-scalar-string-operator.js +6 -1
- package/dist/service/iam/authorize/match/condition/null/sim-iam-null.d.ts +23 -0
- package/dist/service/iam/authorize/match/condition/null/sim-iam-null.js +59 -0
- package/dist/service/iam/authorize/match/condition/numeric/less-than-equals/sim-iam-number-lte.d.ts +4 -1
- package/dist/service/iam/authorize/match/condition/numeric/less-than-equals/sim-iam-number-lte.js +6 -1
- package/dist/service/iam/authorize/match/condition/sim-iam-condition-operator-parser.js +2 -0
- package/dist/service/iam/authorize/match/condition/sim-iam-condition-operator.d.ts +5 -1
- package/dist/service/iam/authorize/match/condition/sim-iam-policy-condition-matcher.js +1 -1
- package/dist/service/iam/authorize/match/condition/string/all-values/sim-iam-for-all-values-string-condition-operator.d.ts +4 -1
- package/dist/service/iam/authorize/match/condition/string/all-values/sim-iam-for-all-values-string-condition-operator.js +6 -1
- package/dist/service/iam/authorize/match/condition/string/any-value/sim-iam-for-any-value-string-condition-operator.d.ts +4 -1
- package/dist/service/iam/authorize/match/condition/string/any-value/sim-iam-for-any-value-string-condition-operator.js +6 -1
- package/dist/service/iam/authorize/match/condition/string/sim-iam-scalar-string-condition-operator.d.ts +4 -1
- package/dist/service/iam/authorize/match/condition/string/sim-iam-scalar-string-condition-operator.js +6 -1
- package/docs/services/dynamodb/README.md +23 -4
- package/docs/services/iam/README.md +17 -3
- package/package.json +1 -1
|
@@ -34,8 +34,11 @@ export class SimDynamoDbQuery {
|
|
|
34
34
|
// The one partition key the query reads is what authorization needs, and
|
|
35
35
|
// reading it needs the view rather than the table, so it is read again
|
|
36
36
|
// here against whichever of the two the request names.
|
|
37
|
-
const table = this.access.required("dynamodb:Query", input.TableName, options?.caller,
|
|
38
|
-
.
|
|
37
|
+
const table = this.access.required("dynamodb:Query", input.TableName, options?.caller, {
|
|
38
|
+
leadingKeys: (reached) => simDynamoDbLeadingKeyOf(expressions.terms.forTable(reached.view(input.IndexName))
|
|
39
|
+
.partitionKeyValue),
|
|
40
|
+
attributes: expressions.attributes,
|
|
41
|
+
});
|
|
39
42
|
// What is being read is settled here: the table, or one of its indexes. An
|
|
40
43
|
// IndexName the table does not have is refused rather than read as the
|
|
41
44
|
// table. Everything after this asks the view rather than the table, so a
|
|
@@ -7,6 +7,8 @@ import type { SimScanCommandInput } from "./scan.command.js";
|
|
|
7
7
|
export interface SimDynamoDbScanExpressions {
|
|
8
8
|
readonly filter: SimDynamoDbFilter | undefined;
|
|
9
9
|
readonly projection: SimDynamoDbProjection | undefined;
|
|
10
|
+
/** The top-level attributes the expressions named, for `dynamodb:Attributes`. */
|
|
11
|
+
readonly attributes: readonly string[];
|
|
10
12
|
}
|
|
11
13
|
/**
|
|
12
14
|
* Read both expressions of a scan against one set of placeholders.
|
|
@@ -22,13 +22,13 @@ export function readSimDynamoDbScanExpressions(input) {
|
|
|
22
22
|
if (input.FilterExpression === undefined &&
|
|
23
23
|
input.ProjectionExpression === undefined) {
|
|
24
24
|
SimDynamoDbExpressionParameters.assertNoneWithout(input);
|
|
25
|
-
return { filter: undefined, projection: undefined };
|
|
25
|
+
return { filter: undefined, projection: undefined, attributes: [] };
|
|
26
26
|
}
|
|
27
27
|
const parameters = new SimDynamoDbExpressionParameters(input);
|
|
28
28
|
const filter = filterIn(input.FilterExpression, parameters);
|
|
29
29
|
const projection = projectionIn(input.ProjectionExpression, parameters);
|
|
30
30
|
parameters.assertAllUsed();
|
|
31
|
-
return { filter, projection };
|
|
31
|
+
return { filter, projection, attributes: parameters.attributes.topLevel };
|
|
32
32
|
}
|
|
33
33
|
/**
|
|
34
34
|
* Read the filter a scan drops read items by, if it names one.
|
|
@@ -39,7 +39,7 @@ export class SimDynamoDbScan {
|
|
|
39
39
|
// attribute, including a key attribute, and needs no key schema to check.
|
|
40
40
|
const segment = readSimDynamoDbScanSegment(input);
|
|
41
41
|
const expressions = readSimDynamoDbScanExpressions(input);
|
|
42
|
-
const table = this.access.required("dynamodb:Scan", input.TableName, options?.caller);
|
|
42
|
+
const table = this.access.required("dynamodb:Scan", input.TableName, options?.caller, { attributes: expressions.attributes });
|
|
43
43
|
// What is being read is settled here: the table, or one of its indexes.
|
|
44
44
|
const view = table.view(input.IndexName);
|
|
45
45
|
const scan = view.scan();
|
|
@@ -4,7 +4,7 @@ import type { SimDynamoDbTable } from "../../table/sim-dynamodb-table.js";
|
|
|
4
4
|
import type { SimDynamoDbTableName } from "../../table/sim-dynamodb-table-name.js";
|
|
5
5
|
import type { SimDynamoDbTableStore } from "../../table/sim-dynamodb-table-store.js";
|
|
6
6
|
import type { SimDynamoDbAuthorizer } from "../authorize/sim-dynamodb-authorizer.js";
|
|
7
|
-
import type {
|
|
7
|
+
import type { SimDynamoDbTableReach } from "./sim-dynamodb-table-reach.js";
|
|
8
8
|
interface SimDynamoDbTableAccessProperties {
|
|
9
9
|
readonly tables: SimDynamoDbTableStore;
|
|
10
10
|
readonly authorizer: SimDynamoDbAuthorizer;
|
|
@@ -36,7 +36,7 @@ export declare class SimDynamoDbTableAccess {
|
|
|
36
36
|
/**
|
|
37
37
|
* Find the table a request names, refusing the caller before answering.
|
|
38
38
|
*/
|
|
39
|
-
required(action: string, tableName: string | undefined, caller: SimAwsCaller | undefined,
|
|
39
|
+
required(action: string, tableName: string | undefined, caller: SimAwsCaller | undefined, reach?: SimDynamoDbTableReach): SimDynamoDbTable;
|
|
40
40
|
/**
|
|
41
41
|
* Find a table by a name that has already been read.
|
|
42
42
|
*
|
|
@@ -44,7 +44,7 @@ export declare class SimDynamoDbTableAccess {
|
|
|
44
44
|
* there, which keeps an unauthorized caller from finding out which table
|
|
45
45
|
* names are taken.
|
|
46
46
|
*/
|
|
47
|
-
requiredByName(action: string, name: SimDynamoDbTableName, caller: SimAwsCaller | undefined,
|
|
47
|
+
requiredByName(action: string, name: SimDynamoDbTableName, caller: SimAwsCaller | undefined, reach?: SimDynamoDbTableReach): SimDynamoDbTable;
|
|
48
48
|
/**
|
|
49
49
|
* Ensure the caller may perform an action that names no particular table.
|
|
50
50
|
*/
|
|
@@ -1,22 +1,6 @@
|
|
|
1
1
|
import { SimDynamoDbResourceNotFoundException } from "../../error/dynamodb.error.js";
|
|
2
2
|
import { readSimDynamoDbTableReference } from "../../table/sim-dynamodb-table-reference.js";
|
|
3
|
-
|
|
4
|
-
* Read the partition key values a request reaches, or none where they cannot
|
|
5
|
-
* be read.
|
|
6
|
-
*
|
|
7
|
-
* Authorization runs ahead of the checks a command makes on what it was given,
|
|
8
|
-
* as it does on AWS. A request whose key or key condition is malformed is
|
|
9
|
-
* authorized carrying no values and refused by the check that follows, so
|
|
10
|
-
* whatever reading them throws is dropped here.
|
|
11
|
-
*/
|
|
12
|
-
function readLeadingKeys(leadingKeys, table) {
|
|
13
|
-
try {
|
|
14
|
-
return leadingKeys?.(table);
|
|
15
|
-
}
|
|
16
|
-
catch {
|
|
17
|
-
return undefined;
|
|
18
|
-
}
|
|
19
|
-
}
|
|
3
|
+
import { simDynamoDbReachedIn } from "./sim-dynamodb-table-reach.js";
|
|
20
4
|
/**
|
|
21
5
|
* How a command reaches the table a request names.
|
|
22
6
|
*
|
|
@@ -49,8 +33,8 @@ export class SimDynamoDbTableAccess {
|
|
|
49
33
|
/**
|
|
50
34
|
* Find the table a request names, refusing the caller before answering.
|
|
51
35
|
*/
|
|
52
|
-
required(action, tableName, caller,
|
|
53
|
-
return this.requiredByName(action, this.reference(tableName), caller,
|
|
36
|
+
required(action, tableName, caller, reach = {}) {
|
|
37
|
+
return this.requiredByName(action, this.reference(tableName), caller, reach);
|
|
54
38
|
}
|
|
55
39
|
/**
|
|
56
40
|
* Find a table by a name that has already been read.
|
|
@@ -59,9 +43,9 @@ export class SimDynamoDbTableAccess {
|
|
|
59
43
|
* there, which keeps an unauthorized caller from finding out which table
|
|
60
44
|
* names are taken.
|
|
61
45
|
*/
|
|
62
|
-
requiredByName(action, name, caller,
|
|
46
|
+
requiredByName(action, name, caller, reach = {}) {
|
|
63
47
|
const table = this.tables.find(name);
|
|
64
|
-
this.authorizer.authorizeTable(action, name.value, caller,
|
|
48
|
+
this.authorizer.authorizeTable(action, name.value, caller, simDynamoDbReachedIn(reach, table));
|
|
65
49
|
if (table === undefined) {
|
|
66
50
|
throw new SimDynamoDbResourceNotFoundException(`No DynamoDB Table named ${name.value}`);
|
|
67
51
|
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { SimDynamoDbReached } from "../authorize/sim-dynamodb-reached.js";
|
|
2
|
+
import type { SimDynamoDbLeadingKeys } from "../authorize/sim-dynamodb-leading-keys.js";
|
|
3
|
+
import type { SimDynamoDbTable } from "../../table/sim-dynamodb-table.js";
|
|
4
|
+
/**
|
|
5
|
+
* What one command's request reaches, for the condition keys authorization
|
|
6
|
+
* supplies.
|
|
7
|
+
*
|
|
8
|
+
* The partition key values need the table to read them, so they arrive as a
|
|
9
|
+
* function of it. The attribute names are read from the request's own
|
|
10
|
+
* parameters before the table is reached, so they arrive as they are.
|
|
11
|
+
*/
|
|
12
|
+
export interface SimDynamoDbTableReach {
|
|
13
|
+
readonly leadingKeys?: SimDynamoDbLeadingKeys | undefined;
|
|
14
|
+
readonly attributes?: readonly string[] | undefined;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Resolve what a request reaches against the table it named.
|
|
18
|
+
*
|
|
19
|
+
* Authorization runs ahead of the checks a command makes on what it was given,
|
|
20
|
+
* as it does on AWS. A request whose key or key condition is malformed is
|
|
21
|
+
* authorized carrying no values and refused by the check that follows, so
|
|
22
|
+
* whatever reading them throws is dropped here. A table that is not there
|
|
23
|
+
* leaves the values unread, since the key schema is what reads them.
|
|
24
|
+
*/
|
|
25
|
+
export declare function simDynamoDbReachedIn(reach: SimDynamoDbTableReach, table: SimDynamoDbTable | undefined): SimDynamoDbReached;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve what a request reaches against the table it named.
|
|
3
|
+
*
|
|
4
|
+
* Authorization runs ahead of the checks a command makes on what it was given,
|
|
5
|
+
* as it does on AWS. A request whose key or key condition is malformed is
|
|
6
|
+
* authorized carrying no values and refused by the check that follows, so
|
|
7
|
+
* whatever reading them throws is dropped here. A table that is not there
|
|
8
|
+
* leaves the values unread, since the key schema is what reads them.
|
|
9
|
+
*/
|
|
10
|
+
export function simDynamoDbReachedIn(reach, table) {
|
|
11
|
+
return {
|
|
12
|
+
leadingKeys: table === undefined ? undefined : leadingKeysIn(reach, table),
|
|
13
|
+
attributes: reach.attributes,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Read the partition key values a request reaches, or none where they cannot
|
|
18
|
+
* be read.
|
|
19
|
+
*/
|
|
20
|
+
function leadingKeysIn(reach, table) {
|
|
21
|
+
try {
|
|
22
|
+
return reach.leadingKeys?.(table);
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return undefined;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -23,7 +23,7 @@ export class SimDynamoDbTransactRead {
|
|
|
23
23
|
* Read the Get one action of a transactional read carries.
|
|
24
24
|
*/
|
|
25
25
|
static of(request) {
|
|
26
|
-
return new this(request.TableName, readSimDynamoDbKey(request.Key), readSimDynamoDbProjection(request));
|
|
26
|
+
return new this(request.TableName, readSimDynamoDbKey(request.Key), readSimDynamoDbProjection(request).projection);
|
|
27
27
|
}
|
|
28
28
|
/**
|
|
29
29
|
* The primary key this Get reads, as the table marshals it.
|
|
@@ -4,13 +4,21 @@ import type { SimDynamoDbCondition } from "./sim-dynamodb-condition.js";
|
|
|
4
4
|
interface SimDynamoDbConditionRequest extends SimDynamoDbExpressionParameterInput {
|
|
5
5
|
readonly ConditionExpression?: string | undefined;
|
|
6
6
|
}
|
|
7
|
+
/**
|
|
8
|
+
* What a request's ConditionExpression said, once it has been read.
|
|
9
|
+
*/
|
|
10
|
+
export interface SimDynamoDbConditionRead {
|
|
11
|
+
readonly condition: SimDynamoDbCondition | undefined;
|
|
12
|
+
/** The top-level attributes the expression named, for `dynamodb:Attributes`. */
|
|
13
|
+
readonly attributes: readonly string[];
|
|
14
|
+
}
|
|
7
15
|
/**
|
|
8
16
|
* Read the condition a write is guarded by, if it names one.
|
|
9
17
|
*
|
|
10
18
|
* A request with no ConditionExpression is an unconditional write, so there is
|
|
11
19
|
* nothing to check.
|
|
12
20
|
*/
|
|
13
|
-
export declare function readSimDynamoDbCondition(request: SimDynamoDbConditionRequest):
|
|
21
|
+
export declare function readSimDynamoDbCondition(request: SimDynamoDbConditionRequest): SimDynamoDbConditionRead;
|
|
14
22
|
/**
|
|
15
23
|
* Read one ConditionExpression against placeholders that have already been
|
|
16
24
|
* gathered.
|
|
@@ -11,12 +11,12 @@ export function readSimDynamoDbCondition(request) {
|
|
|
11
11
|
const expression = request.ConditionExpression;
|
|
12
12
|
if (expression === undefined) {
|
|
13
13
|
SimDynamoDbExpressionParameters.assertNoneWithout(request);
|
|
14
|
-
return undefined;
|
|
14
|
+
return { condition: undefined, attributes: [] };
|
|
15
15
|
}
|
|
16
16
|
const parameters = new SimDynamoDbExpressionParameters(request);
|
|
17
17
|
const condition = parseSimDynamoDbCondition(expression, parameters);
|
|
18
18
|
parameters.assertAllUsed();
|
|
19
|
-
return condition;
|
|
19
|
+
return { condition, attributes: parameters.attributes.topLevel };
|
|
20
20
|
}
|
|
21
21
|
/**
|
|
22
22
|
* Read one ConditionExpression against placeholders that have already been
|
|
@@ -10,7 +10,7 @@ import { SimDynamoDbConditionParser } from "./sim-dynamodb-condition-parser.js";
|
|
|
10
10
|
export function simDynamoDbConditionParser(expressionName, expression, parameters) {
|
|
11
11
|
return new SimDynamoDbConditionParser({
|
|
12
12
|
tokens: SimDynamoDbExpressionTokens.of(expressionName, expression, "the expression says nothing, and an expression cannot be empty"),
|
|
13
|
-
|
|
13
|
+
attributes: parameters.attributes,
|
|
14
14
|
values: parameters.values,
|
|
15
15
|
});
|
|
16
16
|
}
|
package/dist/service/dynamodb/expression/condition/sim-dynamodb-condition-operand-parser.d.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import type { SimDynamoDbValue } from "../../item/sim-dynamodb-value.js";
|
|
2
2
|
import type { SimDynamoDbDocumentPath } from "../sim-dynamodb-document-path.js";
|
|
3
|
+
import type { SimDynamoDbExpressionAttributes } from "../sim-dynamodb-expression-attributes.js";
|
|
3
4
|
import type { SimDynamoDbExpressionPlaceholders } from "../sim-dynamodb-expression-placeholders.js";
|
|
4
5
|
import type { SimDynamoDbExpressionTokens } from "../sim-dynamodb-expression-tokens.js";
|
|
5
6
|
import { type SimDynamoDbConditionOperand, SimDynamoDbPathOperand } from "./sim-dynamodb-condition-operand.js";
|
|
6
7
|
interface SimDynamoDbConditionOperandParserProperties {
|
|
7
8
|
readonly tokens: SimDynamoDbExpressionTokens;
|
|
8
|
-
readonly
|
|
9
|
+
readonly attributes: SimDynamoDbExpressionAttributes;
|
|
9
10
|
readonly values: SimDynamoDbExpressionPlaceholders<SimDynamoDbValue>;
|
|
10
11
|
}
|
|
11
12
|
/**
|
|
@@ -17,7 +18,7 @@ interface SimDynamoDbConditionOperandParserProperties {
|
|
|
17
18
|
*/
|
|
18
19
|
export declare class SimDynamoDbConditionOperandParser {
|
|
19
20
|
private readonly tokens;
|
|
20
|
-
private readonly
|
|
21
|
+
private readonly attributes;
|
|
21
22
|
private readonly values;
|
|
22
23
|
private readonly read;
|
|
23
24
|
constructor(properties: SimDynamoDbConditionOperandParserProperties);
|
|
@@ -15,12 +15,12 @@ const sizeFunctionName = "size";
|
|
|
15
15
|
*/
|
|
16
16
|
export class SimDynamoDbConditionOperandParser {
|
|
17
17
|
tokens;
|
|
18
|
-
|
|
18
|
+
attributes;
|
|
19
19
|
values;
|
|
20
20
|
read = [];
|
|
21
21
|
constructor(properties) {
|
|
22
22
|
this.tokens = properties.tokens;
|
|
23
|
-
this.
|
|
23
|
+
this.attributes = properties.attributes;
|
|
24
24
|
this.values = properties.values;
|
|
25
25
|
}
|
|
26
26
|
/**
|
|
@@ -87,7 +87,7 @@ export class SimDynamoDbConditionOperandParser {
|
|
|
87
87
|
path() {
|
|
88
88
|
const path = new SimDynamoDbDocumentPathParser({
|
|
89
89
|
tokens: this.tokens,
|
|
90
|
-
|
|
90
|
+
attributes: this.attributes,
|
|
91
91
|
}).parse();
|
|
92
92
|
this.read.push(path);
|
|
93
93
|
return new SimDynamoDbPathOperand(path);
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import type { SimDynamoDbValue } from "../../item/sim-dynamodb-value.js";
|
|
2
2
|
import type { SimDynamoDbDocumentPath } from "../sim-dynamodb-document-path.js";
|
|
3
|
+
import type { SimDynamoDbExpressionAttributes } from "../sim-dynamodb-expression-attributes.js";
|
|
3
4
|
import type { SimDynamoDbExpressionPlaceholders } from "../sim-dynamodb-expression-placeholders.js";
|
|
4
5
|
import type { SimDynamoDbExpressionTokens } from "../sim-dynamodb-expression-tokens.js";
|
|
5
6
|
import { type SimDynamoDbCondition } from "./sim-dynamodb-condition.js";
|
|
6
7
|
interface SimDynamoDbConditionParserProperties {
|
|
7
8
|
readonly tokens: SimDynamoDbExpressionTokens;
|
|
8
|
-
readonly
|
|
9
|
+
readonly attributes: SimDynamoDbExpressionAttributes;
|
|
9
10
|
readonly values: SimDynamoDbExpressionPlaceholders<SimDynamoDbValue>;
|
|
10
11
|
}
|
|
11
12
|
/**
|
|
@@ -21,7 +21,7 @@ export class SimDynamoDbConditionParser {
|
|
|
21
21
|
constructor(properties) {
|
|
22
22
|
const operands = new SimDynamoDbConditionOperandParser({
|
|
23
23
|
tokens: properties.tokens,
|
|
24
|
-
|
|
24
|
+
attributes: properties.attributes,
|
|
25
25
|
values: properties.values,
|
|
26
26
|
});
|
|
27
27
|
this.tokens = properties.tokens;
|
package/dist/service/dynamodb/expression/key-condition/sim-dynamodb-key-condition-expression.js
CHANGED
|
@@ -22,7 +22,7 @@ export function readSimDynamoDbKeyCondition(request, parameters) {
|
|
|
22
22
|
}
|
|
23
23
|
const terms = new SimDynamoDbKeyConditionParser({
|
|
24
24
|
tokens: SimDynamoDbExpressionTokens.of(keyConditionExpressionName, expression, "the expression says nothing, and an expression cannot be empty"),
|
|
25
|
-
|
|
25
|
+
attributes: parameters.attributes,
|
|
26
26
|
values: parameters.values,
|
|
27
27
|
}).parse();
|
|
28
28
|
return new SimDynamoDbKeyConditionTerms(terms);
|
package/dist/service/dynamodb/expression/key-condition/sim-dynamodb-key-condition-operands.d.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import type { SimDynamoDbValue } from "../../item/sim-dynamodb-value.js";
|
|
2
|
+
import type { SimDynamoDbExpressionAttributes } from "../sim-dynamodb-expression-attributes.js";
|
|
2
3
|
import type { SimDynamoDbExpressionPlaceholders } from "../sim-dynamodb-expression-placeholders.js";
|
|
3
4
|
import type { SimDynamoDbExpressionTokens } from "../sim-dynamodb-expression-tokens.js";
|
|
4
5
|
import { type SimDynamoDbKeyConditionRefusals } from "./sim-dynamodb-key-condition-refusals.js";
|
|
5
6
|
interface SimDynamoDbKeyConditionOperandsProperties {
|
|
6
7
|
readonly tokens: SimDynamoDbExpressionTokens;
|
|
7
|
-
readonly
|
|
8
|
+
readonly attributes: SimDynamoDbExpressionAttributes;
|
|
8
9
|
readonly values: SimDynamoDbExpressionPlaceholders<SimDynamoDbValue>;
|
|
9
10
|
readonly refusals: SimDynamoDbKeyConditionRefusals;
|
|
10
11
|
}
|
|
@@ -17,7 +18,7 @@ interface SimDynamoDbKeyConditionOperandsProperties {
|
|
|
17
18
|
*/
|
|
18
19
|
export declare class SimDynamoDbKeyConditionOperands {
|
|
19
20
|
private readonly tokens;
|
|
20
|
-
private readonly
|
|
21
|
+
private readonly attributes;
|
|
21
22
|
private readonly values;
|
|
22
23
|
private readonly refusals;
|
|
23
24
|
constructor(properties: SimDynamoDbKeyConditionOperandsProperties);
|
package/dist/service/dynamodb/expression/key-condition/sim-dynamodb-key-condition-operands.js
CHANGED
|
@@ -22,12 +22,12 @@ const keyComparators = new Set([
|
|
|
22
22
|
*/
|
|
23
23
|
export class SimDynamoDbKeyConditionOperands {
|
|
24
24
|
tokens;
|
|
25
|
-
|
|
25
|
+
attributes;
|
|
26
26
|
values;
|
|
27
27
|
refusals;
|
|
28
28
|
constructor(properties) {
|
|
29
29
|
this.tokens = properties.tokens;
|
|
30
|
-
this.
|
|
30
|
+
this.attributes = properties.attributes;
|
|
31
31
|
this.values = properties.values;
|
|
32
32
|
this.refusals = properties.refusals;
|
|
33
33
|
}
|
|
@@ -77,9 +77,11 @@ export class SimDynamoDbKeyConditionOperands {
|
|
|
77
77
|
* The attribute a name token stands for, which may be a placeholder.
|
|
78
78
|
*/
|
|
79
79
|
nameOf(kind, text) {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
80
|
+
const name = kind === "name" ? text : this.attributes.required(text);
|
|
81
|
+
// A key condition reads no document paths, so the attributes it reaches
|
|
82
|
+
// are noted here rather than by the path parser. A key is scalar, and the
|
|
83
|
+
// attribute a term names is always a top-level one.
|
|
84
|
+
this.attributes.reach(name);
|
|
85
|
+
return name;
|
|
84
86
|
}
|
|
85
87
|
}
|
package/dist/service/dynamodb/expression/key-condition/sim-dynamodb-key-condition-parser.d.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import type { SimDynamoDbValue } from "../../item/sim-dynamodb-value.js";
|
|
2
|
+
import type { SimDynamoDbExpressionAttributes } from "../sim-dynamodb-expression-attributes.js";
|
|
2
3
|
import type { SimDynamoDbExpressionPlaceholders } from "../sim-dynamodb-expression-placeholders.js";
|
|
3
4
|
import type { SimDynamoDbExpressionTokens } from "../sim-dynamodb-expression-tokens.js";
|
|
4
5
|
import type { SimDynamoDbKeyConditionTerm } from "./sim-dynamodb-key-condition-term.js";
|
|
5
6
|
interface SimDynamoDbKeyConditionParserProperties {
|
|
6
7
|
readonly tokens: SimDynamoDbExpressionTokens;
|
|
7
|
-
readonly
|
|
8
|
+
readonly attributes: SimDynamoDbExpressionAttributes;
|
|
8
9
|
readonly values: SimDynamoDbExpressionPlaceholders<SimDynamoDbValue>;
|
|
9
10
|
}
|
|
10
11
|
/**
|
|
@@ -27,7 +27,7 @@ export class SimDynamoDbKeyConditionParser {
|
|
|
27
27
|
this.refusals = refusals;
|
|
28
28
|
this.operands = new SimDynamoDbKeyConditionOperands({
|
|
29
29
|
tokens: properties.tokens,
|
|
30
|
-
|
|
30
|
+
attributes: properties.attributes,
|
|
31
31
|
values: properties.values,
|
|
32
32
|
refusals,
|
|
33
33
|
});
|
|
@@ -4,6 +4,14 @@ import { SimDynamoDbProjection } from "./sim-dynamodb-projection.js";
|
|
|
4
4
|
interface SimDynamoDbProjectionRequest extends SimDynamoDbExpressionParameterInput {
|
|
5
5
|
readonly ProjectionExpression?: string | undefined;
|
|
6
6
|
}
|
|
7
|
+
/**
|
|
8
|
+
* What a request's ProjectionExpression said, once it has been read.
|
|
9
|
+
*/
|
|
10
|
+
export interface SimDynamoDbProjectionRead {
|
|
11
|
+
readonly projection: SimDynamoDbProjection | undefined;
|
|
12
|
+
/** The top-level attributes the expression named, for `dynamodb:Attributes`. */
|
|
13
|
+
readonly attributes: readonly string[];
|
|
14
|
+
}
|
|
7
15
|
/**
|
|
8
16
|
* Read the projection a request asks for, if it asks for one.
|
|
9
17
|
*
|
|
@@ -15,7 +23,7 @@ interface SimDynamoDbProjectionRequest extends SimDynamoDbExpressionParameterInp
|
|
|
15
23
|
* carry a filter alongside its projection, and reads both against one set of
|
|
16
24
|
* placeholders through `parseSimDynamoDbProjection`.
|
|
17
25
|
*/
|
|
18
|
-
export declare function readSimDynamoDbProjection(request: SimDynamoDbProjectionRequest):
|
|
26
|
+
export declare function readSimDynamoDbProjection(request: SimDynamoDbProjectionRequest): SimDynamoDbProjectionRead;
|
|
19
27
|
/**
|
|
20
28
|
* Read one ProjectionExpression against placeholders that have already been
|
|
21
29
|
* gathered.
|
|
@@ -19,12 +19,12 @@ export function readSimDynamoDbProjection(request) {
|
|
|
19
19
|
const expression = request.ProjectionExpression;
|
|
20
20
|
if (expression === undefined) {
|
|
21
21
|
SimDynamoDbExpressionParameters.assertNoneWithout(request);
|
|
22
|
-
return undefined;
|
|
22
|
+
return { projection: undefined, attributes: [] };
|
|
23
23
|
}
|
|
24
24
|
const parameters = new SimDynamoDbExpressionParameters(request);
|
|
25
25
|
const projection = parseSimDynamoDbProjection(expression, parameters);
|
|
26
26
|
parameters.assertAllUsed();
|
|
27
|
-
return projection;
|
|
27
|
+
return { projection, attributes: parameters.attributes.topLevel };
|
|
28
28
|
}
|
|
29
29
|
/**
|
|
30
30
|
* Read one ProjectionExpression against placeholders that have already been
|
|
@@ -35,16 +35,16 @@ export function readSimDynamoDbProjection(request) {
|
|
|
35
35
|
* placeholders are checked once every expression has been read.
|
|
36
36
|
*/
|
|
37
37
|
export function parseSimDynamoDbProjection(expression, parameters) {
|
|
38
|
-
const paths = projectedPaths(SimDynamoDbExpressionTokens.of(expressionName, expression, "the expression names no attributes, and an expression cannot be empty"), parameters.
|
|
38
|
+
const paths = projectedPaths(SimDynamoDbExpressionTokens.of(expressionName, expression, "the expression names no attributes, and an expression cannot be empty"), parameters.attributes);
|
|
39
39
|
return new SimDynamoDbProjection({ expressionName, paths });
|
|
40
40
|
}
|
|
41
41
|
/**
|
|
42
42
|
* Read the comma-separated document paths a ProjectionExpression names.
|
|
43
43
|
*/
|
|
44
|
-
function projectedPaths(tokens,
|
|
44
|
+
function projectedPaths(tokens, attributes) {
|
|
45
45
|
const paths = [];
|
|
46
46
|
do {
|
|
47
|
-
paths.push(new SimDynamoDbDocumentPathParser({ tokens,
|
|
47
|
+
paths.push(new SimDynamoDbDocumentPathParser({ tokens, attributes }).parse());
|
|
48
48
|
} while (tokens.takeSymbol(","));
|
|
49
49
|
assertReadToEnd(tokens);
|
|
50
50
|
return paths;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { SimDynamoDbDocumentPath } from "./sim-dynamodb-document-path.js";
|
|
2
|
-
import type {
|
|
2
|
+
import type { SimDynamoDbExpressionAttributes } from "./sim-dynamodb-expression-attributes.js";
|
|
3
3
|
import type { SimDynamoDbExpressionTokens } from "./sim-dynamodb-expression-tokens.js";
|
|
4
4
|
interface SimDynamoDbDocumentPathParserProperties {
|
|
5
5
|
readonly tokens: SimDynamoDbExpressionTokens;
|
|
6
|
-
readonly
|
|
6
|
+
readonly attributes: SimDynamoDbExpressionAttributes;
|
|
7
7
|
}
|
|
8
8
|
/**
|
|
9
9
|
* Reads one document path out of an expression.
|
|
@@ -15,7 +15,7 @@ interface SimDynamoDbDocumentPathParserProperties {
|
|
|
15
15
|
*/
|
|
16
16
|
export declare class SimDynamoDbDocumentPathParser {
|
|
17
17
|
private readonly tokens;
|
|
18
|
-
private readonly
|
|
18
|
+
private readonly attributes;
|
|
19
19
|
private readonly segments;
|
|
20
20
|
constructor(properties: SimDynamoDbDocumentPathParserProperties);
|
|
21
21
|
/**
|
|
@@ -14,17 +14,21 @@ const greatestDepth = 32;
|
|
|
14
14
|
*/
|
|
15
15
|
export class SimDynamoDbDocumentPathParser {
|
|
16
16
|
tokens;
|
|
17
|
-
|
|
17
|
+
attributes;
|
|
18
18
|
segments = [];
|
|
19
19
|
constructor(properties) {
|
|
20
20
|
this.tokens = properties.tokens;
|
|
21
|
-
this.
|
|
21
|
+
this.attributes = properties.attributes;
|
|
22
22
|
}
|
|
23
23
|
/**
|
|
24
24
|
* Read a path, from its first attribute to the last thing it dereferences.
|
|
25
25
|
*/
|
|
26
26
|
parse() {
|
|
27
|
-
this.
|
|
27
|
+
const first = this.attribute();
|
|
28
|
+
// The path starts here, so this is the top-level attribute it reaches.
|
|
29
|
+
// Whatever it dereferences afterwards is inside this one.
|
|
30
|
+
this.attributes.reach(first.name);
|
|
31
|
+
this.segments.push(first);
|
|
28
32
|
while (this.continues()) {
|
|
29
33
|
this.assertWithinDepth();
|
|
30
34
|
}
|
|
@@ -54,7 +58,7 @@ export class SimDynamoDbDocumentPathParser {
|
|
|
54
58
|
return { kind: "attribute", name: token.text };
|
|
55
59
|
}
|
|
56
60
|
if (token.kind === "namePlaceholder") {
|
|
57
|
-
return { kind: "attribute", name: this.
|
|
61
|
+
return { kind: "attribute", name: this.attributes.required(token.text) };
|
|
58
62
|
}
|
|
59
63
|
throw this.tokens.error(`syntax error; an attribute name was expected${this.after()}, but ` +
|
|
60
64
|
`'${token.text}' was given`);
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { SimDynamoDbExpressionPlaceholders } from "./sim-dynamodb-expression-placeholders.js";
|
|
2
|
+
/**
|
|
3
|
+
* The attribute names one request's expressions reach.
|
|
4
|
+
*
|
|
5
|
+
* Every expression kind names attributes the same way, either outright or
|
|
6
|
+
* behind a `#` placeholder, and every one of them reads those names through
|
|
7
|
+
* here. Noting the names as they are read is what lets a request say which
|
|
8
|
+
* attributes it names, which is what `dynamodb:Attributes` asks about.
|
|
9
|
+
*
|
|
10
|
+
* Only the attribute a document path starts at is noted. AWS counts a
|
|
11
|
+
* top-level attribute as reached where the request names it or anything nested
|
|
12
|
+
* inside it, so `Address.City` reaches `Address`.
|
|
13
|
+
*/
|
|
14
|
+
export declare class SimDynamoDbExpressionAttributes {
|
|
15
|
+
private readonly placeholders;
|
|
16
|
+
private readonly reached;
|
|
17
|
+
constructor(placeholders: SimDynamoDbExpressionPlaceholders<string>);
|
|
18
|
+
/**
|
|
19
|
+
* What a placeholder stands for, refusing one the request never defined.
|
|
20
|
+
*
|
|
21
|
+
* Resolving a placeholder says nothing about where in a path it sits, so
|
|
22
|
+
* nothing is noted here.
|
|
23
|
+
*/
|
|
24
|
+
required(placeholder: string): string;
|
|
25
|
+
/**
|
|
26
|
+
* Note a top-level attribute an expression named.
|
|
27
|
+
*/
|
|
28
|
+
reach(name: string): void;
|
|
29
|
+
/**
|
|
30
|
+
* The top-level attributes every expression of the request named.
|
|
31
|
+
*/
|
|
32
|
+
get topLevel(): readonly string[];
|
|
33
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The attribute names one request's expressions reach.
|
|
3
|
+
*
|
|
4
|
+
* Every expression kind names attributes the same way, either outright or
|
|
5
|
+
* behind a `#` placeholder, and every one of them reads those names through
|
|
6
|
+
* here. Noting the names as they are read is what lets a request say which
|
|
7
|
+
* attributes it names, which is what `dynamodb:Attributes` asks about.
|
|
8
|
+
*
|
|
9
|
+
* Only the attribute a document path starts at is noted. AWS counts a
|
|
10
|
+
* top-level attribute as reached where the request names it or anything nested
|
|
11
|
+
* inside it, so `Address.City` reaches `Address`.
|
|
12
|
+
*/
|
|
13
|
+
export class SimDynamoDbExpressionAttributes {
|
|
14
|
+
placeholders;
|
|
15
|
+
reached = new Set();
|
|
16
|
+
constructor(placeholders) {
|
|
17
|
+
this.placeholders = placeholders;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* What a placeholder stands for, refusing one the request never defined.
|
|
21
|
+
*
|
|
22
|
+
* Resolving a placeholder says nothing about where in a path it sits, so
|
|
23
|
+
* nothing is noted here.
|
|
24
|
+
*/
|
|
25
|
+
required(placeholder) {
|
|
26
|
+
return this.placeholders.required(placeholder);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Note a top-level attribute an expression named.
|
|
30
|
+
*/
|
|
31
|
+
reach(name) {
|
|
32
|
+
this.reached.add(name);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* The top-level attributes every expression of the request named.
|
|
36
|
+
*/
|
|
37
|
+
get topLevel() {
|
|
38
|
+
return [...this.reached];
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { SimDynamoDbAttributeValue } from "../command/item/item.types.js";
|
|
2
2
|
import type { SimDynamoDbValue } from "../item/sim-dynamodb-value.js";
|
|
3
|
+
import { SimDynamoDbExpressionAttributes } from "./sim-dynamodb-expression-attributes.js";
|
|
3
4
|
import { SimDynamoDbExpressionPlaceholders } from "./sim-dynamodb-expression-placeholders.js";
|
|
4
5
|
/**
|
|
5
6
|
* The two placeholder parameters a request can carry for its expressions.
|
|
@@ -19,6 +20,11 @@ export interface SimDynamoDbExpressionParameterInput {
|
|
|
19
20
|
export declare class SimDynamoDbExpressionParameters {
|
|
20
21
|
readonly names: SimDynamoDbExpressionPlaceholders<string>;
|
|
21
22
|
readonly values: SimDynamoDbExpressionPlaceholders<SimDynamoDbValue>;
|
|
23
|
+
/**
|
|
24
|
+
* The attribute names the request's expressions reach, gathered as they are
|
|
25
|
+
* read. Authorization asks for these as `dynamodb:Attributes`.
|
|
26
|
+
*/
|
|
27
|
+
readonly attributes: SimDynamoDbExpressionAttributes;
|
|
22
28
|
constructor(input: SimDynamoDbExpressionParameterInput);
|
|
23
29
|
/**
|
|
24
30
|
* Refuse placeholders defined for an expression the request does not carry.
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { SimDynamoDbValidationException } from "../error/dynamodb.error.js";
|
|
2
2
|
import { readSimDynamoDbValue } from "../item/sim-dynamodb-value-reader.js";
|
|
3
|
+
import { SimDynamoDbExpressionAttributes } from "./sim-dynamodb-expression-attributes.js";
|
|
3
4
|
import { SimDynamoDbExpressionPlaceholders } from "./sim-dynamodb-expression-placeholders.js";
|
|
4
5
|
/**
|
|
5
6
|
* The placeholders one request defines for its expressions.
|
|
@@ -12,12 +13,18 @@ import { SimDynamoDbExpressionPlaceholders } from "./sim-dynamodb-expression-pla
|
|
|
12
13
|
export class SimDynamoDbExpressionParameters {
|
|
13
14
|
names;
|
|
14
15
|
values;
|
|
16
|
+
/**
|
|
17
|
+
* The attribute names the request's expressions reach, gathered as they are
|
|
18
|
+
* read. Authorization asks for these as `dynamodb:Attributes`.
|
|
19
|
+
*/
|
|
20
|
+
attributes;
|
|
15
21
|
constructor(input) {
|
|
16
22
|
this.names = new SimDynamoDbExpressionPlaceholders({
|
|
17
23
|
parameterName: "ExpressionAttributeNames",
|
|
18
24
|
marker: "#",
|
|
19
25
|
entries: input.ExpressionAttributeNames,
|
|
20
26
|
});
|
|
27
|
+
this.attributes = new SimDynamoDbExpressionAttributes(this.names);
|
|
21
28
|
this.values = new SimDynamoDbExpressionPlaceholders({
|
|
22
29
|
parameterName: "ExpressionAttributeValues",
|
|
23
30
|
marker: ":",
|