@ooneex/database 0.0.1 → 0.0.5
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 +309 -399
- package/dist/index.d.ts +34 -25
- package/dist/index.js +2 -2
- package/dist/index.js.map +8 -6
- package/package.json +15 -7
- package/dist/ooneex-database-0.0.1.tgz +0 -0
package/README.md
CHANGED
|
@@ -1,30 +1,28 @@
|
|
|
1
1
|
# @ooneex/database
|
|
2
2
|
|
|
3
|
-
A
|
|
3
|
+
A database connection and management library for TypeScript applications with TypeORM integration. This package provides unified interfaces for Redis, PostgreSQL, and SQLite databases with automatic connection handling, repository management, and seamless integration with the Ooneex framework.
|
|
4
4
|
|
|
5
5
|

|
|
6
|
+

|
|
7
|
+

|
|
6
8
|

|
|
7
9
|

|
|
8
10
|
|
|
9
11
|
## Features
|
|
10
12
|
|
|
11
|
-
✅ **
|
|
13
|
+
✅ **Multiple Databases** - Support for PostgreSQL, SQLite, and Redis
|
|
12
14
|
|
|
13
|
-
✅ **
|
|
15
|
+
✅ **TypeORM Integration** - Full TypeORM support for relational databases
|
|
14
16
|
|
|
15
|
-
✅ **
|
|
17
|
+
✅ **Repository Pattern** - Easy access to TypeORM repositories
|
|
16
18
|
|
|
17
|
-
✅ **
|
|
18
|
-
|
|
19
|
-
✅ **Connection Management** - Robust connection opening, closing, and lifecycle management
|
|
20
|
-
|
|
21
|
-
✅ **Database Operations** - Create, drop, and manage database instances
|
|
19
|
+
✅ **Connection Management** - Automatic connection handling and reconnection
|
|
22
20
|
|
|
23
|
-
✅ **
|
|
21
|
+
✅ **Container Integration** - Works seamlessly with dependency injection
|
|
24
22
|
|
|
25
|
-
✅ **
|
|
23
|
+
✅ **Type-Safe** - Full TypeScript support with proper type definitions
|
|
26
24
|
|
|
27
|
-
✅ **
|
|
25
|
+
✅ **Decorators** - Register database services with decorators
|
|
28
26
|
|
|
29
27
|
## Installation
|
|
30
28
|
|
|
@@ -33,289 +31,227 @@ A comprehensive TypeScript/JavaScript database library designed for Bun runtime.
|
|
|
33
31
|
bun add @ooneex/database
|
|
34
32
|
```
|
|
35
33
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
34
|
+
### pnpm
|
|
35
|
+
```bash
|
|
36
|
+
pnpm add @ooneex/database
|
|
37
|
+
```
|
|
39
38
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
39
|
+
### Yarn
|
|
40
|
+
```bash
|
|
41
|
+
yarn add @ooneex/database
|
|
42
|
+
```
|
|
43
43
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
44
|
+
### npm
|
|
45
|
+
```bash
|
|
46
|
+
npm install @ooneex/database
|
|
47
|
+
```
|
|
48
48
|
|
|
49
|
-
|
|
50
|
-
name: string;
|
|
49
|
+
## Usage
|
|
51
50
|
|
|
52
|
-
|
|
53
|
-
email: string;
|
|
54
|
-
}
|
|
51
|
+
### PostgreSQL with TypeORM
|
|
55
52
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
53
|
+
```typescript
|
|
54
|
+
import { TypeormPgDatabase } from '@ooneex/database';
|
|
55
|
+
import { UserEntity } from './entities/UserEntity';
|
|
56
|
+
|
|
57
|
+
const database = new TypeormPgDatabase({
|
|
58
|
+
host: 'localhost',
|
|
59
|
+
port: 5432,
|
|
60
|
+
username: 'postgres',
|
|
61
|
+
password: 'password',
|
|
62
|
+
database: 'myapp'
|
|
60
63
|
});
|
|
61
64
|
|
|
62
|
-
//
|
|
63
|
-
const userRepository = await
|
|
65
|
+
// Get repository for an entity
|
|
66
|
+
const userRepository = await database.open(UserEntity);
|
|
64
67
|
|
|
65
|
-
//
|
|
66
|
-
const user = userRepository.create({
|
|
67
|
-
name: 'John Doe',
|
|
68
|
-
email: 'john@example.com'
|
|
69
|
-
});
|
|
70
|
-
await userRepository.save(user);
|
|
71
|
-
|
|
72
|
-
// Find users
|
|
68
|
+
// Use TypeORM repository methods
|
|
73
69
|
const users = await userRepository.find();
|
|
70
|
+
const user = await userRepository.findOneBy({ id: '123' });
|
|
74
71
|
|
|
75
|
-
// Close connection
|
|
76
|
-
await
|
|
72
|
+
// Close connection when done
|
|
73
|
+
await database.close();
|
|
77
74
|
```
|
|
78
75
|
|
|
79
|
-
###
|
|
76
|
+
### SQLite with TypeORM
|
|
80
77
|
|
|
81
78
|
```typescript
|
|
82
|
-
import {
|
|
83
|
-
import {
|
|
79
|
+
import { TypeormSqliteDatabase } from '@ooneex/database';
|
|
80
|
+
import { ProductEntity } from './entities/ProductEntity';
|
|
84
81
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
id: number;
|
|
82
|
+
const database = new TypeormSqliteDatabase({
|
|
83
|
+
database: './data/app.db'
|
|
84
|
+
});
|
|
89
85
|
|
|
90
|
-
|
|
91
|
-
|
|
86
|
+
// Get repository
|
|
87
|
+
const productRepository = await database.open(ProductEntity);
|
|
92
88
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
const adapter = new TypeormSqliteDatabaseAdapter({
|
|
98
|
-
database: './products.db',
|
|
99
|
-
synchronize: true,
|
|
100
|
-
entities: [Product]
|
|
89
|
+
// Query products
|
|
90
|
+
const products = await productRepository.find({
|
|
91
|
+
where: { category: 'electronics' },
|
|
92
|
+
take: 10
|
|
101
93
|
});
|
|
102
94
|
|
|
103
|
-
|
|
104
|
-
|
|
95
|
+
await database.close();
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Redis Database
|
|
99
|
+
|
|
100
|
+
```typescript
|
|
101
|
+
import { RedisDatabase } from '@ooneex/database';
|
|
105
102
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
name: 'Laptop',
|
|
109
|
-
price: 999.99
|
|
103
|
+
const redis = new RedisDatabase({
|
|
104
|
+
url: 'redis://localhost:6379'
|
|
110
105
|
});
|
|
111
|
-
|
|
106
|
+
|
|
107
|
+
// Open connection and get client
|
|
108
|
+
const client = await redis.open();
|
|
109
|
+
|
|
110
|
+
// Use Redis commands
|
|
111
|
+
await client.set('key', 'value');
|
|
112
|
+
const value = await client.get('key');
|
|
112
113
|
|
|
113
114
|
// Close connection
|
|
114
|
-
await
|
|
115
|
+
await redis.close();
|
|
115
116
|
```
|
|
116
117
|
|
|
117
|
-
###
|
|
118
|
+
### Using Environment Variables
|
|
118
119
|
|
|
119
120
|
```typescript
|
|
120
|
-
import {
|
|
121
|
-
|
|
122
|
-
try {
|
|
123
|
-
const db = new Database('invalid://connection');
|
|
124
|
-
await db.open();
|
|
125
|
-
} catch (error) {
|
|
126
|
-
if (error instanceof DatabaseException) {
|
|
127
|
-
console.error('Database error:', error.message);
|
|
128
|
-
console.error('Error data:', error.data);
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
```
|
|
121
|
+
import { TypeormPgDatabase } from '@ooneex/database';
|
|
132
122
|
|
|
133
|
-
|
|
123
|
+
// Automatically uses environment variables
|
|
124
|
+
const database = new TypeormPgDatabase();
|
|
134
125
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
DATABASE_URL=mysql://user:password@localhost:3306/mydb
|
|
142
|
-
|
|
143
|
-
# For SQLite adapter
|
|
144
|
-
SQLITE_DATABASE_PATH=./myapp.db
|
|
145
|
-
|
|
146
|
-
# For Redis adapter
|
|
147
|
-
REDIS_URL=redis://localhost:6379
|
|
148
|
-
# or
|
|
149
|
-
VALKEY_URL=redis://localhost:6379
|
|
126
|
+
// Environment variables:
|
|
127
|
+
// DATABASE_HOST
|
|
128
|
+
// DATABASE_PORT
|
|
129
|
+
// DATABASE_USERNAME
|
|
130
|
+
// DATABASE_PASSWORD
|
|
131
|
+
// DATABASE_NAME
|
|
150
132
|
```
|
|
151
133
|
|
|
152
134
|
## API Reference
|
|
153
135
|
|
|
154
|
-
###
|
|
136
|
+
### Classes
|
|
155
137
|
|
|
156
|
-
|
|
138
|
+
#### `TypeormPgDatabase`
|
|
157
139
|
|
|
158
|
-
|
|
140
|
+
PostgreSQL database adapter using TypeORM.
|
|
159
141
|
|
|
142
|
+
**Constructor:**
|
|
160
143
|
```typescript
|
|
161
|
-
|
|
144
|
+
new TypeormPgDatabase(options?: PostgresConnectionOptions)
|
|
162
145
|
```
|
|
163
146
|
|
|
164
147
|
**Parameters:**
|
|
165
|
-
- `
|
|
166
|
-
- `options` -
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
148
|
+
- `options.host` - Database host (default: `DATABASE_HOST` env var)
|
|
149
|
+
- `options.port` - Database port (default: `DATABASE_PORT` env var)
|
|
150
|
+
- `options.username` - Database username (default: `DATABASE_USERNAME` env var)
|
|
151
|
+
- `options.password` - Database password (default: `DATABASE_PASSWORD` env var)
|
|
152
|
+
- `options.database` - Database name (default: `DATABASE_NAME` env var)
|
|
153
|
+
- `options.synchronize` - Auto-sync schema (default: false)
|
|
154
|
+
- `options.logging` - Enable query logging (default: false)
|
|
172
155
|
|
|
173
|
-
|
|
156
|
+
**Methods:**
|
|
174
157
|
|
|
175
|
-
##### `
|
|
176
|
-
Returns the underlying Bun.SQL client instance.
|
|
158
|
+
##### `open<Entity>(entity: EntityTarget<Entity>, database?: string): Promise<Repository<Entity>>`
|
|
177
159
|
|
|
178
|
-
|
|
160
|
+
Opens connection and returns a TypeORM repository for the specified entity.
|
|
179
161
|
|
|
180
|
-
**
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
const result = await client`SELECT * FROM users`;
|
|
184
|
-
```
|
|
162
|
+
**Parameters:**
|
|
163
|
+
- `entity` - TypeORM entity class
|
|
164
|
+
- `database` - Optional database name override
|
|
185
165
|
|
|
186
|
-
|
|
187
|
-
Opens the database connection.
|
|
166
|
+
**Returns:** TypeORM Repository instance
|
|
188
167
|
|
|
189
168
|
**Example:**
|
|
190
169
|
```typescript
|
|
191
|
-
await
|
|
170
|
+
const userRepo = await database.open(UserEntity);
|
|
171
|
+
const users = await userRepo.find();
|
|
192
172
|
```
|
|
193
173
|
|
|
194
174
|
##### `close(): Promise<void>`
|
|
195
|
-
Closes the database connection.
|
|
196
175
|
|
|
197
|
-
|
|
198
|
-
```typescript
|
|
199
|
-
await db.close();
|
|
200
|
-
```
|
|
176
|
+
Closes the database connection.
|
|
201
177
|
|
|
202
178
|
##### `drop(): Promise<void>`
|
|
203
|
-
Drops the database. **Caution: This is destructive and cannot be undone.**
|
|
204
179
|
|
|
205
|
-
|
|
206
|
-
```typescript
|
|
207
|
-
await db.drop(); // Permanently deletes the database
|
|
208
|
-
```
|
|
180
|
+
Drops the database (use with caution!).
|
|
209
181
|
|
|
210
|
-
|
|
182
|
+
---
|
|
211
183
|
|
|
212
|
-
|
|
184
|
+
#### `TypeormSqliteDatabase`
|
|
213
185
|
|
|
214
|
-
|
|
186
|
+
SQLite database adapter using TypeORM.
|
|
215
187
|
|
|
188
|
+
**Constructor:**
|
|
216
189
|
```typescript
|
|
217
|
-
|
|
190
|
+
new TypeormSqliteDatabase(options?: SqliteConnectionOptions)
|
|
218
191
|
```
|
|
219
192
|
|
|
220
193
|
**Parameters:**
|
|
221
|
-
- `options` -
|
|
194
|
+
- `options.database` - Path to SQLite database file
|
|
222
195
|
|
|
223
|
-
|
|
196
|
+
**Methods:**
|
|
224
197
|
|
|
225
|
-
|
|
226
|
-
Returns the TypeORM DataSource instance.
|
|
198
|
+
Same interface as `TypeormPgDatabase`.
|
|
227
199
|
|
|
228
|
-
|
|
229
|
-
Opens connection and returns repository for the specified entity.
|
|
200
|
+
---
|
|
230
201
|
|
|
231
|
-
|
|
232
|
-
Closes the database connection.
|
|
202
|
+
#### `AbstractTypeormSqliteDatabase`
|
|
233
203
|
|
|
234
|
-
|
|
235
|
-
Drops the database schema.
|
|
204
|
+
Abstract base class for creating custom SQLite database adapters.
|
|
236
205
|
|
|
237
|
-
|
|
238
|
-
|
|
206
|
+
**Example:**
|
|
207
|
+
```typescript
|
|
208
|
+
class MyDatabase extends AbstractTypeormSqliteDatabase {
|
|
209
|
+
protected getEntities() {
|
|
210
|
+
return [UserEntity, ProductEntity];
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
```
|
|
239
214
|
|
|
240
|
-
|
|
215
|
+
---
|
|
241
216
|
|
|
242
|
-
|
|
217
|
+
#### `RedisDatabase`
|
|
243
218
|
|
|
244
|
-
|
|
219
|
+
Redis database adapter using Bun's built-in Redis client.
|
|
245
220
|
|
|
221
|
+
**Constructor:**
|
|
246
222
|
```typescript
|
|
247
|
-
|
|
223
|
+
new RedisDatabase(options?: RedisConnectionOptionsType)
|
|
248
224
|
```
|
|
249
225
|
|
|
250
226
|
**Parameters:**
|
|
251
|
-
- `options` -
|
|
227
|
+
- `options.url` - Redis connection URL (default: `REDIS_URL` env var)
|
|
228
|
+
- `options.connectionTimeout` - Connection timeout in ms (default: 10000)
|
|
229
|
+
- `options.idleTimeout` - Idle timeout in ms (default: 30000)
|
|
230
|
+
- `options.autoReconnect` - Enable auto reconnection (default: true)
|
|
231
|
+
- `options.maxRetries` - Maximum retry attempts (default: 3)
|
|
232
|
+
- `options.tls` - TLS configuration (optional)
|
|
252
233
|
|
|
253
|
-
|
|
234
|
+
**Methods:**
|
|
254
235
|
|
|
255
|
-
|
|
236
|
+
##### `open(): Promise<RedisClient>`
|
|
256
237
|
|
|
257
|
-
|
|
238
|
+
Opens connection and returns the Redis client.
|
|
258
239
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
#### Constructor
|
|
240
|
+
**Returns:** Bun RedisClient instance
|
|
262
241
|
|
|
242
|
+
**Example:**
|
|
263
243
|
```typescript
|
|
264
|
-
|
|
244
|
+
const client = await redis.open();
|
|
245
|
+
await client.set('session:123', JSON.stringify(sessionData));
|
|
265
246
|
```
|
|
266
247
|
|
|
267
|
-
**Parameters:**
|
|
268
|
-
- `options` - Redis connection configuration
|
|
269
|
-
|
|
270
|
-
**Options:**
|
|
271
|
-
- `url` - Redis connection URL (defaults to environment variables or localhost)
|
|
272
|
-
- `connectionTimeout` - Connection timeout in milliseconds (default: 10000)
|
|
273
|
-
- `idleTimeout` - Idle timeout in milliseconds (default: 0)
|
|
274
|
-
- `autoReconnect` - Whether to automatically reconnect (default: true)
|
|
275
|
-
- `maxRetries` - Maximum reconnection attempts (default: 10)
|
|
276
|
-
- `enableOfflineQueue` - Queue commands when disconnected (default: true)
|
|
277
|
-
- `enableAutoPipelining` - Automatically pipeline commands (default: true)
|
|
278
|
-
- `tls` - TLS configuration (default: false)
|
|
279
|
-
|
|
280
|
-
#### Methods
|
|
281
|
-
|
|
282
|
-
##### `getClient(): RedisClient`
|
|
283
|
-
Returns the underlying Bun Redis client instance.
|
|
284
|
-
|
|
285
|
-
##### `open(): Promise<void>`
|
|
286
|
-
Opens the Redis connection.
|
|
287
|
-
|
|
288
248
|
##### `close(): Promise<void>`
|
|
249
|
+
|
|
289
250
|
Closes the Redis connection.
|
|
290
251
|
|
|
291
252
|
##### `drop(): Promise<void>`
|
|
292
|
-
Flushes the current Redis database (FLUSHDB).
|
|
293
|
-
|
|
294
|
-
##### `ping(): Promise<string>`
|
|
295
|
-
Pings the Redis server.
|
|
296
|
-
|
|
297
|
-
##### `info(section?: string): Promise<string>`
|
|
298
|
-
Gets Redis server information.
|
|
299
253
|
|
|
300
|
-
|
|
301
|
-
Returns connection status.
|
|
302
|
-
|
|
303
|
-
##### `getBufferedAmount(): number`
|
|
304
|
-
Returns buffered data amount in bytes.
|
|
305
|
-
|
|
306
|
-
### `DatabaseException` Class
|
|
307
|
-
|
|
308
|
-
Custom exception class for database-related errors.
|
|
309
|
-
|
|
310
|
-
#### Constructor
|
|
311
|
-
|
|
312
|
-
```typescript
|
|
313
|
-
constructor(message: string, data?: T)
|
|
314
|
-
```
|
|
315
|
-
|
|
316
|
-
**Parameters:**
|
|
317
|
-
- `message` - Error message
|
|
318
|
-
- `data` - Additional error data
|
|
254
|
+
Flushes all data from Redis (use with caution!).
|
|
319
255
|
|
|
320
256
|
### Interfaces
|
|
321
257
|
|
|
@@ -323,265 +259,240 @@ constructor(message: string, data?: T)
|
|
|
323
259
|
|
|
324
260
|
```typescript
|
|
325
261
|
interface IDatabase {
|
|
326
|
-
open()
|
|
327
|
-
close()
|
|
328
|
-
drop()
|
|
262
|
+
open: () => Promise<void>;
|
|
263
|
+
close: () => Promise<void>;
|
|
264
|
+
drop: () => Promise<void>;
|
|
329
265
|
}
|
|
330
266
|
```
|
|
331
267
|
|
|
332
|
-
#### `
|
|
268
|
+
#### `ITypeormDatabase`
|
|
333
269
|
|
|
334
270
|
```typescript
|
|
335
|
-
interface
|
|
336
|
-
open
|
|
337
|
-
|
|
338
|
-
|
|
271
|
+
interface ITypeormDatabase {
|
|
272
|
+
open: <Entity extends ObjectLiteral>(
|
|
273
|
+
entity: EntityTarget<Entity>,
|
|
274
|
+
database?: string
|
|
275
|
+
) => Promise<Repository<Entity>>;
|
|
276
|
+
close: () => Promise<void>;
|
|
277
|
+
drop: () => Promise<void>;
|
|
339
278
|
}
|
|
340
279
|
```
|
|
341
280
|
|
|
342
|
-
|
|
281
|
+
#### `IRedisDatabase`
|
|
343
282
|
|
|
344
|
-
### SQLite
|
|
345
283
|
```typescript
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
// In-memory database
|
|
352
|
-
'sqlite://:memory:'
|
|
353
|
-
':memory:'
|
|
284
|
+
interface IRedisDatabase {
|
|
285
|
+
open: () => Promise<RedisClient>;
|
|
286
|
+
close: () => Promise<void>;
|
|
287
|
+
drop: () => Promise<void>;
|
|
288
|
+
}
|
|
354
289
|
```
|
|
355
290
|
|
|
356
|
-
###
|
|
357
|
-
```typescript
|
|
358
|
-
'postgresql://user:password@localhost:5432/database'
|
|
359
|
-
'postgres://user:password@localhost:5432/database'
|
|
360
|
-
```
|
|
291
|
+
### Types
|
|
361
292
|
|
|
362
|
-
|
|
363
|
-
```typescript
|
|
364
|
-
'mysql://user:password@localhost:3306/database'
|
|
365
|
-
'mysql2://user:password@localhost:3306/database'
|
|
366
|
-
```
|
|
293
|
+
#### `DatabaseClassType`
|
|
367
294
|
|
|
368
|
-
### Redis
|
|
369
295
|
```typescript
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
// With authentication
|
|
374
|
-
'redis://username:password@localhost:6379'
|
|
375
|
-
|
|
376
|
-
// With database number
|
|
377
|
-
'redis://localhost:6379/0'
|
|
296
|
+
type DatabaseClassType = new (...args: any[]) => IDatabase | IRedisDatabase | ITypeormDatabase;
|
|
297
|
+
```
|
|
378
298
|
|
|
379
|
-
|
|
380
|
-
'rediss://localhost:6379'
|
|
381
|
-
'redis+tls://localhost:6379'
|
|
299
|
+
#### `RedisConnectionOptionsType`
|
|
382
300
|
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
301
|
+
```typescript
|
|
302
|
+
type RedisConnectionOptionsType = {
|
|
303
|
+
url?: string;
|
|
304
|
+
connectionTimeout?: number;
|
|
305
|
+
idleTimeout?: number;
|
|
306
|
+
autoReconnect?: boolean;
|
|
307
|
+
maxRetries?: number;
|
|
308
|
+
enableOfflineQueue?: boolean;
|
|
309
|
+
enableAutoPipelining?: boolean;
|
|
310
|
+
tls?: boolean | {
|
|
311
|
+
rejectUnauthorized?: boolean;
|
|
312
|
+
ca?: string;
|
|
313
|
+
cert?: string;
|
|
314
|
+
key?: string;
|
|
315
|
+
};
|
|
316
|
+
};
|
|
386
317
|
```
|
|
387
318
|
|
|
388
|
-
##
|
|
389
|
-
|
|
390
|
-
### Connection Management
|
|
391
|
-
- Always call `close()` when done with database operations
|
|
392
|
-
- Use try-catch blocks for proper error handling
|
|
393
|
-
- Consider connection pooling for high-traffic applications
|
|
319
|
+
## Advanced Usage
|
|
394
320
|
|
|
395
|
-
###
|
|
321
|
+
### Integration with Ooneex App
|
|
396
322
|
|
|
397
323
|
```typescript
|
|
398
|
-
import {
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
324
|
+
import { App } from '@ooneex/app';
|
|
325
|
+
import { TypeormPgDatabase } from '@ooneex/database';
|
|
326
|
+
|
|
327
|
+
const database = new TypeormPgDatabase({
|
|
328
|
+
host: 'localhost',
|
|
329
|
+
port: 5432,
|
|
330
|
+
username: 'postgres',
|
|
331
|
+
password: 'password',
|
|
332
|
+
database: 'myapp'
|
|
405
333
|
});
|
|
406
334
|
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
const client = adapter.getClient();
|
|
412
|
-
|
|
413
|
-
// Basic operations
|
|
414
|
-
await client.set('user:1', 'Alice');
|
|
415
|
-
const user = await client.get('user:1');
|
|
416
|
-
|
|
417
|
-
// Hash operations
|
|
418
|
-
await client.hmset('user:2', ['name', 'Bob', 'email', 'bob@example.com']);
|
|
419
|
-
const userFields = await client.hmget('user:2', ['name', 'email']);
|
|
420
|
-
|
|
421
|
-
// Set operations
|
|
422
|
-
await client.sadd('tags', 'redis', 'database', 'cache');
|
|
423
|
-
const tags = await client.smembers('tags');
|
|
424
|
-
|
|
425
|
-
// Utility methods
|
|
426
|
-
const pingResult = await adapter.ping();
|
|
427
|
-
const serverInfo = await adapter.info('server');
|
|
335
|
+
const app = new App({
|
|
336
|
+
database,
|
|
337
|
+
// ... other config
|
|
338
|
+
});
|
|
428
339
|
|
|
429
|
-
|
|
430
|
-
await adapter.close();
|
|
340
|
+
await app.run();
|
|
431
341
|
```
|
|
432
342
|
|
|
433
|
-
###
|
|
434
|
-
- Catch `DatabaseException` specifically for database errors
|
|
435
|
-
- Log error details for debugging
|
|
436
|
-
- Implement retry logic for transient failures
|
|
437
|
-
|
|
438
|
-
### Security
|
|
439
|
-
- Never hardcode database credentials
|
|
440
|
-
- Use environment variables for sensitive information
|
|
441
|
-
- Validate input data before database operations
|
|
442
|
-
|
|
443
|
-
### Performance
|
|
444
|
-
- Use prepared statements when possible
|
|
445
|
-
- Implement proper indexing strategies
|
|
446
|
-
- Monitor query performance in production
|
|
447
|
-
|
|
448
|
-
## TypeORM Integration
|
|
449
|
-
|
|
450
|
-
This package provides specialized adapters for TypeORM, allowing you to leverage the full power of TypeORM while maintaining the simplicity of the Ooneex database interface.
|
|
451
|
-
|
|
452
|
-
### PostgreSQL with TypeORM
|
|
343
|
+
### Using in Controllers
|
|
453
344
|
|
|
454
345
|
```typescript
|
|
455
|
-
import {
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
346
|
+
import { Route } from '@ooneex/routing';
|
|
347
|
+
import type { IController, ContextType } from '@ooneex/controller';
|
|
348
|
+
import { UserEntity } from '../entities/UserEntity';
|
|
349
|
+
|
|
350
|
+
@Route.http({
|
|
351
|
+
name: 'api.users.list',
|
|
352
|
+
path: '/api/users',
|
|
353
|
+
method: 'GET',
|
|
354
|
+
description: 'List all users'
|
|
355
|
+
})
|
|
356
|
+
class UserListController implements IController {
|
|
357
|
+
public async index(context: ContextType): Promise<IResponse> {
|
|
358
|
+
const { database } = context;
|
|
359
|
+
|
|
360
|
+
const userRepository = await database?.open(UserEntity);
|
|
361
|
+
const users = await userRepository?.find({
|
|
362
|
+
take: 100,
|
|
363
|
+
order: { createdAt: 'DESC' }
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
return context.response.json({ users });
|
|
465
367
|
}
|
|
466
|
-
}
|
|
368
|
+
}
|
|
467
369
|
```
|
|
468
370
|
|
|
469
|
-
###
|
|
371
|
+
### Container Integration with Decorators
|
|
470
372
|
|
|
471
373
|
```typescript
|
|
472
|
-
import {
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
374
|
+
import { container, EContainerScope } from '@ooneex/container';
|
|
375
|
+
import { TypeormPgDatabase, decorator } from '@ooneex/database';
|
|
376
|
+
|
|
377
|
+
// Register with decorator
|
|
378
|
+
@decorator.database()
|
|
379
|
+
class AppDatabase extends TypeormPgDatabase {
|
|
380
|
+
constructor() {
|
|
381
|
+
super({
|
|
382
|
+
host: 'localhost',
|
|
383
|
+
port: 5432,
|
|
384
|
+
database: 'myapp'
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
}
|
|
484
388
|
|
|
485
|
-
|
|
389
|
+
// Resolve from container
|
|
390
|
+
const database = container.get(AppDatabase);
|
|
391
|
+
```
|
|
486
392
|
|
|
487
|
-
###
|
|
393
|
+
### Error Handling
|
|
488
394
|
|
|
489
395
|
```typescript
|
|
490
|
-
import {
|
|
396
|
+
import { TypeormPgDatabase, DatabaseException } from '@ooneex/database';
|
|
491
397
|
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
})
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
398
|
+
try {
|
|
399
|
+
const database = new TypeormPgDatabase();
|
|
400
|
+
const userRepo = await database.open(UserEntity);
|
|
401
|
+
const users = await userRepo.find();
|
|
402
|
+
} catch (error) {
|
|
403
|
+
if (error instanceof DatabaseException) {
|
|
404
|
+
console.error('Database Error:', error.message);
|
|
405
|
+
console.error('Status:', error.status);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
```
|
|
500
409
|
|
|
501
|
-
|
|
502
|
-
await client.set('key', 'value');
|
|
503
|
-
const value = await client.get('key');
|
|
410
|
+
### Transaction Support
|
|
504
411
|
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
412
|
+
```typescript
|
|
413
|
+
import { TypeormPgDatabase } from '@ooneex/database';
|
|
414
|
+
import { UserEntity, OrderEntity } from './entities';
|
|
508
415
|
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
const userData = await client.hmget('user:1', ['name', 'email']);
|
|
416
|
+
const database = new TypeormPgDatabase();
|
|
417
|
+
const userRepo = await database.open(UserEntity);
|
|
512
418
|
|
|
513
|
-
//
|
|
514
|
-
|
|
515
|
-
const allTags = await client.smembers('tags');
|
|
419
|
+
// Access the entity manager for transactions
|
|
420
|
+
const entityManager = userRepo.manager;
|
|
516
421
|
|
|
517
|
-
await
|
|
422
|
+
await entityManager.transaction(async (transactionalManager) => {
|
|
423
|
+
const user = await transactionalManager.findOneBy(UserEntity, { id: '123' });
|
|
424
|
+
|
|
425
|
+
const order = transactionalManager.create(OrderEntity, {
|
|
426
|
+
userId: user.id,
|
|
427
|
+
total: 99.99
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
await transactionalManager.save(order);
|
|
431
|
+
|
|
432
|
+
user.ordersCount += 1;
|
|
433
|
+
await transactionalManager.save(user);
|
|
434
|
+
});
|
|
518
435
|
```
|
|
519
436
|
|
|
520
|
-
###
|
|
437
|
+
### Multiple Database Connections
|
|
521
438
|
|
|
522
439
|
```typescript
|
|
523
|
-
|
|
524
|
-
const subscriber = new RedisDatabaseAdapter();
|
|
440
|
+
import { TypeormPgDatabase, TypeormSqliteDatabase } from '@ooneex/database';
|
|
525
441
|
|
|
526
|
-
|
|
527
|
-
|
|
442
|
+
// Main PostgreSQL database
|
|
443
|
+
const mainDb = new TypeormPgDatabase({
|
|
444
|
+
host: 'localhost',
|
|
445
|
+
database: 'main_app'
|
|
446
|
+
});
|
|
528
447
|
|
|
529
|
-
//
|
|
530
|
-
const
|
|
531
|
-
|
|
532
|
-
console.log(`Received: ${message} on ${channel}`);
|
|
448
|
+
// Analytics SQLite database
|
|
449
|
+
const analyticsDb = new TypeormSqliteDatabase({
|
|
450
|
+
database: './analytics.db'
|
|
533
451
|
});
|
|
534
452
|
|
|
535
|
-
//
|
|
536
|
-
const
|
|
537
|
-
await
|
|
453
|
+
// Use both databases
|
|
454
|
+
const userRepo = await mainDb.open(UserEntity);
|
|
455
|
+
const analyticsRepo = await analyticsDb.open(AnalyticsEntity);
|
|
538
456
|
```
|
|
539
457
|
|
|
540
458
|
### Redis Caching Pattern
|
|
541
459
|
|
|
542
460
|
```typescript
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
461
|
+
import { RedisDatabase } from '@ooneex/database';
|
|
462
|
+
|
|
463
|
+
class CacheService {
|
|
464
|
+
private readonly redis: RedisDatabase;
|
|
465
|
+
private client: Bun.RedisClient | null = null;
|
|
466
|
+
|
|
467
|
+
constructor() {
|
|
468
|
+
this.redis = new RedisDatabase();
|
|
550
469
|
}
|
|
551
|
-
|
|
552
|
-
// Fetch from database
|
|
553
|
-
const user = await database.getUser(userId);
|
|
554
|
-
|
|
555
|
-
// Cache with expiration
|
|
556
|
-
await client.set(cacheKey, JSON.stringify(user));
|
|
557
|
-
await client.expire(cacheKey, 3600); // 1 hour
|
|
558
|
-
|
|
559
|
-
return user;
|
|
560
|
-
}
|
|
561
|
-
```
|
|
562
470
|
|
|
563
|
-
|
|
471
|
+
public async init(): Promise<void> {
|
|
472
|
+
this.client = await this.redis.open();
|
|
473
|
+
}
|
|
564
474
|
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
475
|
+
public async get<T>(key: string): Promise<T | null> {
|
|
476
|
+
const value = await this.client?.get(key);
|
|
477
|
+
return value ? JSON.parse(value) : null;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
public async set<T>(key: string, value: T, ttl?: number): Promise<void> {
|
|
481
|
+
await this.client?.set(key, JSON.stringify(value));
|
|
482
|
+
if (ttl) {
|
|
483
|
+
await this.client?.expire(key, ttl);
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
public async delete(key: string): Promise<void> {
|
|
488
|
+
await this.client?.del(key);
|
|
573
489
|
}
|
|
574
|
-
|
|
575
|
-
return {
|
|
576
|
-
allowed: count <= limit,
|
|
577
|
-
remaining: Math.max(0, limit - count)
|
|
578
|
-
};
|
|
579
490
|
}
|
|
580
491
|
```
|
|
581
492
|
|
|
582
493
|
## License
|
|
583
494
|
|
|
584
|
-
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
495
|
+
This project is licensed under the MIT License - see the [LICENSE](./LICENSE) file for details.
|
|
585
496
|
|
|
586
497
|
## Contributing
|
|
587
498
|
|
|
@@ -600,7 +511,6 @@ Contributions are welcome! Please feel free to submit a Pull Request. For major
|
|
|
600
511
|
- Follow the existing code style
|
|
601
512
|
- Update documentation for API changes
|
|
602
513
|
- Ensure all tests pass before submitting PR
|
|
603
|
-
- Test with different database types (SQLite, PostgreSQL, MySQL)
|
|
604
514
|
|
|
605
515
|
---
|
|
606
516
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,11 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
declare class DatabaseException extends Exception {
|
|
3
|
-
constructor(message: string, data?: Record<string, unknown>);
|
|
4
|
-
}
|
|
5
|
-
import { RedisClient as RedisClient2 } from "bun";
|
|
1
|
+
import { DataSource, EntityManager, EntityTarget as EntityTarget2, ObjectLiteral as ObjectLiteral2, Repository as Repository2 } from "typeorm";
|
|
6
2
|
import { RedisClient } from "bun";
|
|
7
3
|
import { EntityTarget, ObjectLiteral, Repository } from "typeorm";
|
|
8
|
-
type DatabaseClassType = new (...args: any[]) => IDatabase |
|
|
4
|
+
type DatabaseClassType = new (...args: any[]) => IDatabase | IRedisDatabase | ITypeormDatabase;
|
|
9
5
|
type RedisConnectionOptionsType = {
|
|
10
6
|
url?: string;
|
|
11
7
|
connectionTimeout?: number;
|
|
@@ -26,17 +22,34 @@ interface IDatabase {
|
|
|
26
22
|
close: () => Promise<void>;
|
|
27
23
|
drop: () => Promise<void>;
|
|
28
24
|
}
|
|
29
|
-
interface
|
|
25
|
+
interface IRedisDatabase {
|
|
30
26
|
open: () => Promise<RedisClient>;
|
|
31
27
|
close: () => Promise<void>;
|
|
32
28
|
drop: () => Promise<void>;
|
|
33
29
|
}
|
|
34
|
-
interface
|
|
35
|
-
open: <Entity extends ObjectLiteral>(entity: EntityTarget<Entity
|
|
30
|
+
interface ITypeormDatabase {
|
|
31
|
+
open: <Entity extends ObjectLiteral>(entity: EntityTarget<Entity>, database?: string) => Promise<Repository<Entity>>;
|
|
36
32
|
close: () => Promise<void>;
|
|
37
33
|
drop: () => Promise<void>;
|
|
38
34
|
}
|
|
39
|
-
declare class
|
|
35
|
+
declare abstract class AbstractTypeormSqliteDatabase implements ITypeormDatabase {
|
|
36
|
+
protected source: DataSource;
|
|
37
|
+
abstract getSource(database?: string): DataSource;
|
|
38
|
+
open<Entity extends ObjectLiteral2>(entity: EntityTarget2<Entity>, database?: string): Promise<Repository2<Entity>>;
|
|
39
|
+
close(database?: string): Promise<void>;
|
|
40
|
+
drop(database?: string): Promise<void>;
|
|
41
|
+
getEntityManager(database?: string): EntityManager;
|
|
42
|
+
}
|
|
43
|
+
import { Exception } from "@ooneex/exception";
|
|
44
|
+
declare class DatabaseException extends Exception {
|
|
45
|
+
constructor(message: string, data?: Record<string, unknown>);
|
|
46
|
+
}
|
|
47
|
+
import { EContainerScope } from "@ooneex/container";
|
|
48
|
+
declare const decorator: {
|
|
49
|
+
database: (scope?: EContainerScope) => (target: DatabaseClassType) => void;
|
|
50
|
+
};
|
|
51
|
+
import { RedisClient as RedisClient2 } from "bun";
|
|
52
|
+
declare class RedisDatabase implements IRedisDatabase {
|
|
40
53
|
private readonly options;
|
|
41
54
|
private client;
|
|
42
55
|
private connectionUrl;
|
|
@@ -46,26 +59,22 @@ declare class RedisDatabaseAdapter implements IRedisDatabaseAdapter {
|
|
|
46
59
|
close(): Promise<void>;
|
|
47
60
|
drop(): Promise<void>;
|
|
48
61
|
}
|
|
49
|
-
import { DataSource, EntityManager, EntityTarget as EntityTarget2, ObjectLiteral as ObjectLiteral2, Repository as Repository2 } from "typeorm";
|
|
50
|
-
import { PostgresConnectionOptions } from "typeorm/driver/postgres/PostgresConnectionOptions";
|
|
51
|
-
declare class TypeormPgDatabaseAdapter implements ITypeormDatabaseAdapter {
|
|
52
|
-
private source;
|
|
53
|
-
constructor(options: Omit<PostgresConnectionOptions, "type">);
|
|
54
|
-
getSource(): DataSource;
|
|
55
|
-
open<Entity extends ObjectLiteral2>(entity: EntityTarget2<Entity>): Promise<Repository2<Entity>>;
|
|
56
|
-
close(): Promise<void>;
|
|
57
|
-
drop(): Promise<void>;
|
|
58
|
-
getEntityManager(): EntityManager;
|
|
59
|
-
}
|
|
60
62
|
import { DataSource as DataSource2, EntityManager as EntityManager2, EntityTarget as EntityTarget3, ObjectLiteral as ObjectLiteral3, Repository as Repository3 } from "typeorm";
|
|
61
|
-
import {
|
|
62
|
-
declare class
|
|
63
|
+
import { PostgresConnectionOptions } from "typeorm/driver/postgres/PostgresConnectionOptions";
|
|
64
|
+
declare class TypeormPgDatabase implements ITypeormDatabase {
|
|
63
65
|
private source;
|
|
64
|
-
constructor(options
|
|
66
|
+
constructor(options?: Omit<PostgresConnectionOptions, "type">);
|
|
65
67
|
getSource(): DataSource2;
|
|
66
68
|
open<Entity extends ObjectLiteral3>(entity: EntityTarget3<Entity>): Promise<Repository3<Entity>>;
|
|
67
69
|
close(): Promise<void>;
|
|
68
70
|
drop(): Promise<void>;
|
|
69
71
|
getEntityManager(): EntityManager2;
|
|
70
72
|
}
|
|
71
|
-
|
|
73
|
+
import { DataSource as DataSource3 } from "typeorm";
|
|
74
|
+
import { SqliteConnectionOptions } from "typeorm/driver/sqlite/SqliteConnectionOptions";
|
|
75
|
+
declare class TypeormSqliteDatabase extends AbstractTypeormSqliteDatabase {
|
|
76
|
+
private readonly options;
|
|
77
|
+
constructor(options?: Omit<SqliteConnectionOptions, "type"> | undefined);
|
|
78
|
+
getSource(database?: string): DataSource3;
|
|
79
|
+
}
|
|
80
|
+
export { decorator, TypeormSqliteDatabase, TypeormPgDatabase, RedisDatabase, RedisConnectionOptionsType, ITypeormDatabase, IRedisDatabase, IDatabase, DatabaseException, DatabaseClassType, AbstractTypeormSqliteDatabase };
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{Exception as
|
|
2
|
+
class i{source;async open(t,e){let a=this.getSource(e);if(!a.isInitialized)await a.initialize();return a.getRepository(t)}async close(t){let e=this.getSource(t);if(e.isInitialized)await e.destroy()}async drop(t){let e=this.getSource(t);if(e.isInitialized)await e.dropDatabase()}getEntityManager(t){return this.getSource(t).manager}}import{Exception as c}from"@ooneex/exception";import{HttpStatus as p}from"@ooneex/http-status";class r extends c{constructor(t,e={}){super(t,{status:p.Code.InternalServerError,data:e});this.name="DatabaseException"}}import{container as m,EContainerScope as y}from"@ooneex/container";var D={database:(t=y.Singleton)=>{return(e)=>{m.add(e,t)}}};var{RedisClient:u}=globalThis.Bun;class o{options;client;connectionUrl;constructor(t={}){this.options=t;if(this.connectionUrl=t.url||Bun.env.DATABASE_REDIS_URL||"",!this.connectionUrl)throw new r("No Redis connection URL provided. The 'url' option must be specified or set the following environment variable: DATABASE_REDIS_URL.",{...t,connectionUrl:this.connectionUrl});this.client=new u(this.connectionUrl,{connectionTimeout:t.connectionTimeout||1e4,idleTimeout:t.idleTimeout||0,autoReconnect:t.autoReconnect??!0,maxRetries:t.maxRetries||10,enableOfflineQueue:t.enableOfflineQueue??!0,enableAutoPipelining:t.enableAutoPipelining??!0,...t.tls!==void 0&&{tls:t.tls}})}getClient(){return this.client}async open(){try{if(!this.client.connected)await this.client.connect();return this.client}catch(t){throw new r(`Failed to open Redis connection: ${t instanceof Error?t.message:String(t)}`,{connectionUrl:this.connectionUrl,options:this.options,error:t})}}async close(){try{if(this.client.connected)this.client.close()}catch(t){throw new r(`Failed to close Redis connection: ${t instanceof Error?t.message:String(t)}`,{connectionUrl:this.connectionUrl,error:t})}}async drop(){try{if(!this.client.connected)await this.open();await this.client.send("FLUSHDB",[])}catch(t){throw new r(`Failed to drop Redis database: ${t instanceof Error?t.message:String(t)}`,{connectionUrl:this.connectionUrl,error:t})}}}import{DataSource as l}from"typeorm";class s{source;constructor(t={}){let e=(t.url||Bun.env.DATABASE_URL||"").trim();if(!e)throw new r("No database URL provided. Please set DATABASE_URL environment variable or provide a url in the options.",{...t,url:e});this.source=new l({synchronize:!1,entities:[],extra:{max:10},...t,url:e,type:"postgres"})}getSource(){return this.source}async open(t){let e=this.getSource();if(!e.isInitialized)await e.initialize();return e.getRepository(t)}async close(){let t=this.getSource();if(t.isInitialized)await t.destroy()}async drop(){let t=this.getSource();if(t.isInitialized)await t.dropDatabase()}getEntityManager(){return this.getSource().manager}}import{DataSource as d}from"typeorm";class n extends i{options;constructor(t=void 0){super();this.options=t}getSource(t){if(!t&&this.source)return this.source;if(t=t||this.options?.database||Bun.env.SQLITE_DATABASE_PATH||"",!t)throw new r("No database path provided. The 'database' option must be specified with a valid file path or ':memory:' for in-memory database. Alternatively, set the SQLITE_DATABASE_PATH environment variable.",{...this.options||{},database:t});return this.source=new d({synchronize:!1,entities:[],enableWAL:!0,busyErrorRetry:2000,busyTimeout:30000,...this.options||{},database:t,type:"sqlite"}),this.source}}export{D as decorator,n as TypeormSqliteDatabase,s as TypeormPgDatabase,o as RedisDatabase,r as DatabaseException,i as AbstractTypeormSqliteDatabase};
|
|
3
3
|
|
|
4
|
-
//# debugId=
|
|
4
|
+
//# debugId=99403C65D68784B064756E2164756E21
|
package/dist/index.js.map
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["src/DatabaseException.ts", "src/
|
|
3
|
+
"sources": ["src/AbstractTypeormSqliteDatabase.ts", "src/DatabaseException.ts", "src/decorators.ts", "src/RedisDatabase.ts", "src/TypeormPgDatabase.ts", "src/TypeormSqliteDatabase.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
+
"import type { DataSource, EntityManager, EntityTarget, ObjectLiteral, Repository } from \"typeorm\";\nimport type { ITypeormDatabase } from \"./types\";\n\nexport abstract class AbstractTypeormSqliteDatabase implements ITypeormDatabase {\n protected source: DataSource;\n public abstract getSource(database?: string): DataSource;\n\n public async open<Entity extends ObjectLiteral>(\n entity: EntityTarget<Entity>,\n database?: string,\n ): Promise<Repository<Entity>> {\n const source = this.getSource(database);\n\n if (!source.isInitialized) {\n await source.initialize();\n }\n\n return source.getRepository(entity);\n }\n\n public async close(database?: string): Promise<void> {\n const source = this.getSource(database);\n if (source.isInitialized) {\n await source.destroy();\n }\n }\n\n public async drop(database?: string): Promise<void> {\n const source = this.getSource(database);\n if (source.isInitialized) {\n await source.dropDatabase();\n }\n }\n\n public getEntityManager(database?: string): EntityManager {\n return this.getSource(database).manager;\n }\n}\n",
|
|
5
6
|
"import { Exception } from \"@ooneex/exception\";\nimport { HttpStatus } from \"@ooneex/http-status\";\n\nexport class DatabaseException extends Exception {\n constructor(message: string, data: Record<string, unknown> = {}) {\n super(message, {\n status: HttpStatus.Code.InternalServerError,\n data,\n });\n this.name = \"DatabaseException\";\n }\n}\n",
|
|
6
|
-
"import {
|
|
7
|
-
"import {
|
|
8
|
-
"import { DataSource, type EntityManager, type EntityTarget, type ObjectLiteral, type Repository } from \"typeorm\";\nimport type {
|
|
7
|
+
"import { container, EContainerScope } from \"@ooneex/container\";\nimport type { DatabaseClassType } from \"./types\";\n\nexport const decorator = {\n database: (scope: EContainerScope = EContainerScope.Singleton) => {\n return (target: DatabaseClassType): void => {\n container.add(target, scope);\n };\n },\n};\n",
|
|
8
|
+
"import { RedisClient } from \"bun\";\nimport { DatabaseException } from \"./DatabaseException\";\nimport type { IRedisDatabase, RedisConnectionOptionsType } from \"./types\";\n\nexport class RedisDatabase implements IRedisDatabase {\n private client: RedisClient;\n private connectionUrl: string;\n\n constructor(private readonly options: RedisConnectionOptionsType = {}) {\n this.connectionUrl = options.url || Bun.env.DATABASE_REDIS_URL || \"\";\n\n if (!this.connectionUrl) {\n throw new DatabaseException(\n \"No Redis connection URL provided. The 'url' option must be specified or set the following environment variable: DATABASE_REDIS_URL.\",\n {\n ...options,\n connectionUrl: this.connectionUrl,\n },\n );\n }\n\n // Create Redis client with options\n this.client = new RedisClient(this.connectionUrl, {\n connectionTimeout: options.connectionTimeout || 10_000,\n idleTimeout: options.idleTimeout || 0,\n autoReconnect: options.autoReconnect ?? true,\n maxRetries: options.maxRetries || 10,\n enableOfflineQueue: options.enableOfflineQueue ?? true,\n enableAutoPipelining: options.enableAutoPipelining ?? true,\n ...(options.tls !== undefined && { tls: options.tls }),\n });\n }\n\n public getClient(): RedisClient {\n return this.client;\n }\n\n public async open(): Promise<RedisClient> {\n try {\n if (!this.client.connected) {\n await this.client.connect();\n }\n\n return this.client;\n } catch (error) {\n throw new DatabaseException(\n `Failed to open Redis connection: ${error instanceof Error ? error.message : String(error)}`,\n {\n connectionUrl: this.connectionUrl,\n options: this.options,\n error,\n },\n );\n }\n }\n\n public async close(): Promise<void> {\n try {\n if (this.client.connected) {\n this.client.close();\n }\n } catch (error) {\n throw new DatabaseException(\n `Failed to close Redis connection: ${error instanceof Error ? error.message : String(error)}`,\n {\n connectionUrl: this.connectionUrl,\n error,\n },\n );\n }\n }\n\n public async drop(): Promise<void> {\n try {\n if (!this.client.connected) {\n await this.open();\n }\n\n // Use FLUSHDB to clear the current database\n await this.client.send(\"FLUSHDB\", []);\n } catch (error) {\n throw new DatabaseException(\n `Failed to drop Redis database: ${error instanceof Error ? error.message : String(error)}`,\n {\n connectionUrl: this.connectionUrl,\n error,\n },\n );\n }\n }\n}\n",
|
|
9
|
+
"import { DataSource, type EntityManager, type EntityTarget, type ObjectLiteral, type Repository } from \"typeorm\";\nimport type { PostgresConnectionOptions } from \"typeorm/driver/postgres/PostgresConnectionOptions.js\";\nimport { DatabaseException } from \"./DatabaseException\";\nimport type { ITypeormDatabase } from \"./types\";\n\nexport class TypeormPgDatabase implements ITypeormDatabase {\n private source: DataSource;\n\n constructor(options: Omit<PostgresConnectionOptions, \"type\"> = {}) {\n const url = (options.url || Bun.env.DATABASE_URL || \"\").trim();\n\n if (!url) {\n throw new DatabaseException(\n \"No database URL provided. Please set DATABASE_URL environment variable or provide a url in the options.\",\n {\n ...options,\n url,\n },\n );\n }\n\n this.source = new DataSource({\n synchronize: false,\n entities: [],\n extra: {\n max: 10,\n // idleTimeoutMillis: 30000,\n },\n ...options,\n url,\n type: \"postgres\",\n });\n }\n\n public getSource(): DataSource {\n return this.source;\n }\n\n public async open<Entity extends ObjectLiteral>(entity: EntityTarget<Entity>): Promise<Repository<Entity>> {\n const source = this.getSource();\n\n if (!source.isInitialized) {\n await source.initialize();\n }\n\n return source.getRepository(entity);\n }\n\n public async close(): Promise<void> {\n const source = this.getSource();\n if (source.isInitialized) {\n await source.destroy();\n }\n }\n\n public async drop(): Promise<void> {\n const source = this.getSource();\n if (source.isInitialized) {\n await source.dropDatabase();\n }\n }\n\n public getEntityManager(): EntityManager {\n return this.getSource().manager;\n }\n}\n",
|
|
10
|
+
"import { DataSource } from \"typeorm\";\nimport type { SqliteConnectionOptions } from \"typeorm/driver/sqlite/SqliteConnectionOptions.js\";\nimport { AbstractTypeormSqliteDatabase } from \"./AbstractTypeormSqliteDatabase\";\nimport { DatabaseException } from \"./DatabaseException\";\n\nexport class TypeormSqliteDatabase extends AbstractTypeormSqliteDatabase {\n constructor(private readonly options: Omit<SqliteConnectionOptions, \"type\"> | undefined = undefined) {\n super();\n }\n\n public getSource(database?: string): DataSource {\n if (!database && this.source) {\n return this.source;\n }\n\n database = database || this.options?.database || Bun.env.SQLITE_DATABASE_PATH || \"\";\n\n if (!database) {\n throw new DatabaseException(\n \"No database path provided. The 'database' option must be specified with a valid file path or ':memory:' for in-memory database. Alternatively, set the SQLITE_DATABASE_PATH environment variable.\",\n {\n ...(this.options || {}),\n database,\n },\n );\n }\n\n this.source = new DataSource({\n synchronize: false,\n entities: [],\n enableWAL: true,\n busyErrorRetry: 2000,\n busyTimeout: 30_000,\n ...(this.options || {}),\n database,\n type: \"sqlite\",\n });\n\n return this.source;\n }\n}\n"
|
|
9
11
|
],
|
|
10
|
-
"mappings": ";
|
|
11
|
-
"debugId": "
|
|
12
|
+
"mappings": "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",
|
|
13
|
+
"debugId": "99403C65D68784B064756E2164756E21",
|
|
12
14
|
"names": []
|
|
13
15
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ooneex/database",
|
|
3
|
-
"description": "",
|
|
4
|
-
"version": "0.0.
|
|
3
|
+
"description": "Database connection and management utilities with TypeORM integration for Ooneex applications",
|
|
4
|
+
"version": "0.0.5",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
7
7
|
"dist",
|
|
@@ -25,15 +25,23 @@
|
|
|
25
25
|
"test": "bun test tests",
|
|
26
26
|
"build": "bunup",
|
|
27
27
|
"lint": "tsgo --noEmit && bunx biome lint",
|
|
28
|
-
"publish
|
|
29
|
-
"publish:pack": "bun pm pack --destination ./dist",
|
|
30
|
-
"publish:dry": "bun publish --dry-run"
|
|
28
|
+
"npm:publish": "bun publish --tolerate-republish --access public"
|
|
31
29
|
},
|
|
32
30
|
"dependencies": {
|
|
31
|
+
"@ooneex/container": "0.0.2",
|
|
33
32
|
"@ooneex/exception": "0.0.1",
|
|
34
33
|
"@ooneex/http-status": "0.0.1",
|
|
35
34
|
"typeorm": "^0.3.27"
|
|
36
35
|
},
|
|
37
|
-
"
|
|
38
|
-
"
|
|
36
|
+
"devDependencies": {},
|
|
37
|
+
"keywords": [
|
|
38
|
+
"bun",
|
|
39
|
+
"database",
|
|
40
|
+
"db",
|
|
41
|
+
"ooneex",
|
|
42
|
+
"query",
|
|
43
|
+
"sql",
|
|
44
|
+
"typeorm",
|
|
45
|
+
"typescript"
|
|
46
|
+
]
|
|
39
47
|
}
|
|
Binary file
|