From 9b57ed15a4928cf049eeddd85c245bb7ad38b0ea Mon Sep 17 00:00:00 2001 From: Michael Wittwer Date: Mon, 9 Oct 2017 15:05:00 +0200 Subject: [PATCH] feat(updateRequest): add support for all the available support operations --- .../expression/request-expression-builder.ts | 11 +- .../expression/type/update-action-def.ts | 12 + .../type/update-action-defs.const.ts | 16 + .../expression/type/update-action.type.ts | 10 - .../update-expression-definition-chain.ts | 40 ++- .../expression/update-expression-builder.ts | 69 +++- .../request/update/update.request.spec.ts | 316 +++++++++++++++++- test/models/update.model.ts | 24 ++ 8 files changed, 441 insertions(+), 57 deletions(-) create mode 100644 src/dynamo/expression/type/update-action-def.ts create mode 100644 src/dynamo/expression/type/update-action-defs.const.ts diff --git a/src/dynamo/expression/request-expression-builder.ts b/src/dynamo/expression/request-expression-builder.ts index ef823d1c8..80db1d03d 100644 --- a/src/dynamo/expression/request-expression-builder.ts +++ b/src/dynamo/expression/request-expression-builder.ts @@ -12,7 +12,9 @@ import { ExpressionType } from './type/expression-type.type' import { Expression } from './type/expression.type' import { RequestConditionFunction } from './type/request-condition-function' import { RequestSortKeyConditionFunction } from './type/sort-key-condition-function' -import { UpdateAction, UpdateActionDef } from './type/update-action.type' +import { UpdateActionDef } from './type/update-action-def' +import { UPDATE_ACTION_DEFS } from './type/update-action-defs.const' +import { UpdateAction } from './type/update-action.type' import { UpdateExpressionDefinitionChain } from './type/update-expression-definition-chain' import { UpdateExpressionDefinitionFunction } from './type/update-expression-definition-function' import { UpdateExpression } from './type/update-expression.type' @@ -149,12 +151,7 @@ export class RequestExpressionBuilder { * parameters as another example */ private static createUpdateFunctions(impl: (operation: UpdateActionDef) => any): T { - // FIXME add all operators - return [ - new UpdateActionDef('SET', 'incrementBy'), - new UpdateActionDef('SET', 'decrementBy'), - new UpdateActionDef('SET', 'set'), - ].reduce( + return UPDATE_ACTION_DEFS.reduce( (result: T, updateActionDef: UpdateActionDef) => { Reflect.set(result, updateActionDef.action, impl(updateActionDef)) diff --git a/src/dynamo/expression/type/update-action-def.ts b/src/dynamo/expression/type/update-action-def.ts new file mode 100644 index 000000000..aa4068fdf --- /dev/null +++ b/src/dynamo/expression/type/update-action-def.ts @@ -0,0 +1,12 @@ +import { UpdateActionKeyword } from './update-action-keyword.type' +import { UpdateAction } from './update-action.type' + +export class UpdateActionDef { + actionKeyword: UpdateActionKeyword + action: UpdateAction + + constructor(actionKeyWord: UpdateActionKeyword, action: UpdateAction) { + this.actionKeyword = actionKeyWord + this.action = action + } +} diff --git a/src/dynamo/expression/type/update-action-defs.const.ts b/src/dynamo/expression/type/update-action-defs.const.ts new file mode 100644 index 000000000..3a0af9322 --- /dev/null +++ b/src/dynamo/expression/type/update-action-defs.const.ts @@ -0,0 +1,16 @@ +import { UpdateActionDef } from './update-action-def' + +export const UPDATE_ACTION_DEFS: UpdateActionDef[] = [ + // SET + new UpdateActionDef('SET', 'incrementBy'), + new UpdateActionDef('SET', 'decrementBy'), + new UpdateActionDef('SET', 'set'), + new UpdateActionDef('SET', 'appendToList'), + // REMOVE + new UpdateActionDef('REMOVE', 'remove'), + new UpdateActionDef('REMOVE', 'removeFromListAt'), + // ADD + new UpdateActionDef('ADD', 'add'), + // DELETE + new UpdateActionDef('DELETE', 'removeFromSet'), +] diff --git a/src/dynamo/expression/type/update-action.type.ts b/src/dynamo/expression/type/update-action.type.ts index 2a111f204..88ad55cf6 100644 --- a/src/dynamo/expression/type/update-action.type.ts +++ b/src/dynamo/expression/type/update-action.type.ts @@ -22,13 +22,3 @@ export type UpdateAction = | 'removeFromListAt' | 'add' | 'removeFromSet' - -export class UpdateActionDef { - actionKeyword: UpdateActionKeyword - action: UpdateAction - - constructor(actionKeyWord: UpdateActionKeyword, action: UpdateAction) { - this.actionKeyword = actionKeyWord - this.action = action - } -} diff --git a/src/dynamo/expression/type/update-expression-definition-chain.ts b/src/dynamo/expression/type/update-expression-definition-chain.ts index 88f5b9338..add4382dd 100644 --- a/src/dynamo/expression/type/update-expression-definition-chain.ts +++ b/src/dynamo/expression/type/update-expression-definition-chain.ts @@ -4,27 +4,42 @@ import { UpdateExpressionDefinitionFunction } from './update-expression-definiti * see http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html for full documentation */ export interface UpdateExpressionDefinitionChain { - // SET operation TODO add support for ifNotExists + /* ---------------------------------------------------------------- + SET operation TODO add support for ifNotExists + ---------------------------------------------------------------- */ incrementBy: (value: number) => UpdateExpressionDefinitionFunction decrementBy: (value: number) => UpdateExpressionDefinitionFunction + + /** + * will update the item at the path, path can be a top level atribute or a nested attribute. + * samples: + * - persons.age + * - places[0].address.street + */ set: (value: any) => UpdateExpressionDefinitionFunction - setAt: (value: any, at: number) => UpdateExpressionDefinitionFunction /** * appends one or more values to the start or end of a list, value must be of type L(ist) */ - appendToList: (value: any, position: 'START' | 'END') => UpdateExpressionDefinitionFunction + appendToList: (value: any, position?: 'START' | 'END') => UpdateExpressionDefinitionFunction - // REMOVE operation + /* ---------------------------------------------------------------- + REMOVE operation + ---------------------------------------------------------------- */ remove: () => UpdateExpressionDefinitionFunction /** removes an item at the given position(s), the remaining elements are shifted */ removeFromListAt: (...positions: number[]) => UpdateExpressionDefinitionFunction - // ADD operation (only supports number and set type) + /* ---------------------------------------------------------------- + ADD operation (only supports number and set type) + AWS generally recommends to use SET rather than ADD + ---------------------------------------------------------------- */ /** - * adds or manipulates a value, manipulation behaviour differs based on type of attribute + * adds or manipulates a value to an attribute of type N(umber) or S(et), manipulation behaviour differs based on attribute type + * + * @param values {multiple values as vararg | Array | Set} * * --update-expression "ADD QuantityOnHand :q" \ * --expression-attribute-values '{":q": {"N": "5"}}' \ @@ -32,14 +47,17 @@ export interface UpdateExpressionDefinitionChain { * --update-expression "ADD Color :c" \ * --expression-attribute-values '{":c": {"SS":["Orange", "Purple"]}}' \ */ - add: (value: any) => UpdateExpressionDefinitionFunction - - // DELETE operation (only supports set type) + add: (...values: any[]) => UpdateExpressionDefinitionFunction + /* ---------------------------------------------------------------- + DELETE operation (only supports set type) + ---------------------------------------------------------------- */ /** + * @param values {multiple values as vararg | Array | Set} + * @returns {UpdateExpressionDefinitionFunction} * * --update-expression "DELETE Color :p" \ - * --expression-attribute-values '{":p": {"SS": ["Yellow", "Purple"]}}' \ + * --expression-attribute-values '{":p": {"SS": ["Yellow", "Purple"]}}' */ - removeFromSet: (values: Set) => UpdateExpressionDefinitionFunction + removeFromSet: (...values: any[]) => UpdateExpressionDefinitionFunction } diff --git a/src/dynamo/expression/update-expression-builder.ts b/src/dynamo/expression/update-expression-builder.ts index ce5d58c6c..f3784f18f 100644 --- a/src/dynamo/expression/update-expression-builder.ts +++ b/src/dynamo/expression/update-expression-builder.ts @@ -1,14 +1,13 @@ import { AttributeMap, AttributeValue } from 'aws-sdk/clients/dynamodb' -import { curryRight } from 'lodash' import { Metadata } from '../../decorator/metadata/metadata' import { PropertyMetadata } from '../../decorator/metadata/property-metadata.model' import { Mapper } from '../../mapper/mapper' +import { Util } from '../../mapper/util' import { resolveAttributeNames } from './functions/attribute-names.function' -import { isFunctionOperator } from './functions/is-function-operator.function' -import { isNoParamFunctionOperator } from './functions/is-no-param-function-operator.function' import { uniqAttributeValueName } from './functions/unique-attribute-value-name.function' import { Expression } from './type/expression.type' -import { UpdateAction, UpdateActionDef } from './type/update-action.type' +import { UpdateActionDef } from './type/update-action-def' +import { UpdateAction } from './type/update-action.type' import { UpdateExpression } from './type/update-expression.type' export class UpdateExpressionBuilder { @@ -32,6 +31,7 @@ export class UpdateExpressionBuilder { ): UpdateExpression { // TODO investigate is there a use case for undefined desired to be a value // get rid of undefined values + // FIXME should this not be a deep filter? values = values.filter(value => value !== undefined) // TODO check if provided values are valid for given operation @@ -83,22 +83,61 @@ export class UpdateExpressionBuilder { ): UpdateExpression { let statement: string switch (operator.action) { - case 'set': - statement = `${namePlaceholder} = ${valuePlaceholder}` - break case 'incrementBy': statement = `${namePlaceholder} = ${namePlaceholder} + ${valuePlaceholder}` break case 'decrementBy': statement = `${namePlaceholder} = ${namePlaceholder} - ${valuePlaceholder}` break + case 'set': + statement = `${namePlaceholder} = ${valuePlaceholder}` + break + case 'appendToList': + const position = values.length > 1 ? values[values.length - 1] || 'END' : 'END' + switch (position) { + case 'END': + statement = `${namePlaceholder} = list_append(${namePlaceholder}, ${valuePlaceholder})` + break + case 'START': + statement = `${namePlaceholder} = list_append(${valuePlaceholder}, ${namePlaceholder})` + break + default: + throw new Error("make sure to provide either 'START' or 'END' as value for position argument") + } + break + case 'remove': + statement = `${namePlaceholder}` + break + case 'removeFromListAt': + const positions: number[] = values + statement = values.map(pos => `${namePlaceholder}[${pos}]`).join(', ') + break + case 'add': + // TODO add validation to make sure expressionAttributeValue to be N(umber) or S(et) + statement = `${namePlaceholder} ${valuePlaceholder}` + // TODO won't work for numbers, is always gonna be mapped to a collectio type + if ((values.length === 1 && Array.isArray(values[0])) || Util.isSet(values[0])) { + // dealing with arr | set as single argument + } else { + // dealing with vararg + values[0] = [...values] + } + break + case 'removeFromSet': + // TODO add validation to make sure expressionAttributeValue to be S(et) + statement = `${namePlaceholder} ${valuePlaceholder}` + if ((values.length === 1 && Array.isArray(values[0])) || Util.isSet(values[0])) { + // dealing with arr | set as single argument + } else { + // dealing with vararg + values[0] = [...values] + } + break default: - throw new Error('no implementation') + throw new Error(`no implementation for action ${operator.action}`) } - // = [namePlaceholder, operator, valuePlaceholder].join(' ') - // FIXME add hasValue logic - const hasValue = true + const hasValue = !UpdateExpressionBuilder.isNoValueAction(operator.action) const attributeValues: AttributeMap = {} if (hasValue) { @@ -116,4 +155,12 @@ export class UpdateExpressionBuilder { attributeValues, } } + + private static isNoValueAction(action: UpdateAction) { + return ( + action === 'remove' || + // special cases: values are used in statement instaed of expressionValues + action === 'removeFromListAt' + ) + } } diff --git a/src/dynamo/request/update/update.request.spec.ts b/src/dynamo/request/update/update.request.spec.ts index d46f4d6c0..96af29552 100644 --- a/src/dynamo/request/update/update.request.spec.ts +++ b/src/dynamo/request/update/update.request.spec.ts @@ -1,15 +1,34 @@ import * as moment from 'moment' import { getTableName } from '../../../../test/helper/get-table-name.function' -import { ComplexModel } from '../../../../test/models/complex.model' -import { UpdateModel } from '../../../../test/models/update.model' -import { DynamoStore } from '../../dynamo-store' -import { attribute } from '../../expression/logical-operator/attribute.function' +import { Address, UpdateModel } from '../../../../test/models/update.model' import { update } from '../../expression/logical-operator/update.function' import { UpdateRequest } from './update.request' -fdescribe('update request', () => { +describe('update request', () => { describe('update expression', () => { describe('single operation', () => { + it('incrementBy', () => { + const now = moment() + + const request = new UpdateRequest(null, UpdateModel, getTableName(UpdateModel), 'myId', now) + request.operations(update('counter').incrementBy(5)) + + expect(request.params.UpdateExpression).toBe('SET #counter = #counter + :counter') + expect(request.params.ExpressionAttributeNames).toEqual({ '#counter': 'counter' }) + expect(request.params.ExpressionAttributeValues).toEqual({ ':counter': { N: '5' } }) + }) + + it('decrementBy', () => { + const now = moment() + + const request = new UpdateRequest(null, UpdateModel, getTableName(UpdateModel), 'myId', now) + request.operations(update('counter').decrementBy(5)) + + expect(request.params.UpdateExpression).toBe('SET #counter = #counter - :counter') + expect(request.params.ExpressionAttributeNames).toEqual({ '#counter': 'counter' }) + expect(request.params.ExpressionAttributeValues).toEqual({ ':counter': { N: '5' } }) + }) + it('set', () => { const now = moment() @@ -29,32 +48,293 @@ fdescribe('update request', () => { }) }) - it('incrementBy', () => { + it('set (nested map)', () => { const now = moment() const request = new UpdateRequest(null, UpdateModel, getTableName(UpdateModel), 'myId', now) - request.operations(update('counter').incrementBy(5)) - expect(request.params.UpdateExpression).toBe('SET #counter = #counter + :counter') - expect(request.params.ExpressionAttributeNames).toEqual({ '#counter': 'counter' }) - expect(request.params.ExpressionAttributeValues).toEqual({ ':counter': { N: '5' } }) + request.operations(update('info.details').set('the new detail')) + + expect(request.params.UpdateExpression).toBe('SET #info.#details = :info__details') + expect(request.params.ExpressionAttributeNames).toEqual({ '#info': 'info', '#details': 'details' }) + expect(request.params.ExpressionAttributeValues).toEqual({ + ':info__details': { + S: 'the new detail', + }, + }) }) - }) - describe('multiple operations', () => { - it('b', () => { + it('set (list)', () => { const now = moment() + const request = new UpdateRequest(null, UpdateModel, getTableName(UpdateModel), 'myId', now) + request.operations(update('addresses[1]').set({ street: 'Bond Street', place: 'London', zip: 25650 })) + + expect(request.params.UpdateExpression).toBe('SET #addresses[1] = :addresses_at_1') + expect(request.params.ExpressionAttributeNames).toEqual({ '#addresses': 'addresses' }) + expect(request.params.ExpressionAttributeValues).toEqual({ + ':addresses_at_1': { + M: { + street: { + S: 'Bond Street', + }, + place: { + S: 'London', + }, + zip: { + N: '25650', + }, + }, + }, + }) + }) + + it('append to list (default position)', () => { + const now = moment() const request = new UpdateRequest(null, UpdateModel, getTableName(UpdateModel), 'myId', now) - request.operations(update('active').set(true), update('name').set('newName')) - expect(request.params.UpdateExpression).toBe('SET #active = :active, #name = :name') - expect(request.params.ExpressionAttributeNames).toEqual({ '#active': 'isActive', '#name': 'name' }) + const newAddress: Address = { street: 'The street', place: 'London', zip: 15241 } + request.operations(update('addresses').appendToList(newAddress)) + + expect(request.params.UpdateExpression).toBe('SET #addresses = list_append(#addresses, :addresses)') + expect(request.params.ExpressionAttributeNames).toEqual({ '#addresses': 'addresses' }) expect(request.params.ExpressionAttributeValues).toEqual({ - ':active': { BOOL: true }, - ':name': { S: 'newName' }, + ':addresses': { + M: { + street: { + S: 'The street', + }, + place: { + S: 'London', + }, + zip: { + N: '15241', + }, + }, + }, }) }) + + it('append to list (position = END)', () => { + const now = moment() + const request = new UpdateRequest(null, UpdateModel, getTableName(UpdateModel), 'myId', now) + + const newAddress: Address = { street: 'The street', place: 'London', zip: 15241 } + request.operations(update('addresses').appendToList(newAddress, 'END')) + + expect(request.params.UpdateExpression).toBe('SET #addresses = list_append(#addresses, :addresses)') + expect(request.params.ExpressionAttributeNames).toEqual({ '#addresses': 'addresses' }) + expect(request.params.ExpressionAttributeValues).toEqual({ + ':addresses': { + M: { + street: { + S: 'The street', + }, + place: { + S: 'London', + }, + zip: { + N: '15241', + }, + }, + }, + }) + }) + + it('append to list (position = START)', () => { + const now = moment() + const request = new UpdateRequest(null, UpdateModel, getTableName(UpdateModel), 'myId', now) + + const newAddress: Address = { street: 'The street', place: 'London', zip: 15241 } + request.operations(update('addresses').appendToList(newAddress, 'START')) + + expect(request.params.UpdateExpression).toBe('SET #addresses = list_append(:addresses, #addresses)') + expect(request.params.ExpressionAttributeNames).toEqual({ '#addresses': 'addresses' }) + expect(request.params.ExpressionAttributeValues).toEqual({ + ':addresses': { + M: { + street: { + S: 'The street', + }, + place: { + S: 'London', + }, + zip: { + N: '15241', + }, + }, + }, + }) + }) + + it('remove', () => { + const now = moment() + const request = new UpdateRequest(null, UpdateModel, getTableName(UpdateModel), 'myId', now) + + request.operations(update('counter').remove(), update('name').remove()) + + expect(request.params.UpdateExpression).toBe('REMOVE #counter, #name') + expect(request.params.ExpressionAttributeNames).toEqual({ '#counter': 'counter', '#name': 'name' }) + expect(request.params.ExpressionAttributeValues).toBeUndefined() + }) + + it('remove from list at (single)', () => { + const now = moment() + const request = new UpdateRequest(null, UpdateModel, getTableName(UpdateModel), 'myId', now) + + request.operations(update('addresses').removeFromListAt(2)) + + expect(request.params.UpdateExpression).toBe('REMOVE #addresses[2]') + expect(request.params.ExpressionAttributeNames).toEqual({ '#addresses': 'addresses' }) + expect(request.params.ExpressionAttributeValues).toBeUndefined() + }) + + it('remove from list at (many)', () => { + const now = moment() + const request = new UpdateRequest(null, UpdateModel, getTableName(UpdateModel), 'myId', now) + + request.operations(update('addresses').removeFromListAt(2, 5, 6)) + + expect(request.params.UpdateExpression).toBe('REMOVE #addresses[2], #addresses[5], #addresses[6]') + expect(request.params.ExpressionAttributeNames).toEqual({ '#addresses': 'addresses' }) + expect(request.params.ExpressionAttributeValues).toBeUndefined() + }) + + it('add (multiple arr)', () => { + const now = moment() + const request = new UpdateRequest(null, UpdateModel, getTableName(UpdateModel), 'myId', now) + + request.operations(update('topics').add(['newTopic', 'newTopic2'])) + + expect(request.params.UpdateExpression).toBe('ADD #topics :topics') + expect(request.params.ExpressionAttributeNames).toEqual({ '#topics': 'topics' }) + expect(request.params.ExpressionAttributeValues).toEqual({ + ':topics': { + SS: ['newTopic', 'newTopic2'], + }, + }) + }) + + it('add (multiple set)', () => { + const now = moment() + const request = new UpdateRequest(null, UpdateModel, getTableName(UpdateModel), 'myId', now) + + request.operations(update('topics').add(new Set(['newTopic', 'newTopic2']))) + + expect(request.params.UpdateExpression).toBe('ADD #topics :topics') + expect(request.params.ExpressionAttributeNames).toEqual({ '#topics': 'topics' }) + expect(request.params.ExpressionAttributeValues).toEqual({ + ':topics': { + SS: ['newTopic', 'newTopic2'], + }, + }) + }) + + it('add (multiple vararg)', () => { + const now = moment() + const request = new UpdateRequest(null, UpdateModel, getTableName(UpdateModel), 'myId', now) + + request.operations(update('topics').add('newTopic', 'newTopic2')) + + expect(request.params.UpdateExpression).toBe('ADD #topics :topics') + expect(request.params.ExpressionAttributeNames).toEqual({ '#topics': 'topics' }) + expect(request.params.ExpressionAttributeValues).toEqual({ + ':topics': { + SS: ['newTopic', 'newTopic2'], + }, + }) + }) + + it('add (single)', () => { + const now = moment() + const request = new UpdateRequest(null, UpdateModel, getTableName(UpdateModel), 'myId', now) + + request.operations(update('topics').add('newTopic')) + + expect(request.params.UpdateExpression).toBe('ADD #topics :topics') + expect(request.params.ExpressionAttributeNames).toEqual({ '#topics': 'topics' }) + expect(request.params.ExpressionAttributeValues).toEqual({ + ':topics': { + SS: ['newTopic'], + }, + }) + }) + + it('remove from set (single)', () => { + const now = moment() + const request = new UpdateRequest(null, UpdateModel, getTableName(UpdateModel), 'myId', now) + + request.operations(update('topics').removeFromSet('newTopic')) + + expect(request.params.UpdateExpression).toBe('DELETE #topics :topics') + expect(request.params.ExpressionAttributeNames).toEqual({ '#topics': 'topics' }) + expect(request.params.ExpressionAttributeValues).toEqual({ + ':topics': { + SS: ['newTopic'], + }, + }) + }) + + it('remove from set (multiple vararg)', () => { + const now = moment() + const request = new UpdateRequest(null, UpdateModel, getTableName(UpdateModel), 'myId', now) + + request.operations(update('topics').removeFromSet('newTopic', 'newTopic2')) + + expect(request.params.UpdateExpression).toBe('DELETE #topics :topics') + expect(request.params.ExpressionAttributeNames).toEqual({ '#topics': 'topics' }) + expect(request.params.ExpressionAttributeValues).toEqual({ + ':topics': { + SS: ['newTopic', 'newTopic2'], + }, + }) + }) + + it('remove from set (multiple arr)', () => { + const now = moment() + const request = new UpdateRequest(null, UpdateModel, getTableName(UpdateModel), 'myId', now) + + request.operations(update('topics').removeFromSet(['newTopic', 'newTopic2'])) + + expect(request.params.UpdateExpression).toBe('DELETE #topics :topics') + expect(request.params.ExpressionAttributeNames).toEqual({ '#topics': 'topics' }) + expect(request.params.ExpressionAttributeValues).toEqual({ + ':topics': { + SS: ['newTopic', 'newTopic2'], + }, + }) + }) + + it('remove from set (multiple set)', () => { + const now = moment() + const request = new UpdateRequest(null, UpdateModel, getTableName(UpdateModel), 'myId', now) + + request.operations(update('topics').removeFromSet(new Set(['newTopic', 'newTopic2']))) + + expect(request.params.UpdateExpression).toBe('DELETE #topics :topics') + expect(request.params.ExpressionAttributeNames).toEqual({ '#topics': 'topics' }) + expect(request.params.ExpressionAttributeValues).toEqual({ + ':topics': { + SS: ['newTopic', 'newTopic2'], + }, + }) + }) + }) + }) + + describe('multiple operations', () => { + it('b', () => { + const now = moment() + + const request = new UpdateRequest(null, UpdateModel, getTableName(UpdateModel), 'myId', now) + request.operations(update('active').set(true), update('name').set('newName')) + + expect(request.params.UpdateExpression).toBe('SET #active = :active, #name = :name') + expect(request.params.ExpressionAttributeNames).toEqual({ '#active': 'isActive', '#name': 'name' }) + expect(request.params.ExpressionAttributeValues).toEqual({ + ':active': { BOOL: true }, + ':name': { S: 'newName' }, + }) }) }) }) diff --git a/test/models/update.model.ts b/test/models/update.model.ts index 004a456f4..a964e0802 100644 --- a/test/models/update.model.ts +++ b/test/models/update.model.ts @@ -3,6 +3,21 @@ import { PartitionKey } from '../../src/decorator/impl/key/partition-key.decorat import { Model } from '../../src/decorator/impl/model/model.decorator' import { Property } from '../../src/decorator/impl/property/property.decorator' +// tslint:disable-next-line:max-classes-per-file +@Model() +export class Address { + street: string + place: string + zip: number +} + +// tslint:disable-next-line:max-classes-per-file +@Model() +export class Info { + details: string +} + +// tslint:disable-next-line:max-classes-per-file @Model() export class UpdateModel { @PartitionKey() id: string @@ -17,4 +32,13 @@ export class UpdateModel { active: boolean counter: number + + // maps to L(ist) + addresses: Address[] + + // maps to M(ap) + info: Info + + // maps to S(tring)S(et) + topics: string[] }