betterddb 0.4.8 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -61,8 +61,8 @@ const userDdb = new BetterDDB({
61
61
  }
62
62
  },
63
63
  client,
64
- autoTimestamps: true,
65
- entityName: 'USER'
64
+ timestamps: true,
65
+ entityType: 'USER'
66
66
  });
67
67
 
68
68
  (async () => {
@@ -63,7 +63,7 @@ export interface KeysConfig<T> {
63
63
  export interface BetterDDBOptions<T> {
64
64
  schema: z.ZodType<T, z.ZodTypeDef, any>;
65
65
  tableName: string;
66
- entityName: string;
66
+ entityType: string;
67
67
  keys: KeysConfig<T>;
68
68
  client: DynamoDBDocumentClient;
69
69
  /**
@@ -73,7 +73,7 @@ export interface BetterDDBOptions<T> {
73
73
  *
74
74
  * (T should include these fields if enabled.)
75
75
  */
76
- autoTimestamps?: boolean;
76
+ timestamps?: boolean;
77
77
  }
78
78
  /**
79
79
  * BetterDDB is a definition-based DynamoDB wrapper library.
@@ -81,16 +81,17 @@ export interface BetterDDBOptions<T> {
81
81
  export declare class BetterDDB<T> {
82
82
  protected schema: z.ZodType<T, z.ZodTypeDef, any>;
83
83
  protected tableName: string;
84
- protected entityName: string;
84
+ protected entityType: string;
85
85
  protected client: DynamoDBDocumentClient;
86
86
  protected keys: KeysConfig<T>;
87
- protected autoTimestamps: boolean;
87
+ protected timestamps: boolean;
88
88
  constructor(options: BetterDDBOptions<T>);
89
89
  getKeys(): KeysConfig<T>;
90
90
  getTableName(): string;
91
91
  getClient(): DynamoDBDocumentClient;
92
92
  getSchema(): z.ZodType<T, z.ZodTypeDef, any>;
93
- getAutoTimestamps(): boolean;
93
+ getTimestamps(): boolean;
94
+ getEntityType(): string;
94
95
  protected getKeyValue(def: KeyDefinition<T>, rawKey: Partial<T>): string;
95
96
  /**
96
97
  * Build the primary key from a raw key object.
@@ -118,7 +119,7 @@ export declare class BetterDDB<T> {
118
119
  /**
119
120
  * Update an item.
120
121
  */
121
- update(key: Partial<T>, expectedVersion?: number): UpdateBuilder<T>;
122
+ update(key: Partial<T>): UpdateBuilder<T>;
122
123
  /**
123
124
  * Delete an item.
124
125
  */
package/lib/betterddb.js CHANGED
@@ -16,10 +16,10 @@ class BetterDDB {
16
16
  var _a;
17
17
  this.schema = options.schema;
18
18
  this.tableName = options.tableName;
19
- this.entityName = options.entityName.toUpperCase();
19
+ this.entityType = options.entityType.toUpperCase();
20
20
  this.keys = options.keys;
21
21
  this.client = options.client;
22
- this.autoTimestamps = (_a = options.autoTimestamps) !== null && _a !== void 0 ? _a : false;
22
+ this.timestamps = (_a = options.timestamps) !== null && _a !== void 0 ? _a : false;
23
23
  }
24
24
  getKeys() {
25
25
  return this.keys;
@@ -33,8 +33,11 @@ class BetterDDB {
33
33
  getSchema() {
34
34
  return this.schema;
35
35
  }
36
- getAutoTimestamps() {
37
- return this.autoTimestamps;
36
+ getTimestamps() {
37
+ return this.timestamps;
38
+ }
39
+ getEntityType() {
40
+ return this.entityType;
38
41
  }
39
42
  // Helper: Retrieve the key value from a KeyDefinition.
40
43
  getKeyValue(def, rawKey) {
@@ -124,8 +127,8 @@ class BetterDDB {
124
127
  /**
125
128
  * Update an item.
126
129
  */
127
- update(key, expectedVersion) {
128
- return new update_builder_1.UpdateBuilder(this, key, expectedVersion);
130
+ update(key) {
131
+ return new update_builder_1.UpdateBuilder(this, key);
129
132
  }
130
133
  /**
131
134
  * Delete an item.
@@ -9,6 +9,7 @@ class CreateBuilder {
9
9
  this.extraTransactItems = [];
10
10
  }
11
11
  async execute() {
12
+ const validated = this.parent.getSchema().parse(this.item);
12
13
  if (this.extraTransactItems.length > 0) {
13
14
  // Build our update transaction item.
14
15
  const myTransactItem = this.toTransactPut();
@@ -25,14 +26,11 @@ class CreateBuilder {
25
26
  return result;
26
27
  }
27
28
  else {
28
- let item = this.item;
29
- if (this.parent.getAutoTimestamps()) {
29
+ let finalItem = { ...this.item, entityType: this.parent.getEntityType() };
30
+ if (this.parent.getTimestamps()) {
30
31
  const now = new Date().toISOString();
31
- item = { ...item, createdAt: now, updatedAt: now };
32
+ finalItem = { ...finalItem, createdAt: now, updatedAt: now };
32
33
  }
33
- // Validate the item using the schema.
34
- const validated = this.parent.getSchema().parse(item);
35
- let finalItem = { ...validated };
36
34
  // Compute and merge primary key.
37
35
  const computedKeys = this.parent.buildKey(validated);
38
36
  finalItem = { ...finalItem, ...computedKeys };
@@ -1,12 +1,14 @@
1
1
  import { BetterDDB } from '../betterddb';
2
+ import { Operator } from '../operator';
3
+ import { PaginatedResult } from '../types/paginated-result';
2
4
  export declare class QueryBuilder<T> {
3
5
  private parent;
4
6
  private key;
5
- private filters;
7
+ private keyConditions;
8
+ private filterConditions;
6
9
  private expressionAttributeNames;
7
10
  private expressionAttributeValues;
8
11
  private index?;
9
- private sortKeyCondition?;
10
12
  private limit?;
11
13
  private lastKey?;
12
14
  private ascending;
@@ -14,11 +16,12 @@ export declare class QueryBuilder<T> {
14
16
  usingIndex(indexName: string): this;
15
17
  sortAscending(): this;
16
18
  sortDescending(): this;
17
- where(attribute: keyof T, operator: 'eq' | 'begins_with' | 'between', values: any | [any, any]): this;
19
+ where(operator: Operator, values: Partial<T> | [Partial<T>, Partial<T>]): this;
20
+ filter(attribute: keyof T, operator: Operator, values: any | [any, any]): this;
18
21
  limitResults(limit: number): this;
19
22
  startFrom(lastKey: Record<string, any>): this;
20
23
  /**
21
24
  * Executes the query and returns a Promise that resolves with an array of items.
22
25
  */
23
- execute(): Promise<T[]>;
26
+ execute(): Promise<PaginatedResult<T>>;
24
27
  }
@@ -2,11 +2,13 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.QueryBuilder = void 0;
4
4
  const lib_dynamodb_1 = require("@aws-sdk/lib-dynamodb");
5
+ const operator_1 = require("../operator");
5
6
  class QueryBuilder {
6
7
  constructor(parent, key) {
7
8
  this.parent = parent;
8
9
  this.key = key;
9
- this.filters = [];
10
+ this.keyConditions = [];
11
+ this.filterConditions = [];
10
12
  this.expressionAttributeNames = {};
11
13
  this.expressionAttributeValues = {};
12
14
  this.ascending = true;
@@ -29,32 +31,78 @@ class QueryBuilder {
29
31
  this.ascending = false;
30
32
  return this;
31
33
  }
32
- where(attribute, operator, values) {
33
- const attrStr = String(attribute);
34
- const nameKey = `#attr_${attrStr}`;
35
- this.expressionAttributeNames[nameKey] = attrStr;
36
- if (operator === 'eq') {
37
- const valueKey = `:val_${attrStr}`;
38
- this.expressionAttributeValues[valueKey] = values;
39
- this.filters.push(`${nameKey} = ${valueKey}`);
34
+ where(operator, values) {
35
+ var _a, _b;
36
+ const keys = this.parent.getKeys();
37
+ // Determine the sort key name from either the index or the primary keys.
38
+ const sortKeyName = this.index ? (_a = this.index.sort) === null || _a === void 0 ? void 0 : _a.name : (_b = keys.sort) === null || _b === void 0 ? void 0 : _b.name;
39
+ if (!sortKeyName) {
40
+ throw new Error('Sort key is not defined for this table/index.');
41
+ }
42
+ const nameKey = '#sk';
43
+ this.expressionAttributeNames[nameKey] = sortKeyName;
44
+ // Enforce that a complex sort key requires an object input.
45
+ if (typeof values !== 'object' || values === null) {
46
+ throw new Error(`For complex sort keys, please provide an object with all necessary properties.`);
47
+ }
48
+ if (operator === 'between') {
49
+ if (!Array.isArray(values) || values.length !== 2) {
50
+ throw new Error(`For 'between' operator, values must be a tuple of two objects`);
51
+ }
52
+ const valueKeyStart = ':sk_start';
53
+ const valueKeyEnd = ':sk_end';
54
+ // Use the key definition's build function to build the key from the full object.
55
+ this.expressionAttributeValues[valueKeyStart] = this.index
56
+ ? this.parent.buildIndexes(values[0])[sortKeyName]
57
+ : this.parent.buildKey(values[0])[sortKeyName];
58
+ this.expressionAttributeValues[valueKeyEnd] = this.index
59
+ ? this.parent.buildIndexes(values[1])[sortKeyName]
60
+ : this.parent.buildKey(values[1])[sortKeyName];
61
+ this.keyConditions.push(`${nameKey} BETWEEN ${valueKeyStart} AND ${valueKeyEnd}`);
40
62
  }
41
63
  else if (operator === 'begins_with') {
42
- const valueKey = `:val_${attrStr}`;
43
- this.expressionAttributeValues[valueKey] = values;
44
- this.filters.push(`begins_with(${nameKey}, ${valueKey})`);
64
+ const valueKey = ':sk_value';
65
+ this.expressionAttributeValues[valueKey] = this.index
66
+ ? this.parent.buildIndexes(values)[sortKeyName]
67
+ : this.parent.buildKey(values)[sortKeyName];
68
+ this.keyConditions.push(`begins_with(${nameKey}, ${valueKey})`);
45
69
  }
46
- else if (operator === 'between') {
70
+ else {
71
+ // For eq, lt, lte, gt, gte:
72
+ const valueKey = ':sk_value';
73
+ this.expressionAttributeValues[valueKey] = this.index
74
+ ? this.parent.buildIndexes(values)[sortKeyName]
75
+ : this.parent.buildKey(values)[sortKeyName];
76
+ const condition = (0, operator_1.getOperatorExpression)(operator, nameKey, valueKey);
77
+ this.keyConditions.push(condition);
78
+ }
79
+ return this;
80
+ }
81
+ filter(attribute, operator, values) {
82
+ const attrStr = String(attribute);
83
+ const randomString = Math.random().toString(36).substring(2, 15);
84
+ const placeholderName = `#attr_${attrStr}_${randomString}`;
85
+ this.expressionAttributeNames[placeholderName] = attrStr;
86
+ if (operator === 'between') {
47
87
  if (!Array.isArray(values) || values.length !== 2) {
48
- throw new Error(`For 'between' operator, values must be a tuple of two items`);
88
+ throw new Error("For 'between' operator, values must be a tuple of two items");
49
89
  }
50
- const valueKeyStart = `:val_start_${attrStr}`;
51
- const valueKeyEnd = `:val_end_${attrStr}`;
52
- this.expressionAttributeValues[valueKeyStart] = values[0];
53
- this.expressionAttributeValues[valueKeyEnd] = values[1];
54
- this.filters.push(`${nameKey} BETWEEN ${valueKeyStart} AND ${valueKeyEnd}`);
90
+ const placeholderValueStart = `:val_start_${attrStr}_${randomString}`;
91
+ const placeholderValueEnd = `:val_end_${attrStr}_${randomString}`;
92
+ this.expressionAttributeValues[placeholderValueStart] = values[0];
93
+ this.expressionAttributeValues[placeholderValueEnd] = values[1];
94
+ this.filterConditions.push(`${placeholderName} BETWEEN ${placeholderValueStart} AND ${placeholderValueEnd}`);
95
+ }
96
+ else if (operator === 'begins_with' || operator === 'contains') {
97
+ const placeholderValue = `:val_${attrStr}_${randomString}`;
98
+ this.expressionAttributeValues[placeholderValue] = values;
99
+ this.filterConditions.push(`${operator}(${placeholderName}, ${placeholderValue})`);
55
100
  }
56
101
  else {
57
- throw new Error(`Unsupported operator: ${operator}`);
102
+ const placeholderValue = `:val_${attrStr}_${randomString}`;
103
+ this.expressionAttributeValues[placeholderValue] = values;
104
+ const condition = (0, operator_1.getOperatorExpression)(operator, placeholderName, placeholderValue);
105
+ this.filterConditions.push(condition);
58
106
  }
59
107
  return this;
60
108
  }
@@ -70,7 +118,7 @@ class QueryBuilder {
70
118
  * Executes the query and returns a Promise that resolves with an array of items.
71
119
  */
72
120
  async execute() {
73
- var _a, _b;
121
+ var _a, _b, _c;
74
122
  const keys = this.parent.getKeys();
75
123
  let pkName = keys.primary.name;
76
124
  let builtKey = this.parent.buildKey(this.key);
@@ -78,12 +126,12 @@ class QueryBuilder {
78
126
  pkName = this.index.primary.name;
79
127
  builtKey = this.parent.buildIndexes(this.key);
80
128
  }
81
- this.expressionAttributeNames['#pk'] = pkName;
82
- let keyConditionExpression = `#pk = :pk_value`;
83
- if (this.sortKeyCondition) {
84
- keyConditionExpression += ` AND ${this.sortKeyCondition}`;
129
+ if (!this.expressionAttributeNames['#pk']) {
130
+ this.expressionAttributeNames['#pk'] = pkName;
131
+ this.expressionAttributeValues[':pk_value'] = builtKey[pkName];
132
+ this.keyConditions.unshift(`#pk = :pk_value`);
85
133
  }
86
- this.expressionAttributeValues[':pk_value'] = builtKey[pkName];
134
+ const keyConditionExpression = this.keyConditions.join(' AND ');
87
135
  const params = {
88
136
  TableName: this.parent.getTableName(),
89
137
  KeyConditionExpression: keyConditionExpression,
@@ -92,13 +140,14 @@ class QueryBuilder {
92
140
  ScanIndexForward: this.ascending,
93
141
  Limit: this.limit,
94
142
  ExclusiveStartKey: this.lastKey,
95
- IndexName: (_b = (_a = this.index) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : undefined
143
+ IndexName: (_b = (_a = this.index) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : undefined,
96
144
  };
97
- if (this.filters.length > 0) {
98
- params.FilterExpression = this.filters.join(' AND ');
99
- }
145
+ this.filterConditions.push(`#entity = :entity_value`);
146
+ this.expressionAttributeNames['#entity'] = 'entityType';
147
+ this.expressionAttributeValues[':entity_value'] = this.parent.getEntityType();
148
+ params.FilterExpression = this.filterConditions.join(' AND ');
100
149
  const result = await this.parent.getClient().send(new lib_dynamodb_1.QueryCommand(params));
101
- return this.parent.getSchema().array().parse(result.Items);
150
+ return { items: this.parent.getSchema().array().parse(result.Items), lastKey: (_c = result.LastEvaluatedKey) !== null && _c !== void 0 ? _c : undefined };
102
151
  }
103
152
  }
104
153
  exports.QueryBuilder = QueryBuilder;
@@ -1,4 +1,6 @@
1
1
  import { BetterDDB } from '../betterddb';
2
+ import { Operator } from '../operator';
3
+ import { PaginatedResult } from '../types/paginated-result';
2
4
  export declare class ScanBuilder<T> {
3
5
  private parent;
4
6
  private filters;
@@ -7,11 +9,11 @@ export declare class ScanBuilder<T> {
7
9
  private limit?;
8
10
  private lastKey?;
9
11
  constructor(parent: BetterDDB<T>);
10
- where(attribute: keyof T, operator: 'eq' | 'begins_with' | 'between', values: any | [any, any]): this;
12
+ where(attribute: keyof T, operator: Operator, values: any | [any, any]): this;
11
13
  limitResults(limit: number): this;
12
14
  startFrom(lastKey: Record<string, any>): this;
13
15
  /**
14
16
  * Executes the scan and returns a Promise that resolves with an array of items.
15
17
  */
16
- execute(): Promise<T[]>;
18
+ execute(): Promise<PaginatedResult<T>>;
17
19
  }
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ScanBuilder = void 0;
4
4
  const lib_dynamodb_1 = require("@aws-sdk/lib-dynamodb");
5
+ const operator_1 = require("../operator");
5
6
  class ScanBuilder {
6
7
  constructor(parent) {
7
8
  this.parent = parent;
@@ -13,17 +14,7 @@ class ScanBuilder {
13
14
  const attrStr = String(attribute);
14
15
  const nameKey = `#attr_${attrStr}`;
15
16
  this.expressionAttributeNames[nameKey] = attrStr;
16
- if (operator === 'eq') {
17
- const valueKey = `:val_${attrStr}`;
18
- this.expressionAttributeValues[valueKey] = values;
19
- this.filters.push(`${nameKey} = ${valueKey}`);
20
- }
21
- else if (operator === 'begins_with') {
22
- const valueKey = `:val_${attrStr}`;
23
- this.expressionAttributeValues[valueKey] = values;
24
- this.filters.push(`begins_with(${nameKey}, ${valueKey})`);
25
- }
26
- else if (operator === 'between') {
17
+ if (operator === 'between') {
27
18
  if (!Array.isArray(values) || values.length !== 2) {
28
19
  throw new Error(`For 'between' operator, values must be a tuple of two items`);
29
20
  }
@@ -33,8 +24,16 @@ class ScanBuilder {
33
24
  this.expressionAttributeValues[valueKeyEnd] = values[1];
34
25
  this.filters.push(`${nameKey} BETWEEN ${valueKeyStart} AND ${valueKeyEnd}`);
35
26
  }
27
+ else if (operator === 'begins_with' || operator === 'contains') {
28
+ const valueKey = `:val_${attrStr}`;
29
+ this.expressionAttributeValues[valueKey] = values;
30
+ this.filters.push(`${operator}(${nameKey}, ${valueKey})`);
31
+ }
36
32
  else {
37
- throw new Error(`Unsupported operator: ${operator}`);
33
+ const valueKey = `:val_${attrStr}`;
34
+ this.expressionAttributeValues[valueKey] = values;
35
+ const condition = (0, operator_1.getOperatorExpression)(operator, nameKey, valueKey);
36
+ this.filters.push(condition);
38
37
  }
39
38
  return this;
40
39
  }
@@ -50,6 +49,7 @@ class ScanBuilder {
50
49
  * Executes the scan and returns a Promise that resolves with an array of items.
51
50
  */
52
51
  async execute() {
52
+ var _a;
53
53
  const params = {
54
54
  TableName: this.parent.getTableName(),
55
55
  ExpressionAttributeNames: this.expressionAttributeNames,
@@ -61,7 +61,7 @@ class ScanBuilder {
61
61
  params.FilterExpression = this.filters.join(' AND ');
62
62
  }
63
63
  const result = await this.parent.getClient().send(new lib_dynamodb_1.ScanCommand(params));
64
- return this.parent.getSchema().array().parse(result.Items);
64
+ return { items: this.parent.getSchema().array().parse(result.Items), lastKey: (_a = result.LastEvaluatedKey) !== null && _a !== void 0 ? _a : undefined };
65
65
  }
66
66
  }
67
67
  exports.ScanBuilder = ScanBuilder;
@@ -5,9 +5,8 @@ export declare class UpdateBuilder<T> {
5
5
  private key;
6
6
  private actions;
7
7
  private condition?;
8
- private expectedVersion?;
9
8
  private extraTransactItems;
10
- constructor(parent: BetterDDB<T>, key: Partial<T>, expectedVersion?: number);
9
+ constructor(parent: BetterDDB<T>, key: Partial<T>);
11
10
  set(attrs: Partial<T>): this;
12
11
  remove(attrs: (keyof T)[]): this;
13
12
  add(attrs: Partial<Record<keyof T, number | Set<any>>>): this;
@@ -4,13 +4,12 @@ exports.UpdateBuilder = void 0;
4
4
  const lib_dynamodb_1 = require("@aws-sdk/lib-dynamodb");
5
5
  class UpdateBuilder {
6
6
  // Reference to the parent BetterDDB instance and key.
7
- constructor(parent, key, expectedVersion) {
7
+ constructor(parent, key) {
8
8
  this.parent = parent;
9
9
  this.key = key;
10
10
  this.actions = {};
11
11
  // When using transaction mode, we store extra transaction items.
12
12
  this.extraTransactItems = [];
13
- this.expectedVersion = expectedVersion;
14
13
  }
15
14
  // Chainable methods:
16
15
  set(attrs) {
@@ -113,28 +112,6 @@ class UpdateBuilder {
113
112
  clauses.push(`DELETE ${deleteParts.join(', ')}`);
114
113
  }
115
114
  }
116
- // Incorporate expectedVersion if provided.
117
- if (this.expectedVersion !== undefined) {
118
- ExpressionAttributeNames['#version'] = 'version';
119
- ExpressionAttributeValues[':expectedVersion'] = this.expectedVersion;
120
- ExpressionAttributeValues[':newVersion'] = this.expectedVersion + 1;
121
- // Append version update in SET clause.
122
- const versionClause = '#version = :newVersion';
123
- const setIndex = clauses.findIndex(clause => clause.startsWith('SET '));
124
- if (setIndex >= 0) {
125
- clauses[setIndex] += `, ${versionClause}`;
126
- }
127
- else {
128
- clauses.push(`SET ${versionClause}`);
129
- }
130
- // Ensure condition expression includes version check.
131
- if (this.condition && this.condition.expression) {
132
- this.condition.expression += ` AND #version = :expectedVersion`;
133
- }
134
- else {
135
- this.condition = { expression: '#version = :expectedVersion', attributeValues: {} };
136
- }
137
- }
138
115
  // Merge any provided condition attribute values.
139
116
  if (this.condition) {
140
117
  Object.assign(ExpressionAttributeValues, this.condition.attributeValues);
@@ -0,0 +1,2 @@
1
+ export type Operator = '==' | '!=' | '<' | '<=' | '>' | '>=' | 'begins_with' | 'between' | 'contains';
2
+ export declare function getOperatorExpression(operator: Operator, nameKey: string, valueKey: string, secondValueKey?: string): string;
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getOperatorExpression = void 0;
4
+ function getOperatorExpression(operator, nameKey, valueKey, secondValueKey) {
5
+ switch (operator) {
6
+ case '==':
7
+ return `${nameKey} = ${valueKey}`;
8
+ case '!=':
9
+ return `${nameKey} <> ${valueKey}`;
10
+ case '<':
11
+ return `${nameKey} < ${valueKey}`;
12
+ case '<=':
13
+ return `${nameKey} <= ${valueKey}`;
14
+ case '>':
15
+ return `${nameKey} > ${valueKey}`;
16
+ case '>=':
17
+ return `${nameKey} >= ${valueKey}`;
18
+ case 'begins_with':
19
+ return `begins_with(${nameKey}, ${valueKey})`;
20
+ case 'between':
21
+ if (!secondValueKey) {
22
+ throw new Error("The 'between' operator requires two value keys");
23
+ }
24
+ return `${nameKey} BETWEEN ${valueKey} AND ${secondValueKey}`;
25
+ case 'contains':
26
+ return `contains(${nameKey}, ${valueKey})`;
27
+ default:
28
+ throw new Error(`Unsupported operator: ${operator}`);
29
+ }
30
+ }
31
+ exports.getOperatorExpression = getOperatorExpression;
@@ -0,0 +1,4 @@
1
+ export type PaginatedResult<T> = {
2
+ items: T[];
3
+ lastKey: Record<string, any> | undefined;
4
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "betterddb",
3
- "version": "0.4.8",
3
+ "version": "0.5.0",
4
4
  "description": "A definition-based DynamoDB wrapper library that provides a schema-driven and fully typesafe DAL.",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
package/src/betterddb.ts CHANGED
@@ -72,7 +72,7 @@ export interface KeysConfig<T> {
72
72
  export interface BetterDDBOptions<T> {
73
73
  schema: z.ZodType<T, z.ZodTypeDef, any>;
74
74
  tableName: string;
75
- entityName: string;
75
+ entityType: string;
76
76
  keys: KeysConfig<T>;
77
77
  client: DynamoDBDocumentClient;
78
78
  /**
@@ -82,7 +82,7 @@ export interface BetterDDBOptions<T> {
82
82
  *
83
83
  * (T should include these fields if enabled.)
84
84
  */
85
- autoTimestamps?: boolean;
85
+ timestamps?: boolean;
86
86
  }
87
87
 
88
88
  /**
@@ -91,18 +91,18 @@ export interface BetterDDBOptions<T> {
91
91
  export class BetterDDB<T> {
92
92
  protected schema: z.ZodType<T, z.ZodTypeDef, any>;
93
93
  protected tableName: string;
94
- protected entityName: string;
94
+ protected entityType: string;
95
95
  protected client: DynamoDBDocumentClient;
96
96
  protected keys: KeysConfig<T>;
97
- protected autoTimestamps: boolean;
97
+ protected timestamps: boolean;
98
98
 
99
99
  constructor(options: BetterDDBOptions<T>) {
100
100
  this.schema = options.schema;
101
101
  this.tableName = options.tableName;
102
- this.entityName = options.entityName.toUpperCase();
102
+ this.entityType = options.entityType.toUpperCase();
103
103
  this.keys = options.keys;
104
104
  this.client = options.client;
105
- this.autoTimestamps = options.autoTimestamps ?? false;
105
+ this.timestamps = options.timestamps ?? false;
106
106
  }
107
107
 
108
108
  public getKeys(): KeysConfig<T> {
@@ -122,8 +122,12 @@ export class BetterDDB<T> {
122
122
  return this.schema;
123
123
  }
124
124
 
125
- public getAutoTimestamps(): boolean {
126
- return this.autoTimestamps;
125
+ public getTimestamps(): boolean {
126
+ return this.timestamps;
127
+ }
128
+
129
+ public getEntityType(): string {
130
+ return this.entityType;
127
131
  }
128
132
 
129
133
  // Helper: Retrieve the key value from a KeyDefinition.
@@ -223,8 +227,8 @@ export class BetterDDB<T> {
223
227
  /**
224
228
  * Update an item.
225
229
  */
226
- public update(key: Partial<T>, expectedVersion?: number): UpdateBuilder<T> {
227
- return new UpdateBuilder<T>(this, key, expectedVersion);
230
+ public update(key: Partial<T>): UpdateBuilder<T> {
231
+ return new UpdateBuilder<T>(this, key);
228
232
  }
229
233
 
230
234
  /**
@@ -9,6 +9,7 @@ export class CreateBuilder<T> {
9
9
  constructor(private parent: BetterDDB<T>, private item: T) {}
10
10
 
11
11
  public async execute(): Promise<T> {
12
+ const validated = this.parent.getSchema().parse(this.item);
12
13
  if (this.extraTransactItems.length > 0) {
13
14
  // Build our update transaction item.
14
15
  const myTransactItem = this.toTransactPut();
@@ -24,14 +25,12 @@ export class CreateBuilder<T> {
24
25
  }
25
26
  return result;
26
27
  } else {
27
- let item = this.item;
28
- if (this.parent.getAutoTimestamps()) {
28
+
29
+ let finalItem: T = { ...this.item , entityType: this.parent.getEntityType() };
30
+ if (this.parent.getTimestamps()) {
29
31
  const now = new Date().toISOString();
30
- item = { ...item, createdAt: now, updatedAt: now } as T;
32
+ finalItem = { ...finalItem, createdAt: now, updatedAt: now } as T;
31
33
  }
32
- // Validate the item using the schema.
33
- const validated = this.parent.getSchema().parse(item);
34
- let finalItem = { ...validated };
35
34
 
36
35
  // Compute and merge primary key.
37
36
  const computedKeys = this.parent.buildKey(validated as Partial<T>);