Skip to content

Commit 6eb9125

Browse files
committed
chore: clean codes
1 parent e623c3d commit 6eb9125

File tree

10 files changed

+171
-438
lines changed

10 files changed

+171
-438
lines changed

api/src/main/kotlin/com/example/demo/DemoApplication.kt

Lines changed: 44 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -153,8 +153,30 @@ class PersonHandler(private val persons: PersonRepository, private val validator
153153
log.debug("query params offset:$offset, limit: $limit")
154154

155155
val query = req.queryParam("q").getOrNull() ?: run {
156-
return ok().bodyAndAwait(
157-
persons.findAll().drop(offset).take(limit)
156+
return ok().bodyValueAndAwait(
157+
PaginatedResult(
158+
persons.findAll().drop(offset).take(limit)
159+
.map {
160+
PersonSummary(
161+
id = it.id,
162+
name = "${it.firstName} ${it.lastName}",
163+
email = it.email?.value,
164+
birthOfDate = it.birthOfDate
165+
)
166+
}
167+
.toList(),
168+
persons.count()
169+
)
170+
)
171+
}
172+
log.debug("has extra query: $query")
173+
return ok().bodyValueAndAwait(
174+
PaginatedResult(
175+
persons
176+
.findByFirstNameLikeIgnoreCaseOrLastNameLikeIgnoreCaseOrEmailLikeIgnoreCase(
177+
".*$query.*",
178+
PageRequest.of(offset / limit, limit)
179+
)
158180
.map {
159181
PersonSummary(
160182
id = it.id,
@@ -163,21 +185,9 @@ class PersonHandler(private val persons: PersonRepository, private val validator
163185
birthOfDate = it.birthOfDate
164186
)
165187
}
188+
.toList(),
189+
persons.countByFirstNameLikeIgnoreCaseOrLastNameLikeIgnoreCaseOrEmailLikeIgnoreCase(".*$query.*")
166190
)
167-
}
168-
log.debug("has extra query: $query")
169-
return ok().bodyAndAwait(
170-
persons.findByFirstNameLikeIgnoreCaseOrLastNameLikeIgnoreCaseOrEmailLikeIgnoreCase(
171-
".*$query.*",
172-
PageRequest.of(offset / limit, limit)
173-
).map {
174-
PersonSummary(
175-
id = it.id,
176-
name = "${it.firstName} ${it.lastName}",
177-
email = it.email?.value,
178-
birthOfDate = it.birthOfDate
179-
)
180-
}
181191
)
182192
}
183193

@@ -237,6 +247,8 @@ class PersonHandler(private val persons: PersonRepository, private val validator
237247
}
238248
}
239249

250+
data class PaginatedResult<out T>(val data: List<T>, val count: Long)
251+
240252
data class PersonSummary(
241253
val id: String? = null,
242254
val name: String,
@@ -277,6 +289,22 @@ interface PersonRepository : CoroutineCrudRepository<Person, String>,
277289
query: String,
278290
of: PageRequest
279291
): Flow<Person>
292+
293+
@Query(
294+
value = """
295+
{
296+
${'$'}or: [
297+
{'firstName': {${'$'}regex: ?0, ${'$'}options:'i' }},
298+
{'firstName': {${'$'}regex: ?0, ${'$'}options:'i' }},
299+
{'email': {${'$'}regex: ?0, ${'$'}options:'i' }}
300+
]
301+
}
302+
""",
303+
count = true
304+
)
305+
fun countByFirstNameLikeIgnoreCaseOrLastNameLikeIgnoreCaseOrEmailLikeIgnoreCase(
306+
query: String
307+
): Long
280308
}
281309

282310
@JvmInline

api/src/test/kotlin/com/example/demo/IntegrationTests.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,9 @@ class IntegrationTests {
3333
fun `get all persons`() = runTest {
3434
client.get().uri("/persons")
3535
.awaitExchange { clientResponse ->
36-
val entity = clientResponse.awaitEntity<List<PersonSummary>>()
36+
val entity = clientResponse.awaitEntity<PaginatedResult<PersonSummary>>()
3737
entity.statusCode shouldBe HttpStatus.OK
38-
entity.body!!.forAny { it.name shouldContain "foo" }
38+
entity.body!!.data.forAny { it.name shouldContain "foo" }
3939
}
4040
}
4141

api/src/test/kotlin/com/example/demo/PersonRouterTest.kt

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,12 +64,15 @@ class PersonRouterTest {
6464
)
6565
)
6666
)
67+
coEvery { persons.count() } returns 15L
6768
client.get().uri("/persons")
6869
.exchange()
6970
.expectStatus().isOk
70-
.expectBody().jsonPath("$.[0].firstName", equalTo("foo"))
71+
.expectBody().jsonPath("$.data[0].name").isEqualTo("foo bar")
72+
.jsonPath("$.count").isEqualTo(15)
7173

7274
coVerify(exactly = 1) { persons.findAll() }
75+
coVerify(exactly = 1) { persons.count() }
7376
}
7477

7578
@Test
@@ -94,6 +97,9 @@ class PersonRouterTest {
9497
)
9598
)
9699
)
100+
coEvery {
101+
persons.countByFirstNameLikeIgnoreCaseOrLastNameLikeIgnoreCaseOrEmailLikeIgnoreCase(any())
102+
} returns 15L
97103
client.get().uri { builder ->
98104
builder.path("/persons").queryParam("q", "foo")
99105
.queryParam("offset", 0)
@@ -102,14 +108,18 @@ class PersonRouterTest {
102108
}
103109
.exchange()
104110
.expectStatus().isOk
105-
.expectBody().jsonPath("$.[0].firstName", equalTo("foo"))
111+
.expectBody().jsonPath("$.data[0].name").isEqualTo("foo bar")
112+
.jsonPath("$.count").isEqualTo(15)
106113

107114
coVerify(exactly = 1) {
108115
persons.findByFirstNameLikeIgnoreCaseOrLastNameLikeIgnoreCaseOrEmailLikeIgnoreCase(
109116
any(),
110117
any()
111118
)
112119
}
120+
coVerify(exactly = 1) {
121+
persons.countByFirstNameLikeIgnoreCaseOrLastNameLikeIgnoreCaseOrEmailLikeIgnoreCase(any())
122+
}
113123
}
114124

115125
@Test
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package com.example.demo
2+
3+
import kotlinx.coroutines.reactive.awaitFirst
4+
import kotlinx.coroutines.reactor.awaitSingle
5+
import kotlinx.coroutines.test.runTest
6+
import org.junit.jupiter.api.BeforeEach
7+
import org.junit.jupiter.api.Test
8+
import org.slf4j.LoggerFactory
9+
import org.springframework.beans.factory.annotation.Autowired
10+
import org.springframework.boot.test.autoconfigure.data.mongo.DataMongoTest
11+
import org.springframework.context.annotation.Import
12+
import org.springframework.data.annotation.Id
13+
import org.springframework.data.annotation.ReadOnlyProperty
14+
import org.springframework.data.mongodb.core.ReactiveMongoOperations
15+
import org.springframework.data.mongodb.core.mapping.Document
16+
import org.springframework.data.mongodb.core.mapping.DocumentReference
17+
import org.springframework.data.mongodb.core.remove
18+
19+
@DataMongoTest
20+
@Import(TestDemoApplication::class)
21+
class PostRepositoryTest {
22+
companion object {
23+
private val log = LoggerFactory.getLogger(PostRepositoryTest::class.java)
24+
}
25+
26+
@Autowired
27+
lateinit var template: ReactiveMongoOperations
28+
29+
@BeforeEach
30+
fun setup() = runTest {
31+
val deletedComments = template.remove<Comment>().all().awaitSingle().deletedCount
32+
log.debug("deleting comments: $deletedComments")
33+
34+
val deletedPost = template.remove<Post>().all().awaitSingle().deletedCount
35+
log.debug("deleting posts: $deletedPost")
36+
}
37+
38+
@Test
39+
fun `save and find posts`() = runTest {
40+
val post = template.save(Post(title = "test posts", body = "test body")).awaitSingle()
41+
val comment = template.save(Comment(body = "test comment", post = post.id)).awaitSingle()
42+
43+
log.debug("found comment: $comment")
44+
log.debug("related post: ${comment?.post}")
45+
46+
// template.update(Post::class.java)
47+
// .matching(where("id").isEqualTo(post.id))
48+
// .apply(Update().push("comments", comment))
49+
// .allAndAwait()
50+
51+
val foundPost = template.findById(post.id!!, Post::class.java)
52+
.awaitFirst()
53+
log.debug("found post: $foundPost")
54+
log.debug("comments of post: ${foundPost.comments}")
55+
}
56+
}
57+
58+
59+
@Document
60+
data class Post(
61+
@field:Id
62+
val id: String? = null,
63+
var title: String,
64+
var body: String,
65+
66+
@field:ReadOnlyProperty
67+
@field:DocumentReference(lookup = "{'post':?#{#self._id} }" )
68+
// @field:DocumentReference()
69+
var comments: List<Comment>? = emptyList()
70+
)
71+
72+
@Document
73+
data class Comment(
74+
@field:Id
75+
val id: String? = null,
76+
var body: String,
77+
78+
//@field:DocumentReference(lazy =true)
79+
val post: String? = null
80+
)

ui/src/App.tsx

Lines changed: 33 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,37 @@
1+
import {
2+
RouteObject,
3+
RouterProvider,
4+
createBrowserRouter,
5+
} from "react-router-dom";
6+
import "./App.css";
7+
import { ContactsLayout, PersonEdit, PersonList } from "./contacts";
8+
import { Home, HomeLayout} from "./home";
9+
import ErrorPage from "./ErrorPage";
110

2-
import React from 'react';
3-
import './App.css';
4-
import Home from './Home';
5-
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
6-
import PersonList from './PersonList';
7-
import PersonEdit from './PersonEdit';
11+
const routes: RouteObject[] = [
12+
{
13+
path: "/",
14+
element: <HomeLayout />,
15+
children: [{ path: "", element: <Home /> }],
16+
},
17+
{
18+
path: "/contacts",
19+
element: <ContactsLayout />,
20+
children: [
21+
{ path: "", element: <PersonList /> },
22+
{ path: ":id", element: <PersonEdit /> },
23+
],
24+
},
25+
{
26+
path: "*",
27+
element: <ErrorPage/>,
28+
},
29+
];
30+
31+
const router = createBrowserRouter(routes);
832

933
const App = () => {
10-
return (
11-
<Router>
12-
<Routes>
13-
<Route path="/" element={<Home/>}/>
14-
<Route path="/persons" element={<PersonList/>}/>
15-
<Route path="/persons/:id" element={<PersonEdit/>}/>
16-
</Routes>
17-
</Router>
18-
)
19-
}
34+
return <RouterProvider router={router} />;
35+
};
2036

21-
export default App;
37+
export default App;

ui/src/AppNavbar.tsx

Lines changed: 0 additions & 27 deletions
This file was deleted.

ui/src/Home.tsx

Lines changed: 0 additions & 17 deletions
This file was deleted.

ui/src/Model.tsx

Lines changed: 0 additions & 25 deletions
This file was deleted.

0 commit comments

Comments
 (0)