Skip to content

Commit d20962b

Browse files
committed
refactor(batch-write-single-table): renaming, documentation
1 parent fd32421 commit d20962b

File tree

8 files changed

+47
-40
lines changed

8 files changed

+47
-40
lines changed

src/dynamo/dynamo-store.ts

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { DEFAULT_TABLE_NAME_RESOLVER } from './default-table-name-resolver.const
77
import { DynamoApiOperations } from './dynamo-api-operations.type'
88
import { DynamoRx } from './dynamo-rx'
99
import { BatchGetSingleTableRequest } from './request/batchgetsingletable/batch-get-single-table.request'
10-
import { BatchWriteRequest } from './request/batchwrite/batch-write.request'
10+
import { BatchWriteSingleTableRequest } from './request/batchwritesingletable/batch-write-single-table.request'
1111
import { DeleteRequest } from './request/delete/delete.request'
1212
import { GetRequest } from './request/get/get.request'
1313
import { PutRequest } from './request/put/put.request'
@@ -59,8 +59,13 @@ export class DynamoStore<T> {
5959
return new DeleteRequest(this.dynamoRx, this.modelClazz, this.tableName, partitionKey, sortKey)
6060
}
6161

62-
batchWriteMany(): BatchWriteRequest<T> {
63-
return new BatchWriteRequest<T>(this.dynamoRx, this.modelClazz, this.tableName)
62+
/**
63+
* This is a special implementation of batchWriteItem request, because it only supports one table,
64+
* if you wish to write items to multiple tables
65+
* create an instance of BatchWriteItemInput and use store.makeRequest with it.
66+
*/
67+
batchWrite(): BatchWriteSingleTableRequest<T> {
68+
return new BatchWriteSingleTableRequest<T>(this.dynamoRx, this.modelClazz, this.tableName)
6469
}
6570

6671
scan(): ScanRequest<T> {
@@ -72,8 +77,9 @@ export class DynamoStore<T> {
7277
}
7378

7479
/**
75-
* This is a special implementation of BatchGetItem request, because it only supports one table, if you wish to retrieve items from multiple tables
76-
* get an instance of BatchGetItem request and call it there.
80+
* This is a special implementation of BatchGetItem request, because it only supports one table,
81+
* if you wish to retrieve items from multiple tables
82+
* create an instance of BatchGetItemInput and use store.makeRequest with it.
7783
*/
7884
batchGetItem(keys: any[]): BatchGetSingleTableRequest<T> {
7985
return new BatchGetSingleTableRequest(this.dynamoRx, this.modelClazz, this.tableName, keys)

src/dynamo/request/batchwrite/batch-write.request.spec.ts renamed to src/dynamo/request/batchwritesingletable/batch-write-single-table.request.spec.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,17 @@ import { getTableName } from '../../../../test/helper/get-table-name.function'
55
import { Organization } from '../../../../test/models/organization.model'
66
import { DEFAULT_SESSION_VALIDITY_ENSURER } from '../../default-session-validity-ensurer.const'
77
import { DynamoRx } from '../../dynamo-rx'
8-
import { BatchWriteRequest } from './batch-write.request'
8+
import { BatchWriteSingleTableRequest } from './batch-write-single-table.request'
99

10-
describe('batch write many', () => {
10+
describe('batch write single table request', () => {
1111
const tableName = getTableName(Organization)
1212

1313
let item: Organization
1414
let dynamoRx: DynamoRx
15-
let request: BatchWriteRequest<Organization>
15+
let request: BatchWriteSingleTableRequest<Organization>
1616

1717
let nextSpyFn: () => { value: number }
18-
const generatorMock = (i: number) => <any>{ next: nextSpyFn }
18+
const generatorMock = () => <any>{ next: nextSpyFn }
1919

2020
beforeEach(() => {
2121
item = <any>{
@@ -29,7 +29,7 @@ describe('batch write many', () => {
2929
describe('correct params', () => {
3030
beforeEach(() => {
3131
dynamoRx = new DynamoRx(DEFAULT_SESSION_VALIDITY_ENSURER)
32-
request = new BatchWriteRequest(dynamoRx, Organization, tableName)
32+
request = new BatchWriteSingleTableRequest(dynamoRx, Organization, tableName)
3333

3434
const output: DynamoDB.BatchWriteItemOutput = {}
3535
spyOn(dynamoRx, 'batchWriteItem').and.returnValue(of(output))
@@ -96,7 +96,7 @@ describe('batch write many', () => {
9696
describe('correct backoff', () => {
9797
beforeEach(() => {
9898
dynamoRx = new DynamoRx(DEFAULT_SESSION_VALIDITY_ENSURER)
99-
request = new BatchWriteRequest(dynamoRx, Organization, tableName)
99+
request = new BatchWriteSingleTableRequest(dynamoRx, Organization, tableName)
100100

101101
const output: DynamoDB.BatchWriteItemOutput = {
102102
UnprocessedItems: {

src/dynamo/request/batchwrite/batch-write.request.ts renamed to src/dynamo/request/batchwritesingletable/batch-write-single-table.request.ts

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@ import { DynamoRx } from '../../../dynamo/dynamo-rx'
1111
import { randomExponentialBackoffTimer } from '../../../helper'
1212
import { Mapper } from '../../../mapper'
1313
import { ModelConstructor } from '../../../model/model-constructor'
14-
import { BatchWriteResponse } from './batch-write.response'
14+
import { BatchWriteSingleTableResponse } from './batch-write-single-table.response'
1515

1616
const MAX_BATCH_WRITE_ITEMS = 25
1717

18-
export class BatchWriteRequest<T> {
18+
export class BatchWriteSingleTableRequest<T> {
1919
private get toKey(): (item: T) => AttributeMap {
2020
if (!this._keyFn) {
2121
this._keyFn = Mapper.createToKeyFn(this.modelClazz)
@@ -42,19 +42,19 @@ export class BatchWriteRequest<T> {
4242
this.itemsToProcess = []
4343
}
4444

45-
delete(items: T[]): BatchWriteRequest<T> {
45+
delete(items: T[]): BatchWriteSingleTableRequest<T> {
4646
this.itemsToProcess.push(...items.map<WriteRequest>(item => ({ DeleteRequest: { Key: this.toKey(item) } })))
4747
return this
4848
}
4949

50-
put(items: T[]): BatchWriteRequest<T> {
50+
put(items: T[]): BatchWriteSingleTableRequest<T> {
5151
this.itemsToProcess.push(
5252
...items.map<WriteRequest>(item => ({ PutRequest: { Item: Mapper.toDb(item, this.modelClazz) } }))
5353
)
5454
return this
5555
}
5656

57-
private execNextBatch(): Observable<BatchWriteResponse> {
57+
private execNextBatch(): Observable<BatchWriteSingleTableResponse> {
5858
const batch = this.itemsToProcess.splice(0, MAX_BATCH_WRITE_ITEMS)
5959
const batchWriteItemInput: BatchWriteItemInput = {
6060
RequestItems: {
@@ -76,20 +76,25 @@ export class BatchWriteRequest<T> {
7676
)
7777
}
7878

79+
/**
80+
*
81+
* @param backoffTimer generator for how much timeSlots should be waited before requesting next batch. only used when capacity was exceeded. default randomExponentialBackoffTimer
82+
* @param throttleTimeSlot defines how long one timeSlot is for throttling, default 1 second
83+
*/
7984
exec(backoffTimer = randomExponentialBackoffTimer, throttleTimeSlot = 1000): Observable<void> {
80-
let rBoT = backoffTimer(throttleTimeSlot)
85+
let rBoT = backoffTimer()
8186
let backoffTime = 0
8287
return this.execNextBatch().pipe(
83-
mergeMap((r: BatchWriteResponse) => {
88+
mergeMap((r: BatchWriteSingleTableResponse) => {
8489
if (!r.capacityExceeded) {
85-
rBoT = backoffTimer(throttleTimeSlot)
90+
rBoT = backoffTimer()
8691
backoffTime = 0
8792
} else {
8893
backoffTime = rBoT.next().value
8994
}
90-
return of(r).pipe(delay(backoffTime))
95+
return of(r).pipe(delay(backoffTime * throttleTimeSlot))
9196
}),
92-
mergeMap((r: BatchWriteResponse) => {
97+
mergeMap((r: BatchWriteSingleTableResponse) => {
9398
if (r.remainingItems > 0) {
9499
return this.exec()
95100
} else {

src/dynamo/request/batchwrite/batch-write.response.ts renamed to src/dynamo/request/batchwritesingletable/batch-write-single-table.response.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { ConsumedCapacityMultiple } from 'aws-sdk/clients/dynamodb'
22

3-
export interface BatchWriteResponse {
3+
export interface BatchWriteSingleTableResponse {
44
remainingItems: number
55
capacityExceeded: boolean
66
consumedCapacity?: ConsumedCapacityMultiple

src/dynamo/request/query/query.request.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,9 @@ export class QueryRequest<T> extends Request<T, QueryRequest<T>, QueryInput, Que
134134
)
135135
}
136136

137+
/**
138+
* fetches all pages. may uses all provisionedOutput, therefore for client side use cases rather use pagedDatasource (exec)
139+
*/
137140
execFetchAll(): Observable<T[]> {
138141
return fetchAll(this)
139142
}

src/dynamo/request/scan/scan.request.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,9 @@ export class ScanRequest<T> extends Request<T, ScanRequest<T>, ScanInput, ScanRe
6868
return this.dynamoRx.scan(params).pipe(map(response => response.Count!))
6969
}
7070

71+
/**
72+
* fetches all pages. may uses all provisionedOutput, therefore for client side use cases rather use pagedDatasource (exec)
73+
*/
7174
execFetchAll(): Observable<T[]> {
7275
return fetchAll(this)
7376
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
export function* randomExponentialBackoffTimer(throttleTimeSlot: number) {
1+
export function* randomExponentialBackoffTimer() {
22
let i = 0
33
while (true) {
4-
yield ((Math.pow(2, Math.round(Math.random() * ++i)) - 1) / 2) * throttleTimeSlot
4+
yield (Math.pow(2, Math.round(Math.random() * ++i)) - 1) / 2
55
}
66
}

src/mapper/mapper.ts

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -54,21 +54,7 @@ export class Mapper {
5454
/*
5555
* 1) get the value of the property
5656
*/
57-
const propertyDescriptor = Object.getOwnPropertyDescriptor(item, propertyKey)
58-
59-
// use get accessor if available otherwise use value property of descriptor
60-
let propertyValue: any
61-
if (propertyDescriptor) {
62-
if (propertyDescriptor.get) {
63-
propertyValue = propertyDescriptor.get()
64-
} else {
65-
propertyValue = propertyDescriptor.value
66-
}
67-
} else {
68-
throw new Error(
69-
'there is no property descriptor for item ' + JSON.stringify(item) + ' and property key ' + propertyKey
70-
)
71-
}
57+
const propertyValue = Mapper.getPropertyValue(item, propertyKey)
7258

7359
let attributeValue: AttributeValue | undefined | null
7460

@@ -168,6 +154,10 @@ export class Mapper {
168154
}
169155
}
170156

157+
/**
158+
* returns the function for the given ModelConstructor to create the AttributeMap with HASH (and RANGE) Key of a given item. used to delete items
159+
* @param modelConstructor
160+
*/
171161
static createToKeyFn<T>(modelConstructor: ModelConstructor<T>): (item: T) => AttributeMap {
172162
const metadata = MetadataHelper.get(modelConstructor)
173163
const properties = metadata.modelOptions.properties
@@ -326,7 +316,7 @@ export class Mapper {
326316
return this.mapperForType.get(type.toString())!
327317
}
328318

329-
static getPropertyValue(item: any, propertyKey: PropertyKey) {
319+
static getPropertyValue(item: any, propertyKey: PropertyKey): any {
330320
const propertyDescriptor = Object.getOwnPropertyDescriptor(item, propertyKey)
331321

332322
// use get accessor if available otherwise use value property of descriptor

0 commit comments

Comments
 (0)