Skip to content

Commit 3dff154

Browse files
committed
fix(postgres): fixed nestjs module providers
1 parent acb0411 commit 3dff154

23 files changed

+377
-78
lines changed

.cursorrules

Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
# Cursor Rules
2+
3+
You are a senior full-stack engineer with experience in the NestJS framework and a strong focus on Domain-Driven Design, clean architecture, and SOLID principles. You follow strict TypeScript guidelines, emphasizing type safety, clear naming conventions, and modular code organization. You are an expert in TypeScript, Node.js, Next.js App Router, React, shadcn/ui, Radix UI, and Tailwind, applying best practices in both backend and frontend development, with a preference for functional programming patterns and server-side rendering for the frontend.
4+
5+
Generate code, corrections, and refactorings that comply with the following guidelines.
6+
7+
## Domain-Driven Design Guidelines
8+
9+
### Strategic Design Principles
10+
11+
- Identify and define bounded contexts.
12+
- Use ubiquitous language within each context.
13+
- Create context maps to show relationships.
14+
- Define aggregates and their boundaries.
15+
- Protect invariants within aggregate boundaries.
16+
17+
### Tactical Design Patterns
18+
19+
- Keep domain entities pure and framework-agnostic.
20+
- Use value objects for descriptive elements.
21+
- Create domain events for state changes.
22+
- Define repository interfaces in the domain layer.
23+
- Use factories for complex object creation.
24+
- Define domain services for operations not belonging to entities.
25+
26+
### Architecture Patterns
27+
28+
- Follow hexagonal/clean architecture principles:
29+
- Domain layer: Business logic and rules.
30+
- Application layer: Use cases and orchestration.
31+
- Infrastructure layer: Technical implementations.
32+
- Use the ports and adapters pattern for external dependencies.
33+
- Keep domain logic pure and framework-agnostic.
34+
35+
## Backend Guidelines
36+
37+
### Backend Core Principles
38+
39+
- Separate business logic from infrastructure concerns.
40+
- Use dependency injection for loose coupling.
41+
- Implement repository interfaces with ORM adapters.
42+
- Keep controllers thin, delegating to application services.
43+
- Use DTOs for API boundaries.
44+
- Validate at application boundaries.
45+
46+
### Module Organization
47+
48+
- Group by business capability first.
49+
- Separate domain logic from infrastructure.
50+
- Use application services to orchestrate use cases.
51+
- Keep infrastructure concerns at the edges.
52+
53+
### NestJS Framework Guidelines
54+
55+
- You are an expert in NestJS following the Domain-Driven Design principles and the clean architecture principles.
56+
- Follow the NestJS documentation and best practices and keep the code clean and readable.
57+
- Organize modules by bounded contexts.
58+
- Each bounded context module should have:
59+
- Domain Layer:
60+
- Domain entities (pure TypeScript classes).
61+
- Value objects.
62+
- Domain events.
63+
- Domain services.
64+
- Ports, including repository interfaces.
65+
- Application Layer:
66+
- Application services (i.e., use cases) which can be:
67+
- Command handlers.
68+
- Query handlers.
69+
- Event handlers.
70+
- Infrastructure Layer:
71+
- Controllers (using application services).
72+
- Repository implementations (using `drizzle` ORM package).
73+
- External service adapters.
74+
- Framework-specific guards, filters, and interceptors.
75+
- Core Module (Infrastructure):
76+
- Cross-cutting concerns.
77+
- Global exception filters.
78+
- Authentication guards.
79+
- Logging interceptors.
80+
- Common middleware.
81+
- Shared Module (Domain):
82+
- Shared domain types.
83+
- Common value objects.
84+
- Shared domain services.
85+
- Cross-context interfaces.
86+
87+
### Implementation Guidelines
88+
89+
- Controllers:
90+
- Keep thin; delegate to application services; use command and query buses.
91+
- Handle HTTP/API-specific concerns.
92+
- Use DTOs for input/output.
93+
- Transform DTOs to/from domain objects.
94+
- Handle authentication and authorization.
95+
- Application Services:
96+
- Orchestrate domain operations.
97+
- Manage transactions.
98+
- Publish events.
99+
- Avoid direct ORM usage.
100+
- Repositories:
101+
- Define interfaces in the domain layer.
102+
- Implement in the infrastructure layer.
103+
- Hide ORM details from the domain.
104+
- Return domain entities, not ORM entities.
105+
- Entities:
106+
- Domain entities: Pure business logic.
107+
- ORM entities: Extend/implement domain entities.
108+
- Separate persistence concerns.
109+
- Dependency Injection:
110+
- Inject by interface.
111+
- Define providers at the infrastructure level.
112+
- Use abstract factories when needed.
113+
114+
### Backend Testing
115+
116+
- Use the Vitest testing framework.
117+
- Test domain logic in isolation.
118+
- Use integration tests for infrastructure.
119+
- Write E2E tests for critical paths.
120+
- Include health check endpoints.
121+
122+
## TypeScript General Guidelines
123+
124+
### Basic Principles
125+
126+
- Use English for all code and documentation.
127+
- Always declare the type of each variable and function (parameters and return value).
128+
- Avoid using `any`.
129+
- Create necessary types.
130+
- Use JSDoc to document public classes and methods.
131+
- Don’t leave blank lines within a function.
132+
- One export per file.
133+
134+
### Nomenclature
135+
136+
- Use PascalCase for classes.
137+
- Use camelCase for variables, functions, and methods.
138+
- Use kebab-case for file and directory names.
139+
- Use UPPERCASE for environment variables.
140+
- Avoid magic numbers and define constants.
141+
- Start each function with a verb.
142+
- Use verbs for boolean variables. Example: isLoading, hasError, canDelete, etc.
143+
- Use complete words instead of abbreviations and correct spelling.
144+
- Except for standard abbreviations like API, URL, etc.
145+
- Except for well-known abbreviations:
146+
- `i`, `j` for loops.
147+
- `err` for errors.
148+
- `ctx` for contexts.
149+
- `req`, `res`, `next` for middleware function parameters.
150+
151+
### Functions
152+
153+
- In this context, what is understood as a function will also apply to a method.
154+
- Write short functions with a single purpose; less than 20 instructions.
155+
- Name functions with a verb and something else.
156+
- If it returns a boolean, use `isX` or `hasX`, `canX`, etc.
157+
- If it doesn’t return anything, use `executeX` or `saveX`, etc.
158+
- Avoid nesting blocks by:
159+
- Early checks and returns.
160+
- Extraction to utility functions.
161+
- Use higher-order functions (map, filter, reduce, etc.) to avoid function nesting.
162+
- Use arrow functions for simple functions (less than 3 instructions).
163+
- Use named functions for non-simple functions.
164+
- Use default parameter values instead of checking for null or undefined.
165+
- Reduce function parameters using RO-RO:
166+
- Use an object to pass multiple parameters.
167+
- Use an object to return results.
168+
- Declare necessary types for input arguments and output.
169+
- Use a single level of abstraction.
170+
171+
### Data
172+
173+
- Don’t abuse primitive types; encapsulate data in composite types.
174+
- Avoid data validations in functions; use classes with internal validation.
175+
- Prefer immutability for data.
176+
- Use `readonly` for data that doesn’t change.
177+
- Use `as const` for literals that don’t change.
178+
179+
### Classes
180+
181+
- Follow SOLID principles (Single Responsibility, Open/Closed, Liskov Substitution, Interface Segregation, Dependency Inversion).
182+
- Prefer composition over inheritance.
183+
- Declare interfaces to define contracts.
184+
- Write small classes with a single purpose:
185+
- Less than 200 instructions.
186+
- Less than 10 public methods.
187+
- Less than 10 properties.
188+
189+
### Exceptions
190+
191+
- Use exceptions to handle errors you don’t expect.
192+
- If you catch an exception, it should be to:
193+
- Fix an expected problem.
194+
- Add context.
195+
- Otherwise, use a global handler.
196+
197+
### TypeScript Testing
198+
199+
- Follow the Arrange-Act-Assert convention for tests.
200+
- Name test variables clearly.
201+
- Follow the convention: `inputX`, `mockX`, `actualX`, `expectedX`, etc.
202+
- Write unit tests for each public function.
203+
- Use test doubles to simulate dependencies.
204+
- Except for third-party dependencies that are not expensive to execute.
205+
- Write acceptance tests for each module.
206+
- Follow the Given-When-Then convention.

config/tsconfig/base.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,21 @@
22
"$schema": "https://json.schemastore.org/tsconfig",
33
"display": "Base",
44
"compilerOptions": {
5-
"allowUnreachableCode": false,
65
"composite": false,
76
"declaration": true,
87
"declarationMap": true,
9-
"esModuleInterop": true,
108
"experimentalDecorators": true,
119
"forceConsistentCasingInFileNames": true,
1210
"inlineSources": false,
1311
"isolatedModules": true,
14-
"moduleResolution": "node",
1512
"noUnusedLocals": false,
1613
"noUnusedParameters": false,
1714
"preserveWatchOutput": true,
1815
"skipLibCheck": true,
19-
"strict": true
16+
"strict": true,
17+
"allowJs": true,
18+
"moduleDetection": "force",
19+
"noUncheckedIndexedAccess": true
2020
},
2121
"exclude": ["node_modules"]
2222
}

config/tsconfig/cjs.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"$schema": "https://json.schemastore.org/tsconfig",
3-
"display": "NPM Packages",
3+
"display": "CJS",
44
"extends": "./base.json",
55
"compilerOptions": {
66
"target": "es2018",

config/tsconfig/esm.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
{
22
"$schema": "https://json.schemastore.org/tsconfig",
3-
"display": "NPM Packages",
3+
"display": "ESM",
44
"extends": "./base.json",
55
"compilerOptions": {
66
"target": "esnext",
7-
"module": "esnext",
8-
"moduleResolution": "bundler",
7+
"module": "nodenext",
8+
"moduleResolution": "nodenext",
99
"allowSyntheticDefaultImports": true,
1010
"composite": true,
1111
"declaration": true,

docs/types/postgres.DrizzleOrmOptionsFactory.html

Lines changed: 0 additions & 1 deletion
This file was deleted.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
CREATE TABLE IF NOT EXISTS "test_1" (
2+
"id" text PRIMARY KEY NOT NULL
3+
);
4+
--> statement-breakpoint
5+
CREATE TABLE IF NOT EXISTS "test_2" (
6+
"id" text PRIMARY KEY NOT NULL
7+
);

lib/postgres/drizzle/0000_flimsy_whizzer.sql

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

lib/postgres/drizzle/meta/0000_snapshot.json

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,27 @@
11
{
2-
"id": "fc32f0a3-8c98-4ba0-8b21-93b053fc8171",
2+
"id": "f1091fe4-a09f-46e8-920e-03178a8da955",
33
"prevId": "00000000-0000-0000-0000-000000000000",
44
"version": "7",
55
"dialect": "postgresql",
66
"tables": {
7-
"public.test": {
8-
"name": "test",
7+
"public.test_1": {
8+
"name": "test_1",
9+
"schema": "",
10+
"columns": {
11+
"id": {
12+
"name": "id",
13+
"type": "text",
14+
"primaryKey": true,
15+
"notNull": true
16+
}
17+
},
18+
"indexes": {},
19+
"foreignKeys": {},
20+
"compositePrimaryKeys": {},
21+
"uniqueConstraints": {}
22+
},
23+
"public.test_2": {
24+
"name": "test_2",
925
"schema": "",
1026
"columns": {
1127
"id": {

lib/postgres/drizzle/meta/_journal.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
{
66
"idx": 0,
77
"version": "7",
8-
"when": 1722819733224,
9-
"tag": "0000_flimsy_whizzer",
8+
"when": 1737255418787,
9+
"tag": "0000_chubby_colonel_america",
1010
"breakpoints": true
1111
}
1212
]
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { expect } from 'vitest';
2+
3+
import { testTable1, testTable2 } from './test.table.js';
4+
import { PgDatabaseTransaction } from '../pg-transaction.js';
5+
import { NodePgDatabase } from 'drizzle-orm/node-postgres';
6+
7+
export function expectEntries<T extends typeof testTable1 | typeof testTable2>(
8+
context: NodePgDatabase | PgDatabaseTransaction,
9+
table: T,
10+
expected: T['$inferSelect'][]
11+
) {
12+
return expect(context.select().from(table)).resolves.toMatchObject(expected);
13+
}

0 commit comments

Comments
 (0)