@ooneex/database 0.0.1

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Ooneex
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,607 @@
1
+ # @ooneex/database
2
+
3
+ A comprehensive TypeScript/JavaScript database library designed for Bun runtime. This package provides a unified interface for database operations with support for SQLite, PostgreSQL, MySQL, and Redis, along with TypeORM adapters for advanced ORM functionality.
4
+
5
+ ![Bun](https://img.shields.io/badge/Bun-Compatible-orange?style=flat-square&logo=bun)
6
+ ![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue?style=flat-square&logo=typescript)
7
+ ![MIT License](https://img.shields.io/badge/License-MIT-yellow?style=flat-square)
8
+
9
+ ## Features
10
+
11
+ ✅ **Multi-Database Support** - SQLite, PostgreSQL, MySQL, and Redis support
12
+
13
+ ✅ **Bun Native** - Built specifically for Bun runtime with Bun.SQL
14
+
15
+ ✅ **TypeORM Integration** - Dedicated adapters for PostgreSQL and SQLite
16
+
17
+ ✅ **Type-Safe** - Full TypeScript support with proper type definitions
18
+
19
+ ✅ **Connection Management** - Robust connection opening, closing, and lifecycle management
20
+
21
+ ✅ **Database Operations** - Create, drop, and manage database instances
22
+
23
+ ✅ **Error Handling** - Comprehensive error handling with custom exceptions
24
+
25
+ ✅ **Environment Support** - Automatic environment variable detection
26
+
27
+ ✅ **Zero Configuration** - Works out of the box with sensible defaults
28
+
29
+ ## Installation
30
+
31
+ ### Bun
32
+ ```bash
33
+ bun add @ooneex/database
34
+ ```
35
+
36
+ ## Usage
37
+
38
+ ### TypeORM PostgreSQL Adapter
39
+
40
+ ```typescript
41
+ import { TypeormPgDatabaseAdapter } from '@ooneex/database';
42
+ import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';
43
+
44
+ @Entity()
45
+ class User {
46
+ @PrimaryGeneratedColumn()
47
+ id: number;
48
+
49
+ @Column()
50
+ name: string;
51
+
52
+ @Column()
53
+ email: string;
54
+ }
55
+
56
+ const adapter = new TypeormPgDatabaseAdapter({
57
+ url: 'postgresql://user:pass@localhost:5432/mydb',
58
+ synchronize: true,
59
+ entities: [User]
60
+ });
61
+
62
+ // Open and get repository
63
+ const userRepository = await adapter.open(User);
64
+
65
+ // Create user
66
+ const user = userRepository.create({
67
+ name: 'John Doe',
68
+ email: 'john@example.com'
69
+ });
70
+ await userRepository.save(user);
71
+
72
+ // Find users
73
+ const users = await userRepository.find();
74
+
75
+ // Close connection
76
+ await adapter.close();
77
+ ```
78
+
79
+ ### TypeORM SQLite Adapter
80
+
81
+ ```typescript
82
+ import { TypeormSqliteDatabaseAdapter } from '@ooneex/database';
83
+ import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';
84
+
85
+ @Entity()
86
+ class Product {
87
+ @PrimaryGeneratedColumn()
88
+ id: number;
89
+
90
+ @Column()
91
+ name: string;
92
+
93
+ @Column('decimal')
94
+ price: number;
95
+ }
96
+
97
+ const adapter = new TypeormSqliteDatabaseAdapter({
98
+ database: './products.db',
99
+ synchronize: true,
100
+ entities: [Product]
101
+ });
102
+
103
+ // Open and get repository
104
+ const productRepository = await adapter.open(Product);
105
+
106
+ // Create product
107
+ const product = productRepository.create({
108
+ name: 'Laptop',
109
+ price: 999.99
110
+ });
111
+ await productRepository.save(product);
112
+
113
+ // Close connection
114
+ await adapter.close();
115
+ ```
116
+
117
+ ### Error Handling
118
+
119
+ ```typescript
120
+ import { Database, DatabaseException } from '@ooneex/database';
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
+ ```
132
+
133
+ ### Environment Configuration
134
+
135
+ ```bash
136
+ # Set in your .env file
137
+ DATABASE_URL=sqlite://./myapp.db
138
+ # or
139
+ DATABASE_URL=postgresql://user:password@localhost:5432/mydb
140
+ # or
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
150
+ ```
151
+
152
+ ## API Reference
153
+
154
+ ### `Database` Class
155
+
156
+ The main database class providing connection management and basic operations.
157
+
158
+ #### Constructor
159
+
160
+ ```typescript
161
+ constructor(connectionString?: string | URL, options?: Bun.SQL.Options)
162
+ ```
163
+
164
+ **Parameters:**
165
+ - `connectionString` - Database connection string or URL object
166
+ - `options` - Bun.SQL connection options
167
+
168
+ **Example:**
169
+ ```typescript
170
+ const db = new Database('sqlite://./app.db', { timeout: 5000 });
171
+ ```
172
+
173
+ #### Methods
174
+
175
+ ##### `getClient(): Bun.SQL`
176
+ Returns the underlying Bun.SQL client instance.
177
+
178
+ **Returns:** The Bun.SQL client
179
+
180
+ **Example:**
181
+ ```typescript
182
+ const client = db.getClient();
183
+ const result = await client`SELECT * FROM users`;
184
+ ```
185
+
186
+ ##### `open(): Promise<void>`
187
+ Opens the database connection.
188
+
189
+ **Example:**
190
+ ```typescript
191
+ await db.open();
192
+ ```
193
+
194
+ ##### `close(): Promise<void>`
195
+ Closes the database connection.
196
+
197
+ **Example:**
198
+ ```typescript
199
+ await db.close();
200
+ ```
201
+
202
+ ##### `drop(): Promise<void>`
203
+ Drops the database. **Caution: This is destructive and cannot be undone.**
204
+
205
+ **Example:**
206
+ ```typescript
207
+ await db.drop(); // Permanently deletes the database
208
+ ```
209
+
210
+ ### `TypeormPgDatabaseAdapter` Class
211
+
212
+ TypeORM adapter for PostgreSQL databases.
213
+
214
+ #### Constructor
215
+
216
+ ```typescript
217
+ constructor(options: Omit<PostgresConnectionOptions, "type">)
218
+ ```
219
+
220
+ **Parameters:**
221
+ - `options` - PostgreSQL connection options (without type field)
222
+
223
+ #### Methods
224
+
225
+ ##### `getSource(): DataSource`
226
+ Returns the TypeORM DataSource instance.
227
+
228
+ ##### `open<Entity>(entity: EntityTarget<Entity>): Promise<Repository<Entity>>`
229
+ Opens connection and returns repository for the specified entity.
230
+
231
+ ##### `close(): Promise<void>`
232
+ Closes the database connection.
233
+
234
+ ##### `drop(): Promise<void>`
235
+ Drops the database schema.
236
+
237
+ ##### `getEntityManager(): EntityManager`
238
+ Returns the TypeORM EntityManager.
239
+
240
+ ### `TypeormSqliteDatabaseAdapter` Class
241
+
242
+ TypeORM adapter for SQLite databases.
243
+
244
+ #### Constructor
245
+
246
+ ```typescript
247
+ constructor(options: Omit<SqliteConnectionOptions, "type">)
248
+ ```
249
+
250
+ **Parameters:**
251
+ - `options` - SQLite connection options (without type field)
252
+
253
+ #### Methods
254
+
255
+ Same methods as `TypeormPgDatabaseAdapter` but optimized for SQLite.
256
+
257
+ ### `RedisDatabaseAdapter` Class
258
+
259
+ Redis adapter using Bun's native Redis client.
260
+
261
+ #### Constructor
262
+
263
+ ```typescript
264
+ constructor(options: RedisConnectionOptions = {})
265
+ ```
266
+
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
+ ##### `close(): Promise<void>`
289
+ Closes the Redis connection.
290
+
291
+ ##### `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
+
300
+ ##### `isConnected(): boolean`
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
319
+
320
+ ### Interfaces
321
+
322
+ #### `IDatabase`
323
+
324
+ ```typescript
325
+ interface IDatabase {
326
+ open(): Promise<void>;
327
+ close(): Promise<void>;
328
+ drop(): Promise<void>;
329
+ }
330
+ ```
331
+
332
+ #### `ITypeormDatabaseAdapter`
333
+
334
+ ```typescript
335
+ interface ITypeormDatabaseAdapter {
336
+ open(entity: any): Promise<any>;
337
+ close(): Promise<void>;
338
+ drop(): Promise<void>;
339
+ }
340
+ ```
341
+
342
+ ## Supported Database URLs
343
+
344
+ ### SQLite
345
+ ```typescript
346
+ // File-based database
347
+ 'sqlite://./database.db'
348
+ 'sqlite:database.db'
349
+ './database.db'
350
+
351
+ // In-memory database
352
+ 'sqlite://:memory:'
353
+ ':memory:'
354
+ ```
355
+
356
+ ### PostgreSQL
357
+ ```typescript
358
+ 'postgresql://user:password@localhost:5432/database'
359
+ 'postgres://user:password@localhost:5432/database'
360
+ ```
361
+
362
+ ### MySQL
363
+ ```typescript
364
+ 'mysql://user:password@localhost:3306/database'
365
+ 'mysql2://user:password@localhost:3306/database'
366
+ ```
367
+
368
+ ### Redis
369
+ ```typescript
370
+ // Standard Redis URL
371
+ 'redis://localhost:6379'
372
+
373
+ // With authentication
374
+ 'redis://username:password@localhost:6379'
375
+
376
+ // With database number
377
+ 'redis://localhost:6379/0'
378
+
379
+ // TLS connections
380
+ 'rediss://localhost:6379'
381
+ 'redis+tls://localhost:6379'
382
+
383
+ // Unix socket connections
384
+ 'redis+unix:///path/to/socket'
385
+ 'redis+tls+unix:///path/to/socket'
386
+ ```
387
+
388
+ ## Best Practices
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
394
+
395
+ ### Redis Adapter
396
+
397
+ ```typescript
398
+ import { RedisDatabaseAdapter } from '@ooneex/database';
399
+
400
+ const adapter = new RedisDatabaseAdapter({
401
+ url: 'redis://localhost:6379',
402
+ connectionTimeout: 10000,
403
+ autoReconnect: true,
404
+ maxRetries: 10
405
+ });
406
+
407
+ // Open connection
408
+ await adapter.open();
409
+
410
+ // Get Redis client for operations
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');
428
+
429
+ // Close connection
430
+ await adapter.close();
431
+ ```
432
+
433
+ ### Error Handling
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
453
+
454
+ ```typescript
455
+ import { TypeormPgDatabaseAdapter } from '@ooneex/database';
456
+
457
+ const adapter = new TypeormPgDatabaseAdapter({
458
+ url: process.env.DATABASE_URL,
459
+ synchronize: false, // Set to true only in development
460
+ entities: [User, Product, Order],
461
+ migrations: ['./migrations/**/*.ts'],
462
+ extra: {
463
+ max: 20, // Maximum number of connections
464
+ idleTimeoutMillis: 30000
465
+ }
466
+ });
467
+ ```
468
+
469
+ ### SQLite with TypeORM
470
+
471
+ ```typescript
472
+ import { TypeormSqliteDatabaseAdapter } from '@ooneex/database';
473
+
474
+ const adapter = new TypeormSqliteDatabaseAdapter({
475
+ database: './myapp.db',
476
+ synchronize: true,
477
+ entities: [User, Product],
478
+ enableWAL: true, // Write-Ahead Logging for better performance
479
+ busyTimeout: 30000
480
+ });
481
+ ```
482
+
483
+ ## Redis Integration
484
+
485
+ This package provides a native Redis adapter built specifically for Bun's Redis client, offering high-performance Redis operations with full TypeScript support.
486
+
487
+ ### Basic Redis Usage
488
+
489
+ ```typescript
490
+ import { RedisDatabaseAdapter } from '@ooneex/database';
491
+
492
+ const adapter = new RedisDatabaseAdapter({
493
+ url: process.env.REDIS_URL,
494
+ connectionTimeout: 5000,
495
+ autoReconnect: true
496
+ });
497
+
498
+ await adapter.open();
499
+ const client = adapter.getClient();
500
+
501
+ // String operations
502
+ await client.set('key', 'value');
503
+ const value = await client.get('key');
504
+
505
+ // Numeric operations
506
+ await client.incr('counter');
507
+ await client.decr('counter');
508
+
509
+ // Hash operations
510
+ await client.hmset('user:1', ['name', 'Alice', 'email', 'alice@example.com']);
511
+ const userData = await client.hmget('user:1', ['name', 'email']);
512
+
513
+ // Set operations
514
+ await client.sadd('tags', 'redis', 'cache');
515
+ const allTags = await client.smembers('tags');
516
+
517
+ await adapter.close();
518
+ ```
519
+
520
+ ### Redis Pub/Sub
521
+
522
+ ```typescript
523
+ const publisher = new RedisDatabaseAdapter();
524
+ const subscriber = new RedisDatabaseAdapter();
525
+
526
+ await publisher.open();
527
+ await subscriber.open();
528
+
529
+ // Set up subscription
530
+ const subClient = subscriber.getClient();
531
+ await subClient.subscribe('notifications', (message, channel) => {
532
+ console.log(`Received: ${message} on ${channel}`);
533
+ });
534
+
535
+ // Publish message
536
+ const pubClient = publisher.getClient();
537
+ await pubClient.publish('notifications', 'Hello subscribers!');
538
+ ```
539
+
540
+ ### Redis Caching Pattern
541
+
542
+ ```typescript
543
+ async function getUserWithCache(userId: number) {
544
+ const cacheKey = `user:${userId}`;
545
+
546
+ // Try cache first
547
+ const cached = await client.get(cacheKey);
548
+ if (cached) {
549
+ return JSON.parse(cached);
550
+ }
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
+
563
+ ### Redis Rate Limiting
564
+
565
+ ```typescript
566
+ async function rateLimit(ip: string, limit: number = 100, windowSecs: number = 3600) {
567
+ const key = `ratelimit:${ip}`;
568
+
569
+ const count = await client.incr(key);
570
+
571
+ if (count === 1) {
572
+ await client.expire(key, windowSecs);
573
+ }
574
+
575
+ return {
576
+ allowed: count <= limit,
577
+ remaining: Math.max(0, limit - count)
578
+ };
579
+ }
580
+ ```
581
+
582
+ ## License
583
+
584
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
585
+
586
+ ## Contributing
587
+
588
+ Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
589
+
590
+ ### Development Setup
591
+
592
+ 1. Clone the repository
593
+ 2. Install dependencies: `bun install`
594
+ 3. Run tests: `bun run test`
595
+ 4. Build the project: `bun run build`
596
+
597
+ ### Guidelines
598
+
599
+ - Write tests for new features
600
+ - Follow the existing code style
601
+ - Update documentation for API changes
602
+ - Ensure all tests pass before submitting PR
603
+ - Test with different database types (SQLite, PostgreSQL, MySQL)
604
+
605
+ ---
606
+
607
+ Made with ❤️ by the Ooneex team
@@ -0,0 +1,71 @@
1
+ import { Exception } from "@ooneex/exception";
2
+ declare class DatabaseException extends Exception {
3
+ constructor(message: string, data?: Record<string, unknown>);
4
+ }
5
+ import { RedisClient as RedisClient2 } from "bun";
6
+ import { RedisClient } from "bun";
7
+ import { EntityTarget, ObjectLiteral, Repository } from "typeorm";
8
+ type DatabaseClassType = new (...args: any[]) => IDatabase | IRedisDatabaseAdapter | ITypeormDatabaseAdapter;
9
+ type RedisConnectionOptionsType = {
10
+ url?: string;
11
+ connectionTimeout?: number;
12
+ idleTimeout?: number;
13
+ autoReconnect?: boolean;
14
+ maxRetries?: number;
15
+ enableOfflineQueue?: boolean;
16
+ enableAutoPipelining?: boolean;
17
+ tls?: boolean | {
18
+ rejectUnauthorized?: boolean;
19
+ ca?: string;
20
+ cert?: string;
21
+ key?: string;
22
+ };
23
+ };
24
+ interface IDatabase {
25
+ open: () => Promise<void>;
26
+ close: () => Promise<void>;
27
+ drop: () => Promise<void>;
28
+ }
29
+ interface IRedisDatabaseAdapter {
30
+ open: () => Promise<RedisClient>;
31
+ close: () => Promise<void>;
32
+ drop: () => Promise<void>;
33
+ }
34
+ interface ITypeormDatabaseAdapter {
35
+ open: <Entity extends ObjectLiteral>(entity: EntityTarget<Entity>) => Promise<Repository<Entity>>;
36
+ close: () => Promise<void>;
37
+ drop: () => Promise<void>;
38
+ }
39
+ declare class RedisDatabaseAdapter implements IRedisDatabaseAdapter {
40
+ private readonly options;
41
+ private client;
42
+ private connectionUrl;
43
+ constructor(options?: RedisConnectionOptionsType);
44
+ getClient(): RedisClient2;
45
+ open(): Promise<RedisClient2>;
46
+ close(): Promise<void>;
47
+ drop(): Promise<void>;
48
+ }
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
+ import { DataSource as DataSource2, EntityManager as EntityManager2, EntityTarget as EntityTarget3, ObjectLiteral as ObjectLiteral3, Repository as Repository3 } from "typeorm";
61
+ import { SqliteConnectionOptions } from "typeorm/driver/sqlite/SqliteConnectionOptions";
62
+ declare class TypeormSqliteDatabaseAdapter implements ITypeormDatabaseAdapter {
63
+ private source;
64
+ constructor(options: Omit<SqliteConnectionOptions, "type">);
65
+ getSource(): DataSource2;
66
+ open<Entity extends ObjectLiteral3>(entity: EntityTarget3<Entity>): Promise<Repository3<Entity>>;
67
+ close(): Promise<void>;
68
+ drop(): Promise<void>;
69
+ getEntityManager(): EntityManager2;
70
+ }
71
+ export { TypeormSqliteDatabaseAdapter, TypeormPgDatabaseAdapter, RedisDatabaseAdapter, RedisConnectionOptionsType, ITypeormDatabaseAdapter, IRedisDatabaseAdapter, IDatabase, DatabaseException, DatabaseClassType };
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ // @bun
2
+ import{Exception as r}from"@ooneex/exception";import{HttpStatus as a}from"@ooneex/http-status";class i extends r{constructor(t,e={}){super(t,{status:a.Code.InternalServerError,data:e});this.name="DatabaseException"}}var{RedisClient:o}=globalThis.Bun;class s{options;client;connectionUrl;constructor(t={}){this.options=t;if(this.connectionUrl=t.url||Bun.env.DATABASE_REDIS_URL||"",!this.connectionUrl)throw new i("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 o(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 i(`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 i(`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 i(`Failed to drop Redis database: ${t instanceof Error?t.message:String(t)}`,{connectionUrl:this.connectionUrl,error:t})}}}import{DataSource as n}from"typeorm";class c{source;constructor(t){let e=(t.url||Bun.env.DATABASE_URL||"").trim();if(!e)throw new i("No database URL provided. Please set DATABASE_URL environment variable or provide a url in the options.",{...t,url:e});this.source=new n({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 p}from"typeorm";class y{source;constructor(t){let e=t.database||Bun.env.SQLITE_DATABASE_PATH||"";if(!e)throw new i("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.",{...t,database:e});this.source=new p({synchronize:!1,entities:[],enableWAL:!0,busyErrorRetry:2000,busyTimeout:30000,...t,database:e,type:"sqlite"})}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}}export{y as TypeormSqliteDatabaseAdapter,c as TypeormPgDatabaseAdapter,s as RedisDatabaseAdapter,i as DatabaseException};
3
+
4
+ //# debugId=6EB87EF735D078EC64756E2164756E21
@@ -0,0 +1,13 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["src/DatabaseException.ts", "src/RedisDatabaseAdapter.ts", "src/TypeormPgDatabaseAdapter.ts", "src/TypeormSqliteDatabaseAdapter.ts"],
4
+ "sourcesContent": [
5
+ "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 { RedisClient } from \"bun\";\nimport { DatabaseException } from \"./DatabaseException\";\nimport type { IRedisDatabaseAdapter, RedisConnectionOptionsType } from \"./types\";\n\nexport class RedisDatabaseAdapter implements IRedisDatabaseAdapter {\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",
7
+ "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 { ITypeormDatabaseAdapter } from \"./types\";\n\nexport class TypeormPgDatabaseAdapter implements ITypeormDatabaseAdapter {\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",
8
+ "import { DataSource, type EntityManager, type EntityTarget, type ObjectLiteral, type Repository } from \"typeorm\";\nimport type { SqliteConnectionOptions } from \"typeorm/driver/sqlite/SqliteConnectionOptions.js\";\nimport { DatabaseException } from \"./DatabaseException\";\nimport type { ITypeormDatabaseAdapter } from \"./types\";\n\nexport class TypeormSqliteDatabaseAdapter implements ITypeormDatabaseAdapter {\n private source: DataSource;\n\n constructor(options: Omit<SqliteConnectionOptions, \"type\">) {\n const database = 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 ...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 ...options,\n database,\n type: \"sqlite\",\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"
9
+ ],
10
+ "mappings": "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",
11
+ "debugId": "6EB87EF735D078EC64756E2164756E21",
12
+ "names": []
13
+ }
Binary file
package/package.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "@ooneex/database",
3
+ "description": "",
4
+ "version": "0.0.1",
5
+ "type": "module",
6
+ "files": [
7
+ "dist",
8
+ "LICENSE",
9
+ "README.md",
10
+ "package.json"
11
+ ],
12
+ "module": "./dist/index.js",
13
+ "types": "./dist/index.d.ts",
14
+ "exports": {
15
+ ".": {
16
+ "import": {
17
+ "types": "./dist/index.d.ts",
18
+ "default": "./dist/index.js"
19
+ }
20
+ },
21
+ "./package.json": "./package.json"
22
+ },
23
+ "license": "MIT",
24
+ "scripts": {
25
+ "test": "bun test tests",
26
+ "build": "bunup",
27
+ "lint": "tsgo --noEmit && bunx biome lint",
28
+ "publish:prod": "bun publish --tolerate-republish --access public",
29
+ "publish:pack": "bun pm pack --destination ./dist",
30
+ "publish:dry": "bun publish --dry-run"
31
+ },
32
+ "dependencies": {
33
+ "@ooneex/exception": "0.0.1",
34
+ "@ooneex/http-status": "0.0.1",
35
+ "typeorm": "^0.3.27"
36
+ },
37
+ "peerDependencies": {},
38
+ "devDependencies": {}
39
+ }