Skip to content

Commit

Permalink
feat: cursor (marker) pagination
Browse files Browse the repository at this point in the history
  • Loading branch information
alexx666 committed Apr 18, 2021
1 parent 03f73a7 commit 8229047
Show file tree
Hide file tree
Showing 5 changed files with 21 additions and 18 deletions.
2 changes: 1 addition & 1 deletion src/api/routers/todos/list.router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export default function(listTodos: ListTodos) {
try {
const request: ListTodosRequest = {
limit: Number(req.query.limit) || 20,
skip: Number(req.query.skip) || 0
marker: String(req.query.marker)
}

const response = await listTodos.execute(request)
Expand Down
2 changes: 1 addition & 1 deletion src/cli/commands/todos/list-todos.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export default function (listTodos: ListTodos) {
try {
const request: ListTodosRequest = {
limit: Number(cmd.limit),
skip: Number(cmd.skip)
marker: String(cmd.marker)
}

const response = await listTodos.execute(request)
Expand Down
2 changes: 1 addition & 1 deletion src/modules/todos/boundry/list-todos.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export interface ListTodosRequest {
limit: number
skip: number
marker?: string
}

export interface ListTodosResponse {
Expand Down
19 changes: 9 additions & 10 deletions src/providers/todo-in-memory/todo-in-memory.gateway.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import InMemoryTodoGateway from "./todo-in-memory.gateway";
describe("[InMemoryTodoGateway] Initialization", () => {
it("should create an in memory todo gateway without any todos", async () => {
const inMemTodoGW = new InMemoryTodoGateway()
const todos = await inMemTodoGW.find({ limit: 10, skip: 0 })
const todos = await inMemTodoGW.find({ limit: 10 })
expect(todos.length).toEqual(0)
expect.assertions(1)
})
Expand All @@ -26,24 +26,23 @@ describe("[InMemoryTodoGateway] Test Cases", () => {
})

it("should return all items in map as todos", async () => {
const todos = await inMemTodoGW.find({ limit: 10, skip: 0 })
const todos = await inMemTodoGW.find({ limit: 10 })
expect(todos.length).toEqual(3)
expect.assertions(1)
})

it("should return second todo", async () => {
expect.assertions(2)
const todos = await inMemTodoGW.find({ limit: 1, skip: 1 })
const todos = await inMemTodoGW.find({ limit: 1, marker: "1" })
expect(todos.length).toEqual(1)
expect(todos[0].id).toEqual("2")
expect.assertions(2)
})

it("should add a new todo and return it", async () => {
const todo = await inMemTodoGW.save(new Todo("4", "forth", new Date()));
const todos = await inMemTodoGW.find({ limit: 1, skip: 3 })
expect(todos.length).toEqual(1)
expect(todos[0]).toEqual(todo)
expect.assertions(2)
const newTodo = new Todo("4", "forth", new Date())
const savedTodo = await inMemTodoGW.save(newTodo);
expect(savedTodo).toEqual(newTodo)
expect.assertions(1)
})

it("should throw an error because the todo already exist", async () => {
Expand All @@ -57,7 +56,7 @@ describe("[InMemoryTodoGateway] Test Cases", () => {

it("should remove a todo and return its value", async () => {
const todo = await inMemTodoGW.delete("3");
const todos = await inMemTodoGW.find({ limit: 10, skip: 0 })
const todos = await inMemTodoGW.find({ limit: 10 })
expect(todos).not.toContain(todo)
expect(todos.length).toEqual(2)
expect.assertions(2)
Expand Down
14 changes: 9 additions & 5 deletions src/providers/todo-in-memory/todo-in-memory.gateway.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import TodoDocument from "./todo-document";

interface FindQuery {
limit: number;
skip: number;
marker?: string;
}

export default class InMemoryTodoGateway implements ReadableGateway<Todo>, WritableGateway<Todo> {
Expand All @@ -30,12 +30,16 @@ export default class InMemoryTodoGateway implements ReadableGateway<Todo>, Writa
}

public async find(query: FindQuery): Promise<Todo[]> {
const { limit, skip } = query;
const { limit, marker } = query;

const keys = Array.from(this.documents.keys()).filter((_, i) => i >= skip && i < limit + skip)
const keys = Array.from(this.documents.keys())

const docs = keys.map(key => this.documents.get(key)!);
// TODO: apply filter/sort

return docs.map((d, i) => d.toEntity(keys[i]))
const offset = marker ? keys.indexOf(marker) + 1 : 0;

const filteredKeys = keys.filter((_, i) => i >= offset && i < limit + offset);

return filteredKeys.map(key => this.documents.get(key)!.toEntity(key));
}
}

0 comments on commit 8229047

Please sign in to comment.