Skip to content

Commit df99f9a

Browse files
Boris AbramovBoris Abramov
authored andcommitted
Implement MongoDB ODM support
1 parent c06bf94 commit df99f9a

File tree

7 files changed

+238
-56
lines changed

7 files changed

+238
-56
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,9 +123,9 @@ return new UserResource(users).omit('createdAt', 'updatedAt').get()
123123

124124
get() finalizes data processing. While pick(), omit() and redefine() modify data, trailing get() or paginate() is needed to complete the response. This requirement is not applied to refine() and refinePaginate()
125125

126-
## Lucid pagination support
126+
## Pagination support
127127

128-
Lucid offset-based pagination is supported.
128+
Offset-based pagination is supported for [Lucid](https://github.com/adonisjs/lucid) and [MongoDB ODM for AdonisJS](https://github.com/DreamsHive/adonis-odm)
129129

130130
[gh-workflow-image]: https://img.shields.io/github/actions/workflow/status/manomintis/adonis-api-resources/test.yml?style=for-the-badge
131131
[gh-workflow-url]: https://github.com/manomintis/adonis-api-resources/actions/workflows/test.yml "Github action"

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@
6060
"@adonisjs/tsconfig": "^1.2.1",
6161
"@japa/assert": "^2.1.0",
6262
"@japa/runner": "^3.1.1",
63-
"@swc/core": "^1.3.102",
63+
"@swc/core": "^1.13.0",
6464
"@types/node": "^20.10.7",
6565
"c8": "^9.0.0",
6666
"copyfiles": "^2.4.1",

src/resource.ts

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,11 @@ export abstract class Resource {
1313
abstract defineMap(data: any): object
1414

1515
private isPaginated(): boolean {
16-
return 'rows' in this.data && 'currentPage' in this.data
16+
const ormPaginated = 'rows' in this.data && 'currentPage' in this.data
17+
const odmPaginated = 'data' in this.data && 'meta' in this.data
18+
const indeedPaginated = ormPaginated || odmPaginated
19+
if (odmPaginated) this.data.getMeta = () => this.data.meta
20+
return indeedPaginated
1721
}
1822

1923
private isCollection(): boolean {
@@ -68,7 +72,7 @@ export abstract class Resource {
6872
if (this.isPaginated()) {
6973
this.data = this.parsePaginated(
7074
(this.data as any).getMeta(),
71-
this.pickCollection((this.data as any).rows, keys)
75+
this.pickCollection((this.data as any).rows || (this.data as any).data, keys)
7276
)
7377
} else if (this.isCollection()) {
7478
this.data = this.pickCollection(this.data, keys)
@@ -82,7 +86,7 @@ export abstract class Resource {
8286
if (this.isPaginated()) {
8387
this.data = this.parsePaginated(
8488
(this.data as any).getMeta(),
85-
this.omitCollection((this.data as any).rows, keys)
89+
this.omitCollection((this.data as any).rows || (this.data as any).data, keys)
8690
)
8791
} else if (this.isCollection()) {
8892
this.data = this.omitCollection(this.data, keys)
@@ -96,7 +100,7 @@ export abstract class Resource {
96100
if (this.isPaginated()) {
97101
this.data = this.parsePaginated(
98102
(this.data as any).getMeta(),
99-
this.redefineCollection((this.data as any).rows)
103+
this.redefineCollection((this.data as any).rows || (this.data as any).data)
100104
)
101105
} else if (this.isCollection()) {
102106
this.data = this.redefineCollection(this.data)
@@ -115,7 +119,7 @@ export abstract class Resource {
115119
}
116120

117121
paginate(page: number = 1, limit: number = 10) {
118-
let lastPage = Math.max(Math.ceil(this.data.length / limit), 1)
122+
const lastPage = Math.max(Math.ceil(this.data.data.length / limit), 1)
119123
interface PaginationMeta {
120124
total: number
121125
perPage: number
@@ -138,7 +142,7 @@ export abstract class Resource {
138142
nextPageUrl: page < lastPage ? `/?page=${page + 1}` : null,
139143
previousPageUrl: page > 1 ? `/?page=${page - 1}` : null,
140144
}
141-
const collection = this.data.slice((page - 1) * limit, page * limit)
145+
const collection = (this.data.rows || this.data.data).slice((page - 1) * limit, page * limit)
142146
this.data = {
143147
meta: meta,
144148
data: collection,

tests/collection.spec.ts

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import { Resource } from '../src/resource.js'
2+
import { test } from '@japa/runner'
3+
4+
class TestResourceResource extends Resource {
5+
defineMap(data: any): object {
6+
return {
7+
fullName: data.firstName + ' ' + data.lastName,
8+
firstName: data.firstName,
9+
lastName: data.lastName,
10+
}
11+
}
12+
}
13+
14+
const testObjectCollection = [
15+
{
16+
firstName: 'John',
17+
lastName: 'Doe',
18+
serialize: () => {
19+
return {
20+
firstName: 'John',
21+
lastName: 'Doe',
22+
}
23+
},
24+
},
25+
{
26+
firstName: 'Jane',
27+
lastName: 'Doe',
28+
},
29+
{
30+
firstName: 'John1',
31+
lastName: 'Doe1',
32+
},
33+
{
34+
firstName: 'Jane1',
35+
lastName: 'Doe1',
36+
},
37+
{
38+
firstName: 'John2',
39+
lastName: 'Doe2',
40+
},
41+
{
42+
firstName: 'Jane2',
43+
lastName: 'Doe2',
44+
},
45+
{
46+
firstName: 'John3',
47+
lastName: 'Doe3',
48+
},
49+
{
50+
firstName: 'Jane3',
51+
lastName: 'Doe3',
52+
},
53+
]
54+
55+
const resultRefineCollection: any = new TestResourceResource(testObjectCollection).refine()
56+
const resultPickCollection: any = new TestResourceResource(testObjectCollection)
57+
.pick('firstName')
58+
.get()
59+
const resultOmitCollection: any = new TestResourceResource(testObjectCollection)
60+
.omit('firstName')
61+
.get()
62+
63+
test.group('Collection', () => {
64+
test('test_collection', ({ assert }) => {
65+
assert.equal(resultRefineCollection[0].fullName, 'John Doe')
66+
assert.equal(resultRefineCollection[1].fullName, 'Jane Doe')
67+
})
68+
test('test_pick_collection', ({ assert }) => {
69+
assert.equal(resultPickCollection[0].firstName, 'John')
70+
assert.equal(resultPickCollection[0].lastName, undefined)
71+
})
72+
test('test_omit_collection', ({ assert }) => {
73+
assert.equal(resultOmitCollection[0].firstName, undefined)
74+
assert.equal(resultOmitCollection[0].lastName, 'Doe')
75+
})
76+
})

tests/entity.spec.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { Resource } from '../src/resource.js'
2+
import { test } from '@japa/runner'
3+
4+
class TestResourceResource extends Resource {
5+
defineMap(data: any): object {
6+
return {
7+
fullName: data.firstName + ' ' + data.lastName,
8+
firstName: data.firstName,
9+
lastName: data.lastName,
10+
}
11+
}
12+
}
13+
14+
const testObjectEntity = {
15+
firstName: 'John',
16+
lastName: 'Doe',
17+
}
18+
19+
const resultRefineEntity: any = new TestResourceResource(testObjectEntity).refine()
20+
const resultPickEntity: any = new TestResourceResource(testObjectEntity).pick('firstName').get()
21+
const resultOmitEntity: any = new TestResourceResource(testObjectEntity).omit('firstName').get()
22+
23+
test.group('Entity', () => {
24+
test('test_entity', ({ assert }) => {
25+
assert.equal(resultRefineEntity.fullName, 'John Doe')
26+
})
27+
test('test_pick_entity', ({ assert }) => {
28+
assert.equal(resultPickEntity.firstName, 'John')
29+
assert.equal(resultPickEntity.lastName, undefined)
30+
})
31+
test('test_omit_entity', ({ assert }) => {
32+
assert.equal(resultOmitEntity.firstName, undefined)
33+
assert.equal(resultOmitEntity.lastName, 'Doe')
34+
})
35+
})

tests/odmpaginated.spec.ts

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
import { Resource } from '../src/resource.js'
2+
import { test } from '@japa/runner'
3+
4+
class TestResourceResource extends Resource {
5+
defineMap(data: any): object {
6+
return {
7+
fullName: data.firstName + ' ' + data.lastName,
8+
firstName: data.firstName,
9+
lastName: data.lastName,
10+
}
11+
}
12+
}
13+
14+
const testObjectCollection = [
15+
{
16+
firstName: 'John',
17+
lastName: 'Doe',
18+
serialize: () => {
19+
return {
20+
firstName: 'John',
21+
lastName: 'Doe',
22+
}
23+
},
24+
},
25+
{
26+
firstName: 'Jane',
27+
lastName: 'Doe',
28+
},
29+
{
30+
firstName: 'John1',
31+
lastName: 'Doe1',
32+
},
33+
{
34+
firstName: 'Jane1',
35+
lastName: 'Doe1',
36+
},
37+
{
38+
firstName: 'John2',
39+
lastName: 'Doe2',
40+
},
41+
{
42+
firstName: 'Jane2',
43+
lastName: 'Doe2',
44+
},
45+
{
46+
firstName: 'John3',
47+
lastName: 'Doe3',
48+
},
49+
{
50+
firstName: 'Jane3',
51+
lastName: 'Doe3',
52+
},
53+
]
54+
55+
class ObjectPaginated {
56+
data = testObjectCollection
57+
meta = { currentPage: 1 }
58+
}
59+
60+
const testObjectPaginated = new ObjectPaginated()
61+
62+
const resultRefineODMPaginated: any = new TestResourceResource(testObjectPaginated).refine()
63+
const resultRefinedPaginated: any = new TestResourceResource(testObjectPaginated).refinePaginate(
64+
1,
65+
4
66+
)
67+
const resultRefinedPaginated2: any = new TestResourceResource(testObjectPaginated).refinePaginate(
68+
2,
69+
4
70+
)
71+
72+
const resultPickPaginated: any = new TestResourceResource(testObjectPaginated)
73+
.pick('firstName')
74+
.get()
75+
76+
const resultOmitPaginated: any = new TestResourceResource(testObjectPaginated)
77+
.omit('firstName')
78+
.get()
79+
80+
test.group('ODM paginated', () => {
81+
test('test_pagination', ({ assert }) => {
82+
assert.equal(resultRefineODMPaginated.data[0].fullName, 'John Doe')
83+
assert.equal(resultRefineODMPaginated.data[1].fullName, 'Jane Doe')
84+
assert.equal(resultRefineODMPaginated.meta.currentPage, 1)
85+
})
86+
test('test_refine_pagination', ({ assert }) => {
87+
assert.equal(resultRefinedPaginated.data[0].fullName, 'John Doe')
88+
assert.equal(resultRefinedPaginated.data[1].fullName, 'Jane Doe')
89+
assert.equal(resultRefinedPaginated.meta.currentPage, 1)
90+
})
91+
test('test_refine_pagination2', ({ assert }) => {
92+
assert.equal(resultRefinedPaginated2.data[0].fullName, 'John2 Doe2')
93+
assert.equal(resultRefinedPaginated2.data[1].fullName, 'Jane2 Doe2')
94+
assert.equal(resultRefinedPaginated2.meta.currentPage, 2)
95+
})
96+
test('test_pick_collection_paginated', ({ assert }) => {
97+
assert.equal(resultPickPaginated.data[0].firstName, 'John')
98+
assert.equal(resultPickPaginated.data[0].lastName, undefined)
99+
assert.equal(resultPickPaginated.meta.currentPage, 1)
100+
})
101+
test('test_pick_collection_paginated', ({ assert }) => {
102+
assert.equal(resultOmitPaginated.data[0].firstName, undefined)
103+
assert.equal(resultOmitPaginated.data[0].lastName, 'Doe')
104+
assert.equal(resultOmitPaginated.meta.currentPage, 1)
105+
})
106+
})

tests/resource.spec.ts renamed to tests/ormpaginated.spec.ts

Lines changed: 8 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,6 @@ class TestResourceResource extends Resource {
1111
}
1212
}
1313

14-
const testObjectEntity = {
15-
firstName: 'John',
16-
lastName: 'Doe',
17-
}
18-
1914
const testObjectCollection = [
2015
{
2116
firstName: 'John',
@@ -64,48 +59,32 @@ class ObjectPaginated {
6459
return { currentPage: 1 }
6560
}
6661
}
62+
6763
const testObjectPaginated = new ObjectPaginated()
6864

69-
const resultRefineEntity: any = new TestResourceResource(testObjectEntity).refine()
70-
const resultRefineCollection: any = new TestResourceResource(testObjectCollection).refine()
71-
const resultRefineLucidPaginated: any = new TestResourceResource(testObjectPaginated).refine()
72-
const resultRefinedPaginated: any = new TestResourceResource(testObjectCollection).refinePaginate(
65+
const resultRefineORMPaginated: any = new TestResourceResource(testObjectPaginated).refine()
66+
const resultRefinedPaginated: any = new TestResourceResource(testObjectPaginated).refinePaginate(
7367
1,
7468
4
7569
)
76-
const resultRefinedPaginated2: any = new TestResourceResource(testObjectCollection).refinePaginate(
70+
const resultRefinedPaginated2: any = new TestResourceResource(testObjectPaginated).refinePaginate(
7771
2,
7872
4
7973
)
8074

81-
const resultPickEntity: any = new TestResourceResource(testObjectEntity).pick('firstName').get()
82-
const resultPickCollection: any = new TestResourceResource(testObjectCollection)
83-
.pick('firstName')
84-
.get()
8575
const resultPickPaginated: any = new TestResourceResource(testObjectPaginated)
8676
.pick('firstName')
8777
.get()
8878

89-
const resultOmitEntity: any = new TestResourceResource(testObjectEntity).omit('firstName').get()
90-
const resultOmitCollection: any = new TestResourceResource(testObjectCollection)
91-
.omit('firstName')
92-
.get()
9379
const resultOmitPaginated: any = new TestResourceResource(testObjectPaginated)
9480
.omit('firstName')
9581
.get()
9682

97-
test.group('Resource', () => {
98-
test('test_entity', ({ assert }) => {
99-
assert.equal(resultRefineEntity.fullName, 'John Doe')
100-
})
101-
test('test_collection', ({ assert }) => {
102-
assert.equal(resultRefineCollection[0].fullName, 'John Doe')
103-
assert.equal(resultRefineCollection[1].fullName, 'Jane Doe')
104-
})
83+
test.group('ORM paginated', () => {
10584
test('test_pagination', ({ assert }) => {
106-
assert.equal(resultRefineLucidPaginated.data[0].fullName, 'John Doe')
107-
assert.equal(resultRefineLucidPaginated.data[1].fullName, 'Jane Doe')
108-
assert.equal(resultRefineLucidPaginated.meta.currentPage, 1)
85+
assert.equal(resultRefineORMPaginated.data[0].fullName, 'John Doe')
86+
assert.equal(resultRefineORMPaginated.data[1].fullName, 'Jane Doe')
87+
assert.equal(resultRefineORMPaginated.meta.currentPage, 1)
10988
})
11089
test('test_refine_pagination', ({ assert }) => {
11190
assert.equal(resultRefinedPaginated.data[0].fullName, 'John Doe')
@@ -117,29 +96,11 @@ test.group('Resource', () => {
11796
assert.equal(resultRefinedPaginated2.data[1].fullName, 'Jane2 Doe2')
11897
assert.equal(resultRefinedPaginated2.meta.currentPage, 2)
11998
})
120-
121-
test('test_pick_entity', ({ assert }) => {
122-
assert.equal(resultPickEntity.firstName, 'John')
123-
assert.equal(resultPickEntity.lastName, undefined)
124-
})
125-
test('test_pick_collection', ({ assert }) => {
126-
assert.equal(resultPickCollection[0].firstName, 'John')
127-
assert.equal(resultPickCollection[0].lastName, undefined)
128-
})
12999
test('test_pick_collection_paginated', ({ assert }) => {
130100
assert.equal(resultPickPaginated.data[0].firstName, 'John')
131101
assert.equal(resultPickPaginated.data[0].lastName, undefined)
132102
assert.equal(resultPickPaginated.meta.currentPage, 1)
133103
})
134-
135-
test('test_omit_entity', ({ assert }) => {
136-
assert.equal(resultOmitEntity.firstName, undefined)
137-
assert.equal(resultOmitEntity.lastName, 'Doe')
138-
})
139-
test('test_omit_collection', ({ assert }) => {
140-
assert.equal(resultOmitCollection[0].firstName, undefined)
141-
assert.equal(resultOmitCollection[0].lastName, 'Doe')
142-
})
143104
test('test_pick_collection_paginated', ({ assert }) => {
144105
assert.equal(resultOmitPaginated.data[0].firstName, undefined)
145106
assert.equal(resultOmitPaginated.data[0].lastName, 'Doe')

0 commit comments

Comments
 (0)