diff --git a/lib/actions/table/InsertOrMergeEntity.js b/lib/actions/table/InsertOrMergeEntity.js new file mode 100644 index 0000000..ae120d3 --- /dev/null +++ b/lib/actions/table/InsertOrMergeEntity.js @@ -0,0 +1,21 @@ +'use strict'; + +const AzuriteTableResponse = require('./../../model/table/AzuriteTableResponse'), + tableStorageManager = require('./../../core/table/TableStorageManager'), + N = require('./../../core/HttpHeaderNames'); + +class InsertOrMergeEntity { + constructor() { + } + + process(request, res) { + tableStorageManager.insertOrMergeEntity(request) + .then((response) => { + response.addHttpProperty(N.ETAG, response.proxy.etag); + res.set(response.httpProps); + res.status(204).send(); + }); + } +} + +module.exports = new InsertOrMergeEntity; \ No newline at end of file diff --git a/lib/core/Constants.js b/lib/core/Constants.js index 4f7141d..696331d 100644 --- a/lib/core/Constants.js +++ b/lib/core/Constants.js @@ -113,7 +113,8 @@ const Operations = { QUERY_ENTITY: 'QueryEntity', UPDATE_ENTITY: 'UpdateEntity', INSERT_OR_REPLACE_ENTITY: 'InsertOrReplaceEntity', - MERGE_ENTITY: 'MergeEntity' + MERGE_ENTITY: 'MergeEntity', + INSERT_OR_MERGE_ENTITY: 'InsertOrMergeEntity' } } diff --git a/lib/core/table/TableStorageManager.js b/lib/core/table/TableStorageManager.js index ed5c36e..23c77fa 100644 --- a/lib/core/table/TableStorageManager.js +++ b/lib/core/table/TableStorageManager.js @@ -133,19 +133,13 @@ class TableStorageManager { } mergeEntity(request) { - const coll = this.db.getCollection(request.tableName), - entity = EntityGenerator.generateEntity(request.payload, request.tableName), - res = coll.findOne({ partitionKey: request.partitionKey, rowKey: request.rowKey }); + const proxy = this._insertOrMergeEntity(request.partitionKey, request.rowKey, request.tableName, request.payload); + return BbPromise.resolve(new AzuriteTableResponse({ proxy: proxy })); + } - // A property cannot be removed with a Merge Entity operation (in contrast to an update operation). - for (const key of Object.keys(entity.attribs)) { - if (entity.attribs[key]) { - res.attribs[key] = entity.attribs[key]; - } - } - res.odata = entity.odata; - coll.update(res); - return BbPromise.resolve(new AzuriteTableResponse({ proxy: new EntityProxy(res) })); + insertOrMergeEntity(request) { + const proxy = this._insertOrMergeEntity(request.partitionKey, request.rowKey, request.tableName, request.payload); + return BbPromise.resolve(new AzuriteTableResponse({ proxy: proxy })); } _getTable(name) { @@ -208,6 +202,25 @@ class TableStorageManager { const entityProxy = new EntityProxy(coll.insert(entity)); return entityProxy; } + + _insertOrMergeEntity(partitionKey, rowKey, tableName, rawEntity) { + const coll = this.db.getCollection(request.tableName), + entity = EntityGenerator.generateEntity(request.payload, request.tableName), + res = coll.findOne({ partitionKey: request.partitionKey, rowKey: request.rowKey }); + + if (res !== null) { + // A property cannot be removed with a Merge Entity operation (in contrast to an update operation). + for (const key of Object.keys(entity.attribs)) { + if (entity.attribs[key]) { + res.attribs[key] = entity.attribs[key]; + } + } + res.odata = entity.odata; + coll.update(res); + return new EntityProxy(res); + } + return this._createOrUpdateEntity(partitionKey, rowKey, tableName, rawEntity); + } } diff --git a/lib/middleware/table/actions.js b/lib/middleware/table/actions.js index a1c9a65..1ffa39c 100644 --- a/lib/middleware/table/actions.js +++ b/lib/middleware/table/actions.js @@ -10,6 +10,7 @@ const BbPromise = require('bluebird'), updateEntity = require('./../../actions/table/UpdateEntity'), insertOrReplaceEntity = require('./../../actions/table/InsertOrReplaceEntity'), mergeEntity = require('./../../actions/table/MergeEntity'), + insertOrMergeEntity = require('./../../actions/table/InsertOrMergeEntity'), createTable = require('./../../actions/table/CreateTable'); module.exports = (req, res) => { @@ -61,4 +62,8 @@ actions[Operations.INSERT_OR_REPLACE_ENTITY] = (request, res) => { actions[Operations.MERGE_ENTITY] = (request, res) => { mergeEntity.process(request, res); +} + +actions[Operations.INSERT_OR_MERGE_ENTITY] = (request, res) => { + insertOrMergeEntity.process(request, res); } \ No newline at end of file diff --git a/lib/middleware/table/validation.js b/lib/middleware/table/validation.js index 3279c02..43e9809 100644 --- a/lib/middleware/table/validation.js +++ b/lib/middleware/table/validation.js @@ -93,4 +93,9 @@ validations[Operations.MERGE_ENTITY] = (valContext) => { .run(TableExistsVal) .run(EntityExistsVal) .run(EntityIfMatchVal); +} + +validations[Operations.INSERT_OR_MERGE_ENTITY] = (valContext) => { + valContext + .run(TableExistsVal); } \ No newline at end of file diff --git a/lib/routes/table/EntityRoute.js b/lib/routes/table/EntityRoute.js index 7848666..b995147 100644 --- a/lib/routes/table/EntityRoute.js +++ b/lib/routes/table/EntityRoute.js @@ -42,8 +42,10 @@ module.exports = (app) => { next(); }) .merge((req, res, next) => { - req.azuriteOperation = Operations.MERGE_ENTITY; req.azuriteRequest = new AzuriteTableRequest({ req: req, payload: req.payload }); + req.azuriteOperation = req.azuriteRequest.httpProps[N.IF_MATCH] + ? Operations.MERGE_ENTITY + : Operations.INSERT_OR_MERGE_ENTITY; next(); }); } \ No newline at end of file