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 Korsholm
2023-07-14 16:14:51 +02:00
committed by GitHub
parent 55db914151
commit 5b91a3503a
21 changed files with 401 additions and 192 deletions

View File

@@ -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", () => {

View File

@@ -24,6 +24,12 @@ const {
jest.setTimeout(30000)
const adminHeaders = {
headers: {
Authorization: "Bearer test_token",
},
}
describe("/admin/swaps", () => {
describe("tax exclusive", () => {
let medusaProcess
@@ -57,11 +63,7 @@ describe("/admin/swaps", () => {
const api = useApi()
const response = await api
.get("/admin/swaps/test-swap", {
headers: {
Authorization: "Bearer test_token",
},
})
.get("/admin/swaps/test-swap", adminHeaders)
.catch((err) => {
console.log(err)
})
@@ -88,11 +90,7 @@ describe("/admin/swaps", () => {
const api = useApi()
const response = await api
.get("/admin/swaps/disc-swap", {
headers: {
Authorization: "Bearer test_token",
},
})
.get("/admin/swaps/disc-swap", adminHeaders)
.catch((err) => {
console.log(err)
})
@@ -131,11 +129,7 @@ describe("/admin/swaps", () => {
const api = useApi()
const response = await api
.get("/admin/swaps/", {
headers: {
Authorization: "Bearer test_token",
},
})
.get("/admin/swaps/", adminHeaders)
.catch((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", () => {
@@ -268,11 +273,7 @@ describe("/admin/swaps", () => {
{
items: [{ item_id: "line-item", quantity: 1 }],
},
{
headers: {
Authorization: "Bearer test_token",
},
}
adminHeaders
)
const fulfillmentId = fulfilledOrder.data.order.fulfillments[0].id
@@ -282,22 +283,10 @@ describe("/admin/swaps", () => {
{
fulfillment_id: fulfillmentId,
},
{
headers: {
Authorization: "Bearer test_token",
},
}
adminHeaders
)
await api.post(
`/admin/orders/${orderId}/capture`,
{},
{
headers: {
Authorization: "Bearer test_token",
},
}
)
await api.post(`/admin/orders/${orderId}/capture`, {}, adminHeaders)
// ********* CREATE SWAP *********
const createSwap = await api.post(
@@ -311,11 +300,7 @@ describe("/admin/swaps", () => {
],
additional_items: [{ variant_id: "prod-b-var", quantity: 1 }],
},
{
headers: {
authorization: "Bearer test_token",
},
}
adminHeaders
)
let swap = createSwap.data.order.swaps[0]
@@ -335,11 +320,7 @@ describe("/admin/swaps", () => {
await api.post(`/store/carts/${swap.cart_id}/complete`)
swap = await api
.get(`/admin/swaps/${swap.id}`, {
headers: {
Authorization: "Bearer test_token",
},
})
.get(`/admin/swaps/${swap.id}`, adminHeaders)
.catch((err) => {
console.log(err)
})
@@ -495,11 +476,7 @@ describe("/admin/swaps", () => {
{
items: [{ item_id: "line-item", quantity: 1 }],
},
{
headers: {
Authorization: "Bearer test_token",
},
}
adminHeaders
)
const fulfillmentId = fulfilledOrder.data.order.fulfillments[0].id
@@ -509,22 +486,10 @@ describe("/admin/swaps", () => {
{
fulfillment_id: fulfillmentId,
},
{
headers: {
Authorization: "Bearer test_token",
},
}
adminHeaders
)
await api.post(
`/admin/orders/${orderId}/capture`,
{},
{
headers: {
Authorization: "Bearer test_token",
},
}
)
await api.post(`/admin/orders/${orderId}/capture`, {}, adminHeaders)
// ********* CREATE SWAP *********
const createSwap = await api.post(
@@ -538,11 +503,7 @@ describe("/admin/swaps", () => {
],
additional_items: [{ variant_id: "prod-b-var", quantity: 1 }],
},
{
headers: {
authorization: "Bearer test_token",
},
}
adminHeaders
)
let swap = createSwap.data.order.swaps[0]
@@ -562,11 +523,7 @@ describe("/admin/swaps", () => {
await api.post(`/store/carts/${swap.cart_id}/complete`)
swap = await api
.get(`/admin/swaps/${swap.id}`, {
headers: {
Authorization: "Bearer test_token",
},
})
.get(`/admin/swaps/${swap.id}`, adminHeaders)
.catch((err) => {
console.log(err)
})

View File

@@ -18,6 +18,12 @@ const {
jest.setTimeout(30000)
const adminHeaders = {
headers: {
authorization: "Bearer test_token",
},
}
describe("/admin/orders", () => {
let medusaProcess
let dbConnection
@@ -60,11 +66,7 @@ describe("/admin/orders", () => {
},
],
},
{
headers: {
authorization: "Bearer test_token",
},
}
adminHeaders
)
expect(response.status).toEqual(200)
@@ -103,11 +105,7 @@ describe("/admin/orders", () => {
},
],
},
{
headers: {
authorization: "Bearer test_token",
},
}
adminHeaders
)
expect(response.status).toEqual(200)
@@ -156,11 +154,7 @@ describe("/admin/orders", () => {
},
],
},
{
headers: {
authorization: "Bearer test_token",
},
}
adminHeaders
)
expect(response.status).toEqual(200)
@@ -215,11 +209,7 @@ describe("/admin/orders", () => {
},
],
},
{
headers: {
authorization: "Bearer test_token",
},
}
adminHeaders
)
expect(response.status).toEqual(200)
@@ -364,11 +354,7 @@ describe("/admin/orders", () => {
},
],
},
{
headers: {
authorization: "Bearer test_token",
},
}
adminHeaders
)
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
@@ -430,7 +416,7 @@ describe("/admin/orders", () => {
const claimFulfillmentCreatedResponse = await api.post(
`/admin/orders/${order.id}/claims/${claimId}/fulfillments`,
{},
{ headers: { authorization: "Bearer test_token" } }
adminHeaders
)
const fulfillmentId =
@@ -438,7 +424,7 @@ describe("/admin/orders", () => {
await api.post(
`/admin/orders/${order.id}/claims/${claimId}/shipments`,
{ fulfillment_id: fulfillmentId },
{ headers: { authorization: "Bearer test_token" } }
adminHeaders
)
const returnCreatedResponse = await api.post(
@@ -452,11 +438,7 @@ describe("/admin/orders", () => {
},
],
},
{
headers: {
authorization: "Bearer test_token",
},
}
adminHeaders
)
const returnOrder = returnCreatedResponse.data.order.returns[0]
@@ -469,23 +451,56 @@ describe("/admin/orders", () => {
quantity: i.quantity,
})),
},
{
headers: {
authorization: "Bearer test_token",
},
}
adminHeaders
)
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(
dbConnection,
{
id: "test-product",
variants: [{ id: "test-variant" }],
id: "test-product" + suffix,
variants: [{ id: "test-variant" + suffix }],
},
100
)
@@ -495,24 +510,24 @@ const createReturnableOrder = async (dbConnection, options) => {
if (options.discount) {
discounts = [
{
code: "TESTCODE",
code: "TESTCODE" + suffix,
},
]
}
return await simpleOrderFactory(dbConnection, {
email: "test@testson.com",
email: "test@testson.com" + suffix,
tax_rate: options.oldTaxes ? undefined : null,
region: {
id: "test-region",
id: "test-region" + suffix,
name: "Test region",
tax_rate: 12.5, // Should be ignored due to item tax line
},
discounts,
line_items: [
{
id: "test-item",
variant_id: "test-variant",
id: "test-item" + suffix,
variant_id: "test-variant" + suffix,
quantity: 2,
fulfilled_quantity: options.shipped ? 2 : undefined,
shipped_quantity: options.shipped ? 2 : undefined,
@@ -521,9 +536,9 @@ const createReturnableOrder = async (dbConnection, options) => {
? [
{
amount: 200,
discount_code: "TESTCODE",
discount_code: "TESTCODE" + suffix,
description: "discount",
item_id: "test-item",
item_id: "test-item" + suffix,
},
]
: [],

View File

@@ -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)
})
})
})

View File

@@ -7,4 +7,16 @@ import type { Notification } from "./Notification"
export interface AdminNotificationsListRes {
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
}

View File

@@ -12,4 +12,16 @@ export interface StoreRegionsListRes {
"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
}

View File

@@ -69,7 +69,7 @@ export default async (req, res) => {
}
const noteService: NoteService = req.scope.resolve("noteService")
const notes = await noteService.list(selector, {
const [notes, count] = await noteService.listAndCount(selector, {
take: validated.limit,
skip: validated.offset,
relations: ["author"],
@@ -77,7 +77,7 @@ export default async (req, res) => {
res.status(200).json({
notes,
count: notes.length,
count,
offset: validated.offset,
limit: validated.limit,
})

View File

@@ -1,5 +1,6 @@
import { Router } from "express"
import { Notification } from "./../../../../"
import { PaginatedResponse } from "@medusajs/types"
import { Router } from "express"
import middlewares from "../../../middlewares"
const route = Router()
@@ -50,8 +51,17 @@ export const defaultAdminNotificationsFields = [
* type: array
* items:
* $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[]
}

View File

@@ -3,9 +3,9 @@ import {
defaultAdminNotificationsFields,
defaultAdminNotificationsRelations,
} from "./"
import { Notification } from "../../../../models"
import { FindConfig } from "../../../../types/common"
import { FindConfig } from "../../../../types/common"
import { Notification } from "../../../../models"
import { NotificationService } from "../../../../services"
import { Type } from "class-transformer"
import { pick } from "lodash"
@@ -135,7 +135,10 @@ export default async (req, res) => {
order: { created_at: "DESC" },
} as FindConfig<Notification>
const notifications = await notificationService.list(selector, listConfig)
const [notifications, count] = await notificationService.listAndCount(
selector,
listConfig
)
const resultFields = [
...(listConfig.select ?? []),
@@ -143,7 +146,7 @@ export default async (req, res) => {
]
const data = notifications.map((o) => pick(o, resultFields))
res.json({ notifications: data })
res.json({ notifications: data, count, limit, offset })
}
export class AdminGetNotificationsParams {

View File

@@ -1,11 +1,11 @@
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 { Return } from "../../../../models"
import { ReturnService } from "../../../../services"
import { Type } from "class-transformer"
import { defaultRelationsList } from "."
import { validator } from "../../../../utils/validator"
/**
* @oas [get] /admin/returns
@@ -73,11 +73,13 @@ export default async (req, res) => {
order: { created_at: "DESC" },
} as FindConfig<Return>
const returns = await returnService.list(selector, { ...listConfig })
const [returns, count] = await returnService.listAndCount(selector, {
...listConfig,
})
res.json({
returns,
count: returns.length,
count,
offset: validated.offset,
limit: validated.limit,
})

View File

@@ -1,6 +1,6 @@
import { IdMap } from "medusa-test-utils"
import { request } from "../../../../../helpers/test-request"
import { SwapServiceMock } from "../../../../../services/__mocks__/swap"
import { request } from "../../../../../helpers/test-request"
const defaultListOptions = {
take: 50,
@@ -27,8 +27,8 @@ describe("GET /admin/swaps/", () => {
})
it("calls swapService list with default pagination and sorting options", () => {
expect(SwapServiceMock.list).toHaveBeenCalledTimes(1)
expect(SwapServiceMock.list).toHaveBeenCalledWith(
expect(SwapServiceMock.listAndCount).toHaveBeenCalledTimes(1)
expect(SwapServiceMock.listAndCount).toHaveBeenCalledWith(
{},
{
...defaultListOptions,

View File

@@ -1,10 +1,10 @@
import { Type } from "class-transformer"
import { IsInt, IsOptional } from "class-validator"
import { SwapService } from "../../../../services"
import { validator } from "../../../../utils/validator"
import { FindConfig } from "../../../../types/common"
import { Swap } from "../../../../models"
import { SwapService } from "../../../../services"
import { Type } from "class-transformer"
import { validator } from "../../../../utils/validator"
/**
* @oas [get] /admin/swaps
@@ -72,9 +72,11 @@ export default async (req, res) => {
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 {

View File

@@ -1,6 +1,6 @@
import { IdMap } from "medusa-test-utils"
import { request } from "../../../../../helpers/test-request"
import { RegionServiceMock } from "../../../../../services/__mocks__/region"
import { request } from "../../../../../helpers/test-request"
describe("List regions", () => {
describe("list regions", () => {
@@ -14,8 +14,8 @@ describe("List regions", () => {
})
it("calls list from region service", () => {
expect(RegionServiceMock.list).toHaveBeenCalledTimes(1)
expect(RegionServiceMock.list).toHaveBeenCalledWith(
expect(RegionServiceMock.listAndCount).toHaveBeenCalledTimes(1)
expect(RegionServiceMock.listAndCount).toHaveBeenCalledWith(
{},
{
relations: [

View File

@@ -1,6 +1,7 @@
import { PaginatedResponse } from "@medusajs/types"
import { Region } from "./../../../../"
import { Router } from "express"
import middlewares from "../../../middlewares"
import { Region } from "./../../../../"
const route = Router()
@@ -38,8 +39,17 @@ export const defaultRelations = [
* type: array
* items:
* $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[]
}

View File

@@ -3,9 +3,9 @@ import { IsInt, IsOptional, ValidateNested } from "class-validator"
import { DateComparisonOperator } from "../../../../types/common"
import RegionService from "../../../../services/region"
import { Type } from "class-transformer"
import { defaultRelations } from "."
import { omit } from "lodash"
import { validator } from "../../../../utils/validator"
import { defaultRelations } from "."
/**
* @oas [get] /store/regions
@@ -110,9 +110,12 @@ export default async (req, res) => {
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 {

View File

@@ -1,16 +1,16 @@
import { IdMap } from "medusa-test-utils"
export const SwapServiceMock = {
withTransaction: function() {
withTransaction: function () {
return this
},
registerCartCompletion: jest.fn().mockImplementation(data => {
registerCartCompletion: jest.fn().mockImplementation((data) => {
return Promise.resolve({ id: "test-swap" })
}),
create: jest.fn().mockImplementation(data => {
create: jest.fn().mockImplementation((data) => {
return Promise.resolve()
}),
retrieve: jest.fn().mockImplementation(data => {
retrieve: jest.fn().mockImplementation((data) => {
switch (data) {
case IdMap.getId("test-swap"):
return Promise.resolve({
@@ -21,11 +21,11 @@ export const SwapServiceMock = {
return Promise.resolve({ id: "test-swap" })
}
}),
cancel: jest.fn().mockImplementation(f => {
cancel: jest.fn().mockImplementation((f) => {
return Promise.resolve({ f })
}),
cancelFulfillment: jest.fn().mockImplementation(f => {
cancelFulfillment: jest.fn().mockImplementation((f) => {
return Promise.resolve({ id: IdMap.getId("test-swap") })
}),
list: jest.fn().mockImplementation((...args) => {
@@ -34,6 +34,12 @@ export const SwapServiceMock = {
{ 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(() => {

View File

@@ -1,6 +1,7 @@
import NoteService from "../note"
import { IdMap, MockManager, MockRepository } from "medusa-test-utils"
import { EventBusServiceMock } from "../__mocks__/event-bus"
import NoteService from "../note"
describe("NoteService", () => {
describe("list", () => {
@@ -10,6 +11,12 @@ describe("NoteService", () => {
{ id: IdMap.getId("note"), value: "some note" },
])
},
findAndCount: (q) => {
return Promise.resolve([
[{ id: IdMap.getId("note"), value: "some note" }],
1,
])
},
})
const noteService = new NoteService({
@@ -28,8 +35,8 @@ describe("NoteService", () => {
relations: ["author"],
}
)
expect(noteRepo.find).toHaveBeenCalledTimes(1)
expect(noteRepo.find).toHaveBeenCalledWith({
expect(noteRepo.findAndCount).toHaveBeenCalledTimes(1)
expect(noteRepo.findAndCount).toHaveBeenCalledWith({
where: {
resource_id: IdMap.getId("note"),
},

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 { TransactionBaseService } from "../interfaces"
import EventBusService from "./event-bus"
import { Note } from "../models"
import { NoteRepository } from "../repositories/note"
import { FindConfig, Selector } from "../types/common"
import { CreateNoteInput } from "../types/note"
import { TransactionBaseService } from "../interfaces"
import { buildQuery } from "../utils"
import EventBusService from "./event-bus"
type InjectedDependencies = {
manager: EntityManager
@@ -81,11 +82,32 @@ class NoteService extends TransactionBaseService {
relations: [],
}
): 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 query = buildQuery(selector, config)
return noteRepo.find(query)
return noteRepo.findAndCount(query)
}
/**

View File

@@ -1,15 +1,16 @@
import { MedusaError } from "medusa-core-utils"
import {
AbstractNotificationService,
TransactionBaseService,
} from "../interfaces"
import { FindConfig, Selector } from "../types/common"
import { EntityManager } from "typeorm"
import { Logger } from "../types/global"
import { NotificationRepository } from "../repositories/notification"
import { NotificationProviderRepository } from "../repositories/notification-provider"
import { FindConfig, Selector } from "../types/common"
import { buildQuery } from "../utils"
import { MedusaError } from "medusa-core-utils"
import { Notification } from "../models"
import { NotificationProviderRepository } from "../repositories/notification-provider"
import { NotificationRepository } from "../repositories/notification"
import { buildQuery } from "../utils"
type InjectedDependencies = {
manager: EntityManager
@@ -82,11 +83,30 @@ class NotificationService extends TransactionBaseService {
order: { created_at: "DESC" },
}
): 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(
this.notificationRepository_
)
const query = buildQuery(selector, config)
return await notiRepo.find(query)
return await notiRepo.findAndCount(query)
}
/**

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 { buildQuery, setMetadata } from "../utils"
import { DeepPartial, EntityManager } from "typeorm"
import { FindConfig, Selector } from "../types/common"
import {
FulfillmentProviderService,
LineItemService,
@@ -27,6 +11,22 @@ import {
TaxProviderService,
TotalsService,
} 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 = {
manager: EntityManager
@@ -146,11 +146,28 @@ class ReturnService extends TransactionBaseService {
order: { created_at: "DESC" },
}
): 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(
this.returnRepository_
)
const query = buildQuery(selector, config)
return returnRepo.find(query)
return returnRepo.findAndCount(query)
}
/**

View File

@@ -29,7 +29,7 @@ import {
} from "./index"
import { EntityManager, In } from "typeorm"
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 { CreateShipmentConfig } from "../types/fulfillment"
@@ -278,11 +278,31 @@ class SwapService extends TransactionBaseService {
order: { created_at: "DESC" },
}
): 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 query = buildQuery(selector, config)
query.relationLoadStrategy = "query"
return await swapRepo.find(query)
return await swapRepo.findAndCount(query)
}
/**