Skip to content

Commit b348b3b

Browse files
Merge pull request #59 from shiftcode/key-members-validation
Key members validation
2 parents 9785fe7 + ae5f642 commit b348b3b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+683
-448
lines changed

src/decorator/impl/mapper/custom-mapper.decorator.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
import { MapperForType } from '../../../mapper/for-type/base.mapper'
2+
import { Attribute } from '../../../mapper/type/attribute.type'
23
import { ModelConstructor } from '../../../model/model-constructor'
34
import { initOrUpdateProperty } from '../property/property.decorator'
45

5-
export function CustomMapper(mapperClazz: ModelConstructor<MapperForType<any>>): PropertyDecorator {
6+
export function CustomMapper<T extends Attribute>(
7+
mapperClazz: ModelConstructor<MapperForType<any, T>>
8+
): PropertyDecorator {
69
return (target: any, propertyKey: string | symbol) => {
710
if (typeof propertyKey === 'string') {
811
initOrUpdateProperty({ mapper: mapperClazz }, target, propertyKey)

src/decorator/impl/property/property.decorator.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { KeyType } from 'aws-sdk/clients/dynamodb'
22
import { DynamoEasyConfig } from '../../../config/dynamo-easy-config'
3-
import { AttributeModelType } from '../../../mapper/type/attribute-model.type'
3+
import { AttributeValueType } from '../../../mapper/type/attribute-value-type.type'
4+
import { Attribute } from '../../../mapper/type/attribute.type'
45
import { MomentType } from '../../../mapper/type/moment.type'
56
import { Util } from '../../../mapper/util'
67
import { PropertyMetadata, TypeInfo } from '../../metadata/property-metadata.model'
@@ -74,7 +75,7 @@ function initOrUpdateLSI(indexes: string[], indexData: IndexData): Partial<Prope
7475
}
7576

7677
export function initOrUpdateProperty(
77-
propertyMetadata: Partial<PropertyMetadata<any>> = {},
78+
propertyMetadata: Partial<PropertyMetadata<any, Attribute>> = {},
7879
target: any,
7980
propertyKey: string
8081
): void {
@@ -86,7 +87,10 @@ export function initOrUpdateProperty(
8687
if (existingProperty) {
8788
// merge property options
8889
// console.log('merge into existing property', existingProperty, propertyMetadata);
89-
Object.assign<PropertyMetadata<any>, Partial<PropertyMetadata<any>>>(existingProperty, propertyMetadata)
90+
Object.assign<PropertyMetadata<any, Attribute>, Partial<PropertyMetadata<any, Attribute>>>(
91+
existingProperty,
92+
propertyMetadata
93+
)
9094
} else {
9195
// add new options
9296
const newProperty: PropertyMetadata<any> = createNewProperty(propertyMetadata, target, propertyKey)
@@ -98,11 +102,11 @@ export function initOrUpdateProperty(
98102
}
99103

100104
function createNewProperty(
101-
propertyOptions: Partial<PropertyMetadata<any>> = {},
105+
propertyOptions: Partial<PropertyMetadata<any, Attribute>> = {},
102106
target: any,
103107
propertyKey: string
104108
): PropertyMetadata<any> {
105-
let propertyType: AttributeModelType = getMetadataType(target, propertyKey)
109+
let propertyType: AttributeValueType = getMetadataType(target, propertyKey)
106110
let customType = isCustomType(propertyType)
107111

108112
const typeByConvention = Util.typeByConvention(propertyKey)

src/decorator/metadata/property-metadata.model.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { KeyType } from 'aws-sdk/clients/dynamodb'
22
import { MapperForType } from '../../mapper/for-type/base.mapper'
3+
import { Attribute } from '../../mapper/type/attribute.type'
34
import { ModelConstructor } from '../../model/model-constructor'
45

56
export interface TypeInfo {
@@ -14,7 +15,7 @@ export interface Key {
1415
uuid?: boolean
1516
}
1617

17-
export interface PropertyMetadata<T> {
18+
export interface PropertyMetadata<T, R extends Attribute = Attribute> {
1819
// this property desribes a key attribute (either partition or sort) for the table
1920
key?: Key
2021

@@ -35,7 +36,7 @@ export interface PropertyMetadata<T> {
3536
*/
3637
isSortedCollection?: boolean
3738

38-
mapper?: ModelConstructor<MapperForType<any>>
39+
mapper?: ModelConstructor<MapperForType<any, R>>
3940

4041
// maps the index name to the key type to describe for which GSI this property describes a key attribute
4142
keyForGSI?: { [key: string]: KeyType }
@@ -47,6 +48,6 @@ export interface PropertyMetadata<T> {
4748
transient?: boolean
4849
}
4950

50-
export function hasGenericType(propertyMetadata?: PropertyMetadata<any>): boolean {
51+
export function hasGenericType(propertyMetadata?: PropertyMetadata<any, any>): boolean {
5152
return !!(propertyMetadata && propertyMetadata.typeInfo && propertyMetadata.typeInfo.genericType)
5253
}

src/dynamo/batchget/batch-get.request.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
import { AttributeMap, BatchGetItemInput } from 'aws-sdk/clients/dynamodb'
1+
import { BatchGetItemInput } from 'aws-sdk/clients/dynamodb'
22
import { isObject, isString } from 'lodash'
33
import { Observable } from 'rxjs'
44
import { map } from 'rxjs/operators'
55
import { MetadataHelper } from '../../decorator/metadata/metadata-helper'
66
import { Mapper } from '../../mapper/mapper'
7+
import { Attributes } from '../../mapper/type/attribute.type'
78
import { ModelConstructor } from '../../model/model-constructor'
89
import { DEFAULT_SESSION_VALIDITY_ENSURER } from '../default-session-validity-ensurer.const'
910
import { DEFAULT_TABLE_NAME_RESOLVER } from '../default-table-name-resolver.const'
@@ -44,11 +45,11 @@ export class BatchGetRequest {
4445
this.tables.set(tableName, modelClazz)
4546

4647
const metadata = MetadataHelper.get(modelClazz)
47-
const attributeMaps: AttributeMap[] = []
48+
const attributeMaps: Attributes[] = []
4849

4950
// loop over all the keys
5051
keys.forEach(key => {
51-
const idOb: AttributeMap = {}
52+
const idOb: Attributes = {}
5253

5354
if (isString(key)) {
5455
// got a simple primary key
@@ -100,8 +101,8 @@ export class BatchGetRequest {
100101

101102
if (response.Responses && Object.keys(response.Responses).length) {
102103
Object.keys(response.Responses).forEach(tableName => {
103-
const mapped = response.Responses![tableName].map(attributeMap =>
104-
Mapper.fromDb(attributeMap, this.tables.get(tableName))
104+
const mapped = response.Responses![tableName].map(attributes =>
105+
Mapper.fromDb(<Attributes>attributes, this.tables.get(tableName))
105106
)
106107
r.Responses![tableName] = mapped
107108
})
@@ -119,7 +120,7 @@ export class BatchGetRequest {
119120
if (response.Responses && Object.keys(response.Responses).length) {
120121
Object.keys(response.Responses).forEach(tableName => {
121122
const mapped = response.Responses![tableName].map(attributeMap =>
122-
Mapper.fromDb(attributeMap, this.tables.get(tableName))
123+
Mapper.fromDb(<Attributes>attributeMap, this.tables.get(tableName))
123124
)
124125
r[tableName] = mapped
125126
})

src/dynamo/expression/condition-expression-builder.ts

Lines changed: 21 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import { AttributeMap, AttributeValue } from 'aws-sdk/clients/dynamodb'
21
import { curryRight, forEach, isPlainObject } from 'lodash'
32
import { Metadata } from '../../decorator/metadata/metadata'
43
import { PropertyMetadata } from '../../decorator/metadata/property-metadata.model'
54
import { Mapper } from '../../mapper/mapper'
5+
import { Attribute, Attributes } from '../../mapper/type/attribute.type'
66
import { Util } from '../../mapper/util'
77
import { resolveAttributeNames } from './functions/attribute-names.function'
88
import { isFunctionOperator } from './functions/is-function-operator.function'
@@ -151,17 +151,15 @@ export class ConditionExpressionBuilder {
151151
existingValueNames: string[] | undefined,
152152
propertyMetadata: PropertyMetadata<any> | undefined
153153
): Expression {
154-
const attributeValues: AttributeMap = (<any[]>values[0])
155-
.map(value => Mapper.toDbOne(value, propertyMetadata))
156-
.reduce(
157-
(result, mappedValue: AttributeValue | null, index: number) => {
158-
if (mappedValue !== null) {
159-
result[`${valuePlaceholder}_${index}`] = mappedValue
160-
}
161-
return result
162-
},
163-
<AttributeMap>{}
164-
)
154+
const attributeValues: Attributes = (<any[]>values[0]).map(value => Mapper.toDbOne(value, propertyMetadata)).reduce(
155+
(result, mappedValue: Attribute | null, index: number) => {
156+
if (mappedValue !== null) {
157+
result[`${valuePlaceholder}_${index}`] = mappedValue
158+
}
159+
return result
160+
},
161+
<Attributes>{}
162+
)
165163

166164
const inStatement = (<any[]>values[0]).map((value: any, index: number) => `${valuePlaceholder}_${index}`).join(', ')
167165

@@ -181,7 +179,7 @@ export class ConditionExpressionBuilder {
181179
existingValueNames: string[] | undefined,
182180
propertyMetadata: PropertyMetadata<any> | undefined
183181
): Expression {
184-
const attributeValues: AttributeMap = {}
182+
const attributes: Attributes = {}
185183
const mappedValue1 = Mapper.toDbOne(values[0], propertyMetadata)
186184
const mappedValue2 = Mapper.toDbOne(values[1], propertyMetadata)
187185

@@ -192,13 +190,13 @@ export class ConditionExpressionBuilder {
192190
const value2Placeholder = uniqAttributeValueName(attributePath, [valuePlaceholder].concat(existingValueNames || []))
193191

194192
const statement = `${namePlaceholder} BETWEEN ${valuePlaceholder} AND ${value2Placeholder}`
195-
attributeValues[valuePlaceholder] = mappedValue1
196-
attributeValues[value2Placeholder] = mappedValue2
193+
attributes[valuePlaceholder] = mappedValue1
194+
attributes[value2Placeholder] = mappedValue2
197195

198196
return {
199197
statement,
200198
attributeNames,
201-
attributeValues,
199+
attributeValues: attributes,
202200
}
203201
}
204202

@@ -225,28 +223,28 @@ export class ConditionExpressionBuilder {
225223
statement = [namePlaceholder, operator, valuePlaceholder].join(' ')
226224
}
227225

228-
const attributeValues: AttributeMap = {}
226+
const attributes: Attributes = {}
229227
if (hasValue) {
230-
let value: AttributeValue | null
228+
let attribute: Attribute | null
231229
switch (operator) {
232230
case 'contains':
233231
// TODO think about validation
234232
// ConditionExpressionBuilder.validateValueForContains(values[0], propertyMetadata)
235-
value = Mapper.toDbOne(values[0], propertyMetadata)
233+
attribute = Mapper.toDbOne(values[0], propertyMetadata)
236234
break
237235
default:
238-
value = Mapper.toDbOne(values[0], propertyMetadata)
236+
attribute = Mapper.toDbOne(values[0], propertyMetadata)
239237
}
240238

241-
if (value) {
242-
attributeValues[valuePlaceholder] = value
239+
if (attribute) {
240+
attributes[valuePlaceholder] = attribute
243241
}
244242
}
245243

246244
return {
247245
statement,
248246
attributeNames,
249-
attributeValues,
247+
attributeValues: attributes,
250248
}
251249
}
252250

src/dynamo/expression/type/condition-expression-chain.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { AttributeType } from '../../../mapper/type/attribute.type'
1+
import { AttributeType } from '../../../mapper/type/attribute-type.type'
22
import { Expression } from './expression.type'
33

44
export interface ConditionExpressionChain {

src/dynamo/expression/type/condition-expression-definition-chain.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { AttributeType } from '../../../mapper/type/attribute.type'
1+
import { AttributeType } from '../../../mapper/type/attribute-type.type'
22
import { ConditionExpressionDefinitionFunction } from './condition-expression-definition-function'
33

44
export interface ConditionExpressionDefinitionChain {
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import { AttributeMap } from 'aws-sdk/clients/dynamodb'
1+
import { Attributes } from '../../../mapper/type/attribute.type'
22

33
export interface Expression {
44
attributeNames: { [key: string]: string }
5-
attributeValues: AttributeMap
5+
attributeValues: Attributes
66
statement: string
77
}

src/dynamo/expression/type/request-condition-function.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { AttributeType } from '../../../mapper/type/attribute.type'
1+
import { AttributeType } from '../../../mapper/type/attribute-type.type'
22
import { BaseRequest } from '../../request/base.request'
33

44
export interface RequestConditionFunction<T extends BaseRequest<any, any>> {

src/dynamo/expression/update-expression-builder.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import { AttributeMap, AttributeValue } from 'aws-sdk/clients/dynamodb'
21
import { Metadata } from '../../decorator/metadata/metadata'
32
import { PropertyMetadata } from '../../decorator/metadata/property-metadata.model'
43
import { Mapper } from '../../mapper/mapper'
4+
import { Attribute, Attributes } from '../../mapper/type/attribute.type'
55
import { Util } from '../../mapper/util'
66
import { ConditionExpressionBuilder } from './condition-expression-builder'
77
import { resolveAttributeNames } from './functions/attribute-names.function'
@@ -137,20 +137,20 @@ export class UpdateExpressionBuilder {
137137

138138
const hasValue = !UpdateExpressionBuilder.isNoValueAction(operator.action)
139139

140-
const attributeValues: AttributeMap = {}
140+
const attributes: Attributes = {}
141141
if (hasValue) {
142-
const value: AttributeValue | null = Mapper.toDbOne(values[0], propertyMetadata)
142+
const attribute: Attribute | null = Mapper.toDbOne(values[0], propertyMetadata)
143143

144-
if (value) {
145-
attributeValues[valuePlaceholder] = value
144+
if (attribute) {
145+
attributes[valuePlaceholder] = attribute
146146
}
147147
}
148148

149149
return {
150150
type: operator.actionKeyword,
151151
statement,
152152
attributeNames,
153-
attributeValues,
153+
attributeValues: attributes,
154154
}
155155
}
156156

0 commit comments

Comments
 (0)