tapestry-orm 0.0.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.
- tapestry/__init__.py +11 -0
- tapestry/base.py +401 -0
- tapestry/base.pyi +54 -0
- tapestry/edge.py +271 -0
- tapestry/edge.pyi +45 -0
- tapestry/engine.py +301 -0
- tapestry/field.py +315 -0
- tapestry/field.pyi +113 -0
- tapestry/node.py +169 -0
- tapestry/node.pyi +28 -0
- tapestry/py.typed +0 -0
- tapestry/query.py +404 -0
- tapestry/query.pyi +33 -0
- tapestry/table.py +464 -0
- tapestry/tokenizer.py +156 -0
- tapestry/utils.py +70 -0
- tapestry_orm-0.0.1.dist-info/METADATA +418 -0
- tapestry_orm-0.0.1.dist-info/RECORD +19 -0
- tapestry_orm-0.0.1.dist-info/WHEEL +4 -0
tapestry/__init__.py
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
__all__ = [
|
|
2
|
+
"Base", "Text", "create_engine", "Reference", "Node", "Edge", "Q"
|
|
3
|
+
]
|
|
4
|
+
|
|
5
|
+
from .query import Q
|
|
6
|
+
from .base import Base
|
|
7
|
+
from .node import Node
|
|
8
|
+
from .edge import Edge
|
|
9
|
+
from .tokenizer import Text
|
|
10
|
+
from .table import Reference
|
|
11
|
+
from .engine import create_engine
|
tapestry/base.py
ADDED
|
@@ -0,0 +1,401 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import inspect
|
|
4
|
+
|
|
5
|
+
from enum import Enum
|
|
6
|
+
from copy import deepcopy
|
|
7
|
+
from itertools import chain
|
|
8
|
+
from queue import LifoQueue
|
|
9
|
+
from pydantic_core.core_schema import ValidationInfo
|
|
10
|
+
from pydantic.fields import FieldInfo, ComputedFieldInfo
|
|
11
|
+
from surrealdb import AsyncWsSurrealConnection, AsyncHttpSurrealConnection, RecordID
|
|
12
|
+
from typing import Any, ClassVar, Optional, Self, Any, Unpack, Union, Type, get_args
|
|
13
|
+
from pydantic import BaseModel, field_validator, model_serializer, field_serializer, Field, ConfigDict, model_validator
|
|
14
|
+
|
|
15
|
+
from .table import Table, Reference
|
|
16
|
+
from .utils import convert_types, replace_type, flatten_type
|
|
17
|
+
from .field import Field as CustomField, NestedFieldDescriptor, ComputedFieldDescriptor
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
# Registry base class -------------------------------------------------------
|
|
21
|
+
class Base(BaseModel):
|
|
22
|
+
"""
|
|
23
|
+
Base class for creating SurrealDB table models with Pydantic.
|
|
24
|
+
|
|
25
|
+
The Base class provides the foundation for defining SurrealDB tables as Python classes
|
|
26
|
+
using Pydantic models. All table models should inherit from this class, which handles
|
|
27
|
+
automatic registration, schema generation, and serialization/deserialization.
|
|
28
|
+
|
|
29
|
+
Attributes:
|
|
30
|
+
id (RecordID | None): The SurrealDB record ID. Automatically assigned when records
|
|
31
|
+
are created in the database. Can be None for new records.
|
|
32
|
+
|
|
33
|
+
Class Attributes:
|
|
34
|
+
_registry: Tuple of all registered tables in the system
|
|
35
|
+
_tokenizers: Set of tokenizer definitions for full-text search
|
|
36
|
+
_to_create: Queue for chaining object creations
|
|
37
|
+
child_classes: Dictionary mapping table names to their model classes
|
|
38
|
+
|
|
39
|
+
Example:
|
|
40
|
+
>>> from tapestry import Base
|
|
41
|
+
>>> from datetime import date
|
|
42
|
+
>>>
|
|
43
|
+
>>> class Person(Base):
|
|
44
|
+
... first_name: str
|
|
45
|
+
... last_name: str
|
|
46
|
+
... date_of_birth: date
|
|
47
|
+
...
|
|
48
|
+
>>> # Person is automatically registered and can generate SurrealDB schema
|
|
49
|
+
>>> schema = Base.generate_schema()
|
|
50
|
+
|
|
51
|
+
Notes:
|
|
52
|
+
- Subclasses are automatically registered upon definition
|
|
53
|
+
- Field types are automatically mapped to SurrealDB types
|
|
54
|
+
- Supports relationships through Reference fields
|
|
55
|
+
- Handles enum serialization automatically
|
|
56
|
+
- Provides full-text search capabilities with Text fields
|
|
57
|
+
"""
|
|
58
|
+
id: RecordID | None = Field(exclude=False, default = None)
|
|
59
|
+
|
|
60
|
+
model_config = {
|
|
61
|
+
"arbitrary_types_allowed": True,
|
|
62
|
+
"use_enum_values": False, # would be great to have a 'use_enum_names'
|
|
63
|
+
"validate_assignment": True
|
|
64
|
+
}
|
|
65
|
+
_registry: ClassVar[tuple[Table, ...]] = ()
|
|
66
|
+
_tokenizers: ClassVar[set[str]] = set()
|
|
67
|
+
_to_create: ClassVar[LifoQueue[Base]]
|
|
68
|
+
child_classes: ClassVar[dict[str, Type[Base]]] = {}
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
@classmethod
|
|
72
|
+
@field_validator('id')
|
|
73
|
+
def validate_record_id(cls, v: Any) -> Optional[RecordID]:
|
|
74
|
+
"""
|
|
75
|
+
Validate and convert record ID values.
|
|
76
|
+
|
|
77
|
+
Args:
|
|
78
|
+
v: The value to validate (can be None, RecordID, or string)
|
|
79
|
+
|
|
80
|
+
Returns:
|
|
81
|
+
Optional[RecordID]: A valid RecordID or None
|
|
82
|
+
|
|
83
|
+
Notes:
|
|
84
|
+
Automatically converts string IDs to RecordID instances with the
|
|
85
|
+
appropriate table name.
|
|
86
|
+
"""
|
|
87
|
+
if v is None:
|
|
88
|
+
return None
|
|
89
|
+
if isinstance(v, RecordID):
|
|
90
|
+
return v
|
|
91
|
+
# Convert string to RecordID if needed
|
|
92
|
+
return RecordID(cls.__name__.lower(), v)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
@model_serializer(mode="wrap")
|
|
96
|
+
def _serialize(self, serializer, info):
|
|
97
|
+
"""
|
|
98
|
+
Custom serializer for handling record references.
|
|
99
|
+
|
|
100
|
+
When serializing nested objects, this method ensures that only the record ID
|
|
101
|
+
is serialized for referenced records, not the entire object.
|
|
102
|
+
|
|
103
|
+
Args:
|
|
104
|
+
serializer: The default Pydantic serializer
|
|
105
|
+
info: Serialization context information
|
|
106
|
+
|
|
107
|
+
Returns:
|
|
108
|
+
Serialized representation of the object or just its ID for references
|
|
109
|
+
|
|
110
|
+
Raises:
|
|
111
|
+
Exception: If attempting to reference a record that hasn't been created yet
|
|
112
|
+
"""
|
|
113
|
+
if not info.context:
|
|
114
|
+
return serializer(self)
|
|
115
|
+
if info.context.get("root"):
|
|
116
|
+
info.context["root"] = False
|
|
117
|
+
return serializer(self)
|
|
118
|
+
else:
|
|
119
|
+
if self.id is None:
|
|
120
|
+
raise Exception(f"You should create your record before referecing to it : create {self}")
|
|
121
|
+
# self._to_create.put(self)
|
|
122
|
+
# maybe check here in context if we are inserting in db
|
|
123
|
+
return self.id
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
@field_validator('*', mode='before')
|
|
127
|
+
@classmethod
|
|
128
|
+
def validate_enums(cls, v: Any, info: ValidationInfo) -> Any:
|
|
129
|
+
"""
|
|
130
|
+
Universal validator for enum fields and record references.
|
|
131
|
+
|
|
132
|
+
Automatically handles:
|
|
133
|
+
- Converting enum names (strings) to enum instances
|
|
134
|
+
- Validating enum values
|
|
135
|
+
- Processing RecordID references
|
|
136
|
+
|
|
137
|
+
Args:
|
|
138
|
+
v: The value to validate
|
|
139
|
+
info: Validation context with field information
|
|
140
|
+
|
|
141
|
+
Returns:
|
|
142
|
+
The validated/converted value
|
|
143
|
+
"""
|
|
144
|
+
constructor = cls._table.name_to_type.get(info.field_name)
|
|
145
|
+
if inspect.isclass(constructor) and issubclass(constructor, Enum):
|
|
146
|
+
if isinstance(v, constructor):
|
|
147
|
+
return v
|
|
148
|
+
name = constructor[v]
|
|
149
|
+
return name
|
|
150
|
+
# if isinstance(v, RecordID) and not info.field_name == "id":
|
|
151
|
+
# try:
|
|
152
|
+
# constructor = cls.child_classes[v.table_name]
|
|
153
|
+
# except KeyError:
|
|
154
|
+
# return v
|
|
155
|
+
# values = {key: None for key in constructor.model_fields}
|
|
156
|
+
# values["id"] = v
|
|
157
|
+
# stub = constructor.model_construct(**values)
|
|
158
|
+
# # def _frozen_setattr(self, name, value):
|
|
159
|
+
# # raise AttributeError(f"Instance {type(self).__name__} is frozen; cannot set {name!r}")
|
|
160
|
+
# # stub.__setattr__ = MethodType(_frozen_setattr, stub)
|
|
161
|
+
# print("stub : ", stub, constructor)
|
|
162
|
+
# return stub
|
|
163
|
+
return v
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def __init_subclass__(cls, **kwargs: Unpack[ConfigDict]):
|
|
167
|
+
discarded = kwargs.pop("discarded", False)
|
|
168
|
+
# Create unique queue for each subclass
|
|
169
|
+
# this queue will be used to chain several object creations
|
|
170
|
+
cls._to_create = LifoQueue()
|
|
171
|
+
cls._discarded = discarded
|
|
172
|
+
return super().__init_subclass__(**kwargs)
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
@classmethod
|
|
176
|
+
def __pydantic_init_subclass__(cls, **kwargs):
|
|
177
|
+
relation = kwargs.pop("relation", None)
|
|
178
|
+
super().__pydantic_init_subclass__(**kwargs)
|
|
179
|
+
|
|
180
|
+
if cls._discarded:
|
|
181
|
+
return
|
|
182
|
+
|
|
183
|
+
model_fields: dict[str, FieldInfo | ComputedFieldInfo] = deepcopy(cls.model_fields)
|
|
184
|
+
model_fields.update(cls.model_computed_fields)
|
|
185
|
+
fields: list[CustomField[Any]] = []
|
|
186
|
+
for field_name, field_info in model_fields.items():
|
|
187
|
+
field_type = field_info.annotation if isinstance(field_info, FieldInfo) else field_info.return_type
|
|
188
|
+
if isinstance(field_info, ComputedFieldInfo):
|
|
189
|
+
field_descriptor = ComputedFieldDescriptor[field_type](field_name, cls.__name__.lower(), field_type or Any, getattr(cls, field_name, None))
|
|
190
|
+
else:
|
|
191
|
+
field_descriptor = CustomField[field_type](field_name, cls.__name__.lower(), field_type or Any)
|
|
192
|
+
fields.append(field_descriptor)
|
|
193
|
+
|
|
194
|
+
# Handle different field types
|
|
195
|
+
nested_class = None
|
|
196
|
+
try:
|
|
197
|
+
# Check if it's a Base subclass directly
|
|
198
|
+
if field_type and hasattr(field_type, '__mro__') and Base in field_type.__mro__:
|
|
199
|
+
nested_class = field_type
|
|
200
|
+
# Check if it's Optional[Base subclass] (Union with None)
|
|
201
|
+
elif hasattr(field_type, '__origin__') and field_type.__origin__ is Union:
|
|
202
|
+
# Get the args of the Union
|
|
203
|
+
args = getattr(field_type, '__args__', ())
|
|
204
|
+
# Filter out None and check if any remaining type is a Base subclass
|
|
205
|
+
for arg in args:
|
|
206
|
+
if arg is not type(None) and hasattr(arg, '__mro__') and Base in arg.__mro__:
|
|
207
|
+
nested_class = arg
|
|
208
|
+
break
|
|
209
|
+
|
|
210
|
+
if nested_class:
|
|
211
|
+
# Create a nested field descriptor that allows chaining
|
|
212
|
+
nested_descriptor = NestedFieldDescriptor(field_name, cls.__name__.lower(), nested_class)
|
|
213
|
+
setattr(cls, field_name, nested_descriptor)
|
|
214
|
+
else:
|
|
215
|
+
setattr(cls, field_name, field_descriptor)
|
|
216
|
+
except (TypeError, AttributeError):
|
|
217
|
+
# For other complex types, just use the field descriptor
|
|
218
|
+
setattr(cls, field_name, field_descriptor)
|
|
219
|
+
|
|
220
|
+
# replace Base instance with Union[annotation, RecordID]
|
|
221
|
+
if field_name in cls.model_fields:
|
|
222
|
+
cls.model_fields[field_name].annotation = replace_type(cls.model_fields[field_name].annotation, Base, Union[Base, RecordID])
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
table = Table(name=cls.__name__.lower(), base_class=Base, model_class=cls, fields=tuple(fields), relation=relation)
|
|
226
|
+
for tokenizer in table.tokenizers:
|
|
227
|
+
Base._tokenizers.add(tokenizer.define())
|
|
228
|
+
|
|
229
|
+
cls._table = table
|
|
230
|
+
# I want to keep _registry as immutable as possible and only append data to it
|
|
231
|
+
Base.add_table(table, cls)
|
|
232
|
+
cls.model_rebuild(force=True)
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
@classmethod
|
|
236
|
+
def registered_tables(cls) -> set[str]:
|
|
237
|
+
"""
|
|
238
|
+
Get the names of all registered tables.
|
|
239
|
+
|
|
240
|
+
Returns:
|
|
241
|
+
set[str]: Set of table names that have been registered
|
|
242
|
+
|
|
243
|
+
Example:
|
|
244
|
+
>>> tables = Base.registered_tables()
|
|
245
|
+
>>> print(tables)
|
|
246
|
+
{'person', 'entity', 'role', ...}
|
|
247
|
+
"""
|
|
248
|
+
return {f.name for f in cls._registry}
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
@classmethod
|
|
252
|
+
def add_table(cls, table: Table, child_class: Type[Base]):
|
|
253
|
+
"""
|
|
254
|
+
Register a new table in the system registry.
|
|
255
|
+
|
|
256
|
+
Args:
|
|
257
|
+
table: The Table definition to register
|
|
258
|
+
child_class: The model class associated with the table
|
|
259
|
+
|
|
260
|
+
Notes:
|
|
261
|
+
This is called automatically when subclasses are defined.
|
|
262
|
+
Users typically don't need to call this directly.
|
|
263
|
+
"""
|
|
264
|
+
cls._registry = tuple(t for t in chain(cls._registry, (table, )))
|
|
265
|
+
cls.child_classes[table.name] = child_class
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
@classmethod
|
|
269
|
+
def registered_models(cls) -> list[Table]:
|
|
270
|
+
"""
|
|
271
|
+
Get all registered table definitions.
|
|
272
|
+
|
|
273
|
+
Returns:
|
|
274
|
+
list[Table]: List of Table objects that have been registered
|
|
275
|
+
|
|
276
|
+
Example:
|
|
277
|
+
>>> models = Base.registered_models()
|
|
278
|
+
>>> for model in models:
|
|
279
|
+
... print(f"Table: {model.name}")
|
|
280
|
+
"""
|
|
281
|
+
return list(cls._registry)
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
@classmethod
|
|
285
|
+
def generate_schema(cls) -> str:
|
|
286
|
+
"""
|
|
287
|
+
Generate complete SurrealQL schema for all registered tables.
|
|
288
|
+
|
|
289
|
+
Creates the SQL statements needed to define all tables, fields, indexes,
|
|
290
|
+
and tokenizers in SurrealDB. This should be executed when setting up
|
|
291
|
+
a new database or updating the schema.
|
|
292
|
+
|
|
293
|
+
Returns:
|
|
294
|
+
str: Complete SurrealQL schema definition
|
|
295
|
+
|
|
296
|
+
Example:
|
|
297
|
+
>>> async with AsyncSurreal(url) as db:
|
|
298
|
+
... await db.signin({"username": "root", "password": "root"})
|
|
299
|
+
... await db.use("mydb", "myns")
|
|
300
|
+
... schema = Base.generate_schema()
|
|
301
|
+
... await db.query(schema)
|
|
302
|
+
|
|
303
|
+
Notes:
|
|
304
|
+
- Includes table definitions with SCHEMAFULL
|
|
305
|
+
- Defines all fields with proper types
|
|
306
|
+
- Sets up full-text search indexes
|
|
307
|
+
- Configures tokenizers for text analysis
|
|
308
|
+
- Creates relationship constraints
|
|
309
|
+
"""
|
|
310
|
+
blocks = [t.generate_table_sql() for t in cls._registry]
|
|
311
|
+
return "\n\n".join(chain(cls._tokenizers, blocks))
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
@classmethod
|
|
315
|
+
def deserialize_record(cls, data: dict) -> Any:
|
|
316
|
+
"""
|
|
317
|
+
Deserialize a SurrealDB record into a Pydantic model instance.
|
|
318
|
+
|
|
319
|
+
Automatically converts SurrealDB records to the appropriate model class
|
|
320
|
+
based on the record's table name.
|
|
321
|
+
|
|
322
|
+
Args:
|
|
323
|
+
data: Dictionary containing the record data from SurrealDB
|
|
324
|
+
|
|
325
|
+
Returns:
|
|
326
|
+
An instance of the appropriate model class, or the original data
|
|
327
|
+
if no matching model is found
|
|
328
|
+
|
|
329
|
+
Notes:
|
|
330
|
+
- Handles edge records by converting 'in' and 'out' to 'in_' and 'out_'
|
|
331
|
+
- Automatically determines the model class from the record ID
|
|
332
|
+
- Validates data using Pydantic validation
|
|
333
|
+
"""
|
|
334
|
+
if not isinstance(data, dict):
|
|
335
|
+
return data
|
|
336
|
+
|
|
337
|
+
if "in" in data and "out" in data:
|
|
338
|
+
data["in_"] = data.pop("in", None)
|
|
339
|
+
data["out_"] = data.pop("out", None)
|
|
340
|
+
|
|
341
|
+
# Get the model class from the record ID
|
|
342
|
+
record_id = data.get('id')
|
|
343
|
+
if not record_id or not isinstance(record_id, RecordID):
|
|
344
|
+
return data
|
|
345
|
+
|
|
346
|
+
model_class = cls.child_classes.get(record_id.table_name)
|
|
347
|
+
if not model_class:
|
|
348
|
+
return data
|
|
349
|
+
|
|
350
|
+
# The model validator will handle RecordID conversion
|
|
351
|
+
# here maybe specify if the users wants related records as ids or full objects
|
|
352
|
+
return model_class.model_validate(data, context="could this parameter be of any use ?")
|
|
353
|
+
|
|
354
|
+
|
|
355
|
+
@classmethod
|
|
356
|
+
def deserialize_response(cls, response: Any) -> Any:
|
|
357
|
+
"""
|
|
358
|
+
Deserialize a complete SurrealDB response.
|
|
359
|
+
|
|
360
|
+
Recursively processes responses to convert all records to their
|
|
361
|
+
appropriate model instances.
|
|
362
|
+
|
|
363
|
+
Args:
|
|
364
|
+
response: The response from SurrealDB (can be list, dict, or primitive)
|
|
365
|
+
|
|
366
|
+
Returns:
|
|
367
|
+
The deserialized response with records converted to model instances
|
|
368
|
+
|
|
369
|
+
Example:
|
|
370
|
+
>>> result = await db.select("person")
|
|
371
|
+
>>> people = Base.deserialize_response(result)
|
|
372
|
+
>>> # people is now a list of Person instances
|
|
373
|
+
"""
|
|
374
|
+
if isinstance(response, list):
|
|
375
|
+
return [cls.deserialize_record(item) if isinstance(item, dict) else item for item in response]
|
|
376
|
+
elif isinstance(response, dict):
|
|
377
|
+
return cls.deserialize_record(response)
|
|
378
|
+
return response
|
|
379
|
+
|
|
380
|
+
|
|
381
|
+
def db_dump(self) -> dict[str, Any]:
|
|
382
|
+
"""
|
|
383
|
+
Serialize the model instance for database insertion/update.
|
|
384
|
+
|
|
385
|
+
Prepares the model data for sending to SurrealDB by:
|
|
386
|
+
- Removing the ID field (handled separately by SurrealDB)
|
|
387
|
+
- Converting Python types to SurrealDB-compatible formats
|
|
388
|
+
- Serializing nested objects appropriately
|
|
389
|
+
|
|
390
|
+
Returns:
|
|
391
|
+
dict[str, Any]: Dictionary ready for database operations
|
|
392
|
+
|
|
393
|
+
Example:
|
|
394
|
+
>>> person = Person(first_name="John", last_name="Doe")
|
|
395
|
+
>>> data = person.db_dump()
|
|
396
|
+
>>> await db.create("person", data)
|
|
397
|
+
"""
|
|
398
|
+
serialized = self.model_dump(context={"root": True})
|
|
399
|
+
serialized.pop('id', None)
|
|
400
|
+
# this convert_types fonction is only here
|
|
401
|
+
return convert_types(serialized)
|
tapestry/base.pyi
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any, ClassVar, Optional, Type, TypeVar, Unpack, Union, Self
|
|
4
|
+
from queue import LifoQueue
|
|
5
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
6
|
+
from pydantic.fields import FieldInfo, ComputedFieldInfo
|
|
7
|
+
from surrealdb import AsyncWsSurrealConnection, AsyncHttpSurrealConnection, RecordID
|
|
8
|
+
|
|
9
|
+
from .table import Table
|
|
10
|
+
|
|
11
|
+
T = TypeVar('T', bound='Base')
|
|
12
|
+
|
|
13
|
+
class Base(BaseModel):
|
|
14
|
+
id: RecordID | None
|
|
15
|
+
|
|
16
|
+
_registry: ClassVar[tuple[Table, ...]]
|
|
17
|
+
_tokenizers: ClassVar[set[str]]
|
|
18
|
+
_to_create: ClassVar[LifoQueue[Base]]
|
|
19
|
+
child_classes: ClassVar[dict[str, Type[Base]]]
|
|
20
|
+
_table: ClassVar[Table]
|
|
21
|
+
_discarded: ClassVar[bool]
|
|
22
|
+
|
|
23
|
+
@classmethod
|
|
24
|
+
def validate_record_id(cls, v: Any) -> Optional[RecordID]: ...
|
|
25
|
+
|
|
26
|
+
def _serialize(self, serializer: Any, info: Any) -> Any: ...
|
|
27
|
+
|
|
28
|
+
@classmethod
|
|
29
|
+
def validate_enums(cls, v: Any, info: Any) -> Any: ...
|
|
30
|
+
|
|
31
|
+
def __init_subclass__(cls, **kwargs: Unpack[ConfigDict]) -> None: ...
|
|
32
|
+
|
|
33
|
+
@classmethod
|
|
34
|
+
def __pydantic_init_subclass__(cls, **kwargs: Any) -> None: ...
|
|
35
|
+
|
|
36
|
+
@classmethod
|
|
37
|
+
def registered_tables(cls) -> set[str]: ...
|
|
38
|
+
|
|
39
|
+
@classmethod
|
|
40
|
+
def add_table(cls, table: Table, child_class: Type[Base]) -> None: ...
|
|
41
|
+
|
|
42
|
+
@classmethod
|
|
43
|
+
def registered_models(cls) -> list[Table]: ...
|
|
44
|
+
|
|
45
|
+
@classmethod
|
|
46
|
+
def generate_schema(cls) -> str: ...
|
|
47
|
+
|
|
48
|
+
@classmethod
|
|
49
|
+
def deserialize_record(cls, data: dict[str, Any]) -> Any: ...
|
|
50
|
+
|
|
51
|
+
@classmethod
|
|
52
|
+
def deserialize_response(cls, response: Any) -> Any: ...
|
|
53
|
+
|
|
54
|
+
def db_dump(self) -> dict[str, Any]: ...
|