wirejs-deploy-amplify-basic 0.0.68-table-resource → 0.0.70-table-resource
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.
|
@@ -7,7 +7,7 @@ import { Bucket, BlockPublicAccess } from 'aws-cdk-lib/aws-s3';
|
|
|
7
7
|
import { Table, AttributeType, BillingMode } from 'aws-cdk-lib/aws-dynamodb';
|
|
8
8
|
import { api } from './functions/api/resource';
|
|
9
9
|
import { auth } from './auth/resource';
|
|
10
|
-
import {
|
|
10
|
+
import { TableDefinition } from 'wirejs-resources';
|
|
11
11
|
|
|
12
12
|
// @ts-ignore
|
|
13
13
|
import generated from './generated-resources';
|
|
@@ -58,11 +58,7 @@ bucket.grantReadWrite(backend.api.resources.lambda);
|
|
|
58
58
|
*/
|
|
59
59
|
function isDistributedTable(resource: any): resource is {
|
|
60
60
|
type: 'DistributedTable';
|
|
61
|
-
options:
|
|
62
|
-
absoluteId: string;
|
|
63
|
-
partitionKey: KeyFieldDefinition<any, any, any>;
|
|
64
|
-
sortKey: KeyFieldDefinition<any, any, any> | undefined;
|
|
65
|
-
}
|
|
61
|
+
options: TableDefinition;
|
|
66
62
|
} {
|
|
67
63
|
return resource.type === 'DistributedTable';
|
|
68
64
|
}
|
|
@@ -76,6 +72,7 @@ const PKFieldTypes = {
|
|
|
76
72
|
for (const resource of generated) {
|
|
77
73
|
if (isDistributedTable(resource)) {
|
|
78
74
|
const sanitizedId = resource.options.absoluteId.replace(/[^a-zA-Z0-9-_]/g, '_');
|
|
75
|
+
|
|
79
76
|
const table = new Table(backend.stack, sanitizedId, {
|
|
80
77
|
partitionKey: {
|
|
81
78
|
name: resource.options.partitionKey.field,
|
|
@@ -90,6 +87,22 @@ for (const resource of generated) {
|
|
|
90
87
|
billingMode: BillingMode.PAY_PER_REQUEST,
|
|
91
88
|
pointInTimeRecovery: true,
|
|
92
89
|
});
|
|
90
|
+
|
|
91
|
+
for (const index of resource.options.indexes ?? []) {
|
|
92
|
+
const gsi = table.addGlobalSecondaryIndex({
|
|
93
|
+
indexName: `by${index.partition.field}And${index.sort?.field ?? 'None'}`,
|
|
94
|
+
partitionKey: {
|
|
95
|
+
name: index.partition.field,
|
|
96
|
+
type: PKFieldTypes[index.partition.type],
|
|
97
|
+
},
|
|
98
|
+
sortKey: index.sort ? {
|
|
99
|
+
name: index.sort.field,
|
|
100
|
+
type: PKFieldTypes[index.sort.type],
|
|
101
|
+
} : undefined,
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
}
|
|
105
|
+
|
|
93
106
|
table.grantReadWriteData(backend.api.resources.lambda);
|
|
94
107
|
}
|
|
95
108
|
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { DynamoDBClient } from '@aws-sdk/client-dynamodb';
|
|
2
|
-
import {
|
|
3
|
-
export declare function PassThruParser<T>(record: Record<string, any>): T;
|
|
2
|
+
import { AllIndexesByName, KeyCondition, IndexFieldNames, Filter, Index, KindaPretty, Parser, RecordKey, Resource, DistributedTable as BaseDistributedTable } from 'wirejs-resources';
|
|
4
3
|
/**
|
|
5
4
|
* A table of records that favors very high *overall* scalability at the expense of
|
|
6
5
|
* scalability *between* partitions. Providers will distribute your data across many
|
|
@@ -12,31 +11,31 @@ export declare function PassThruParser<T>(record: Record<string, any>): T;
|
|
|
12
11
|
*
|
|
13
12
|
* High cardinality, non-sequential partition keys allow for the best overall scaling.
|
|
14
13
|
*/
|
|
15
|
-
export declare class DistributedTable<const P extends Parser<any>, const T extends ReturnType<P
|
|
14
|
+
export declare class DistributedTable<const P extends Parser<any>, const T extends KindaPretty<ReturnType<P>>, const Key extends Index<T>, const Indexes extends Index<T>[] | undefined = undefined> extends Resource implements Omit<BaseDistributedTable<P, T, Key, Indexes>, '#private'> {
|
|
16
15
|
#private;
|
|
17
16
|
parse: P;
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
key: Key;
|
|
18
|
+
indexes: Indexes | undefined;
|
|
20
19
|
ddbClient: DynamoDBClient;
|
|
21
|
-
table
|
|
20
|
+
private table;
|
|
22
21
|
constructor(scope: Resource | string, id: string, options: {
|
|
23
22
|
parse: P;
|
|
24
|
-
key:
|
|
25
|
-
|
|
26
|
-
sort?: SK;
|
|
27
|
-
};
|
|
23
|
+
key: Key;
|
|
24
|
+
indexes?: Indexes;
|
|
28
25
|
});
|
|
29
|
-
get partitionKeyName():
|
|
30
|
-
get sortKeyName(): 'field' extends
|
|
26
|
+
get partitionKeyName(): Key['partition']['field'];
|
|
27
|
+
get sortKeyName(): 'field' extends keyof Key['sort'] ? (Key['sort']['field'] extends string ? Key['sort']['field'] : undefined) : undefined;
|
|
31
28
|
save(item: T): Promise<void>;
|
|
32
29
|
saveMany(items: T[]): Promise<void>;
|
|
33
|
-
delete(item: RecordKey<T,
|
|
34
|
-
deleteMany(items: (RecordKey<T,
|
|
35
|
-
get(key: RecordKey<T,
|
|
30
|
+
delete(item: RecordKey<T, Key>): Promise<void>;
|
|
31
|
+
deleteMany(items: (RecordKey<T, Key>)[]): Promise<void>;
|
|
32
|
+
get(key: RecordKey<T, Key>): Promise<T | undefined>;
|
|
36
33
|
scan(options?: {
|
|
37
34
|
filter?: Filter<T>;
|
|
38
35
|
}): AsyncGenerator<T>;
|
|
39
|
-
query
|
|
40
|
-
|
|
36
|
+
query<const GivenPartition extends keyof AllIndexesByName<BaseDistributedTable<P, T, Key, Indexes>> & string>(options: {
|
|
37
|
+
by: GivenPartition;
|
|
38
|
+
where: KeyCondition<BaseDistributedTable<P, T, Key, Indexes>, GivenPartition>;
|
|
39
|
+
filter?: Filter<Omit<T, IndexFieldNames<BaseDistributedTable<P, T, Key, Indexes>, GivenPartition> & string>>;
|
|
41
40
|
}): AsyncGenerator<T>;
|
|
42
41
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { env } from 'process';
|
|
2
2
|
import { DynamoDBClient, } from '@aws-sdk/client-dynamodb';
|
|
3
3
|
import { PutCommand, GetCommand, QueryCommand, ScanCommand, DeleteCommand, } from '@aws-sdk/lib-dynamodb';
|
|
4
|
-
import { Resource, } from 'wirejs-resources';
|
|
4
|
+
import { Resource, indexName } from 'wirejs-resources';
|
|
5
5
|
import { addResource } from '../resource-collector.js';
|
|
6
6
|
function isFieldComparison(filter) {
|
|
7
7
|
return !['and', 'or', 'not'].some(key => key in filter);
|
|
@@ -78,9 +78,6 @@ function buildExpressionAttributeValues(filter) {
|
|
|
78
78
|
}
|
|
79
79
|
return values;
|
|
80
80
|
}
|
|
81
|
-
export function PassThruParser(record) {
|
|
82
|
-
return record;
|
|
83
|
-
}
|
|
84
81
|
/**
|
|
85
82
|
* A table of records that favors very high *overall* scalability at the expense of
|
|
86
83
|
* scalability *between* partitions. Providers will distribute your data across many
|
|
@@ -94,28 +91,30 @@ export function PassThruParser(record) {
|
|
|
94
91
|
*/
|
|
95
92
|
export class DistributedTable extends Resource {
|
|
96
93
|
parse;
|
|
97
|
-
|
|
98
|
-
|
|
94
|
+
key;
|
|
95
|
+
indexes;
|
|
99
96
|
ddbClient;
|
|
100
97
|
table;
|
|
101
98
|
constructor(scope, id, options) {
|
|
102
99
|
super(scope, id);
|
|
103
100
|
this.parse = options.parse;
|
|
104
|
-
this.
|
|
105
|
-
this.
|
|
101
|
+
this.key = options.key;
|
|
102
|
+
this.indexes = options.indexes;
|
|
106
103
|
this.ddbClient = new DynamoDBClient();
|
|
107
104
|
this.table = env['TABLE_NAME_PREFIX'] + this.absoluteId.replace(/[^a-zA-Z0-9-_]/g, '_');
|
|
108
|
-
|
|
105
|
+
const resourceDefinition = {
|
|
109
106
|
absoluteId: this.absoluteId,
|
|
110
|
-
partitionKey: this.
|
|
111
|
-
sortKey: this.sort,
|
|
112
|
-
|
|
107
|
+
partitionKey: this.key.partition,
|
|
108
|
+
sortKey: this.key.sort,
|
|
109
|
+
indexes: this.indexes
|
|
110
|
+
};
|
|
111
|
+
addResource('DistributedTable', resourceDefinition);
|
|
113
112
|
}
|
|
114
113
|
get partitionKeyName() {
|
|
115
|
-
return this.
|
|
114
|
+
return this.key.partition.field;
|
|
116
115
|
}
|
|
117
116
|
get sortKeyName() {
|
|
118
|
-
return this.sort?.field;
|
|
117
|
+
return this.key.sort?.field;
|
|
119
118
|
}
|
|
120
119
|
#getDDBKey(key) {
|
|
121
120
|
const ddbKey = {
|
|
@@ -167,10 +166,10 @@ export class DistributedTable extends Resource {
|
|
|
167
166
|
}
|
|
168
167
|
async *scan(options = {}) {
|
|
169
168
|
console.log('Scanning DynamoDB table:', this.table, options);
|
|
169
|
+
const filterExpression = options.filter ? buildFilterExpression(options.filter) : undefined;
|
|
170
|
+
const expressionAttributeValues = options.filter ? buildExpressionAttributeValues(options.filter) : undefined;
|
|
170
171
|
let lastEvaluatedKey = undefined;
|
|
171
172
|
do {
|
|
172
|
-
const filterExpression = options.filter ? buildFilterExpression(options.filter) : undefined;
|
|
173
|
-
const expressionAttributeValues = options.filter ? buildExpressionAttributeValues(options.filter) : undefined;
|
|
174
173
|
const result = await this.ddbClient.send(new ScanCommand({
|
|
175
174
|
TableName: this.table,
|
|
176
175
|
FilterExpression: filterExpression,
|
|
@@ -186,27 +185,40 @@ export class DistributedTable extends Resource {
|
|
|
186
185
|
lastEvaluatedKey = result.LastEvaluatedKey;
|
|
187
186
|
} while (lastEvaluatedKey);
|
|
188
187
|
}
|
|
189
|
-
async *query(
|
|
190
|
-
console.log('Querying DynamoDB table:', this.table,
|
|
188
|
+
async *query(options) {
|
|
189
|
+
console.log('Querying DynamoDB table:', this.table, options);
|
|
190
|
+
// Build the key condition expression from the `where` clause
|
|
191
|
+
const whereClauseAsFilter = {
|
|
192
|
+
// decompose each `where` clause property into a separate condition.
|
|
193
|
+
and: Object.entries(options.where).map(([k, v]) => buildFilterExpression({ [k]: v }))
|
|
194
|
+
};
|
|
195
|
+
const keyConditionExpression = buildFilterExpression(whereClauseAsFilter);
|
|
196
|
+
// Build the filter expression if provided
|
|
197
|
+
const filterExpression = options.filter ? buildFilterExpression(options.filter) : undefined;
|
|
198
|
+
// Combine expression attribute values for both key conditions and filters
|
|
199
|
+
const expressionAttributeValues = {
|
|
200
|
+
...buildExpressionAttributeValues(whereClauseAsFilter),
|
|
201
|
+
...(options.filter ? buildExpressionAttributeValues(options.filter) : {}),
|
|
202
|
+
};
|
|
203
|
+
const isIndexNameTheDefault = options.by === indexName({
|
|
204
|
+
partition: this.key.partition,
|
|
205
|
+
sort: this.key.sort
|
|
206
|
+
});
|
|
191
207
|
let lastEvaluatedKey = undefined;
|
|
192
208
|
do {
|
|
193
|
-
const ddbKey = this.#getDDBKey(partition);
|
|
194
|
-
const filterExpression = options.filter ? buildFilterExpression(options.filter) : undefined;
|
|
195
|
-
const expressionAttributeValues = options.filter ? buildExpressionAttributeValues(options.filter) : undefined;
|
|
196
209
|
const result = await this.ddbClient.send(new QueryCommand({
|
|
197
210
|
TableName: this.table,
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
':partitionKey': ddbKey[this.partitionKeyName],
|
|
201
|
-
...expressionAttributeValues
|
|
202
|
-
},
|
|
211
|
+
IndexName: isIndexNameTheDefault ? undefined : options.by,
|
|
212
|
+
KeyConditionExpression: keyConditionExpression,
|
|
203
213
|
FilterExpression: filterExpression,
|
|
214
|
+
ExpressionAttributeValues: expressionAttributeValues,
|
|
204
215
|
ExclusiveStartKey: lastEvaluatedKey,
|
|
205
216
|
}));
|
|
206
217
|
for (const item of result.Items || []) {
|
|
207
218
|
if (!item)
|
|
208
219
|
continue;
|
|
209
|
-
|
|
220
|
+
const record = this.parse(item);
|
|
221
|
+
yield record;
|
|
210
222
|
}
|
|
211
223
|
lastEvaluatedKey = result.LastEvaluatedKey;
|
|
212
224
|
} while (lastEvaluatedKey);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wirejs-deploy-amplify-basic",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.70-table-resource",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"recursive-copy": "^2.0.14",
|
|
33
33
|
"rimraf": "^6.0.1",
|
|
34
34
|
"wirejs-dom": "^1.0.38",
|
|
35
|
-
"wirejs-resources": "^0.1.
|
|
35
|
+
"wirejs-resources": "^0.1.38-table-resource"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
38
|
"@aws-amplify/backend": "^1.14.0",
|