graphxr-database-proxy 1.0.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.
- graphxr_database_proxy/__init__.py +16 -0
- graphxr_database_proxy/api/__init__.py +1 -0
- graphxr_database_proxy/api/database.py +266 -0
- graphxr_database_proxy/api/google.py +437 -0
- graphxr_database_proxy/api/projects.py +99 -0
- graphxr_database_proxy/common/util.py +38 -0
- graphxr_database_proxy/drivers/__init__.py +1 -0
- graphxr_database_proxy/drivers/base.py +56 -0
- graphxr_database_proxy/drivers/factory.py +36 -0
- graphxr_database_proxy/drivers/spanner.py +814 -0
- graphxr_database_proxy/main.py +110 -0
- graphxr_database_proxy/models/__init__.py +1 -0
- graphxr_database_proxy/models/google.py +50 -0
- graphxr_database_proxy/models/project.py +170 -0
- graphxr_database_proxy/proxy.py +495 -0
- graphxr_database_proxy/proxyForDev.py +290 -0
- graphxr_database_proxy/services/__init__.py +1 -0
- graphxr_database_proxy/services/project_service.py +150 -0
- graphxr_database_proxy/static/favicon.ico +0 -0
- graphxr_database_proxy/static/index.html +1 -0
- graphxr_database_proxy/static/main.7391ee9773c403483393.css +175 -0
- graphxr_database_proxy/static/main.7391ee9773c403483393.css.map +1 -0
- graphxr_database_proxy/static/main.ce3fbb85a7bc9452edb9.js +2 -0
- graphxr_database_proxy/static/main.ce3fbb85a7bc9452edb9.js.map +1 -0
- graphxr_database_proxy/static/vendors.70542a99f336a8021013.js +3 -0
- graphxr_database_proxy/static/vendors.70542a99f336a8021013.js.LICENSE.txt +95 -0
- graphxr_database_proxy/static/vendors.70542a99f336a8021013.js.map +1 -0
- graphxr_database_proxy-1.0.0.dist-info/METADATA +180 -0
- graphxr_database_proxy-1.0.0.dist-info/RECORD +33 -0
- graphxr_database_proxy-1.0.0.dist-info/WHEEL +5 -0
- graphxr_database_proxy-1.0.0.dist-info/entry_points.txt +2 -0
- graphxr_database_proxy-1.0.0.dist-info/licenses/LICENSE +21 -0
- graphxr_database_proxy-1.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"""
|
|
2
|
+
GraphXR Database Proxy
|
|
3
|
+
|
|
4
|
+
A secure middleware for connecting GraphXR Frontend to various backend databases.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
__version__ = "1.0.0"
|
|
8
|
+
__author__ = "Kineviz"
|
|
9
|
+
__email__ = "support@kineviz.com"
|
|
10
|
+
|
|
11
|
+
from .main import app
|
|
12
|
+
from .proxy import DatabaseProxy
|
|
13
|
+
from .models.project import Project, DatabaseConfig
|
|
14
|
+
from .services.project_service import ProjectService
|
|
15
|
+
|
|
16
|
+
__all__ = ["app", "DatabaseProxy", "Project", "DatabaseConfig", "ProjectService"]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# API package
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Database API endpoints
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from typing import Any, Dict
|
|
6
|
+
from fastapi import APIRouter, HTTPException, Depends, Path
|
|
7
|
+
from ..models.project import DatabaseType, QueryRequest, QueryResponse, SchemaResponse, GraphSchemaResponse, SampleDataResponse, APIInfo
|
|
8
|
+
from ..services.project_service import ProjectService
|
|
9
|
+
from ..drivers.factory import DriverFactory
|
|
10
|
+
|
|
11
|
+
router = APIRouter(prefix="/api", tags=["database"])
|
|
12
|
+
|
|
13
|
+
def get_project_service() -> ProjectService:
|
|
14
|
+
return ProjectService()
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@router.get("/{database_type}/{project_name}", response_model=APIInfo)
|
|
18
|
+
async def get_database_info(
|
|
19
|
+
database_type: DatabaseType = Path(..., description="Database type"),
|
|
20
|
+
project_name: str = Path(..., description="Project name"),
|
|
21
|
+
service: ProjectService = Depends(get_project_service)
|
|
22
|
+
):
|
|
23
|
+
"""Get database API information"""
|
|
24
|
+
try:
|
|
25
|
+
# Find project by name
|
|
26
|
+
project = await service.get_project_by_name(project_name)
|
|
27
|
+
if not project:
|
|
28
|
+
raise HTTPException(status_code=404, detail="Project not found")
|
|
29
|
+
|
|
30
|
+
if project.database_type != database_type:
|
|
31
|
+
raise HTTPException(
|
|
32
|
+
status_code=400,
|
|
33
|
+
detail=f"Project database type {project.database_type} does not match requested type {database_type}"
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
# Create driver and get API info
|
|
37
|
+
driver = DriverFactory.create_driver(project)
|
|
38
|
+
api_info = driver.get_api_info(project.name)
|
|
39
|
+
|
|
40
|
+
return APIInfo(
|
|
41
|
+
type=database_type,
|
|
42
|
+
api_urls=api_info["api_urls"],
|
|
43
|
+
version=api_info.get("version")
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
except HTTPException:
|
|
47
|
+
raise
|
|
48
|
+
except Exception as e:
|
|
49
|
+
raise HTTPException(status_code=500, detail=str(e))
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
@router.post("/{database_type}/{project_name}/query", response_model=QueryResponse)
|
|
53
|
+
async def execute_query(
|
|
54
|
+
database_type: DatabaseType = Path(..., description="Database type"),
|
|
55
|
+
project_name: str = Path(..., description="Project name"),
|
|
56
|
+
query_request: QueryRequest = ...,
|
|
57
|
+
service: ProjectService = Depends(get_project_service)
|
|
58
|
+
):
|
|
59
|
+
"""Execute a database query"""
|
|
60
|
+
try:
|
|
61
|
+
# Find project by name
|
|
62
|
+
project = await service.get_project_by_name(project_name)
|
|
63
|
+
if not project:
|
|
64
|
+
raise HTTPException(status_code=404, detail="Project not found")
|
|
65
|
+
|
|
66
|
+
if project.database_type != database_type:
|
|
67
|
+
raise HTTPException(
|
|
68
|
+
status_code=400,
|
|
69
|
+
detail=f"Project database type {project.database_type} does not match requested type {database_type}"
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
# Create driver and execute query
|
|
73
|
+
driver = DriverFactory.create_driver(project)
|
|
74
|
+
await driver.connect()
|
|
75
|
+
|
|
76
|
+
try:
|
|
77
|
+
result = await driver.execute_query(
|
|
78
|
+
query_request.query,
|
|
79
|
+
query_request.parameters
|
|
80
|
+
)
|
|
81
|
+
return result
|
|
82
|
+
finally:
|
|
83
|
+
await driver.disconnect()
|
|
84
|
+
|
|
85
|
+
except HTTPException:
|
|
86
|
+
raise
|
|
87
|
+
except Exception as e:
|
|
88
|
+
raise HTTPException(status_code=500, detail=str(e))
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
@router.get("/{database_type}/{project_name}/schema", response_model=SchemaResponse)
|
|
92
|
+
async def get_schema(
|
|
93
|
+
database_type: DatabaseType = Path(..., description="Database type"),
|
|
94
|
+
project_name: str = Path(..., description="Project name"),
|
|
95
|
+
service: ProjectService = Depends(get_project_service)
|
|
96
|
+
):
|
|
97
|
+
"""Get database schema"""
|
|
98
|
+
try:
|
|
99
|
+
# Find project by name
|
|
100
|
+
project = await service.get_project_by_name(project_name)
|
|
101
|
+
if not project:
|
|
102
|
+
raise HTTPException(status_code=404, detail="Project not found")
|
|
103
|
+
|
|
104
|
+
if project.database_type != database_type:
|
|
105
|
+
raise HTTPException(
|
|
106
|
+
status_code=400,
|
|
107
|
+
detail=f"Project database type {project.database_type} does not match requested type {database_type}"
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
# Create driver and get schema
|
|
111
|
+
driver = DriverFactory.create_driver(project)
|
|
112
|
+
await driver.connect()
|
|
113
|
+
|
|
114
|
+
try:
|
|
115
|
+
result = await driver.get_schema()
|
|
116
|
+
return result
|
|
117
|
+
finally:
|
|
118
|
+
await driver.disconnect()
|
|
119
|
+
|
|
120
|
+
except HTTPException:
|
|
121
|
+
raise
|
|
122
|
+
except Exception as e:
|
|
123
|
+
raise HTTPException(status_code=500, detail=str(e))
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
@router.get("/{database_type}/{project_name}/token-status")
|
|
127
|
+
async def get_token_status(
|
|
128
|
+
database_type: DatabaseType = Path(..., description="Database type"),
|
|
129
|
+
project_name: str = Path(..., description="Project name"),
|
|
130
|
+
service: ProjectService = Depends(get_project_service)
|
|
131
|
+
):
|
|
132
|
+
"""Get OAuth token status information"""
|
|
133
|
+
try:
|
|
134
|
+
# Find project by name
|
|
135
|
+
project = await service.get_project_by_name(project_name)
|
|
136
|
+
if not project:
|
|
137
|
+
raise HTTPException(status_code=404, detail="Project not found")
|
|
138
|
+
|
|
139
|
+
if project.database_type != database_type:
|
|
140
|
+
raise HTTPException(
|
|
141
|
+
status_code=400,
|
|
142
|
+
detail=f"Project database type {project.database_type} does not match requested type {database_type}"
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
# Create driver and get token status
|
|
146
|
+
driver = DriverFactory.create_driver(project)
|
|
147
|
+
if hasattr(driver, 'get_token_status'):
|
|
148
|
+
token_status = driver.get_token_status()
|
|
149
|
+
return {
|
|
150
|
+
"success": True,
|
|
151
|
+
"data": token_status
|
|
152
|
+
}
|
|
153
|
+
else:
|
|
154
|
+
return {
|
|
155
|
+
"success": False,
|
|
156
|
+
"error": "Token status not available for this database type"
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
except HTTPException:
|
|
160
|
+
raise
|
|
161
|
+
except Exception as e:
|
|
162
|
+
raise HTTPException(status_code=500, detail=str(e))
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
@router.post("/{database_type}/{project_name}/test")
|
|
166
|
+
async def test_connection(
|
|
167
|
+
database_type: DatabaseType = Path(..., description="Database type"),
|
|
168
|
+
project_name: str = Path(..., description="Project name"),
|
|
169
|
+
service: ProjectService = Depends(get_project_service)
|
|
170
|
+
):
|
|
171
|
+
"""Test database connection"""
|
|
172
|
+
try:
|
|
173
|
+
# Find project by name
|
|
174
|
+
project = await service.get_project_by_name(project_name)
|
|
175
|
+
if not project:
|
|
176
|
+
raise HTTPException(status_code=404, detail="Project not found")
|
|
177
|
+
|
|
178
|
+
if project.database_type != database_type:
|
|
179
|
+
raise HTTPException(
|
|
180
|
+
status_code=400,
|
|
181
|
+
detail=f"Project database type {project.database_type} does not match requested type {database_type}"
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
# Create driver and test connection
|
|
185
|
+
driver = DriverFactory.create_driver(project)
|
|
186
|
+
is_connected = await driver.test_connection()
|
|
187
|
+
|
|
188
|
+
return {
|
|
189
|
+
"success": is_connected,
|
|
190
|
+
"message": "Connection successful" if is_connected else "Connection failed"
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
except HTTPException:
|
|
194
|
+
raise
|
|
195
|
+
except Exception as e:
|
|
196
|
+
raise HTTPException(status_code=500, detail=str(e))
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
@router.get("/{database_type}/{project_name}/graphSchema", response_model=GraphSchemaResponse)
|
|
200
|
+
async def get_graph_schema(
|
|
201
|
+
database_type: DatabaseType = Path(..., description="Database type"),
|
|
202
|
+
project_name: str = Path(..., description="Project name"),
|
|
203
|
+
service: ProjectService = Depends(get_project_service)
|
|
204
|
+
):
|
|
205
|
+
"""Get graph database schema"""
|
|
206
|
+
try:
|
|
207
|
+
# Find project by name
|
|
208
|
+
project = await service.get_project_by_name(project_name)
|
|
209
|
+
if not project:
|
|
210
|
+
raise HTTPException(status_code=404, detail="Project not found")
|
|
211
|
+
|
|
212
|
+
if project.database_type != database_type:
|
|
213
|
+
raise HTTPException(
|
|
214
|
+
status_code=400,
|
|
215
|
+
detail=f"Project database type {project.database_type} does not match requested type {database_type}"
|
|
216
|
+
)
|
|
217
|
+
|
|
218
|
+
# Create driver and get graph schema
|
|
219
|
+
driver = DriverFactory.create_driver(project)
|
|
220
|
+
await driver.connect()
|
|
221
|
+
|
|
222
|
+
try:
|
|
223
|
+
result = await driver.get_graph_schema()
|
|
224
|
+
return result
|
|
225
|
+
finally:
|
|
226
|
+
await driver.disconnect()
|
|
227
|
+
|
|
228
|
+
except HTTPException:
|
|
229
|
+
raise
|
|
230
|
+
except Exception as e:
|
|
231
|
+
raise HTTPException(status_code=500, detail=str(e))
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
@router.get("/{database_type}/{project_name}/sampleData", response_model=SampleDataResponse)
|
|
235
|
+
async def get_sample_data(
|
|
236
|
+
database_type: DatabaseType = Path(..., description="Database type"),
|
|
237
|
+
project_name: str = Path(..., description="Project name"),
|
|
238
|
+
service: ProjectService = Depends(get_project_service),
|
|
239
|
+
):
|
|
240
|
+
"""Get sample data from database"""
|
|
241
|
+
try:
|
|
242
|
+
# Find project by name
|
|
243
|
+
project = await service.get_project_by_name(project_name)
|
|
244
|
+
if not project:
|
|
245
|
+
raise HTTPException(status_code=404, detail="Project not found")
|
|
246
|
+
|
|
247
|
+
if project.database_type != database_type:
|
|
248
|
+
raise HTTPException(
|
|
249
|
+
status_code=400,
|
|
250
|
+
detail=f"Project database type {project.database_type} does not match requested type {database_type}"
|
|
251
|
+
)
|
|
252
|
+
|
|
253
|
+
# Create driver and get sample data
|
|
254
|
+
driver = DriverFactory.create_driver(project)
|
|
255
|
+
await driver.connect()
|
|
256
|
+
|
|
257
|
+
try:
|
|
258
|
+
result = await driver.get_sample_data()
|
|
259
|
+
return result
|
|
260
|
+
finally:
|
|
261
|
+
await driver.disconnect()
|
|
262
|
+
|
|
263
|
+
except HTTPException:
|
|
264
|
+
raise
|
|
265
|
+
except Exception as e:
|
|
266
|
+
raise HTTPException(status_code=500, detail=str(e))
|