Skip to content

Commit ed1d731

Browse files
authored
Merge pull request #25 from techdiary-dev/editor_temp
Editor temp
2 parents 4f6d12b + 0df3457 commit ed1d731

File tree

20 files changed

+383
-115
lines changed

20 files changed

+383
-115
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/(dashboard-editor)/dashboard/articles/[uuid]/page.tsx

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,56 @@
1-
import ArticleEditor from "@/components/Editor/ArticleEditor";
2-
import * as articleActions from "@/backend/services/article.actions";
3-
import React from "react";
1+
import { Article, ArticleTag, Tag, User } from "@/backend/models/domain-models";
2+
import { persistenceRepository } from "@/backend/persistence-repositories";
3+
import { DatabaseTableName } from "@/backend/persistence/persistence-contracts";
4+
import {
5+
and,
6+
eq,
7+
inArray,
8+
leftJoin,
9+
} from "@/backend/persistence/persistence-where-operator";
410
import * as sessionActions from "@/backend/services/session.actions";
11+
import ArticleEditor from "@/components/Editor/ArticleEditor";
512
import { notFound } from "next/navigation";
6-
import { persistenceRepository } from "@/backend/persistence-repositories";
7-
import { eq, and } from "@/backend/persistence/persistence-where-operator";
13+
import React from "react";
814

915
interface Props {
1016
params: Promise<{ uuid: string }>;
1117
}
1218
const page: React.FC<Props> = async ({ params }) => {
1319
const sessionUserId = await sessionActions.getSessionUserId();
1420
const _params = await params;
15-
21+
// eq("author_id", sessionUserId)
1622
const [article] = await persistenceRepository.article.findRows({
1723
limit: 1,
1824
where: and(eq("id", _params.uuid), eq("author_id", sessionUserId)),
25+
joins: [
26+
leftJoin<Article, User>({
27+
as: "author",
28+
joinTo: DatabaseTableName.users,
29+
localField: "author_id",
30+
foreignField: "id",
31+
columns: ["id", "name", "username"],
32+
}),
33+
],
34+
});
35+
36+
const aggregatedTags = await persistenceRepository.articleTag.findRows({
37+
where: inArray("article_id", [article.id]),
38+
joins: [
39+
leftJoin<ArticleTag, Tag>({
40+
as: "tag",
41+
joinTo: "tags",
42+
localField: "tag_id",
43+
foreignField: "id",
44+
columns: ["id", "name", "color", "icon", "description"],
45+
}),
46+
],
1947
});
2048

49+
const tags = aggregatedTags?.map((item) => item?.tag);
50+
if (tags.length) {
51+
article.tags = tags as Tag[];
52+
}
53+
2154
if (!article) {
2255
throw notFound();
2356
}

src/app/[username]/[articleHandle]/opengraph-image.tsx

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
import { Article, User } from "@/backend/models/domain-models";
22
import { persistenceRepository } from "@/backend/persistence-repositories";
3-
import {
4-
eq,
5-
joinTable,
6-
} from "@/backend/persistence/persistence-where-operator";
3+
import { eq, leftJoin } from "@/backend/persistence/persistence-where-operator";
74
import { ImageResponse } from "next/og";
85
import { readFile } from "node:fs/promises";
96
import { join } from "node:path";
@@ -33,7 +30,7 @@ export default async function Image(options: ArticlePageProps) {
3330
columns: ["title", "excerpt", "cover_image", "body"],
3431
limit: 1,
3532
joins: [
36-
joinTable<Article, User>({
33+
leftJoin<Article, User>({
3734
as: "user",
3835
joinTo: "users",
3936
localField: "author_id",

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/app/sitemaps/articles/sitemap.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { persistenceRepository } from "@/backend/persistence-repositories";
33
import {
44
and,
55
eq,
6-
joinTable,
6+
leftJoin,
77
neq,
88
} from "@/backend/persistence/persistence-where-operator";
99
import type { MetadataRoute } from "next";
@@ -14,7 +14,7 @@ export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
1414
columns: ["handle", "updated_at"],
1515
limit: -1,
1616
joins: [
17-
joinTable<Article, User>({
17+
leftJoin<Article, User>({
1818
as: "user",
1919
joinTo: "users",
2020
localField: "author_id",

0 commit comments

Comments
 (0)