fastmssql 0.2.1__cp313-cp313-macosx_11_0_arm64.whl → 0.3.0__cp313-cp313-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.

@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fastmssql
3
- Version: 0.2.1
3
+ Version: 0.3.0
4
4
  Classifier: Development Status :: 4 - Beta
5
5
  Classifier: Intended Audience :: Developers
6
- Classifier: License :: Other/Proprietary License
6
+ Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
7
7
  Classifier: Programming Language :: Python :: 3
8
8
  Classifier: Programming Language :: Python :: 3.8
9
9
  Classifier: Programming Language :: Python :: 3.9
@@ -21,37 +21,81 @@ Provides-Extra: dev
21
21
  License-File: LICENSE
22
22
  Summary: A high-performance Python library for Microsoft SQL Server using Rust and Tiberius
23
23
  Author-email: Riveranda <riverb514@gmail.com>
24
- License: PolyForm Noncommercial License 1.0.0
24
+ License: GPL-3.0-or-later OR Commercial
25
25
  Requires-Python: >=3.8
26
26
  Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
27
27
  Project-URL: Homepage, https://github.com/Rivendael/pymssql-rs
28
28
 
29
29
 
30
- # Fastmssql
30
+ # Fastmssql
31
31
 
32
- A high-performance Python library for Microsoft SQL Server, built with Rust using the [Tiberius](https://github.com/prisma/tiberius) driver, [PyO3](https://github.com/PyO3/pyo3), and [bb8](https://github.com/djc/bb8) connection pooling.
32
+ A Python library for Microsoft SQL Server built with Rust using the [Tiberius](https://github.com/prisma/tiberius) driver, [PyO3](https://github.com/PyO3/pyo3), and [bb8](https://github.com/djc/bb8) connection pooling.
33
+
34
+ [![Language](https://img.shields.io/badge/Language-Rust_Backend-red)](https://github.com/Rivendael/pymssql-rs)
35
+ [![Async](https://img.shields.io/badge/Async-Native_Tokio-blue)](https://github.com/Rivendael/pymssql-rs)
36
+ [![Performance](https://img.shields.io/badge/Performance-17%2C800%2B_RPS-brightgreen)](https://github.com/Rivendael/pymssql-rs)
33
37
 
34
38
  ## Features
35
39
 
36
- - **High Performance**: Built with Rust for memory safety and speed
37
- - **Connection Pooling**: Advanced bb8-based connection pool for optimal performance
38
- - **Async-Only Design**: Built on Tokio for excellent concurrency with clean async/await API
40
+ - **High Performance**: Exceptional throughput with 17,800+ RPS capability
41
+ - **Rust-Powered Backend**: Built with Rust for memory safety and reliability
42
+ - **No ODBC Required**: Direct native SQL Server connection without ODBC drivers
43
+ - **Connection Pooling**: Intelligent bb8-based connection pooling (default: 75 max, 25 min idle)
44
+ - **Async-Only Design**: Built on Tokio with clean async/await API
39
45
  - **Context Managers**: Automatic resource management with `async with`
40
46
  - **Type Safety**: Strong typing with automatic Python type conversion
41
- - **Thread Safety**: Full support for concurrent operations
47
+ - **Thread Safety**: Support for concurrent operations
42
48
  - **Cross-Platform**: Works on Windows, macOS, and Linux
43
- - **Simple API**: Clean, intuitive async-only interface
49
+ - **Simple API**: Clean, intuitive async-only interface with separate `query()` and `execute()` methods
50
+
51
+ ## Key API Methods
52
+
53
+ FastMSSQL provides two distinct methods for database operations:
54
+
55
+ - **`query()`** - For SELECT statements that return rows
56
+ - **`execute()`** - For INSERT/UPDATE/DELETE statements that return affected row count
57
+
58
+ ```python
59
+ # Use query() for SELECT statements
60
+ result = await conn.query("SELECT * FROM users WHERE age > @P1", [25])
61
+ rows = result.rows()
62
+
63
+ # Use execute() for data modification
64
+ affected = await conn.execute("INSERT INTO users (name) VALUES (@P1)", ["John"])
65
+ ```
66
+
67
+ ## Performance Highlights
68
+
69
+ Fastmssql delivers exceptional database performance through Rust-powered architecture:
70
+
71
+ - **Outstanding Throughput**: Up to **17,800+ RPS** with multiple connection pattern
72
+ - **High Performance**: **5,000+ RPS** with single connection (default usage)
73
+ - **Low Latency**: ~2ms average query latency under high load
74
+ - **Scalable Architecture**: Linear scaling with multiple connection objects
75
+ - **Production Ready**: Stable API with comprehensive error handling
76
+ - **Connection Pooling**: Efficient resource management with configurable pools
77
+ - **Type Conversion**: Automatic conversion between SQL Server and Python types
78
+ - **SSL/TLS Support**: Secure connections with flexible encryption options
44
79
 
45
- ## Connection Pool Benefits
80
+ ### Performance Benchmarks
46
81
 
47
- This library uses the high-performance **bb8 connection pool** which provides:
82
+ | Pattern | RPS | Configuration | Use Case |
83
+ |---------|-----|---------------|----------|
84
+ | Single Connection (Default) | **5,000+** | Default pool (75/25) | Standard applications |
85
+ | Multiple Connections | **17,800+** | 50 workers, high_throughput() | High-concurrency scenarios |
86
+ | Conservative Load | 3,500+ | Shared connection | Traditional pooling |
48
87
 
49
- - **Connection Reuse**: Eliminates connection setup overhead
50
- - **Concurrent Operations**: Multiple queries run simultaneously using pool connections
51
- - **Automatic Health Management**: Built-in connection validation and recovery
52
- - **Configurable Scaling**: Pool size adapts to your workload requirements
53
- - **Thread Safety**: Safe concurrent access from multiple threads
54
- - **Resource Management**: Automatic connection cleanup and lifecycle management
88
+ **Benchmark Environment:**
89
+ - Database: SQL Server (local instance)
90
+ - Query: `SELECT 1` (minimal overhead)
91
+ - Test Duration: 15-30 seconds per test
92
+ - Hardware: Modern development machine
93
+
94
+ **Key Performance Insights:**
95
+ 1. **Multiple Connection Objects**: Creating separate `Connection()` objects eliminates serialization bottlenecks
96
+ 2. **Pool Configuration**: Use `PoolConfig.high_throughput()` for demanding workloads
97
+ 3. **Optimal Worker Count**: 30-50 concurrent workers provides best throughput
98
+ 4. **Tokio Optimization**: Aggressive threading configuration maximizes async performance
55
99
 
56
100
  ## Installation
57
101
 
@@ -69,7 +113,7 @@ pip install fastmssql
69
113
  - Microsoft SQL Server (any recent version)
70
114
 
71
115
  ### From Source (Development)
72
-
116
+ Ensure you have Docker, Rust, and Python installed.
73
117
  If you want to build from source or contribute to development:
74
118
 
75
119
  1. Clone the repository:
@@ -78,21 +122,9 @@ git clone <your-repo-url>
78
122
  cd mssql-python-rust
79
123
  ```
80
124
 
81
- 2. Install Rust if you haven't already:
82
- ```bash
83
- curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
84
- source $HOME/.cargo/env
85
- ```
86
-
87
- 3. Install maturin:
88
- ```bash
89
- pip install maturin
125
+ 2. Run the setup script
90
126
  ```
91
-
92
- 4. Build and install the package:
93
- ```bash
94
- # Or manually
95
- maturin develop --release
127
+ ./setup.sh
96
128
  ```
97
129
 
98
130
  ## Quick Start
@@ -109,7 +141,9 @@ async def main():
109
141
 
110
142
  # Automatic connection pool management
111
143
  async with Connection(connection_string) as conn:
112
- rows = await conn.execute("SELECT @@VERSION as version")
144
+ # Use query() for SELECT statements that return rows
145
+ result = await conn.query("SELECT @@VERSION as version")
146
+ rows = result.rows()
113
147
  for row in rows:
114
148
  print(row['version'])
115
149
 
@@ -135,8 +169,10 @@ async def main():
135
169
  connection_string = "Server=localhost;Database=master;User Id=myuser;Password=mypass"
136
170
 
137
171
  async with Connection(connection_string=connection_string) as conn:
138
- result = await conn.execute("SELECT @@VERSION as version")
139
- for row in result.rows():
172
+ # Use query() for SELECT statements that return rows
173
+ result = await conn.query("SELECT @@VERSION as version")
174
+ rows = result.rows()
175
+ for row in rows:
140
176
  print(row['version'])
141
177
 
142
178
  asyncio.run(main())
@@ -158,13 +194,50 @@ async def main():
158
194
  username="myuser",
159
195
  password="mypassword"
160
196
  ) as conn:
161
- result = await conn.execute("SELECT SUSER_NAME() as login")
162
- for row in result.rows():
197
+ # Use query() for SELECT statements that return rows
198
+ result = await conn.query("SELECT SUSER_NAME() as login")
199
+ rows = result.rows()
200
+ for row in rows:
163
201
  print(f"Logged in as: {row['login']}")
164
202
 
165
203
  asyncio.run(main())
166
204
  ```
167
205
 
206
+ ### Performance Patterns
207
+
208
+ For maximum performance in high-concurrency scenarios, create multiple Connection objects:
209
+
210
+ ```python
211
+ import asyncio
212
+ from fastmssql import Connection, PoolConfig
213
+
214
+ async def high_performance_pattern():
215
+ """Optimal pattern for maximum throughput."""
216
+ connection_string = "Server=localhost;Database=master;User Id=myuser;Password=mypass"
217
+ config = PoolConfig.high_throughput() # Optimized settings
218
+
219
+ async def worker():
220
+ # Each worker gets its own Connection object for maximum throughput
221
+ async with Connection(connection_string, pool_config=config) as conn:
222
+ for _ in range(1000):
223
+ # Use query() for SELECT statements that return rows
224
+ result = await conn.query("SELECT data FROM my_table WHERE id = @P1", [123])
225
+ rows = result.rows()
226
+ # Process results...
227
+
228
+ # Launch multiple workers - each with their own connection
229
+ workers = [asyncio.create_task(worker()) for _ in range(50)]
230
+ await asyncio.gather(*workers)
231
+
232
+ # This pattern can achieve 17,800+ RPS
233
+
234
+ asyncio.run(high_performance_pattern())
235
+ ```
236
+
237
+ **Key Performance Insight**: While a single Connection object provides excellent performance (5,000+ RPS),
238
+ creating multiple Connection objects eliminates serialization bottlenecks and can achieve 17,800+ RPS
239
+ for maximum throughput scenarios.
240
+
168
241
  ### Connection Pool Configuration
169
242
 
170
243
  Configure the connection pool for your specific needs:
@@ -184,33 +257,36 @@ async def main():
184
257
  )
185
258
 
186
259
  async with Connection(connection_string, pool_config) as conn:
187
- result = await conn.execute("SELECT * FROM users")
260
+ # Use query() for SELECT statements that return rows
261
+ result = await conn.query("SELECT * FROM users")
262
+ rows = result.rows()
263
+ for row in rows:
264
+ print(f"User: {row['name']}")
188
265
 
189
- # Predefined configurations for common scenarios
190
- high_throughput_config = PoolConfig.high_throughput() # 20 connections, optimized for load
191
- low_resource_config = PoolConfig.low_resource() # 3 connections, minimal resources
192
- dev_config = PoolConfig.development() # 5 connections, shorter timeouts
266
+ # Predefined configurations for different scenarios
267
+ high_throughput_config = PoolConfig.high_throughput() # 100 connections, optimized for high RPS
268
+ maximum_performance = PoolConfig.maximum_performance() # 150 connections, optimized for peak load
269
+ low_resource_config = PoolConfig.low_resource() # 3 connections, minimal resources
270
+ dev_config = PoolConfig.development() # 5 connections, shorter timeouts
271
+
272
+ # Default configuration is optimized for high performance
273
+ # Default: max_size=75, min_idle=25 - ready for production workloads
274
+
275
+ # For maximum throughput, use multiple Connection objects:
276
+ async def high_perf_worker():
277
+ async with Connection(connection_string, maximum_performance) as conn:
278
+ # Use query() for SELECT statements that return rows
279
+ result = await conn.query("SELECT * FROM fast_table")
280
+ return result.rows()
281
+
282
+ # Each worker gets its own connection for optimal performance
283
+ tasks = [asyncio.create_task(high_perf_worker()) for _ in range(50)]
284
+ results = await asyncio.gather(*tasks)
193
285
 
194
286
  asyncio.run(main())
195
287
  ```
196
288
 
197
- ### Connection Pool Benefits
198
-
199
- The bb8 connection pool provides significant performance improvements:
200
289
 
201
- | Scenario | Traditional | bb8 Pool | Improvement |
202
- |----------|-------------|----------|-------------|
203
- | Single Query | 50ms | 45ms | 10% faster |
204
- | 10 Concurrent | 500ms | 150ms | 3.3x faster |
205
- | 100 Concurrent | 5000ms | 400ms | 12.5x faster |
206
- | High Load | Timeouts | Stable | Reliable |
207
-
208
- **Key Benefits:**
209
- - **Connection Reuse**: Eliminates connection establishment overhead
210
- - **Concurrency**: Safe multi-threaded access with automatic pooling
211
- - **Resource Management**: Automatic cleanup prevents connection leaks
212
- - **Load Balancing**: Intelligent connection distribution across threads
213
- - **Timeouts**: Configurable timeouts prevent hanging connections
214
290
 
215
291
  ### Connection Strings
216
292
 
@@ -235,21 +311,37 @@ from fastmssql import Connection
235
311
 
236
312
  async def main():
237
313
  async with Connection(connection_string) as conn:
238
- # Execute queries
239
- users = await conn.execute("SELECT id, name, email FROM users WHERE active = 1")
314
+ # === SELECT QUERIES - Use query() method (returns rows) ===
315
+ result = await conn.query("SELECT id, name, email FROM users WHERE active = 1")
316
+ rows = result.rows()
240
317
 
241
318
  # Iterate through results
242
- for user in users:
243
- print(f"User {user['id']}: {user['name']} ({user['email']})")
319
+ for row in rows:
320
+ print(f"User {row['id']}: {row['name']} ({row['email']})")
244
321
 
245
- # Execute non-query operations
246
- rows_affected = await conn.execute_non_query(
247
- "UPDATE users SET last_login = GETDATE() WHERE id = 123"
322
+ # === DATA MODIFICATION - Use execute() method (returns affected row count) ===
323
+ # INSERT operation
324
+ rows_affected = await conn.execute(
325
+ "INSERT INTO users (name, email, active) VALUES (@P1, @P2, @P3)",
326
+ ["John Doe", "john@example.com", 1]
248
327
  )
249
- print(f"Updated {rows_affected} rows")
328
+ print(f"Inserted {rows_affected} row(s)")
250
329
 
251
- # Work with different data types
252
- data = await conn.execute("""
330
+ # UPDATE operation
331
+ rows_affected = await conn.execute(
332
+ "UPDATE users SET last_login = GETDATE() WHERE id = @P1",
333
+ [123]
334
+ )
335
+ print(f"Updated {rows_affected} row(s)")
336
+
337
+ # DELETE operation
338
+ rows_affected = await conn.execute(
339
+ "DELETE FROM users WHERE active = 0 AND last_login < DATEADD(year, -1, GETDATE())"
340
+ )
341
+ print(f"Deleted {rows_affected} inactive users")
342
+
343
+ # === WORKING WITH DIFFERENT DATA TYPES ===
344
+ result = await conn.query("""
253
345
  SELECT
254
346
  42 as int_value,
255
347
  3.14159 as float_value,
@@ -259,9 +351,11 @@ async def main():
259
351
  NULL as null_value
260
352
  """)
261
353
 
262
- row = data[0]
263
- for column_name, value in row.items():
264
- print(f"{column_name}: {value} (type: {type(value).__name__})")
354
+ rows = result.rows()
355
+ if rows:
356
+ row = rows[0]
357
+ for column_name, value in row.items():
358
+ print(f"{column_name}: {value} (type: {type(value).__name__})")
265
359
 
266
360
  asyncio.run(main())
267
361
  ```
@@ -281,7 +375,9 @@ async def main():
281
375
 
282
376
  # Async context manager with automatic pool management
283
377
  async with Connection(connection_string) as conn:
284
- rows = await conn.execute("SELECT name FROM sys.databases")
378
+ # Use query() for SELECT statements that return rows
379
+ result = await conn.query("SELECT name FROM sys.databases")
380
+ rows = result.rows()
285
381
  for row in rows:
286
382
  print(row['name'])
287
383
 
@@ -292,7 +388,9 @@ async def main():
292
388
  # High-performance concurrent operations
293
389
  async def fetch_user_data(user_id):
294
390
  async with Connection(connection_string) as conn:
295
- return await conn.execute(f"SELECT * FROM users WHERE id = {user_id}")
391
+ # Use query() for SELECT statements that return rows
392
+ result = await conn.query(f"SELECT * FROM users WHERE id = {user_id}")
393
+ return result.rows()
296
394
 
297
395
  # Execute multiple queries concurrently using the connection pool
298
396
  user_ids = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
@@ -306,89 +404,6 @@ async def main():
306
404
  asyncio.run(main())
307
405
  ```
308
406
 
309
- ### Performance Comparison: bb8 Connection Pool
310
-
311
- The bb8 connection pool dramatically improves performance, especially under load:
312
-
313
- ```python
314
- import asyncio
315
- import time
316
- from fastmssql import Connection
317
-
318
- async def performance_comparison():
319
- connection_string = "Server=localhost;Database=test;User Id=myuser;Password=mypass"
320
-
321
- # Sequential async operations (still efficient with pool reuse)
322
- start = time.time()
323
- async with Connection(connection_string) as conn:
324
- for i in range(10):
325
- result = await conn.execute("SELECT COUNT(*) FROM users")
326
- sequential_time = time.time() - start
327
-
328
- # Concurrent async operations (much faster with bb8 pool)
329
- start = time.time()
330
- async def concurrent_queries():
331
- tasks = []
332
- for i in range(10):
333
- async def query():
334
- async with Connection(connection_string) as conn: # Pool reuse
335
- return await conn.execute("SELECT COUNT(*) FROM users")
336
- tasks.append(query())
337
- return await asyncio.gather(*tasks)
338
-
339
- await concurrent_queries()
340
- concurrent_time = time.time() - start
341
-
342
- print(f"Sequential: {sequential_time:.3f}s")
343
- print(f"Concurrent: {concurrent_time:.3f}s")
344
- print(f"Improvement: {sequential_time/concurrent_time:.1f}x faster")
345
-
346
- asyncio.run(performance_comparison())
347
- ```
348
-
349
- **Real-world Performance Benefits:**
350
- - **Web Applications**: Handle 100+ concurrent requests without connection exhaustion
351
- - **Batch Processing**: Process large datasets with optimal resource usage
352
- - **Microservices**: Reliable database connections across service boundaries
353
- - **Data Analytics**: Concurrent query execution for faster insights
354
-
355
- ## Examples
356
-
357
- Run the provided examples to see async patterns and features:
358
-
359
- ```bash
360
- # Basic asynchronous usage
361
- python examples/basic_usage.py
362
-
363
- # Advanced asynchronous features
364
- python examples/advanced_usage.py
365
-
366
- # Asynchronous usage patterns
367
- python examples/async_usage.py
368
-
369
- # Advanced pool configuration
370
- python examples/advanced_pool_config.py
371
-
372
- # Connection parameters demonstration
373
- python examples/connection_parameters_demo.py
374
- ```
375
-
376
- ### Key API Improvements
377
-
378
- Our async-only design provides a clean, intuitive interface:
379
-
380
- ```python
381
- # ✅ Clean async API (New Design)
382
- async with Connection(connection_string) as conn:
383
- result = await conn.execute(sql) # Intuitive!
384
- rows_affected = await conn.execute_non_query(sql)
385
-
386
- # ❌ Old confusing API (Removed)
387
- # async with Connection(connection_string) as conn:
388
- # result = await conn.execute_async(sql) # Confusing suffixes
389
- # rows_affected = await conn.execute_non_query_async(sql)
390
- ```
391
-
392
407
  ## Development
393
408
 
394
409
  ### Building from Source
@@ -442,6 +457,29 @@ python examples/advanced_usage.py
442
457
 
443
458
  ## API Reference
444
459
 
460
+ ### Query vs Execute Methods
461
+
462
+ FastMSSQL provides two distinct methods for database operations:
463
+
464
+ - **`query()`** - For SELECT statements that return rows
465
+ - Returns a `QueryResult` object with a `rows()` method
466
+ - Use for retrieving data from the database
467
+
468
+ - **`execute()`** - For INSERT, UPDATE, DELETE statements
469
+ - Returns the number of affected rows as an integer
470
+ - Use for modifying data in the database
471
+
472
+ **SQL Server Parameter Syntax**: Use positional parameters `@P1`, `@P2`, `@P3`, etc.
473
+
474
+ ```python
475
+ # SELECT queries - use query()
476
+ result = await conn.query("SELECT * FROM users WHERE age > @P1 AND city = @P2", [25, "New York"])
477
+ rows = result.rows()
478
+
479
+ # INSERT/UPDATE/DELETE - use execute()
480
+ affected = await conn.execute("INSERT INTO users (name, email) VALUES (@P1, @P2)", ["John", "john@example.com"])
481
+ ```
482
+
445
483
  ### Core Classes
446
484
 
447
485
  #### `Connection`
@@ -454,21 +492,45 @@ Connection(connection_string: str, pool_config: Optional[PoolConfig] = None)
454
492
 
455
493
  **Context Manager Support:**
456
494
  ```python
457
- # Synchronous
458
- with Connection(conn_str) as conn:
459
- result = conn.execute("SELECT * FROM table")
460
-
461
- # Asynchronous
495
+ # Asynchronous (recommended)
462
496
  async with Connection(conn_str) as conn:
463
- result = await conn.execute_async("SELECT * FROM table")
497
+ # Use query() for SELECT statements
498
+ result = await conn.query("SELECT * FROM table")
499
+ rows = result.rows()
500
+
501
+ # Use execute() for INSERT/UPDATE/DELETE statements
502
+ affected = await conn.execute("INSERT INTO table (col) VALUES (@P1)", ["value"])
503
+ ```
464
504
  ```
465
505
 
466
506
  **Methods:**
467
- - `execute(sql: str) -> List[Row]` - Execute a query synchronously
507
+ - `query(sql: str, params: Optional[List] = None) -> QueryResult` - Execute SELECT queries that return rows
508
+ - `execute(sql: str, params: Optional[List] = None) -> int` - Execute INSERT/UPDATE/DELETE statements, returns affected row count
468
509
  - `pool_stats() -> dict` - Get connection pool statistics
469
510
  - `disconnect()` - Close the connection pool
470
511
  - `is_connected() -> bool` - Check if pool is active
471
512
 
513
+ **Method Details:**
514
+
515
+ `query()` - For SELECT statements that return data:
516
+ ```python
517
+ # Returns a QueryResult object with rows() method
518
+ result = await conn.query("SELECT * FROM users WHERE age > @P1", [21])
519
+ rows = result.rows()
520
+ for row in rows:
521
+ print(row['name'])
522
+ ```
523
+
524
+ `execute()` - For INSERT/UPDATE/DELETE statements:
525
+ ```python
526
+ # Returns the number of affected rows
527
+ affected = await conn.execute("INSERT INTO users (name) VALUES (@P1)", ["John"])
528
+ print(f"Inserted {affected} row(s)")
529
+
530
+ affected = await conn.execute("UPDATE users SET age = @P1 WHERE name = @P2", [25, "John"])
531
+ print(f"Updated {affected} row(s)")
532
+ ```
533
+
472
534
  **Pool Statistics:**
473
535
  ```python
474
536
  stats = conn.pool_stats()
@@ -519,15 +581,17 @@ Represents a database row with column access.
519
581
 
520
582
  #### Connection Management
521
583
  ```python
522
- # Create connection with default pool settings
523
- connect(connection_string: str) -> Connection
584
+ # Create connection with connection pooling
585
+ Connection(connection_string: str, pool_config: Optional[PoolConfig] = None) -> Connection
524
586
 
525
- # Create async connection with default pool settings
526
- connect_async(connection_string: str) -> Connection
527
-
528
- # One-liner query execution
529
- execute(connection_string: str, sql: str) -> List[dict]
530
- execute_async(connection_string: str, sql: str) -> List[dict]
587
+ # Usage with async context manager (recommended)
588
+ async with Connection(connection_string) as conn:
589
+ # Use query() for SELECT statements that return rows
590
+ result = await conn.query("SELECT * FROM users")
591
+ rows = result.rows()
592
+
593
+ # Use execute() for INSERT/UPDATE/DELETE statements that return affected count
594
+ affected = await conn.execute("INSERT INTO users (name) VALUES (@P1)", ["John"])
531
595
  ```
532
596
 
533
597
  #### Utility Functions
@@ -550,7 +614,8 @@ The library uses the bb8 connection pool for efficient resource management:
550
614
  ```python
551
615
  try:
552
616
  async with mssql.connect_async(connection_string) as conn:
553
- result = await conn.execute("SELECT * FROM invalid_table")
617
+ result = await conn.query("SELECT * FROM invalid_table")
618
+ rows = result.rows()
554
619
  except Exception as e:
555
620
  print(f"Database error: {e}")
556
621
  # Connection automatically returned to pool even on error
@@ -564,26 +629,14 @@ This library has been upgraded to use async-only operations with the bb8 connect
564
629
  ```python
565
630
  # Async-only with automatic connection pooling
566
631
  async with mssql.connect_async(conn_str) as conn:
567
- result = await conn.execute("SELECT * FROM table")
632
+ result = await conn.query("SELECT * FROM table")
633
+ rows = result.rows()
568
634
 
569
635
  # Pool statistics
570
636
  stats = conn.pool_stats()
571
637
  print(f"Pool utilization: {stats['active_connections']}/{stats['connections']}")
572
638
  ```
573
639
 
574
- **Features:**
575
- - Async-only operations for maximum performance
576
- - Automatic connection pooling with bb8
577
- - Configurable pool settings via `PoolConfig`
578
- - Pool statistics and monitoring
579
- - Improved concurrent performance
580
- - Better resource management
581
-
582
- **Breaking Changes:**
583
- - None - the API is fully backward compatible
584
- - All existing code continues to work without modification
585
- - Performance improvements are automatic
586
-
587
640
  ## Advanced Usage Patterns
588
641
 
589
642
  ### Custom Pool Configuration for Different Scenarios
@@ -649,7 +702,7 @@ async def oltp_operations():
649
702
  async with mssql.connect_async(conn_str, oltp_config) as conn:
650
703
  # Fast, concurrent transactions
651
704
  tasks = [
652
- conn.execute_async("SELECT * FROM users WHERE id = $1", [user_id])
705
+ conn.query("SELECT * FROM users WHERE id = @P1", [user_id])
653
706
  for user_id in range(1, 101)
654
707
  ]
655
708
  results = await asyncio.gather(*tasks)
@@ -659,7 +712,7 @@ olap_config = PoolConfig.low_resource()
659
712
  async def olap_operations():
660
713
  async with mssql.connect_async(conn_str, olap_config) as conn:
661
714
  # Long-running analytical queries
662
- quarterly_report = await conn.execute_async("""
715
+ result = await conn.query("""
663
716
  SELECT
664
717
  DATE_TRUNC('quarter', order_date) as quarter,
665
718
  SUM(total_amount) as total_revenue,
@@ -669,10 +722,10 @@ async def olap_operations():
669
722
  GROUP BY DATE_TRUNC('quarter', order_date)
670
723
  ORDER BY quarter
671
724
  """)
672
- return quarterly_report
725
+ return result.rows()
673
726
  ```
674
727
 
675
- ## Troubleshooting
728
+ ## API Reference
676
729
 
677
730
  ### Common Issues
678
731
 
@@ -689,7 +742,22 @@ Contributions are welcome! Please open an issue or submit a pull request for any
689
742
 
690
743
  ## License
691
744
 
692
- This project is licensed under the PolyForm Noncommercial License 1.0.0. See the LICENSE file for details.
745
+ FastMSSQL is available under your choice of two licenses:
746
+
747
+ ### Option 1: GNU General Public License v3.0 (GPL-3.0)
748
+
749
+ **Free for open source projects.** If you distribute your application, you must make your entire application open source under GPL-3.0.
750
+
751
+ ### Option 2: Commercial License
752
+
753
+ **Paid license for proprietary applications.** Allows you to keep your application closed source. Contact riverb514@gmail.com for commercial licensing.
754
+
755
+ See the [LICENSE](LICENSE) file for full GPL-3.0 terms and commercial licensing details.
756
+
757
+ ### Examples and Benchmarks
758
+
759
+ - **Examples Directory**: All files in the `examples/` directory are licensed under the MIT License. See `examples/LICENSE` for full terms.
760
+ - **Benchmarks Directory**: All files in the `benchmarks/` directory are licensed under the MIT License. See `licenses/MIT_LICENSE.txt` for full terms.
693
761
 
694
762
  ## Third-Party Attributions
695
763
 
@@ -0,0 +1,6 @@
1
+ fastmssql/fastmssql.cpython-313-darwin.so,sha256=n7nk9cxWlb5d_YXt5zjIrq4NLTbzifgybRtfiwoijEY,1986192
2
+ fastmssql/__init__.py,sha256=pFvT4Iki4PdpHWl3APWVeXccWxakueCkU57jbEKcIDA,30407
3
+ fastmssql-0.3.0.dist-info/RECORD,,
4
+ fastmssql-0.3.0.dist-info/WHEEL,sha256=nje8d54qjzj9oDOkiu7cWmGJPP2Drc1KEOrMVah4qAM,132
5
+ fastmssql-0.3.0.dist-info/METADATA,sha256=R42eU--uZBAeryGZsy144qctjMYUOF3lSaTASzaH5Z0,29342
6
+ fastmssql-0.3.0.dist-info/licenses/LICENSE,sha256=OHj2nKice3tSk2Us200EWXDpwDKtAzeOu4NF4rwg5gk,33858
@@ -2,3 +2,5 @@ Wheel-Version: 1.0
2
2
  Generator: maturin (1.9.3)
3
3
  Root-Is-Purelib: false
4
4
  Tag: cp313-cp313-macosx_11_0_arm64
5
+ Generator: delocate 0.13.0
6
+