kover 2.7.2__tar.gz → 2.7.3__tar.gz

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.
Files changed (64) hide show
  1. kover-2.7.3/PKG-INFO +239 -0
  2. kover-2.7.3/README.md +209 -0
  3. {kover-2.7.2 → kover-2.7.3}/kover/__init__.py +1 -1
  4. {kover-2.7.2 → kover-2.7.3}/kover/bulk_write_builder.py +11 -13
  5. {kover-2.7.2 → kover-2.7.3}/kover/client.py +88 -4
  6. {kover-2.7.2 → kover-2.7.3}/kover/database.py +24 -1
  7. {kover-2.7.2 → kover-2.7.3}/kover/network/compressors.py +1 -0
  8. {kover-2.7.2 → kover-2.7.3}/kover/session.py +1 -1
  9. {kover-2.7.2 → kover-2.7.3}/kover/uri_parser.py +1 -4
  10. {kover-2.7.2 → kover-2.7.3}/pyproject.toml +2 -5
  11. kover-2.7.2/PKG-INFO +0 -350
  12. kover-2.7.2/README.md +0 -320
  13. {kover-2.7.2 → kover-2.7.3}/.gitignore +0 -0
  14. {kover-2.7.2 → kover-2.7.3}/CODE_OF_CONDUCT.md +0 -0
  15. {kover-2.7.2 → kover-2.7.3}/LICENSE +0 -0
  16. {kover-2.7.2 → kover-2.7.3}/kover/_internals/__init__.py +0 -0
  17. {kover-2.7.2 → kover-2.7.3}/kover/_internals/_mixins.py +0 -0
  18. {kover-2.7.2 → kover-2.7.3}/kover/_internals/_serializers.py +0 -0
  19. {kover-2.7.2 → kover-2.7.3}/kover/bson/__init__.py +0 -0
  20. {kover-2.7.2 → kover-2.7.3}/kover/bson/_helpers.py +0 -0
  21. {kover-2.7.2 → kover-2.7.3}/kover/bson/binary.py +0 -0
  22. {kover-2.7.2 → kover-2.7.3}/kover/bson/code.py +0 -0
  23. {kover-2.7.2 → kover-2.7.3}/kover/bson/codec_options.py +0 -0
  24. {kover-2.7.2 → kover-2.7.3}/kover/bson/datetime_ms.py +0 -0
  25. {kover-2.7.2 → kover-2.7.3}/kover/bson/dbref.py +0 -0
  26. {kover-2.7.2 → kover-2.7.3}/kover/bson/decimal128.py +0 -0
  27. {kover-2.7.2 → kover-2.7.3}/kover/bson/errors.py +0 -0
  28. {kover-2.7.2 → kover-2.7.3}/kover/bson/int64.py +0 -0
  29. {kover-2.7.2 → kover-2.7.3}/kover/bson/json_util.py +0 -0
  30. {kover-2.7.2 → kover-2.7.3}/kover/bson/max_key.py +0 -0
  31. {kover-2.7.2 → kover-2.7.3}/kover/bson/min_key.py +0 -0
  32. {kover-2.7.2 → kover-2.7.3}/kover/bson/objectid.py +0 -0
  33. {kover-2.7.2 → kover-2.7.3}/kover/bson/raw_bson.py +0 -0
  34. {kover-2.7.2 → kover-2.7.3}/kover/bson/regex.py +0 -0
  35. {kover-2.7.2 → kover-2.7.3}/kover/bson/son.py +0 -0
  36. {kover-2.7.2 → kover-2.7.3}/kover/bson/timestamp.py +0 -0
  37. {kover-2.7.2 → kover-2.7.3}/kover/bson/typings.py +0 -0
  38. {kover-2.7.2 → kover-2.7.3}/kover/bson/tz_util.py +0 -0
  39. {kover-2.7.2 → kover-2.7.3}/kover/codes.py +0 -0
  40. {kover-2.7.2 → kover-2.7.3}/kover/collection.py +0 -0
  41. {kover-2.7.2 → kover-2.7.3}/kover/cursor.py +0 -0
  42. {kover-2.7.2 → kover-2.7.3}/kover/enums.py +0 -0
  43. {kover-2.7.2 → kover-2.7.3}/kover/exceptions.py +0 -0
  44. {kover-2.7.2 → kover-2.7.3}/kover/gridfs/__init__.py +0 -0
  45. {kover-2.7.2 → kover-2.7.3}/kover/gridfs/exceptions.py +0 -0
  46. {kover-2.7.2 → kover-2.7.3}/kover/gridfs/gridfs.py +0 -0
  47. {kover-2.7.2 → kover-2.7.3}/kover/gridfs/models.py +0 -0
  48. {kover-2.7.2 → kover-2.7.3}/kover/helpers.py +0 -0
  49. {kover-2.7.2 → kover-2.7.3}/kover/metadata/__init__.py +0 -0
  50. {kover-2.7.2 → kover-2.7.3}/kover/metadata/definitions.py +0 -0
  51. {kover-2.7.2 → kover-2.7.3}/kover/models/__init__.py +0 -0
  52. {kover-2.7.2 → kover-2.7.3}/kover/models/operations.py +0 -0
  53. {kover-2.7.2 → kover-2.7.3}/kover/models/other.py +0 -0
  54. {kover-2.7.2 → kover-2.7.3}/kover/models/replset.py +0 -0
  55. {kover-2.7.2 → kover-2.7.3}/kover/network/__init__.py +0 -0
  56. {kover-2.7.2 → kover-2.7.3}/kover/network/auth.py +0 -0
  57. {kover-2.7.2 → kover-2.7.3}/kover/network/resolver.py +0 -0
  58. {kover-2.7.2 → kover-2.7.3}/kover/network/transport.py +0 -0
  59. {kover-2.7.2 → kover-2.7.3}/kover/network/wirehelper.py +0 -0
  60. {kover-2.7.2 → kover-2.7.3}/kover/py.typed +0 -0
  61. {kover-2.7.2 → kover-2.7.3}/kover/schema.py +0 -0
  62. {kover-2.7.2 → kover-2.7.3}/kover/transaction.py +0 -0
  63. {kover-2.7.2 → kover-2.7.3}/kover/typings.py +0 -0
  64. {kover-2.7.2 → kover-2.7.3}/requirements.txt +0 -0
kover-2.7.3/PKG-INFO ADDED
@@ -0,0 +1,239 @@
1
+ Metadata-Version: 2.4
2
+ Name: kover
3
+ Version: 2.7.3
4
+ Summary: Fully async mongodb driver for mongod and replica sets.
5
+ Project-URL: Repository, https://github.com/megawattka/kover
6
+ Project-URL: Documentation, https://github.com/megawattka/kover
7
+ Author-email: megawattka <gunter56741@gmail.com>
8
+ License-Expression: MIT
9
+ License-File: LICENSE
10
+ Keywords: async driver,kover,kover mongodb,mongo async,mongod driver,mongodb
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Programming Language :: Python :: 3 :: Only
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Topic :: Database
18
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
19
+ Classifier: Topic :: Software Development :: Quality Assurance
20
+ Classifier: Typing :: Typed
21
+ Requires-Python: >=3.10
22
+ Requires-Dist: dnspython>=2.7.0
23
+ Requires-Dist: pydantic>=2.10.6
24
+ Requires-Dist: typing-extensions>=4.12.2
25
+ Provides-Extra: snappy
26
+ Requires-Dist: python-snappy; extra == 'snappy'
27
+ Provides-Extra: zstd
28
+ Requires-Dist: zstd; extra == 'zstd'
29
+ Description-Content-Type: text/markdown
30
+
31
+ # kover
32
+ ![Build Status](https://img.shields.io/github/actions/workflow/status/megawattka/kover/actions.yml)
33
+ ![License](https://img.shields.io/github/license/megawattka/kover)
34
+ ![Python - Req](https://img.shields.io/badge/python-3.10+-blue)
35
+ ![Pypi Status](https://img.shields.io/pypi/status/kover)
36
+ ![Last Commit](https://img.shields.io/github/last-commit/megawattka/kover)
37
+ ![MongoDB](https://img.shields.io/badge/MongoDB-6.0+-green)
38
+
39
+ Kover is a model-oriented, strictly-typed, and asynchronous Object-Document Mapper (ODM) for MongoDB. It was built from the ground up using `asyncio` to provide a clean and high-performance alternative to traditional database drivers that rely on thread pools.
40
+
41
+ This library is inspired by `aiomongo` but is modernized for recent versions of Python and MongoDB, with a strong emphasis on type safety and developer experience. Kover is linted with Ruff and supports `pyright`'s strict type-checking mode.
42
+
43
+ ## Features
44
+
45
+ * **Fully Asynchronous:** Uses `asyncio` for non-blocking database operations, avoiding the use of thread pool executors.
46
+ * **Pydantic Integration:** Define your document schemas using Pydantic-style models for automatic validation and serialization.
47
+ * **Strictly Typed:** Designed for modern Python, with full type hinting support for better static analysis and code completion.
48
+ * **Modern MongoDB Support:** Built for MongoDB 6.0+ and omits deprecated features for a cleaner API.
49
+ * **Comprehensive API:** Supports nearly all of PyMongo's features, including CRUD operations, bulk writes, transactions, and GridFS.
50
+ * **Authentication:** Supports all standard MongoDB authentication mechanisms.
51
+
52
+ **Note:** The `kover.bson` package is adapted from the `pymongo` source code.
53
+
54
+ ## Dependencies
55
+ - `Python 3.10+`
56
+ - `pydantic>=2.10.6`
57
+ - `dnspython>=2.7.0`
58
+
59
+ ## Installation
60
+
61
+ ```bash
62
+ pip install kover
63
+ ```
64
+ Optional dependencies for compression can be installed with:
65
+ ```bash
66
+ pip install kover[snappy,zstd]
67
+ ```
68
+
69
+ ## Quick Start
70
+
71
+ Connect to MongoDB, create a client, and perform a simple query.
72
+
73
+ ```python
74
+ import asyncio
75
+ import logging
76
+
77
+ from kover import Kover
78
+
79
+ log = logging.getLogger(__name__)
80
+ logging.basicConfig(level=logging.INFO)
81
+
82
+ async def main():
83
+ # Connect using a connection string
84
+ client = await Kover.from_uri("mongodb://user:pass@host:port/?tls=false")
85
+
86
+ # Or, create a client programmatically
87
+ # from kover import AuthCredentials
88
+ # credentials = AuthCredentials(username="<user>", password="<pass>")
89
+ # client = await Kover.make_client(credentials=credentials)
90
+
91
+ db = client.testdb
92
+ collection = db.test_collection
93
+
94
+ # Insert a document
95
+ await collection.insert_one({"message": "Hello, Kover!"})
96
+
97
+ # Find documents
98
+ found = await collection.find().to_list()
99
+ log.info(found)
100
+
101
+ await client.close()
102
+
103
+ if __name__ == "__main__":
104
+ asyncio.run(main())
105
+ ```
106
+
107
+ ## Examples
108
+
109
+ ### Defining Schemas with Pydantic
110
+
111
+ Kover leverages Pydantic for defining document structures. This provides data validation, serialization, and a clear, explicit schema.
112
+
113
+ ```python
114
+ from uuid import UUID
115
+ from kover import Document
116
+
117
+ class User(Document):
118
+ """A user document schema."""
119
+
120
+ uuid: UUID
121
+ name: str
122
+ age: int
123
+ ```
124
+
125
+ You can even generate and enforce a JSON schema on the collection in MongoDB.
126
+
127
+ ```python
128
+ from kover import SchemaGenerator
129
+
130
+ # Generate a schema from the User model
131
+ schema = client.generate_schema(User)
132
+
133
+ # Apply the schema to the collection
134
+ collection = await client.db.users.create_if_not_exists()
135
+ await collection.set_validator(schema)
136
+ ```
137
+
138
+ ### Inserting Documents
139
+
140
+ You can insert Pydantic model instances directly into a collection.
141
+
142
+ ```python
143
+ from uuid import uuid4
144
+
145
+ user = User(name="Jane Doe", age=30, uuid=uuid4())
146
+ result = await client.db.users.insert_one(user)
147
+ log.info("Inserted user with ID: %s", result)
148
+ ```
149
+
150
+ ### Querying Documents
151
+
152
+ Kover's cursor provides a powerful and flexible way to retrieve data.
153
+
154
+ **Iterating over a Cursor:**
155
+ ```python
156
+ # The cursor asynchronously yields `User` objects
157
+ async with client.db.users.find(cls=User).limit(100) as cursor:
158
+ async for user in cursor:
159
+ log.info("User: %s, Age: %d", user.name, user.age)
160
+ ```
161
+
162
+ **Fetching all results into a list:**
163
+ ```python
164
+ users_list = await client.db.users.find(cls=User).to_list()
165
+ ```
166
+
167
+ ### Updating and Deleting
168
+
169
+ Use `Update` and `Delete` models to construct operations. This approach makes it clear which documents are being targeted and what modifications are being made.
170
+
171
+ ```python
172
+ from kover import Update, Delete
173
+
174
+ # Update a user's age
175
+ update = Update({"name": "Jane Doe"}, {"$set": {"age": 31}})
176
+ await client.db.users.update(update)
177
+
178
+ # Delete a user
179
+ delete = Delete({"name": "Jane Doe"}, limit=1)
180
+ n_deleted = await client.db.users.delete(delete)
181
+ log.info("Documents deleted: %d", n_deleted)
182
+ ```
183
+
184
+ ### Bulk Writes
185
+
186
+ Perform multiple operations in a single request for efficiency.
187
+
188
+ ```python
189
+ from kover import BulkWriteBuilder, Update, Delete
190
+
191
+ builder = BulkWriteBuilder()
192
+ builder.add_insert([{"product": "A"}], ns="testdb.inventory")
193
+ builder.add_update(
194
+ Update({"product": "A"}, {"$set": {"quantity": 10}}),
195
+ ns="testdb.inventory",
196
+ )
197
+ builder.add_delete(Delete({"product": "A"}, limit=1), ns="testdb.inventory")
198
+
199
+ await client.bulk_write(builder.build())
200
+ ```
201
+
202
+ ### Transactions
203
+
204
+ Kover supports ACID transactions for operations that require atomicity.
205
+
206
+ ```python
207
+ session = await client.start_session()
208
+ collection = client.db.test
209
+
210
+ async with session.start_transaction() as transaction:
211
+ await collection.insert_one({"step": 1}, transaction=transaction)
212
+ await collection.insert_one({"step": 2}, transaction=transaction)
213
+ # The transaction will be automatically committed on successful exit.
214
+ # If an exception occurs, it will be aborted.
215
+ ```
216
+
217
+ ### GridFS for Large Files
218
+
219
+ Store and retrieve large files (e.g., images, videos) seamlessly with GridFS.
220
+
221
+ ```python
222
+ from kover.gridfs import GridFS
223
+
224
+ # Get a GridFS instance for a database
225
+ fs = await GridFS(client.get_database("files")).indexed()
226
+
227
+ # Put a file into GridFS
228
+ file_id = await fs.put(b"Hello, large world!", filename="greeting.txt")
229
+
230
+ # Retrieve the file
231
+ file_info, file_bytes_io = await fs.get_by_file_id(file_id)
232
+
233
+ log.info(file_info)
234
+ log.info(file_bytes_io.read())
235
+ ```
236
+
237
+ ## Found a Bug?
238
+
239
+ If you find a bug, please [open an issue](https://github.com/megawattka/kover/issues). Better yet, create a pull request with a fix. Contributions are welcome! ❤️
kover-2.7.3/README.md ADDED
@@ -0,0 +1,209 @@
1
+ # kover
2
+ ![Build Status](https://img.shields.io/github/actions/workflow/status/megawattka/kover/actions.yml)
3
+ ![License](https://img.shields.io/github/license/megawattka/kover)
4
+ ![Python - Req](https://img.shields.io/badge/python-3.10+-blue)
5
+ ![Pypi Status](https://img.shields.io/pypi/status/kover)
6
+ ![Last Commit](https://img.shields.io/github/last-commit/megawattka/kover)
7
+ ![MongoDB](https://img.shields.io/badge/MongoDB-6.0+-green)
8
+
9
+ Kover is a model-oriented, strictly-typed, and asynchronous Object-Document Mapper (ODM) for MongoDB. It was built from the ground up using `asyncio` to provide a clean and high-performance alternative to traditional database drivers that rely on thread pools.
10
+
11
+ This library is inspired by `aiomongo` but is modernized for recent versions of Python and MongoDB, with a strong emphasis on type safety and developer experience. Kover is linted with Ruff and supports `pyright`'s strict type-checking mode.
12
+
13
+ ## Features
14
+
15
+ * **Fully Asynchronous:** Uses `asyncio` for non-blocking database operations, avoiding the use of thread pool executors.
16
+ * **Pydantic Integration:** Define your document schemas using Pydantic-style models for automatic validation and serialization.
17
+ * **Strictly Typed:** Designed for modern Python, with full type hinting support for better static analysis and code completion.
18
+ * **Modern MongoDB Support:** Built for MongoDB 6.0+ and omits deprecated features for a cleaner API.
19
+ * **Comprehensive API:** Supports nearly all of PyMongo's features, including CRUD operations, bulk writes, transactions, and GridFS.
20
+ * **Authentication:** Supports all standard MongoDB authentication mechanisms.
21
+
22
+ **Note:** The `kover.bson` package is adapted from the `pymongo` source code.
23
+
24
+ ## Dependencies
25
+ - `Python 3.10+`
26
+ - `pydantic>=2.10.6`
27
+ - `dnspython>=2.7.0`
28
+
29
+ ## Installation
30
+
31
+ ```bash
32
+ pip install kover
33
+ ```
34
+ Optional dependencies for compression can be installed with:
35
+ ```bash
36
+ pip install kover[snappy,zstd]
37
+ ```
38
+
39
+ ## Quick Start
40
+
41
+ Connect to MongoDB, create a client, and perform a simple query.
42
+
43
+ ```python
44
+ import asyncio
45
+ import logging
46
+
47
+ from kover import Kover
48
+
49
+ log = logging.getLogger(__name__)
50
+ logging.basicConfig(level=logging.INFO)
51
+
52
+ async def main():
53
+ # Connect using a connection string
54
+ client = await Kover.from_uri("mongodb://user:pass@host:port/?tls=false")
55
+
56
+ # Or, create a client programmatically
57
+ # from kover import AuthCredentials
58
+ # credentials = AuthCredentials(username="<user>", password="<pass>")
59
+ # client = await Kover.make_client(credentials=credentials)
60
+
61
+ db = client.testdb
62
+ collection = db.test_collection
63
+
64
+ # Insert a document
65
+ await collection.insert_one({"message": "Hello, Kover!"})
66
+
67
+ # Find documents
68
+ found = await collection.find().to_list()
69
+ log.info(found)
70
+
71
+ await client.close()
72
+
73
+ if __name__ == "__main__":
74
+ asyncio.run(main())
75
+ ```
76
+
77
+ ## Examples
78
+
79
+ ### Defining Schemas with Pydantic
80
+
81
+ Kover leverages Pydantic for defining document structures. This provides data validation, serialization, and a clear, explicit schema.
82
+
83
+ ```python
84
+ from uuid import UUID
85
+ from kover import Document
86
+
87
+ class User(Document):
88
+ """A user document schema."""
89
+
90
+ uuid: UUID
91
+ name: str
92
+ age: int
93
+ ```
94
+
95
+ You can even generate and enforce a JSON schema on the collection in MongoDB.
96
+
97
+ ```python
98
+ from kover import SchemaGenerator
99
+
100
+ # Generate a schema from the User model
101
+ schema = client.generate_schema(User)
102
+
103
+ # Apply the schema to the collection
104
+ collection = await client.db.users.create_if_not_exists()
105
+ await collection.set_validator(schema)
106
+ ```
107
+
108
+ ### Inserting Documents
109
+
110
+ You can insert Pydantic model instances directly into a collection.
111
+
112
+ ```python
113
+ from uuid import uuid4
114
+
115
+ user = User(name="Jane Doe", age=30, uuid=uuid4())
116
+ result = await client.db.users.insert_one(user)
117
+ log.info("Inserted user with ID: %s", result)
118
+ ```
119
+
120
+ ### Querying Documents
121
+
122
+ Kover's cursor provides a powerful and flexible way to retrieve data.
123
+
124
+ **Iterating over a Cursor:**
125
+ ```python
126
+ # The cursor asynchronously yields `User` objects
127
+ async with client.db.users.find(cls=User).limit(100) as cursor:
128
+ async for user in cursor:
129
+ log.info("User: %s, Age: %d", user.name, user.age)
130
+ ```
131
+
132
+ **Fetching all results into a list:**
133
+ ```python
134
+ users_list = await client.db.users.find(cls=User).to_list()
135
+ ```
136
+
137
+ ### Updating and Deleting
138
+
139
+ Use `Update` and `Delete` models to construct operations. This approach makes it clear which documents are being targeted and what modifications are being made.
140
+
141
+ ```python
142
+ from kover import Update, Delete
143
+
144
+ # Update a user's age
145
+ update = Update({"name": "Jane Doe"}, {"$set": {"age": 31}})
146
+ await client.db.users.update(update)
147
+
148
+ # Delete a user
149
+ delete = Delete({"name": "Jane Doe"}, limit=1)
150
+ n_deleted = await client.db.users.delete(delete)
151
+ log.info("Documents deleted: %d", n_deleted)
152
+ ```
153
+
154
+ ### Bulk Writes
155
+
156
+ Perform multiple operations in a single request for efficiency.
157
+
158
+ ```python
159
+ from kover import BulkWriteBuilder, Update, Delete
160
+
161
+ builder = BulkWriteBuilder()
162
+ builder.add_insert([{"product": "A"}], ns="testdb.inventory")
163
+ builder.add_update(
164
+ Update({"product": "A"}, {"$set": {"quantity": 10}}),
165
+ ns="testdb.inventory",
166
+ )
167
+ builder.add_delete(Delete({"product": "A"}, limit=1), ns="testdb.inventory")
168
+
169
+ await client.bulk_write(builder.build())
170
+ ```
171
+
172
+ ### Transactions
173
+
174
+ Kover supports ACID transactions for operations that require atomicity.
175
+
176
+ ```python
177
+ session = await client.start_session()
178
+ collection = client.db.test
179
+
180
+ async with session.start_transaction() as transaction:
181
+ await collection.insert_one({"step": 1}, transaction=transaction)
182
+ await collection.insert_one({"step": 2}, transaction=transaction)
183
+ # The transaction will be automatically committed on successful exit.
184
+ # If an exception occurs, it will be aborted.
185
+ ```
186
+
187
+ ### GridFS for Large Files
188
+
189
+ Store and retrieve large files (e.g., images, videos) seamlessly with GridFS.
190
+
191
+ ```python
192
+ from kover.gridfs import GridFS
193
+
194
+ # Get a GridFS instance for a database
195
+ fs = await GridFS(client.get_database("files")).indexed()
196
+
197
+ # Put a file into GridFS
198
+ file_id = await fs.put(b"Hello, large world!", filename="greeting.txt")
199
+
200
+ # Retrieve the file
201
+ file_info, file_bytes_io = await fs.get_by_file_id(file_id)
202
+
203
+ log.info(file_info)
204
+ log.info(file_bytes_io.read())
205
+ ```
206
+
207
+ ## Found a Bug?
208
+
209
+ If you find a bug, please [open an issue](https://github.com/megawattka/kover/issues). Better yet, create a pull request with a fix. Contributions are welcome! ❤️
@@ -20,7 +20,7 @@
20
20
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
21
  # SOFTWARE.
22
22
 
23
- __version__ = "2.7.2"
23
+ __version__ = "2.7.3"
24
24
  __author__ = "megawattka"
25
25
  __license__ = "MIT"
26
26
  __copyright__ = "Copyright (C) 2024-present megawattka"
@@ -24,7 +24,7 @@ class BulkWriteBuilder:
24
24
  let: xJsonT | None = None,
25
25
  errors_only: bool = False,
26
26
  cursor_batch_size: int | None = None,
27
- write_concern: str = "majority",
27
+ write_concern: str | int = "majority",
28
28
  ) -> None:
29
29
  self.ordered = ordered
30
30
  self.bypass_document_validation = bypass_document_validation
@@ -66,29 +66,27 @@ class BulkWriteBuilder:
66
66
 
67
67
  def add_update(
68
68
  self,
69
- *updates: Update,
69
+ update: Update,
70
70
  ns: str,
71
71
  ) -> None:
72
72
  """Adds an Update operations into the builder."""
73
73
  idx = self._get_ns_idx(ns)
74
- for update in updates:
75
- self._operations.append({
76
- "update": idx,
77
- **update.as_bulk_write_op(),
78
- })
74
+ self._operations.append({
75
+ "update": idx,
76
+ **update.as_bulk_write_op(),
77
+ })
79
78
 
80
79
  def add_delete(
81
80
  self,
82
- *deletes: Delete,
81
+ delete: Delete,
83
82
  ns: str,
84
83
  ) -> None:
85
84
  """Adds an Delete operations into the builder."""
86
85
  idx = self._get_ns_idx(ns)
87
- for delete in deletes:
88
- self._operations.append({
89
- "delete": idx,
90
- **delete.as_bulk_write_op(),
91
- })
86
+ self._operations.append({
87
+ "delete": idx,
88
+ **delete.as_bulk_write_op(),
89
+ })
92
90
 
93
91
  def build(self) -> xJsonT:
94
92
  """Build the command.
@@ -14,8 +14,9 @@ from .helpers import (
14
14
  filter_non_null,
15
15
  maybe_to_dict,
16
16
  )
17
- from .models import BuildInfo, WriteConcern
17
+ from .models import BuildInfo, ReadConcern, WriteConcern
18
18
  from .network import MongoTransport, SrvResolver
19
+ from .schema import SchemaGenerator
19
20
  from .session import Session
20
21
  from .typings import DEFAULT_MONGODB_PORT
21
22
  from .uri_parser import parse_uri
@@ -23,11 +24,12 @@ from .uri_parser import parse_uri
23
24
  if TYPE_CHECKING:
24
25
  from .models import ReplicaSetConfig
25
26
  from .network import AuthCredentials
27
+ from .schema import Document
26
28
  from .transaction import Transaction
27
29
  from .typings import COMPRESSION_T, DocumentT, xJsonT
28
30
 
29
31
 
30
- def create_connection_pool(
32
+ def _create_connection_pool(
31
33
  host: str,
32
34
  port: int,
33
35
  size: int,
@@ -64,6 +66,7 @@ class Kover:
64
66
  self._credentials = credentials
65
67
  self._compression = compression
66
68
  self._application = application
69
+ self._schema_generator = SchemaGenerator()
67
70
 
68
71
  async def __aenter__(self) -> Self:
69
72
  return self
@@ -115,6 +118,17 @@ class Kover:
115
118
  self._write_concern = WriteConcern(w=w, j=j, wtimeout=wtimeout)
116
119
  return self
117
120
 
121
+ def generate_schema(self, cls: type[Document]) -> xJsonT:
122
+ """Generate a JSON schema for the provided Document class.
123
+
124
+ Parameters:
125
+ cls : The Document class for which to generate the schema.
126
+
127
+ Returns:
128
+ A JSON schema as a dictionary.
129
+ """
130
+ return self._schema_generator.generate(cls)
131
+
118
132
  @classmethod
119
133
  async def from_uri(
120
134
  cls,
@@ -154,7 +168,7 @@ class Kover:
154
168
  nodes = [host]
155
169
 
156
170
  args = (nodes[0], parsed.port, parsed.max_pool_size)
157
- pool = create_connection_pool(*args, tls=parsed.tls, loop=loop)
171
+ pool = _create_connection_pool(*args, tls=parsed.tls, loop=loop)
158
172
 
159
173
  return cls(
160
174
  w=parsed.write_concern,
@@ -196,7 +210,7 @@ class Kover:
196
210
  Returns:
197
211
  An instance of the Kover client.
198
212
  """
199
- pool = create_connection_pool(
213
+ pool = _create_connection_pool(
200
214
  host, port, max_pool_size, tls=tls, loop=loop)
201
215
 
202
216
  return cls(
@@ -316,6 +330,25 @@ class Kover:
316
330
  """
317
331
  await self.request({"dropDatabase": 1.0}, db_name=name)
318
332
 
333
+ # https://www.mongodb.com/docs/manual/reference/command/dropConnections
334
+ async def drop_connections(
335
+ self,
336
+ hosts: list[str],
337
+ comment: str | None = None,
338
+ ) -> None:
339
+ """Drop connections to the specified hosts.
340
+
341
+ Parameters:
342
+ hosts : A list of hostnames whose connections should be dropped.
343
+ comment : Optional comment for the operation.
344
+ """
345
+ document: xJsonT = filter_non_null({
346
+ "dropConnections": 1.0,
347
+ "hostAndPort": hosts,
348
+ "comment": comment,
349
+ })
350
+ await self.request(document)
351
+
319
352
  # https://www.mongodb.com/docs/manual/reference/command/replSetInitiate/
320
353
  async def replica_set_initiate(
321
354
  self,
@@ -487,3 +520,54 @@ class Kover:
487
520
  "comment": comment,
488
521
  })
489
522
  await self.request(command)
523
+
524
+ # https://www.mongodb.com/docs/manual/reference/command/getDefaultRWConcern
525
+ async def get_default_rw_concern(
526
+ self,
527
+ *,
528
+ in_memory: bool = False,
529
+ comment: str | None = None,
530
+ ) -> tuple[ReadConcern, WriteConcern]:
531
+ """Get the default read and write concern settings for the database.
532
+
533
+ Parameters:
534
+ in_memory : If True, returns a WriteConcern instance without
535
+ querying the server, by default False.
536
+ comment : Optional comment for the operation.
537
+
538
+ Returns:
539
+ An instance of WriteConcern representing the default settings.
540
+ """
541
+ command = filter_non_null({
542
+ "getDefaultRWConcern": 1.0,
543
+ "inMemory": in_memory,
544
+ "comment": comment,
545
+ })
546
+ resp = await self.request(command)
547
+ read_concern = ReadConcern(level=resp["defaultReadConcern"]["level"])
548
+ write_concern = WriteConcern(w=resp["defaultWriteConcern"]["w"])
549
+
550
+ return read_concern, write_concern
551
+
552
+ # https://www.mongodb.com/docs/manual/reference/command/getParameter
553
+ async def get_parameter(self, name: str) -> object:
554
+ """Get the value of a specific server parameter.
555
+
556
+ Parameters:
557
+ name : The name of the server parameter to retrieve.
558
+
559
+ Returns:
560
+ A Parameter itself.
561
+ """
562
+ resp = await self.request({"getParameter": 1.0, name: 1.0})
563
+ return resp[name]
564
+
565
+ # https://www.mongodb.com/docs/manual/reference/command/setParameter
566
+ async def set_parameter(self, name: str, value: object) -> None:
567
+ """Set the server parameter at runtime.
568
+
569
+ Parameters:
570
+ name : The name of the server parameter to set.
571
+ value : The value of that parameter.
572
+ """
573
+ await self.request({"setParameter": 1.0, name: value})
@@ -5,13 +5,14 @@ from __future__ import annotations
5
5
  from typing import TYPE_CHECKING
6
6
 
7
7
  from .collection import Collection
8
- from .helpers import classrepr, filter_non_null
8
+ from .helpers import classrepr, filter_non_null, maybe_to_dict
9
9
  from .models import User
10
10
 
11
11
  if TYPE_CHECKING:
12
12
  from collections.abc import Sequence
13
13
 
14
14
  from .client import Kover
15
+ from .models import WriteConcern
15
16
  from .session import Transaction
16
17
  from .typings import xJsonT
17
18
 
@@ -214,6 +215,28 @@ class Database:
214
215
  })
215
216
  await self.command(command)
216
217
 
218
+ async def drop_all_users_from_database(
219
+ self,
220
+ write_concern: WriteConcern | None = None,
221
+ comment: str | None = None,
222
+ ) -> int:
223
+ """Drops all users from the database.
224
+
225
+ Parameters:
226
+ write_concern : Optional write concern for the operation.
227
+ comment : Optional comment for the operation.
228
+
229
+ Returns:
230
+ The number of users dropped.
231
+ """
232
+ command = filter_non_null({
233
+ "dropAllUsersFromDatabase": 1.0,
234
+ "writeConcern": maybe_to_dict(write_concern),
235
+ "comment": comment,
236
+ })
237
+ resp = await self.command(command)
238
+ return resp["n"]
239
+
217
240
  async def grant_roles_to_user(
218
241
  self,
219
242
  username: str,