nextorm 0.1.0__py3-none-any.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.
nextorm/__init__.py ADDED
@@ -0,0 +1,317 @@
1
+ """Public API surface for nextorm."""
2
+
3
+ import contextlib
4
+
5
+ from nextorm.async_database import AsyncDatabase, AsyncQuerySet
6
+ from nextorm.database import Database
7
+ from nextorm.debug import (
8
+ QueryStat,
9
+ clear_global_stats,
10
+ global_stats,
11
+ set_sql_debug,
12
+ sql_debugging,
13
+ )
14
+ from nextorm.entity import Entity, LocalDescriptor
15
+ from nextorm.exceptions import (
16
+ CommitException,
17
+ ConstraintError,
18
+ MappingError,
19
+ MultipleObjectsFoundError,
20
+ ObjectNotFound,
21
+ OptimisticCheckError,
22
+ PartialCommitException,
23
+ TransactionError,
24
+ ) # noqa: F401
25
+ from nextorm.expr import ColumnExpr
26
+ from nextorm.fields import (
27
+ PK,
28
+ ULID,
29
+ CompositeConstraint,
30
+ DateTimeTz,
31
+ FieldSpec,
32
+ Json,
33
+ Local,
34
+ LocalSpec,
35
+ LongStr,
36
+ Opt,
37
+ PrimaryKey,
38
+ RelationSpec,
39
+ Req,
40
+ Set,
41
+ Single,
42
+ Vec,
43
+ composite_index,
44
+ composite_key,
45
+ ulid,
46
+ uuid4,
47
+ uuid7,
48
+ )
49
+ from nextorm.generators import DecompileError, avg, count, max, min, select, sum
50
+ from nextorm.migrations import MigrationRunner, makemigrations, migrate
51
+ from nextorm.pool import AsyncConnectionPool, ConnectionPool, PoolTimeoutError
52
+ from nextorm.providers import (
53
+ AsyncConnection,
54
+ AsyncCursor,
55
+ AsyncProvider,
56
+ SyncConnection,
57
+ SyncCursor,
58
+ SyncProvider,
59
+ get_async_provider,
60
+ get_sync_provider,
61
+ register_provider,
62
+ registered_providers,
63
+ )
64
+ from nextorm.query import EntityProxy, QuerySet
65
+ from nextorm.session import SessionCache, async_db_session, db_session
66
+ from nextorm.sql import (
67
+ Alias,
68
+ BinOp,
69
+ Case,
70
+ CaseWhen,
71
+ Cast,
72
+ ColumnRef,
73
+ Delete,
74
+ FormatBuilder,
75
+ FunctionCall,
76
+ Insert,
77
+ Literal,
78
+ OrderItem,
79
+ Param,
80
+ RawSql,
81
+ Select,
82
+ SQLiteBuilder,
83
+ Star,
84
+ UnaryOp,
85
+ Update,
86
+ render,
87
+ sql,
88
+ )
89
+
90
+ __all__ = [
91
+ "Entity",
92
+ "FieldSpec",
93
+ "RelationSpec",
94
+ "LocalSpec",
95
+ "Local",
96
+ "Set",
97
+ "PK",
98
+ "Req",
99
+ "Opt",
100
+ "Single",
101
+ "CompositeConstraint",
102
+ "composite_key",
103
+ "composite_index",
104
+ "PrimaryKey",
105
+ "LocalDescriptor",
106
+ # UUID / ULID
107
+ "ULID",
108
+ "uuid7",
109
+ "uuid4",
110
+ "ulid",
111
+ # Extended types
112
+ "LongStr",
113
+ "Json",
114
+ "DateTimeTz",
115
+ "Vec",
116
+ "Database",
117
+ "AsyncDatabase",
118
+ "AsyncQuerySet",
119
+ "SessionCache",
120
+ "db_session",
121
+ "async_db_session",
122
+ # Generators
123
+ "select",
124
+ "DecompileError",
125
+ "count",
126
+ "avg",
127
+ "sum",
128
+ "min",
129
+ "max",
130
+ # Transaction helpers
131
+ "commit",
132
+ "rollback",
133
+ "flush",
134
+ # Migrations
135
+ "MigrationRunner",
136
+ "makemigrations",
137
+ "migrate",
138
+ # SQL nodes & builder
139
+ "Param",
140
+ "Literal",
141
+ "ColumnRef",
142
+ "Star",
143
+ "BinOp",
144
+ "UnaryOp",
145
+ "Cast",
146
+ "FunctionCall",
147
+ "Case",
148
+ "CaseWhen",
149
+ "Alias",
150
+ "OrderItem",
151
+ "Select",
152
+ "Insert",
153
+ "Update",
154
+ "Delete",
155
+ "RawSql",
156
+ "sql",
157
+ "SQLiteBuilder",
158
+ "FormatBuilder",
159
+ "render",
160
+ # Providers
161
+ "SyncProvider",
162
+ "SyncConnection",
163
+ "SyncCursor",
164
+ "AsyncProvider",
165
+ "AsyncConnection",
166
+ "AsyncCursor",
167
+ "register_provider",
168
+ "get_sync_provider",
169
+ "get_async_provider",
170
+ "registered_providers",
171
+ # Query DSL
172
+ "ColumnExpr",
173
+ "EntityProxy",
174
+ "QuerySet",
175
+ # Debug / diagnostics
176
+ "set_sql_debug",
177
+ "sql_debugging",
178
+ "QueryStat",
179
+ "global_stats",
180
+ "clear_global_stats",
181
+ # Exceptions
182
+ "MappingError",
183
+ "ObjectNotFound",
184
+ "MultipleObjectsFoundError",
185
+ "ConstraintError",
186
+ "TransactionError",
187
+ "OptimisticCheckError",
188
+ "CommitException",
189
+ "PartialCommitException",
190
+ # Connection pool
191
+ "ConnectionPool",
192
+ "AsyncConnectionPool",
193
+ "PoolTimeoutError",
194
+ ]
195
+
196
+ # ---------------------------------------------------------------------------
197
+ # Module-level transaction helpers (mirrors PonyORM's commit/rollback/flush)
198
+ # ---------------------------------------------------------------------------
199
+
200
+
201
+ def commit() -> None:
202
+ """Commit all sync databases that have entities in the current session.
203
+
204
+ Mirrors PonyORM's staged-commit strategy:
205
+
206
+ 1. Flush all databases first. On any flush error every database is rolled
207
+ back and the exception is re-raised.
208
+ 2. Commit the *primary* database (first in the list) first. On failure
209
+ all secondary databases are rolled back and a
210
+ :exc:`~nextorm.exceptions.CommitException` is raised.
211
+ 3. Commit the remaining databases. On any failure a
212
+ :exc:`~nextorm.exceptions.PartialCommitException` is raised (the
213
+ primary commit is already durable at this point).
214
+
215
+ When called outside a session this is a no-op.
216
+ For async databases use ``await db.acommit()`` directly.
217
+ """
218
+ from nextorm.session import _get_session_stack # noqa: PLC0415
219
+
220
+ cache = _get_session_stack().current
221
+ if cache is None:
222
+ return
223
+ seen: set[int] = set()
224
+ dbs: list[Database] = []
225
+ for entity in list(cache._objects.values()) + list(cache._to_save) + list(cache._dirty):
226
+ db = vars(entity).get("_db_")
227
+ if db is not None and isinstance(db, Database) and id(db) not in seen:
228
+ seen.add(id(db))
229
+ dbs.append(db)
230
+ if not dbs:
231
+ return
232
+
233
+ # Step 1 — flush all; on error roll back everything.
234
+ try:
235
+ for db in dbs:
236
+ db.flush()
237
+ except Exception:
238
+ for _db in dbs:
239
+ with contextlib.suppress(Exception):
240
+ _db._rollback_transaction()
241
+ raise
242
+
243
+ # Step 2 — commit primary first.
244
+ primary, secondaries = dbs[0], dbs[1:]
245
+ rollback_exceptions: list[Exception] = []
246
+ try:
247
+ primary._commit_transaction()
248
+ except Exception as primary_exc:
249
+ for _db in secondaries:
250
+ try:
251
+ _db._rollback_transaction()
252
+ except Exception as re:
253
+ rollback_exceptions.append(re)
254
+ raise CommitException(
255
+ str(primary_exc), [primary_exc, *rollback_exceptions]
256
+ ) from primary_exc
257
+
258
+ # Step 3 — commit secondaries; primary's work is already durable.
259
+ secondary_exceptions: list[Exception] = []
260
+ for db in secondaries:
261
+ try:
262
+ db._commit_transaction()
263
+ except Exception as e:
264
+ secondary_exceptions.append(e)
265
+ if secondary_exceptions:
266
+ raise PartialCommitException(
267
+ str(secondary_exceptions[0]), secondary_exceptions
268
+ ) from secondary_exceptions[0]
269
+
270
+
271
+ def rollback() -> None:
272
+ """Roll back all databases that have entities in the current session.
273
+
274
+ Iterates the identity map of the active :func:`~nextorm.session.db_session`,
275
+ collects the unique :class:`Database` objects referenced by cached entities,
276
+ calls :meth:`~nextorm.database.Database.rollback` on each, and then clears
277
+ the session cache.
278
+
279
+ When called outside a session this is a no-op.
280
+ """
281
+ from nextorm.session import _get_session_stack # noqa: PLC0415
282
+
283
+ cache = _get_session_stack().current
284
+ if cache is None:
285
+ return
286
+ dbs: set[Database] = set()
287
+ for entity in list(cache._objects.values()) + list(cache._to_save) + list(cache._dirty):
288
+ db = vars(entity).get("_db_")
289
+ if db is not None and isinstance(db, Database):
290
+ dbs.add(db)
291
+ for db in dbs:
292
+ db.rollback()
293
+
294
+
295
+ def flush() -> None:
296
+ """Flush all pending changes to all databases in the current session.
297
+
298
+ Iterates the dirty set and new-objects queue of the active
299
+ :func:`~nextorm.session.db_session`, groups them by :class:`Database`,
300
+ and calls :meth:`~nextorm.database.Database.flush` on each.
301
+
302
+ When called outside a session this is a no-op.
303
+ """
304
+ from nextorm.session import _get_session_stack # noqa: PLC0415
305
+
306
+ cache = _get_session_stack().current
307
+ if cache is None:
308
+ return
309
+ # Collect both new and dirty objects to find the involved databases.
310
+ pending = list(cache.objects_to_save) + list(cache.dirty_objects)
311
+ dbs: set[Database] = set()
312
+ for entity in pending:
313
+ db = vars(entity).get("_db_")
314
+ if db is not None and isinstance(db, Database):
315
+ dbs.add(db)
316
+ for db in dbs:
317
+ db.flush()