dynoquery 0.1.4 → 0.1.6
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 +71 -18
- package/dist/index-query.d.ts +13 -0
- package/dist/index-query.js +46 -0
- package/dist/index.d.ts +8 -3
- package/dist/index.js +77 -26
- package/dist/partition.d.ts +26 -7
- package/dist/partition.js +92 -31
- package/package.json +1 -1
- package/dist/model.js +0 -102
package/README.md
CHANGED
|
@@ -12,7 +12,6 @@ npm install dynoquery
|
|
|
12
12
|
|
|
13
13
|
- Basic CRUD operations (create, get, update, delete)
|
|
14
14
|
- Optimized for **Single-Table Design**
|
|
15
|
-
- Model-based approach for easy data management
|
|
16
15
|
- Query and Scan support
|
|
17
16
|
- Batch operations (batchGet, batchWrite)
|
|
18
17
|
- TypeScript support
|
|
@@ -31,9 +30,10 @@ const db = new DynoQuery({
|
|
|
31
30
|
// optional endpoint for local development
|
|
32
31
|
// endpoint: 'http://localhost:8000'
|
|
33
32
|
partitions: {
|
|
34
|
-
User: { pkPrefix: 'USER#' },
|
|
33
|
+
User: { pkPrefix: 'USER#' }, // TENANT#A#USER#
|
|
35
34
|
},
|
|
36
35
|
indexes: {
|
|
36
|
+
// TENANT#A#CAT#
|
|
37
37
|
ByCategory: { indexName: 'GSI1', pkPrefix: 'CAT#' } // pkName defaults to GSI1PK, skName defaults to GSI1SK
|
|
38
38
|
}
|
|
39
39
|
});
|
|
@@ -66,14 +66,23 @@ async function example() {
|
|
|
66
66
|
console.log(userMetadata);
|
|
67
67
|
|
|
68
68
|
// Create an item through partition
|
|
69
|
-
|
|
69
|
+
await john.create('PROFILE', { name: 'John Doe', email: 'john@example.com' });
|
|
70
70
|
|
|
71
|
-
//
|
|
72
|
-
|
|
71
|
+
// You can also use getPkValue() to get the generated PK for the partition or index
|
|
72
|
+
// This is useful when you need to store it in another attribute (e.g., GSI)
|
|
73
|
+
const cat = db.ByCategory('USER');
|
|
74
|
+
await john.create('PROFILE', {
|
|
75
|
+
name: 'John Doe',
|
|
76
|
+
email: 'john@example.com',
|
|
77
|
+
GSI1PK: cat.getPkValue(),
|
|
78
|
+
GSI1SK: 'john@example.com'
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
// Update the item (updates both DB and partition cache)
|
|
82
|
+
await john.update('PROFILE', { theme: 'dark' });
|
|
73
83
|
|
|
74
|
-
//
|
|
75
|
-
|
|
76
|
-
await metaModel.save({ lastLogin: new Date().toISOString() });
|
|
84
|
+
// Delete an item
|
|
85
|
+
await john.delete('METADATA');
|
|
77
86
|
|
|
78
87
|
// Advanced Partition usage (Subclassing)
|
|
79
88
|
class UserPartition extends Partition {
|
|
@@ -88,6 +97,48 @@ async function example() {
|
|
|
88
97
|
}
|
|
89
98
|
```
|
|
90
99
|
|
|
100
|
+
### Batch Operations
|
|
101
|
+
|
|
102
|
+
If you have a `tableName` configured in `DynoQuery`, you can use the `Items` property in `batchGet` and `batchWrite` to automatically target that table.
|
|
103
|
+
|
|
104
|
+
You can also generate items for `batchGet` using the `batchGetInput` method from partitions and indexes:
|
|
105
|
+
|
|
106
|
+
```typescript
|
|
107
|
+
const john = db.User('john@example.com');
|
|
108
|
+
const jack = db.User('jack@example.com');
|
|
109
|
+
const cat = db.ByCategory('1');
|
|
110
|
+
|
|
111
|
+
const batchItem1 = john.batchGetInput('METADATA');
|
|
112
|
+
const batchOthers = cat.batchGetInput('METADATA', 'DATA', 'PROFILE');
|
|
113
|
+
const batchCat = cat.batchGetInput(); // No sk defined, so will get partition key only
|
|
114
|
+
|
|
115
|
+
await db.batchGet(batchItem1, batchOthers, batchCat);
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
```typescript
|
|
119
|
+
// batchGet with explicit Items
|
|
120
|
+
await db.batchGet({
|
|
121
|
+
Items: [
|
|
122
|
+
{ PK: 'USER#1', SK: 'METADATA' },
|
|
123
|
+
{ PK: 'USER#2', SK: 'METADATA' }
|
|
124
|
+
]
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
// batchWrite with simplified Items (automatically wrapped in PutRequest)
|
|
128
|
+
await db.batchWrite({
|
|
129
|
+
Items: [
|
|
130
|
+
{ PK: 'USER#3', SK: 'METADATA', name: 'Alice' },
|
|
131
|
+
{
|
|
132
|
+
DeleteRequest: {
|
|
133
|
+
Key: { PK: 'USER#1', SK: 'SESSION#123' }
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
]
|
|
137
|
+
});
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
You can still use the standard AWS SDK `RequestItems` if you need to target multiple tables or if you prefer the original syntax.
|
|
141
|
+
|
|
91
142
|
## API Reference
|
|
92
143
|
|
|
93
144
|
### DynoQuery
|
|
@@ -101,25 +152,27 @@ The main client for interacting with DynamoDB.
|
|
|
101
152
|
- `batchGet(params)`: Batch get items.
|
|
102
153
|
- `batchWrite(params)`: Batch write items.
|
|
103
154
|
|
|
104
|
-
### Model
|
|
105
|
-
A model-based abstraction for a specific data type.
|
|
106
|
-
- `find(id?)`: Find an item by ID (PK suffix).
|
|
107
|
-
- `save(data, id?)`: Save an item.
|
|
108
|
-
- `update(data, id?)`: Update an existing item (partial update).
|
|
109
|
-
- `remove(id?)`: Delete an item.
|
|
110
|
-
|
|
111
155
|
### Partition
|
|
112
|
-
A way to manage
|
|
156
|
+
A way to manage data within a specific partition.
|
|
157
|
+
- `getPkValue()`: Returns the generated partition key value.
|
|
113
158
|
- `get(sk)`: Fetches data for a specific sort key (returns a Promise).
|
|
114
159
|
- `getAll()`: Fetches all items in the partition and caches them. Returns the items.
|
|
115
|
-
- `create(sk, data)`: Creates an item in the partition
|
|
116
|
-
- `
|
|
160
|
+
- `create(sk, data)`: Creates an item in the partition.
|
|
161
|
+
- `update(sk, data)`: Updates an existing item (partial update).
|
|
162
|
+
- `delete(sk)`: Deletes an item.
|
|
163
|
+
- `batchGetInput(...sks)`: Generates items for batch query.
|
|
164
|
+
- `batchWriteInput(...items)`: Generates items for batch write.
|
|
165
|
+
- `batchDeleteInput(...sks)`: Generates items for batch delete.
|
|
117
166
|
- `deleteAll()`: Deletes all items in the partition.
|
|
118
167
|
|
|
119
168
|
### IndexQuery
|
|
120
169
|
A way to query Global Secondary Indexes.
|
|
170
|
+
- `getPkValue()`: Returns the generated partition key value for this index.
|
|
121
171
|
- `get(skValue | options)`: Query items in the index. Supports `skValue` (string) for `begins_with` search, or an options object with `skValue`, `limit`, and `scanIndexForward`.
|
|
122
172
|
- `getAll()`: Fetches all items in the index for the given partition key.
|
|
173
|
+
- `batchGetInput(...sks)`: Generates items for batch query.
|
|
174
|
+
- `batchWriteInput(...items)`: Generates items for batch write.
|
|
175
|
+
- `batchDeleteInput(...sks)`: Generates items for batch delete.
|
|
123
176
|
- Automatically identifies models in results using `__model` and provides `getPartition()` helper.
|
|
124
177
|
|
|
125
178
|
## License
|
package/dist/index-query.d.ts
CHANGED
|
@@ -21,5 +21,18 @@ export declare class IndexQuery {
|
|
|
21
21
|
scanIndexForward?: boolean;
|
|
22
22
|
}): Promise<T[]>;
|
|
23
23
|
getAll<T = any>(): Promise<T[]>;
|
|
24
|
+
getPkValue(): string;
|
|
25
|
+
/**
|
|
26
|
+
* Generates items for batch query.
|
|
27
|
+
*/
|
|
28
|
+
batchGetInput(...sks: string[]): any[];
|
|
29
|
+
/**
|
|
30
|
+
* Generates items for batch write (put).
|
|
31
|
+
*/
|
|
32
|
+
batchWriteInput(...items: any[]): any[];
|
|
33
|
+
/**
|
|
34
|
+
* Generates items for batch delete.
|
|
35
|
+
*/
|
|
36
|
+
batchDeleteInput(...sks: string[]): any[];
|
|
24
37
|
private mapItemToModel;
|
|
25
38
|
}
|
package/dist/index-query.js
CHANGED
|
@@ -68,6 +68,52 @@ class IndexQuery {
|
|
|
68
68
|
return this.get();
|
|
69
69
|
});
|
|
70
70
|
}
|
|
71
|
+
getPkValue() {
|
|
72
|
+
return this.pkValue;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Generates items for batch query.
|
|
76
|
+
*/
|
|
77
|
+
batchGetInput(...sks) {
|
|
78
|
+
if (sks.length === 0) {
|
|
79
|
+
return [{
|
|
80
|
+
TableName: this.tableName,
|
|
81
|
+
Key: { [this.pkName]: this.pkValue }
|
|
82
|
+
}];
|
|
83
|
+
}
|
|
84
|
+
return sks.map(sk => ({
|
|
85
|
+
TableName: this.tableName,
|
|
86
|
+
Key: {
|
|
87
|
+
[this.pkName]: this.pkValue,
|
|
88
|
+
[this.skName]: sk
|
|
89
|
+
}
|
|
90
|
+
}));
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Generates items for batch write (put).
|
|
94
|
+
*/
|
|
95
|
+
batchWriteInput(...items) {
|
|
96
|
+
return items.map(item => ({
|
|
97
|
+
TableName: this.tableName,
|
|
98
|
+
PutRequest: {
|
|
99
|
+
Item: Object.assign({ [this.pkName]: this.pkValue }, item)
|
|
100
|
+
}
|
|
101
|
+
}));
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Generates items for batch delete.
|
|
105
|
+
*/
|
|
106
|
+
batchDeleteInput(...sks) {
|
|
107
|
+
return sks.map(sk => ({
|
|
108
|
+
TableName: this.tableName,
|
|
109
|
+
DeleteRequest: {
|
|
110
|
+
Key: {
|
|
111
|
+
[this.pkName]: this.pkValue,
|
|
112
|
+
[this.skName]: sk
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}));
|
|
116
|
+
}
|
|
71
117
|
mapItemToModel(item) {
|
|
72
118
|
const pkName = this.db.getPkName();
|
|
73
119
|
const pkValue = item[pkName];
|
package/dist/index.d.ts
CHANGED
|
@@ -21,6 +21,12 @@ export interface DynoQueryConfig {
|
|
|
21
21
|
pkPrefix?: string;
|
|
22
22
|
}>;
|
|
23
23
|
}
|
|
24
|
+
export type BatchGetInput = BatchGetCommandInput & {
|
|
25
|
+
Items?: any[];
|
|
26
|
+
};
|
|
27
|
+
export type BatchWriteInput = BatchWriteCommandInput & {
|
|
28
|
+
Items?: any[];
|
|
29
|
+
};
|
|
24
30
|
export declare class DynoQuery {
|
|
25
31
|
private client;
|
|
26
32
|
private docClient;
|
|
@@ -58,11 +64,11 @@ export declare class DynoQuery {
|
|
|
58
64
|
/**
|
|
59
65
|
* Get multiple items by their primary keys.
|
|
60
66
|
*/
|
|
61
|
-
batchGet(params:
|
|
67
|
+
batchGet(params: BatchGetInput | any, ...additionalItems: any[][]): Promise<import("@aws-sdk/lib-dynamodb").BatchGetCommandOutput>;
|
|
62
68
|
/**
|
|
63
69
|
* Put or delete multiple items in one or more tables.
|
|
64
70
|
*/
|
|
65
|
-
batchWrite(params:
|
|
71
|
+
batchWrite(params: BatchWriteInput): Promise<import("@aws-sdk/lib-dynamodb").BatchWriteCommandOutput>;
|
|
66
72
|
getTableName(): string | undefined;
|
|
67
73
|
getPkPrefix(): string;
|
|
68
74
|
getPkName(): string;
|
|
@@ -71,6 +77,5 @@ export declare class DynoQuery {
|
|
|
71
77
|
pkPrefix: string;
|
|
72
78
|
}>;
|
|
73
79
|
}
|
|
74
|
-
export * from "./model";
|
|
75
80
|
export * from "./partition";
|
|
76
81
|
export * from "./index-query";
|
package/dist/index.js
CHANGED
|
@@ -22,6 +22,17 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
22
22
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
23
23
|
});
|
|
24
24
|
};
|
|
25
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
26
|
+
var t = {};
|
|
27
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
28
|
+
t[p] = s[p];
|
|
29
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
30
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
31
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
32
|
+
t[p[i]] = s[p[i]];
|
|
33
|
+
}
|
|
34
|
+
return t;
|
|
35
|
+
};
|
|
25
36
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
37
|
exports.DynoQuery = void 0;
|
|
27
38
|
const client_dynamodb_1 = require("@aws-sdk/client-dynamodb");
|
|
@@ -30,35 +41,28 @@ const partition_1 = require("./partition");
|
|
|
30
41
|
class DynoQuery {
|
|
31
42
|
constructor(config = {}) {
|
|
32
43
|
this.registeredPartitions = {};
|
|
33
|
-
const clientConfig =
|
|
34
|
-
// Remove properties that are not part of DynamoDBClientConfig
|
|
35
|
-
delete clientConfig.tableName;
|
|
36
|
-
delete clientConfig.pkPrefix;
|
|
37
|
-
delete clientConfig.partitions;
|
|
38
|
-
delete clientConfig.indexes;
|
|
39
|
-
delete clientConfig.pkName;
|
|
40
|
-
delete clientConfig.skName;
|
|
44
|
+
const { tableName, pkName, skName, pkPrefix, partitions, indexes } = config, clientConfig = __rest(config, ["tableName", "pkName", "skName", "pkPrefix", "partitions", "indexes"]);
|
|
41
45
|
this.client = new client_dynamodb_1.DynamoDBClient(clientConfig);
|
|
42
46
|
this.docClient = lib_dynamodb_1.DynamoDBDocumentClient.from(this.client, {
|
|
43
47
|
marshallOptions: {
|
|
44
48
|
removeUndefinedValues: true,
|
|
45
49
|
}
|
|
46
50
|
});
|
|
47
|
-
this.defaultTableName =
|
|
48
|
-
this.globalPkPrefix =
|
|
49
|
-
this.pkName =
|
|
50
|
-
this.skName =
|
|
51
|
-
if (
|
|
52
|
-
this.registeredPartitions =
|
|
53
|
-
Object.entries(
|
|
51
|
+
this.defaultTableName = tableName;
|
|
52
|
+
this.globalPkPrefix = pkPrefix || "";
|
|
53
|
+
this.pkName = pkName || "PK";
|
|
54
|
+
this.skName = skName || "SK";
|
|
55
|
+
if (partitions) {
|
|
56
|
+
this.registeredPartitions = partitions;
|
|
57
|
+
Object.entries(partitions).forEach(([name, def]) => {
|
|
54
58
|
this[name] = (id) => {
|
|
55
59
|
return new partition_1.Partition(this, { pkPrefix: this.globalPkPrefix + def.pkPrefix }, id);
|
|
56
60
|
};
|
|
57
61
|
});
|
|
58
62
|
}
|
|
59
|
-
if (
|
|
63
|
+
if (indexes) {
|
|
60
64
|
const { IndexQuery } = require("./index-query");
|
|
61
|
-
Object.entries(
|
|
65
|
+
Object.entries(indexes).forEach(([name, def]) => {
|
|
62
66
|
this[name] = (id) => {
|
|
63
67
|
return new IndexQuery(this, {
|
|
64
68
|
indexName: def.indexName,
|
|
@@ -146,16 +150,46 @@ class DynoQuery {
|
|
|
146
150
|
/**
|
|
147
151
|
* Get multiple items by their primary keys.
|
|
148
152
|
*/
|
|
149
|
-
batchGet(params) {
|
|
153
|
+
batchGet(params, ...additionalItems) {
|
|
150
154
|
return __awaiter(this, void 0, void 0, function* () {
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
//
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
155
|
+
let finalParams;
|
|
156
|
+
if (params && !params.RequestItems && !params.Items && (Array.isArray(params) || additionalItems.length > 0)) {
|
|
157
|
+
// Handle the case where arguments are multiple arrays of items
|
|
158
|
+
const allItems = Array.isArray(params) ? [...params] : [];
|
|
159
|
+
additionalItems.forEach(chunk => {
|
|
160
|
+
if (Array.isArray(chunk)) {
|
|
161
|
+
allItems.push(...chunk);
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
allItems.push(chunk);
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
finalParams = {
|
|
168
|
+
Items: allItems
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
finalParams = params;
|
|
157
173
|
}
|
|
158
|
-
|
|
174
|
+
if (!finalParams.RequestItems && finalParams.Items) {
|
|
175
|
+
finalParams.RequestItems = {};
|
|
176
|
+
finalParams.Items.forEach((item) => {
|
|
177
|
+
const tableName = item.TableName || this.defaultTableName;
|
|
178
|
+
if (!tableName) {
|
|
179
|
+
throw new Error("TableName must be provided for batch operations if no default tableName is set");
|
|
180
|
+
}
|
|
181
|
+
if (!finalParams.RequestItems[tableName]) {
|
|
182
|
+
finalParams.RequestItems[tableName] = { Keys: [] };
|
|
183
|
+
}
|
|
184
|
+
const key = item.Key || item;
|
|
185
|
+
finalParams.RequestItems[tableName].Keys.push(key);
|
|
186
|
+
});
|
|
187
|
+
delete finalParams.Items;
|
|
188
|
+
}
|
|
189
|
+
else if (!finalParams.RequestItems && this.defaultTableName) {
|
|
190
|
+
finalParams.RequestItems = {};
|
|
191
|
+
}
|
|
192
|
+
const command = new lib_dynamodb_1.BatchGetCommand(finalParams);
|
|
159
193
|
return yield this.docClient.send(command);
|
|
160
194
|
});
|
|
161
195
|
}
|
|
@@ -164,6 +198,24 @@ class DynoQuery {
|
|
|
164
198
|
*/
|
|
165
199
|
batchWrite(params) {
|
|
166
200
|
return __awaiter(this, void 0, void 0, function* () {
|
|
201
|
+
if (!params.RequestItems && params.Items) {
|
|
202
|
+
params.RequestItems = {};
|
|
203
|
+
params.Items.forEach((item) => {
|
|
204
|
+
const tableName = item.TableName || this.defaultTableName;
|
|
205
|
+
if (!tableName) {
|
|
206
|
+
throw new Error("TableName must be provided for batch operations if no default tableName is set");
|
|
207
|
+
}
|
|
208
|
+
if (!params.RequestItems[tableName]) {
|
|
209
|
+
params.RequestItems[tableName] = [];
|
|
210
|
+
}
|
|
211
|
+
const request = item.PutRequest || item.DeleteRequest ? item : { PutRequest: { Item: item } };
|
|
212
|
+
params.RequestItems[tableName].push(request);
|
|
213
|
+
});
|
|
214
|
+
delete params.Items;
|
|
215
|
+
}
|
|
216
|
+
else if (!params.RequestItems && this.defaultTableName) {
|
|
217
|
+
params.RequestItems = {};
|
|
218
|
+
}
|
|
167
219
|
const command = new lib_dynamodb_1.BatchWriteCommand(params);
|
|
168
220
|
return yield this.docClient.send(command);
|
|
169
221
|
});
|
|
@@ -185,6 +237,5 @@ class DynoQuery {
|
|
|
185
237
|
}
|
|
186
238
|
}
|
|
187
239
|
exports.DynoQuery = DynoQuery;
|
|
188
|
-
__exportStar(require("./model"), exports);
|
|
189
240
|
__exportStar(require("./partition"), exports);
|
|
190
241
|
__exportStar(require("./index-query"), exports);
|
package/dist/partition.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { DynoQuery } from "./index";
|
|
2
|
-
import { Model } from "./model";
|
|
3
2
|
export interface PartitionConfig {
|
|
4
3
|
tableName?: string;
|
|
5
4
|
pk?: string;
|
|
@@ -8,7 +7,7 @@ export interface PartitionConfig {
|
|
|
8
7
|
export declare class Partition {
|
|
9
8
|
protected db: DynoQuery;
|
|
10
9
|
protected tableName?: string;
|
|
11
|
-
protected
|
|
10
|
+
protected pkValue: string;
|
|
12
11
|
protected pkName: string;
|
|
13
12
|
protected skName: string;
|
|
14
13
|
protected cache: Record<string, any>;
|
|
@@ -20,20 +19,40 @@ export declare class Partition {
|
|
|
20
19
|
*/
|
|
21
20
|
getAll<T = any>(): Promise<T[]>;
|
|
22
21
|
/**
|
|
23
|
-
*
|
|
22
|
+
* Create an item in this partition.
|
|
24
23
|
*/
|
|
25
|
-
|
|
26
|
-
getPK(): string;
|
|
24
|
+
create<T = any>(sk: string, data: T): Promise<void>;
|
|
27
25
|
/**
|
|
28
|
-
*
|
|
26
|
+
* Update an existing item in this partition.
|
|
29
27
|
*/
|
|
30
|
-
|
|
28
|
+
update<T = any>(sk: string, data: Partial<T>): Promise<void>;
|
|
29
|
+
/**
|
|
30
|
+
* Delete an item by its SK within this partition.
|
|
31
|
+
*/
|
|
32
|
+
delete(sk: string): Promise<void>;
|
|
31
33
|
/**
|
|
32
34
|
* Get data for a specific SK within this partition.
|
|
33
35
|
* If the partition is loaded, it returns from cache.
|
|
34
36
|
* Otherwise, it fetches the data immediately.
|
|
35
37
|
*/
|
|
36
38
|
get<T = any>(sk: string): Promise<T | null>;
|
|
39
|
+
getPkValue(): string;
|
|
40
|
+
/**
|
|
41
|
+
* Generates items for batch query.
|
|
42
|
+
* If no SKs are provided, it might not be very useful for batchGet (which requires full keys),
|
|
43
|
+
* but the requirement says "will get all by pkValue" if no sk defined.
|
|
44
|
+
* Actually, BatchGetItem requires both PK and SK if the table has both.
|
|
45
|
+
* If it's for IndexQuery, it might be different.
|
|
46
|
+
*/
|
|
47
|
+
batchGetInput(...sks: string[]): any[];
|
|
48
|
+
/**
|
|
49
|
+
* Generates items for batch write (put).
|
|
50
|
+
*/
|
|
51
|
+
batchWriteInput(...items: any[]): any[];
|
|
52
|
+
/**
|
|
53
|
+
* Generates items for batch delete.
|
|
54
|
+
*/
|
|
55
|
+
batchDeleteInput(...sks: string[]): any[];
|
|
37
56
|
/**
|
|
38
57
|
* Delete all data in this partition.
|
|
39
58
|
*/
|
package/dist/partition.js
CHANGED
|
@@ -10,7 +10,6 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.Partition = void 0;
|
|
13
|
-
const model_1 = require("./model");
|
|
14
13
|
class Partition {
|
|
15
14
|
constructor(db, config, id) {
|
|
16
15
|
this.cache = {};
|
|
@@ -20,7 +19,7 @@ class Partition {
|
|
|
20
19
|
this.pkName = db.getPkName();
|
|
21
20
|
this.skName = db.getSkName();
|
|
22
21
|
if (config.pk) {
|
|
23
|
-
this.
|
|
22
|
+
this.pkValue = config.pk;
|
|
24
23
|
}
|
|
25
24
|
else {
|
|
26
25
|
const globalPrefix = db.getPkPrefix();
|
|
@@ -41,10 +40,10 @@ class Partition {
|
|
|
41
40
|
if (globalPrefix && !partitionPrefix.startsWith(globalPrefix)) {
|
|
42
41
|
finalPrefix = globalPrefix + partitionPrefix;
|
|
43
42
|
}
|
|
44
|
-
this.
|
|
43
|
+
this.pkValue = `${finalPrefix}${id || ""}`;
|
|
45
44
|
}
|
|
46
45
|
else {
|
|
47
|
-
throw new Error("Either
|
|
46
|
+
throw new Error("Either pkValue or pkPrefix must be provided in PartitionConfig");
|
|
48
47
|
}
|
|
49
48
|
}
|
|
50
49
|
if (!this.tableName) {
|
|
@@ -64,7 +63,7 @@ class Partition {
|
|
|
64
63
|
"#pk": this.pkName,
|
|
65
64
|
},
|
|
66
65
|
ExpressionAttributeValues: {
|
|
67
|
-
":pk": this.
|
|
66
|
+
":pk": this.pkValue,
|
|
68
67
|
},
|
|
69
68
|
});
|
|
70
69
|
const items = (response.Items || []);
|
|
@@ -78,35 +77,41 @@ class Partition {
|
|
|
78
77
|
});
|
|
79
78
|
}
|
|
80
79
|
/**
|
|
81
|
-
*
|
|
80
|
+
* Create an item in this partition.
|
|
82
81
|
*/
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
else {
|
|
93
|
-
this.cache[updatedSk] = data;
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
};
|
|
97
|
-
return new model_1.Model(this.db, config);
|
|
82
|
+
create(sk, data) {
|
|
83
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
84
|
+
const item = Object.assign({ [this.pkName]: this.pkValue, [this.skName]: sk }, data);
|
|
85
|
+
yield this.db.create({
|
|
86
|
+
TableName: this.tableName,
|
|
87
|
+
Item: item,
|
|
88
|
+
});
|
|
89
|
+
this.cache[sk] = item;
|
|
90
|
+
});
|
|
98
91
|
}
|
|
99
|
-
|
|
100
|
-
|
|
92
|
+
/**
|
|
93
|
+
* Update an existing item in this partition.
|
|
94
|
+
*/
|
|
95
|
+
update(sk, data) {
|
|
96
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
97
|
+
const current = (yield this.get(sk)) || {};
|
|
98
|
+
const updated = Object.assign(Object.assign({}, current), data);
|
|
99
|
+
yield this.create(sk, updated);
|
|
100
|
+
});
|
|
101
101
|
}
|
|
102
102
|
/**
|
|
103
|
-
*
|
|
103
|
+
* Delete an item by its SK within this partition.
|
|
104
104
|
*/
|
|
105
|
-
|
|
105
|
+
delete(sk) {
|
|
106
106
|
return __awaiter(this, void 0, void 0, function* () {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
107
|
+
yield this.db.delete({
|
|
108
|
+
TableName: this.tableName,
|
|
109
|
+
Key: {
|
|
110
|
+
[this.pkName]: this.pkValue,
|
|
111
|
+
[this.skName]: sk,
|
|
112
|
+
},
|
|
113
|
+
});
|
|
114
|
+
delete this.cache[sk];
|
|
110
115
|
});
|
|
111
116
|
}
|
|
112
117
|
/**
|
|
@@ -122,14 +127,70 @@ class Partition {
|
|
|
122
127
|
if (this.isLoaded) {
|
|
123
128
|
return null;
|
|
124
129
|
}
|
|
125
|
-
const
|
|
126
|
-
|
|
130
|
+
const response = yield this.db.get({
|
|
131
|
+
TableName: this.tableName,
|
|
132
|
+
Key: {
|
|
133
|
+
[this.pkName]: this.pkValue,
|
|
134
|
+
[this.skName]: sk,
|
|
135
|
+
},
|
|
136
|
+
});
|
|
137
|
+
const data = response.Item || null;
|
|
127
138
|
if (data) {
|
|
128
139
|
this.cache[sk] = data;
|
|
129
140
|
}
|
|
130
141
|
return data;
|
|
131
142
|
});
|
|
132
143
|
}
|
|
144
|
+
getPkValue() {
|
|
145
|
+
return this.pkValue;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Generates items for batch query.
|
|
149
|
+
* If no SKs are provided, it might not be very useful for batchGet (which requires full keys),
|
|
150
|
+
* but the requirement says "will get all by pkValue" if no sk defined.
|
|
151
|
+
* Actually, BatchGetItem requires both PK and SK if the table has both.
|
|
152
|
+
* If it's for IndexQuery, it might be different.
|
|
153
|
+
*/
|
|
154
|
+
batchGetInput(...sks) {
|
|
155
|
+
if (sks.length === 0) {
|
|
156
|
+
return [{
|
|
157
|
+
TableName: this.tableName,
|
|
158
|
+
Key: { [this.pkName]: this.pkValue }
|
|
159
|
+
}];
|
|
160
|
+
}
|
|
161
|
+
return sks.map(sk => ({
|
|
162
|
+
TableName: this.tableName,
|
|
163
|
+
Key: {
|
|
164
|
+
[this.pkName]: this.pkValue,
|
|
165
|
+
[this.skName]: sk
|
|
166
|
+
}
|
|
167
|
+
}));
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Generates items for batch write (put).
|
|
171
|
+
*/
|
|
172
|
+
batchWriteInput(...items) {
|
|
173
|
+
return items.map(item => ({
|
|
174
|
+
TableName: this.tableName,
|
|
175
|
+
PutRequest: {
|
|
176
|
+
Item: Object.assign({ [this.pkName]: this.pkValue }, item)
|
|
177
|
+
}
|
|
178
|
+
}));
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Generates items for batch delete.
|
|
182
|
+
*/
|
|
183
|
+
batchDeleteInput(...sks) {
|
|
184
|
+
return sks.map(sk => ({
|
|
185
|
+
TableName: this.tableName,
|
|
186
|
+
DeleteRequest: {
|
|
187
|
+
Key: {
|
|
188
|
+
[this.pkName]: this.pkValue,
|
|
189
|
+
[this.skName]: sk
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}));
|
|
193
|
+
}
|
|
133
194
|
/**
|
|
134
195
|
* Delete all data in this partition.
|
|
135
196
|
*/
|
|
@@ -142,7 +203,7 @@ class Partition {
|
|
|
142
203
|
"#pk": this.pkName,
|
|
143
204
|
},
|
|
144
205
|
ExpressionAttributeValues: {
|
|
145
|
-
":pk": this.
|
|
206
|
+
":pk": this.pkValue,
|
|
146
207
|
},
|
|
147
208
|
});
|
|
148
209
|
if (response.Items && response.Items.length > 0) {
|
package/package.json
CHANGED
package/dist/model.js
DELETED
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
-
});
|
|
10
|
-
};
|
|
11
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
exports.Model = void 0;
|
|
13
|
-
class Model {
|
|
14
|
-
constructor(db, config) {
|
|
15
|
-
this.db = db;
|
|
16
|
-
this.tableName = config.tableName || db.getTableName();
|
|
17
|
-
this.pkPrefix = config.pkPrefix;
|
|
18
|
-
this.skValue = config.skValue;
|
|
19
|
-
this.pkName = db.getPkName();
|
|
20
|
-
this.skName = db.getSkName();
|
|
21
|
-
this.onUpdate = config.onUpdate;
|
|
22
|
-
if (!this.tableName) {
|
|
23
|
-
throw new Error("TableName must be provided in ModelConfig or DynoQueryConfig");
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
getTableName() {
|
|
27
|
-
return this.tableName;
|
|
28
|
-
}
|
|
29
|
-
getPK(id = "") {
|
|
30
|
-
return `${this.pkPrefix}${id}`;
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* Find an item by its identifier (part of the PK).
|
|
34
|
-
* Assumes the SK is fixed as defined in ModelConfig.
|
|
35
|
-
*/
|
|
36
|
-
find() {
|
|
37
|
-
return __awaiter(this, arguments, void 0, function* (id = "") {
|
|
38
|
-
const response = yield this.db.get({
|
|
39
|
-
TableName: this.getTableName(),
|
|
40
|
-
Key: {
|
|
41
|
-
[this.pkName]: this.getPK(id),
|
|
42
|
-
[this.skName]: this.skValue,
|
|
43
|
-
},
|
|
44
|
-
});
|
|
45
|
-
return response.Item || null;
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
/**
|
|
49
|
-
* Save an item.
|
|
50
|
-
*/
|
|
51
|
-
save(data_1) {
|
|
52
|
-
return __awaiter(this, arguments, void 0, function* (data, id = "") {
|
|
53
|
-
const item = Object.assign({ [this.pkName]: this.getPK(id), [this.skName]: this.skValue }, data);
|
|
54
|
-
yield this.db.create({
|
|
55
|
-
TableName: this.getTableName(),
|
|
56
|
-
Item: item,
|
|
57
|
-
});
|
|
58
|
-
if (this.onUpdate) {
|
|
59
|
-
this.onUpdate(this.skValue, item);
|
|
60
|
-
}
|
|
61
|
-
});
|
|
62
|
-
}
|
|
63
|
-
/**
|
|
64
|
-
* Update an existing item.
|
|
65
|
-
*/
|
|
66
|
-
update(data_1) {
|
|
67
|
-
return __awaiter(this, arguments, void 0, function* (data, id = "") {
|
|
68
|
-
// For simplicity in this wrapper, we use create (PutItem) to update the whole item
|
|
69
|
-
// but the user might expect a partial update if we use UpdateCommand.
|
|
70
|
-
// However, for single table and this kind of wrapper, often we just put the whole item.
|
|
71
|
-
// If we want to support partial updates in the cache, we need the current item.
|
|
72
|
-
const response = yield this.db.get({
|
|
73
|
-
TableName: this.getTableName(),
|
|
74
|
-
Key: {
|
|
75
|
-
[this.pkName]: this.getPK(id),
|
|
76
|
-
[this.skName]: this.skValue,
|
|
77
|
-
},
|
|
78
|
-
});
|
|
79
|
-
const current = response.Item || {};
|
|
80
|
-
const updated = Object.assign(Object.assign({}, current), data);
|
|
81
|
-
yield this.save(updated, id);
|
|
82
|
-
});
|
|
83
|
-
}
|
|
84
|
-
/**
|
|
85
|
-
* Delete an item by its identifier.
|
|
86
|
-
*/
|
|
87
|
-
remove() {
|
|
88
|
-
return __awaiter(this, arguments, void 0, function* (id = "") {
|
|
89
|
-
yield this.db.delete({
|
|
90
|
-
TableName: this.getTableName(),
|
|
91
|
-
Key: {
|
|
92
|
-
[this.pkName]: this.getPK(id),
|
|
93
|
-
[this.skName]: this.skValue,
|
|
94
|
-
},
|
|
95
|
-
});
|
|
96
|
-
if (this.onUpdate) {
|
|
97
|
-
this.onUpdate(this.skValue, null);
|
|
98
|
-
}
|
|
99
|
-
});
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
exports.Model = Model;
|