surrealdb-orm 0.1.4__py3-none-any.whl → 0.5.1__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.
Potentially problematic release.
This version of surrealdb-orm might be problematic. Click here for more details.
- surreal_orm/__init__.py +72 -3
- surreal_orm/aggregations.py +164 -0
- surreal_orm/auth/__init__.py +15 -0
- surreal_orm/auth/access.py +167 -0
- surreal_orm/auth/mixins.py +302 -0
- surreal_orm/cli/__init__.py +15 -0
- surreal_orm/cli/commands.py +369 -0
- surreal_orm/connection_manager.py +58 -18
- surreal_orm/fields/__init__.py +36 -0
- surreal_orm/fields/encrypted.py +166 -0
- surreal_orm/fields/relation.py +465 -0
- surreal_orm/migrations/__init__.py +51 -0
- surreal_orm/migrations/executor.py +380 -0
- surreal_orm/migrations/generator.py +272 -0
- surreal_orm/migrations/introspector.py +305 -0
- surreal_orm/migrations/migration.py +188 -0
- surreal_orm/migrations/operations.py +531 -0
- surreal_orm/migrations/state.py +406 -0
- surreal_orm/model_base.py +530 -44
- surreal_orm/query_set.py +609 -33
- surreal_orm/relations.py +645 -0
- surreal_orm/surreal_function.py +95 -0
- surreal_orm/surreal_ql.py +113 -0
- surreal_orm/types.py +86 -0
- surreal_sdk/README.md +79 -0
- surreal_sdk/__init__.py +151 -0
- surreal_sdk/connection/__init__.py +17 -0
- surreal_sdk/connection/base.py +516 -0
- surreal_sdk/connection/http.py +421 -0
- surreal_sdk/connection/pool.py +244 -0
- surreal_sdk/connection/websocket.py +519 -0
- surreal_sdk/exceptions.py +71 -0
- surreal_sdk/functions.py +607 -0
- surreal_sdk/protocol/__init__.py +13 -0
- surreal_sdk/protocol/rpc.py +218 -0
- surreal_sdk/py.typed +0 -0
- surreal_sdk/pyproject.toml +49 -0
- surreal_sdk/streaming/__init__.py +31 -0
- surreal_sdk/streaming/change_feed.py +278 -0
- surreal_sdk/streaming/live_query.py +265 -0
- surreal_sdk/streaming/live_select.py +369 -0
- surreal_sdk/transaction.py +386 -0
- surreal_sdk/types.py +346 -0
- surrealdb_orm-0.5.1.dist-info/METADATA +465 -0
- surrealdb_orm-0.5.1.dist-info/RECORD +52 -0
- {surrealdb_orm-0.1.4.dist-info → surrealdb_orm-0.5.1.dist-info}/WHEEL +1 -1
- surrealdb_orm-0.5.1.dist-info/entry_points.txt +2 -0
- {surrealdb_orm-0.1.4.dist-info → surrealdb_orm-0.5.1.dist-info}/licenses/LICENSE +1 -1
- surrealdb_orm-0.1.4.dist-info/METADATA +0 -184
- surrealdb_orm-0.1.4.dist-info/RECORD +0 -12
|
@@ -0,0 +1,465 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Relation field types for SurrealDB ORM.
|
|
3
|
+
|
|
4
|
+
This module provides relation field types that leverage SurrealDB's
|
|
5
|
+
graph capabilities for defining relationships between models.
|
|
6
|
+
|
|
7
|
+
Example:
|
|
8
|
+
from surreal_orm import BaseSurrealModel
|
|
9
|
+
from surreal_orm.fields import ForeignKey, ManyToMany, Relation
|
|
10
|
+
|
|
11
|
+
class User(BaseSurrealModel):
|
|
12
|
+
id: str | None = None
|
|
13
|
+
name: str
|
|
14
|
+
|
|
15
|
+
# Graph relations (SurrealDB edges)
|
|
16
|
+
followers: Relation("follows", "User", reverse=True)
|
|
17
|
+
following: Relation("follows", "User")
|
|
18
|
+
|
|
19
|
+
# Traditional relations
|
|
20
|
+
profile: ForeignKey("Profile", on_delete="CASCADE")
|
|
21
|
+
groups: ManyToMany("Group", through="membership")
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
from dataclasses import dataclass
|
|
25
|
+
from typing import TYPE_CHECKING, Annotated, Any, Literal, get_args, get_origin
|
|
26
|
+
|
|
27
|
+
from pydantic import GetCoreSchemaHandler, GetJsonSchemaHandler
|
|
28
|
+
from pydantic.json_schema import JsonSchemaValue
|
|
29
|
+
from pydantic_core import CoreSchema, core_schema
|
|
30
|
+
|
|
31
|
+
if TYPE_CHECKING:
|
|
32
|
+
pass
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@dataclass
|
|
36
|
+
class RelationInfo:
|
|
37
|
+
"""
|
|
38
|
+
Metadata for relation fields used during schema generation and querying.
|
|
39
|
+
|
|
40
|
+
Attributes:
|
|
41
|
+
to_model: The target model name (string to allow forward references)
|
|
42
|
+
relation_type: Type of relation (foreign_key, many_to_many, relation)
|
|
43
|
+
edge_table: Name of the edge table for graph relations
|
|
44
|
+
reverse: Whether to traverse in reverse direction (<- vs ->)
|
|
45
|
+
on_delete: Delete behavior for foreign keys (CASCADE, SET_NULL, PROTECT)
|
|
46
|
+
related_name: Name for the reverse relation on the target model
|
|
47
|
+
through: Intermediate table for many-to-many relations
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
to_model: str
|
|
51
|
+
relation_type: Literal["foreign_key", "many_to_many", "relation"]
|
|
52
|
+
edge_table: str | None = None
|
|
53
|
+
reverse: bool = False
|
|
54
|
+
on_delete: Literal["CASCADE", "SET_NULL", "PROTECT"] | None = None
|
|
55
|
+
related_name: str | None = None
|
|
56
|
+
through: str | None = None
|
|
57
|
+
|
|
58
|
+
@property
|
|
59
|
+
def traversal_direction(self) -> str:
|
|
60
|
+
"""Get the SurrealDB traversal direction operator."""
|
|
61
|
+
return "<-" if self.reverse else "->"
|
|
62
|
+
|
|
63
|
+
def get_traversal_query(self, from_table: str, from_id: str) -> str:
|
|
64
|
+
"""
|
|
65
|
+
Generate the SurrealDB traversal query.
|
|
66
|
+
|
|
67
|
+
Args:
|
|
68
|
+
from_table: Source table name
|
|
69
|
+
from_id: Source record ID
|
|
70
|
+
|
|
71
|
+
Returns:
|
|
72
|
+
SurrealQL traversal query string
|
|
73
|
+
"""
|
|
74
|
+
if self.relation_type == "relation":
|
|
75
|
+
if self.reverse:
|
|
76
|
+
return f"SELECT * FROM {from_table}:{from_id}<-{self.edge_table}<-{self.to_model}"
|
|
77
|
+
return f"SELECT * FROM {from_table}:{from_id}->{self.edge_table}->{self.to_model}"
|
|
78
|
+
elif self.relation_type == "foreign_key":
|
|
79
|
+
return f"SELECT * FROM {self.to_model} WHERE id = {from_table}:{from_id}.{self.edge_table}"
|
|
80
|
+
else: # many_to_many
|
|
81
|
+
through = self.through or f"{from_table}_{self.to_model}"
|
|
82
|
+
return f"SELECT * FROM {from_table}:{from_id}->{through}->{self.to_model}"
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
class _ForeignKeyMarker:
|
|
86
|
+
"""
|
|
87
|
+
Marker class for ForeignKey fields.
|
|
88
|
+
|
|
89
|
+
Foreign keys represent a single reference to another record,
|
|
90
|
+
stored as a record ID in the source table.
|
|
91
|
+
"""
|
|
92
|
+
|
|
93
|
+
to: str
|
|
94
|
+
on_delete: Literal["CASCADE", "SET_NULL", "PROTECT"]
|
|
95
|
+
related_name: str | None
|
|
96
|
+
|
|
97
|
+
def __init__(
|
|
98
|
+
self,
|
|
99
|
+
to: str,
|
|
100
|
+
on_delete: Literal["CASCADE", "SET_NULL", "PROTECT"] = "CASCADE",
|
|
101
|
+
related_name: str | None = None,
|
|
102
|
+
):
|
|
103
|
+
self.to = to
|
|
104
|
+
self.on_delete = on_delete
|
|
105
|
+
self.related_name = related_name
|
|
106
|
+
|
|
107
|
+
@classmethod
|
|
108
|
+
def __get_pydantic_core_schema__(
|
|
109
|
+
cls,
|
|
110
|
+
source_type: Any,
|
|
111
|
+
handler: GetCoreSchemaHandler,
|
|
112
|
+
) -> CoreSchema:
|
|
113
|
+
"""Build the Pydantic core schema for validation."""
|
|
114
|
+
# ForeignKey stores a record ID (string) or None
|
|
115
|
+
to_model = ""
|
|
116
|
+
on_delete: Literal["CASCADE", "SET_NULL", "PROTECT"] = "CASCADE"
|
|
117
|
+
related_name = None
|
|
118
|
+
|
|
119
|
+
args = get_args(source_type)
|
|
120
|
+
for arg in args:
|
|
121
|
+
if isinstance(arg, _ForeignKeyMarker):
|
|
122
|
+
to_model = arg.to
|
|
123
|
+
on_delete = arg.on_delete
|
|
124
|
+
related_name = arg.related_name
|
|
125
|
+
break
|
|
126
|
+
|
|
127
|
+
return core_schema.nullable_schema(
|
|
128
|
+
core_schema.str_schema(
|
|
129
|
+
metadata={
|
|
130
|
+
"relation_type": "foreign_key",
|
|
131
|
+
"to_model": to_model,
|
|
132
|
+
"on_delete": on_delete,
|
|
133
|
+
"related_name": related_name,
|
|
134
|
+
"surreal_type": "record",
|
|
135
|
+
}
|
|
136
|
+
)
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
@classmethod
|
|
140
|
+
def __get_pydantic_json_schema__(
|
|
141
|
+
cls,
|
|
142
|
+
core_schema_obj: CoreSchema,
|
|
143
|
+
handler: GetJsonSchemaHandler,
|
|
144
|
+
) -> JsonSchemaValue:
|
|
145
|
+
"""Generate JSON schema for OpenAPI documentation."""
|
|
146
|
+
return {"type": "string", "format": "record-id", "nullable": True}
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
class _ManyToManyMarker:
|
|
150
|
+
"""
|
|
151
|
+
Marker class for ManyToMany fields.
|
|
152
|
+
|
|
153
|
+
Many-to-many relations are implemented using SurrealDB graph edges,
|
|
154
|
+
with an optional intermediate table for storing relation metadata.
|
|
155
|
+
"""
|
|
156
|
+
|
|
157
|
+
to: str
|
|
158
|
+
through: str | None
|
|
159
|
+
related_name: str | None
|
|
160
|
+
|
|
161
|
+
def __init__(
|
|
162
|
+
self,
|
|
163
|
+
to: str,
|
|
164
|
+
through: str | None = None,
|
|
165
|
+
related_name: str | None = None,
|
|
166
|
+
):
|
|
167
|
+
self.to = to
|
|
168
|
+
self.through = through
|
|
169
|
+
self.related_name = related_name
|
|
170
|
+
|
|
171
|
+
@classmethod
|
|
172
|
+
def __get_pydantic_core_schema__(
|
|
173
|
+
cls,
|
|
174
|
+
source_type: Any,
|
|
175
|
+
handler: GetCoreSchemaHandler,
|
|
176
|
+
) -> CoreSchema:
|
|
177
|
+
"""Build the Pydantic core schema for validation."""
|
|
178
|
+
to_model = ""
|
|
179
|
+
through = None
|
|
180
|
+
related_name = None
|
|
181
|
+
|
|
182
|
+
args = get_args(source_type)
|
|
183
|
+
for arg in args:
|
|
184
|
+
if isinstance(arg, _ManyToManyMarker):
|
|
185
|
+
to_model = arg.to
|
|
186
|
+
through = arg.through
|
|
187
|
+
related_name = arg.related_name
|
|
188
|
+
break
|
|
189
|
+
|
|
190
|
+
# ManyToMany is represented as a list of record IDs (virtual field)
|
|
191
|
+
return core_schema.list_schema(
|
|
192
|
+
core_schema.str_schema(),
|
|
193
|
+
metadata={
|
|
194
|
+
"relation_type": "many_to_many",
|
|
195
|
+
"to_model": to_model,
|
|
196
|
+
"through": through,
|
|
197
|
+
"related_name": related_name,
|
|
198
|
+
"surreal_type": "virtual",
|
|
199
|
+
},
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
@classmethod
|
|
203
|
+
def __get_pydantic_json_schema__(
|
|
204
|
+
cls,
|
|
205
|
+
core_schema_obj: CoreSchema,
|
|
206
|
+
handler: GetJsonSchemaHandler,
|
|
207
|
+
) -> JsonSchemaValue:
|
|
208
|
+
"""Generate JSON schema for OpenAPI documentation."""
|
|
209
|
+
return {"type": "array", "items": {"type": "string", "format": "record-id"}}
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
class _RelationMarker:
|
|
213
|
+
"""
|
|
214
|
+
Marker class for graph Relation fields.
|
|
215
|
+
|
|
216
|
+
Relations use SurrealDB's native graph capabilities with RELATE
|
|
217
|
+
statements and edge traversal (-> and <-).
|
|
218
|
+
"""
|
|
219
|
+
|
|
220
|
+
edge: str
|
|
221
|
+
to: str
|
|
222
|
+
reverse: bool
|
|
223
|
+
|
|
224
|
+
def __init__(
|
|
225
|
+
self,
|
|
226
|
+
edge: str,
|
|
227
|
+
to: str,
|
|
228
|
+
reverse: bool = False,
|
|
229
|
+
):
|
|
230
|
+
self.edge = edge
|
|
231
|
+
self.to = to
|
|
232
|
+
self.reverse = reverse
|
|
233
|
+
|
|
234
|
+
@classmethod
|
|
235
|
+
def __get_pydantic_core_schema__(
|
|
236
|
+
cls,
|
|
237
|
+
source_type: Any,
|
|
238
|
+
handler: GetCoreSchemaHandler,
|
|
239
|
+
) -> CoreSchema:
|
|
240
|
+
"""Build the Pydantic core schema for validation."""
|
|
241
|
+
edge = ""
|
|
242
|
+
to_model = ""
|
|
243
|
+
reverse = False
|
|
244
|
+
|
|
245
|
+
args = get_args(source_type)
|
|
246
|
+
for arg in args:
|
|
247
|
+
if isinstance(arg, _RelationMarker):
|
|
248
|
+
edge = arg.edge
|
|
249
|
+
to_model = arg.to
|
|
250
|
+
reverse = arg.reverse
|
|
251
|
+
break
|
|
252
|
+
|
|
253
|
+
# Relation is represented as a list of related objects (virtual field)
|
|
254
|
+
return core_schema.list_schema(
|
|
255
|
+
core_schema.any_schema(),
|
|
256
|
+
metadata={
|
|
257
|
+
"relation_type": "relation",
|
|
258
|
+
"edge_table": edge,
|
|
259
|
+
"to_model": to_model,
|
|
260
|
+
"reverse": reverse,
|
|
261
|
+
"surreal_type": "virtual",
|
|
262
|
+
},
|
|
263
|
+
)
|
|
264
|
+
|
|
265
|
+
@classmethod
|
|
266
|
+
def __get_pydantic_json_schema__(
|
|
267
|
+
cls,
|
|
268
|
+
core_schema_obj: CoreSchema,
|
|
269
|
+
handler: GetJsonSchemaHandler,
|
|
270
|
+
) -> JsonSchemaValue:
|
|
271
|
+
"""Generate JSON schema for OpenAPI documentation."""
|
|
272
|
+
return {"type": "array", "items": {"type": "object"}}
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
def ForeignKey(
|
|
276
|
+
to: str,
|
|
277
|
+
on_delete: Literal["CASCADE", "SET_NULL", "PROTECT"] = "CASCADE",
|
|
278
|
+
related_name: str | None = None,
|
|
279
|
+
) -> Any:
|
|
280
|
+
"""
|
|
281
|
+
Create a ForeignKey field type.
|
|
282
|
+
|
|
283
|
+
A ForeignKey represents a single reference to another model,
|
|
284
|
+
stored as a record ID in the database.
|
|
285
|
+
|
|
286
|
+
Args:
|
|
287
|
+
to: Target model name (string for forward references)
|
|
288
|
+
on_delete: Behavior when referenced record is deleted
|
|
289
|
+
- CASCADE: Delete this record too
|
|
290
|
+
- SET_NULL: Set the field to null
|
|
291
|
+
- PROTECT: Prevent deletion of referenced record
|
|
292
|
+
related_name: Name for reverse relation on target model
|
|
293
|
+
|
|
294
|
+
Returns:
|
|
295
|
+
Annotated type for use in model definition
|
|
296
|
+
|
|
297
|
+
Example:
|
|
298
|
+
class Post(BaseSurrealModel):
|
|
299
|
+
author: ForeignKey("User", related_name="posts")
|
|
300
|
+
"""
|
|
301
|
+
return Annotated[str | None, _ForeignKeyMarker(to, on_delete, related_name)]
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
def ManyToMany(
|
|
305
|
+
to: str,
|
|
306
|
+
through: str | None = None,
|
|
307
|
+
related_name: str | None = None,
|
|
308
|
+
) -> Any:
|
|
309
|
+
"""
|
|
310
|
+
Create a ManyToMany field type.
|
|
311
|
+
|
|
312
|
+
A ManyToMany relation uses SurrealDB graph edges to connect
|
|
313
|
+
multiple records. An optional intermediate table can store
|
|
314
|
+
additional metadata about the relationship.
|
|
315
|
+
|
|
316
|
+
Args:
|
|
317
|
+
to: Target model name (string for forward references)
|
|
318
|
+
through: Intermediate edge table name (auto-generated if not specified)
|
|
319
|
+
related_name: Name for reverse relation on target model
|
|
320
|
+
|
|
321
|
+
Returns:
|
|
322
|
+
Annotated type for use in model definition
|
|
323
|
+
|
|
324
|
+
Example:
|
|
325
|
+
class User(BaseSurrealModel):
|
|
326
|
+
groups: ManyToMany("Group", through="membership")
|
|
327
|
+
|
|
328
|
+
class Group(BaseSurrealModel):
|
|
329
|
+
members: ManyToMany("User", through="membership", related_name="groups")
|
|
330
|
+
"""
|
|
331
|
+
return Annotated[list, _ManyToManyMarker(to, through, related_name)]
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
def Relation(
|
|
335
|
+
edge: str,
|
|
336
|
+
to: str,
|
|
337
|
+
reverse: bool = False,
|
|
338
|
+
) -> Any:
|
|
339
|
+
"""
|
|
340
|
+
Create a graph Relation field type.
|
|
341
|
+
|
|
342
|
+
A Relation uses SurrealDB's native graph capabilities for
|
|
343
|
+
traversing edges between records. This is the most flexible
|
|
344
|
+
relation type, supporting arbitrary graph structures.
|
|
345
|
+
|
|
346
|
+
Args:
|
|
347
|
+
edge: Name of the edge table (e.g., "follows", "likes")
|
|
348
|
+
to: Target model name (string for forward references)
|
|
349
|
+
reverse: Whether to traverse in reverse direction
|
|
350
|
+
- False (default): Forward traversal (->)
|
|
351
|
+
- True: Reverse traversal (<-)
|
|
352
|
+
|
|
353
|
+
Returns:
|
|
354
|
+
Annotated type for use in model definition
|
|
355
|
+
|
|
356
|
+
Example:
|
|
357
|
+
class User(BaseSurrealModel):
|
|
358
|
+
# People this user follows (outgoing edges)
|
|
359
|
+
following: Relation("follows", "User")
|
|
360
|
+
|
|
361
|
+
# People who follow this user (incoming edges)
|
|
362
|
+
followers: Relation("follows", "User", reverse=True)
|
|
363
|
+
|
|
364
|
+
SurrealQL equivalent:
|
|
365
|
+
- following: SELECT * FROM user:id->follows->User
|
|
366
|
+
- followers: SELECT * FROM user:id<-follows<-User
|
|
367
|
+
"""
|
|
368
|
+
return Annotated[list, _RelationMarker(edge, to, reverse)]
|
|
369
|
+
|
|
370
|
+
|
|
371
|
+
def is_relation_field(field_type: Any) -> bool:
|
|
372
|
+
"""
|
|
373
|
+
Check if a field type is a relation type.
|
|
374
|
+
|
|
375
|
+
Args:
|
|
376
|
+
field_type: The type annotation to check
|
|
377
|
+
|
|
378
|
+
Returns:
|
|
379
|
+
True if the field is a ForeignKey, ManyToMany, or Relation
|
|
380
|
+
"""
|
|
381
|
+
origin = get_origin(field_type)
|
|
382
|
+
|
|
383
|
+
if origin is Annotated:
|
|
384
|
+
args = get_args(field_type)
|
|
385
|
+
for arg in args:
|
|
386
|
+
if isinstance(arg, (_ForeignKeyMarker, _ManyToManyMarker, _RelationMarker)):
|
|
387
|
+
return True
|
|
388
|
+
|
|
389
|
+
return False
|
|
390
|
+
|
|
391
|
+
|
|
392
|
+
def is_foreign_key(field_type: Any) -> bool:
|
|
393
|
+
"""Check if a field type is a ForeignKey."""
|
|
394
|
+
origin = get_origin(field_type)
|
|
395
|
+
if origin is Annotated:
|
|
396
|
+
args = get_args(field_type)
|
|
397
|
+
for arg in args:
|
|
398
|
+
if isinstance(arg, _ForeignKeyMarker):
|
|
399
|
+
return True
|
|
400
|
+
return False
|
|
401
|
+
|
|
402
|
+
|
|
403
|
+
def is_many_to_many(field_type: Any) -> bool:
|
|
404
|
+
"""Check if a field type is a ManyToMany relation."""
|
|
405
|
+
origin = get_origin(field_type)
|
|
406
|
+
if origin is Annotated:
|
|
407
|
+
args = get_args(field_type)
|
|
408
|
+
for arg in args:
|
|
409
|
+
if isinstance(arg, _ManyToManyMarker):
|
|
410
|
+
return True
|
|
411
|
+
return False
|
|
412
|
+
|
|
413
|
+
|
|
414
|
+
def is_graph_relation(field_type: Any) -> bool:
|
|
415
|
+
"""Check if a field type is a graph Relation."""
|
|
416
|
+
origin = get_origin(field_type)
|
|
417
|
+
if origin is Annotated:
|
|
418
|
+
args = get_args(field_type)
|
|
419
|
+
for arg in args:
|
|
420
|
+
if isinstance(arg, _RelationMarker):
|
|
421
|
+
return True
|
|
422
|
+
return False
|
|
423
|
+
|
|
424
|
+
|
|
425
|
+
def get_relation_info(field_type: Any) -> RelationInfo | None:
|
|
426
|
+
"""
|
|
427
|
+
Extract relation information from a field type.
|
|
428
|
+
|
|
429
|
+
Args:
|
|
430
|
+
field_type: The type annotation to extract from
|
|
431
|
+
|
|
432
|
+
Returns:
|
|
433
|
+
RelationInfo if the field is a relation, None otherwise
|
|
434
|
+
"""
|
|
435
|
+
if not is_relation_field(field_type):
|
|
436
|
+
return None
|
|
437
|
+
|
|
438
|
+
origin = get_origin(field_type)
|
|
439
|
+
|
|
440
|
+
if origin is Annotated:
|
|
441
|
+
args = get_args(field_type)
|
|
442
|
+
for arg in args:
|
|
443
|
+
if isinstance(arg, _ForeignKeyMarker):
|
|
444
|
+
return RelationInfo(
|
|
445
|
+
to_model=arg.to,
|
|
446
|
+
relation_type="foreign_key",
|
|
447
|
+
on_delete=arg.on_delete,
|
|
448
|
+
related_name=arg.related_name,
|
|
449
|
+
)
|
|
450
|
+
elif isinstance(arg, _ManyToManyMarker):
|
|
451
|
+
return RelationInfo(
|
|
452
|
+
to_model=arg.to,
|
|
453
|
+
relation_type="many_to_many",
|
|
454
|
+
through=arg.through,
|
|
455
|
+
related_name=arg.related_name,
|
|
456
|
+
)
|
|
457
|
+
elif isinstance(arg, _RelationMarker):
|
|
458
|
+
return RelationInfo(
|
|
459
|
+
to_model=arg.to,
|
|
460
|
+
relation_type="relation",
|
|
461
|
+
edge_table=arg.edge,
|
|
462
|
+
reverse=arg.reverse,
|
|
463
|
+
)
|
|
464
|
+
|
|
465
|
+
return None
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"""
|
|
2
|
+
SurrealDB ORM Migration System.
|
|
3
|
+
|
|
4
|
+
This module provides Django-style migrations for SurrealDB, including:
|
|
5
|
+
- Schema versioning with migration files
|
|
6
|
+
- Auto-detection of model changes
|
|
7
|
+
- Forward and backward migrations
|
|
8
|
+
- Data migrations for record transformations
|
|
9
|
+
|
|
10
|
+
Usage:
|
|
11
|
+
# Generate migrations from model changes
|
|
12
|
+
await manager.makemigrations(name="initial")
|
|
13
|
+
|
|
14
|
+
# Apply pending migrations
|
|
15
|
+
await manager.migrate()
|
|
16
|
+
|
|
17
|
+
# Rollback to a specific migration
|
|
18
|
+
await manager.rollback("0001_initial")
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
from .migration import Migration
|
|
22
|
+
from .operations import (
|
|
23
|
+
AddField,
|
|
24
|
+
AlterField,
|
|
25
|
+
CreateIndex,
|
|
26
|
+
CreateTable,
|
|
27
|
+
DataMigration,
|
|
28
|
+
DefineAccess,
|
|
29
|
+
DropField,
|
|
30
|
+
DropIndex,
|
|
31
|
+
DropTable,
|
|
32
|
+
Operation,
|
|
33
|
+
RawSQL,
|
|
34
|
+
RemoveAccess,
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
__all__ = [
|
|
38
|
+
"Migration",
|
|
39
|
+
"Operation",
|
|
40
|
+
"CreateTable",
|
|
41
|
+
"DropTable",
|
|
42
|
+
"AddField",
|
|
43
|
+
"DropField",
|
|
44
|
+
"AlterField",
|
|
45
|
+
"CreateIndex",
|
|
46
|
+
"DropIndex",
|
|
47
|
+
"DefineAccess",
|
|
48
|
+
"RemoveAccess",
|
|
49
|
+
"DataMigration",
|
|
50
|
+
"RawSQL",
|
|
51
|
+
]
|