dinah 0.13.0 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cdk.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { t as Table } from "./table-D814Vwjm.cjs";
1
+ import { t as Table } from "./table-GSI2RvTa.cjs";
2
2
  import { TSchema } from "typebox";
3
3
  import * as cdk from "aws-cdk-lib/aws-dynamodb";
4
4
 
package/dist/cdk.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { t as Table } from "./table-CatYaz7J.mjs";
1
+ import { t as Table } from "./table-O4EneQbj.mjs";
2
2
  import { TSchema } from "typebox";
3
3
  import * as cdk from "aws-cdk-lib/aws-dynamodb";
4
4
 
package/dist/index.cjs CHANGED
@@ -116,7 +116,10 @@ var ExpressionBuilder = class {
116
116
  const setDelOperations = [];
117
117
  for (const [path, valOrOperation] of Object.entries(expression)) {
118
118
  const placeholder = this.getPathSub(path);
119
- if (valOrOperation === void 0) removeOperations.push(placeholder);
119
+ if (valOrOperation === void 0) throw new DinahError({
120
+ type: "VALIDATION",
121
+ message: `Field "${path}" cannot be set to undefined in an update expression. Use { $remove: true } to remove an optional attribute.`
122
+ });
120
123
  else if (isOperation(valOrOperation)) if (valOrOperation.$remove === true) removeOperations.push(placeholder);
121
124
  else if (valOrOperation.$setAdd !== void 0 || valOrOperation.$setDel !== void 0) {
122
125
  const operations = valOrOperation.$setAdd ? setAddOperations : setDelOperations;
@@ -204,7 +207,10 @@ var ExpressionBuilder = class {
204
207
  const sets = [];
205
208
  const removes = [];
206
209
  const params = [];
207
- for (const [path, valOrOp] of Object.entries(expression)) if (valOrOp === void 0) removes.push(`"${path}"`);
210
+ for (const [path, valOrOp] of Object.entries(expression)) if (valOrOp === void 0) throw new DinahError({
211
+ type: "VALIDATION",
212
+ message: `Field "${path}" cannot be set to undefined in an update expression. Use { $remove: true } to remove an optional attribute.`
213
+ });
208
214
  else if (isOperation(valOrOp)) if (valOrOp.$remove === true) removes.push(`"${path}"`);
209
215
  else sets.push(`"${path}"=${this.resolvePartiQLSetOperand(path, valOrOp, params)}`);
210
216
  else {
@@ -632,7 +638,7 @@ var Repo = class {
632
638
  }
633
639
  if (computedAttributes) for (const [key, def] of Object.entries(computedAttributes)) {
634
640
  const { from, compute } = def;
635
- const computed = compute(merged[from]);
641
+ const computed = compute(...Array.isArray(from) ? from.map((k) => merged[k]) : [merged[from]]);
636
642
  if (computed !== void 0) merged[key] = computed;
637
643
  else delete merged[key];
638
644
  }
@@ -673,15 +679,42 @@ var Repo = class {
673
679
  }
674
680
  if (computedAttributes) for (const [computedKey, def] of Object.entries(computedAttributes)) {
675
681
  const { from, compute } = def;
676
- if (!(from in result)) continue;
677
- const val = result[from];
678
- if (val === void 0 || isOperation(val) && val.$remove === true) result[computedKey] = void 0;
679
- else if (!isOperation(val)) result[computedKey] = compute(val);
680
- else if (val.$set !== void 0) result[computedKey] = compute(val.$set);
681
- else throw new DinahError({
682
- type: "VALIDATION",
683
- message: `Field "${from}" drives computed field "${computedKey}" and cannot use arithmetic or list operators in updates.`
684
- });
682
+ if (Array.isArray(from)) {
683
+ const fromArr = from;
684
+ if (fromArr.filter((k) => k in result).length === 0) continue;
685
+ const missingKeys = fromArr.filter((k) => !(k in result));
686
+ if (missingKeys.length > 0) throw new DinahError({
687
+ type: "VALIDATION",
688
+ message: `Field "${computedKey}" is computed from [${fromArr.join(", ")}]. All source fields must be included in the update or none. Missing: [${missingKeys.join(", ")}].`
689
+ });
690
+ const args = [];
691
+ for (const key of fromArr) {
692
+ const val = result[key];
693
+ if (val === void 0 || isOperation(val) && val.$remove === true) args.push(void 0);
694
+ else if (!isOperation(val)) args.push(val);
695
+ else if (val.$set !== void 0) args.push(val.$set);
696
+ else throw new DinahError({
697
+ type: "VALIDATION",
698
+ message: `Field "${key}" drives computed field "${computedKey}" and cannot use arithmetic or list operators in updates.`
699
+ });
700
+ }
701
+ const computed = compute(...args);
702
+ result[computedKey] = computed !== void 0 ? computed : { $remove: true };
703
+ } else {
704
+ const fromKey = from;
705
+ if (!(fromKey in result)) continue;
706
+ const val = result[fromKey];
707
+ let resolvedVal;
708
+ if (val === void 0 || isOperation(val) && val.$remove === true) resolvedVal = void 0;
709
+ else if (!isOperation(val)) resolvedVal = val;
710
+ else if (val.$set !== void 0) resolvedVal = val.$set;
711
+ else throw new DinahError({
712
+ type: "VALIDATION",
713
+ message: `Field "${fromKey}" drives computed field "${computedKey}" and cannot use arithmetic or list operators in updates.`
714
+ });
715
+ const computed = compute(resolvedVal);
716
+ result[computedKey] = computed !== void 0 ? computed : { $remove: true };
717
+ }
685
718
  }
686
719
  return result;
687
720
  }
@@ -725,12 +758,19 @@ var Db = class {
725
758
  else {
726
759
  const { endpoint, ...clientConfig } = clientOrConfig;
727
760
  this.client = _aws_sdk_lib_dynamodb.DynamoDBDocumentClient.from(new _aws_sdk_client_dynamodb.DynamoDBClient({
728
- endpoint: endpoint || void 0,
761
+ ...endpoint ? { endpoint } : {},
729
762
  ...clientConfig
730
763
  }));
731
764
  }
732
765
  this.config = dbConfig;
733
766
  }
767
+ normalizeUpdate(expression) {
768
+ const behavior = this.config?.updateUndefinedBehavior ?? "throw";
769
+ if (behavior === "throw") return expression;
770
+ const entries = Object.entries(expression);
771
+ if (behavior === "strip") return Object.fromEntries(entries.filter(([, v]) => v !== void 0));
772
+ return Object.fromEntries(entries.map(([k, v]) => [k, v === void 0 ? { $remove: true } : v]));
773
+ }
734
774
  makeRepo(table, config) {
735
775
  return new Repo(this, table, config);
736
776
  }
@@ -807,7 +847,7 @@ var Db = class {
807
847
  Key: data.key,
808
848
  ReturnValues: "ALL_NEW",
809
849
  ReturnValuesOnConditionCheckFailure: "ALL_OLD",
810
- UpdateExpression: exp.update(data.update),
850
+ UpdateExpression: exp.update(this.normalizeUpdate(data.update)),
811
851
  ConditionExpression: exp.condition(condition),
812
852
  ExpressionAttributeNames: exp.attributeNames,
813
853
  ExpressionAttributeValues: exp.attributeValues
@@ -1074,7 +1114,7 @@ var Db = class {
1074
1114
  while (queue.length && retryCount < 5) {
1075
1115
  const batch = queue.splice(0, batchSize || 1);
1076
1116
  const statements = batch.map(([table, key, update]) => {
1077
- const { sets, removes, params } = new ExpressionBuilder().partiqlUpdate(update);
1117
+ const { sets, removes, params } = new ExpressionBuilder().partiqlUpdate(this.normalizeUpdate(update));
1078
1118
  const whereParts = [];
1079
1119
  for (const [field, value] of Object.entries(key)) {
1080
1120
  whereParts.push(`"${field}"=?`);
@@ -1159,7 +1199,7 @@ var Db = class {
1159
1199
  return { Update: {
1160
1200
  Key: request.key,
1161
1201
  TableName: request.table,
1162
- UpdateExpression: exp.update(request.update),
1202
+ UpdateExpression: exp.update(this.normalizeUpdate(request.update)),
1163
1203
  ConditionExpression: exp.condition(request.condition),
1164
1204
  ExpressionAttributeNames: exp.attributeNames,
1165
1205
  ExpressionAttributeValues: exp.attributeValues