beanis 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.
- beanis/__init__.py +50 -0
- beanis/exceptions.py +74 -0
- beanis/executors/__init__.py +0 -0
- beanis/executors/migrate.py +221 -0
- beanis/migrations/__init__.py +0 -0
- beanis/migrations/controllers/__init__.py +0 -0
- beanis/migrations/controllers/base.py +18 -0
- beanis/migrations/controllers/free_fall.py +28 -0
- beanis/migrations/controllers/iterative.py +130 -0
- beanis/migrations/database.py +16 -0
- beanis/migrations/models.py +33 -0
- beanis/migrations/runner.py +240 -0
- beanis/migrations/template.py +6 -0
- beanis/migrations/utils.py +7 -0
- beanis/odm/__init__.py +0 -0
- beanis/odm/actions.py +257 -0
- beanis/odm/cache.py +45 -0
- beanis/odm/custom_types/__init__.py +10 -0
- beanis/odm/custom_types/bson/__init__.py +0 -0
- beanis/odm/custom_types/bson/binary.py +0 -0
- beanis/odm/custom_types/decimal.py +12 -0
- beanis/odm/documents.py +431 -0
- beanis/odm/enums.py +10 -0
- beanis/odm/fields.py +158 -0
- beanis/odm/interfaces/__init__.py +0 -0
- beanis/odm/interfaces/clone.py +6 -0
- beanis/odm/interfaces/detector.py +13 -0
- beanis/odm/interfaces/find.py +480 -0
- beanis/odm/interfaces/getters.py +28 -0
- beanis/odm/interfaces/inheritance.py +19 -0
- beanis/odm/interfaces/session.py +19 -0
- beanis/odm/interfaces/setters.py +28 -0
- beanis/odm/models.py +24 -0
- beanis/odm/operators/__init__.py +40 -0
- beanis/odm/operators/find/__init__.py +7 -0
- beanis/odm/operators/find/array.py +121 -0
- beanis/odm/operators/find/bitwise.py +60 -0
- beanis/odm/operators/find/comparison.py +227 -0
- beanis/odm/operators/find/element.py +76 -0
- beanis/odm/operators/find/evaluation.py +193 -0
- beanis/odm/operators/find/geospatial.py +316 -0
- beanis/odm/operators/find/logical.py +166 -0
- beanis/odm/operators/update/__init__.py +11 -0
- beanis/odm/operators/update/array.py +142 -0
- beanis/odm/operators/update/bitwise.py +23 -0
- beanis/odm/operators/update/general.py +234 -0
- beanis/odm/registry.py +31 -0
- beanis/odm/settings/__init__.py +0 -0
- beanis/odm/settings/base.py +21 -0
- beanis/odm/settings/document.py +38 -0
- beanis/odm/settings/timeseries.py +43 -0
- beanis/odm/settings/union_doc.py +5 -0
- beanis/odm/settings/view.py +13 -0
- beanis/odm/utils/__init__.py +0 -0
- beanis/odm/utils/dump.py +50 -0
- beanis/odm/utils/encoder.py +142 -0
- beanis/odm/utils/find.py +403 -0
- beanis/odm/utils/general.py +0 -0
- beanis/odm/utils/init.py +311 -0
- beanis/odm/utils/parsing.py +148 -0
- beanis/odm/utils/projection.py +36 -0
- beanis/odm/utils/pydantic.py +62 -0
- beanis/odm/utils/relations.py +50 -0
- beanis/odm/utils/self_validation.py +21 -0
- beanis/odm/utils/state.py +89 -0
- beanis/odm/utils/typing.py +74 -0
- beanis/operators.py +118 -0
- beanis/py.typed +0 -0
- beanis/pydantic_check.py +5 -0
- beanis/test.py +47 -0
- beanis-0.0.1.dist-info/LICENSE +201 -0
- beanis-0.0.1.dist-info/METADATA +135 -0
- beanis-0.0.1.dist-info/RECORD +75 -0
- beanis-0.0.1.dist-info/WHEEL +4 -0
- beanis-0.0.1.dist-info/entry_points.txt +3 -0
beanis/__init__.py
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
from beanis.migrations.controllers.free_fall import free_fall_migration
|
|
2
|
+
from beanis.migrations.controllers.iterative import iterative_migration
|
|
3
|
+
from beanis.odm.actions import (
|
|
4
|
+
After,
|
|
5
|
+
Before,
|
|
6
|
+
Delete,
|
|
7
|
+
Insert,
|
|
8
|
+
Replace,
|
|
9
|
+
Save,
|
|
10
|
+
SaveChanges,
|
|
11
|
+
Update,
|
|
12
|
+
ValidateOnSave,
|
|
13
|
+
after_event,
|
|
14
|
+
before_event,
|
|
15
|
+
)
|
|
16
|
+
from beanis.odm.custom_types import DecimalAnnotation
|
|
17
|
+
from beanis.odm.documents import (
|
|
18
|
+
Document,
|
|
19
|
+
MergeStrategy,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
from beanis.odm.settings.timeseries import Granularity, TimeSeriesConfig
|
|
23
|
+
from beanis.odm.utils.init import init_beanis
|
|
24
|
+
|
|
25
|
+
__version__ = "0.0.1"
|
|
26
|
+
__all__ = [
|
|
27
|
+
# ODM
|
|
28
|
+
"Document",
|
|
29
|
+
"init_beanis",
|
|
30
|
+
"TimeSeriesConfig",
|
|
31
|
+
"Granularity",
|
|
32
|
+
"MergeStrategy",
|
|
33
|
+
# Actions
|
|
34
|
+
"before_event",
|
|
35
|
+
"after_event",
|
|
36
|
+
"Insert",
|
|
37
|
+
"Replace",
|
|
38
|
+
"Save",
|
|
39
|
+
"SaveChanges",
|
|
40
|
+
"ValidateOnSave",
|
|
41
|
+
"Delete",
|
|
42
|
+
"Before",
|
|
43
|
+
"After",
|
|
44
|
+
"Update",
|
|
45
|
+
# Migrations
|
|
46
|
+
"iterative_migration",
|
|
47
|
+
"free_fall_migration",
|
|
48
|
+
# Custom Types
|
|
49
|
+
"DecimalAnnotation",
|
|
50
|
+
]
|
beanis/exceptions.py
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
class WrongDocumentUpdateStrategy(Exception):
|
|
2
|
+
pass
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class DocumentNotFound(Exception):
|
|
6
|
+
pass
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class DocumentAlreadyCreated(Exception):
|
|
10
|
+
pass
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class DocumentWasNotSaved(Exception):
|
|
14
|
+
pass
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class CollectionWasNotInitialized(Exception):
|
|
18
|
+
pass
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class MigrationException(Exception):
|
|
22
|
+
pass
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class ReplaceError(Exception):
|
|
26
|
+
pass
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class StateManagementIsTurnedOff(Exception):
|
|
30
|
+
pass
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class StateNotSaved(Exception):
|
|
34
|
+
pass
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class RevisionIdWasChanged(Exception):
|
|
38
|
+
pass
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class NotSupported(Exception):
|
|
42
|
+
pass
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class MongoDBVersionError(Exception):
|
|
46
|
+
pass
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class ViewWasNotInitialized(Exception):
|
|
50
|
+
pass
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class ViewHasNoSettings(Exception):
|
|
54
|
+
pass
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class UnionHasNoRegisteredDocs(Exception):
|
|
58
|
+
pass
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class UnionDocNotInited(Exception):
|
|
62
|
+
pass
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class DocWasNotRegisteredInUnionClass(Exception):
|
|
66
|
+
pass
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class Deprecation(Exception):
|
|
70
|
+
pass
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class ApplyChangesException(Exception):
|
|
74
|
+
pass
|
|
File without changes
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import logging
|
|
3
|
+
import os
|
|
4
|
+
import shutil
|
|
5
|
+
from datetime import datetime
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import Any
|
|
8
|
+
|
|
9
|
+
import click
|
|
10
|
+
import toml
|
|
11
|
+
|
|
12
|
+
from beanis.migrations import template
|
|
13
|
+
from beanis.migrations.database import DBHandler
|
|
14
|
+
from beanis.migrations.models import RunningDirections, RunningMode
|
|
15
|
+
from beanis.migrations.runner import MigrationNode
|
|
16
|
+
|
|
17
|
+
logging.basicConfig(format="%(message)s", level=logging.INFO)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class MigrationSettings:
|
|
21
|
+
def __init__(self, **kwargs):
|
|
22
|
+
self.direction = (
|
|
23
|
+
kwargs.get("direction")
|
|
24
|
+
or self.get_env_value("direction")
|
|
25
|
+
or self.get_from_toml("direction")
|
|
26
|
+
or RunningDirections.FORWARD
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
self.distance = int(
|
|
30
|
+
kwargs.get("distance")
|
|
31
|
+
or self.get_env_value("distance")
|
|
32
|
+
or self.get_from_toml("distance")
|
|
33
|
+
or 0
|
|
34
|
+
)
|
|
35
|
+
self.connection_uri = str(
|
|
36
|
+
kwargs.get("connection_uri")
|
|
37
|
+
or self.get_env_value("connection_uri")
|
|
38
|
+
or self.get_from_toml("connection_uri")
|
|
39
|
+
)
|
|
40
|
+
self.database_name = str(
|
|
41
|
+
kwargs.get("database_name")
|
|
42
|
+
or self.get_env_value("database_name")
|
|
43
|
+
or self.get_from_toml("database_name")
|
|
44
|
+
)
|
|
45
|
+
self.path = Path(
|
|
46
|
+
kwargs.get("path")
|
|
47
|
+
or self.get_env_value("path")
|
|
48
|
+
or self.get_from_toml("path")
|
|
49
|
+
)
|
|
50
|
+
self.allow_index_dropping = bool(
|
|
51
|
+
kwargs.get("allow_index_dropping")
|
|
52
|
+
or self.get_env_value("allow_index_dropping")
|
|
53
|
+
or self.get_from_toml("allow_index_dropping")
|
|
54
|
+
or False
|
|
55
|
+
)
|
|
56
|
+
self.use_transaction = bool(kwargs.get("use_transaction"))
|
|
57
|
+
|
|
58
|
+
@staticmethod
|
|
59
|
+
def get_env_value(field_name) -> Any:
|
|
60
|
+
if field_name == "connection_uri":
|
|
61
|
+
value = (
|
|
62
|
+
os.environ.get("BEANIE_URI")
|
|
63
|
+
or os.environ.get("BEANIE_CONNECTION_URI")
|
|
64
|
+
or os.environ.get("BEANIE_CONNECTION_STRING")
|
|
65
|
+
or os.environ.get("BEANIE_MONGODB_DSN")
|
|
66
|
+
or os.environ.get("BEANIE_MONGODB_URI")
|
|
67
|
+
or os.environ.get("beanie_uri")
|
|
68
|
+
or os.environ.get("beanie_connection_uri")
|
|
69
|
+
or os.environ.get("beanie_connection_string")
|
|
70
|
+
or os.environ.get("beanie_mongodb_dsn")
|
|
71
|
+
or os.environ.get("beanie_mongodb_uri")
|
|
72
|
+
)
|
|
73
|
+
elif field_name == "database_name":
|
|
74
|
+
value = (
|
|
75
|
+
os.environ.get("BEANIE_DB")
|
|
76
|
+
or os.environ.get("BEANIE_DB_NAME")
|
|
77
|
+
or os.environ.get("BEANIE_DATABASE_NAME")
|
|
78
|
+
or os.environ.get("beanie_db")
|
|
79
|
+
or os.environ.get("beanie_db_name")
|
|
80
|
+
or os.environ.get("beanie_database_name")
|
|
81
|
+
)
|
|
82
|
+
else:
|
|
83
|
+
value = os.environ.get(
|
|
84
|
+
f"BEANIE_{field_name.upper()}"
|
|
85
|
+
) or os.environ.get(f"beanie_{field_name.lower()}")
|
|
86
|
+
return value
|
|
87
|
+
|
|
88
|
+
@staticmethod
|
|
89
|
+
def get_from_toml(field_name) -> Any:
|
|
90
|
+
path = Path("pyproject.toml")
|
|
91
|
+
if path.is_file():
|
|
92
|
+
val = (
|
|
93
|
+
toml.load(path)
|
|
94
|
+
.get("tool", {})
|
|
95
|
+
.get("beanis", {})
|
|
96
|
+
.get("migrations", {})
|
|
97
|
+
)
|
|
98
|
+
else:
|
|
99
|
+
val = {}
|
|
100
|
+
return val.get(field_name)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
@click.group()
|
|
104
|
+
def migrations():
|
|
105
|
+
pass
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
async def run_migrate(settings: MigrationSettings):
|
|
109
|
+
DBHandler.set_db(settings.connection_uri, settings.database_name)
|
|
110
|
+
root = await MigrationNode.build(settings.path)
|
|
111
|
+
mode = RunningMode(
|
|
112
|
+
direction=settings.direction, distance=settings.distance
|
|
113
|
+
)
|
|
114
|
+
await root.run(
|
|
115
|
+
mode=mode,
|
|
116
|
+
allow_index_dropping=settings.allow_index_dropping,
|
|
117
|
+
use_transaction=settings.use_transaction,
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
@migrations.command()
|
|
122
|
+
@click.option(
|
|
123
|
+
"--forward",
|
|
124
|
+
"direction",
|
|
125
|
+
required=False,
|
|
126
|
+
flag_value="FORWARD",
|
|
127
|
+
help="Roll the migrations forward. This is default",
|
|
128
|
+
)
|
|
129
|
+
@click.option(
|
|
130
|
+
"--backward",
|
|
131
|
+
"direction",
|
|
132
|
+
required=False,
|
|
133
|
+
flag_value="BACKWARD",
|
|
134
|
+
help="Roll the migrations backward",
|
|
135
|
+
)
|
|
136
|
+
@click.option(
|
|
137
|
+
"-d",
|
|
138
|
+
"--distance",
|
|
139
|
+
required=False,
|
|
140
|
+
help="How many migrations should be done since the current? "
|
|
141
|
+
"0 - all the migrations. Default is 0",
|
|
142
|
+
)
|
|
143
|
+
@click.option(
|
|
144
|
+
"-uri",
|
|
145
|
+
"--connection-uri",
|
|
146
|
+
required=False,
|
|
147
|
+
type=str,
|
|
148
|
+
help="MongoDB connection URI",
|
|
149
|
+
)
|
|
150
|
+
@click.option(
|
|
151
|
+
"-db", "--database_name", required=False, type=str, help="DataBase name"
|
|
152
|
+
)
|
|
153
|
+
@click.option(
|
|
154
|
+
"-p",
|
|
155
|
+
"--path",
|
|
156
|
+
required=False,
|
|
157
|
+
type=str,
|
|
158
|
+
help="Path to the migrations directory",
|
|
159
|
+
)
|
|
160
|
+
@click.option(
|
|
161
|
+
"--allow-index-dropping/--forbid-index-dropping",
|
|
162
|
+
required=False,
|
|
163
|
+
default=False,
|
|
164
|
+
help="if allow-index-dropping is set, Beanie will drop indexes from your collection",
|
|
165
|
+
)
|
|
166
|
+
@click.option(
|
|
167
|
+
"--use-transaction/--no-use-transaction",
|
|
168
|
+
required=False,
|
|
169
|
+
default=True,
|
|
170
|
+
help="Enable or disable the use of transactions during migration. "
|
|
171
|
+
"When enabled (--use-transaction), Beanie uses transactions for migration, "
|
|
172
|
+
"which necessitates a replica set. When disabled (--no-use-transaction), "
|
|
173
|
+
"migrations occur without transactions.",
|
|
174
|
+
)
|
|
175
|
+
def migrate(
|
|
176
|
+
direction,
|
|
177
|
+
distance,
|
|
178
|
+
connection_uri,
|
|
179
|
+
database_name,
|
|
180
|
+
path,
|
|
181
|
+
allow_index_dropping,
|
|
182
|
+
use_transaction,
|
|
183
|
+
):
|
|
184
|
+
settings_kwargs = {}
|
|
185
|
+
if direction:
|
|
186
|
+
settings_kwargs["direction"] = direction
|
|
187
|
+
if distance:
|
|
188
|
+
settings_kwargs["distance"] = distance
|
|
189
|
+
if connection_uri:
|
|
190
|
+
settings_kwargs["connection_uri"] = connection_uri
|
|
191
|
+
if database_name:
|
|
192
|
+
settings_kwargs["database_name"] = database_name
|
|
193
|
+
if path:
|
|
194
|
+
settings_kwargs["path"] = path
|
|
195
|
+
if allow_index_dropping:
|
|
196
|
+
settings_kwargs["allow_index_dropping"] = allow_index_dropping
|
|
197
|
+
settings_kwargs["use_transaction"] = use_transaction
|
|
198
|
+
settings = MigrationSettings(**settings_kwargs)
|
|
199
|
+
|
|
200
|
+
asyncio.run(run_migrate(settings))
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
@migrations.command()
|
|
204
|
+
@click.option("-n", "--name", required=True, type=str, help="Migration name")
|
|
205
|
+
@click.option(
|
|
206
|
+
"-p",
|
|
207
|
+
"--path",
|
|
208
|
+
required=True,
|
|
209
|
+
type=str,
|
|
210
|
+
help="Path to the migrations directory",
|
|
211
|
+
)
|
|
212
|
+
def new_migration(name, path):
|
|
213
|
+
path = Path(path)
|
|
214
|
+
ts_string = datetime.now().strftime("%Y%m%d%H%M%S")
|
|
215
|
+
file_name = f"{ts_string}_{name}.py"
|
|
216
|
+
|
|
217
|
+
shutil.copy(template.__file__, path / file_name)
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
if __name__ == "__main__":
|
|
221
|
+
migrations()
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
from typing import List, Type
|
|
3
|
+
|
|
4
|
+
from beanis.odm.documents import Document
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class BaseMigrationController(ABC):
|
|
8
|
+
def __init__(self, function):
|
|
9
|
+
self.function = function
|
|
10
|
+
|
|
11
|
+
@abstractmethod
|
|
12
|
+
async def run(self, session):
|
|
13
|
+
pass
|
|
14
|
+
|
|
15
|
+
@property
|
|
16
|
+
@abstractmethod
|
|
17
|
+
def models(self) -> List[Type[Document]]:
|
|
18
|
+
pass
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
from inspect import signature
|
|
2
|
+
from typing import List, Type
|
|
3
|
+
|
|
4
|
+
from beanis.migrations.controllers.base import BaseMigrationController
|
|
5
|
+
from beanis.odm.documents import Document
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def free_fall_migration(document_models: List[Type[Document]]):
|
|
9
|
+
class FreeFallMigrationController(BaseMigrationController):
|
|
10
|
+
def __init__(self, function):
|
|
11
|
+
self.function = function
|
|
12
|
+
self.function_signature = signature(function)
|
|
13
|
+
self.document_models = document_models
|
|
14
|
+
|
|
15
|
+
def __call__(self, *args, **kwargs):
|
|
16
|
+
pass
|
|
17
|
+
|
|
18
|
+
@property
|
|
19
|
+
def models(self) -> List[Type[Document]]:
|
|
20
|
+
return self.document_models
|
|
21
|
+
|
|
22
|
+
async def run(self, session):
|
|
23
|
+
function_kwargs = {"session": session}
|
|
24
|
+
if "self" in self.function_signature.parameters:
|
|
25
|
+
function_kwargs["self"] = None
|
|
26
|
+
await self.function(**function_kwargs)
|
|
27
|
+
|
|
28
|
+
return FreeFallMigrationController
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
from inspect import isclass, signature
|
|
3
|
+
from typing import List, Optional, Type, Union
|
|
4
|
+
|
|
5
|
+
from beanis.migrations.controllers.base import BaseMigrationController
|
|
6
|
+
from beanis.migrations.utils import update_dict
|
|
7
|
+
from beanis.odm.documents import Document
|
|
8
|
+
from beanis.odm.utils.pydantic import parse_model
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class DummyOutput:
|
|
12
|
+
def __init__(self):
|
|
13
|
+
super(DummyOutput, self).__setattr__("_internal_structure_dict", {})
|
|
14
|
+
|
|
15
|
+
def __setattr__(self, key, value):
|
|
16
|
+
self._internal_structure_dict[key] = value
|
|
17
|
+
|
|
18
|
+
def __getattr__(self, item):
|
|
19
|
+
try:
|
|
20
|
+
return self._internal_structure_dict[item]
|
|
21
|
+
except KeyError:
|
|
22
|
+
self._internal_structure_dict[item] = DummyOutput()
|
|
23
|
+
return self._internal_structure_dict[item]
|
|
24
|
+
|
|
25
|
+
def dict(self, to_parse: Optional[Union[dict, "DummyOutput"]] = None):
|
|
26
|
+
if to_parse is None:
|
|
27
|
+
to_parse = self
|
|
28
|
+
input_dict = (
|
|
29
|
+
to_parse._internal_structure_dict
|
|
30
|
+
if isinstance(to_parse, DummyOutput)
|
|
31
|
+
else to_parse
|
|
32
|
+
)
|
|
33
|
+
result_dict = {}
|
|
34
|
+
for key, value in input_dict.items():
|
|
35
|
+
if isinstance(value, (DummyOutput, dict)):
|
|
36
|
+
result_dict[key] = self.dict(to_parse=value)
|
|
37
|
+
else:
|
|
38
|
+
result_dict[key] = value
|
|
39
|
+
return result_dict
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def iterative_migration(
|
|
43
|
+
document_models: Optional[List[Type[Document]]] = None,
|
|
44
|
+
batch_size: int = 10000,
|
|
45
|
+
):
|
|
46
|
+
class IterativeMigration(BaseMigrationController):
|
|
47
|
+
def __init__(self, function):
|
|
48
|
+
self.function = function
|
|
49
|
+
self.function_signature = signature(function)
|
|
50
|
+
input_signature = self.function_signature.parameters.get(
|
|
51
|
+
"input_document"
|
|
52
|
+
)
|
|
53
|
+
if input_signature is None:
|
|
54
|
+
raise RuntimeError("input_signature must not be None")
|
|
55
|
+
self.input_document_model: Type[
|
|
56
|
+
Document
|
|
57
|
+
] = input_signature.annotation
|
|
58
|
+
output_signature = self.function_signature.parameters.get(
|
|
59
|
+
"output_document"
|
|
60
|
+
)
|
|
61
|
+
if output_signature is None:
|
|
62
|
+
raise RuntimeError("output_signature must not be None")
|
|
63
|
+
self.output_document_model: Type[
|
|
64
|
+
Document
|
|
65
|
+
] = output_signature.annotation
|
|
66
|
+
|
|
67
|
+
if (
|
|
68
|
+
not isclass(self.input_document_model)
|
|
69
|
+
or not issubclass(self.input_document_model, Document)
|
|
70
|
+
or not isclass(self.output_document_model)
|
|
71
|
+
or not issubclass(self.output_document_model, Document)
|
|
72
|
+
):
|
|
73
|
+
raise TypeError(
|
|
74
|
+
"input_document and output_document "
|
|
75
|
+
"must have annotation of Document subclass"
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
self.batch_size = batch_size
|
|
79
|
+
|
|
80
|
+
def __call__(self, *args, **kwargs):
|
|
81
|
+
pass
|
|
82
|
+
|
|
83
|
+
@property
|
|
84
|
+
def models(self) -> List[Type[Document]]:
|
|
85
|
+
preset_models = document_models
|
|
86
|
+
if preset_models is None:
|
|
87
|
+
preset_models = []
|
|
88
|
+
return preset_models + [
|
|
89
|
+
self.input_document_model,
|
|
90
|
+
self.output_document_model,
|
|
91
|
+
]
|
|
92
|
+
|
|
93
|
+
async def run(self, session):
|
|
94
|
+
output_documents = []
|
|
95
|
+
all_migration_ops = []
|
|
96
|
+
async for input_document in self.input_document_model.find_all(
|
|
97
|
+
session=session
|
|
98
|
+
):
|
|
99
|
+
output = DummyOutput()
|
|
100
|
+
function_kwargs = {
|
|
101
|
+
"input_document": input_document,
|
|
102
|
+
"output_document": output,
|
|
103
|
+
}
|
|
104
|
+
if "self" in self.function_signature.parameters:
|
|
105
|
+
function_kwargs["self"] = None
|
|
106
|
+
await self.function(**function_kwargs)
|
|
107
|
+
output_dict = input_document.dict()
|
|
108
|
+
update_dict(output_dict, output.dict())
|
|
109
|
+
output_document = parse_model(
|
|
110
|
+
self.output_document_model, output_dict
|
|
111
|
+
)
|
|
112
|
+
output_documents.append(output_document)
|
|
113
|
+
|
|
114
|
+
if len(output_documents) == self.batch_size:
|
|
115
|
+
all_migration_ops.append(
|
|
116
|
+
self.output_document_model.replace_many(
|
|
117
|
+
documents=output_documents, session=session
|
|
118
|
+
)
|
|
119
|
+
)
|
|
120
|
+
output_documents = []
|
|
121
|
+
|
|
122
|
+
if output_documents:
|
|
123
|
+
all_migration_ops.append(
|
|
124
|
+
self.output_document_model.replace_many(
|
|
125
|
+
documents=output_documents, session=session
|
|
126
|
+
)
|
|
127
|
+
)
|
|
128
|
+
await asyncio.gather(*all_migration_ops)
|
|
129
|
+
|
|
130
|
+
return IterativeMigration
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import motor.motor_asyncio
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class DBHandler:
|
|
5
|
+
@classmethod
|
|
6
|
+
def set_db(cls, uri, db_name):
|
|
7
|
+
cls.client = motor.motor_asyncio.AsyncIOMotorClient(uri)
|
|
8
|
+
cls.database = cls.client[db_name]
|
|
9
|
+
|
|
10
|
+
@classmethod
|
|
11
|
+
def get_cli(cls):
|
|
12
|
+
return cls.client if hasattr(cls, "client") else None
|
|
13
|
+
|
|
14
|
+
@classmethod
|
|
15
|
+
def get_db(cls):
|
|
16
|
+
return cls.database if hasattr(cls, "database") else None
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
from enum import Enum
|
|
3
|
+
from typing import List, Optional
|
|
4
|
+
|
|
5
|
+
from pydantic import Field
|
|
6
|
+
from pydantic.main import BaseModel
|
|
7
|
+
|
|
8
|
+
from beanis.odm.documents import Document
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class MigrationLog(Document):
|
|
12
|
+
ts: datetime = Field(default_factory=datetime.now)
|
|
13
|
+
name: str
|
|
14
|
+
is_current: bool
|
|
15
|
+
|
|
16
|
+
class Settings:
|
|
17
|
+
name = "migrations_log"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class RunningDirections(str, Enum):
|
|
21
|
+
FORWARD = "FORWARD"
|
|
22
|
+
BACKWARD = "BACKWARD"
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class RunningMode(BaseModel):
|
|
26
|
+
direction: RunningDirections
|
|
27
|
+
distance: int = 0
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class ParsedMigrations(BaseModel):
|
|
31
|
+
path: str
|
|
32
|
+
names: List[str]
|
|
33
|
+
current: Optional[MigrationLog] = None
|