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/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,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.27.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any