fastmssql 0.2.4__cp312-cp312-macosx_11_0_arm64.whl → 0.2.7__cp312-cp312-macosx_11_0_arm64.whl

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.

Potentially problematic release.


This version of fastmssql might be problematic. Click here for more details.

fastmssql/__init__.py CHANGED
@@ -1,18 +1,661 @@
1
1
  """
2
- fastmssql: A high-performance Python library for Microsoft SQL Server
2
+ FastMSSQL - High-Performance Microsoft SQL Server Driver for Python
3
+ ===================================================================
3
4
 
4
- This library provides a Python interface to Microsoft SQL Server using the Tiberius
5
- Rust driver for excellent performance and memory safety.
5
+ This library provides direct access to high-performance Rust implementations
6
+ with minimal Python overhead for maximum performance. Built on top of the
7
+ tiberius crate, it offers both synchronous and asynchronous database operations
8
+ with advanced features like connection pooling, SSL/TLS configuration, and
9
+ efficient parameter handling.
6
10
 
7
- Example (async):
11
+ Key Features:
12
+ - High-performance Rust backend with Python bindings
13
+ - Async/await support for non-blocking operations
14
+ - Connection pooling with configurable parameters
15
+ - SSL/TLS encryption with certificate validation
16
+ - Parameterized queries with automatic type conversion
17
+ - Memory-efficient result iteration
18
+ - Comprehensive error handling and logging
19
+
20
+ Basic Usage (Async):
21
+ >>> import asyncio
22
+ >>> from fastmssql import Connection
23
+ >>>
24
+ >>> async def main():
25
+ ... async with Connection("Server=localhost;Database=test;Trusted_Connection=yes") as conn:
26
+ ... # Simple query
27
+ ... result = await conn.execute("SELECT * FROM users")
28
+ ... async for row in result:
29
+ ... print(f"User: {row['name']}, Age: {row['age']}")
30
+ ...
31
+ ... # Parameterized query
32
+ ... result = await conn.execute(
33
+ ... "SELECT * FROM users WHERE age > @P1 AND city = @P2",
34
+ ... [18, "New York"]
35
+ ... )
36
+ ... rows = await result.fetchall()
37
+ ... print(f"Found {len(rows)} users")
38
+ >>>
39
+ >>> asyncio.run(main())
40
+
41
+ Basic Usage (Sync):
8
42
  >>> from fastmssql import Connection
9
- >>> async with Connection("DATABASE_CONNECTION_STRING") as conn:
10
- ... result = await conn.execute("SELECT * FROM users WHERE age > @P1", [18])
11
- ... for row in result:
12
- ... print(row['name'], row['age'])
43
+ >>>
44
+ >>> with Connection("Server=localhost;Database=test;Trusted_Connection=yes") as conn:
45
+ ... result = conn.execute_with_python_params(
46
+ ... "SELECT COUNT(*) as count FROM users WHERE active = ?",
47
+ ... [True]
48
+ ... )
49
+ ... print(f"Active users: {result[0]['count']}")
50
+
51
+ Advanced Configuration:
52
+ >>> from fastmssql import Connection, PoolConfig, SslConfig, EncryptionLevel
53
+ >>>
54
+ >>> # Configure connection pool
55
+ >>> pool_config = PoolConfig(
56
+ ... max_connections=20,
57
+ ... min_connections=2,
58
+ ... acquire_timeout_seconds=30,
59
+ ... idle_timeout_seconds=600
60
+ ... )
61
+ >>>
62
+ >>> # Configure SSL/TLS
63
+ >>> ssl_config = SslConfig(
64
+ ... encryption_level=EncryptionLevel.Required,
65
+ ... trust_server_certificate=False,
66
+ ... certificate_path="/path/to/cert.pem"
67
+ ... )
68
+ >>>
69
+ >>> conn = Connection(
70
+ ... server="myserver.database.windows.net",
71
+ ... database="mydatabase",
72
+ ... username="myuser",
73
+ ... password="mypassword",
74
+ ... pool_config=pool_config,
75
+ ... ssl_config=ssl_config
76
+ ... )
77
+
78
+ Performance Considerations:
79
+ - Use parameterized queries to prevent SQL injection and improve performance
80
+ - Leverage connection pooling for applications with multiple concurrent operations
81
+ - Use async methods for I/O-bound applications to improve throughput
82
+ - Consider batch operations for bulk data manipulation
83
+ - Monitor connection pool statistics to optimize pool configuration
84
+
85
+ Thread Safety:
86
+ This library is thread-safe and can be used in multi-threaded applications.
87
+ Each Connection instance maintains its own connection pool and can be safely
88
+ shared across threads when using async methods.
13
89
  """
14
90
 
15
- # Import everything from the main API module
16
- from .fastmssql import *
91
+ # Import from the maturin-generated module
92
+ from .fastmssql import Connection as _RustConnection
93
+ from .fastmssql import PoolConfig
94
+ from .fastmssql import SslConfig
95
+ from .fastmssql import FastExecutionResult
96
+ from .fastmssql import version, EncryptionLevel, Parameter, Parameters
97
+
98
+ # Wrapper class to handle async execution result conversion
99
+ class Connection:
100
+ """
101
+ High-performance connection to Microsoft SQL Server.
102
+
103
+ This class provides a Python wrapper around the Rust-based connection implementation,
104
+ offering both synchronous and asynchronous database operations with advanced features
105
+ like connection pooling, SSL/TLS configuration, and efficient parameter handling.
106
+
107
+ The Connection class supports multiple initialization patterns:
108
+ 1. Connection string-based initialization
109
+ 2. Individual parameter initialization
110
+ 3. Advanced configuration with pool and SSL settings
111
+
112
+ Connection Patterns:
113
+ # Using connection string
114
+ conn = Connection("Server=localhost;Database=test;Trusted_Connection=yes")
115
+
116
+ # Using individual parameters
117
+ conn = Connection(
118
+ server="localhost",
119
+ database="test",
120
+ trusted_connection=True
121
+ )
122
+
123
+ # Using username/password authentication
124
+ conn = Connection(
125
+ server="myserver.database.windows.net",
126
+ database="mydatabase",
127
+ username="myuser",
128
+ password="mypassword"
129
+ )
130
+
131
+ Thread Safety:
132
+ This class is thread-safe and maintains an internal connection pool that can
133
+ be safely accessed from multiple threads when using async methods.
134
+
135
+ Performance Notes:
136
+ - Async methods are recommended for I/O-bound applications
137
+ - Connection pooling is automatically managed for optimal resource usage
138
+ - Parameterized queries provide better performance and security
139
+ - Results are streamed efficiently to minimize memory usage
140
+
141
+ Attributes:
142
+ _conn: The underlying Rust connection implementation
143
+ """
144
+
145
+ def __init__(
146
+ self,
147
+ connection_string=None,
148
+ pool_config=None,
149
+ ssl_config=None,
150
+ server=None,
151
+ database=None,
152
+ username=None,
153
+ password=None,
154
+ trusted_connection=None
155
+ ):
156
+ """
157
+ Initialize a new SQL Server connection.
158
+
159
+ Args:
160
+ connection_string (str, optional): Complete ADO.NET-style connection string.
161
+ Takes precedence over individual parameters if provided.
162
+ Example: "Server=localhost;Database=test;Trusted_Connection=yes"
163
+
164
+ pool_config (PoolConfig, optional): Configuration for the connection pool.
165
+ Allows customization of pool size, timeouts, and behavior.
166
+
167
+ ssl_config (SslConfig, optional): SSL/TLS configuration for secure connections.
168
+ Required for encrypted connections to Azure SQL Database and other
169
+ secure SQL Server instances.
170
+
171
+ server (str, optional): SQL Server hostname or IP address.
172
+ Can include instance name (e.g., "localhost\\SQLEXPRESS") or port
173
+ (e.g., "localhost:1433").
174
+
175
+ database (str, optional): Name of the database to connect to.
176
+ If not specified, connects to the default database for the user.
177
+
178
+ username (str, optional): Username for SQL Server authentication.
179
+ Required when not using Windows Authentication.
180
+
181
+ password (str, optional): Password for SQL Server authentication.
182
+ Required when username is provided.
183
+
184
+ trusted_connection (bool, optional): Whether to use Windows Authentication.
185
+ When True, uses the current Windows user's credentials.
186
+ Mutually exclusive with username/password.
187
+
188
+ Raises:
189
+ ValueError: If connection parameters are invalid or conflicting.
190
+ ConnectionError: If unable to establish initial connection pool.
191
+
192
+ Examples:
193
+ # Connection string approach
194
+ >>> conn = Connection("Server=localhost;Database=AdventureWorks;Trusted_Connection=yes")
195
+
196
+ # Individual parameters
197
+ >>> conn = Connection(
198
+ ... server="localhost",
199
+ ... database="AdventureWorks",
200
+ ... trusted_connection=True
201
+ ... )
202
+
203
+ # SQL Server authentication
204
+ >>> conn = Connection(
205
+ ... server="myserver.database.windows.net",
206
+ ... database="mydatabase",
207
+ ... username="myuser@mydomain.com",
208
+ ... password="SecurePassword123!"
209
+ ... )
210
+
211
+ # With advanced configuration
212
+ >>> from fastmssql import PoolConfig, SslConfig, EncryptionLevel
213
+ >>> pool_config = PoolConfig(max_connections=10, min_connections=2)
214
+ >>> ssl_config = SslConfig(encryption_level=EncryptionLevel.Required)
215
+ >>> conn = Connection(
216
+ ... server="secure-server.example.com",
217
+ ... database="production_db",
218
+ ... username="app_user",
219
+ ... password="app_password",
220
+ ... pool_config=pool_config,
221
+ ... ssl_config=ssl_config
222
+ ... )
223
+ """
224
+ self._conn = _RustConnection(
225
+ connection_string=connection_string,
226
+ pool_config=pool_config,
227
+ ssl_config=ssl_config,
228
+ server=server,
229
+ database=database,
230
+ username=username,
231
+ password=password,
232
+ trusted_connection=trusted_connection
233
+ )
234
+
235
+ async def execute(self, query, parameters=None):
236
+ """
237
+ Execute a SQL query asynchronously and return a FastExecutionResult.
238
+
239
+ This method executes SQL queries with optional parameterization for security
240
+ and performance. It supports all types of SQL statements including SELECT,
241
+ INSERT, UPDATE, DELETE, and stored procedure calls.
242
+
243
+ Parameter Binding:
244
+ Parameters are bound using positional placeholders (@P1, @P2, etc.) in the
245
+ query string. The parameter values are provided as a list in the same order.
246
+
247
+ Supported Parameter Types:
248
+ - None (NULL)
249
+ - bool
250
+ - int (32-bit and 64-bit)
251
+ - float (32-bit and 64-bit)
252
+ - str (varchar, nvarchar, text)
253
+ - bytes (varbinary, image)
254
+ - datetime.datetime (datetime, datetime2)
255
+ - datetime.date (date)
256
+ - datetime.time (time)
257
+ - decimal.Decimal (decimal, money)
258
+ - uuid.UUID (uniqueidentifier)
259
+
260
+ Args:
261
+ query (str): SQL query to execute. Use @P1, @P2, etc. for parameters.
262
+ Example: "SELECT * FROM users WHERE age > @P1 AND city = @P2"
263
+
264
+ parameters (list, optional): List of parameter values in order.
265
+ Values are automatically converted to appropriate SQL types.
266
+ Example: [18, "New York"]
267
+
268
+ Returns:
269
+ FastExecutionResult: An async iterable result object that provides:
270
+ - Async iteration over result rows
271
+ - fetchone(), fetchmany(), fetchall() methods
272
+ - Row count and column metadata
273
+ - Efficient memory usage for large result sets
274
+
275
+ Raises:
276
+ SqlError: If the SQL query contains syntax errors or constraint violations.
277
+ ConnectionError: If the database connection is lost during execution.
278
+ TimeoutError: If the query execution exceeds configured timeouts.
279
+ ParameterError: If parameter types cannot be converted or are invalid.
280
+
281
+ Examples:
282
+ # Simple SELECT query
283
+ >>> result = await conn.execute("SELECT * FROM users")
284
+ >>> async for row in result:
285
+ ... print(f"User ID: {row['id']}, Name: {row['name']}")
286
+
287
+ # Parameterized query
288
+ >>> result = await conn.execute(
289
+ ... "SELECT * FROM orders WHERE created_date > @P1 AND amount > @P2",
290
+ ... [datetime(2023, 1, 1), 100.0]
291
+ ... )
292
+ >>> rows = await result.fetchall()
293
+ >>> print(f"Found {len(rows)} orders")
294
+
295
+ # INSERT with parameters
296
+ >>> result = await conn.execute(
297
+ ... "INSERT INTO users (name, email, age) VALUES (@P1, @P2, @P3)",
298
+ ... ["John Doe", "john@example.com", 30]
299
+ ... )
300
+ >>> print(f"Inserted {result.rowcount} row(s)")
301
+
302
+ # Stored procedure call
303
+ >>> result = await conn.execute(
304
+ ... "EXEC GetUsersByDepartment @P1, @P2",
305
+ ... ["Engineering", True] # department, active_only
306
+ ... )
307
+ >>> users = await result.fetchall()
308
+
309
+ # Complex query with multiple data types
310
+ >>> from decimal import Decimal
311
+ >>> from datetime import datetime
312
+ >>> import uuid
313
+ >>>
314
+ >>> result = await conn.execute(
315
+ ... \"\"\"UPDATE products
316
+ ... SET price = @P1, updated_date = @P2, active = @P3
317
+ ... WHERE product_id = @P4\"\"\",
318
+ ... [Decimal('29.99'), datetime.now(), True, uuid.uuid4()]
319
+ ... )
320
+
321
+ Performance Tips:
322
+ - Use parameterized queries instead of string formatting for better performance
323
+ - For large result sets, iterate asynchronously rather than calling fetchall()
324
+ - Reuse Connection instances to benefit from connection pooling
325
+ - Consider batch operations for bulk data manipulation
326
+
327
+ Security Notes:
328
+ - Always use parameterized queries to prevent SQL injection attacks
329
+ - Parameter values are automatically escaped and type-checked
330
+ - Never concatenate user input directly into SQL query strings
331
+ """
332
+ # The Rust implementation now returns results directly
333
+ return await self._conn.execute(query, parameters)
334
+
335
+ def execute_with_python_params(self, query, params):
336
+ """
337
+ Execute a SQL query synchronously with Python-style parameter substitution.
338
+
339
+ This method provides a synchronous interface for executing SQL queries with
340
+ parameter substitution using Python's DB-API 2.0 style placeholders (?).
341
+ It's designed for compatibility with existing Python database code and
342
+ simple synchronous operations.
343
+
344
+ Parameter Binding:
345
+ Uses question mark (?) placeholders in the query string, with parameters
346
+ provided as a list in the same order as the placeholders appear.
347
+
348
+ Note:
349
+ This is a synchronous method that blocks until the query completes.
350
+ For better performance in async applications, prefer the async execute() method.
351
+
352
+ Args:
353
+ query (str): SQL query with ? placeholders for parameters.
354
+ Example: "SELECT * FROM users WHERE age > ? AND city = ?"
355
+
356
+ params (list): List of parameter values in order of appearance.
357
+ Values are automatically converted to appropriate SQL types.
358
+ Example: [18, "New York"]
359
+
360
+ Returns:
361
+ list: A list of dictionaries representing the result rows.
362
+ Each dictionary maps column names to values.
363
+ For non-SELECT queries, returns an empty list.
364
+
365
+ Raises:
366
+ SqlError: If the SQL query contains syntax errors or constraint violations.
367
+ ConnectionError: If the database connection is not available.
368
+ ParameterError: If parameter types cannot be converted or are invalid.
369
+
370
+ Examples:
371
+ # Simple SELECT query
372
+ >>> rows = conn.execute_with_python_params(
373
+ ... "SELECT id, name, email FROM users WHERE active = ?",
374
+ ... [True]
375
+ ... )
376
+ >>> for row in rows:
377
+ ... print(f"User: {row['name']} ({row['email']})")
378
+
379
+ # INSERT operation
380
+ >>> conn.execute_with_python_params(
381
+ ... "INSERT INTO logs (message, level, timestamp) VALUES (?, ?, ?)",
382
+ ... ["Application started", "INFO", datetime.now()]
383
+ ... )
384
+
385
+ # UPDATE with multiple parameters
386
+ >>> conn.execute_with_python_params(
387
+ ... "UPDATE users SET last_login = ?, login_count = login_count + 1 WHERE id = ?",
388
+ ... [datetime.now(), 12345]
389
+ ... )
390
+
391
+ # Complex query with various data types
392
+ >>> from decimal import Decimal
393
+ >>> rows = conn.execute_with_python_params(
394
+ ... \"\"\"SELECT p.name, p.price, c.name as category
395
+ ... FROM products p
396
+ ... JOIN categories c ON p.category_id = c.id
397
+ ... WHERE p.price BETWEEN ? AND ? AND p.discontinued = ?\"\"\",
398
+ ... [Decimal('10.00'), Decimal('100.00'), False]
399
+ ... )
400
+
401
+ Migration from DB-API 2.0:
402
+ This method is designed to be compatible with Python's DB-API 2.0
403
+ specification, making it easier to migrate from libraries like pyodbc
404
+ or pymssql with minimal code changes.
405
+
406
+ # Old pyodbc code:
407
+ # cursor.execute("SELECT * FROM users WHERE id = ?", [user_id])
408
+ # rows = cursor.fetchall()
409
+
410
+ # New fastmssql code:
411
+ # rows = conn.execute_with_python_params("SELECT * FROM users WHERE id = ?", [user_id])
412
+
413
+ Performance Considerations:
414
+ - This method is synchronous and will block the calling thread
415
+ - For high-throughput applications, use the async execute() method instead
416
+ - Connection pooling is still utilized for efficient resource management
417
+ - Results are loaded entirely into memory, so be cautious with large result sets
418
+ """
419
+ return self._conn.execute_with_python_params(query, params)
420
+
421
+ async def is_connected(self):
422
+ """
423
+ Check if the connection is active and available for queries.
424
+
425
+ This method performs a lightweight check to determine if the underlying
426
+ connection pool has active connections and can accept new queries.
427
+ It's useful for health checks and connection validation in long-running
428
+ applications.
429
+
430
+ The check verifies:
431
+ - Connection pool is initialized and operational
432
+ - At least one connection in the pool is active
433
+ - Network connectivity to the SQL Server instance
434
+ - Authentication credentials are still valid
435
+
436
+ Returns:
437
+ bool: True if the connection is active and ready for queries,
438
+ False if the connection is closed, failed, or unavailable.
439
+
440
+ Raises:
441
+ ConnectionError: If there's an unexpected error checking connection status.
442
+
443
+ Examples:
444
+ # Basic connection check
445
+ >>> if await conn.is_connected():
446
+ ... result = await conn.execute("SELECT COUNT(*) FROM users")
447
+ ... else:
448
+ ... await conn.connect() # Reconnect if needed
449
+
450
+ # Health check in a web application
451
+ >>> async def health_check():
452
+ ... try:
453
+ ... if await conn.is_connected():
454
+ ... return {"database": "healthy", "status": "connected"}
455
+ ... else:
456
+ ... return {"database": "unhealthy", "status": "disconnected"}
457
+ ... except Exception as e:
458
+ ... return {"database": "error", "status": str(e)}
459
+
460
+ # Periodic connection monitoring
461
+ >>> import asyncio
462
+ >>>
463
+ >>> async def monitor_connection():
464
+ ... while True:
465
+ ... if await conn.is_connected():
466
+ ... print(f"{datetime.now()}: Database connection is healthy")
467
+ ... else:
468
+ ... print(f"{datetime.now()}: Database connection is down!")
469
+ ... # Attempt to reconnect
470
+ ... try:
471
+ ... await conn.connect()
472
+ ... print("Reconnection successful")
473
+ ... except Exception as e:
474
+ ... print(f"Reconnection failed: {e}")
475
+ ...
476
+ ... await asyncio.sleep(60) # Check every minute
477
+
478
+ Performance Notes:
479
+ - This is a lightweight operation that doesn't execute actual SQL
480
+ - The check uses connection pool metadata and cached connection state
481
+ - Suitable for frequent health checks without performance impact
482
+ - Does not count against connection pool limits
483
+
484
+ Use Cases:
485
+ - Application startup validation
486
+ - Periodic health monitoring
487
+ - Circuit breaker pattern implementation
488
+ - Load balancer health checks
489
+ - Graceful degradation in microservices
490
+ """
491
+ return await self._conn.is_connected()
492
+
493
+ async def pool_stats(self):
494
+ """
495
+ Get comprehensive connection pool statistics and health metrics.
496
+
497
+ This method provides detailed information about the current state of the
498
+ connection pool, including active connections, idle connections, and
499
+ configuration parameters. It's essential for monitoring, debugging, and
500
+ optimizing connection pool performance in production environments.
501
+
502
+ The statistics help identify:
503
+ - Connection pool utilization patterns
504
+ - Potential connection leaks
505
+ - Optimal pool sizing configuration
506
+ - Performance bottlenecks
507
+ - Resource contention issues
508
+
509
+ Returns:
510
+ dict: A dictionary containing pool statistics with the following keys:
511
+
512
+ When connected:
513
+ - 'connections' (int): Total number of connections in the pool
514
+ - 'idle_connections' (int): Number of idle connections available
515
+ - 'active_connections' (int): Number of connections currently in use
516
+ - 'max_size' (int): Maximum allowed connections in the pool
517
+ - 'min_idle' (int): Minimum idle connections maintained
518
+
519
+ When disconnected:
520
+ - 'connected' (bool): False, indicating no active pool
521
+
522
+ Raises:
523
+ ConnectionError: If unable to retrieve pool statistics due to connection issues.
524
+
525
+ Examples:
526
+ # Basic pool monitoring
527
+ >>> stats = await conn.pool_stats()
528
+ >>> if stats.get('connected', True): # Handle disconnected case
529
+ ... print(f"Active connections: {stats['active_connections']}")
530
+ ... print(f"Idle connections: {stats['idle_connections']}")
531
+ ... print(f"Pool utilization: {stats['active_connections']/stats['max_size']*100:.1f}%")
532
+
533
+ # Comprehensive pool monitoring
534
+ >>> async def monitor_pool():
535
+ ... stats = await conn.pool_stats()
536
+ ...
537
+ ... if not stats.get('connected', True):
538
+ ... print("❌ Connection pool is not active")
539
+ ... return
540
+ ...
541
+ ... total = stats['connections']
542
+ ... active = stats['active_connections']
543
+ ... idle = stats['idle_connections']
544
+ ... max_size = stats['max_size']
545
+ ... min_idle = stats['min_idle']
546
+ ...
547
+ ... utilization = (active / max_size) * 100
548
+ ...
549
+ ... print(f"📊 Connection Pool Statistics:")
550
+ ... print(f" Total connections: {total}")
551
+ ... print(f" Active connections: {active}")
552
+ ... print(f" Idle connections: {idle}")
553
+ ... print(f" Max pool size: {max_size}")
554
+ ... print(f" Min idle: {min_idle}")
555
+ ... print(f" Utilization: {utilization:.1f}%")
556
+ ...
557
+ ... # Health assessment
558
+ ... if utilization > 90:
559
+ ... print("⚠️ High pool utilization - consider increasing max_size")
560
+ ... elif idle < min_idle:
561
+ ... print("⚠️ Low idle connections - pool may be under pressure")
562
+ ... elif utilization < 10 and total > min_idle * 2:
563
+ ... print("ℹ️ Low utilization - consider reducing max_size")
564
+ ... else:
565
+ ... print("✅ Pool appears healthy")
566
+
567
+ # Pool statistics for alerting
568
+ >>> async def check_pool_health():
569
+ ... stats = await conn.pool_stats()
570
+ ...
571
+ ... if not stats.get('connected', True):
572
+ ... return {"status": "critical", "message": "Pool disconnected"}
573
+ ...
574
+ ... utilization = stats['active_connections'] / stats['max_size']
575
+ ... idle_ratio = stats['idle_connections'] / stats['max_size']
576
+ ...
577
+ ... if utilization > 0.9:
578
+ ... return {
579
+ ... "status": "warning",
580
+ ... "message": f"High utilization: {utilization:.1%}",
581
+ ... "stats": stats
582
+ ... }
583
+ ... elif idle_ratio < 0.1:
584
+ ... return {
585
+ ... "status": "warning",
586
+ ... "message": f"Low idle connections: {stats['idle_connections']}",
587
+ ... "stats": stats
588
+ ... }
589
+ ... else:
590
+ ... return {"status": "healthy", "stats": stats}
591
+
592
+ # Logging pool metrics
593
+ >>> import logging
594
+ >>>
595
+ >>> async def log_pool_metrics():
596
+ ... stats = await conn.pool_stats()
597
+ ... if stats.get('connected', True):
598
+ ... logging.info(
599
+ ... "Pool metrics: active=%d, idle=%d, total=%d, utilization=%.1f%%",
600
+ ... stats['active_connections'],
601
+ ... stats['idle_connections'],
602
+ ... stats['connections'],
603
+ ... (stats['active_connections'] / stats['max_size']) * 100
604
+ ... )
605
+
606
+ Monitoring Best Practices:
607
+ - Monitor pool utilization during peak load periods
608
+ - Set up alerts for utilization > 80% or idle connections < min_idle
609
+ - Track connection acquisition times and pool exhaustion events
610
+ - Use metrics for capacity planning and performance optimization
611
+ - Log pool statistics periodically for historical analysis
612
+
613
+ Performance Impact:
614
+ - This operation has minimal performance overhead
615
+ - Safe to call frequently for monitoring purposes
616
+ - Does not affect active connections or pool operation
617
+ - Recommended for inclusion in health check endpoints
618
+ """
619
+ result_tuple = await self._conn.pool_stats()
620
+
621
+ # Convert tuple to dictionary
622
+ connected, connections, idle_connections, max_size, min_idle = result_tuple
623
+
624
+ if connected:
625
+ return {
626
+ 'connections': connections,
627
+ 'idle_connections': idle_connections,
628
+ 'max_size': max_size,
629
+ 'min_idle': min_idle,
630
+ 'active_connections': connections - idle_connections,
631
+ }
632
+ else:
633
+ return {'connected': False}
634
+
635
+ async def connect(self):
636
+ """Explicitly connect to the database."""
637
+ return await self._conn.connect()
638
+
639
+ async def disconnect(self):
640
+ """Explicitly disconnect from the database."""
641
+ return await self._conn.disconnect()
642
+
643
+ async def __aenter__(self):
644
+ await self._conn.__aenter__()
645
+ return self
646
+
647
+ async def __aexit__(self, exc_type, exc_val, exc_tb):
648
+ await self._conn.__aexit__(exc_type, exc_val, exc_tb)
649
+ return None
650
+
651
+ def __enter__(self):
652
+ return self._conn.__enter__()
653
+
654
+ def __exit__(self, exc_type, exc_val, exc_tb):
655
+ return self._conn.__exit__(exc_type, exc_val, exc_tb)
656
+
657
+ # Preserve module documentation
658
+ if hasattr(_RustConnection, "__doc__"):
659
+ __doc__ = _RustConnection.__doc__
17
660
 
18
- __version__ = version()
661
+ __all__ = ["Connection", "PoolConfig", "SslConfig", "FastExecutionResult", "version", "EncryptionLevel", "Parameter", "Parameters"]