betterddb 0.6.0 → 0.6.4

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.
Files changed (49) hide show
  1. package/.eslintrc.cjs +41 -0
  2. package/lib/betterddb.js +29 -17
  3. package/lib/builders/batch-get-builder.js +6 -2
  4. package/lib/builders/create-builder.js +14 -6
  5. package/lib/builders/delete-builder.js +8 -5
  6. package/lib/builders/get-builder.js +11 -6
  7. package/lib/builders/query-builder.js +38 -31
  8. package/lib/builders/scan-builder.js +17 -11
  9. package/lib/builders/update-builder.js +27 -18
  10. package/lib/operator.js +10 -10
  11. package/lib/{betterddb.d.ts → types/betterddb.d.ts} +13 -9
  12. package/lib/types/betterddb.d.ts.map +1 -0
  13. package/lib/{builders → types/builders}/batch-get-builder.d.ts +2 -1
  14. package/lib/types/builders/batch-get-builder.d.ts.map +1 -0
  15. package/lib/{builders → types/builders}/create-builder.d.ts +3 -2
  16. package/lib/types/builders/create-builder.d.ts.map +1 -0
  17. package/lib/{builders → types/builders}/delete-builder.d.ts +3 -2
  18. package/lib/types/builders/delete-builder.d.ts.map +1 -0
  19. package/lib/{builders → types/builders}/get-builder.d.ts +3 -2
  20. package/lib/types/builders/get-builder.d.ts.map +1 -0
  21. package/lib/{builders → types/builders}/query-builder.d.ts +4 -3
  22. package/lib/types/builders/query-builder.d.ts.map +1 -0
  23. package/lib/{builders → types/builders}/scan-builder.d.ts +4 -3
  24. package/lib/types/builders/scan-builder.d.ts.map +1 -0
  25. package/lib/{builders → types/builders}/update-builder.d.ts +3 -2
  26. package/lib/types/builders/update-builder.d.ts.map +1 -0
  27. package/lib/types/index.d.ts +2 -0
  28. package/lib/types/index.d.ts.map +1 -0
  29. package/lib/types/operator.d.ts +3 -0
  30. package/lib/types/operator.d.ts.map +1 -0
  31. package/lib/types/{paginated-result.d.ts → types/paginated-result.d.ts} +1 -0
  32. package/lib/types/types/paginated-result.d.ts.map +1 -0
  33. package/package.json +15 -5
  34. package/prettier.config.js +6 -0
  35. package/src/betterddb.ts +46 -37
  36. package/src/builders/batch-get-builder.ts +11 -6
  37. package/src/builders/create-builder.ts +42 -27
  38. package/src/builders/delete-builder.ts +28 -17
  39. package/src/builders/get-builder.ts +26 -19
  40. package/src/builders/query-builder.ts +64 -44
  41. package/src/builders/scan-builder.ts +18 -14
  42. package/src/builders/update-builder.ts +53 -27
  43. package/src/index.ts +1 -1
  44. package/src/operator.ts +21 -21
  45. package/src/types/paginated-result.ts +1 -1
  46. package/test/update.test.ts +6 -0
  47. package/tsconfig.json +25 -11
  48. package/lib/index.d.ts +0 -1
  49. package/lib/operator.d.ts +0 -2
@@ -1,13 +1,16 @@
1
- import { BetterDDB } from '../betterddb';
2
- import { BatchGetCommand } from '@aws-sdk/lib-dynamodb';
3
- import { BatchGetItemInput } from '@aws-sdk/client-dynamodb';
1
+ import { BetterDDB } from "../betterddb";
2
+ import { BatchGetCommand } from "@aws-sdk/lib-dynamodb";
3
+ import { BatchGetItemInput } from "@aws-sdk/client-dynamodb";
4
4
 
5
5
  export class BatchGetBuilder<T> {
6
6
  /**
7
7
  * @param parent - The BetterDDB instance for the table.
8
8
  * @param keys - An array of partial keys for the items you wish to retrieve.
9
9
  */
10
- constructor(private parent: BetterDDB<T>, private keys: Partial<T>[]) {}
10
+ constructor(
11
+ private parent: BetterDDB<T>,
12
+ private keys: Partial<T>[],
13
+ ) {}
11
14
 
12
15
  /**
13
16
  * Executes the batch get operation.
@@ -29,7 +32,7 @@ export class BatchGetBuilder<T> {
29
32
  });
30
33
  const tableName = this.parent.getTableName();
31
34
  // Build an array of keys using the parent's key builder.
32
- const keysArray = deduplicatedKeys.map(key => this.parent.buildKey(key));
35
+ const keysArray = deduplicatedKeys.map((key) => this.parent.buildKey(key));
33
36
 
34
37
  // Construct the BatchGet parameters.
35
38
  const params: BatchGetItemInput = {
@@ -40,7 +43,9 @@ export class BatchGetBuilder<T> {
40
43
  },
41
44
  };
42
45
 
43
- const result = await this.parent.getClient().send(new BatchGetCommand(params));
46
+ const result = await this.parent
47
+ .getClient()
48
+ .send(new BatchGetCommand(params));
44
49
  const responses = result.Responses ? result.Responses[tableName] : [];
45
50
  if (!responses) {
46
51
  return [];
@@ -1,12 +1,18 @@
1
-
2
- import { AttributeValue, Put, TransactWriteItem } from '@aws-sdk/client-dynamodb';
3
- import { BetterDDB } from '../betterddb';
4
- import { PutCommand, TransactWriteCommand } from '@aws-sdk/lib-dynamodb';
1
+ import {
2
+ AttributeValue,
3
+ Put,
4
+ TransactWriteItem,
5
+ } from "@aws-sdk/client-dynamodb";
6
+ import { BetterDDB } from "../betterddb";
7
+ import { PutCommand, TransactWriteCommand } from "@aws-sdk/lib-dynamodb";
5
8
 
6
9
  export class CreateBuilder<T> {
7
10
  private extraTransactItems: TransactWriteItem[] = [];
8
11
 
9
- constructor(private parent: BetterDDB<T>, private item: T) {}
12
+ constructor(
13
+ private parent: BetterDDB<T>,
14
+ private item: T,
15
+ ) {}
10
16
 
11
17
  public async execute(): Promise<T> {
12
18
  const validated = this.parent.getSchema().parse(this.item);
@@ -15,35 +21,41 @@ export class CreateBuilder<T> {
15
21
  const myTransactItem = this.toTransactPut();
16
22
  // Combine with extra transaction items.
17
23
  const allItems = [...this.extraTransactItems, myTransactItem];
18
- await this.parent.getClient().send(new TransactWriteCommand({
19
- TransactItems: allItems
20
- }));
24
+ await this.parent.getClient().send(
25
+ new TransactWriteCommand({
26
+ TransactItems: allItems,
27
+ }),
28
+ );
21
29
  // After transaction, retrieve the updated item.
22
30
  const result = await this.parent.get(this.item).execute();
23
31
  if (result === null) {
24
- throw new Error('Item not found after transaction create');
32
+ throw new Error("Item not found after transaction create");
25
33
  }
26
34
  return result;
27
35
  } else {
36
+ let finalItem: T = {
37
+ ...this.item,
38
+ entityType: this.parent.getEntityType(),
39
+ };
40
+ if (this.parent.getTimestamps()) {
41
+ const now = new Date().toISOString();
42
+ finalItem = { ...finalItem, createdAt: now, updatedAt: now } as T;
43
+ }
28
44
 
29
- let finalItem: T = { ...this.item , entityType: this.parent.getEntityType() };
30
- if (this.parent.getTimestamps()) {
31
- const now = new Date().toISOString();
32
- finalItem = { ...finalItem, createdAt: now, updatedAt: now } as T;
33
- }
45
+ // Compute and merge primary key.
46
+ const computedKeys = this.parent.buildKey(validated as Partial<T>);
47
+ finalItem = { ...finalItem, ...computedKeys };
34
48
 
35
- // Compute and merge primary key.
36
- const computedKeys = this.parent.buildKey(validated as Partial<T>);
37
- finalItem = { ...finalItem, ...computedKeys };
49
+ // Compute and merge index attributes.
50
+ const indexAttributes = this.parent.buildIndexes(validated as Partial<T>);
51
+ finalItem = { ...finalItem, ...indexAttributes };
38
52
 
39
- // Compute and merge index attributes.
40
- const indexAttributes = this.parent.buildIndexes(validated as Partial<T>);
41
- finalItem = { ...finalItem, ...indexAttributes };
42
-
43
- await this.parent.getClient().send(new PutCommand({
44
- TableName: this.parent.getTableName(),
45
- Item: finalItem as Record<string, AttributeValue>
46
- }));
53
+ await this.parent.getClient().send(
54
+ new PutCommand({
55
+ TableName: this.parent.getTableName(),
56
+ Item: finalItem as Record<string, AttributeValue>,
57
+ }),
58
+ );
47
59
 
48
60
  return validated as T;
49
61
  }
@@ -58,9 +70,12 @@ export class CreateBuilder<T> {
58
70
  return this;
59
71
  }
60
72
 
61
- public toTransactPut(): TransactWriteItem{
73
+ public toTransactPut(): TransactWriteItem {
62
74
  const validated = this.parent.getSchema().parse(this.item);
63
- let finalItem: T = { ...this.item , entityType: this.parent.getEntityType() };
75
+ let finalItem: T = {
76
+ ...this.item,
77
+ entityType: this.parent.getEntityType(),
78
+ };
64
79
  if (this.parent.getTimestamps()) {
65
80
  const now = new Date().toISOString();
66
81
  finalItem = { ...finalItem, createdAt: now, updatedAt: now } as T;
@@ -1,15 +1,24 @@
1
- import { BetterDDB } from '../betterddb';
2
- import { TransactWriteItem, DeleteItemInput } from '@aws-sdk/client-dynamodb';
3
- import { TransactWriteCommand, DeleteCommand } from '@aws-sdk/lib-dynamodb';
1
+ import { BetterDDB } from "../betterddb";
2
+ import { TransactWriteItem, DeleteItemInput } from "@aws-sdk/client-dynamodb";
3
+ import { TransactWriteCommand, DeleteCommand } from "@aws-sdk/lib-dynamodb";
4
4
  export class DeleteBuilder<T> {
5
- private condition?: { expression: string; attributeValues: Record<string, any> };
5
+ private condition?: {
6
+ expression: string;
7
+ attributeValues: Record<string, any>;
8
+ };
6
9
  private extraTransactItems: TransactWriteItem[] = [];
7
- constructor(private parent: BetterDDB<T>, private key: Partial<T>) {}
10
+ constructor(
11
+ private parent: BetterDDB<T>,
12
+ private key: Partial<T>,
13
+ ) {}
8
14
 
9
15
  /**
10
16
  * Specify a condition expression for the delete operation.
11
17
  */
12
- public withCondition(expression: string, attributeValues: Record<string, any>): this {
18
+ public withCondition(
19
+ expression: string,
20
+ attributeValues: Record<string, any>,
21
+ ): this {
13
22
  if (this.condition) {
14
23
  this.condition.expression += ` AND ${expression}`;
15
24
  Object.assign(this.condition.attributeValues, attributeValues);
@@ -25,21 +34,23 @@ export class DeleteBuilder<T> {
25
34
  const myTransactItem = this.toTransactDelete();
26
35
  // Combine with extra transaction items.
27
36
  const allItems = [...this.extraTransactItems, myTransactItem];
28
- await this.parent.getClient().send(new TransactWriteCommand({
29
- TransactItems: allItems
30
- }));
37
+ await this.parent.getClient().send(
38
+ new TransactWriteCommand({
39
+ TransactItems: allItems,
40
+ }),
41
+ );
31
42
  // After transaction, retrieve the updated item.
32
43
  const result = await this.parent.get(this.key).execute();
33
44
  if (result === null) {
34
- throw new Error('Item not found after transaction delete');
45
+ throw new Error("Item not found after transaction delete");
35
46
  }
36
47
  } else {
37
- const params: DeleteItemInput = {
38
- TableName: this.parent.getTableName(),
39
- Key: this.parent.buildKey(this.key)
40
- };
41
- if (this.condition) {
42
- params.ConditionExpression = this.condition.expression;
48
+ const params: DeleteItemInput = {
49
+ TableName: this.parent.getTableName(),
50
+ Key: this.parent.buildKey(this.key),
51
+ };
52
+ if (this.condition) {
53
+ params.ConditionExpression = this.condition.expression;
43
54
  params.ExpressionAttributeValues = this.condition.attributeValues;
44
55
  }
45
56
  await this.parent.getClient().send(new DeleteCommand(params));
@@ -58,7 +69,7 @@ export class DeleteBuilder<T> {
58
69
  public toTransactDelete(): TransactWriteItem {
59
70
  const deleteItem: DeleteItemInput = {
60
71
  TableName: this.parent.getTableName(),
61
- Key: this.parent.buildKey(this.key)
72
+ Key: this.parent.buildKey(this.key),
62
73
  };
63
74
  if (this.condition) {
64
75
  deleteItem.ConditionExpression = this.condition.expression;
@@ -1,17 +1,22 @@
1
- import { BetterDDB } from '../betterddb';
2
- import { TransactGetCommand, GetCommand } from '@aws-sdk/lib-dynamodb';
3
- import { GetItemInput, TransactGetItem } from '@aws-sdk/client-dynamodb';
1
+ import { BetterDDB } from "../betterddb";
2
+ import { TransactGetCommand, GetCommand } from "@aws-sdk/lib-dynamodb";
3
+ import { GetItemInput, TransactGetItem } from "@aws-sdk/client-dynamodb";
4
4
  export class GetBuilder<T> {
5
5
  private projectionExpression?: string;
6
6
  private expressionAttributeNames: Record<string, string> = {};
7
7
  private extraTransactItems: TransactGetItem[] = [];
8
- constructor(private parent: BetterDDB<T>, private key: Partial<T>) {}
8
+ constructor(
9
+ private parent: BetterDDB<T>,
10
+ private key: Partial<T>,
11
+ ) {}
9
12
 
10
13
  /**
11
14
  * Specify a projection by providing an array of attribute names.
12
15
  */
13
16
  public withProjection(attributes: (keyof T)[]): this {
14
- this.projectionExpression = attributes.map(attr => `#${String(attr)}`).join(', ');
17
+ this.projectionExpression = attributes
18
+ .map((attr) => `#${String(attr)}`)
19
+ .join(", ");
15
20
  for (const attr of attributes) {
16
21
  this.expressionAttributeNames[`#${String(attr)}`] = String(attr);
17
22
  }
@@ -24,23 +29,25 @@ export class GetBuilder<T> {
24
29
  const myTransactItem = this.toTransactGet();
25
30
  // Combine with extra transaction items.
26
31
  const allItems = [...this.extraTransactItems, myTransactItem];
27
- await this.parent.getClient().send(new TransactGetCommand({
28
- TransactItems: allItems
29
- }));
32
+ await this.parent.getClient().send(
33
+ new TransactGetCommand({
34
+ TransactItems: allItems,
35
+ }),
36
+ );
30
37
  // After transaction, retrieve the updated item.
31
38
  const result = await this.parent.get(this.key).execute();
32
39
  return result;
33
40
  } else {
34
- const params: GetItemInput = {
35
- TableName: this.parent.getTableName(),
36
- Key: this.parent.buildKey(this.key)
37
- };
38
- if (this.projectionExpression) {
39
- params.ProjectionExpression = this.projectionExpression;
40
- params.ExpressionAttributeNames = this.expressionAttributeNames;
41
- }
42
- const result = await this.parent.getClient().send(new GetCommand(params));
43
- if (!result.Item) return null;
41
+ const params: GetItemInput = {
42
+ TableName: this.parent.getTableName(),
43
+ Key: this.parent.buildKey(this.key),
44
+ };
45
+ if (this.projectionExpression) {
46
+ params.ProjectionExpression = this.projectionExpression;
47
+ params.ExpressionAttributeNames = this.expressionAttributeNames;
48
+ }
49
+ const result = await this.parent.getClient().send(new GetCommand(params));
50
+ if (!result.Item) return null;
44
51
  return this.parent.getSchema().parse(result.Item) as T;
45
52
  }
46
53
  }
@@ -57,7 +64,7 @@ export class GetBuilder<T> {
57
64
  public toTransactGet(): TransactGetItem {
58
65
  const getItem: GetItemInput = {
59
66
  TableName: this.parent.getTableName(),
60
- Key: this.parent.buildKey(this.key)
67
+ Key: this.parent.buildKey(this.key),
61
68
  };
62
69
  if (this.projectionExpression) {
63
70
  getItem.ProjectionExpression = this.projectionExpression;
@@ -1,7 +1,7 @@
1
- import { QueryCommand, QueryCommandInput } from '@aws-sdk/lib-dynamodb';
2
- import { BetterDDB, GSIConfig } from '../betterddb';
3
- import { getOperatorExpression, Operator } from '../operator';
4
- import { PaginatedResult } from '../types/paginated-result';
1
+ import { QueryCommand, QueryCommandInput } from "@aws-sdk/lib-dynamodb";
2
+ import { BetterDDB, GSIConfig } from "../betterddb";
3
+ import { getOperatorExpression, Operator } from "../operator";
4
+ import { PaginatedResult } from "../types/paginated-result";
5
5
 
6
6
  export class QueryBuilder<T> {
7
7
  private keyConditions: string[] = [];
@@ -13,29 +13,32 @@ export class QueryBuilder<T> {
13
13
  private lastKey?: Record<string, any>;
14
14
  private ascending: boolean = true;
15
15
 
16
- constructor(private parent: BetterDDB<T>, private key: Partial<T>, ) {
16
+ constructor(
17
+ private parent: BetterDDB<T>,
18
+ private key: Partial<T>,
19
+ ) {
17
20
  const keys = this.parent.getKeys();
18
21
  let pkName = keys.primary.name;
19
22
  let builtKey = this.parent.buildKey(this.key) as Record<string, any>;
20
-
21
- this.expressionAttributeNames['#pk'] = pkName;
22
- this.expressionAttributeValues[':pk_value'] = builtKey[pkName];
23
+
24
+ this.expressionAttributeNames["#pk"] = pkName;
25
+ this.expressionAttributeValues[":pk_value"] = builtKey[pkName];
23
26
  }
24
27
 
25
28
  public usingIndex(indexName: string): this {
26
29
  if (!this.parent.getKeys().gsis) {
27
- throw new Error('No global secondary indexes defined for this table');
30
+ throw new Error("No global secondary indexes defined for this table");
28
31
  }
29
32
  if (!(indexName in this.parent.getKeys().gsis!)) {
30
- throw new Error('index does not exist')
33
+ throw new Error("index does not exist");
31
34
  }
32
-
35
+
33
36
  this.index = this.parent.getKeys().gsis![indexName];
34
37
 
35
- const pkName = this.index.primary.name;
38
+ const pkName = this.index!.primary.name;
36
39
  const builtKey = this.parent.buildIndexes(this.key);
37
- this.expressionAttributeNames['#pk'] = pkName;
38
- this.expressionAttributeValues[':pk_value'] = builtKey[pkName];
40
+ this.expressionAttributeNames["#pk"] = pkName;
41
+ this.expressionAttributeValues[":pk_value"] = builtKey[pkName];
39
42
 
40
43
  return this;
41
44
  }
@@ -52,28 +55,32 @@ export class QueryBuilder<T> {
52
55
 
53
56
  public where(
54
57
  operator: Operator,
55
- values: Partial<T> | [Partial<T>, Partial<T>]
58
+ values: Partial<T> | [Partial<T>, Partial<T>],
56
59
  ): this {
57
60
  const keys = this.parent.getKeys();
58
61
  // Determine the sort key name from either the index or the primary keys.
59
62
  const sortKeyName = this.index ? this.index.sort?.name : keys.sort?.name;
60
63
  if (!sortKeyName) {
61
- throw new Error('Sort key is not defined for this table/index.');
64
+ throw new Error("Sort key is not defined for this table/index.");
62
65
  }
63
- const nameKey = '#sk';
66
+ const nameKey = "#sk";
64
67
  this.expressionAttributeNames[nameKey] = sortKeyName;
65
-
68
+
66
69
  // Enforce that a complex sort key requires an object input.
67
- if (typeof values !== 'object' || values === null) {
68
- throw new Error(`For complex sort keys, please provide an object with all necessary properties.`);
70
+ if (typeof values !== "object" || values === null) {
71
+ throw new Error(
72
+ `For complex sort keys, please provide an object with all necessary properties.`,
73
+ );
69
74
  }
70
-
71
- if (operator === 'between') {
75
+
76
+ if (operator === "between") {
72
77
  if (!Array.isArray(values) || values.length !== 2) {
73
- throw new Error(`For 'between' operator, values must be a tuple of two objects`);
78
+ throw new Error(
79
+ `For 'between' operator, values must be a tuple of two objects`,
80
+ );
74
81
  }
75
- const valueKeyStart = ':sk_start';
76
- const valueKeyEnd = ':sk_end';
82
+ const valueKeyStart = ":sk_start";
83
+ const valueKeyEnd = ":sk_end";
77
84
  // Use the key definition's build function to build the key from the full object.
78
85
  this.expressionAttributeValues[valueKeyStart] = this.index
79
86
  ? this.parent.buildIndexes(values[0])[sortKeyName]
@@ -81,16 +88,18 @@ export class QueryBuilder<T> {
81
88
  this.expressionAttributeValues[valueKeyEnd] = this.index
82
89
  ? this.parent.buildIndexes(values[1])[sortKeyName]
83
90
  : this.parent.buildKey(values[1])[sortKeyName];
84
- this.keyConditions.push(`${nameKey} BETWEEN ${valueKeyStart} AND ${valueKeyEnd}`);
85
- } else if (operator === 'begins_with') {
86
- const valueKey = ':sk_value';
91
+ this.keyConditions.push(
92
+ `${nameKey} BETWEEN ${valueKeyStart} AND ${valueKeyEnd}`,
93
+ );
94
+ } else if (operator === "begins_with") {
95
+ const valueKey = ":sk_value";
87
96
  this.expressionAttributeValues[valueKey] = this.index
88
97
  ? this.parent.buildIndexes(values as Partial<T>)[sortKeyName]
89
98
  : this.parent.buildKey(values as Partial<T>)[sortKeyName];
90
99
  this.keyConditions.push(`begins_with(${nameKey}, ${valueKey})`);
91
100
  } else {
92
101
  // For eq, lt, lte, gt, gte:
93
- const valueKey = ':sk_value';
102
+ const valueKey = ":sk_value";
94
103
  this.expressionAttributeValues[valueKey] = this.index
95
104
  ? this.parent.buildIndexes(values as Partial<T>)[sortKeyName]
96
105
  : this.parent.buildKey(values as Partial<T>)[sortKeyName];
@@ -99,36 +108,43 @@ export class QueryBuilder<T> {
99
108
  }
100
109
  return this;
101
110
  }
102
-
103
-
104
-
105
111
 
106
112
  public filter(
107
113
  attribute: keyof T,
108
114
  operator: Operator,
109
- values: any | [any, any]
115
+ values: any | [any, any],
110
116
  ): this {
111
117
  const attrStr = String(attribute);
112
118
  const randomString = Math.random().toString(36).substring(2, 15);
113
119
  const placeholderName = `#attr_${attrStr}_${randomString}`;
114
120
  this.expressionAttributeNames[placeholderName] = attrStr;
115
- if (operator === 'between') {
121
+ if (operator === "between") {
116
122
  if (!Array.isArray(values) || values.length !== 2) {
117
- throw new Error("For 'between' operator, values must be a tuple of two items");
123
+ throw new Error(
124
+ "For 'between' operator, values must be a tuple of two items",
125
+ );
118
126
  }
119
127
  const placeholderValueStart = `:val_start_${attrStr}_${randomString}`;
120
128
  const placeholderValueEnd = `:val_end_${attrStr}_${randomString}`;
121
129
  this.expressionAttributeValues[placeholderValueStart] = values[0];
122
130
  this.expressionAttributeValues[placeholderValueEnd] = values[1];
123
- this.filterConditions.push(`${placeholderName} BETWEEN ${placeholderValueStart} AND ${placeholderValueEnd}`);
124
- } else if (operator === 'begins_with' || operator === 'contains') {
131
+ this.filterConditions.push(
132
+ `${placeholderName} BETWEEN ${placeholderValueStart} AND ${placeholderValueEnd}`,
133
+ );
134
+ } else if (operator === "begins_with" || operator === "contains") {
125
135
  const placeholderValue = `:val_${attrStr}_${randomString}`;
126
136
  this.expressionAttributeValues[placeholderValue] = values;
127
- this.filterConditions.push(`${operator}(${placeholderName}, ${placeholderValue})`);
137
+ this.filterConditions.push(
138
+ `${operator}(${placeholderName}, ${placeholderValue})`,
139
+ );
128
140
  } else {
129
141
  const placeholderValue = `:val_${attrStr}_${randomString}`;
130
142
  this.expressionAttributeValues[placeholderValue] = values;
131
- const condition = getOperatorExpression(operator, placeholderName, placeholderValue);
143
+ const condition = getOperatorExpression(
144
+ operator,
145
+ placeholderName,
146
+ placeholderValue,
147
+ );
132
148
  this.filterConditions.push(condition);
133
149
  }
134
150
 
@@ -150,7 +166,7 @@ export class QueryBuilder<T> {
150
166
  */
151
167
  public async execute(): Promise<PaginatedResult<T>> {
152
168
  this.keyConditions.unshift(`#pk = :pk_value`);
153
- const keyConditionExpression = this.keyConditions.join(' AND ');
169
+ const keyConditionExpression = this.keyConditions.join(" AND ");
154
170
 
155
171
  const params: QueryCommandInput = {
156
172
  TableName: this.parent.getTableName(),
@@ -165,12 +181,16 @@ export class QueryBuilder<T> {
165
181
 
166
182
  if (this.parent.getEntityType()) {
167
183
  this.filterConditions.push(`#entity = :entity_value`);
168
- this.expressionAttributeNames['#entity'] = 'entityType';
169
- this.expressionAttributeValues[':entity_value'] = this.parent.getEntityType();
184
+ this.expressionAttributeNames["#entity"] = "entityType";
185
+ this.expressionAttributeValues[":entity_value"] =
186
+ this.parent.getEntityType();
170
187
  }
171
- params.FilterExpression = this.filterConditions.join(' AND ');
188
+ params.FilterExpression = this.filterConditions.join(" AND ");
172
189
 
173
190
  const result = await this.parent.getClient().send(new QueryCommand(params));
174
- return {items: this.parent.getSchema().array().parse(result.Items) as T[], lastKey: result.LastEvaluatedKey ?? undefined};
191
+ return {
192
+ items: this.parent.getSchema().array().parse(result.Items) as T[],
193
+ lastKey: result.LastEvaluatedKey ?? undefined,
194
+ };
175
195
  }
176
196
  }
@@ -1,7 +1,7 @@
1
- import { ScanCommand, ScanCommandInput } from '@aws-sdk/lib-dynamodb';
2
- import { BetterDDB } from '../betterddb';
3
- import { getOperatorExpression, Operator } from '../operator';
4
- import { PaginatedResult } from '../types/paginated-result';
1
+ import { ScanCommand, ScanCommandInput } from "@aws-sdk/lib-dynamodb";
2
+ import { BetterDDB } from "../betterddb";
3
+ import { getOperatorExpression, Operator } from "../operator";
4
+ import { PaginatedResult } from "../types/paginated-result";
5
5
 
6
6
  export class ScanBuilder<T> {
7
7
  private filters: string[] = [];
@@ -15,16 +15,16 @@ export class ScanBuilder<T> {
15
15
  public where(
16
16
  attribute: keyof T,
17
17
  operator: Operator,
18
- values: any | [any, any]
18
+ values: any | [any, any],
19
19
  ): this {
20
20
  const attrStr = String(attribute);
21
21
  const nameKey = `#attr_${attrStr}`;
22
22
  this.expressionAttributeNames[nameKey] = attrStr;
23
23
 
24
- if (operator === 'between') {
24
+ if (operator === "between") {
25
25
  if (!Array.isArray(values) || values.length !== 2) {
26
26
  throw new Error(
27
- `For 'between' operator, values must be a tuple of two items`
27
+ `For 'between' operator, values must be a tuple of two items`,
28
28
  );
29
29
  }
30
30
  const valueKeyStart = `:val_start_${attrStr}`;
@@ -32,9 +32,9 @@ export class ScanBuilder<T> {
32
32
  this.expressionAttributeValues[valueKeyStart] = values[0];
33
33
  this.expressionAttributeValues[valueKeyEnd] = values[1];
34
34
  this.filters.push(
35
- `${nameKey} BETWEEN ${valueKeyStart} AND ${valueKeyEnd}`
35
+ `${nameKey} BETWEEN ${valueKeyStart} AND ${valueKeyEnd}`,
36
36
  );
37
- } else if (operator === 'begins_with' || operator === 'contains') {
37
+ } else if (operator === "begins_with" || operator === "contains") {
38
38
  const valueKey = `:val_${attrStr}`;
39
39
  this.expressionAttributeValues[valueKey] = values;
40
40
  this.filters.push(`${operator}(${nameKey}, ${valueKey})`);
@@ -66,18 +66,22 @@ export class ScanBuilder<T> {
66
66
  ExpressionAttributeNames: this.expressionAttributeNames,
67
67
  ExpressionAttributeValues: this.expressionAttributeValues,
68
68
  Limit: this.limit,
69
- ExclusiveStartKey: this.lastKey
69
+ ExclusiveStartKey: this.lastKey,
70
70
  };
71
71
 
72
72
  if (this.parent.getEntityType()) {
73
73
  this.filters.push(`#entity = :entity_value`);
74
- this.expressionAttributeNames['#entity'] = 'entityType';
75
- this.expressionAttributeValues[':entity_value'] = this.parent.getEntityType();
74
+ this.expressionAttributeNames["#entity"] = "entityType";
75
+ this.expressionAttributeValues[":entity_value"] =
76
+ this.parent.getEntityType();
76
77
  }
77
- params.FilterExpression = this.filters.join(' AND ');
78
+ params.FilterExpression = this.filters.join(" AND ");
78
79
 
79
80
  const result = await this.parent.getClient().send(new ScanCommand(params));
80
81
 
81
- return {items: this.parent.getSchema().array().parse(result.Items) as T[], lastKey: result.LastEvaluatedKey ?? undefined};
82
+ return {
83
+ items: this.parent.getSchema().array().parse(result.Items) as T[],
84
+ lastKey: result.LastEvaluatedKey ?? undefined,
85
+ };
82
86
  }
83
87
  }