diff --git a/packages/medusa-test-utils/yarn.lock b/packages/medusa-test-utils/yarn.lock index 42c35acef3..51e89d11a7 100644 --- a/packages/medusa-test-utils/yarn.lock +++ b/packages/medusa-test-utils/yarn.lock @@ -971,6 +971,44 @@ exec-sh "^0.3.2" minimist "^1.2.0" +"@hapi/address@^2.1.2": + version "2.1.4" + resolved "https://registry.yarnpkg.com/@hapi/address/-/address-2.1.4.tgz#5d67ed43f3fd41a69d4b9ff7b56e7c0d1d0a81e5" + integrity sha512-QD1PhQk+s31P1ixsX0H0Suoupp3VMXzIVMSwobR3F3MSUO2YCV0B7xqLcUw/Bh8yuvd3LhpyqLQWTNcRmp6IdQ== + +"@hapi/formula@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@hapi/formula/-/formula-1.2.0.tgz#994649c7fea1a90b91a0a1e6d983523f680e10cd" + integrity sha512-UFbtbGPjstz0eWHb+ga/GM3Z9EzqKXFWIbSOFURU0A/Gku0Bky4bCk9/h//K2Xr3IrCfjFNhMm4jyZ5dbCewGA== + +"@hapi/hoek@^8.2.4", "@hapi/hoek@^8.3.0": + version "8.5.1" + resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-8.5.1.tgz#fde96064ca446dec8c55a8c2f130957b070c6e06" + integrity sha512-yN7kbciD87WzLGc5539Tn0sApjyiGHAJgKvG9W8C7O+6c7qmoQMfVs0W4bX17eqz6C78QJqqFrtgdK5EWf6Qow== + +"@hapi/joi@^16.1.8": + version "16.1.8" + resolved "https://registry.yarnpkg.com/@hapi/joi/-/joi-16.1.8.tgz#84c1f126269489871ad4e2decc786e0adef06839" + integrity sha512-wAsVvTPe+FwSrsAurNt5vkg3zo+TblvC5Bb1zMVK6SJzZqw9UrJnexxR+76cpePmtUZKHAPxcQ2Bf7oVHyahhg== + dependencies: + "@hapi/address" "^2.1.2" + "@hapi/formula" "^1.2.0" + "@hapi/hoek" "^8.2.4" + "@hapi/pinpoint" "^1.0.2" + "@hapi/topo" "^3.1.3" + +"@hapi/pinpoint@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@hapi/pinpoint/-/pinpoint-1.0.2.tgz#025b7a36dbbf4d35bf1acd071c26b20ef41e0d13" + integrity sha512-dtXC/WkZBfC5vxscazuiJ6iq4j9oNx1SHknmIr8hofarpKUZKmlUVYVIhNVzIEgK5Wrc4GMHL5lZtt1uS2flmQ== + +"@hapi/topo@^3.1.3": + version "3.1.6" + resolved "https://registry.yarnpkg.com/@hapi/topo/-/topo-3.1.6.tgz#68d935fa3eae7fdd5ab0d7f953f3205d8b2bfc29" + integrity sha512-tAag0jEcjwH+P2quUfipd7liWCNX2F8NvYjQp2wtInsZxnMlypdw0FtAOLxtvvkO+GSRRbmNi8m/5y42PQJYCQ== + dependencies: + "@hapi/hoek" "^8.3.0" + "@istanbuljs/load-nyc-config@^1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.0.0.tgz#10602de5570baea82f8afbfa2630b24e7a8cfe5b" @@ -3254,6 +3292,11 @@ jest@^25.5.2: import-local "^3.0.2" jest-cli "^25.5.2" +joi-objectid@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/joi-objectid/-/joi-objectid-3.0.1.tgz#63ace7860f8e1a993a28d40c40ffd8eff01a3668" + integrity sha512-V/3hbTlGpvJ03Me6DJbdBI08hBTasFOmipsauOsxOSnsF1blxV537WTl1zPwbfcKle4AK0Ma4OPnzMH4LlvTpQ== + "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" @@ -3487,6 +3530,14 @@ map-visit@^1.0.0: dependencies: object-visit "^1.0.0" +medusa-core-utils@^0.3.0: + version "0.1.39" + resolved "https://registry.yarnpkg.com/medusa-core-utils/-/medusa-core-utils-0.1.39.tgz#d57816c9bd43f9a92883650c1e66add1665291df" + integrity sha512-R8+U1ile7if+nR6Cjh5exunx0ETV0OfkWUUBUpz1KmHSDv0V0CcvQqU9lcZesPFDEbu3Y2iEjsCqidVA4nG2nQ== + dependencies: + "@hapi/joi" "^16.1.8" + joi-objectid "^3.0.1" + memory-pager@^1.0.2: version "1.5.0" resolved "https://registry.yarnpkg.com/memory-pager/-/memory-pager-1.5.0.tgz#d8751655d22d384682741c972f2c3d6dfa3e66b5" diff --git a/packages/medusa/src/models/__mocks__/cart.js b/packages/medusa/src/models/__mocks__/cart.js index 906842177e..f3a0e0bcb8 100644 --- a/packages/medusa/src/models/__mocks__/cart.js +++ b/packages/medusa/src/models/__mocks__/cart.js @@ -143,6 +143,23 @@ export const carts = { }, quantity: 10, }, + { + _id: IdMap.getId("itemToRemove"), + title: "merge line", + description: "This is a new line", + thumbnail: "test-img-yeah.com/thumb", + content: { + unit_price: 123, + variant: { + _id: IdMap.getId("can-cover"), + }, + product: { + _id: IdMap.getId("product"), + }, + quantity: 1, + }, + quantity: 1, + }, ], shipping_address: {}, billing_address: {}, diff --git a/packages/medusa/src/services/__tests__/cart.js b/packages/medusa/src/services/__tests__/cart.js index 26eae60d26..671ec0b421 100644 --- a/packages/medusa/src/services/__tests__/cart.js +++ b/packages/medusa/src/services/__tests__/cart.js @@ -14,6 +14,7 @@ import { CartModelMock, carts } from "../../models/__mocks__/cart" import { LineItemServiceMock } from "../__mocks__/line-item" import { DiscountModelMock, discounts } from "../../models/__mocks__/discount" import { DiscountServiceMock } from "../__mocks__/discount" +import idMap from "medusa-test-utils/dist/id-map" describe("CartService", () => { describe("retrieve", () => { @@ -78,6 +79,46 @@ describe("CartService", () => { }) }) + describe("deleteMetadata", () => { + const cartService = new CartService({ + cartModel: CartModelMock, + eventBusService: EventBusServiceMock, + }) + + beforeEach(() => { + jest.clearAllMocks() + }) + + it("calls updateOne with correct params", async () => { + const id = mongoose.Types.ObjectId() + await cartService.deleteMetadata(`${id}`, "metadata") + + expect(EventBusServiceMock.emit).toHaveBeenCalledTimes(1) + expect(EventBusServiceMock.emit).toHaveBeenCalledWith( + "cart.updated", + expect.any(Object) + ) + + expect(CartModelMock.updateOne).toBeCalledTimes(1) + expect(CartModelMock.updateOne).toBeCalledWith( + { _id: `${id}` }, + { $unset: { "metadata.metadata": "" } } + ) + }) + + it("throw error on invalid key type", async () => { + const id = mongoose.Types.ObjectId() + + try { + await cartService.deleteMetadata(`${id}`, 1234) + } catch (err) { + expect(err.message).toEqual( + "Key type is invalid. Metadata keys must be strings" + ) + } + }) + }) + describe("create", () => { const cartService = new CartService({ cartModel: CartModelMock, @@ -297,6 +338,75 @@ describe("CartService", () => { }) }) + describe("removeLineItem", () => { + const cartService = new CartService({ + cartModel: CartModelMock, + productVariantService: ProductVariantServiceMock, + lineItemService: LineItemServiceMock, + eventBusService: EventBusServiceMock, + }) + + beforeEach(() => { + jest.clearAllMocks() + }) + + it("successfully removes a line item", async () => { + await cartService.removeLineItem( + IdMap.getId("cartWithLine"), + IdMap.getId("itemToRemove") + ) + + expect(EventBusServiceMock.emit).toHaveBeenCalledTimes(1) + expect(EventBusServiceMock.emit).toHaveBeenCalledWith( + "cart.updated", + expect.any(Object) + ) + + expect(CartModelMock.updateOne).toHaveBeenCalledTimes(1) + expect(CartModelMock.updateOne).toHaveBeenCalledWith( + { + _id: IdMap.getId("cartWithLine"), + }, + { + $pull: { items: { _id: IdMap.getId("itemToRemove") } }, + } + ) + }) + + it("successfully decrements quantity if more than 1", async () => { + await cartService.removeLineItem( + IdMap.getId("cartWithLine"), + IdMap.getId("existingLine") + ) + + expect(EventBusServiceMock.emit).toHaveBeenCalledTimes(1) + expect(EventBusServiceMock.emit).toHaveBeenCalledWith( + "cart.updated", + expect.any(Object) + ) + + expect(CartModelMock.updateOne).toHaveBeenCalledTimes(1) + expect(CartModelMock.updateOne).toHaveBeenCalledWith( + { + _id: IdMap.getId("cartWithLine"), + "items._id": IdMap.getId("existingLine"), + }, + { + $set: { "items.$.quantity": 9 }, + } + ) + }) + + it("resolves if line item is not in cart", async () => { + await cartService.removeLineItem( + IdMap.getId("cartWithLine"), + IdMap.getId("nonExisting") + ) + + expect(CartModelMock.updateOne).toHaveBeenCalledTimes(0) + }) + }) + describe("updateLineItem", () => { const cartService = new CartService({ cartModel: CartModelMock, diff --git a/packages/medusa/src/services/__tests__/shipping-option.js b/packages/medusa/src/services/__tests__/shipping-option.js index e4a4696be3..20ddb4bc8f 100644 --- a/packages/medusa/src/services/__tests__/shipping-option.js +++ b/packages/medusa/src/services/__tests__/shipping-option.js @@ -87,17 +87,23 @@ describe("ShippingOptionService", () => { }) it("throw error on invalid key type", async () => { - const id = mongoose.Types.ObjectId() - - expect(() => optionService.setMetadata(`${id}`, 1234, "nono")).toThrow( - "Key type is invalid. Metadata keys must be strings" - ) + try { + optionService.setMetadata(IdMap.getId("test"), 1234, "nono") + } catch (error) { + expect(error.message).toEqual( + "Key type is invalid. Metadata keys must be strings" + ) + } }) it("throws error on invalid optionId type", async () => { - expect(() => + try { optionService.setMetadata("fakeProfileId", 1234, "nono") - ).toThrow("The shippingOptionId could not be casted to an ObjectId") + } catch (error) { + expect(error.message).toEqual( + "The shippingOptionId could not be casted to an ObjectId" + ) + } }) }) diff --git a/packages/medusa/src/services/__tests__/shipping-profile.js b/packages/medusa/src/services/__tests__/shipping-profile.js index 39d304203f..9a49f349bd 100644 --- a/packages/medusa/src/services/__tests__/shipping-profile.js +++ b/packages/medusa/src/services/__tests__/shipping-profile.js @@ -146,7 +146,7 @@ describe("ShippingProfileService", () => { it("throws error on invalid profileId type", async () => { try { - await profileService.setMetadata("fakeProfileId", 1234, "nono") + await profileService.setMetadata("fakeProfileId", "1234", "nono") } catch (err) { expect(err.message).toEqual( "The profileId could not be casted to an ObjectId" diff --git a/packages/medusa/src/services/cart.js b/packages/medusa/src/services/cart.js index c89f013edc..29d52c3d59 100644 --- a/packages/medusa/src/services/cart.js +++ b/packages/medusa/src/services/cart.js @@ -230,6 +230,62 @@ class CartService extends BaseService { return c } + /** + * Removes a line item from the cart. + * @param {string} cartId - the id of the cart that we will remove from + * @param {LineItem} lineItemId - the line item to remove. + * @retur {Promise} the result of the update operation + */ + async removeLineItem(cartId, lineItemId) { + const cart = await this.retrieve(cartId) + const itemToRemove = cart.items.find(line => line._id === lineItemId) + + if (!itemToRemove) { + return Promise.resolve() + } + + // If cart has more than one of those line items, we update the quantity + // instead of removing it + if (itemToRemove.quantity > 1) { + const newQuantity = itemToRemove.quantity - 1 + + return this.cartModel_ + .updateOne( + { + _id: cartId, + "items._id": itemToRemove._id, + }, + { + $set: { + "items.$.quantity": newQuantity, + }, + } + ) + .then(result => { + // Notify subscribers + this.eventBus_.emit(CartService.Events.UPDATED, result) + return result + }) + } + + return this.cartModel_ + .updateOne( + { + _id: cartId, + }, + { + $pull: { + items: { _id: itemToRemove._id }, + }, + } + ) + .then(result => { + // Notify subscribers + this.eventBus_.emit(CartService.Events.UPDATED, result) + return result + }) + } + /** * Adds a line item to the cart. * @param {string} cartId - the id of the cart that we will add to @@ -929,7 +985,7 @@ class CartService extends BaseService { * @param {string} value - value for metadata field. * @return {Promise} resolves to the updated result. */ - setMetadata(cartId, key, value) { + async setMetadata(cartId, key, value) { const validatedId = this.validateId_(cartId) if (typeof key !== "string") { @@ -951,6 +1007,35 @@ class CartService extends BaseService { throw new MedusaError(MedusaError.Types.DB_ERROR, err.message) }) } + + /** + * Dedicated method to delete metadata for a cart. + * @param {string} cartId - the cart to delete metadata from. + * @param {string} key - key for metadata field + * @return {Promise} resolves to the updated result. + */ + async deleteMetadata(cartId, key) { + const validatedId = this.validateId_(cartId) + + if (typeof key !== "string") { + throw new MedusaError( + MedusaError.Types.INVALID_ARGUMENT, + "Key type is invalid. Metadata keys must be strings" + ) + } + + const keyPath = `metadata.${key}` + return this.cartModel_ + .updateOne({ _id: validatedId }, { $unset: { [keyPath]: "" } }) + .then(result => { + // Notify subscribers + this.eventBus_.emit(CartService.Events.UPDATED, result) + return result + }) + .catch(err => { + throw new MedusaError(MedusaError.Types.DB_ERROR, err.message) + }) + } } export default CartService diff --git a/packages/medusa/src/services/customer.js b/packages/medusa/src/services/customer.js index ff3b1b0646..ba91e4cf69 100644 --- a/packages/medusa/src/services/customer.js +++ b/packages/medusa/src/services/customer.js @@ -270,7 +270,7 @@ class CustomerService extends BaseService { * @param {string} value - value for metadata field. * @return {Promise} resolves to the updated result. */ - setMetadata(customerId, key, value) { + async setMetadata(customerId, key, value) { const validatedId = this.validateId_(customerId) if (typeof key !== "string") { @@ -287,6 +287,30 @@ class CustomerService extends BaseService { throw new MedusaError(MedusaError.Types.DB_ERROR, err.message) }) } + + /** + * Dedicated method to delete metadata for a customer. + * @param {string} customerId - the customer to delete metadata from. + * @param {string} key - key for metadata field + * @return {Promise} resolves to the updated result. + */ + async deleteMetadata(customerId, key) { + const validatedId = this.validateId_(customerId) + + if (typeof key !== "string") { + throw new MedusaError( + MedusaError.Types.INVALID_ARGUMENT, + "Key type is invalid. Metadata keys must be strings" + ) + } + + const keyPath = `metadata.${key}` + return this.customerModel_ + .updateOne({ _id: validatedId }, { $unset: { [keyPath]: "" } }) + .catch(err => { + throw new MedusaError(MedusaError.Types.DB_ERROR, err.message) + }) + } } export default CustomerService diff --git a/packages/medusa/src/services/discount.js b/packages/medusa/src/services/discount.js index 513c50461d..8bd333ae99 100644 --- a/packages/medusa/src/services/discount.js +++ b/packages/medusa/src/services/discount.js @@ -286,7 +286,7 @@ class DiscountService extends BaseService { * @param {string} value - value for metadata field. * @return {Promise} resolves to the updated result. */ - setMetadata(discountId, key, value) { + async setMetadata(discountId, key, value) { const validatedId = this.validateId_(discountId) if (typeof key !== "string") { @@ -303,6 +303,30 @@ class DiscountService extends BaseService { throw new MedusaError(MedusaError.Types.DB_ERROR, err.message) }) } + + /** + * Dedicated method to delete metadata for a discount. + * @param {string} discountId - the discount to delete metadata from. + * @param {string} key - key for metadata field + * @return {Promise} resolves to the updated result. + */ + async deleteMetadata(discountId, key) { + const validatedId = this.validateId_(discountId) + + if (typeof key !== "string") { + throw new MedusaError( + MedusaError.Types.INVALID_ARGUMENT, + "Key type is invalid. Metadata keys must be strings" + ) + } + + const keyPath = `metadata.${key}` + return this.discountModel_ + .updateOne({ _id: validatedId }, { $unset: { [keyPath]: "" } }) + .catch(err => { + throw new MedusaError(MedusaError.Types.DB_ERROR, err.message) + }) + } } export default DiscountService diff --git a/packages/medusa/src/services/order.js b/packages/medusa/src/services/order.js index 2f3ef87b78..769926efdc 100644 --- a/packages/medusa/src/services/order.js +++ b/packages/medusa/src/services/order.js @@ -496,7 +496,7 @@ class OrderService extends BaseService { * @param {string} value - value for metadata field. * @return {Promise} resolves to the updated result. */ - setMetadata(orderId, key, value) { + async setMetadata(orderId, key, value) { const validatedId = this.validateId_(orderId) if (typeof key !== "string") { @@ -513,6 +513,30 @@ class OrderService extends BaseService { throw new MedusaError(MedusaError.Types.DB_ERROR, err.message) }) } + + /** + * Dedicated method to delete metadata for an order. + * @param {string} orderId - the order to delete metadata from. + * @param {string} key - key for metadata field + * @return {Promise} resolves to the updated result. + */ + async deleteMetadata(orderId, key) { + const validatedId = this.validateId_(orderId) + + if (typeof key !== "string") { + throw new MedusaError( + MedusaError.Types.INVALID_ARGUMENT, + "Key type is invalid. Metadata keys must be strings" + ) + } + + const keyPath = `metadata.${key}` + return this.orderModel_ + .updateOne({ _id: validatedId }, { $unset: { [keyPath]: "" } }) + .catch(err => { + throw new MedusaError(MedusaError.Types.DB_ERROR, err.message) + }) + } } export default OrderService diff --git a/packages/medusa/src/services/product-variant.js b/packages/medusa/src/services/product-variant.js index a67946d2de..96e2bde2a8 100644 --- a/packages/medusa/src/services/product-variant.js +++ b/packages/medusa/src/services/product-variant.js @@ -505,7 +505,7 @@ class ProductVariantService extends BaseService { * @param {string} value - value for metadata field. * @return {Promise} resolves to the updated result. */ - setMetadata(variantId, key, value) { + async setMetadata(variantId, key, value) { const validatedId = this.validateId_(variantId) if (typeof key !== "string") { @@ -522,6 +522,30 @@ class ProductVariantService extends BaseService { throw new MedusaError(MedusaError.Types.DB_ERROR, err.message) }) } + + /** + * Dedicated method to delete metadata for a product variant. + * @param {string} variantId - the product variant to delete metadata from. + * @param {string} key - key for metadata field + * @return {Promise} resolves to the updated result. + */ + async deleteMetadata(variantId, key) { + const validatedId = this.validateId_(variantId) + + if (typeof key !== "string") { + throw new MedusaError( + MedusaError.Types.INVALID_ARGUMENT, + "Key type is invalid. Metadata keys must be strings" + ) + } + + const keyPath = `metadata.${key}` + return this.productVariantModel_ + .updateOne({ _id: validatedId }, { $unset: { [keyPath]: "" } }) + .catch(err => { + throw new MedusaError(MedusaError.Types.DB_ERROR, err.message) + }) + } } export default ProductVariantService diff --git a/packages/medusa/src/services/product.js b/packages/medusa/src/services/product.js index d01ecb2dac..1bd5729fb6 100644 --- a/packages/medusa/src/services/product.js +++ b/packages/medusa/src/services/product.js @@ -692,7 +692,7 @@ class ProductService extends BaseService { * @param {string} value - value for metadata field. * @return {Promise} resolves to the updated result. */ - setMetadata(productId, key, value) { + async setMetadata(productId, key, value) { const validatedId = this.validateId_(productId) if (typeof key !== "string") { @@ -713,6 +713,30 @@ class ProductService extends BaseService { throw new MedusaError(MedusaError.Types.DB_ERROR, err.message) }) } + + /** + * Dedicated method to delete metadata for a product. + * @param {string} productId - the product to delete metadata from. + * @param {string} key - key for metadata field + * @return {Promise} resolves to the updated result. + */ + async deleteMetadata(productId, key) { + const validatedId = this.validateId_(productId) + + if (typeof key !== "string") { + throw new MedusaError( + MedusaError.Types.INVALID_ARGUMENT, + "Key type is invalid. Metadata keys must be strings" + ) + } + + const keyPath = `metadata.${key}` + return this.productModel_ + .updateOne({ _id: validatedId }, { $unset: { [keyPath]: "" } }) + .catch(err => { + throw new MedusaError(MedusaError.Types.DB_ERROR, err.message) + }) + } } export default ProductService diff --git a/packages/medusa/src/services/shipping-option.js b/packages/medusa/src/services/shipping-option.js index ec41f85e9c..597a65fc88 100644 --- a/packages/medusa/src/services/shipping-option.js +++ b/packages/medusa/src/services/shipping-option.js @@ -412,7 +412,7 @@ class ShippingOptionService extends BaseService { * @param {string} value - value for metadata field. * @return {Promise} resolves to the updated result. */ - setMetadata(optionId, key, value) { + async setMetadata(optionId, key, value) { const validatedId = this.validateId_(optionId) if (typeof key !== "string") { @@ -429,6 +429,30 @@ class ShippingOptionService extends BaseService { throw new MedusaError(MedusaError.Types.DB_ERROR, err.message) }) } + + /** + * Dedicated method to delete metadata for a shipping option. + * @param {string} optionId - the shipping option to delete metadata from. + * @param {string} key - key for metadata field + * @return {Promise} resolves to the updated result. + */ + async deleteMetadata(optionId, key) { + const validatedId = this.validateId_(optionId) + + if (typeof key !== "string") { + throw new MedusaError( + MedusaError.Types.INVALID_ARGUMENT, + "Key type is invalid. Metadata keys must be strings" + ) + } + + const keyPath = `metadata.${key}` + return this.optionModel_ + .updateOne({ _id: validatedId }, { $unset: { [keyPath]: "" } }) + .catch(err => { + throw new MedusaError(MedusaError.Types.DB_ERROR, err.message) + }) + } } export default ShippingOptionService diff --git a/packages/medusa/src/services/shipping-profile.js b/packages/medusa/src/services/shipping-profile.js index 66c37b9954..18b22b24cc 100644 --- a/packages/medusa/src/services/shipping-profile.js +++ b/packages/medusa/src/services/shipping-profile.js @@ -382,7 +382,7 @@ class ShippingProfileService extends BaseService { * @param {string} value - value for metadata field. * @return {Promise} resolves to the updated result. */ - setMetadata(profileId, key, value) { + async setMetadata(profileId, key, value) { const validatedId = this.validateId_(profileId) if (typeof key !== "string") { @@ -399,6 +399,30 @@ class ShippingProfileService extends BaseService { throw new MedusaError(MedusaError.Types.DB_ERROR, err.message) }) } + + /** + * Dedicated method to delete metadata for a shipping profile. + * @param {string} profileId - the shipping profile to delete metadata from. + * @param {string} key - key for metadata field + * @return {Promise} resolves to the updated result. + */ + async deleteMetadata(profileId, key) { + const validatedId = this.validateId_(profileId) + + if (typeof key !== "string") { + throw new MedusaError( + MedusaError.Types.INVALID_ARGUMENT, + "Key type is invalid. Metadata keys must be strings" + ) + } + + const keyPath = `metadata.${key}` + return this.profileModel_ + .updateOne({ _id: validatedId }, { $unset: { [keyPath]: "" } }) + .catch(err => { + throw new MedusaError(MedusaError.Types.DB_ERROR, err.message) + }) + } } export default ShippingProfileService diff --git a/packages/medusa/src/services/user.js b/packages/medusa/src/services/user.js index 1fbeb02a20..7e6a1da349 100644 --- a/packages/medusa/src/services/user.js +++ b/packages/medusa/src/services/user.js @@ -279,7 +279,7 @@ class UserService extends BaseService { * @param {string} value - value for metadata field. * @return {Promise} resolves to the updated result. */ - setMetadata(userId, key, value) { + async setMetadata(userId, key, value) { const validatedId = this.validateId_(userId) if (typeof key !== "string") { @@ -296,6 +296,30 @@ class UserService extends BaseService { throw new MedusaError(MedusaError.Types.DB_ERROR, err.message) }) } + + /** + * Dedicated method to delete metadata for a user. + * @param {string} userId - the user to delete metadata from. + * @param {string} key - key for metadata field + * @return {Promise} resolves to the updated result. + */ + async deleteMetadata(userId, key) { + const validatedId = this.validateId_(userId) + + if (typeof key !== "string") { + throw new MedusaError( + MedusaError.Types.INVALID_ARGUMENT, + "Key type is invalid. Metadata keys must be strings" + ) + } + + const keyPath = `metadata.${key}` + return this.userModel_ + .updateOne({ _id: validatedId }, { $unset: { [keyPath]: "" } }) + .catch(err => { + throw new MedusaError(MedusaError.Types.DB_ERROR, err.message) + }) + } } export default UserService