@infra-blocks/aws-dynamodb 0.62.0 → 0.63.0-alpha.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.
@@ -28,15 +28,46 @@ export declare class AttributeNames {
28
28
  * Returns a substitution variable for the given attribute path.
29
29
  *
30
30
  * If the attribute path is seen for the first time by this object, a new substitution is generated,
31
- * assigned to the attribute path, and returned.
31
+ * it is assigned to the attribute path, and returned. If the attribute path was previously registered,
32
+ * then the associated substitution is returned instead.
32
33
  *
33
- * If the attribute path was previously seen, then the associated substitution is returned.
34
+ * The substitution is of the form "#attr<N>", where N is a counter starting at 1 and incremented
35
+ * each time a *new* path is seen. So the first substitution returned by this object will inevitably
36
+ * start with "#attr1".*
37
+ *
38
+ * The substitution's default algorithm goes like this:
39
+ * - Throw if the provided input is empty.
40
+ * - Split all path tokens sperated by dots ('.').
41
+ * - For each of them:
42
+ * - Throw if they are an empty string.
43
+ * - They are indexed if a pair of square brackets can be found ('[]'). *No parsing is done
44
+ * within the brackets*. So, even though "toto[ta[t]a]" is an invalid attribute path for DynamoDB,
45
+ * this function will let it slide. The corresponding expression will be rejected by DynamoDB at runtime
46
+ * mfk. Why would you even? Anyway, if the prefix to the opening bracket is empty, throw again.
47
+ * - Generate a corresponding substitution and append in result
48
+ * - Join result subsitutions with dots and return.
49
+ *
50
+ * If the attribute path is a nested item expression, such as "object.inner.stuff", then the
51
+ * function will return "#attr1.#attr2.#attr3" and have registered 3 paths for future use:
52
+ * "object", "inner", and "stuff".
53
+ *
54
+ * If the attribute path is an indexed item expression, such as "list[2]", then the function
55
+ * will return "#attr1[2]" and have registered one path for future use: "list".
56
+ *
57
+ * Every other attribute path is simply replaced by "#attr<N>" and stored as is for future use.
58
+ *
59
+ * If a user wishes to bypass all the above logic and simply register the path as is, such as
60
+ * could be the case if an attribute's name contains a dot, then the `literal` option can be set
61
+ * to true.
34
62
  *
35
63
  * @param attribute - The path of the attribute to substitute.
64
+ * @param options - The substitution option.
36
65
  *
37
66
  * @returns The substitution associated with the attribute path.
38
67
  */
39
- substitute(attribute: AttributePath): PathSubstitution;
68
+ substitute(attribute: AttributePath, options?: {
69
+ literal?: boolean;
70
+ }): PathSubstitution;
40
71
  /**
41
72
  * Returns a record where the keys are the substitutions generated by this object
42
73
  * and the values are the corresponding attribute paths they where generated for.
@@ -44,6 +75,6 @@ export declare class AttributeNames {
44
75
  * @returns A mapping of substitutions generated by this object, undefined if none were.
45
76
  */
46
77
  getSubstitutions(): Record<PathSubstitution, AttributePath> | undefined;
47
- private getAndSetNextSubstituteFor;
78
+ private getOrSetNextSubstituteFor;
48
79
  static create(): AttributeNames;
49
80
  }
@@ -26,29 +26,76 @@ class AttributeNames {
26
26
  constructor() {
27
27
  this.names = new Map();
28
28
  }
29
+ // TODO: the edge case where the path would be something like literal("hello.toto").otherField is still
30
+ // not covered.
29
31
  /**
30
32
  * Returns a substitution variable for the given attribute path.
31
33
  *
32
34
  * If the attribute path is seen for the first time by this object, a new substitution is generated,
33
- * assigned to the attribute path, and returned.
35
+ * it is assigned to the attribute path, and returned. If the attribute path was previously registered,
36
+ * then the associated substitution is returned instead.
34
37
  *
35
- * If the attribute path was previously seen, then the associated substitution is returned.
38
+ * The substitution is of the form "#attr<N>", where N is a counter starting at 1 and incremented
39
+ * each time a *new* path is seen. So the first substitution returned by this object will inevitably
40
+ * start with "#attr1".*
41
+ *
42
+ * The substitution's default algorithm goes like this:
43
+ * - Throw if the provided input is empty.
44
+ * - Split all path tokens sperated by dots ('.').
45
+ * - For each of them:
46
+ * - Throw if they are an empty string.
47
+ * - They are indexed if a pair of square brackets can be found ('[]'). *No parsing is done
48
+ * within the brackets*. So, even though "toto[ta[t]a]" is an invalid attribute path for DynamoDB,
49
+ * this function will let it slide. The corresponding expression will be rejected by DynamoDB at runtime
50
+ * mfk. Why would you even? Anyway, if the prefix to the opening bracket is empty, throw again.
51
+ * - Generate a corresponding substitution and append in result
52
+ * - Join result subsitutions with dots and return.
53
+ *
54
+ * If the attribute path is a nested item expression, such as "object.inner.stuff", then the
55
+ * function will return "#attr1.#attr2.#attr3" and have registered 3 paths for future use:
56
+ * "object", "inner", and "stuff".
57
+ *
58
+ * If the attribute path is an indexed item expression, such as "list[2]", then the function
59
+ * will return "#attr1[2]" and have registered one path for future use: "list".
60
+ *
61
+ * Every other attribute path is simply replaced by "#attr<N>" and stored as is for future use.
62
+ *
63
+ * If a user wishes to bypass all the above logic and simply register the path as is, such as
64
+ * could be the case if an attribute's name contains a dot, then the `literal` option can be set
65
+ * to true.
36
66
  *
37
67
  * @param attribute - The path of the attribute to substitute.
68
+ * @param options - The substitution option.
38
69
  *
39
70
  * @returns The substitution associated with the attribute path.
40
71
  */
41
- substitute(attribute) {
72
+ substitute(attribute, options) {
73
+ const { literal = false } = options || {};
42
74
  if (attribute.length === 0) {
43
75
  throw new Error("error substituting attribute: empty attribute path not allowed");
44
76
  }
45
- const pathTokens = attribute.split(".");
77
+ if (literal) {
78
+ return this.getOrSetNextSubstituteFor(attribute);
79
+ }
46
80
  const result = [];
47
- for (const token of pathTokens) {
81
+ for (const token of attribute.split(".")) {
48
82
  if (token.length === 0) {
49
83
  throw new Error(`error substituting attribute ${attribute}: empty path token not allowed`);
50
84
  }
51
- const substitute = this.names.get(token) ?? this.getAndSetNextSubstituteFor(token);
85
+ // If it's indexed.
86
+ const match = INDEX_REGEX.exec(token);
87
+ if (match != null) {
88
+ const indexedToken = token.slice(0, match.index);
89
+ if (indexedToken.length === 0) {
90
+ throw new Error(`error substituting attribute ${attribute}: empty path token not allowed`);
91
+ }
92
+ // #attrN substitution will map to the token before the index brackets.
93
+ const pathSubstitute = this.getOrSetNextSubstituteFor(indexedToken);
94
+ // The substitute will be of the form #attrN[<originalIndex>]
95
+ result.push(`${pathSubstitute}${match[1]}`);
96
+ continue;
97
+ }
98
+ const substitute = this.getOrSetNextSubstituteFor(token);
52
99
  result.push(substitute);
53
100
  }
54
101
  return result.join(".");
@@ -69,14 +116,21 @@ class AttributeNames {
69
116
  }
70
117
  return result;
71
118
  }
72
- getAndSetNextSubstituteFor(path) {
73
- const nextSubstitute = `#attr${this.names.size + 1}`;
74
- this.names.set(path, nextSubstitute);
75
- return nextSubstitute;
119
+ getOrSetNextSubstituteFor(path) {
120
+ const current = this.names.get(path);
121
+ if (current != null) {
122
+ return current;
123
+ }
124
+ const next = `#attr${this.names.size + 1}`;
125
+ this.names.set(path, next);
126
+ return next;
76
127
  }
77
128
  static create() {
78
129
  return new AttributeNames();
79
130
  }
80
131
  }
81
132
  exports.AttributeNames = AttributeNames;
133
+ // REGEX used to find a pair of matching brackets within an attribute path token.
134
+ // The expression starting with the opening bracket all the way to the end of the token is capture in group 1.
135
+ const INDEX_REGEX = /(\[.*\].*)$/;
82
136
  //# sourceMappingURL=names.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"names.js","sourceRoot":"","sources":["../../../../src/commands/attributes/names.ts"],"names":[],"mappings":";;;AAOA,yJAAyJ;AACzJ,kEAAkE;AAClE;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAa,cAAc;IACR,KAAK,CAAuC;IAE7D;QACE,IAAI,CAAC,KAAK,GAAG,IAAI,GAAG,EAAmC,CAAC;IAC1D,CAAC;IAED;;;;;;;;;;;OAWG;IACH,UAAU,CAAC,SAAwB;QACjC,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC3B,MAAM,IAAI,KAAK,CACb,gEAAgE,CACjE,CAAC;QACJ,CAAC;QAED,MAAM,UAAU,GAAG,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACxC,MAAM,MAAM,GAAG,EAAE,CAAC;QAClB,KAAK,MAAM,KAAK,IAAI,UAAU,EAAE,CAAC;YAC/B,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACvB,MAAM,IAAI,KAAK,CACb,gCAAgC,SAAS,gCAAgC,CAC1E,CAAC;YACJ,CAAC;YACD,MAAM,UAAU,GACd,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,0BAA0B,CAAC,KAAK,CAAC,CAAC;YAClE,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC1B,CAAC;QACD,OAAO,MAAM,CAAC,IAAI,CAAC,GAAG,CAAqB,CAAC;IAC9C,CAAC;IAED;;;;;OAKG;IACH,gBAAgB;QACd,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YAC1B,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,MAAM,MAAM,GAA4C,EAAE,CAAC;QAC3D,KAAK,MAAM,CAAC,SAAS,EAAE,UAAU,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,CAAC;YAC3D,MAAM,CAAC,UAAU,CAAC,GAAG,SAAS,CAAC;QACjC,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IAEO,0BAA0B,CAAC,IAAmB;QACpD,MAAM,cAAc,GAAG,QAAQ,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,EAAsB,CAAC;QACzE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC;QACrC,OAAO,cAAc,CAAC;IACxB,CAAC;IAED,MAAM,CAAC,MAAM;QACX,OAAO,IAAI,cAAc,EAAE,CAAC;IAC9B,CAAC;CACF;AApED,wCAoEC"}
1
+ {"version":3,"file":"names.js","sourceRoot":"","sources":["../../../../src/commands/attributes/names.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,3 @@
1
1
  export { type ImplicitOperand, type Operand, operand, type RawOperand, } from "./operand.js";
2
- export { type ImplicitPath, Path, path, type RawPath } from "./path.js";
2
+ export { type ImplicitPath, literal, Path, path, type RawPath, } from "./path.js";
3
3
  export { type ImplicitValue, type RawValue, Value, value, } from "./value.js";
@@ -1,9 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.value = exports.Value = exports.path = exports.Path = exports.operand = void 0;
3
+ exports.value = exports.Value = exports.path = exports.Path = exports.literal = exports.operand = void 0;
4
4
  var operand_js_1 = require("./operand.js");
5
5
  Object.defineProperty(exports, "operand", { enumerable: true, get: function () { return operand_js_1.operand; } });
6
6
  var path_js_1 = require("./path.js");
7
+ Object.defineProperty(exports, "literal", { enumerable: true, get: function () { return path_js_1.literal; } });
7
8
  Object.defineProperty(exports, "Path", { enumerable: true, get: function () { return path_js_1.Path; } });
8
9
  Object.defineProperty(exports, "path", { enumerable: true, get: function () { return path_js_1.path; } });
9
10
  var value_js_1 = require("./value.js");
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/commands/expressions/operands/index.ts"],"names":[],"mappings":";;;AAAA,2CAKsB;AAFpB,qGAAA,OAAO,OAAA;AAGT,qCAAwE;AAA5C,+FAAA,IAAI,OAAA;AAAE,+FAAA,IAAI,OAAA;AACtC,uCAKoB;AAFlB,iGAAA,KAAK,OAAA;AACL,iGAAA,KAAK,OAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/commands/expressions/operands/index.ts"],"names":[],"mappings":";;;AAAA,2CAKsB;AAFpB,qGAAA,OAAO,OAAA;AAGT,qCAMmB;AAJjB,kGAAA,OAAO,OAAA;AACP,+FAAA,IAAI,OAAA;AACJ,+FAAA,IAAI,OAAA;AAGN,uCAKoB;AAFlB,iGAAA,KAAK,OAAA;AACL,iGAAA,KAAK,OAAA"}
@@ -1,4 +1,4 @@
1
- import { type AttributePath } from "../../../types.js";
1
+ import { type AttributeName, type AttributePath } from "../../../types.js";
2
2
  import type { AttributeNames } from "../../attributes/names.js";
3
3
  import type { IOperand } from "./operand.js";
4
4
  /**
@@ -31,6 +31,7 @@ export type RawPath = AttributePath | Path;
31
31
  */
32
32
  export declare class Path implements IOperand {
33
33
  private readonly path;
34
+ private readonly literal;
34
35
  private constructor();
35
36
  substitute(params: {
36
37
  names: AttributeNames;
@@ -38,7 +39,9 @@ export declare class Path implements IOperand {
38
39
  /**
39
40
  * @private
40
41
  */
41
- static from(path: AttributePath): Path;
42
+ static from(path: AttributePath, options?: {
43
+ literal?: true;
44
+ }): Path;
42
45
  /**
43
46
  * Turns {@link RawPath} path into a {@link Path} instance.
44
47
  *
@@ -46,22 +49,49 @@ export declare class Path implements IOperand {
46
49
  * Otherwise, a new {@link Path} instance will be created from the provided
47
50
  * argument.
48
51
  *
49
- * @param loosePath - The path to return as is or convert to a {@link Path} instance.
52
+ * @param raw - The path to return as is or convert to a {@link Path} instance.
50
53
  *
51
54
  * @returns The normalized {@link Path} instance.
52
55
  *
53
56
  * @private
54
57
  */
55
- static normalize(loosePath: RawPath): Path;
58
+ static normalize(raw: RawPath): Path;
56
59
  }
57
60
  /**
58
61
  * Factory function to create a {@link Path}.
59
62
  *
63
+ * Client code can use this function to disambiguate the expression.
64
+ * Normally, strings are treated as paths by default in expression constructs,
65
+ * but it can be clearer to write something like `set(path("toto"), path("tata"))`
66
+ * instead of `set("toto", "tata")`, for example.
67
+ *
60
68
  * @param path - The path of the attribute this operand represents.
61
69
  *
62
70
  * @returns A new {@link Path} instance for the provided path.
63
71
  */
64
72
  export declare function path(path: AttributePath): Path;
73
+ /**
74
+ * Factory function to create a literal {@link Path}.
75
+ *
76
+ * A literal path does not get parsed before being stringified into an expression
77
+ * attribute name. It is simply used as is. For example, if the name of
78
+ * an attribute contains a dot, such as "not.a.good.idea", then the client code
79
+ * *must* use a {@link literal} to translate it as the following attribute names:
80
+ * {
81
+ * "#attr1": "not.a.good.idea"
82
+ * }
83
+ * Instead of the default of:
84
+ * {
85
+ * "#attr1": "not",
86
+ * "#attr2": "a",
87
+ * "#attr3": "good",
88
+ * "#attr4": "idea"
89
+ * }
90
+ *
91
+ * @param name - The attribute name, taken literally.
92
+ * @returns A new literal {@link Path} instance for the provided name.
93
+ */
94
+ export declare function literal(name: AttributeName): Path;
65
95
  /**
66
96
  * A type guard to assess if something is a {@link RawPath}.
67
97
  *
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Path = void 0;
4
4
  exports.path = path;
5
+ exports.literal = literal;
5
6
  exports.isRawPath = isRawPath;
6
7
  const types_js_1 = require("../../../types.js");
7
8
  /**
@@ -13,18 +14,22 @@ const types_js_1 = require("../../../types.js");
13
14
  */
14
15
  class Path {
15
16
  path;
16
- constructor(path) {
17
+ literal;
18
+ constructor(params) {
19
+ const { path, literal } = params;
17
20
  this.path = path;
21
+ this.literal = literal;
18
22
  }
19
23
  substitute(params) {
20
24
  const { names } = params;
21
- return names.substitute(this.path);
25
+ return names.substitute(this.path, { literal: this.literal });
22
26
  }
23
27
  /**
24
28
  * @private
25
29
  */
26
- static from(path) {
27
- return new Path(path);
30
+ static from(path, options) {
31
+ const { literal = false } = options ?? {};
32
+ return new Path({ path, literal });
28
33
  }
29
34
  /**
30
35
  * Turns {@link RawPath} path into a {@link Path} instance.
@@ -33,23 +38,28 @@ class Path {
33
38
  * Otherwise, a new {@link Path} instance will be created from the provided
34
39
  * argument.
35
40
  *
36
- * @param loosePath - The path to return as is or convert to a {@link Path} instance.
41
+ * @param raw - The path to return as is or convert to a {@link Path} instance.
37
42
  *
38
43
  * @returns The normalized {@link Path} instance.
39
44
  *
40
45
  * @private
41
46
  */
42
- static normalize(loosePath) {
43
- if (loosePath instanceof Path) {
44
- return loosePath;
47
+ static normalize(raw) {
48
+ if (raw instanceof Path) {
49
+ return raw;
45
50
  }
46
- return Path.from(loosePath);
51
+ return Path.from(raw);
47
52
  }
48
53
  }
49
54
  exports.Path = Path;
50
55
  /**
51
56
  * Factory function to create a {@link Path}.
52
57
  *
58
+ * Client code can use this function to disambiguate the expression.
59
+ * Normally, strings are treated as paths by default in expression constructs,
60
+ * but it can be clearer to write something like `set(path("toto"), path("tata"))`
61
+ * instead of `set("toto", "tata")`, for example.
62
+ *
53
63
  * @param path - The path of the attribute this operand represents.
54
64
  *
55
65
  * @returns A new {@link Path} instance for the provided path.
@@ -57,6 +67,30 @@ exports.Path = Path;
57
67
  function path(path) {
58
68
  return Path.from(path);
59
69
  }
70
+ /**
71
+ * Factory function to create a literal {@link Path}.
72
+ *
73
+ * A literal path does not get parsed before being stringified into an expression
74
+ * attribute name. It is simply used as is. For example, if the name of
75
+ * an attribute contains a dot, such as "not.a.good.idea", then the client code
76
+ * *must* use a {@link literal} to translate it as the following attribute names:
77
+ * {
78
+ * "#attr1": "not.a.good.idea"
79
+ * }
80
+ * Instead of the default of:
81
+ * {
82
+ * "#attr1": "not",
83
+ * "#attr2": "a",
84
+ * "#attr3": "good",
85
+ * "#attr4": "idea"
86
+ * }
87
+ *
88
+ * @param name - The attribute name, taken literally.
89
+ * @returns A new literal {@link Path} instance for the provided name.
90
+ */
91
+ function literal(name) {
92
+ return Path.from(name, { literal: true });
93
+ }
60
94
  /**
61
95
  * A type guard to assess if something is a {@link RawPath}.
62
96
  *
@@ -1 +1 @@
1
- {"version":3,"file":"path.js","sourceRoot":"","sources":["../../../../../src/commands/expressions/operands/path.ts"],"names":[],"mappings":";;;AAiFA,oBAEC;AASD,8BAEC;AA9FD,gDAAuE;AA2BvE;;;;;;GAMG;AACH,MAAa,IAAI;IACE,IAAI,CAAgB;IAErC,YAAoB,IAAmB;QACrC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;IAED,UAAU,CAAC,MAAiC;QAC1C,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,CAAC;QACzB,OAAO,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACrC,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,IAAI,CAAC,IAAmB;QAC7B,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC;IACxB,CAAC;IAED;;;;;;;;;;;;OAYG;IACH,MAAM,CAAC,SAAS,CAAC,SAAkB;QACjC,IAAI,SAAS,YAAY,IAAI,EAAE,CAAC;YAC9B,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,OAAO,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAC9B,CAAC;CACF;AAtCD,oBAsCC;AAED;;;;;;GAMG;AACH,SAAgB,IAAI,CAAC,IAAmB;IACtC,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACzB,CAAC;AAED;;;;;;GAMG;AACH,SAAgB,SAAS,CAAC,OAAgB;IACxC,OAAO,cAAc,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,CAAC;AACpD,CAAC;AAED,SAAS,cAAc,CAAC,OAAgB;IACtC,OAAO,IAAA,yBAAc,EAAC,OAAO,CAAC,CAAC;AACjC,CAAC;AAED,SAAS,MAAM,CAAC,OAAgB;IAC9B,OAAO,OAAO,YAAY,IAAI,CAAC;AACjC,CAAC"}
1
+ {"version":3,"file":"path.js","sourceRoot":"","sources":["../../../../../src/commands/expressions/operands/path.ts"],"names":[],"mappings":";;;AA8FA,oBAEC;AAuBD,0BAEC;AASD,8BAEC;AApID,gDAI2B;AA2B3B;;;;;;GAMG;AACH,MAAa,IAAI;IACE,IAAI,CAAgB;IACpB,OAAO,CAAU;IAElC,YAAoB,MAAiD;QACnE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,MAAM,CAAC;QACjC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;IAED,UAAU,CAAC,MAAiC;QAC1C,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,CAAC;QACzB,OAAO,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;IAChE,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,IAAI,CAAC,IAAmB,EAAE,OAA4B;QAC3D,MAAM,EAAE,OAAO,GAAG,KAAK,EAAE,GAAG,OAAO,IAAI,EAAE,CAAC;QAC1C,OAAO,IAAI,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;IACrC,CAAC;IAED;;;;;;;;;;;;OAYG;IACH,MAAM,CAAC,SAAS,CAAC,GAAY;QAC3B,IAAI,GAAG,YAAY,IAAI,EAAE,CAAC;YACxB,OAAO,GAAG,CAAC;QACb,CAAC;QACD,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACxB,CAAC;CACF;AA1CD,oBA0CC;AAED;;;;;;;;;;;GAWG;AACH,SAAgB,IAAI,CAAC,IAAmB;IACtC,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACzB,CAAC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,SAAgB,OAAO,CAAC,IAAmB;IACzC,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;AAC5C,CAAC;AAED;;;;;;GAMG;AACH,SAAgB,SAAS,CAAC,OAAgB;IACxC,OAAO,cAAc,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,CAAC;AACpD,CAAC;AAED,SAAS,cAAc,CAAC,OAAgB;IACtC,OAAO,IAAA,yBAAc,EAAC,OAAO,CAAC,CAAC;AACjC,CAAC;AAED,SAAS,MAAM,CAAC,OAAgB;IAC9B,OAAO,OAAO,YAAY,IAAI,CAAC;AACjC,CAAC"}
@@ -1,4 +1,3 @@
1
- export * from "./attributes/index.js";
2
1
  export type { CommandInput, CommandOutput } from "./base.js";
3
2
  export type { DynamoDbClientCommand } from "./command.js";
4
3
  export { CreateTable } from "./create-table.js";
@@ -15,7 +15,6 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  exports.WriteTransaction = exports.UpdateTimeToLive = exports.UpdateItem = exports.Query = exports.PutItem = exports.GetItem = exports.DeleteTable = exports.DeleteItem = exports.CreateTable = void 0;
18
- __exportStar(require("./attributes/index.js"), exports);
19
18
  var create_table_js_1 = require("./create-table.js");
20
19
  Object.defineProperty(exports, "CreateTable", { enumerable: true, get: function () { return create_table_js_1.CreateTable; } });
21
20
  var delete_item_js_1 = require("./delete-item.js");
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,wDAAsC;AAGtC,qDAAgD;AAAvC,8GAAA,WAAW,OAAA;AACpB,mDAA8C;AAArC,4GAAA,UAAU,OAAA;AACnB,qDAAgD;AAAvC,8GAAA,WAAW,OAAA;AACpB,yDAAuC;AACvC,6CAAwC;AAA/B,sGAAA,OAAO,OAAA;AA0BhB,6CAAwC;AAA/B,sGAAA,OAAO,OAAA;AAChB,uCAAmC;AAA1B,iGAAA,KAAK,OAAA;AACd,mDAA8C;AAArC,4GAAA,UAAU,OAAA;AACnB,mEAA4D;AAAnD,0HAAA,gBAAgB,OAAA;AACzB,+DAA0D;AAAjD,wHAAA,gBAAgB,OAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAEA,qDAAgD;AAAvC,8GAAA,WAAW,OAAA;AACpB,mDAA8C;AAArC,4GAAA,UAAU,OAAA;AACnB,qDAAgD;AAAvC,8GAAA,WAAW,OAAA;AACpB,yDAAuC;AACvC,6CAAwC;AAA/B,sGAAA,OAAO,OAAA;AA0BhB,6CAAwC;AAA/B,sGAAA,OAAO,OAAA;AAChB,uCAAmC;AAA1B,iGAAA,KAAK,OAAA;AACd,mDAA8C;AAArC,4GAAA,UAAU,OAAA;AACnB,mEAA4D;AAAnD,0HAAA,gBAAgB,OAAA;AACzB,+DAA0D;AAAjD,wHAAA,gBAAgB,OAAA"}
@@ -28,15 +28,46 @@ export declare class AttributeNames {
28
28
  * Returns a substitution variable for the given attribute path.
29
29
  *
30
30
  * If the attribute path is seen for the first time by this object, a new substitution is generated,
31
- * assigned to the attribute path, and returned.
31
+ * it is assigned to the attribute path, and returned. If the attribute path was previously registered,
32
+ * then the associated substitution is returned instead.
32
33
  *
33
- * If the attribute path was previously seen, then the associated substitution is returned.
34
+ * The substitution is of the form "#attr<N>", where N is a counter starting at 1 and incremented
35
+ * each time a *new* path is seen. So the first substitution returned by this object will inevitably
36
+ * start with "#attr1".*
37
+ *
38
+ * The substitution's default algorithm goes like this:
39
+ * - Throw if the provided input is empty.
40
+ * - Split all path tokens sperated by dots ('.').
41
+ * - For each of them:
42
+ * - Throw if they are an empty string.
43
+ * - They are indexed if a pair of square brackets can be found ('[]'). *No parsing is done
44
+ * within the brackets*. So, even though "toto[ta[t]a]" is an invalid attribute path for DynamoDB,
45
+ * this function will let it slide. The corresponding expression will be rejected by DynamoDB at runtime
46
+ * mfk. Why would you even? Anyway, if the prefix to the opening bracket is empty, throw again.
47
+ * - Generate a corresponding substitution and append in result
48
+ * - Join result subsitutions with dots and return.
49
+ *
50
+ * If the attribute path is a nested item expression, such as "object.inner.stuff", then the
51
+ * function will return "#attr1.#attr2.#attr3" and have registered 3 paths for future use:
52
+ * "object", "inner", and "stuff".
53
+ *
54
+ * If the attribute path is an indexed item expression, such as "list[2]", then the function
55
+ * will return "#attr1[2]" and have registered one path for future use: "list".
56
+ *
57
+ * Every other attribute path is simply replaced by "#attr<N>" and stored as is for future use.
58
+ *
59
+ * If a user wishes to bypass all the above logic and simply register the path as is, such as
60
+ * could be the case if an attribute's name contains a dot, then the `literal` option can be set
61
+ * to true.
34
62
  *
35
63
  * @param attribute - The path of the attribute to substitute.
64
+ * @param options - The substitution option.
36
65
  *
37
66
  * @returns The substitution associated with the attribute path.
38
67
  */
39
- substitute(attribute: AttributePath): PathSubstitution;
68
+ substitute(attribute: AttributePath, options?: {
69
+ literal?: boolean;
70
+ }): PathSubstitution;
40
71
  /**
41
72
  * Returns a record where the keys are the substitutions generated by this object
42
73
  * and the values are the corresponding attribute paths they where generated for.
@@ -44,6 +75,6 @@ export declare class AttributeNames {
44
75
  * @returns A mapping of substitutions generated by this object, undefined if none were.
45
76
  */
46
77
  getSubstitutions(): Record<PathSubstitution, AttributePath> | undefined;
47
- private getAndSetNextSubstituteFor;
78
+ private getOrSetNextSubstituteFor;
48
79
  static create(): AttributeNames;
49
80
  }
@@ -23,29 +23,76 @@ export class AttributeNames {
23
23
  constructor() {
24
24
  this.names = new Map();
25
25
  }
26
+ // TODO: the edge case where the path would be something like literal("hello.toto").otherField is still
27
+ // not covered.
26
28
  /**
27
29
  * Returns a substitution variable for the given attribute path.
28
30
  *
29
31
  * If the attribute path is seen for the first time by this object, a new substitution is generated,
30
- * assigned to the attribute path, and returned.
32
+ * it is assigned to the attribute path, and returned. If the attribute path was previously registered,
33
+ * then the associated substitution is returned instead.
31
34
  *
32
- * If the attribute path was previously seen, then the associated substitution is returned.
35
+ * The substitution is of the form "#attr<N>", where N is a counter starting at 1 and incremented
36
+ * each time a *new* path is seen. So the first substitution returned by this object will inevitably
37
+ * start with "#attr1".*
38
+ *
39
+ * The substitution's default algorithm goes like this:
40
+ * - Throw if the provided input is empty.
41
+ * - Split all path tokens sperated by dots ('.').
42
+ * - For each of them:
43
+ * - Throw if they are an empty string.
44
+ * - They are indexed if a pair of square brackets can be found ('[]'). *No parsing is done
45
+ * within the brackets*. So, even though "toto[ta[t]a]" is an invalid attribute path for DynamoDB,
46
+ * this function will let it slide. The corresponding expression will be rejected by DynamoDB at runtime
47
+ * mfk. Why would you even? Anyway, if the prefix to the opening bracket is empty, throw again.
48
+ * - Generate a corresponding substitution and append in result
49
+ * - Join result subsitutions with dots and return.
50
+ *
51
+ * If the attribute path is a nested item expression, such as "object.inner.stuff", then the
52
+ * function will return "#attr1.#attr2.#attr3" and have registered 3 paths for future use:
53
+ * "object", "inner", and "stuff".
54
+ *
55
+ * If the attribute path is an indexed item expression, such as "list[2]", then the function
56
+ * will return "#attr1[2]" and have registered one path for future use: "list".
57
+ *
58
+ * Every other attribute path is simply replaced by "#attr<N>" and stored as is for future use.
59
+ *
60
+ * If a user wishes to bypass all the above logic and simply register the path as is, such as
61
+ * could be the case if an attribute's name contains a dot, then the `literal` option can be set
62
+ * to true.
33
63
  *
34
64
  * @param attribute - The path of the attribute to substitute.
65
+ * @param options - The substitution option.
35
66
  *
36
67
  * @returns The substitution associated with the attribute path.
37
68
  */
38
- substitute(attribute) {
69
+ substitute(attribute, options) {
70
+ const { literal = false } = options || {};
39
71
  if (attribute.length === 0) {
40
72
  throw new Error("error substituting attribute: empty attribute path not allowed");
41
73
  }
42
- const pathTokens = attribute.split(".");
74
+ if (literal) {
75
+ return this.getOrSetNextSubstituteFor(attribute);
76
+ }
43
77
  const result = [];
44
- for (const token of pathTokens) {
78
+ for (const token of attribute.split(".")) {
45
79
  if (token.length === 0) {
46
80
  throw new Error(`error substituting attribute ${attribute}: empty path token not allowed`);
47
81
  }
48
- const substitute = this.names.get(token) ?? this.getAndSetNextSubstituteFor(token);
82
+ // If it's indexed.
83
+ const match = INDEX_REGEX.exec(token);
84
+ if (match != null) {
85
+ const indexedToken = token.slice(0, match.index);
86
+ if (indexedToken.length === 0) {
87
+ throw new Error(`error substituting attribute ${attribute}: empty path token not allowed`);
88
+ }
89
+ // #attrN substitution will map to the token before the index brackets.
90
+ const pathSubstitute = this.getOrSetNextSubstituteFor(indexedToken);
91
+ // The substitute will be of the form #attrN[<originalIndex>]
92
+ result.push(`${pathSubstitute}${match[1]}`);
93
+ continue;
94
+ }
95
+ const substitute = this.getOrSetNextSubstituteFor(token);
49
96
  result.push(substitute);
50
97
  }
51
98
  return result.join(".");
@@ -66,13 +113,20 @@ export class AttributeNames {
66
113
  }
67
114
  return result;
68
115
  }
69
- getAndSetNextSubstituteFor(path) {
70
- const nextSubstitute = `#attr${this.names.size + 1}`;
71
- this.names.set(path, nextSubstitute);
72
- return nextSubstitute;
116
+ getOrSetNextSubstituteFor(path) {
117
+ const current = this.names.get(path);
118
+ if (current != null) {
119
+ return current;
120
+ }
121
+ const next = `#attr${this.names.size + 1}`;
122
+ this.names.set(path, next);
123
+ return next;
73
124
  }
74
125
  static create() {
75
126
  return new AttributeNames();
76
127
  }
77
128
  }
129
+ // REGEX used to find a pair of matching brackets within an attribute path token.
130
+ // The expression starting with the opening bracket all the way to the end of the token is capture in group 1.
131
+ const INDEX_REGEX = /(\[.*\].*)$/;
78
132
  //# sourceMappingURL=names.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"names.js","sourceRoot":"","sources":["../../../../src/commands/attributes/names.ts"],"names":[],"mappings":"AAOA,yJAAyJ;AACzJ,kEAAkE;AAClE;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,OAAO,cAAc;IACR,KAAK,CAAuC;IAE7D;QACE,IAAI,CAAC,KAAK,GAAG,IAAI,GAAG,EAAmC,CAAC;IAC1D,CAAC;IAED;;;;;;;;;;;OAWG;IACH,UAAU,CAAC,SAAwB;QACjC,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC3B,MAAM,IAAI,KAAK,CACb,gEAAgE,CACjE,CAAC;QACJ,CAAC;QAED,MAAM,UAAU,GAAG,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACxC,MAAM,MAAM,GAAG,EAAE,CAAC;QAClB,KAAK,MAAM,KAAK,IAAI,UAAU,EAAE,CAAC;YAC/B,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACvB,MAAM,IAAI,KAAK,CACb,gCAAgC,SAAS,gCAAgC,CAC1E,CAAC;YACJ,CAAC;YACD,MAAM,UAAU,GACd,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,0BAA0B,CAAC,KAAK,CAAC,CAAC;YAClE,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC1B,CAAC;QACD,OAAO,MAAM,CAAC,IAAI,CAAC,GAAG,CAAqB,CAAC;IAC9C,CAAC;IAED;;;;;OAKG;IACH,gBAAgB;QACd,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YAC1B,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,MAAM,MAAM,GAA4C,EAAE,CAAC;QAC3D,KAAK,MAAM,CAAC,SAAS,EAAE,UAAU,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,CAAC;YAC3D,MAAM,CAAC,UAAU,CAAC,GAAG,SAAS,CAAC;QACjC,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IAEO,0BAA0B,CAAC,IAAmB;QACpD,MAAM,cAAc,GAAG,QAAQ,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,EAAsB,CAAC;QACzE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC;QACrC,OAAO,cAAc,CAAC;IACxB,CAAC;IAED,MAAM,CAAC,MAAM;QACX,OAAO,IAAI,cAAc,EAAE,CAAC;IAC9B,CAAC;CACF"}
1
+ {"version":3,"file":"names.js","sourceRoot":"","sources":["../../../../src/commands/attributes/names.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,3 @@
1
1
  export { type ImplicitOperand, type Operand, operand, type RawOperand, } from "./operand.js";
2
- export { type ImplicitPath, Path, path, type RawPath } from "./path.js";
2
+ export { type ImplicitPath, literal, Path, path, type RawPath, } from "./path.js";
3
3
  export { type ImplicitValue, type RawValue, Value, value, } from "./value.js";
@@ -1,4 +1,4 @@
1
1
  export { operand, } from "./operand.js";
2
- export { Path, path } from "./path.js";
2
+ export { literal, Path, path, } from "./path.js";
3
3
  export { Value, value, } from "./value.js";
4
4
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/commands/expressions/operands/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,OAAO,GAER,MAAM,cAAc,CAAC;AACtB,OAAO,EAAqB,IAAI,EAAE,IAAI,EAAgB,MAAM,WAAW,CAAC;AACxE,OAAO,EAGL,KAAK,EACL,KAAK,GACN,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/commands/expressions/operands/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,OAAO,GAER,MAAM,cAAc,CAAC;AACtB,OAAO,EAEL,OAAO,EACP,IAAI,EACJ,IAAI,GAEL,MAAM,WAAW,CAAC;AACnB,OAAO,EAGL,KAAK,EACL,KAAK,GACN,MAAM,YAAY,CAAC"}
@@ -1,4 +1,4 @@
1
- import { type AttributePath } from "../../../types.js";
1
+ import { type AttributeName, type AttributePath } from "../../../types.js";
2
2
  import type { AttributeNames } from "../../attributes/names.js";
3
3
  import type { IOperand } from "./operand.js";
4
4
  /**
@@ -31,6 +31,7 @@ export type RawPath = AttributePath | Path;
31
31
  */
32
32
  export declare class Path implements IOperand {
33
33
  private readonly path;
34
+ private readonly literal;
34
35
  private constructor();
35
36
  substitute(params: {
36
37
  names: AttributeNames;
@@ -38,7 +39,9 @@ export declare class Path implements IOperand {
38
39
  /**
39
40
  * @private
40
41
  */
41
- static from(path: AttributePath): Path;
42
+ static from(path: AttributePath, options?: {
43
+ literal?: true;
44
+ }): Path;
42
45
  /**
43
46
  * Turns {@link RawPath} path into a {@link Path} instance.
44
47
  *
@@ -46,22 +49,49 @@ export declare class Path implements IOperand {
46
49
  * Otherwise, a new {@link Path} instance will be created from the provided
47
50
  * argument.
48
51
  *
49
- * @param loosePath - The path to return as is or convert to a {@link Path} instance.
52
+ * @param raw - The path to return as is or convert to a {@link Path} instance.
50
53
  *
51
54
  * @returns The normalized {@link Path} instance.
52
55
  *
53
56
  * @private
54
57
  */
55
- static normalize(loosePath: RawPath): Path;
58
+ static normalize(raw: RawPath): Path;
56
59
  }
57
60
  /**
58
61
  * Factory function to create a {@link Path}.
59
62
  *
63
+ * Client code can use this function to disambiguate the expression.
64
+ * Normally, strings are treated as paths by default in expression constructs,
65
+ * but it can be clearer to write something like `set(path("toto"), path("tata"))`
66
+ * instead of `set("toto", "tata")`, for example.
67
+ *
60
68
  * @param path - The path of the attribute this operand represents.
61
69
  *
62
70
  * @returns A new {@link Path} instance for the provided path.
63
71
  */
64
72
  export declare function path(path: AttributePath): Path;
73
+ /**
74
+ * Factory function to create a literal {@link Path}.
75
+ *
76
+ * A literal path does not get parsed before being stringified into an expression
77
+ * attribute name. It is simply used as is. For example, if the name of
78
+ * an attribute contains a dot, such as "not.a.good.idea", then the client code
79
+ * *must* use a {@link literal} to translate it as the following attribute names:
80
+ * {
81
+ * "#attr1": "not.a.good.idea"
82
+ * }
83
+ * Instead of the default of:
84
+ * {
85
+ * "#attr1": "not",
86
+ * "#attr2": "a",
87
+ * "#attr3": "good",
88
+ * "#attr4": "idea"
89
+ * }
90
+ *
91
+ * @param name - The attribute name, taken literally.
92
+ * @returns A new literal {@link Path} instance for the provided name.
93
+ */
94
+ export declare function literal(name: AttributeName): Path;
65
95
  /**
66
96
  * A type guard to assess if something is a {@link RawPath}.
67
97
  *
@@ -1,4 +1,4 @@
1
- import { isNativeString } from "../../../types.js";
1
+ import { isNativeString, } from "../../../types.js";
2
2
  /**
3
3
  * Represents an attribute path operand in an expression.
4
4
  *
@@ -8,18 +8,22 @@ import { isNativeString } from "../../../types.js";
8
8
  */
9
9
  export class Path {
10
10
  path;
11
- constructor(path) {
11
+ literal;
12
+ constructor(params) {
13
+ const { path, literal } = params;
12
14
  this.path = path;
15
+ this.literal = literal;
13
16
  }
14
17
  substitute(params) {
15
18
  const { names } = params;
16
- return names.substitute(this.path);
19
+ return names.substitute(this.path, { literal: this.literal });
17
20
  }
18
21
  /**
19
22
  * @private
20
23
  */
21
- static from(path) {
22
- return new Path(path);
24
+ static from(path, options) {
25
+ const { literal = false } = options ?? {};
26
+ return new Path({ path, literal });
23
27
  }
24
28
  /**
25
29
  * Turns {@link RawPath} path into a {@link Path} instance.
@@ -28,22 +32,27 @@ export class Path {
28
32
  * Otherwise, a new {@link Path} instance will be created from the provided
29
33
  * argument.
30
34
  *
31
- * @param loosePath - The path to return as is or convert to a {@link Path} instance.
35
+ * @param raw - The path to return as is or convert to a {@link Path} instance.
32
36
  *
33
37
  * @returns The normalized {@link Path} instance.
34
38
  *
35
39
  * @private
36
40
  */
37
- static normalize(loosePath) {
38
- if (loosePath instanceof Path) {
39
- return loosePath;
41
+ static normalize(raw) {
42
+ if (raw instanceof Path) {
43
+ return raw;
40
44
  }
41
- return Path.from(loosePath);
45
+ return Path.from(raw);
42
46
  }
43
47
  }
44
48
  /**
45
49
  * Factory function to create a {@link Path}.
46
50
  *
51
+ * Client code can use this function to disambiguate the expression.
52
+ * Normally, strings are treated as paths by default in expression constructs,
53
+ * but it can be clearer to write something like `set(path("toto"), path("tata"))`
54
+ * instead of `set("toto", "tata")`, for example.
55
+ *
47
56
  * @param path - The path of the attribute this operand represents.
48
57
  *
49
58
  * @returns A new {@link Path} instance for the provided path.
@@ -51,6 +60,30 @@ export class Path {
51
60
  export function path(path) {
52
61
  return Path.from(path);
53
62
  }
63
+ /**
64
+ * Factory function to create a literal {@link Path}.
65
+ *
66
+ * A literal path does not get parsed before being stringified into an expression
67
+ * attribute name. It is simply used as is. For example, if the name of
68
+ * an attribute contains a dot, such as "not.a.good.idea", then the client code
69
+ * *must* use a {@link literal} to translate it as the following attribute names:
70
+ * {
71
+ * "#attr1": "not.a.good.idea"
72
+ * }
73
+ * Instead of the default of:
74
+ * {
75
+ * "#attr1": "not",
76
+ * "#attr2": "a",
77
+ * "#attr3": "good",
78
+ * "#attr4": "idea"
79
+ * }
80
+ *
81
+ * @param name - The attribute name, taken literally.
82
+ * @returns A new literal {@link Path} instance for the provided name.
83
+ */
84
+ export function literal(name) {
85
+ return Path.from(name, { literal: true });
86
+ }
54
87
  /**
55
88
  * A type guard to assess if something is a {@link RawPath}.
56
89
  *
@@ -1 +1 @@
1
- {"version":3,"file":"path.js","sourceRoot":"","sources":["../../../../../src/commands/expressions/operands/path.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,cAAc,EAAE,MAAM,mBAAmB,CAAC;AA2BvE;;;;;;GAMG;AACH,MAAM,OAAO,IAAI;IACE,IAAI,CAAgB;IAErC,YAAoB,IAAmB;QACrC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;IAED,UAAU,CAAC,MAAiC;QAC1C,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,CAAC;QACzB,OAAO,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACrC,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,IAAI,CAAC,IAAmB;QAC7B,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC;IACxB,CAAC;IAED;;;;;;;;;;;;OAYG;IACH,MAAM,CAAC,SAAS,CAAC,SAAkB;QACjC,IAAI,SAAS,YAAY,IAAI,EAAE,CAAC;YAC9B,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,OAAO,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAC9B,CAAC;CACF;AAED;;;;;;GAMG;AACH,MAAM,UAAU,IAAI,CAAC,IAAmB;IACtC,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACzB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,SAAS,CAAC,OAAgB;IACxC,OAAO,cAAc,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,CAAC;AACpD,CAAC;AAED,SAAS,cAAc,CAAC,OAAgB;IACtC,OAAO,cAAc,CAAC,OAAO,CAAC,CAAC;AACjC,CAAC;AAED,SAAS,MAAM,CAAC,OAAgB;IAC9B,OAAO,OAAO,YAAY,IAAI,CAAC;AACjC,CAAC"}
1
+ {"version":3,"file":"path.js","sourceRoot":"","sources":["../../../../../src/commands/expressions/operands/path.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,cAAc,GACf,MAAM,mBAAmB,CAAC;AA2B3B;;;;;;GAMG;AACH,MAAM,OAAO,IAAI;IACE,IAAI,CAAgB;IACpB,OAAO,CAAU;IAElC,YAAoB,MAAiD;QACnE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,MAAM,CAAC;QACjC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;IAED,UAAU,CAAC,MAAiC;QAC1C,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,CAAC;QACzB,OAAO,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;IAChE,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,IAAI,CAAC,IAAmB,EAAE,OAA4B;QAC3D,MAAM,EAAE,OAAO,GAAG,KAAK,EAAE,GAAG,OAAO,IAAI,EAAE,CAAC;QAC1C,OAAO,IAAI,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;IACrC,CAAC;IAED;;;;;;;;;;;;OAYG;IACH,MAAM,CAAC,SAAS,CAAC,GAAY;QAC3B,IAAI,GAAG,YAAY,IAAI,EAAE,CAAC;YACxB,OAAO,GAAG,CAAC;QACb,CAAC;QACD,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACxB,CAAC;CACF;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,IAAI,CAAC,IAAmB;IACtC,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACzB,CAAC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,OAAO,CAAC,IAAmB;IACzC,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;AAC5C,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,SAAS,CAAC,OAAgB;IACxC,OAAO,cAAc,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,CAAC;AACpD,CAAC;AAED,SAAS,cAAc,CAAC,OAAgB;IACtC,OAAO,cAAc,CAAC,OAAO,CAAC,CAAC;AACjC,CAAC;AAED,SAAS,MAAM,CAAC,OAAgB;IAC9B,OAAO,OAAO,YAAY,IAAI,CAAC;AACjC,CAAC"}
@@ -1,4 +1,3 @@
1
- export * from "./attributes/index.js";
2
1
  export type { CommandInput, CommandOutput } from "./base.js";
3
2
  export type { DynamoDbClientCommand } from "./command.js";
4
3
  export { CreateTable } from "./create-table.js";
@@ -1,4 +1,3 @@
1
- export * from "./attributes/index.js";
2
1
  export { CreateTable } from "./create-table.js";
3
2
  export { DeleteItem } from "./delete-item.js";
4
3
  export { DeleteTable } from "./delete-table.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC;AAGtC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,cAAc,wBAAwB,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AA0BxC,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,cAAc,wBAAwB,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AA0BxC,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@infra-blocks/aws-dynamodb",
3
- "version": "0.62.0",
3
+ "version": "0.63.0-alpha.0",
4
4
  "description": "A convenience wrapper over @aws-sdk/client-dynamodb and @aws-sdk/lib-dynamodb.",
5
5
  "keywords": [
6
6
  "aws",