@db-bridge/core 1.0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Berke Erdoğan
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,423 @@
1
+ # @db-bridge/core
2
+
3
+ Core package for DB Bridge - Provides base classes, interfaces, and utilities for database adapters.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @db-bridge/core
9
+ ```
10
+
11
+ ## Overview
12
+
13
+ This package provides the foundation for all DB Bridge database adapters:
14
+
15
+ - **Base Classes**: Abstract implementations for adapters and query builders
16
+ - **Interfaces**: TypeScript interfaces for consistent API across adapters
17
+ - **Error Classes**: Typed errors for better error handling
18
+ - **Utilities**: Helper functions for retries, validation, and formatting
19
+ - **Types**: Common type definitions
20
+
21
+ ## Core Components
22
+
23
+ ### DatabaseAdapter
24
+
25
+ The main interface that all database adapters must implement:
26
+
27
+ ```typescript
28
+ import { DatabaseAdapter } from '@db-bridge/core';
29
+
30
+ interface DatabaseAdapter {
31
+ // Connection management
32
+ connect(config: ConnectionConfig): Promise<void>;
33
+ disconnect(): Promise<void>;
34
+ ping(): Promise<boolean>;
35
+
36
+ // Query execution
37
+ query<T>(sql: string, params?: any[], options?: QueryOptions): Promise<QueryResult<T>>;
38
+ execute(sql: string, params?: any[], options?: QueryOptions): Promise<QueryResult>;
39
+
40
+ // Prepared statements
41
+ prepare(sql: string, name?: string): Promise<PreparedStatement>;
42
+
43
+ // Transactions
44
+ beginTransaction(options?: TransactionOptions): Promise<Transaction>;
45
+
46
+ // Query builder
47
+ createQueryBuilder<T>(): QueryBuilder<T>;
48
+
49
+ // Utilities
50
+ escape(value: any): string;
51
+ escapeIdentifier(identifier: string): string;
52
+ getPoolStats(): PoolStats;
53
+ }
54
+ ```
55
+
56
+ ### BaseAdapter
57
+
58
+ Abstract class providing common functionality for database adapters:
59
+
60
+ ```typescript
61
+ import { BaseAdapter } from '@db-bridge/core';
62
+
63
+ class MyAdapter extends BaseAdapter {
64
+ protected async doConnect(config: ConnectionConfig): Promise<void> {
65
+ // Implementation
66
+ }
67
+
68
+ protected async doDisconnect(): Promise<void> {
69
+ // Implementation
70
+ }
71
+
72
+ protected async doQuery<T>(
73
+ sql: string,
74
+ params?: any[],
75
+ options?: QueryOptions,
76
+ ): Promise<QueryResult<T>> {
77
+ // Implementation
78
+ }
79
+
80
+ // Other required methods...
81
+ }
82
+ ```
83
+
84
+ ### QueryBuilder
85
+
86
+ Fluent interface for building SQL queries:
87
+
88
+ ```typescript
89
+ import { QueryBuilder } from '@db-bridge/core';
90
+
91
+ interface QueryBuilder<T> {
92
+ // SELECT
93
+ select(...columns: string[]): QueryBuilder<T>;
94
+ select(columns: string[]): QueryBuilder<T>;
95
+ from(table: string, alias?: string): QueryBuilder<T>;
96
+
97
+ // JOIN
98
+ join(table: string, condition: string, type?: JoinType): QueryBuilder<T>;
99
+ leftJoin(table: string, condition: string): QueryBuilder<T>;
100
+ rightJoin(table: string, condition: string): QueryBuilder<T>;
101
+ innerJoin(table: string, condition: string): QueryBuilder<T>;
102
+
103
+ // WHERE
104
+ where(column: string, operator: string, value: any): QueryBuilder<T>;
105
+ where(conditions: Record<string, any>): QueryBuilder<T>;
106
+ whereIn(column: string, values: any[]): QueryBuilder<T>;
107
+ whereNotIn(column: string, values: any[]): QueryBuilder<T>;
108
+ whereBetween(column: string, min: any, max: any): QueryBuilder<T>;
109
+ whereNotBetween(column: string, min: any, max: any): QueryBuilder<T>;
110
+ whereNull(column: string): QueryBuilder<T>;
111
+ whereNotNull(column: string): QueryBuilder<T>;
112
+
113
+ // Grouping & Ordering
114
+ groupBy(...columns: string[]): QueryBuilder<T>;
115
+ having(condition: string, value?: any): QueryBuilder<T>;
116
+ orderBy(column: string, direction?: 'ASC' | 'DESC'): QueryBuilder<T>;
117
+
118
+ // Limit & Offset
119
+ limit(limit: number): QueryBuilder<T>;
120
+ offset(offset: number): QueryBuilder<T>;
121
+
122
+ // DML
123
+ insert(table: string, data: Record<string, any> | Record<string, any>[]): QueryBuilder<T>;
124
+ update(table: string, data: Record<string, any>): QueryBuilder<T>;
125
+ delete(table: string): QueryBuilder<T>;
126
+
127
+ // Execution
128
+ toSQL(): { sql: string; bindings: any[] };
129
+ execute(options?: QueryOptions): Promise<QueryResult<T>>;
130
+ first(options?: QueryOptions): Promise<T | null>;
131
+ count(column?: string): Promise<number>;
132
+ exists(): Promise<boolean>;
133
+ }
134
+ ```
135
+
136
+ ### Transaction Interface
137
+
138
+ ```typescript
139
+ import { Transaction, IsolationLevel } from '@db-bridge/core';
140
+
141
+ interface Transaction {
142
+ id: string;
143
+
144
+ // Transaction control
145
+ commit(): Promise<void>;
146
+ rollback(): Promise<void>;
147
+
148
+ // Savepoints (if supported)
149
+ savepoint(name: string): Promise<void>;
150
+ rollbackToSavepoint(name: string): Promise<void>;
151
+ releaseSavepoint(name: string): Promise<void>;
152
+
153
+ // Query execution within transaction
154
+ query<T>(sql: string, params?: any[]): Promise<QueryResult<T>>;
155
+ execute(sql: string, params?: any[]): Promise<QueryResult>;
156
+ }
157
+
158
+ // Isolation levels
159
+ enum IsolationLevel {
160
+ READ_UNCOMMITTED = 'READ UNCOMMITTED',
161
+ READ_COMMITTED = 'READ COMMITTED',
162
+ REPEATABLE_READ = 'REPEATABLE READ',
163
+ SERIALIZABLE = 'SERIALIZABLE',
164
+ }
165
+ ```
166
+
167
+ ### Error Classes
168
+
169
+ Typed errors for better error handling:
170
+
171
+ ```typescript
172
+ import {
173
+ DatabaseError,
174
+ ConnectionError,
175
+ QueryError,
176
+ TransactionError,
177
+ ValidationError,
178
+ TimeoutError,
179
+ } from '@db-bridge/core';
180
+
181
+ // Base error class
182
+ class DatabaseError extends Error {
183
+ code: string;
184
+ cause?: Error;
185
+ }
186
+
187
+ // Connection errors
188
+ class ConnectionError extends DatabaseError {
189
+ code = 'CONNECTION_ERROR';
190
+ host?: string;
191
+ port?: number;
192
+ }
193
+
194
+ // Query errors
195
+ class QueryError extends DatabaseError {
196
+ code = 'QUERY_ERROR';
197
+ sql?: string;
198
+ params?: any[];
199
+ }
200
+
201
+ // Transaction errors
202
+ class TransactionError extends DatabaseError {
203
+ code = 'TRANSACTION_ERROR';
204
+ transactionId?: string;
205
+ }
206
+
207
+ // Validation errors
208
+ class ValidationError extends DatabaseError {
209
+ code = 'VALIDATION_ERROR';
210
+ field?: string;
211
+ value?: any;
212
+ }
213
+
214
+ // Timeout errors
215
+ class TimeoutError extends DatabaseError {
216
+ code = 'TIMEOUT_ERROR';
217
+ timeout?: number;
218
+ }
219
+ ```
220
+
221
+ ### Utilities
222
+
223
+ #### Retry Utility
224
+
225
+ ```typescript
226
+ import { retry } from '@db-bridge/core/utils';
227
+
228
+ const result = await retry(
229
+ async () => {
230
+ return await riskyOperation();
231
+ },
232
+ {
233
+ maxRetries: 3,
234
+ retryDelay: 1000,
235
+ exponentialBackoff: true,
236
+ onRetry: (error, attempt) => {
237
+ console.log(`Retry attempt ${attempt} after error:`, error);
238
+ },
239
+ },
240
+ );
241
+ ```
242
+
243
+ #### SQL Utilities
244
+
245
+ ```typescript
246
+ import { formatSQL, validateIdentifier } from '@db-bridge/core/utils';
247
+
248
+ // Format SQL for logging
249
+ const formatted = formatSQL('SELECT * FROM users WHERE id = ?', [123]);
250
+ // Output: "SELECT * FROM users WHERE id = 123"
251
+
252
+ // Validate identifiers
253
+ validateIdentifier('user_table'); // OK
254
+ validateIdentifier('users; DROP TABLE users'); // Throws ValidationError
255
+ ```
256
+
257
+ #### Type Guards
258
+
259
+ ```typescript
260
+ import { isConnectionError, isQueryError, isTransactionError } from '@db-bridge/core/utils';
261
+
262
+ try {
263
+ await adapter.query('SELECT * FROM users');
264
+ } catch (error) {
265
+ if (isQueryError(error)) {
266
+ console.error('Query failed:', error.sql);
267
+ } else if (isConnectionError(error)) {
268
+ console.error('Connection lost');
269
+ }
270
+ }
271
+ ```
272
+
273
+ ## Types
274
+
275
+ ### Common Types
276
+
277
+ ```typescript
278
+ // Connection configuration
279
+ interface ConnectionConfig {
280
+ host: string;
281
+ port?: number;
282
+ user: string;
283
+ password: string;
284
+ database: string;
285
+ [key: string]: any; // Adapter-specific options
286
+ }
287
+
288
+ // Query result
289
+ interface QueryResult<T = any> {
290
+ rows: T[];
291
+ fields?: FieldInfo[];
292
+ rowCount: number;
293
+ command?: string;
294
+ duration?: number;
295
+ insertId?: number | string;
296
+ affectedRows?: number;
297
+ }
298
+
299
+ // Query options
300
+ interface QueryOptions {
301
+ timeout?: number;
302
+ transaction?: Transaction;
303
+ cache?: CacheOptions | false;
304
+ [key: string]: any; // Adapter-specific options
305
+ }
306
+
307
+ // Pool statistics
308
+ interface PoolStats {
309
+ total: number;
310
+ active: number;
311
+ idle: number;
312
+ waiting: number;
313
+ }
314
+
315
+ // Field information
316
+ interface FieldInfo {
317
+ name: string;
318
+ type: string;
319
+ nullable: boolean;
320
+ primary?: boolean;
321
+ autoIncrement?: boolean;
322
+ default?: any;
323
+ }
324
+ ```
325
+
326
+ ## Creating a Custom Adapter
327
+
328
+ To create a custom database adapter:
329
+
330
+ ```typescript
331
+ import {
332
+ BaseAdapter,
333
+ ConnectionConfig,
334
+ QueryResult,
335
+ QueryOptions,
336
+ Transaction,
337
+ PreparedStatement,
338
+ ConnectionError,
339
+ QueryError,
340
+ } from '@db-bridge/core';
341
+
342
+ export class CustomAdapter extends BaseAdapter {
343
+ private connection: any;
344
+
345
+ protected async doConnect(config: ConnectionConfig): Promise<void> {
346
+ try {
347
+ this.connection = await customDriver.connect(config);
348
+ } catch (error) {
349
+ throw new ConnectionError('Failed to connect', { cause: error });
350
+ }
351
+ }
352
+
353
+ protected async doDisconnect(): Promise<void> {
354
+ if (this.connection) {
355
+ await this.connection.close();
356
+ this.connection = null;
357
+ }
358
+ }
359
+
360
+ protected async doQuery<T>(
361
+ sql: string,
362
+ params: any[] = [],
363
+ options: QueryOptions = {},
364
+ ): Promise<QueryResult<T>> {
365
+ try {
366
+ const result = await this.connection.query(sql, params);
367
+ return {
368
+ rows: result.rows,
369
+ rowCount: result.rowCount,
370
+ fields: result.fields,
371
+ };
372
+ } catch (error) {
373
+ throw new QueryError('Query failed', {
374
+ cause: error,
375
+ sql,
376
+ params,
377
+ });
378
+ }
379
+ }
380
+
381
+ protected async doPing(): Promise<boolean> {
382
+ try {
383
+ await this.connection.query('SELECT 1');
384
+ return true;
385
+ } catch {
386
+ return false;
387
+ }
388
+ }
389
+
390
+ async beginTransaction(options?: TransactionOptions): Promise<Transaction> {
391
+ // Implementation
392
+ }
393
+
394
+ async prepare(sql: string, name?: string): Promise<PreparedStatement> {
395
+ // Implementation
396
+ }
397
+
398
+ escape(value: any): string {
399
+ // Implementation
400
+ }
401
+
402
+ escapeIdentifier(identifier: string): string {
403
+ // Implementation
404
+ }
405
+
406
+ getPoolStats(): PoolStats {
407
+ // Implementation
408
+ }
409
+ }
410
+ ```
411
+
412
+ ## Best Practices
413
+
414
+ 1. **Extend BaseAdapter**: Always extend BaseAdapter for common functionality
415
+ 2. **Use Typed Errors**: Throw appropriate error types for better error handling
416
+ 3. **Implement Retry Logic**: Use the retry utility for transient failures
417
+ 4. **Validate Input**: Use validation utilities for identifiers and values
418
+ 5. **Type Everything**: Provide full TypeScript types for better developer experience
419
+ 6. **Handle Cleanup**: Always clean up resources in disconnect/error handlers
420
+
421
+ ## License
422
+
423
+ MIT © Berke Erdoğan