@@ -2,7 +2,7 @@ import toReadableStream from "to-readable-stream";
22
33import BufferStream from "../../common/utils/BufferStream" ;
44import {
5- checkEtagIsInvalidFormat ,
5+ isEtagValid ,
66 getUTF8ByteSize ,
77 newTableEntityEtag
88} from "../utils/utils" ;
@@ -40,6 +40,7 @@ import {
4040} from "../utils/utils" ;
4141import BaseHandler from "./BaseHandler" ;
4242import { EdmType , getEdmType } from "../entity/IEdmType" ;
43+ import { truncatedISO8061Date } from "../../common/utils/utils" ;
4344
4445interface IPartialResponsePreferProperties {
4546 statusCode : 200 | 201 | 204 ;
@@ -198,18 +199,17 @@ export default class TableHandler extends BaseHandler implements ITableHandler {
198199 throw StorageErrorFactory . getPropertiesNeedValue ( context ) ;
199200 }
200201
201- this . checkProperties ( context , options . tableEntityProperties ) ;
202-
203- const entity : Entity = {
204- PartitionKey : options . tableEntityProperties . PartitionKey ,
205- RowKey : options . tableEntityProperties . RowKey ,
206- properties : options . tableEntityProperties ,
207- lastModifiedTime : context . startTime ! ,
208- eTag : newTableEntityEtag ( context . startTime ! )
209- } ;
210202 // check that key properties are valid
211- this . validateKey ( context , entity . PartitionKey ) ;
212- this . validateKey ( context , entity . RowKey ) ;
203+ this . validateKey ( context , options . tableEntityProperties . PartitionKey ) ;
204+ this . validateKey ( context , options . tableEntityProperties . RowKey ) ;
205+
206+ this . checkProperties ( context , options . tableEntityProperties ) ;
207+ const entity : Entity = this . createPersistedEntity (
208+ context ,
209+ options ,
210+ options . tableEntityProperties . PartitionKey ,
211+ options . tableEntityProperties . RowKey
212+ ) ;
213213 let normalizedEntity ;
214214 try {
215215 normalizedEntity = new NormalizedEntity ( entity ) ;
@@ -284,6 +284,31 @@ export default class TableHandler extends BaseHandler implements ITableHandler {
284284 return response ;
285285 }
286286
287+ private createPersistedEntity (
288+ context : Context ,
289+ options :
290+ | Models . TableMergeEntityOptionalParams
291+ | Models . TableInsertEntityOptionalParams
292+ | Models . TableUpdateEntityOptionalParams ,
293+ partitionKey : string ,
294+ rowKey : string
295+ ) {
296+ const modTime = truncatedISO8061Date ( context . startTime ! , true , true ) ;
297+ const eTag = newTableEntityEtag ( modTime ) ;
298+
299+ const entity : Entity = {
300+ PartitionKey : partitionKey ,
301+ RowKey : rowKey ,
302+ properties :
303+ options . tableEntityProperties === undefined
304+ ? { }
305+ : options . tableEntityProperties ,
306+ lastModifiedTime : modTime ,
307+ eTag
308+ } ;
309+ return entity ;
310+ }
311+
287312 private static getAndCheck (
288313 key : string | undefined ,
289314 getFromContext : ( ) => string ,
@@ -367,25 +392,21 @@ export default class TableHandler extends BaseHandler implements ITableHandler {
367392 throw StorageErrorFactory . getPreconditionFailed ( context ) ;
368393 }
369394 if ( options ?. ifMatch && options . ifMatch !== "*" ) {
370- if ( checkEtagIsInvalidFormat ( options . ifMatch ) ) {
395+ if ( isEtagValid ( options . ifMatch ) ) {
371396 throw StorageErrorFactory . getInvalidOperation ( context ) ;
372397 }
373398 }
399+ // check that key properties are valid
400+ this . validateKey ( context , partitionKey ) ;
401+ this . validateKey ( context , rowKey ) ;
374402
375- const eTag = newTableEntityEtag ( context . startTime ! ) ;
376-
377- // Entity, which is used to update an existing entity
378- const entity : Entity = {
379- PartitionKey : partitionKey ,
380- RowKey : rowKey ,
381- properties : options . tableEntityProperties ,
382- lastModifiedTime : context . startTime ! ,
383- eTag
384- } ;
403+ const entity : Entity = this . createPersistedEntity (
404+ context ,
405+ options ,
406+ partitionKey ,
407+ rowKey
408+ ) ;
385409
386- // check that key properties are valid
387- this . validateKey ( context , entity . PartitionKey ) ;
388- this . validateKey ( context , entity . RowKey ) ;
389410 let normalizedEntity ;
390411 try {
391412 normalizedEntity = new NormalizedEntity ( entity ) ;
@@ -413,7 +434,7 @@ export default class TableHandler extends BaseHandler implements ITableHandler {
413434 requestId : tableContext . contextID ,
414435 version : TABLE_API_VERSION ,
415436 date : context . startTime ,
416- eTag,
437+ eTag : entity . eTag ,
417438 statusCode : 204
418439 } ;
419440
@@ -443,7 +464,7 @@ export default class TableHandler extends BaseHandler implements ITableHandler {
443464 throw StorageErrorFactory . getPropertiesNeedValue ( context ) ;
444465 }
445466 if ( options ?. ifMatch && options . ifMatch !== "*" && options . ifMatch !== "" ) {
446- if ( checkEtagIsInvalidFormat ( options . ifMatch ) ) {
467+ if ( isEtagValid ( options . ifMatch ) ) {
447468 throw StorageErrorFactory . getInvalidOperation ( context ) ;
448469 }
449470 }
@@ -456,20 +477,17 @@ export default class TableHandler extends BaseHandler implements ITableHandler {
456477 `TableHandler:mergeEntity() Incoming PartitionKey:${ partitionKey } RowKey:${ rowKey } in URL parameters don't align with entity body PartitionKey:${ options . tableEntityProperties . PartitionKey } RowKey:${ options . tableEntityProperties . RowKey } .`
457478 ) ;
458479 }
480+ // check that key properties are valid
481+ this . validateKey ( context , partitionKey ) ;
482+ this . validateKey ( context , rowKey ) ;
459483
460484 this . checkProperties ( context , options . tableEntityProperties ) ;
461- const eTag = newTableEntityEtag ( context . startTime ! ) ;
462-
463- const entity : Entity = {
464- PartitionKey : partitionKey ,
465- RowKey : rowKey ,
466- properties : options . tableEntityProperties ,
467- lastModifiedTime : context . startTime ! ,
468- eTag
469- } ;
470- // check that key properties are valid
471- this . validateKey ( context , entity . PartitionKey ) ;
472- this . validateKey ( context , entity . RowKey ) ;
485+ const entity : Entity = this . createPersistedEntity (
486+ context ,
487+ options ,
488+ partitionKey ,
489+ rowKey
490+ ) ;
473491 let normalizedEntity ;
474492 try {
475493 normalizedEntity = new NormalizedEntity ( entity ) ;
@@ -497,7 +515,7 @@ export default class TableHandler extends BaseHandler implements ITableHandler {
497515 version : TABLE_API_VERSION ,
498516 date : context . startTime ,
499517 statusCode : 204 ,
500- eTag
518+ eTag : entity . eTag
501519 } ;
502520
503521 return response ;
@@ -524,7 +542,7 @@ export default class TableHandler extends BaseHandler implements ITableHandler {
524542 if ( ifMatch === "" || ifMatch === undefined ) {
525543 throw StorageErrorFactory . getPreconditionFailed ( context ) ;
526544 }
527- if ( ifMatch !== "*" && checkEtagIsInvalidFormat ( ifMatch ) ) {
545+ if ( ifMatch !== "*" && isEtagValid ( ifMatch ) ) {
528546 throw StorageErrorFactory . getInvalidOperation ( context ) ;
529547 }
530548 // currently the props are not coming through as args, so we take them from the table context
@@ -1009,7 +1027,7 @@ export default class TableHandler extends BaseHandler implements ITableHandler {
10091027 // key is a string value that may be up to 1 KiB in size.
10101028 // although a little arbitrary, for performance and
10111029 // generally a better idea, choosing a shorter length
1012- if ( key . length > DEFAULT_KEY_MAX_LENGTH ) {
1030+ if ( key !== undefined && key . length > DEFAULT_KEY_MAX_LENGTH ) {
10131031 throw StorageErrorFactory . getInvalidInput ( context ) ;
10141032 }
10151033 const match = key . match ( / [ \u0000 - \u001f \u007f - \u009f \/ \\ \# \? ] + / ) ;
@@ -1037,14 +1055,17 @@ export default class TableHandler extends BaseHandler implements ITableHandler {
10371055 ) {
10381056 for ( const prop in properties ) {
10391057 if ( properties . hasOwnProperty ( prop ) ) {
1040- if ( null !== properties [ prop ] && undefined !== properties [ prop ] . length ) {
1058+ if (
1059+ null !== properties [ prop ] &&
1060+ undefined !== properties [ prop ] . length
1061+ ) {
10411062 const typeKey = `${ prop } ${ ODATA_TYPE } ` ;
10421063 let type ;
10431064 if ( properties [ typeKey ] ) {
1044- type = getEdmType ( properties [ typeKey ] )
1065+ type = getEdmType ( properties [ typeKey ] ) ;
10451066 }
10461067 if ( type === EdmType . Binary ) {
1047- if ( Buffer . from ( properties [ prop ] , ' base64' ) . length > 64 * 1024 ) {
1068+ if ( Buffer . from ( properties [ prop ] , " base64" ) . length > 64 * 1024 ) {
10481069 throw StorageErrorFactory . getPropertyValueTooLargeError ( context ) ;
10491070 }
10501071 } else if ( properties [ prop ] . length > 32 * 1024 ) {
0 commit comments