feat(medusa): Add proper pagination (#4517)

* update method for listing regions

* add changeset

* fix unit tests

* listAndCount swaps

* add count calculation to list-returns

* swap integration test

* notes pagination

* pagination props for notifications

* listAndCount store regions

* fix nit

* fix note unit test

* update list-regions store unit test

* cleanup integration test

* rename introduced tests

---------

Co-authored-by: Oliver Windall Juhl <59018053+olivermrbl@users.noreply.github.com>
This commit is contained in:
Philip KorsholmandOliver Windall Juhl authored and GitHub committed 2023-07-14 16:14:51 +02:00
1 parent 55db914151
commit 5b91a3503a
21 files changed
+401 -192

No files matched your search

@@ -163,6 +163,22 @@ describe("/admin/notes", () => {
], ],
}) })
}) })
it("should list the notes with correct count in pagination", async () => {
const api = useApi()
const response = await api
.get("/admin/notes?limit=2", {
headers: {
authorization: "Bearer test_token",
},
})
.catch((err) => {
console.log(err)
})
expect(response.data.notes.length).toEqual(2)
expect(response.data.count).toEqual(3)
})
}) })
describe("POST /admin/notes/:id", () => { describe("POST /admin/notes/:id", () => {
+30 -73
View File
@@ -24,6 +24,12 @@ const {
jest.setTimeout(30000) jest.setTimeout(30000)
const adminHeaders = {
headers: {
Authorization: "Bearer test_token",
},
}
describe("/admin/swaps", () => { describe("/admin/swaps", () => {
describe("tax exclusive", () => { describe("tax exclusive", () => {
let medusaProcess let medusaProcess
@@ -57,11 +63,7 @@ describe("/admin/swaps", () => {
const api = useApi() const api = useApi()
const response = await api const response = await api
.get("/admin/swaps/test-swap", { .get("/admin/swaps/test-swap", adminHeaders)
headers: {
Authorization: "Bearer test_token",
},
})
.catch((err) => { .catch((err) => {
console.log(err) console.log(err)
}) })
@@ -88,11 +90,7 @@ describe("/admin/swaps", () => {
const api = useApi() const api = useApi()
const response = await api const response = await api
.get("/admin/swaps/disc-swap", { .get("/admin/swaps/disc-swap", adminHeaders)
headers: {
Authorization: "Bearer test_token",
},
})
.catch((err) => { .catch((err) => {
console.log(err) console.log(err)
}) })
@@ -131,11 +129,7 @@ describe("/admin/swaps", () => {
const api = useApi() const api = useApi()
const response = await api const response = await api
.get("/admin/swaps/", { .get("/admin/swaps/", adminHeaders)
headers: {
Authorization: "Bearer test_token",
},
})
.catch((err) => { .catch((err) => {
console.log(err) console.log(err)
}) })
@@ -150,6 +144,17 @@ describe("/admin/swaps", () => {
}) })
) )
}) })
it("should list the swaps with correct pagination", async () => {
const api = useApi()
const response = await api.get("/admin/swaps?limit=5", adminHeaders)
expect(response.status).toEqual(200)
expect(response.data.count).toBe(8)
expect(response.data.limit).toBe(5)
expect(response.data.swaps.length).toBe(5)
})
}) })
describe("Complete swap flow", () => { describe("Complete swap flow", () => {
@@ -268,11 +273,7 @@ describe("/admin/swaps", () => {
{ {
items: [{ item_id: "line-item", quantity: 1 }], items: [{ item_id: "line-item", quantity: 1 }],
}, },
{ adminHeaders
headers: {
Authorization: "Bearer test_token",
},
}
) )
const fulfillmentId = fulfilledOrder.data.order.fulfillments[0].id const fulfillmentId = fulfilledOrder.data.order.fulfillments[0].id
@@ -282,22 +283,10 @@ describe("/admin/swaps", () => {
{ {
fulfillment_id: fulfillmentId, fulfillment_id: fulfillmentId,
}, },
{ adminHeaders
headers: {
Authorization: "Bearer test_token",
},
}
) )
await api.post( await api.post(`/admin/orders/${orderId}/capture`, {}, adminHeaders)
`/admin/orders/${orderId}/capture`,
{},
{
headers: {
Authorization: "Bearer test_token",
},
}
)
// ********* CREATE SWAP ********* // ********* CREATE SWAP *********
const createSwap = await api.post( const createSwap = await api.post(
@@ -311,11 +300,7 @@ describe("/admin/swaps", () => {
], ],
additional_items: [{ variant_id: "prod-b-var", quantity: 1 }], additional_items: [{ variant_id: "prod-b-var", quantity: 1 }],
}, },
{ adminHeaders
headers: {
authorization: "Bearer test_token",
},
}
) )
let swap = createSwap.data.order.swaps[0] let swap = createSwap.data.order.swaps[0]
@@ -335,11 +320,7 @@ describe("/admin/swaps", () => {
await api.post(`/store/carts/${swap.cart_id}/complete`) await api.post(`/store/carts/${swap.cart_id}/complete`)
swap = await api swap = await api
.get(`/admin/swaps/${swap.id}`, { .get(`/admin/swaps/${swap.id}`, adminHeaders)
headers: {
Authorization: "Bearer test_token",
},
})
.catch((err) => { .catch((err) => {
console.log(err) console.log(err)
}) })
@@ -495,11 +476,7 @@ describe("/admin/swaps", () => {
{ {
items: [{ item_id: "line-item", quantity: 1 }], items: [{ item_id: "line-item", quantity: 1 }],
}, },
{ adminHeaders
headers: {
Authorization: "Bearer test_token",
},
}
) )
const fulfillmentId = fulfilledOrder.data.order.fulfillments[0].id const fulfillmentId = fulfilledOrder.data.order.fulfillments[0].id
@@ -509,22 +486,10 @@ describe("/admin/swaps", () => {
{ {
fulfillment_id: fulfillmentId, fulfillment_id: fulfillmentId,
}, },
{ adminHeaders
headers: {
Authorization: "Bearer test_token",
},
}
) )
await api.post( await api.post(`/admin/orders/${orderId}/capture`, {}, adminHeaders)
`/admin/orders/${orderId}/capture`,
{},
{
headers: {
Authorization: "Bearer test_token",
},
}
)
// ********* CREATE SWAP ********* // ********* CREATE SWAP *********
const createSwap = await api.post( const createSwap = await api.post(
@@ -538,11 +503,7 @@ describe("/admin/swaps", () => {
], ],
additional_items: [{ variant_id: "prod-b-var", quantity: 1 }], additional_items: [{ variant_id: "prod-b-var", quantity: 1 }],
}, },
{ adminHeaders
headers: {
authorization: "Bearer test_token",
},
}
) )
let swap = createSwap.data.order.swaps[0] let swap = createSwap.data.order.swaps[0]
@@ -562,11 +523,7 @@ describe("/admin/swaps", () => {
await api.post(`/store/carts/${swap.cart_id}/complete`) await api.post(`/store/carts/${swap.cart_id}/complete`)
swap = await api swap = await api
.get(`/admin/swaps/${swap.id}`, { .get(`/admin/swaps/${swap.id}`, adminHeaders)
headers: {
Authorization: "Bearer test_token",
},
})
.catch((err) => { .catch((err) => {
console.log(err) console.log(err)
}) })
@@ -18,6 +18,12 @@ const {
jest.setTimeout(30000) jest.setTimeout(30000)
const adminHeaders = {
headers: {
authorization: "Bearer test_token",
},
}
describe("/admin/orders", () => { describe("/admin/orders", () => {
let medusaProcess let medusaProcess
let dbConnection let dbConnection
@@ -60,11 +66,7 @@ describe("/admin/orders", () => {
}, },
], ],
}, },
{ adminHeaders
headers: {
authorization: "Bearer test_token",
},
}
) )
expect(response.status).toEqual(200) expect(response.status).toEqual(200)
@@ -103,11 +105,7 @@ describe("/admin/orders", () => {
}, },
], ],
}, },
{ adminHeaders
headers: {
authorization: "Bearer test_token",
},
}
) )
expect(response.status).toEqual(200) expect(response.status).toEqual(200)
@@ -156,11 +154,7 @@ describe("/admin/orders", () => {
}, },
], ],
}, },
{ adminHeaders
headers: {
authorization: "Bearer test_token",
},
}
) )
expect(response.status).toEqual(200) expect(response.status).toEqual(200)
@@ -215,11 +209,7 @@ describe("/admin/orders", () => {
}, },
], ],
}, },
{ adminHeaders
headers: {
authorization: "Bearer test_token",
},
}
) )
expect(response.status).toEqual(200) expect(response.status).toEqual(200)
@@ -364,11 +354,7 @@ describe("/admin/orders", () => {
}, },
], ],
}, },
{ adminHeaders
headers: {
authorization: "Bearer test_token",
},
}
) )
expect(response.status).toEqual(200) expect(response.status).toEqual(200)
@@ -421,7 +407,7 @@ describe("/admin/orders", () => {
}, },
], ],
}, },
{ headers: { authorization: "Bearer test_token" } } adminHeaders
) )
const claimId = createRes.data.order.claims[0].id const claimId = createRes.data.order.claims[0].id
@@ -430,7 +416,7 @@ describe("/admin/orders", () => {
const claimFulfillmentCreatedResponse = await api.post( const claimFulfillmentCreatedResponse = await api.post(
`/admin/orders/${order.id}/claims/${claimId}/fulfillments`, `/admin/orders/${order.id}/claims/${claimId}/fulfillments`,
{}, {},
{ headers: { authorization: "Bearer test_token" } } adminHeaders
) )
const fulfillmentId = const fulfillmentId =
@@ -438,7 +424,7 @@ describe("/admin/orders", () => {
await api.post( await api.post(
`/admin/orders/${order.id}/claims/${claimId}/shipments`, `/admin/orders/${order.id}/claims/${claimId}/shipments`,
{ fulfillment_id: fulfillmentId }, { fulfillment_id: fulfillmentId },
{ headers: { authorization: "Bearer test_token" } } adminHeaders
) )
const returnCreatedResponse = await api.post( const returnCreatedResponse = await api.post(
@@ -452,11 +438,7 @@ describe("/admin/orders", () => {
}, },
], ],
}, },
{ adminHeaders
headers: {
authorization: "Bearer test_token",
},
}
) )
const returnOrder = returnCreatedResponse.data.order.returns[0] const returnOrder = returnCreatedResponse.data.order.returns[0]
@@ -469,23 +451,56 @@ describe("/admin/orders", () => {
quantity: i.quantity, quantity: i.quantity,
})), })),
}, },
{ adminHeaders
headers: {
authorization: "Bearer test_token",
},
}
) )
expect(returnReceivedResponse.status).toEqual(200) expect(returnReceivedResponse.status).toEqual(200)
}) })
it("shoutl list the returns with correct pagination", async () => {
await adminSeeder(dbConnection)
const api = useApi()
const createOrderAndReturn = async (suffix = "") => {
const order = await createReturnableOrder(
dbConnection,
{
discount: false,
oldTaxes: false,
},
suffix
)
const response = await api.post(
`/admin/orders/${order.id}/return`,
{
items: [
{
item_id: "test-item" + suffix,
quantity: 1,
note: "TOO SMALL",
},
],
},
adminHeaders
)
}
await Promise.all([createOrderAndReturn(), createOrderAndReturn("-1")])
const result = await api.get(`/admin/returns?limit=1`, adminHeaders)
expect(result.status).toEqual(200)
expect(result.data.count).toEqual(2)
})
}) })
const createReturnableOrder = async (dbConnection, options) => { const createReturnableOrder = async (dbConnection, options, suffix = "") => {
await simpleProductFactory( await simpleProductFactory(
dbConnection, dbConnection,
{ {
id: "test-product", id: "test-product" + suffix,
variants: [{ id: "test-variant" }], variants: [{ id: "test-variant" + suffix }],
}, },
100 100
) )
@@ -495,24 +510,24 @@ const createReturnableOrder = async (dbConnection, options) => {
if (options.discount) { if (options.discount) {
discounts = [ discounts = [
{ {
code: "TESTCODE", code: "TESTCODE" + suffix,
}, },
] ]
} }
return await simpleOrderFactory(dbConnection, { return await simpleOrderFactory(dbConnection, {
email: "test@testson.com", email: "test@testson.com" + suffix,
tax_rate: options.oldTaxes ? undefined : null, tax_rate: options.oldTaxes ? undefined : null,
region: { region: {
id: "test-region", id: "test-region" + suffix,
name: "Test region", name: "Test region",
tax_rate: 12.5, // Should be ignored due to item tax line tax_rate: 12.5, // Should be ignored due to item tax line
}, },
discounts, discounts,
line_items: [ line_items: [
{ {
id: "test-item", id: "test-item" + suffix,
variant_id: "test-variant", variant_id: "test-variant" + suffix,
quantity: 2, quantity: 2,
fulfilled_quantity: options.shipped ? 2 : undefined, fulfilled_quantity: options.shipped ? 2 : undefined,
shipped_quantity: options.shipped ? 2 : undefined, shipped_quantity: options.shipped ? 2 : undefined,
@@ -521,9 +536,9 @@ const createReturnableOrder = async (dbConnection, options) => {
? [ ? [
{ {
amount: 200, amount: 200,
discount_code: "TESTCODE", discount_code: "TESTCODE" + suffix,
description: "discount", description: "discount",
item_id: "test-item", item_id: "test-item" + suffix,
}, },
] ]
: [], : [],
@@ -0,0 +1,75 @@
const path = require("path")
const {
Region,
ReturnReason,
Order,
Customer,
ShippingProfile,
Product,
ProductVariant,
ShippingOption,
FulfillmentProvider,
LineItem,
Discount,
DiscountRule,
} = require("@medusajs/medusa")
const setupServer = require("../../../helpers/setup-server")
const { useApi } = require("../../../helpers/use-api")
const { initDb, useDb } = require("../../../helpers/use-db")
jest.setTimeout(30000)
describe("/store/carts", () => {
let medusaProcess
let dbConnection
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", ".."))
dbConnection = await initDb({ cwd })
medusaProcess = await setupServer({ cwd })
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
medusaProcess.kill()
})
describe("GET /store/regions", () => {
beforeEach(async () => {
const manager = dbConnection.manager
await manager.insert(Region, {
id: "region",
name: "Test Region",
currency_code: "usd",
tax_rate: 0,
})
await manager.insert(Region, {
id: "region-1",
name: "Test Region 1",
currency_code: "usd",
tax_rate: 0,
})
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
it("should list the store regions with pagination", async () => {
const api = useApi()
const response = await api.get("/store/regions?limit=1&offset=1")
expect(response.status).toEqual(200)
expect(response.data.regions.length).toEqual(1)
expect(response.data.count).toEqual(2)
expect(response.data.offset).toEqual(1)
expect(response.data.limit).toEqual(1)
})
})
})
@@ -7,4 +7,16 @@ import type { Notification } from "./Notification"
export interface AdminNotificationsListRes { export interface AdminNotificationsListRes {
notifications: Array<SetRelation<Notification, "resends">> notifications: Array<SetRelation<Notification, "resends">>
/**
* The total number of notifications
*/
count?: number
/**
* The number of notifications skipped before these notifications
*/
offset?: number
/**
* The number of notifications per page
*/
limit?: number
} }
@@ -12,4 +12,16 @@ export interface StoreRegionsListRes {
"countries" | "payment_providers" | "fulfillment_providers" "countries" | "payment_providers" | "fulfillment_providers"
> >
> >
/**
* The total number of items available
*/
count?: number
/**
* The number of items skipped before these items
*/
offset?: number
/**
* The number of items per page
*/
limit?: number
} }
@@ -69,7 +69,7 @@ export default async (req, res) => {
} }
const noteService: NoteService = req.scope.resolve("noteService") const noteService: NoteService = req.scope.resolve("noteService")
const notes = await noteService.list(selector, { const [notes, count] = await noteService.listAndCount(selector, {
take: validated.limit, take: validated.limit,
skip: validated.offset, skip: validated.offset,
relations: ["author"], relations: ["author"],
@@ -77,7 +77,7 @@ export default async (req, res) => {
res.status(200).json({ res.status(200).json({
notes, notes,
count: notes.length, count,
offset: validated.offset, offset: validated.offset,
limit: validated.limit, limit: validated.limit,
}) })
@@ -1,5 +1,6 @@
import { Router } from "express"
import { Notification } from "./../../../../" import { Notification } from "./../../../../"
import { PaginatedResponse } from "@medusajs/types"
import { Router } from "express"
import middlewares from "../../../middlewares" import middlewares from "../../../middlewares"
const route = Router() const route = Router()
@@ -50,8 +51,17 @@ export const defaultAdminNotificationsFields = [
* type: array * type: array
* items: * items:
* $ref: "#/components/schemas/Notification" * $ref: "#/components/schemas/Notification"
* count:
* type: integer
* description: The total number of notifications
* offset:
* type: integer
* description: The number of notifications skipped before these notifications
* limit:
* type: integer
* description: The number of notifications per page
*/ */
export type AdminNotificationsListRes = { export type AdminNotificationsListRes = PaginatedResponse & {
notifications: Notification[] notifications: Notification[]
} }
@@ -3,9 +3,9 @@ import {
defaultAdminNotificationsFields, defaultAdminNotificationsFields,
defaultAdminNotificationsRelations, defaultAdminNotificationsRelations,
} from "./" } from "./"
import { Notification } from "../../../../models"
import { FindConfig } from "../../../../types/common"
import { FindConfig } from "../../../../types/common"
import { Notification } from "../../../../models"
import { NotificationService } from "../../../../services" import { NotificationService } from "../../../../services"
import { Type } from "class-transformer" import { Type } from "class-transformer"
import { pick } from "lodash" import { pick } from "lodash"
@@ -135,7 +135,10 @@ export default async (req, res) => {
order: { created_at: "DESC" }, order: { created_at: "DESC" },
} as FindConfig<Notification> } as FindConfig<Notification>
const notifications = await notificationService.list(selector, listConfig) const [notifications, count] = await notificationService.listAndCount(
selector,
listConfig
)
const resultFields = [ const resultFields = [
...(listConfig.select ?? []), ...(listConfig.select ?? []),
@@ -143,7 +146,7 @@ export default async (req, res) => {
] ]
const data = notifications.map((o) => pick(o, resultFields)) const data = notifications.map((o) => pick(o, resultFields))
res.json({ notifications: data }) res.json({ notifications: data, count, limit, offset })
} }
export class AdminGetNotificationsParams { export class AdminGetNotificationsParams {
@@ -1,11 +1,11 @@
import { IsNumber, IsOptional } from "class-validator" import { IsNumber, IsOptional } from "class-validator"
import { ReturnService } from "../../../../services"
import { Type } from "class-transformer"
import { validator } from "../../../../utils/validator"
import { FindConfig } from "../../../../types/common" import { FindConfig } from "../../../../types/common"
import { Return } from "../../../../models" import { Return } from "../../../../models"
import { ReturnService } from "../../../../services"
import { Type } from "class-transformer"
import { defaultRelationsList } from "." import { defaultRelationsList } from "."
import { validator } from "../../../../utils/validator"
/** /**
* @oas [get] /admin/returns * @oas [get] /admin/returns
@@ -73,11 +73,13 @@ export default async (req, res) => {
order: { created_at: "DESC" }, order: { created_at: "DESC" },
} as FindConfig<Return> } as FindConfig<Return>
const returns = await returnService.list(selector, { ...listConfig }) const [returns, count] = await returnService.listAndCount(selector, {
...listConfig,
})
res.json({ res.json({
returns, returns,
count: returns.length, count,
offset: validated.offset, offset: validated.offset,
limit: validated.limit, limit: validated.limit,
}) })
@@ -1,6 +1,6 @@
import { IdMap } from "medusa-test-utils" import { IdMap } from "medusa-test-utils"
import { request } from "../../../../../helpers/test-request"
import { SwapServiceMock } from "../../../../../services/__mocks__/swap" import { SwapServiceMock } from "../../../../../services/__mocks__/swap"
import { request } from "../../../../../helpers/test-request"
const defaultListOptions = { const defaultListOptions = {
take: 50, take: 50,
@@ -27,8 +27,8 @@ describe("GET /admin/swaps/", () => {
}) })
it("calls swapService list with default pagination and sorting options", () => { it("calls swapService list with default pagination and sorting options", () => {
expect(SwapServiceMock.list).toHaveBeenCalledTimes(1) expect(SwapServiceMock.listAndCount).toHaveBeenCalledTimes(1)
expect(SwapServiceMock.list).toHaveBeenCalledWith( expect(SwapServiceMock.listAndCount).toHaveBeenCalledWith(
{}, {},
{ {
...defaultListOptions, ...defaultListOptions,
@@ -1,10 +1,10 @@
import { Type } from "class-transformer"
import { IsInt, IsOptional } from "class-validator" import { IsInt, IsOptional } from "class-validator"
import { SwapService } from "../../../../services"
import { validator } from "../../../../utils/validator"
import { FindConfig } from "../../../../types/common" import { FindConfig } from "../../../../types/common"
import { Swap } from "../../../../models" import { Swap } from "../../../../models"
import { SwapService } from "../../../../services"
import { Type } from "class-transformer"
import { validator } from "../../../../utils/validator"
/** /**
* @oas [get] /admin/swaps * @oas [get] /admin/swaps
@@ -72,9 +72,11 @@ export default async (req, res) => {
order: { created_at: "DESC" }, order: { created_at: "DESC" },
} }
const swaps = await swapService.list(selector, { ...listConfig }) const [swaps, count] = await swapService.listAndCount(selector, {
...listConfig,
})
res.json({ swaps, count: swaps.length, offset, limit }) res.json({ swaps, count, offset, limit })
} }
export class AdminGetSwapsParams { export class AdminGetSwapsParams {
@@ -1,6 +1,6 @@
import { IdMap } from "medusa-test-utils" import { IdMap } from "medusa-test-utils"
import { request } from "../../../../../helpers/test-request"
import { RegionServiceMock } from "../../../../../services/__mocks__/region" import { RegionServiceMock } from "../../../../../services/__mocks__/region"
import { request } from "../../../../../helpers/test-request"
describe("List regions", () => { describe("List regions", () => {
describe("list regions", () => { describe("list regions", () => {
@@ -14,8 +14,8 @@ describe("List regions", () => {
}) })
it("calls list from region service", () => { it("calls list from region service", () => {
expect(RegionServiceMock.list).toHaveBeenCalledTimes(1) expect(RegionServiceMock.listAndCount).toHaveBeenCalledTimes(1)
expect(RegionServiceMock.list).toHaveBeenCalledWith( expect(RegionServiceMock.listAndCount).toHaveBeenCalledWith(
{}, {},
{ {
relations: [ relations: [
@@ -1,6 +1,7 @@
import { PaginatedResponse } from "@medusajs/types"
import { Region } from "./../../../../"
import { Router } from "express" import { Router } from "express"
import middlewares from "../../../middlewares" import middlewares from "../../../middlewares"
import { Region } from "./../../../../"
const route = Router() const route = Router()
@@ -38,8 +39,17 @@ export const defaultRelations = [
* type: array * type: array
* items: * items:
* $ref: "#/components/schemas/Region" * $ref: "#/components/schemas/Region"
* count:
* type: integer
* description: The total number of items available
* offset:
* type: integer
* description: The number of items skipped before these items
* limit:
* type: integer
* description: The number of items per page
*/ */
export type StoreRegionsListRes = { export type StoreRegionsListRes = PaginatedResponse & {
regions: Region[] regions: Region[]
} }
@@ -3,9 +3,9 @@ import { IsInt, IsOptional, ValidateNested } from "class-validator"
import { DateComparisonOperator } from "../../../../types/common" import { DateComparisonOperator } from "../../../../types/common"
import RegionService from "../../../../services/region" import RegionService from "../../../../services/region"
import { Type } from "class-transformer" import { Type } from "class-transformer"
import { defaultRelations } from "."
import { omit } from "lodash" import { omit } from "lodash"
import { validator } from "../../../../utils/validator" import { validator } from "../../../../utils/validator"
import { defaultRelations } from "."
/** /**
* @oas [get] /store/regions * @oas [get] /store/regions
@@ -110,9 +110,12 @@ export default async (req, res) => {
take: limit, take: limit,
} }
const regions = await regionService.list(filterableFields, listConfig) const [regions, count] = await regionService.listAndCount(
filterableFields,
listConfig
)
res.json({ regions }) res.json({ regions, count, limit, offset })
} }
export class StoreGetRegionsParams { export class StoreGetRegionsParams {
+12 -6
View File
@@ -1,16 +1,16 @@
import { IdMap } from "medusa-test-utils" import { IdMap } from "medusa-test-utils"
export const SwapServiceMock = { export const SwapServiceMock = {
withTransaction: function() { withTransaction: function () {
return this return this
}, },
registerCartCompletion: jest.fn().mockImplementation(data => { registerCartCompletion: jest.fn().mockImplementation((data) => {
return Promise.resolve({ id: "test-swap" }) return Promise.resolve({ id: "test-swap" })
}), }),
create: jest.fn().mockImplementation(data => { create: jest.fn().mockImplementation((data) => {
return Promise.resolve() return Promise.resolve()
}), }),
retrieve: jest.fn().mockImplementation(data => { retrieve: jest.fn().mockImplementation((data) => {
switch (data) { switch (data) {
case IdMap.getId("test-swap"): case IdMap.getId("test-swap"):
return Promise.resolve({ return Promise.resolve({
@@ -21,11 +21,11 @@ export const SwapServiceMock = {
return Promise.resolve({ id: "test-swap" }) return Promise.resolve({ id: "test-swap" })
} }
}), }),
cancel: jest.fn().mockImplementation(f => { cancel: jest.fn().mockImplementation((f) => {
return Promise.resolve({ f }) return Promise.resolve({ f })
}), }),
cancelFulfillment: jest.fn().mockImplementation(f => { cancelFulfillment: jest.fn().mockImplementation((f) => {
return Promise.resolve({ id: IdMap.getId("test-swap") }) return Promise.resolve({ id: IdMap.getId("test-swap") })
}), }),
list: jest.fn().mockImplementation((...args) => { list: jest.fn().mockImplementation((...args) => {
@@ -34,6 +34,12 @@ export const SwapServiceMock = {
{ id: IdMap.getId("test-swap-1") }, { id: IdMap.getId("test-swap-1") },
]) ])
}), }),
listAndCount: jest.fn().mockImplementation((...args) => {
return Promise.resolve([
[{ id: IdMap.getId("test-swap") }, { id: IdMap.getId("test-swap-1") }],
2,
])
}),
} }
const mock = jest.fn().mockImplementation(() => { const mock = jest.fn().mockImplementation(() => {
+10 -3
View File
@@ -1,6 +1,7 @@
import NoteService from "../note"
import { IdMap, MockManager, MockRepository } from "medusa-test-utils" import { IdMap, MockManager, MockRepository } from "medusa-test-utils"
import { EventBusServiceMock } from "../__mocks__/event-bus" import { EventBusServiceMock } from "../__mocks__/event-bus"
import NoteService from "../note"
describe("NoteService", () => { describe("NoteService", () => {
describe("list", () => { describe("list", () => {
@@ -10,6 +11,12 @@ describe("NoteService", () => {
{ id: IdMap.getId("note"), value: "some note" }, { id: IdMap.getId("note"), value: "some note" },
]) ])
}, },
findAndCount: (q) => {
return Promise.resolve([
[{ id: IdMap.getId("note"), value: "some note" }],
1,
])
},
}) })
const noteService = new NoteService({ const noteService = new NoteService({
@@ -28,8 +35,8 @@ describe("NoteService", () => {
relations: ["author"], relations: ["author"],
} }
) )
expect(noteRepo.find).toHaveBeenCalledTimes(1) expect(noteRepo.findAndCount).toHaveBeenCalledTimes(1)
expect(noteRepo.find).toHaveBeenCalledWith({ expect(noteRepo.findAndCount).toHaveBeenCalledWith({
where: { where: {
resource_id: IdMap.getId("note"), resource_id: IdMap.getId("note"),
}, },
+28 -6
View File
@@ -1,12 +1,13 @@
import { isDefined, MedusaError } from "medusa-core-utils" import { FindConfig, Selector } from "../types/common"
import { MedusaError, isDefined } from "medusa-core-utils"
import { CreateNoteInput } from "../types/note"
import { EntityManager } from "typeorm" import { EntityManager } from "typeorm"
import { TransactionBaseService } from "../interfaces" import EventBusService from "./event-bus"
import { Note } from "../models" import { Note } from "../models"
import { NoteRepository } from "../repositories/note" import { NoteRepository } from "../repositories/note"
import { FindConfig, Selector } from "../types/common" import { TransactionBaseService } from "../interfaces"
import { CreateNoteInput } from "../types/note"
import { buildQuery } from "../utils" import { buildQuery } from "../utils"
import EventBusService from "./event-bus"
type InjectedDependencies = { type InjectedDependencies = {
manager: EntityManager manager: EntityManager
@@ -81,11 +82,32 @@ class NoteService extends TransactionBaseService {
relations: [], relations: [],
} }
): Promise<Note[]> { ): Promise<Note[]> {
const [result] = await this.listAndCount(selector, config)
return result
}
/** Fetches all notes related to the given selector
* @param selector - the query object for find
* @param config - the configuration used to find the objects. contains relations, skip, and take.
* @param config.relations - Which relations to include in the resulting list of Notes.
* @param config.take - How many Notes to take in the resulting list of Notes.
* @param config.skip - How many Notes to skip in the resulting list of Notes.
* @return notes related to the given search.
*/
async listAndCount(
selector: Selector<Note>,
config: FindConfig<Note> = {
skip: 0,
take: 50,
relations: [],
}
): Promise<[Note[], number]> {
const noteRepo = this.activeManager_.withRepository(this.noteRepository_) const noteRepo = this.activeManager_.withRepository(this.noteRepository_)
const query = buildQuery(selector, config) const query = buildQuery(selector, config)
return noteRepo.find(query) return noteRepo.findAndCount(query)
} }
/** /**
+26 -6
View File
@@ -1,15 +1,16 @@
import { MedusaError } from "medusa-core-utils"
import { import {
AbstractNotificationService, AbstractNotificationService,
TransactionBaseService, TransactionBaseService,
} from "../interfaces" } from "../interfaces"
import { FindConfig, Selector } from "../types/common"
import { EntityManager } from "typeorm" import { EntityManager } from "typeorm"
import { Logger } from "../types/global" import { Logger } from "../types/global"
import { NotificationRepository } from "../repositories/notification" import { MedusaError } from "medusa-core-utils"
import { NotificationProviderRepository } from "../repositories/notification-provider"
import { FindConfig, Selector } from "../types/common"
import { buildQuery } from "../utils"
import { Notification } from "../models" import { Notification } from "../models"
import { NotificationProviderRepository } from "../repositories/notification-provider"
import { NotificationRepository } from "../repositories/notification"
import { buildQuery } from "../utils"
type InjectedDependencies = { type InjectedDependencies = {
manager: EntityManager manager: EntityManager
@@ -82,11 +83,30 @@ class NotificationService extends TransactionBaseService {
order: { created_at: "DESC" }, order: { created_at: "DESC" },
} }
): Promise<Notification[]> { ): Promise<Notification[]> {
const [notifications] = await this.listAndCount(selector, config)
return notifications
}
/**
* Retrieves a list of notifications and total count.
* @param selector - the params to select the notifications by.
* @param config - the configuration to apply to the query
* @return the notifications that satisfy the query as well as the count.
*/
async listAndCount(
selector: Selector<Notification>,
config: FindConfig<Notification> = {
skip: 0,
take: 50,
order: { created_at: "DESC" },
}
): Promise<[Notification[], number]> {
const notiRepo = this.activeManager_.withRepository( const notiRepo = this.activeManager_.withRepository(
this.notificationRepository_ this.notificationRepository_
) )
const query = buildQuery(selector, config) const query = buildQuery(selector, config)
return await notiRepo.find(query) return await notiRepo.findAndCount(query)
} }
/** /**
+36 -19
View File
@@ -1,22 +1,6 @@
import { isDefined, MedusaError } from "medusa-core-utils"
import { DeepPartial, EntityManager } from "typeorm"
import { TransactionBaseService } from "../interfaces"
import {
FulfillmentStatus,
LineItem,
Order,
PaymentStatus,
Return,
ReturnItem,
ReturnStatus,
} from "../models"
import { ReturnRepository } from "../repositories/return"
import { ReturnItemRepository } from "../repositories/return-item"
import { FindConfig, Selector } from "../types/common"
import { OrdersReturnItem } from "../types/orders"
import { CreateReturnInput, UpdateReturnInput } from "../types/return" import { CreateReturnInput, UpdateReturnInput } from "../types/return"
import { buildQuery, setMetadata } from "../utils" import { DeepPartial, EntityManager } from "typeorm"
import { FindConfig, Selector } from "../types/common"
import { import {
FulfillmentProviderService, FulfillmentProviderService,
LineItemService, LineItemService,
@@ -27,6 +11,22 @@ import {
TaxProviderService, TaxProviderService,
TotalsService, TotalsService,
} from "." } from "."
import {
FulfillmentStatus,
LineItem,
Order,
PaymentStatus,
Return,
ReturnItem,
ReturnStatus,
} from "../models"
import { MedusaError, isDefined } from "medusa-core-utils"
import { buildQuery, setMetadata } from "../utils"
import { OrdersReturnItem } from "../types/orders"
import { ReturnItemRepository } from "../repositories/return-item"
import { ReturnRepository } from "../repositories/return"
import { TransactionBaseService } from "../interfaces"
type InjectedDependencies = { type InjectedDependencies = {
manager: EntityManager manager: EntityManager
@@ -146,11 +146,28 @@ class ReturnService extends TransactionBaseService {
order: { created_at: "DESC" }, order: { created_at: "DESC" },
} }
): Promise<Return[]> { ): Promise<Return[]> {
const [returns] = await this.listAndCount(selector, config)
return returns
}
/**
* @param selector - the query object for find
* @param config - the config object for find
* @return the result of the find operation
*/
async listAndCount(
selector: Selector<Return>,
config: FindConfig<Return> = {
skip: 0,
take: 50,
order: { created_at: "DESC" },
}
): Promise<[Return[], number]> {
const returnRepo = this.activeManager_.withRepository( const returnRepo = this.activeManager_.withRepository(
this.returnRepository_ this.returnRepository_
) )
const query = buildQuery(selector, config) const query = buildQuery(selector, config)
return returnRepo.find(query) return returnRepo.findAndCount(query)
} }
/** /**
+22 -2
View File
@@ -29,7 +29,7 @@ import {
} from "./index" } from "./index"
import { EntityManager, In } from "typeorm" import { EntityManager, In } from "typeorm"
import { FindConfig, Selector, WithRequiredProperty } from "../types/common" import { FindConfig, Selector, WithRequiredProperty } from "../types/common"
import { isDefined, MedusaError } from "medusa-core-utils" import { MedusaError, isDefined } from "medusa-core-utils"
import { buildQuery, setMetadata, validateId } from "../utils" import { buildQuery, setMetadata, validateId } from "../utils"
import { CreateShipmentConfig } from "../types/fulfillment" import { CreateShipmentConfig } from "../types/fulfillment"
@@ -278,11 +278,31 @@ class SwapService extends TransactionBaseService {
order: { created_at: "DESC" }, order: { created_at: "DESC" },
} }
): Promise<Swap[]> { ): Promise<Swap[]> {
const [swaps] = await this.listAndCount(selector, config)
return swaps
}
/**
* List swaps.
*
* @param selector - the query object for find
* @param config - the configuration used to find the objects. contains relations, skip, and take.
* @return the result of the find operation
*/
async listAndCount(
selector: Selector<Swap>,
config: FindConfig<Swap> = {
skip: 0,
take: 50,
order: { created_at: "DESC" },
}
): Promise<[Swap[], number]> {
const swapRepo = this.activeManager_.withRepository(this.swapRepository_) const swapRepo = this.activeManager_.withRepository(this.swapRepository_)
const query = buildQuery(selector, config) const query = buildQuery(selector, config)
query.relationLoadStrategy = "query" query.relationLoadStrategy = "query"
return await swapRepo.find(query) return await swapRepo.findAndCount(query)
} }
/** /**