@gennext/lb-infra 0.2.1 → 0.2.2
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/README.md +133 -273
- package/dist/base/index.js +1 -1
- package/dist/base/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/base/loopback/filter/index.d.ts +0 -2
- package/dist/base/loopback/filter/index.d.ts.map +0 -1
- package/dist/base/loopback/filter/index.js +0 -5
- package/dist/base/loopback/filter/index.js.map +0 -1
- package/dist/base/loopback/http-server/index.d.ts +0 -2
- package/dist/base/loopback/http-server/index.d.ts.map +0 -1
- package/dist/base/loopback/http-server/index.js +0 -5
- package/dist/base/loopback/http-server/index.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,340 +1,200 @@
|
|
|
1
|
-
# @gennext/lb-infra
|
|
1
|
+
# 📘 Cẩm nang Kĩ thuật: @gennext/lb-infra
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
## 1. Giới thiệu
|
|
6
|
-
`@gennext/lb-infra` là nền tảng xây dựng backend hiện đại tại Gennex, kết hợp các công nghệ:
|
|
7
|
-
- **Hono**: Web framework siêu nhẹ, hỗ trợ TypeScript và OpenAPI native.
|
|
8
|
-
- **Drizzle ORM**: ORM thế hệ mới, type-safe tuyệt đối cho PostgreSQL.
|
|
9
|
-
- **Zod**: Thư viện validation và định nghĩa schema mạnh mẽ.
|
|
10
|
-
- **Winston**: Hệ thống logging đa kênh (Console, File, UDP).
|
|
11
|
-
|
|
12
|
-
**Khi nào nên dùng:** Phù hợp cho các dự án yêu cầu tốc độ phản hồi cao, cấu trúc mã nguồn tường minh (Controller-Service-Repository) và tự động hóa tài liệu API (Swagger/OpenAPI).
|
|
13
|
-
|
|
14
|
-
---
|
|
15
|
-
|
|
16
|
-
## 2. Cài đặt
|
|
17
|
-
|
|
18
|
-
Cài đặt package chính:
|
|
19
|
-
```bash
|
|
20
|
-
bun add @gennext/lb-infra
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
Các peer dependency cần thiết:
|
|
24
|
-
```bash
|
|
25
|
-
bun add hono @hono/zod-openapi zod drizzle-orm pg winston
|
|
26
|
-
# Nếu dùng Auth/Authorization
|
|
27
|
-
bun add jose casbin
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
---
|
|
31
|
-
|
|
32
|
-
## 3. Khởi tạo ứng dụng
|
|
33
|
-
Sử dụng `BaseApplication` kết hợp với `bootMixin` để tự động quét và đăng ký các thành phần.
|
|
34
|
-
|
|
35
|
-
```typescript
|
|
36
|
-
import { BaseApplication, bootMixin, bootStrapApplication, IApplicationConfigs } from '@gennext/lb-infra';
|
|
37
|
-
|
|
38
|
-
class OrderApplication extends bootMixin(BaseApplication) {
|
|
39
|
-
getAppInfo() {
|
|
40
|
-
return {
|
|
41
|
-
name: 'Order Service',
|
|
42
|
-
version: '1.0.0',
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
const configs: IApplicationConfigs = {
|
|
48
|
-
port: Number(process.env.PORT) || 3000,
|
|
49
|
-
path: { base: '/api' }
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
bootStrapApplication(OrderApplication, configs);
|
|
53
|
-
```
|
|
3
|
+
Hạ tầng Backend Hybrid chuẩn Gennex: Kết hợp sức mạnh kiến trúc của **LoopBack 4** và hiệu năng của **Hono/Drizzle**.
|
|
54
4
|
|
|
55
5
|
---
|
|
56
6
|
|
|
57
|
-
##
|
|
58
|
-
Sử dụng Drizzle để định nghĩa schema và các Repository để thao tác dữ liệu.
|
|
59
|
-
|
|
60
|
-
### Khai báo Drizzle Schema
|
|
61
|
-
Sử dụng các helper trong `column-defs.ts` để chuẩn hóa cấu trúc bảng.
|
|
62
|
-
|
|
63
|
-
```typescript
|
|
64
|
-
import { pgTable, text, integer } from 'drizzle-orm/pg-core';
|
|
65
|
-
import { generateIdColumnDefs, generateSoftDeleteColumnDefs, generateTzColumnDefs } from '@gennext/lb-infra';
|
|
66
|
-
|
|
67
|
-
export const orders = pgTable('orders', {
|
|
68
|
-
...generateIdColumnDefs({ id: { dataType: 'string' } }),
|
|
69
|
-
orderNumber: text('order_number').notNull(),
|
|
70
|
-
amount: integer('amount'),
|
|
71
|
-
...generateTzColumnDefs(),
|
|
72
|
-
...generateSoftDeleteColumnDefs(),
|
|
73
|
-
});
|
|
74
|
-
```
|
|
7
|
+
## 🏗 1. Tổng quan kiến trúc & Cài đặt
|
|
75
8
|
|
|
76
|
-
###
|
|
77
|
-
|
|
9
|
+
### 1.1 Hybrid Platform
|
|
10
|
+
Thư viện cung cấp hai lộ trình phát triển:
|
|
11
|
+
- **Hono Path (Modern):** Cho các service yêu cầu tốc độ cao, hỗ trợ OpenAPI native qua Zod.
|
|
12
|
+
- **LoopBack Path (Standard):** Cho các ứng dụng phức tạp cần DI (Dependency Injection) và tính tương thích ngược.
|
|
78
13
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
14
|
+
### 1.2 Cấu trúc Export (Sub-paths)
|
|
15
|
+
Được cấu hình trong `package.json`, giúp developer import sạch sẽ:
|
|
16
|
+
- `@gennext/lb-infra`: Entry chính (Hono, Drizzle, Utilities).
|
|
17
|
+
- `@gennext/lb-infra/lb-core`: LoopBack Core (Binding, Context, Metadata).
|
|
18
|
+
- `@gennext/lb-infra/lb-rest`: LoopBack Rest (Decorators, Sequence).
|
|
19
|
+
- `@gennext/lb-infra/lb-repo`: LoopBack Repository (Juggler, Filter).
|
|
20
|
+
- `@gennext/lb-infra/socket-io`: WebSocket component.
|
|
21
|
+
- `@gennext/lb-infra/grpc`: gRPC component.
|
|
82
22
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
```
|
|
23
|
+
### 1.3 Pin Dependencies (Không cần cài thêm)
|
|
24
|
+
Thư viện đã đóng gói sẵn và re-export các "vũ khí" sau:
|
|
25
|
+
- **Framework:** `Hono`, `@hono/zod-openapi`, `zod`.
|
|
26
|
+
- **Database:** `Drizzle ORM` (core + pg), `pg` (node-postgres).
|
|
27
|
+
- **Utilities:** `axios`, `lodash`, `dayjs` (thông qua `date.utility`).
|
|
89
28
|
|
|
90
29
|
---
|
|
91
30
|
|
|
92
|
-
##
|
|
93
|
-
Các service kế thừa `BaseService` và sử dụng `this.logger` (HFLogger pattern) để ghi log theo phương thức.
|
|
31
|
+
## 🚀 2. Application Kernel
|
|
94
32
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
export class OrderService extends BaseService {
|
|
99
|
-
async processOrder(orderId: string) {
|
|
100
|
-
const logger = this.logger.for('processOrder');
|
|
101
|
-
logger.info('Starting process', { orderId });
|
|
102
|
-
|
|
103
|
-
try {
|
|
104
|
-
// Logic xử lý đơn hàng...
|
|
105
|
-
} catch (error) {
|
|
106
|
-
logger.error('Failed to process', error);
|
|
107
|
-
throw error;
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
```
|
|
112
|
-
|
|
113
|
-
---
|
|
114
|
-
|
|
115
|
-
## 6. Controller & Routing
|
|
116
|
-
Controller quản lý các route và tích hợp Zod để tự động tạo tài liệu OpenAPI qua `defineRoute` hoặc `bindRoute`.
|
|
33
|
+
### 2.1 Khởi tạo với `BaseApplication`
|
|
34
|
+
Mọi ứng dụng phải kế thừa từ class này.
|
|
117
35
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
36
|
+
**Interface `IApplicationConfigs`:**
|
|
37
|
+
- `port`: (Bắt buộc) Cổng chạy server.
|
|
38
|
+
- `host?`: Hostname (Mặc định `0.0.0.0`).
|
|
39
|
+
- `path?`: `{ base: string, isStrict?: boolean }` - Prefix cho API.
|
|
40
|
+
- `debug?`: `{ shouldShowRoutes?: boolean }` - In ra danh sách route khi startup.
|
|
121
41
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
42
|
+
**Vòng đời (Lifecycle) trong `start()`:**
|
|
43
|
+
1. `preConfigure()`: Thiết lập biến môi trường, kết nối DB sớm.
|
|
44
|
+
2. `setupMiddlewares()`: Đăng ký Logger, CORS, v.v.
|
|
45
|
+
3. `boot()`: Tự động đăng ký Controllers/Services (khi dùng `bootMixin`).
|
|
46
|
+
4. `postConfigure()`: Chạy các tác vụ sau khi server đã lắng nghe.
|
|
126
47
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
path: '/',
|
|
133
|
-
method: 'post',
|
|
134
|
-
request: {
|
|
135
|
-
body: { content: { 'application/json': { schema: OrderSchema } } }
|
|
136
|
-
},
|
|
137
|
-
responses: {
|
|
138
|
-
200: {
|
|
139
|
-
description: 'Order created',
|
|
140
|
-
content: { 'application/json': { schema: OrderSchema } }
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
}).to({
|
|
145
|
-
handler: async (c) => {
|
|
146
|
-
const body = await c.req.json();
|
|
147
|
-
return c.json(body);
|
|
148
|
-
}
|
|
149
|
-
});
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
```
|
|
48
|
+
### 2.2 Dependency Injection (DI)
|
|
49
|
+
Hệ thống sử dụng Map-based Binding:
|
|
50
|
+
- **Bind:** `app.bind({ key: 'services.UserService' }).toClass(UserService)`
|
|
51
|
+
- **Get:** `const service = app.get<UserService>({ key: 'services.UserService' })`
|
|
52
|
+
- **Namespaces:** Nên dùng `BindingNamespaces.SERVICE`, `.CONTROLLER`, `.REPOSITORY`, `.DATASOURCE`.
|
|
153
53
|
|
|
154
54
|
---
|
|
155
55
|
|
|
156
|
-
##
|
|
157
|
-
Cấu hình kết nối cơ sở dữ liệu qua các class kế thừa.
|
|
56
|
+
## 🪵 3. Hệ thống Logger & Context
|
|
158
57
|
|
|
159
|
-
|
|
160
|
-
|
|
58
|
+
### 3.1 Logger nâng cao
|
|
59
|
+
Được xây dựng trên Winston, hỗ trợ ghi log đa kênh.
|
|
161
60
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
61
|
+
**Các Method:**
|
|
62
|
+
- `debug(msg, ...args)`: ⚠️ Chỉ hoạt động nếu `NODE_ENV` là local/dev/alpha... **VÀ** biến `DEBUG=true`.
|
|
63
|
+
- `withScope(scope)`: Gắn prefix cho log.
|
|
64
|
+
- `for(method)`: Child logger cho từng hàm cụ thể (có cache để tối ưu).
|
|
165
65
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
```
|
|
66
|
+
**UDP Logging (`DgramTransport`):**
|
|
67
|
+
Gửi log qua socket UDP (ví dụ đến Logstash/Graylog).
|
|
68
|
+
Cấu hình qua `IDgramTransportOptions`: `host`, `port`, `levels` (các mức log muốn gửi đi).
|
|
170
69
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
```typescript
|
|
177
|
-
import { LoggerFactory, RequestContext } from '@gennext/lb-infra';
|
|
178
|
-
|
|
179
|
-
const logger = LoggerFactory.getLogger(['OrderModule']);
|
|
180
|
-
|
|
181
|
-
// Sử dụng RequestContext để gắn ID tự động
|
|
182
|
-
RequestContext.run({ requestId: 'req-123' }, () => {
|
|
183
|
-
logger.info('User action log'); // Log sẽ có prefix [req-123]
|
|
184
|
-
});
|
|
185
|
-
```
|
|
70
|
+
### 3.2 RequestContext & HttpAccessLogger
|
|
71
|
+
Dùng để theo vết request ID xuyên suốt các tầng.
|
|
72
|
+
- **Tự động hóa:** Middleware tự lấy `x-request-id` từ header hoặc tự sinh mới.
|
|
73
|
+
- **Data Masking:** Tự động ẩn thông tin nhạy cảm trong log: `authorization`, `cookie`, `session`, `password`.
|
|
186
74
|
|
|
187
75
|
---
|
|
188
76
|
|
|
189
|
-
##
|
|
190
|
-
Bộ công cụ hỗ trợ Redis String, Hash, JSON và Pub/Sub.
|
|
191
|
-
|
|
192
|
-
```typescript
|
|
193
|
-
import { RedisHelper } from '@gennext/lb-infra/helpers/redis';
|
|
194
|
-
|
|
195
|
-
const redis = new RedisHelper({ host: 'localhost', port: 6379 });
|
|
77
|
+
## 🗄️ 4. Data Layer (Drizzle ORM)
|
|
196
78
|
|
|
197
|
-
|
|
79
|
+
### 4.1 Schema Helpers (`column-defs.ts`)
|
|
80
|
+
Giúp định nghĩa bảng chuẩn Gennex:
|
|
81
|
+
- `generateIdColumnDefs()`: Cột `id` (Serial hoặc UUID).
|
|
82
|
+
- `generateTzColumnDefs()`: Cột `created_at`, `modified_at` tự động cập nhật.
|
|
83
|
+
- `generateSoftDeleteColumnDefs()`: Cột `deleted_at`.
|
|
198
84
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
const lang = await redis.jGet({ key: 'user:data', path: '$.settings.lang' });
|
|
207
|
-
```
|
|
85
|
+
### 4.2 Tầng Repository (Tiering)
|
|
86
|
+
- **ReadableRepository**: Tìm kiếm cơ bản.
|
|
87
|
+
- **DefaultCRUDRepository**: Thao tác Thêm/Sửa/Xóa.
|
|
88
|
+
- **SoftDeletableRepository**: 💡 Tự động thêm điều kiện `deleted_at IS NULL` vào mọi câu query.
|
|
89
|
+
- `hardDeleteById()`: Xóa vĩnh viễn.
|
|
90
|
+
- `restore()`: Khôi phục bản ghi đã xóa.
|
|
208
91
|
|
|
209
92
|
---
|
|
210
93
|
|
|
211
|
-
##
|
|
212
|
-
Tích hợp sẵn các chiến lược xác thực phổ biến.
|
|
94
|
+
## ⚡ 5. Redis & Caching
|
|
213
95
|
|
|
214
|
-
|
|
215
|
-
|
|
96
|
+
### 5.1 RedisManager
|
|
97
|
+
Quản lý tập trung các instance Redis. Hỗ trợ cả **Standalone** và **Cluster mode**.
|
|
216
98
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
99
|
+
### 5.2 DefaultRedisHelper API
|
|
100
|
+
- `set({ key, value, options: { ttl } })`: Lưu object (tự serialize JSON).
|
|
101
|
+
- `getObject({ key })`: Lấy và tự parse JSON.
|
|
102
|
+
- `publish({ topics, payload, useCompress })`: Pub/Sub có hỗ trợ nén zlib để tiết kiệm băng thông.
|
|
221
103
|
|
|
222
104
|
---
|
|
223
105
|
|
|
224
|
-
##
|
|
225
|
-
Phân quyền dựa trên thuộc tính (RBAC/ABAC) sử dụng Casbin.
|
|
226
|
-
|
|
227
|
-
```typescript
|
|
228
|
-
import { AuthorizeComponent, DrizzleCasbinAdapter } from '@gennext/lb-infra';
|
|
229
|
-
|
|
230
|
-
this.component(AuthorizeComponent);
|
|
231
|
-
// Dùng DrizzleCasbinAdapter để lưu policy vào PostgreSQL
|
|
232
|
-
```
|
|
233
|
-
|
|
234
|
-
---
|
|
106
|
+
## 🌐 6. HTTP Layer (Hono + OpenAPI)
|
|
235
107
|
|
|
236
|
-
|
|
108
|
+
### 6.1 BaseController
|
|
109
|
+
Sử dụng `bindRoute` để có được sự hỗ trợ tuyệt đối từ TypeScript và tự sinh Swagger.
|
|
237
110
|
|
|
238
|
-
### gRPC
|
|
239
111
|
```typescript
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
}
|
|
112
|
+
this.bindRoute({
|
|
113
|
+
configs: {
|
|
114
|
+
path: '/:id',
|
|
115
|
+
method: 'get',
|
|
116
|
+
request: { params: zod.object({ id: zod.string() }) },
|
|
117
|
+
responses: { 200: jsonResponse({ schema: UserSchema, description: 'User info' }) }
|
|
118
|
+
}
|
|
119
|
+
}).to({
|
|
120
|
+
handler: async (c) => {
|
|
121
|
+
const id = c.req.param('id');
|
|
122
|
+
// ... logic
|
|
123
|
+
}
|
|
124
|
+
});
|
|
245
125
|
```
|
|
246
126
|
|
|
247
|
-
### Socket.IO
|
|
248
|
-
Sử dụng `SocketIOServerHelper` để quản lý kết nối thời gian thực.
|
|
249
|
-
|
|
250
|
-
### Health Check
|
|
251
|
-
Tích hợp sẵn endpoint `/health` để monitor trạng thái hệ thống.
|
|
252
|
-
|
|
253
127
|
---
|
|
254
128
|
|
|
255
|
-
##
|
|
256
|
-
Các hàm tiện ích tối ưu trong `src/utilities`:
|
|
129
|
+
## 🧰 7. Bộ tiện ích (Utilities Deep Dive)
|
|
257
130
|
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
131
|
+
| Utility | Method tiêu biểu | Mô tả |
|
|
132
|
+
| :--- | :--- | :--- |
|
|
133
|
+
| **parse** | `getUID()`, `keysToCamel()`, `toBoolean()`, `int()`, `float()` | Xử lý kiểu dữ liệu và format key. |
|
|
134
|
+
| **crypto** | `hashPassword()`, `comparePassword()`, `encrypt()`, `decrypt()` | Bảo mật mật khẩu và mã hóa AES. |
|
|
135
|
+
| **error** | `getError()`, `ValidationError()`, `NotImplementedError()` | Tạo lỗi chuẩn hóa có Status Code. |
|
|
136
|
+
| **model** | `buildRequestBody()`, `buildPaginationResponse()` | Tự động sinh OpenAPI schema từ Model. |
|
|
137
|
+
| **promise** | `delay(ms)` | Hàm ngủ async. |
|
|
138
|
+
| **axios** | `get()`, `post()`, `put()`, `del()` | Wrapper axios kèm xử lý lỗi chuẩn. |
|
|
264
139
|
|
|
265
140
|
---
|
|
266
141
|
|
|
267
|
-
##
|
|
268
|
-
|
|
269
|
-
| Class | Thuộc tính/Phương thức có sẵn |
|
|
270
|
-
| :--- | :--- |
|
|
271
|
-
| `BaseHelper` | `this.logger` |
|
|
272
|
-
| `BaseService` | `this.logger` (HFLogger), `this.get(key)` (DI) |
|
|
273
|
-
| `BaseController` | `this.logger`, `this.bindRoute()`, `this.defineRoute()` |
|
|
274
|
-
| `BaseDataSource` | `this.name`, `this.connector` |
|
|
275
|
-
|
|
276
|
-
---
|
|
142
|
+
## 🔑 8. Auth & Security
|
|
277
143
|
|
|
278
|
-
|
|
144
|
+
### 8.1 Authentication
|
|
145
|
+
- Đăng ký `AuthenticateComponent`.
|
|
146
|
+
- Hỗ trợ `JwtStrategy` (đọc secret từ `APP_ENV_APPLICATION_SECRET`).
|
|
279
147
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
| `APP_ENV_POSTGRES_PORT` | Cổng PostgreSQL | `5432` |
|
|
285
|
-
| `APP_ENV_POSTGRES_USERNAME` | Username DB | `postgres` |
|
|
286
|
-
| `APP_ENV_POSTGRES_PASSWORD` | Password DB | `password` |
|
|
287
|
-
| `APP_ENV_POSTGRES_DATABASE` | Tên Database | `postgres` |
|
|
288
|
-
| `APP_ENV_REDIS_DATASOURCE_HOST` | Địa chỉ Redis | `0.0.0.0` |
|
|
289
|
-
| `APP_ENV_REDIS_DATASOURCE_PORT` | Cổng Redis | `6379` |
|
|
290
|
-
| `APP_ENV_LOGGER_FOLDER_PATH` | Đường dẫn lưu file log | `./logs` |
|
|
291
|
-
| `DEBUG` | Kích hoạt log debug | `false` |
|
|
148
|
+
### 8.2 Authorization (Casbin)
|
|
149
|
+
⚠️ Cần cài `casbin`.
|
|
150
|
+
- `CasbinDrizzleAdapter`: Lưu Policy vào bảng DB do Drizzle quản lý.
|
|
151
|
+
- `CasbinEnforcer`: Check quyền bằng cú pháp: `enforcer.enforce(user, object, action)`.
|
|
292
152
|
|
|
293
153
|
---
|
|
294
154
|
|
|
295
|
-
##
|
|
155
|
+
## 🧪 9. Ví dụ: Full User Flow
|
|
296
156
|
|
|
297
157
|
```typescript
|
|
298
|
-
// --- 1. Model
|
|
299
|
-
export const
|
|
158
|
+
// --- 1. Model ---
|
|
159
|
+
export const users = pgTable('users', {
|
|
300
160
|
...generateIdColumnDefs({ id: { dataType: 'string' } }),
|
|
301
|
-
|
|
302
|
-
...generateTzColumnDefs()
|
|
161
|
+
email: text('email').notNull().unique(),
|
|
162
|
+
...generateTzColumnDefs(),
|
|
163
|
+
...generateSoftDeleteColumnDefs()
|
|
303
164
|
});
|
|
304
165
|
|
|
305
|
-
// --- 2. Repository
|
|
306
|
-
export class
|
|
307
|
-
constructor() { super(
|
|
166
|
+
// --- 2. Repository ---
|
|
167
|
+
export class UserRepository extends SoftDeletableRepository<typeof users> {
|
|
168
|
+
constructor() { super(users); }
|
|
308
169
|
}
|
|
309
170
|
|
|
310
|
-
// --- 3.
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
const repo = this.get<OrderRepository>('repositories.OrderRepository');
|
|
314
|
-
return repo.create({ item });
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
// --- 4. Controller (order.controller.ts) ---
|
|
319
|
-
@controller({ path: '/orders' })
|
|
320
|
-
export class OrderController extends BaseController {
|
|
171
|
+
// --- 3. Controller ---
|
|
172
|
+
@controller({ path: '/users' })
|
|
173
|
+
export class UserController extends BaseController {
|
|
321
174
|
async binding() {
|
|
322
175
|
this.bindRoute({
|
|
323
|
-
|
|
324
|
-
|
|
176
|
+
configs: {
|
|
177
|
+
path: '/',
|
|
178
|
+
method: 'get',
|
|
179
|
+
responses: { 200: { description: 'List' } }
|
|
180
|
+
}
|
|
325
181
|
}).to({
|
|
326
182
|
handler: async (c) => {
|
|
327
|
-
const
|
|
328
|
-
return c.json(await
|
|
183
|
+
const repo = app.get<UserRepository>({ key: 'repositories.UserRepository' });
|
|
184
|
+
return c.json(await repo.findAll());
|
|
329
185
|
}
|
|
330
186
|
});
|
|
331
187
|
}
|
|
332
188
|
}
|
|
189
|
+
```
|
|
333
190
|
|
|
334
|
-
|
|
335
|
-
class OrderApp extends bootMixin(BaseApplication) {
|
|
336
|
-
getAppInfo() { return { name: 'OrderAPI', version: '1.0' }; }
|
|
337
|
-
}
|
|
191
|
+
---
|
|
338
192
|
|
|
339
|
-
|
|
340
|
-
|
|
193
|
+
## 🛠️ 10. Scripts
|
|
194
|
+
|
|
195
|
+
- `bun run build`: Build project (TSC + tsc-alias).
|
|
196
|
+
- `bun run migrate:push`: Đẩy schema Drizzle lên Database.
|
|
197
|
+
- `bun run lint`: Kiểm tra code style các file mới thay đổi.
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
© 2024 Gennex Technology. Toàn quyền bảo lưu.
|
package/dist/base/index.js
CHANGED
|
@@ -45,7 +45,7 @@ __exportStar(require("./drizzle"), exports);
|
|
|
45
45
|
exports.drizzlePg = __importStar(require("./drizzle/pg"));
|
|
46
46
|
// pg
|
|
47
47
|
__exportStar(require("./pg"), exports);
|
|
48
|
-
//
|
|
48
|
+
// exports
|
|
49
49
|
__exportStar(require("./base.helper"), exports);
|
|
50
50
|
__exportStar(require("./datasources"), exports);
|
|
51
51
|
__exportStar(require("./models"), exports);
|
package/dist/base/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/base/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,OAAO;AACP,+CAA+B;AAC/B,qDAAmC;AAEnC,UAAU;AACV,4CAA0B;AAC1B,0DAA0C;AAE1C,KAAK;AACL,uCAAqB;AAErB,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/base/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,OAAO;AACP,+CAA+B;AAC/B,qDAAmC;AAEnC,UAAU;AACV,4CAA0B;AAC1B,0DAA0C;AAE1C,KAAK;AACL,uCAAqB;AAErB,UAAU;AACV,gDAA8B;AAC9B,gDAA8B;AAC9B,2CAAyB;AACzB,+CAA6B"}
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/base/loopback/filter/index.ts"],"names":[],"mappings":""}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/base/loopback/filter/index.ts"],"names":[],"mappings":";;AAAA,oCAAoC;AACpC,yCAAyC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/base/loopback/http-server/index.ts"],"names":[],"mappings":""}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/base/loopback/http-server/index.ts"],"names":[],"mappings":";;AAAA,yCAAyC;AACzC,8CAA8C"}
|