konecty-sdk-python 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.
- cli/__init__.py +7 -0
- cli/apply.py +455 -0
- cli/backup.py +129 -0
- cli/pull.py +262 -0
- konecty_sdk_python-0.1.0.dist-info/METADATA +30 -0
- konecty_sdk_python-0.1.0.dist-info/RECORD +13 -0
- konecty_sdk_python-0.1.0.dist-info/WHEEL +4 -0
- lib/client.py +423 -0
- lib/file_manager.py +248 -0
- lib/filters.py +155 -0
- lib/model.py +76 -0
- lib/settings.py +115 -0
- lib/types.py +303 -0
cli/pull.py
ADDED
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
"""Script para extrair dados do MongoDB e gerar arquivos JSON."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Any, Dict, List, Literal, Optional, TypedDict, Union, cast
|
|
6
|
+
|
|
7
|
+
import black
|
|
8
|
+
import inquirer
|
|
9
|
+
from pymongo import MongoClient
|
|
10
|
+
from rich.console import Console
|
|
11
|
+
from rich.progress import Progress
|
|
12
|
+
from rich.table import Table
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class DocFiles(TypedDict):
|
|
16
|
+
document: List[Path]
|
|
17
|
+
view: List[Path]
|
|
18
|
+
list: List[Path]
|
|
19
|
+
pivot: List[Path]
|
|
20
|
+
access: List[Path]
|
|
21
|
+
hook: List[Path]
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class RelatedResults(TypedDict):
|
|
25
|
+
view: List[str]
|
|
26
|
+
list: List[str]
|
|
27
|
+
pivot: List[str]
|
|
28
|
+
access: List[str]
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class MongoFilter(TypedDict, total=False):
|
|
32
|
+
document: str
|
|
33
|
+
type: str
|
|
34
|
+
name: str
|
|
35
|
+
or_conditions: List[Dict[str, str]]
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class MongoCondition(TypedDict, total=False):
|
|
39
|
+
type: str
|
|
40
|
+
name: str
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
MongoQuery = Dict[str, Union[str, List[MongoCondition]]]
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
DocType = Literal["document", "view", "list", "pivot", "access", "hook"]
|
|
47
|
+
MetaType = Literal["view", "list", "pivot", "access"]
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
console = Console()
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def format_code(name: str, code: str) -> str:
|
|
54
|
+
"""Formata o código JavaScript usando black."""
|
|
55
|
+
try:
|
|
56
|
+
return black.format_str(code, mode=black.Mode())
|
|
57
|
+
except Exception as error:
|
|
58
|
+
console.print(f"[red]Erro ao formatar código {name}[/red]: {str(error)}")
|
|
59
|
+
return code
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
async def write_file(file_path: str, content: str) -> None:
|
|
63
|
+
"""Escreve conteúdo em um arquivo, criando diretórios se necessário."""
|
|
64
|
+
try:
|
|
65
|
+
path = Path(file_path)
|
|
66
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
67
|
+
path.write_text(content)
|
|
68
|
+
except Exception as error:
|
|
69
|
+
console.print(f"[red]Erro ao escrever arquivo {file_path}[/red]: {str(error)}")
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
async def pull_command(
|
|
73
|
+
doc_parameter: Optional[str] = None,
|
|
74
|
+
host: str = "localhost",
|
|
75
|
+
port: int = 27017,
|
|
76
|
+
database: str = "default",
|
|
77
|
+
output: str = "metadata",
|
|
78
|
+
view: Optional[str] = None,
|
|
79
|
+
list_param: Optional[str] = None,
|
|
80
|
+
pivot: Optional[str] = None,
|
|
81
|
+
access: Optional[str] = None,
|
|
82
|
+
hook: Optional[str] = None,
|
|
83
|
+
username: Optional[str] = None,
|
|
84
|
+
password: Optional[str] = None,
|
|
85
|
+
replicaset: Optional[str] = None,
|
|
86
|
+
extract_all: bool = False,
|
|
87
|
+
) -> None:
|
|
88
|
+
"""Extrai dados do MongoDB e gera arquivos JSON."""
|
|
89
|
+
output_dir = Path(output).resolve()
|
|
90
|
+
|
|
91
|
+
uri_params = []
|
|
92
|
+
if replicaset:
|
|
93
|
+
uri_params.extend([f"replicaSet={replicaset}", "directConnection=false", "retryWrites=true", "w=majority"])
|
|
94
|
+
|
|
95
|
+
uri_suffix = f"?{'&'.join(uri_params)}" if uri_params else ""
|
|
96
|
+
|
|
97
|
+
if username and password:
|
|
98
|
+
uri = f"mongodb://{username}:{password}@{host}:{port}/admin{uri_suffix}"
|
|
99
|
+
else:
|
|
100
|
+
uri = f"mongodb://{host}:{port}{uri_suffix}"
|
|
101
|
+
|
|
102
|
+
client = MongoClient(
|
|
103
|
+
uri, serverSelectionTimeoutMS=30000, connectTimeoutMS=20000, socketTimeoutMS=20000, maxPoolSize=1
|
|
104
|
+
)
|
|
105
|
+
db = client[database]
|
|
106
|
+
collection = db["MetaObjects"]
|
|
107
|
+
|
|
108
|
+
document = doc_parameter
|
|
109
|
+
|
|
110
|
+
table = Table(title="Resultados da Extração")
|
|
111
|
+
table.add_column("Documento")
|
|
112
|
+
table.add_column("Hook")
|
|
113
|
+
table.add_column("View")
|
|
114
|
+
table.add_column("List")
|
|
115
|
+
table.add_column("Pivot")
|
|
116
|
+
table.add_column("Access")
|
|
117
|
+
|
|
118
|
+
if document is None and not extract_all:
|
|
119
|
+
document_names = list(
|
|
120
|
+
collection.find({"type": {"$in": ["composite", "document"]}}, {"name": 1}).sort("name", 1)
|
|
121
|
+
)
|
|
122
|
+
choices = [{"name": "Todos", "value": "all"}] + [
|
|
123
|
+
{"name": doc["name"], "value": doc["name"]} for doc in document_names
|
|
124
|
+
]
|
|
125
|
+
|
|
126
|
+
questions = [
|
|
127
|
+
inquirer.List(
|
|
128
|
+
"document", message="Qual documento você precisa?", choices=[choice["name"] for choice in choices]
|
|
129
|
+
)
|
|
130
|
+
]
|
|
131
|
+
answers = inquirer.prompt(questions)
|
|
132
|
+
if answers is None:
|
|
133
|
+
console.print("[red]Operação cancelada pelo usuário[/red]")
|
|
134
|
+
return
|
|
135
|
+
document = "all" if answers["document"] == "Todos" else answers["document"]
|
|
136
|
+
elif extract_all:
|
|
137
|
+
document = "all"
|
|
138
|
+
|
|
139
|
+
filter_query: Dict[str, Any] = {"type": {"$in": ["composite", "document"]}}
|
|
140
|
+
if document != "all":
|
|
141
|
+
filter_query["name"] = document
|
|
142
|
+
|
|
143
|
+
metas = list(collection.find(filter_query).sort("_id", 1))
|
|
144
|
+
|
|
145
|
+
with Progress() as progress:
|
|
146
|
+
task = progress.add_task("[cyan]Processando...", total=len(metas))
|
|
147
|
+
|
|
148
|
+
for doc in metas:
|
|
149
|
+
doc_path = output_dir / doc["name"]
|
|
150
|
+
|
|
151
|
+
# Processando hooks
|
|
152
|
+
hook_results = []
|
|
153
|
+
if hook or all(x is None for x in [view, list_param, pivot, access]):
|
|
154
|
+
doc_meta = doc.copy()
|
|
155
|
+
for field in ["scriptBeforeValidation", "validationData", "validationScript", "scriptAfterSave"]:
|
|
156
|
+
doc_meta.pop(field, None)
|
|
157
|
+
|
|
158
|
+
if hook in (None, "validationData") and "validationData" in doc:
|
|
159
|
+
await write_file(
|
|
160
|
+
str(doc_path / "hook" / "validationData.json"), json.dumps(doc["validationData"], indent=2)
|
|
161
|
+
)
|
|
162
|
+
hook_results.append("✓ validationData")
|
|
163
|
+
|
|
164
|
+
for script_type in ["scriptBeforeValidation", "validationScript", "scriptAfterSave"]:
|
|
165
|
+
if script_type in doc and (hook is None or hook == script_type):
|
|
166
|
+
formatted = format_code(f"{script_type}.js", doc[script_type])
|
|
167
|
+
await write_file(str(doc_path / "hook" / f"{script_type}.js"), formatted)
|
|
168
|
+
hook_results.append(f"✓ {script_type}")
|
|
169
|
+
|
|
170
|
+
if hook is None:
|
|
171
|
+
await write_file(str(doc_path / "document.json"), json.dumps(doc_meta, indent=2))
|
|
172
|
+
|
|
173
|
+
# Processando views, lists, pivots e access
|
|
174
|
+
related_results: RelatedResults = {"view": [], "list": [], "pivot": [], "access": []}
|
|
175
|
+
if all(x is None for x in [hook, view, list_param, pivot, access]) or any(
|
|
176
|
+
x is not None for x in [view, list_param, pivot, access]
|
|
177
|
+
):
|
|
178
|
+
MONGO_OR = "$or"
|
|
179
|
+
meta_filter = {"document": doc["name"]}
|
|
180
|
+
meta_filter[MONGO_OR] = []
|
|
181
|
+
|
|
182
|
+
if any(x is not None for x in [view, list_param, pivot, access]):
|
|
183
|
+
for type_name, param in [
|
|
184
|
+
("view", view),
|
|
185
|
+
("list", list_param),
|
|
186
|
+
("pivot", pivot),
|
|
187
|
+
("access", access),
|
|
188
|
+
]:
|
|
189
|
+
if param is not None:
|
|
190
|
+
condition = {"type": type_name}
|
|
191
|
+
if param != "all":
|
|
192
|
+
condition["name"] = param
|
|
193
|
+
meta_filter[MONGO_OR].append(condition)
|
|
194
|
+
|
|
195
|
+
related_metas = list(collection.find(meta_filter).sort("_id", 1))
|
|
196
|
+
|
|
197
|
+
for meta in related_metas:
|
|
198
|
+
meta_type = cast(MetaType, meta["type"])
|
|
199
|
+
if meta_type in ("view", "list", "pivot", "access"):
|
|
200
|
+
await write_file(str(doc_path / meta_type / f"{meta['name']}.json"), json.dumps(meta, indent=2))
|
|
201
|
+
related_results[meta_type].append(f"✓ {meta['name']}")
|
|
202
|
+
|
|
203
|
+
table.add_row(
|
|
204
|
+
doc["name"],
|
|
205
|
+
"\n".join(hook_results),
|
|
206
|
+
"\n".join(related_results["view"]),
|
|
207
|
+
"\n".join(related_results["list"]),
|
|
208
|
+
"\n".join(related_results["pivot"]),
|
|
209
|
+
"\n".join(related_results["access"]),
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
progress.update(task, advance=1)
|
|
213
|
+
|
|
214
|
+
client.close()
|
|
215
|
+
console.print(f"[green]Extração concluída com sucesso do banco[/green] [cyan]{database}[/cyan]")
|
|
216
|
+
if document != "all":
|
|
217
|
+
console.print(f"[cyan]Documento: {document}[/cyan]")
|
|
218
|
+
|
|
219
|
+
console.print(table)
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
def main():
|
|
223
|
+
"""Função principal para execução via linha de comando."""
|
|
224
|
+
import argparse
|
|
225
|
+
import asyncio
|
|
226
|
+
import sys
|
|
227
|
+
|
|
228
|
+
parser = argparse.ArgumentParser(description="Extrai dados do MongoDB")
|
|
229
|
+
parser.add_argument("--host", default="localhost", help="Host do MongoDB")
|
|
230
|
+
parser.add_argument("--port", type=int, default=27017, help="Porta do MongoDB")
|
|
231
|
+
parser.add_argument("--database", required=True, help="Nome do banco de dados")
|
|
232
|
+
parser.add_argument("--output", default="metadata", help="Diretório de saída")
|
|
233
|
+
parser.add_argument("--view", help="Nome da view específica para extrair")
|
|
234
|
+
parser.add_argument("--list", dest="list_param", help="Nome da lista específica para extrair")
|
|
235
|
+
parser.add_argument("--pivot", help="Nome do pivot específico para extrair")
|
|
236
|
+
parser.add_argument("--access", help="Nome do access específica para extrair")
|
|
237
|
+
parser.add_argument("--hook", help="Nome do hook específico para extrair")
|
|
238
|
+
parser.add_argument("--username", help="Usuário do MongoDB")
|
|
239
|
+
parser.add_argument("--password", help="Senha do MongoDB")
|
|
240
|
+
parser.add_argument("--replicaset", help="Nome do ReplicaSet do MongoDB (ex: rs0)")
|
|
241
|
+
parser.add_argument("collection", nargs="?", help="Nome da collection específica para extrair")
|
|
242
|
+
parser.add_argument("--all", action="store_true", help="Extrair todas as collections sem perguntar")
|
|
243
|
+
|
|
244
|
+
args = parser.parse_args()
|
|
245
|
+
args_dict = vars(args)
|
|
246
|
+
|
|
247
|
+
# Se collection foi especificada, usa como doc_parameter
|
|
248
|
+
if "collection" in args_dict:
|
|
249
|
+
args_dict["doc_parameter"] = args_dict.pop("collection")
|
|
250
|
+
|
|
251
|
+
# Renomeia o parâmetro all para extract_all
|
|
252
|
+
if "all" in args_dict:
|
|
253
|
+
args_dict["extract_all"] = args_dict.pop("all")
|
|
254
|
+
|
|
255
|
+
if sys.platform == "win32":
|
|
256
|
+
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
|
|
257
|
+
|
|
258
|
+
asyncio.run(pull_command(**args_dict))
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
if __name__ == "__main__":
|
|
262
|
+
main()
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: konecty-sdk-python
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Konecty SDK Python
|
|
5
|
+
Author-email: Leonardo Leal <leonardo.leal@konecty.com>, Derotino Silveira <derotino.silveira@konecty.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Keywords: api,konecty,sdk
|
|
8
|
+
Classifier: Development Status :: 4 - Beta
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
15
|
+
Requires-Python: >=3.11
|
|
16
|
+
Requires-Dist: aiohttp>=3.11.11
|
|
17
|
+
Requires-Dist: asyncio>=3.4.3
|
|
18
|
+
Requires-Dist: black>=24.10.0
|
|
19
|
+
Requires-Dist: email-validator>=2.2.0
|
|
20
|
+
Requires-Dist: inquirer>=3.4.0
|
|
21
|
+
Requires-Dist: pydantic>=2.11.4
|
|
22
|
+
Requires-Dist: pymongo>=4.10.1
|
|
23
|
+
Requires-Dist: requests>=2.32.3
|
|
24
|
+
Requires-Dist: rich>=13.9.4
|
|
25
|
+
Requires-Dist: typing-extensions>=4.12.2
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
|
|
28
|
+
## Konecty Python SDK
|
|
29
|
+
|
|
30
|
+
> 🛠️ Work in progress
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
cli/__init__.py,sha256=l6FP1E2atmdMYszmUTO7eLS7GYvzOfgjkd_Fs9Gvh_s,212
|
|
2
|
+
cli/apply.py,sha256=MUDcVq7qssJPfSBR-ef0L8l73EL7h8OOq9J07SAJNy4,16102
|
|
3
|
+
cli/backup.py,sha256=iozWaoJw5orjMcwDXOTvpdYl_szAdqCT_fd27-7ENO4,4408
|
|
4
|
+
cli/pull.py,sha256=QXfpzfH4R2F65hPNLm-kXqN6yB6YIwVg0Us7KFd2A14,9725
|
|
5
|
+
lib/client.py,sha256=24PJxBKEm8n3kwnQwQr3wg6BYyL0d9CfYceesz91tvA,15020
|
|
6
|
+
lib/file_manager.py,sha256=CLpOJWdA1tb2iq0qOIeRyEEIuACRq9tIo7Rls1YT2ig,9986
|
|
7
|
+
lib/filters.py,sha256=PsFaUFCEyKgxgzD566LdTLvuMJevoF_i9U1WnpJZzPQ,4482
|
|
8
|
+
lib/model.py,sha256=OFkzSxOL99Uz91n-FAIdCNVrm5czBECsh7s6trg7O_E,2745
|
|
9
|
+
lib/settings.py,sha256=cueZQIVfKBqBufUSYBM0auD9StsPLVN6KMQsYLGPbhQ,4122
|
|
10
|
+
lib/types.py,sha256=2GGlFnuWy3MYKKWYJQwQWU-eZSCzO-re1lyiFfamlTc,9104
|
|
11
|
+
konecty_sdk_python-0.1.0.dist-info/METADATA,sha256=QSbtHd9Nf17WsqTWQGoudGqWTzPt2368gWGGGmBDflo,1037
|
|
12
|
+
konecty_sdk_python-0.1.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
13
|
+
konecty_sdk_python-0.1.0.dist-info/RECORD,,
|