@dqcai/sqlite 3.0.5 → 3.2.0
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 +615 -299
- package/lib/adapters/base-adapter.d.ts +2 -2
- package/lib/adapters/base-adapter.d.ts.map +1 -1
- package/lib/adapters/index.d.ts +2 -1
- package/lib/adapters/index.d.ts.map +1 -1
- package/lib/adapters/nodejs-adapter.d.ts +8 -0
- package/lib/adapters/nodejs-adapter.d.ts.map +1 -0
- package/lib/adapters/reactnative-adapter.d.ts +9 -0
- package/lib/adapters/reactnative-adapter.d.ts.map +1 -0
- package/lib/core/base-service.d.ts +25 -1
- package/lib/core/base-service.d.ts.map +1 -1
- package/lib/core/database-factory.d.ts +2 -2
- package/lib/core/database-factory.d.ts.map +1 -1
- package/lib/core/database-manager.d.ts.map +1 -1
- package/lib/core/service-manager.d.ts +1 -1
- package/lib/core/service-manager.d.ts.map +1 -1
- package/lib/core/universal-dao.d.ts +1 -2
- package/lib/core/universal-dao.d.ts.map +1 -1
- package/lib/index.d.ts +5 -319
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -1
- package/lib/index.js.map +1 -1
- package/lib/index.mjs +11 -11
- package/lib/index.mjs.map +1 -1
- package/lib/logger/index.d.ts +32 -0
- package/lib/logger/index.d.ts.map +1 -0
- package/lib/types.d.ts +37 -3
- package/lib/types.d.ts.map +1 -1
- package/package.json +27 -3
- package/lib/index.umd.js +0 -1
- package/lib/index.umd.js.map +0 -1
- package/lib/logger/logger-config.d.ts +0 -81
- package/lib/logger/logger-config.d.ts.map +0 -1
package/README.md
CHANGED
|
@@ -10,427 +10,743 @@
|
|
|
10
10
|
|
|
11
11
|
## 🚀 Why Choose @dqcai/sqlite?
|
|
12
12
|
|
|
13
|
-
-
|
|
13
|
+
- **🌐 Universal**: Works everywhere - Browser, Node.js, Deno, Bun, React Native
|
|
14
14
|
- **🛡️ Type-Safe**: Full TypeScript support with complete type definitions
|
|
15
15
|
- **⚡ High Performance**: Built-in optimization, connection pooling, and batch operations
|
|
16
|
-
-
|
|
16
|
+
- **🗃️ Enterprise-Ready**: Service lifecycle management with ServiceManager
|
|
17
17
|
- **📊 Schema Management**: JSON-based schema definitions with migrations
|
|
18
18
|
- **🔄 Transaction Support**: Single and cross-schema transaction management
|
|
19
19
|
- **📈 Monitoring**: Real-time health monitoring and auto-recovery
|
|
20
20
|
- **🎯 DAO Pattern**: Clean separation of data access logic
|
|
21
|
+
- **📝 Advanced Logging**: Integrated logger with @dqcai/logger for comprehensive debugging
|
|
21
22
|
|
|
22
23
|
## 📦 Installation
|
|
23
24
|
|
|
24
25
|
```bash
|
|
25
|
-
npm install @dqcai/sqlite
|
|
26
|
+
npm install @dqcai/sqlite @dqcai/logger
|
|
26
27
|
# or
|
|
27
|
-
yarn add @dqcai/sqlite
|
|
28
|
+
yarn add @dqcai/sqlite @dqcai/logger
|
|
28
29
|
# or
|
|
29
|
-
pnpm add @dqcai/sqlite
|
|
30
|
+
pnpm add @dqcai/sqlite @dqcai/logger
|
|
30
31
|
```
|
|
31
32
|
|
|
32
|
-
|
|
33
|
+
### Cài đặt dependencies theo môi trường
|
|
33
34
|
|
|
34
|
-
|
|
35
|
-
import { DatabaseManager, ServiceManager, BaseService } from '@dqcai/sqlite';
|
|
35
|
+
**React Native:**
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
database_name: "users",
|
|
41
|
-
schemas: {
|
|
42
|
-
users: {
|
|
43
|
-
cols: [
|
|
44
|
-
{ name: "id", type: "integer", primary_key: true, auto_increment: true },
|
|
45
|
-
{ name: "username", type: "varchar", length: 50, unique: true },
|
|
46
|
-
{ name: "email", type: "varchar", length: 100, unique: true },
|
|
47
|
-
{ name: "created_at", type: "datetime", default: "CURRENT_TIMESTAMP" }
|
|
48
|
-
]
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
};
|
|
37
|
+
```bash
|
|
38
|
+
npm install react-native-sqlite-storage
|
|
39
|
+
```
|
|
52
40
|
|
|
53
|
-
|
|
54
|
-
await DatabaseManager.registerSchema('users', userSchema);
|
|
55
|
-
await DatabaseManager.initializeCoreConnection();
|
|
41
|
+
**Node.js:**
|
|
56
42
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
return await this.create(data);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
async getAllUsers() {
|
|
64
|
-
return await this.findAll();
|
|
65
|
-
}
|
|
66
|
-
}
|
|
43
|
+
```bash
|
|
44
|
+
npm install better-sqlite3
|
|
45
|
+
```
|
|
67
46
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
}
|
|
47
|
+
## 2. Lựa chọn Adapter theo môi trường
|
|
48
|
+
|
|
49
|
+
### React Native Adapter
|
|
50
|
+
|
|
51
|
+
```typescript
|
|
52
|
+
import { ReactNativeAdapter, DatabaseFactory } from "@dqcai/sqlite";
|
|
53
|
+
|
|
54
|
+
// Đăng ký adapter
|
|
55
|
+
DatabaseFactory.registerAdapter(new ReactNativeAdapter());
|
|
74
56
|
```
|
|
75
57
|
|
|
76
|
-
|
|
58
|
+
### Node.js Adapter
|
|
77
59
|
|
|
78
|
-
|
|
79
|
-
|
|
60
|
+
```typescript
|
|
61
|
+
import { NodeJSAdapter, DatabaseFactory } from "@dqcai/sqlite";
|
|
62
|
+
|
|
63
|
+
// Đăng ký adapter
|
|
64
|
+
DatabaseFactory.registerAdapter(new NodeJSAdapter());
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Adapter tự động phát hiện
|
|
80
68
|
|
|
81
69
|
```typescript
|
|
82
|
-
import {
|
|
70
|
+
import { DatabaseFactory } from "@dqcai/sqlite";
|
|
71
|
+
import { ReactNativeAdapter } from "@dqcai/sqlite";
|
|
72
|
+
import { NodeJSAdapter } from "@dqcai/sqlite";
|
|
83
73
|
|
|
84
|
-
//
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
products: productSchema
|
|
88
|
-
});
|
|
74
|
+
// Đăng ký cả hai adapter - thư viện sẽ tự chọn adapter phù hợp
|
|
75
|
+
DatabaseFactory.registerAdapter(new ReactNativeAdapter());
|
|
76
|
+
DatabaseFactory.registerAdapter(new NodeJSAdapter());
|
|
89
77
|
|
|
90
|
-
//
|
|
91
|
-
|
|
78
|
+
// Kiểm tra môi trường hiện tại
|
|
79
|
+
console.log("Environment:", DatabaseFactory.getEnvironmentInfo());
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## 3. Quản lý Database với DatabaseManager
|
|
92
83
|
|
|
93
|
-
|
|
94
|
-
|
|
84
|
+
### Khai báo Schema
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
import { DatabaseSchema, SQLITE_TYPE_MAPPING } from "@dqcai/sqlite";
|
|
88
|
+
|
|
89
|
+
const coreSchema: DatabaseSchema = {
|
|
90
|
+
version: "v1",
|
|
91
|
+
database_name: "core.db",
|
|
92
|
+
description: "Core database schema",
|
|
93
|
+
type_mapping: SQLITE_TYPE_MAPPING,
|
|
94
|
+
schemas: {
|
|
95
|
+
users: {
|
|
96
|
+
description: "User management table",
|
|
97
|
+
cols: [
|
|
98
|
+
{
|
|
99
|
+
name: "id",
|
|
100
|
+
type: "uuid",
|
|
101
|
+
constraints: "NOT NULL UNIQUE PRIMARY KEY",
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
name: "username",
|
|
105
|
+
type: "varchar",
|
|
106
|
+
length: 50,
|
|
107
|
+
constraints: "NOT NULL UNIQUE",
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
name: "email",
|
|
111
|
+
type: "email",
|
|
112
|
+
constraints: "UNIQUE",
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
name: "created_at",
|
|
116
|
+
type: "timestamp",
|
|
117
|
+
constraints: "DEFAULT CURRENT_TIMESTAMP",
|
|
118
|
+
},
|
|
119
|
+
],
|
|
120
|
+
indexes: [
|
|
121
|
+
{
|
|
122
|
+
name: "idx_users_username",
|
|
123
|
+
columns: ["username"],
|
|
124
|
+
unique: true,
|
|
125
|
+
},
|
|
126
|
+
],
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
};
|
|
95
130
|
```
|
|
96
131
|
|
|
97
|
-
###
|
|
98
|
-
Centralized service lifecycle management with automatic optimization.
|
|
132
|
+
### Đăng ký Schema và khởi tạo Database
|
|
99
133
|
|
|
100
134
|
```typescript
|
|
101
|
-
import {
|
|
135
|
+
import { DatabaseManager } from "@dqcai/sqlite";
|
|
102
136
|
|
|
103
|
-
|
|
137
|
+
// Đăng ký schema
|
|
138
|
+
DatabaseManager.registerSchema("core", coreSchema);
|
|
104
139
|
|
|
105
|
-
//
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
140
|
+
// Khởi tạo kết nối core database
|
|
141
|
+
await DatabaseManager.initializeCoreConnection();
|
|
142
|
+
|
|
143
|
+
// Lazy loading cho database khác
|
|
144
|
+
const dao = await DatabaseManager.getLazyLoading("core");
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Quản lý kết nối theo Role
|
|
148
|
+
|
|
149
|
+
```typescript
|
|
150
|
+
// Đăng ký role configuration
|
|
151
|
+
DatabaseManager.registerRole({
|
|
152
|
+
roleName: "admin",
|
|
153
|
+
requiredDatabases: ["core", "inventory"],
|
|
154
|
+
optionalDatabases: ["reports"],
|
|
155
|
+
priority: 1,
|
|
110
156
|
});
|
|
111
157
|
|
|
112
|
-
//
|
|
113
|
-
|
|
158
|
+
// Set user roles - tự động khởi tạo databases cần thiết
|
|
159
|
+
await DatabaseManager.setCurrentUserRoles(["admin"]);
|
|
114
160
|
|
|
115
|
-
//
|
|
116
|
-
const
|
|
161
|
+
// Lấy database đã được khởi tạo
|
|
162
|
+
const coreDao = DatabaseManager.get("core");
|
|
117
163
|
```
|
|
118
164
|
|
|
119
|
-
|
|
120
|
-
|
|
165
|
+
## 4. Định nghĩa Service từ BaseService
|
|
166
|
+
|
|
167
|
+
### Service đơn giản (sử dụng DefaultService)
|
|
121
168
|
|
|
122
169
|
```typescript
|
|
123
|
-
import { BaseService } from
|
|
170
|
+
import { BaseService } from "@dqcai/sqlite";
|
|
124
171
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
172
|
+
// Sử dụng BaseService trực tiếp cho CRUD cơ bản
|
|
173
|
+
const userService = new BaseService("core", "users");
|
|
174
|
+
await userService.init();
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Service mở rộng với logic nghiệp vụ
|
|
130
178
|
|
|
131
|
-
|
|
179
|
+
```typescript
|
|
180
|
+
import { BaseService } from "@dqcai/sqlite";
|
|
181
|
+
|
|
182
|
+
export class UserService extends BaseService<User> {
|
|
132
183
|
constructor() {
|
|
133
|
-
super(
|
|
184
|
+
super("core", "users");
|
|
185
|
+
this.setPrimaryKeyFields(["id"]);
|
|
134
186
|
}
|
|
135
187
|
|
|
136
|
-
|
|
137
|
-
|
|
188
|
+
// Business logic method
|
|
189
|
+
async findByStoreId(storeId: string): Promise<User[]> {
|
|
190
|
+
await this._ensureInitialized();
|
|
191
|
+
return await this.findAll({ store_id: storeId });
|
|
138
192
|
}
|
|
139
193
|
|
|
140
|
-
async
|
|
141
|
-
|
|
194
|
+
async findActiveUsers(): Promise<User[]> {
|
|
195
|
+
await this._ensureInitialized();
|
|
196
|
+
return await this.findAll({ is_active: true });
|
|
142
197
|
}
|
|
143
198
|
|
|
144
|
-
async
|
|
145
|
-
|
|
199
|
+
async updateLastLogin(userId: string): Promise<void> {
|
|
200
|
+
await this._ensureInitialized();
|
|
201
|
+
await this.update(userId, {
|
|
202
|
+
last_login: new Date().toISOString(),
|
|
203
|
+
});
|
|
146
204
|
}
|
|
147
205
|
|
|
148
|
-
async
|
|
149
|
-
|
|
206
|
+
async lockUser(userId: string, duration: number): Promise<void> {
|
|
207
|
+
await this._ensureInitialized();
|
|
208
|
+
const lockedUntil = new Date(Date.now() + duration);
|
|
209
|
+
await this.update(userId, {
|
|
210
|
+
is_active: false,
|
|
211
|
+
locked_until: lockedUntil.toISOString(),
|
|
212
|
+
});
|
|
150
213
|
}
|
|
151
214
|
}
|
|
152
215
|
```
|
|
153
216
|
|
|
154
|
-
|
|
217
|
+
### Service với validation và events
|
|
155
218
|
|
|
156
|
-
### Browser
|
|
157
219
|
```typescript
|
|
158
|
-
|
|
220
|
+
export class StoreService extends BaseService<Store> {
|
|
221
|
+
constructor() {
|
|
222
|
+
super("core", "stores");
|
|
223
|
+
this.setupEventHandlers();
|
|
224
|
+
}
|
|
159
225
|
|
|
160
|
-
|
|
161
|
-
|
|
226
|
+
private setupEventHandlers() {
|
|
227
|
+
// Lắng nghe events
|
|
228
|
+
this.on("dataCreated", (event) => {
|
|
229
|
+
console.log("Store created:", event.data);
|
|
230
|
+
});
|
|
162
231
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
232
|
+
this.on("dataUpdated", (event) => {
|
|
233
|
+
console.log("Store updated:", event.id);
|
|
234
|
+
});
|
|
166
235
|
|
|
167
|
-
|
|
168
|
-
|
|
236
|
+
// Custom error handler
|
|
237
|
+
this.setErrorHandler("CREATE_ERROR", (error) => {
|
|
238
|
+
console.error("Failed to create store:", error.message);
|
|
239
|
+
});
|
|
240
|
+
}
|
|
169
241
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
242
|
+
// Override create để thêm validation
|
|
243
|
+
async create(data: Partial<Store>): Promise<Store | null> {
|
|
244
|
+
// Validate
|
|
245
|
+
if (!data.enterprise_id) {
|
|
246
|
+
throw new Error("Enterprise ID is required");
|
|
247
|
+
}
|
|
248
|
+
if (!data.name?.trim()) {
|
|
249
|
+
throw new Error("Store name is required");
|
|
250
|
+
}
|
|
174
251
|
|
|
175
|
-
|
|
176
|
-
|
|
252
|
+
// Set defaults
|
|
253
|
+
data.currency = data.currency || "VND";
|
|
254
|
+
data.timezone = data.timezone || "Asia/Ho_Chi_Minh";
|
|
255
|
+
data.status = data.status || "active";
|
|
177
256
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
257
|
+
return await super.create(data);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
async findByEnterpriseId(enterpriseId: string): Promise<Store[]> {
|
|
261
|
+
return await this.findAll({ enterprise_id: enterpriseId });
|
|
262
|
+
}
|
|
181
263
|
|
|
182
|
-
|
|
264
|
+
async getActiveStores(enterpriseId: string): Promise<Store[]> {
|
|
265
|
+
return await this.findAll(
|
|
266
|
+
{ enterprise_id: enterpriseId, status: "active" },
|
|
267
|
+
{ orderBy: [{ name: "name", direction: "ASC" }] }
|
|
268
|
+
);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
183
271
|
```
|
|
184
272
|
|
|
185
|
-
##
|
|
273
|
+
## 5. Quản lý Service với ServiceManager
|
|
186
274
|
|
|
187
|
-
|
|
275
|
+
### Đăng ký Services
|
|
188
276
|
|
|
189
277
|
```typescript
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
description: "Application database",
|
|
194
|
-
schemas: {
|
|
195
|
-
users: {
|
|
196
|
-
description: "User accounts",
|
|
197
|
-
cols: [
|
|
198
|
-
{
|
|
199
|
-
name: "id",
|
|
200
|
-
type: "integer",
|
|
201
|
-
primary_key: true,
|
|
202
|
-
auto_increment: true
|
|
203
|
-
},
|
|
204
|
-
{
|
|
205
|
-
name: "username",
|
|
206
|
-
type: "varchar",
|
|
207
|
-
length: 50,
|
|
208
|
-
nullable: false,
|
|
209
|
-
unique: true
|
|
210
|
-
},
|
|
211
|
-
{
|
|
212
|
-
name: "email",
|
|
213
|
-
type: "varchar",
|
|
214
|
-
length: 100,
|
|
215
|
-
nullable: false,
|
|
216
|
-
unique: true
|
|
217
|
-
},
|
|
218
|
-
{
|
|
219
|
-
name: "password",
|
|
220
|
-
type: "varchar",
|
|
221
|
-
length: 255,
|
|
222
|
-
nullable: false
|
|
223
|
-
},
|
|
224
|
-
{
|
|
225
|
-
name: "created_at",
|
|
226
|
-
type: "datetime",
|
|
227
|
-
nullable: false,
|
|
228
|
-
default: "CURRENT_TIMESTAMP"
|
|
229
|
-
}
|
|
230
|
-
],
|
|
231
|
-
indexes: [
|
|
232
|
-
{
|
|
233
|
-
name: "idx_username",
|
|
234
|
-
columns: ["username"],
|
|
235
|
-
unique: true
|
|
236
|
-
}
|
|
237
|
-
]
|
|
238
|
-
},
|
|
239
|
-
posts: {
|
|
240
|
-
description: "User posts",
|
|
241
|
-
cols: [
|
|
242
|
-
{ name: "id", type: "integer", primary_key: true, auto_increment: true },
|
|
243
|
-
{ name: "user_id", type: "integer", nullable: false },
|
|
244
|
-
{ name: "title", type: "varchar", length: 200 },
|
|
245
|
-
{ name: "content", type: "text" },
|
|
246
|
-
{ name: "created_at", type: "datetime", default: "CURRENT_TIMESTAMP" }
|
|
247
|
-
],
|
|
248
|
-
foreign_keys: [
|
|
249
|
-
{
|
|
250
|
-
name: "fk_post_user",
|
|
251
|
-
column: "user_id",
|
|
252
|
-
references: { table: "users", column: "id" },
|
|
253
|
-
on_delete: "CASCADE"
|
|
254
|
-
}
|
|
255
|
-
]
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
};
|
|
259
|
-
```
|
|
278
|
+
import { ServiceManager } from "@dqcai/sqlite";
|
|
279
|
+
import { UserService } from "./services/UserService";
|
|
280
|
+
import { StoreService } from "./services/StoreService";
|
|
260
281
|
|
|
261
|
-
|
|
282
|
+
const serviceManager = ServiceManager.getInstance();
|
|
262
283
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
284
|
+
// Đăng ký service với custom class
|
|
285
|
+
serviceManager.registerService({
|
|
286
|
+
schemaName: "core",
|
|
287
|
+
tableName: "users",
|
|
288
|
+
primaryKeyFields: ["id"],
|
|
289
|
+
serviceClass: UserService,
|
|
269
290
|
});
|
|
270
291
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
292
|
+
serviceManager.registerService({
|
|
293
|
+
schemaName: "core",
|
|
294
|
+
tableName: "stores",
|
|
295
|
+
serviceClass: StoreService,
|
|
275
296
|
});
|
|
297
|
+
|
|
298
|
+
// Đăng ký nhiều services cùng lúc
|
|
299
|
+
serviceManager.registerServices([
|
|
300
|
+
{
|
|
301
|
+
schemaName: "core",
|
|
302
|
+
tableName: "enterprises",
|
|
303
|
+
primaryKeyFields: ["id"],
|
|
304
|
+
},
|
|
305
|
+
{
|
|
306
|
+
schemaName: "core",
|
|
307
|
+
tableName: "settings",
|
|
308
|
+
primaryKeyFields: ["id"],
|
|
309
|
+
},
|
|
310
|
+
]);
|
|
276
311
|
```
|
|
277
312
|
|
|
278
|
-
###
|
|
313
|
+
### Lấy và sử dụng Service
|
|
314
|
+
|
|
279
315
|
```typescript
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
316
|
+
// Lấy service - tự động khởi tạo nếu chưa tồn tại
|
|
317
|
+
const userService = (await serviceManager.getService(
|
|
318
|
+
"core",
|
|
319
|
+
"users"
|
|
320
|
+
)) as UserService;
|
|
321
|
+
|
|
322
|
+
// Khởi tạo service ngay lập tức
|
|
323
|
+
const storeService = await serviceManager.initializeService("core", "stores");
|
|
324
|
+
|
|
325
|
+
// Lấy service đã tồn tại (không tự động tạo)
|
|
326
|
+
const existingService = serviceManager.getExistingService("core", "users");
|
|
286
327
|
```
|
|
287
328
|
|
|
288
|
-
###
|
|
329
|
+
### Quản lý lifecycle
|
|
330
|
+
|
|
289
331
|
```typescript
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
332
|
+
// Kiểm tra sức khỏe tất cả services
|
|
333
|
+
const healthReport = await serviceManager.healthCheck();
|
|
334
|
+
console.log("Overall health:", healthReport.overallHealth);
|
|
335
|
+
console.log("Healthy services:", healthReport.healthyServices);
|
|
294
336
|
|
|
295
|
-
|
|
337
|
+
// Lấy thông tin services
|
|
338
|
+
const allServices = serviceManager.getAllServiceInfo();
|
|
339
|
+
console.log("Total services:", allServices.length);
|
|
340
|
+
|
|
341
|
+
// Destroy service
|
|
342
|
+
await serviceManager.destroyService("core", "users");
|
|
343
|
+
|
|
344
|
+
// Destroy tất cả services trong một schema
|
|
345
|
+
await serviceManager.destroyServicesBySchema("core");
|
|
296
346
|
```
|
|
297
347
|
|
|
298
|
-
|
|
348
|
+
## 6. Thực thi CRUD và Logic nghiệp vụ
|
|
349
|
+
|
|
350
|
+
### CRUD cơ bản
|
|
351
|
+
|
|
299
352
|
```typescript
|
|
300
|
-
|
|
353
|
+
// Create
|
|
354
|
+
const newUser = await userService.create({
|
|
355
|
+
id: crypto.randomUUID(),
|
|
356
|
+
username: "john_doe",
|
|
357
|
+
email: "john@example.com",
|
|
358
|
+
full_name: "John Doe",
|
|
359
|
+
store_id: storeId,
|
|
360
|
+
role: "staff",
|
|
361
|
+
});
|
|
301
362
|
|
|
302
|
-
|
|
303
|
-
|
|
363
|
+
// Read
|
|
364
|
+
const user = await userService.findById(userId);
|
|
365
|
+
const allUsers = await userService.findAll();
|
|
366
|
+
const activeUsers = await userService.findAll({ is_active: true });
|
|
304
367
|
|
|
305
|
-
//
|
|
306
|
-
|
|
307
|
-
|
|
368
|
+
// Update
|
|
369
|
+
await userService.update(userId, {
|
|
370
|
+
email: "newemail@example.com",
|
|
371
|
+
updated_at: new Date().toISOString(),
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
// Delete
|
|
375
|
+
await userService.delete(userId);
|
|
376
|
+
|
|
377
|
+
// Count
|
|
378
|
+
const userCount = await userService.count({ is_active: true });
|
|
379
|
+
|
|
380
|
+
// Exists
|
|
381
|
+
const exists = await userService.exists(userId);
|
|
308
382
|
```
|
|
309
383
|
|
|
310
|
-
###
|
|
384
|
+
### Query nâng cao
|
|
385
|
+
|
|
311
386
|
```typescript
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
.setEnabled(true) // Turn on logger for all
|
|
323
|
-
.setDefaultLevel('trace') // Set level default is 'trace'
|
|
324
|
-
// Config custom logger for each module
|
|
325
|
-
.addModule(SQLiteModules.UNIVERSAL_SQLITE, true, ['info', 'warn', 'error'], ['console'])
|
|
326
|
-
.addModule(SQLiteModules.UNIVERSAL_DAO, true, ['debug', 'info', 'warn', 'error'], ['console'])
|
|
327
|
-
.build();
|
|
328
|
-
|
|
329
|
-
// Use this logger config for another module in your code
|
|
330
|
-
|
|
331
|
-
// Update configuration for logger
|
|
332
|
-
SQLiteLoggerConfig.updateConfiguration(customConfig);
|
|
387
|
+
// Tìm kiếm với options
|
|
388
|
+
const users = await userService.findAll(
|
|
389
|
+
{ role: "staff", is_active: true },
|
|
390
|
+
{
|
|
391
|
+
orderBy: [{ name: "created_at", direction: "DESC" }],
|
|
392
|
+
limit: 10,
|
|
393
|
+
offset: 0,
|
|
394
|
+
columns: ["id", "username", "email", "full_name"],
|
|
395
|
+
}
|
|
396
|
+
);
|
|
333
397
|
|
|
398
|
+
// Pagination
|
|
399
|
+
const page = 1;
|
|
400
|
+
const perPage = 20;
|
|
401
|
+
const offset = (page - 1) * perPage;
|
|
402
|
+
|
|
403
|
+
const paginatedUsers = await userService.findAll(
|
|
404
|
+
{},
|
|
405
|
+
{ limit: perPage, offset }
|
|
406
|
+
);
|
|
334
407
|
```
|
|
335
408
|
|
|
336
|
-
|
|
409
|
+
### Bulk operations
|
|
337
410
|
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
411
|
+
```typescript
|
|
412
|
+
// Bulk insert
|
|
413
|
+
const users = [
|
|
414
|
+
{
|
|
415
|
+
id: uuid(),
|
|
416
|
+
username: "user1",
|
|
417
|
+
email: "user1@example.com",
|
|
418
|
+
store_id: storeId,
|
|
419
|
+
},
|
|
420
|
+
{
|
|
421
|
+
id: uuid(),
|
|
422
|
+
username: "user2",
|
|
423
|
+
email: "user2@example.com",
|
|
424
|
+
store_id: storeId,
|
|
425
|
+
},
|
|
426
|
+
];
|
|
344
427
|
|
|
345
|
-
|
|
428
|
+
const importResult = await userService.bulkInsert(users);
|
|
429
|
+
console.log(`Imported ${importResult.successRows} users`);
|
|
346
430
|
|
|
347
|
-
|
|
431
|
+
// Bulk create with transaction
|
|
432
|
+
const createdUsers = await userService.bulkCreate(users);
|
|
433
|
+
```
|
|
348
434
|
|
|
349
|
-
|
|
435
|
+
### Transaction
|
|
350
436
|
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
437
|
+
```typescript
|
|
438
|
+
// Single service transaction
|
|
439
|
+
await userService.executeTransaction(async () => {
|
|
440
|
+
await userService.create(user1);
|
|
441
|
+
await userService.create(user2);
|
|
442
|
+
await userService.update(userId, { status: "active" });
|
|
443
|
+
});
|
|
355
444
|
|
|
356
|
-
|
|
445
|
+
// Cross-service transaction (same schema)
|
|
446
|
+
await serviceManager.executeSchemaTransaction("core", async (services) => {
|
|
447
|
+
const [userSvc, storeSvc] = services;
|
|
357
448
|
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
449
|
+
const store = await storeSvc.create(storeData);
|
|
450
|
+
await userSvc.create({
|
|
451
|
+
...userData,
|
|
452
|
+
store_id: store.id,
|
|
453
|
+
});
|
|
454
|
+
});
|
|
455
|
+
```
|
|
363
456
|
|
|
364
|
-
|
|
457
|
+
### Import/Export
|
|
365
458
|
|
|
366
459
|
```typescript
|
|
367
|
-
//
|
|
368
|
-
const
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
460
|
+
// Import from CSV
|
|
461
|
+
const csvData = `username,email,role
|
|
462
|
+
john,john@example.com,staff
|
|
463
|
+
jane,jane@example.com,manager`;
|
|
464
|
+
|
|
465
|
+
const result = await userService.importFromCSV(csvData, {
|
|
466
|
+
hasHeader: true,
|
|
467
|
+
delimiter: ",",
|
|
468
|
+
skipErrors: false,
|
|
469
|
+
});
|
|
470
|
+
|
|
471
|
+
// Import with column mapping
|
|
472
|
+
const columnMappings = [
|
|
473
|
+
{ sourceColumn: "user_name", targetColumn: "username" },
|
|
474
|
+
{ sourceColumn: "mail", targetColumn: "email" },
|
|
475
|
+
{
|
|
476
|
+
sourceColumn: "created",
|
|
477
|
+
targetColumn: "created_at",
|
|
478
|
+
transform: (value) => new Date(value).toISOString(),
|
|
374
479
|
},
|
|
375
|
-
|
|
376
|
-
async down(dao) {
|
|
377
|
-
// Rollback logic
|
|
378
|
-
}
|
|
379
|
-
};
|
|
480
|
+
];
|
|
380
481
|
|
|
381
|
-
|
|
382
|
-
await migrationManager.runMigration(migration);
|
|
482
|
+
await userService.importDataWithMapping(data, columnMappings);
|
|
383
483
|
```
|
|
384
484
|
|
|
385
|
-
##
|
|
485
|
+
## 7. Ví dụ hoàn chỉnh với Core Schema
|
|
386
486
|
|
|
387
487
|
```typescript
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
488
|
+
import {
|
|
489
|
+
DatabaseFactory,
|
|
490
|
+
DatabaseManager,
|
|
491
|
+
ServiceManager,
|
|
492
|
+
BaseService,
|
|
493
|
+
} from "@dqcai/sqlite";
|
|
494
|
+
import { NodeJSAdapter } from "@dqcai/sqlite";
|
|
495
|
+
import { coreSchema } from "./schemas/core";
|
|
496
|
+
|
|
497
|
+
// ========== BƯỚC 1: Setup Adapters ==========
|
|
498
|
+
DatabaseFactory.registerAdapter(new NodeJSAdapter());
|
|
499
|
+
|
|
500
|
+
// ========== BƯỚC 2: Đăng ký Schemas ==========
|
|
501
|
+
DatabaseManager.registerSchema("core", coreSchema);
|
|
502
|
+
|
|
503
|
+
// ========== BƯỚC 3: Định nghĩa Services ==========
|
|
504
|
+
class UserService extends BaseService {
|
|
505
|
+
constructor() {
|
|
506
|
+
super("core", "users");
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
async findByStoreId(storeId: string) {
|
|
510
|
+
return await this.findAll({ store_id: storeId });
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
async authenticate(username: string, password: string) {
|
|
514
|
+
const user = await this.findFirst({ username });
|
|
515
|
+
if (!user) return null;
|
|
516
|
+
|
|
517
|
+
// Verify password (simplified)
|
|
518
|
+
if (user.password_hash === password) {
|
|
519
|
+
await this.update(user.id, {
|
|
520
|
+
last_login: new Date().toISOString(),
|
|
521
|
+
failed_login_attempts: 0,
|
|
522
|
+
});
|
|
523
|
+
return user;
|
|
524
|
+
}
|
|
391
525
|
|
|
392
|
-
|
|
393
|
-
|
|
526
|
+
// Increment failed attempts
|
|
527
|
+
await this.update(user.id, {
|
|
528
|
+
failed_login_attempts: (user.failed_login_attempts || 0) + 1,
|
|
529
|
+
});
|
|
530
|
+
|
|
531
|
+
return null;
|
|
532
|
+
}
|
|
533
|
+
}
|
|
394
534
|
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
535
|
+
class StoreService extends BaseService {
|
|
536
|
+
constructor() {
|
|
537
|
+
super("core", "stores");
|
|
538
|
+
}
|
|
398
539
|
|
|
399
|
-
|
|
400
|
-
await
|
|
401
|
-
|
|
402
|
-
const allUsers = await userService.getAllUsers();
|
|
403
|
-
setUsers(allUsers);
|
|
404
|
-
};
|
|
540
|
+
async findByEnterpriseId(enterpriseId: string) {
|
|
541
|
+
return await this.findAll({ enterprise_id: enterpriseId });
|
|
542
|
+
}
|
|
405
543
|
|
|
406
|
-
|
|
544
|
+
async getActiveStores(enterpriseId: string) {
|
|
545
|
+
return await this.findAll(
|
|
546
|
+
{ enterprise_id: enterpriseId, status: "active" },
|
|
547
|
+
{ orderBy: [{ name: "name", direction: "ASC" }] }
|
|
548
|
+
);
|
|
549
|
+
}
|
|
407
550
|
}
|
|
408
|
-
```
|
|
409
551
|
|
|
410
|
-
|
|
552
|
+
// ========== BƯỚC 4: Đăng ký Services ==========
|
|
553
|
+
const serviceManager = ServiceManager.getInstance();
|
|
411
554
|
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
555
|
+
serviceManager.registerServices([
|
|
556
|
+
{
|
|
557
|
+
schemaName: "core",
|
|
558
|
+
tableName: "enterprises",
|
|
559
|
+
},
|
|
560
|
+
{
|
|
561
|
+
schemaName: "core",
|
|
562
|
+
tableName: "stores",
|
|
563
|
+
serviceClass: StoreService,
|
|
564
|
+
},
|
|
565
|
+
{
|
|
566
|
+
schemaName: "core",
|
|
567
|
+
tableName: "users",
|
|
568
|
+
serviceClass: UserService,
|
|
569
|
+
},
|
|
570
|
+
]);
|
|
571
|
+
|
|
572
|
+
// ========== BƯỚC 5: Khởi tạo và sử dụng ==========
|
|
573
|
+
async function main() {
|
|
574
|
+
try {
|
|
575
|
+
// Khởi tạo core database
|
|
576
|
+
await DatabaseManager.initializeCoreConnection();
|
|
577
|
+
|
|
578
|
+
// Lấy services
|
|
579
|
+
const enterpriseService = await serviceManager.getService(
|
|
580
|
+
"core",
|
|
581
|
+
"enterprises"
|
|
582
|
+
);
|
|
583
|
+
const storeService = (await serviceManager.getService(
|
|
584
|
+
"core",
|
|
585
|
+
"stores"
|
|
586
|
+
)) as StoreService;
|
|
587
|
+
const userService = (await serviceManager.getService(
|
|
588
|
+
"core",
|
|
589
|
+
"users"
|
|
590
|
+
)) as UserService;
|
|
591
|
+
|
|
592
|
+
// ========== TEST CRUD Operations ==========
|
|
593
|
+
|
|
594
|
+
// 1. Create Enterprise
|
|
595
|
+
const enterprise = await enterpriseService.create({
|
|
596
|
+
id: crypto.randomUUID(),
|
|
597
|
+
name: "My Company",
|
|
598
|
+
business_type: "ltd",
|
|
599
|
+
email: "contact@mycompany.com",
|
|
600
|
+
status: "active",
|
|
601
|
+
subscription_plan: "premium",
|
|
602
|
+
});
|
|
603
|
+
console.log("✅ Enterprise created:", enterprise?.name);
|
|
604
|
+
|
|
605
|
+
// 2. Create Store
|
|
606
|
+
const store = await storeService.create({
|
|
607
|
+
id: crypto.randomUUID(),
|
|
608
|
+
enterprise_id: enterprise!.id,
|
|
609
|
+
name: "Main Store",
|
|
610
|
+
store_type: "retail",
|
|
611
|
+
address: "123 Main St",
|
|
612
|
+
status: "active",
|
|
613
|
+
});
|
|
614
|
+
console.log("✅ Store created:", store?.name);
|
|
615
|
+
|
|
616
|
+
// 3. Create Users
|
|
617
|
+
const users = [
|
|
618
|
+
{
|
|
619
|
+
id: crypto.randomUUID(),
|
|
620
|
+
store_id: store!.id,
|
|
621
|
+
username: "admin",
|
|
622
|
+
password_hash: "hashed_password",
|
|
623
|
+
full_name: "Admin User",
|
|
624
|
+
email: "admin@mycompany.com",
|
|
625
|
+
role: "admin",
|
|
626
|
+
is_active: true,
|
|
627
|
+
},
|
|
628
|
+
{
|
|
629
|
+
id: crypto.randomUUID(),
|
|
630
|
+
store_id: store!.id,
|
|
631
|
+
username: "staff1",
|
|
632
|
+
password_hash: "hashed_password",
|
|
633
|
+
full_name: "Staff One",
|
|
634
|
+
email: "staff1@mycompany.com",
|
|
635
|
+
role: "staff",
|
|
636
|
+
is_active: true,
|
|
637
|
+
},
|
|
638
|
+
];
|
|
639
|
+
|
|
640
|
+
const importResult = await userService.bulkInsert(users);
|
|
641
|
+
console.log(`✅ Users imported: ${importResult.successRows} successful`);
|
|
642
|
+
|
|
643
|
+
// 4. Query data
|
|
644
|
+
const allUsers = await userService.findByStoreId(store!.id);
|
|
645
|
+
console.log(`✅ Users in store: ${allUsers.length}`);
|
|
646
|
+
|
|
647
|
+
const activeStores = await storeService.getActiveStores(enterprise!.id);
|
|
648
|
+
console.log(`✅ Active stores: ${activeStores.length}`);
|
|
649
|
+
|
|
650
|
+
// 5. Update
|
|
651
|
+
await userService.update(users[0].id, {
|
|
652
|
+
last_login: new Date().toISOString(),
|
|
653
|
+
});
|
|
654
|
+
console.log("✅ User login updated");
|
|
655
|
+
|
|
656
|
+
// 6. Transaction example
|
|
657
|
+
await serviceManager.executeSchemaTransaction("core", async (services) => {
|
|
658
|
+
const [entSvc, storeSvc, userSvc] = services;
|
|
659
|
+
|
|
660
|
+
// Create another store and user in transaction
|
|
661
|
+
const newStore = await storeSvc.create({
|
|
662
|
+
id: crypto.randomUUID(),
|
|
663
|
+
enterprise_id: enterprise!.id,
|
|
664
|
+
name: "Branch Store",
|
|
665
|
+
status: "active",
|
|
666
|
+
});
|
|
667
|
+
|
|
668
|
+
await userSvc.create({
|
|
669
|
+
id: crypto.randomUUID(),
|
|
670
|
+
store_id: newStore.id,
|
|
671
|
+
username: "branch_manager",
|
|
672
|
+
password_hash: "hashed_password",
|
|
673
|
+
full_name: "Branch Manager",
|
|
674
|
+
email: "manager@branch.com",
|
|
675
|
+
role: "manager",
|
|
676
|
+
is_active: true,
|
|
677
|
+
});
|
|
678
|
+
});
|
|
679
|
+
console.log("✅ Transaction completed");
|
|
680
|
+
|
|
681
|
+
// 7. Health check
|
|
682
|
+
const health = await serviceManager.healthCheck();
|
|
683
|
+
console.log("✅ System health:", health.overallHealth);
|
|
684
|
+
console.log(
|
|
685
|
+
` Healthy services: ${health.healthyServices}/${health.totalServices}`
|
|
686
|
+
);
|
|
687
|
+
|
|
688
|
+
// 8. Statistics
|
|
689
|
+
const enterpriseCount = await enterpriseService.count();
|
|
690
|
+
const storeCount = await storeService.count();
|
|
691
|
+
const userCount = await userService.count();
|
|
692
|
+
|
|
693
|
+
console.log("\n📊 Statistics:");
|
|
694
|
+
console.log(` Enterprises: ${enterpriseCount}`);
|
|
695
|
+
console.log(` Stores: ${storeCount}`);
|
|
696
|
+
console.log(` Users: ${userCount}`);
|
|
697
|
+
} catch (error) {
|
|
698
|
+
console.error("❌ Error:", error);
|
|
699
|
+
} finally {
|
|
700
|
+
// Cleanup
|
|
701
|
+
await DatabaseManager.closeAll();
|
|
702
|
+
console.log("\n✅ Database connections closed");
|
|
703
|
+
}
|
|
704
|
+
}
|
|
416
705
|
|
|
417
|
-
|
|
706
|
+
// Run test
|
|
707
|
+
main().catch(console.error);
|
|
708
|
+
```
|
|
418
709
|
|
|
419
|
-
|
|
420
|
-
const userService = await ServiceManager.getService('users', 'users');
|
|
421
|
-
const users = await userService.getAllUsers();
|
|
422
|
-
res.json(users);
|
|
423
|
-
});
|
|
710
|
+
### Kết quả mong đợi:
|
|
424
711
|
|
|
425
|
-
// Initialize database before starting server
|
|
426
|
-
await DatabaseService.initialize();
|
|
427
|
-
app.listen(3000);
|
|
428
712
|
```
|
|
713
|
+
✅ Enterprise created: My Company
|
|
714
|
+
✅ Store created: Main Store
|
|
715
|
+
✅ Users imported: 2 successful
|
|
716
|
+
✅ Users in store: 2
|
|
717
|
+
✅ Active stores: 1
|
|
718
|
+
✅ User login updated
|
|
719
|
+
✅ Transaction completed
|
|
720
|
+
✅ System health: true
|
|
721
|
+
Healthy services: 3/3
|
|
722
|
+
|
|
723
|
+
📊 Statistics:
|
|
724
|
+
Enterprises: 1
|
|
725
|
+
Stores: 2
|
|
726
|
+
Users: 3
|
|
727
|
+
|
|
728
|
+
✅ Database connections closed
|
|
729
|
+
```
|
|
730
|
+
|
|
731
|
+
## Tổng kết
|
|
732
|
+
|
|
733
|
+
Thư viện @dqcai/sqlite cung cấp:
|
|
734
|
+
|
|
735
|
+
- ✅ **Cross-platform**: Hỗ trợ React Native và Node.js
|
|
736
|
+
- ✅ **Type-safe**: TypeScript support đầy đủ
|
|
737
|
+
- ✅ **Schema-driven**: Quản lý database qua JSON schema
|
|
738
|
+
- ✅ **Service-based**: Architecture rõ ràng, dễ mở rộng
|
|
739
|
+
- ✅ **Lazy loading**: Tối ưu performance trên mobile
|
|
740
|
+
- ✅ **Transaction support**: ACID compliance
|
|
741
|
+
- ✅ **Event system**: Lắng nghe và xử lý events
|
|
742
|
+
- ✅ **Import/Export**: CSV, JSON, bulk operations
|
|
743
|
+
- ✅ **Logging**: Tích hợp @dqcai/logger để trace/debug
|
|
429
744
|
|
|
430
745
|
## 🤝 Community & Support
|
|
431
746
|
|
|
432
747
|
- **GitHub**: [https://github.com/cuongdqpayment/dqcai-sqlite](https://github.com/cuongdqpayment/dqcai-sqlite)
|
|
433
748
|
- **NPM**: [https://www.npmjs.com/package/@dqcai/sqlite](https://www.npmjs.com/package/@dqcai/sqlite)
|
|
749
|
+
- **Logger Package**: [https://www.npmjs.com/package/@dqcai/logger](https://www.npmjs.com/package/@dqcai/logger)
|
|
434
750
|
- **Issues**: [GitHub Issues](https://github.com/cuongdqpayment/dqcai-sqlite/issues)
|
|
435
751
|
- **Facebook**: [Facebook Page](https://www.facebook.com/share/p/19esHGbaGj/)
|
|
436
752
|
|
|
@@ -441,11 +757,11 @@ MIT License - see [LICENSE](https://github.com/cuongdqpayment/dqcai-sqlite/blob/
|
|
|
441
757
|
## 🚀 Get Started Now
|
|
442
758
|
|
|
443
759
|
```bash
|
|
444
|
-
npm install @dqcai/sqlite
|
|
760
|
+
npm install @dqcai/sqlite @dqcai/logger
|
|
445
761
|
```
|
|
446
762
|
|
|
447
763
|
Transform your data management with the most powerful universal SQLite library for JavaScript and TypeScript!
|
|
448
764
|
|
|
449
765
|
---
|
|
450
766
|
|
|
451
|
-
**@dqcai/sqlite** - One library, all platforms! 🌟
|
|
767
|
+
**@dqcai/sqlite** - One library, all platforms! 🌟
|