Skip to content

Commit 0df3457

Browse files
committed
Implement article tag deletion logic in persistence layer and enhance SQL query building. Update GET request handler to remove specified tags for an article. Refactor related functions for improved clarity and functionality.
1 parent d868276 commit 0df3457

File tree

10 files changed

+148
-21
lines changed

10 files changed

+148
-21
lines changed

.github/persistence-context.md

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
## Project Overview
2+
3+
This project is a custom-built mini-ORM utility for managing database operations in a Node.js/TypeScript application. It includes features like query building, pagination, joins, and CRUD operations.
4+
5+
### Key Directories and Files
6+
7+
- **`src/backend/persistence/`**: Contains the core persistence logic.
8+
9+
- `persistence.repository.ts`: Implements the `PersistentRepository` class for database operations.
10+
- `persistence-contracts.ts`: Defines interfaces and types for persistence operations.
11+
- `persistence-utils.ts`: Utility functions for building SQL queries.
12+
- `persistence-where-operator.ts`: Helper functions for building `WHERE` clauses.
13+
- `database-drivers/pg.client.ts`: PostgreSQL database driver implementation.
14+
15+
- **`src/backend/persistence-repositories.ts`**: Exports repository instances for specific database tables.
16+
17+
### Key Features
18+
19+
1. **Dynamic Query Building**:
20+
21+
- Supports `WHERE`, `ORDER BY`, `JOIN`, and pagination.
22+
- Utility functions like `buildWhereClause`, `buildOrderByClause`, and `buildJoinClause`.
23+
24+
2. **CRUD Operations**:
25+
26+
- `findRows`, `findRowCount`, `createOne`, `createMany`, `updateOne`, `deleteRows`.
27+
28+
3. **Error Handling**:
29+
30+
- Custom error classes like `PersistenceDriverError`.
31+
32+
4. **Database Driver**:
33+
- Uses PostgreSQL (`pg` package) for database interactions.
34+
35+
### Testing
36+
37+
- Tests are written using Jest.
38+
- Mocking is used for the database driver (`IPersistentDriver`).
39+
- Test cases cover all repository methods and utility functions.
40+
41+
### Common Queries
42+
43+
1. **How to test a specific method?**
44+
45+
- Provide the method name and its file path. Example: `findRows` in `persistence.repository.ts`.
46+
47+
2. **How to add a new feature?**
48+
49+
- Specify the feature and its purpose. Example: Add support for `GROUP BY` in queries.
50+
51+
3. **How to debug an issue?**
52+
53+
- Provide the error message and the relevant file or method.
54+
55+
4. **How to write migrations?**
56+
- Specify the table and column changes. Example: Add a new column to the `users` table.
57+
58+
### Example Prompts
59+
60+
- "Can you check the `findRows` method in `persistence.repository.ts`?"
61+
- "Can you write test cases for the `updateOne` method?"
62+
- "How can I add a `GROUP BY` clause to the query builder?"
63+
- "Can you help me debug this error: `Failed to initialize database connection`?"
64+
65+
### Notes
66+
67+
- Always use parameterized queries to prevent SQL injection.
68+
- Follow TypeScript best practices for type safety.
69+
- Use environment variables for database configuration.

.idea/.gitignore

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/inspectionProfiles/Project_Default.xml

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/modules.xml

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/techdiary.dev.iml

Lines changed: 12 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/vcs.xml

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/app/api/play/route.ts

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,35 @@
1-
import * as articleActions from "@/backend/services/article.actions";
2-
import { NextResponse } from "next/server";
1+
import {persistenceRepository} from "@/backend/persistence-repositories";
2+
import {NextResponse} from "next/server";
33

44
export async function GET(request: Request) {
5-
// return NextResponse.json({
6-
// handle: await articleActions.updateArticle({
7-
// article_id: "5f0a1c0c-a8c8-4f5b-b8d8-c4d4d4d4d4d4",
8-
// }),
9-
// });
5+
// [
6+
// {
7+
// "key": "article_id",
8+
// "operator": "=",
9+
// "value": "317eb5cf-9ef5-4ef1-9da7-78007dd83149"
10+
// },
11+
// {
12+
// "key": "tag_id",
13+
// "operator": "not in",
14+
// "value": []
15+
// }
16+
// ]
17+
return NextResponse.json({
18+
handle: await persistenceRepository.articleTag.deleteRows({
19+
where: {
20+
AND: [
21+
{
22+
"key": "article_id",
23+
"operator": "=",
24+
"value": "317eb5cf-9ef5-4ef1-9da7-78007dd83149"
25+
},
26+
{
27+
"key": "tag_id",
28+
"operator": "not in",
29+
"value": ["060f882f-e40e-415b-bc06-ed618f77d9bc", "2e27c4b0-226d-41ed-ae3f-3f9ac493b6a7"]
30+
}
31+
]
32+
}
33+
}),
34+
});
1035
}

src/backend/persistence/persistence-utils.ts

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ export const sql = String.raw;
1111
/**
1212
* Builds a WHERE clause for SQL queries
1313
* @param where Where condition or undefined
14+
* @param tableName
1415
* @returns Object containing the WHERE clause and values array
1516
*/
1617
export const buildWhereClause = <T>(
@@ -27,8 +28,6 @@ export const buildWhereClause = <T>(
2728
// Process the where condition
2829
const whereClause = processWhereCondition(where, values, tableName);
2930

30-
console.log({ whereClause, tableName });
31-
3231
return {
3332
whereClause,
3433
values,
@@ -94,15 +93,7 @@ const processSimpleCondition = <T>(
9493
return operator === "in" ? "FALSE" : "TRUE";
9594
}
9695

97-
const placeholders = value
98-
.map(() => `$${values.length + 1}`)
99-
.map((placeholder, index) => {
100-
values.push(value[index]);
101-
return placeholder;
102-
})
103-
.join(", ");
104-
105-
return `"${tableName}"."${key.toString()}" ${operator} (${placeholders})`;
96+
return `"${tableName}"."${key.toString()}" ${operator} (${value.map(v => `'${v}'`).join(',')})`;
10697
}
10798

10899
// Handle NULL values

src/backend/services/article.actions.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
neq,
1616
notInArray,
1717
or,
18+
inArray,
1819
} from "../persistence/persistence-where-operator";
1920
import { PersistentRepository } from "../persistence/persistence.repository";
2021
import {
@@ -233,12 +234,13 @@ export async function updateMyArticle(
233234
});
234235

235236
if (input.tag_ids) {
236-
await persistenceRepository.articleTag.deleteRows({
237+
const deleted = await persistenceRepository.articleTag.deleteRows({
237238
where: and(
238-
eq("article_id", article.id),
239+
// eq("article_id", article.id),
239240
notInArray("tag_id", input.tag_ids)
240241
),
241242
});
243+
console.log(deleted)
242244

243245
input.tag_ids.forEach(async (tag_id) => {
244246
await persistenceRepository.articleTag.createOne({

src/backend/services/tag.action.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22

33
import { z } from "zod";
44
import { persistenceRepository } from "../persistence-repositories";
5+
import { like } from "../persistence/persistence-where-operator";
56
import { TagRepositoryInput } from "./inputs/tag.input";
67
import { handleRepositoryException } from "./RepositoryException";
7-
import { like } from "../persistence/persistence-where-operator";
88

99
export const getTags = async (
1010
_input: z.infer<typeof TagRepositoryInput.findAllInput>

0 commit comments

Comments
 (0)