create-m5kdev 0.13.0 → 0.13.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-m5kdev",
3
- "version": "0.13.0",
3
+ "version": "0.13.1",
4
4
  "license": "GPL-3.0-only",
5
5
  "repository": {
6
6
  "type": "git",
@@ -6,7 +6,7 @@ import type {
6
6
  import { BaseTableRepository } from "@m5kdev/backend/modules/base/base.repository";
7
7
  import type { ServerResultAsync } from "@m5kdev/backend/utils/types";
8
8
  import { and, asc, count, desc, eq, isNull, like, ne, or } from "drizzle-orm";
9
- import { ok } from "neverthrow";
9
+ import { err, ok } from "neverthrow";
10
10
  import type { Orm, Schema } from "../../db";
11
11
 
12
12
  export class PostsRepository extends BaseTableRepository<
@@ -16,73 +16,82 @@ export class PostsRepository extends BaseTableRepository<
16
16
  Schema["posts"]
17
17
  > {
18
18
  async list(input: PostsListInputSchema = {}): ServerResultAsync<PostsListOutputSchema> {
19
- return this.throwableAsync(async () => {
20
- const page = input.page ?? 1;
21
- const limit = input.limit ?? 6;
22
- const search = input.search?.trim();
23
- const conditions = [isNull(this.table.deletedAt)];
19
+ const page = input.page ?? 1;
20
+ const limit = input.limit ?? 6;
21
+ const search = input.search?.trim();
22
+ const conditions = [isNull(this.table.deletedAt)];
24
23
 
25
- if (input.status) {
26
- conditions.push(eq(this.table.status, input.status));
27
- }
28
-
29
- if (search) {
30
- const pattern = `%${search}%`;
31
- const searchCondition = or(
32
- like(this.table.title, pattern),
33
- like(this.table.slug, pattern),
34
- like(this.table.excerpt, pattern),
35
- like(this.table.content, pattern)
36
- );
24
+ if (input.status) {
25
+ conditions.push(eq(this.table.status, input.status));
26
+ }
37
27
 
38
- if (searchCondition) {
39
- conditions.push(searchCondition);
40
- }
28
+ if (search) {
29
+ const escapedSearch = search.replace(/[%_]/g, '\\ if (search) {
30
+ const pattern = `%${search}%`;
31
+ const searchCondition = or(
32
+ like(this.table.title, pattern),
33
+ like(this.table.slug, pattern),
34
+ like(this.table.excerpt, pattern),
35
+ like(this.table.content, pattern)
36
+ );
37
+ ');
38
+ const pattern = `%${escapedSearch}%`;
39
+ const searchCondition = or(
40
+ like(this.table.title, pattern),
41
+ like(this.table.slug, pattern),
42
+ like(this.table.excerpt, pattern),
43
+ like(this.table.content, pattern)
44
+ );
45
+ if (searchCondition) {
46
+ conditions.push(searchCondition);
41
47
  }
48
+ }
42
49
 
43
- const whereClause = and(...conditions);
44
- const ordering =
45
- input.sort === "title"
50
+ const whereClause = and(...conditions);
51
+ const ordering =
52
+ input.sort === "title"
53
+ ? input.order === "asc"
54
+ ? asc(this.table.title)
55
+ : desc(this.table.title)
56
+ : input.sort === "publishedAt"
46
57
  ? input.order === "asc"
47
- ? asc(this.table.title)
48
- : desc(this.table.title)
49
- : input.sort === "publishedAt"
50
- ? input.order === "asc"
51
- ? asc(this.table.publishedAt)
52
- : desc(this.table.publishedAt)
53
- : input.order === "asc"
54
- ? asc(this.table.updatedAt)
55
- : desc(this.table.updatedAt);
58
+ ? asc(this.table.publishedAt)
59
+ : desc(this.table.publishedAt)
60
+ : input.order === "asc"
61
+ ? asc(this.table.updatedAt)
62
+ : desc(this.table.updatedAt);
63
+
64
+ const rowsQuery = this.orm
65
+ .select()
66
+ .from(this.table)
67
+ .where(whereClause)
68
+ .orderBy(ordering, desc(this.table.createdAt))
69
+ .limit(limit)
70
+ .offset((page - 1) * limit);
56
71
 
57
- const rows = await this.orm
58
- .select()
59
- .from(this.table)
60
- .where(whereClause)
61
- .orderBy(ordering, desc(this.table.createdAt))
62
- .limit(limit)
63
- .offset((page - 1) * limit);
72
+ const countQuery = this.orm.select({ count: count() }).from(this.table).where(whereClause);
64
73
 
65
- const [totalRow] = await this.orm
66
- .select({ count: count() })
67
- .from(this.table)
68
- .where(whereClause);
74
+ const result = await this.throwableQuery(() => Promise.all([rowsQuery, countQuery]));
75
+ if (result.isErr()) return err(result.error);
76
+ const [rows, [totalRow]] = result.value;
69
77
 
70
- return ok({
71
- rows: rows as PostSchema[],
72
- total: totalRow?.count ?? 0,
73
- });
78
+ return ok({
79
+ rows: rows as PostSchema[],
80
+ total: totalRow?.count ?? 0,
74
81
  });
75
82
  }
76
83
 
77
84
  async findBySlug(slug: string, excludeId?: string) {
78
- return this.throwableAsync(async () => {
79
- const whereClause = excludeId
80
- ? and(eq(this.table.slug, slug), ne(this.table.id, excludeId), isNull(this.table.deletedAt))
81
- : and(eq(this.table.slug, slug), isNull(this.table.deletedAt));
85
+ const whereClause = excludeId
86
+ ? and(eq(this.table.slug, slug), ne(this.table.id, excludeId), isNull(this.table.deletedAt))
87
+ : and(eq(this.table.slug, slug), isNull(this.table.deletedAt));
82
88
 
83
- const [row] = await this.orm.select().from(this.table).where(whereClause).limit(1);
84
- return ok(row);
85
- });
89
+ const result = await this.throwableQuery(() =>
90
+ this.orm.select().from(this.table).where(whereClause).limit(1)
91
+ );
92
+ if (result.isErr()) return err(result.error);
93
+ const [row] = result.value;
94
+ return ok(row);
86
95
  }
87
96
 
88
97
  async resolveUniqueSlug(candidate: string, excludeId?: string) {