dbgraph 0.2.0__tar.gz → 0.2.2__tar.gz
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.
- dbgraph-0.2.2/.idea/workspace.xml +289 -0
- {dbgraph-0.2.0 → dbgraph-0.2.2}/PKG-INFO +2 -2
- dbgraph-0.2.2/data/northwind-graph-import.db +0 -0
- {dbgraph-0.2.0 → dbgraph-0.2.2}/dbgraph/__init__.py +1 -1
- {dbgraph-0.2.0 → dbgraph-0.2.2}/dbgraph/builder/sql_graph_builder.py +41 -6
- {dbgraph-0.2.0 → dbgraph-0.2.2}/dbgraph/entity/aspect.py +12 -0
- {dbgraph-0.2.0 → dbgraph-0.2.2}/dbgraph/entity/dbgraph.py +10 -2
- dbgraph-0.2.2/dbgraph/persistent/json_utils.py +34 -0
- {dbgraph-0.2.0 → dbgraph-0.2.2}/dbgraph/persistent/models.py +4 -4
- {dbgraph-0.2.0 → dbgraph-0.2.2}/dbgraph/persistent/sql_graph_persistent.py +16 -11
- {dbgraph-0.2.0 → dbgraph-0.2.2}/dbgraph/render/graph_renderer.py +2 -2
- {dbgraph-0.2.0 → dbgraph-0.2.2}/dbgraph/render/markdown_renderer.py +4 -9
- {dbgraph-0.2.0 → dbgraph-0.2.2}/pyproject.toml +2 -2
- dbgraph-0.2.2/tests/test_load_graph_sql.py +21 -0
- {dbgraph-0.2.0 → dbgraph-0.2.2}/tests/test_markdown_renderer.py +2 -2
- {dbgraph-0.2.0 → dbgraph-0.2.2}/tests/test_sql_graph_builder.py +1 -1
- {dbgraph-0.2.0 → dbgraph-0.2.2}/tests/test_sql_graph_persistent.py +6 -5
- {dbgraph-0.2.0 → dbgraph-0.2.2}/uv.lock +2 -2
- dbgraph-0.2.0/.idea/workspace.xml +0 -168
- dbgraph-0.2.0/dbgraph/event/event.py +0 -20
- dbgraph-0.2.0/dbgraph/event/event_bus.py +0 -61
- dbgraph-0.2.0/dbgraph/event/event_handler.py +0 -11
- dbgraph-0.2.0/dbgraph/render/text_renderer.py +0 -11
- dbgraph-0.2.0/tests/__init__.py +0 -0
- {dbgraph-0.2.0 → dbgraph-0.2.2}/.gitignore +0 -0
- {dbgraph-0.2.0 → dbgraph-0.2.2}/.idea/.gitignore +0 -0
- {dbgraph-0.2.0 → dbgraph-0.2.2}/.idea/dbgraph.iml +0 -0
- {dbgraph-0.2.0 → dbgraph-0.2.2}/.idea/inspectionProfiles/profiles_settings.xml +0 -0
- {dbgraph-0.2.0 → dbgraph-0.2.2}/.idea/misc.xml +0 -0
- {dbgraph-0.2.0 → dbgraph-0.2.2}/.idea/modules.xml +0 -0
- {dbgraph-0.2.0 → dbgraph-0.2.2}/.idea/vcs.xml +0 -0
- {dbgraph-0.2.0 → dbgraph-0.2.2}/.python-version +0 -0
- {dbgraph-0.2.0 → dbgraph-0.2.2}/README.md +0 -0
- {dbgraph-0.2.0 → dbgraph-0.2.2}/data/northwind-desc.md +0 -0
- {dbgraph-0.2.0 → dbgraph-0.2.2}/data/northwind-graph-v2.json +0 -0
- {dbgraph-0.2.0 → dbgraph-0.2.2}/data/northwind-graph-v4.json +0 -0
- {dbgraph-0.2.0 → dbgraph-0.2.2}/data/northwind-graph.db +0 -0
- {dbgraph-0.2.0 → dbgraph-0.2.2}/data/northwind-graph.json +0 -0
- {dbgraph-0.2.0 → dbgraph-0.2.2}/data/northwind-graph.png +0 -0
- {dbgraph-0.2.0 → dbgraph-0.2.2}/data/northwind-index/corpus.jsonl +0 -0
- {dbgraph-0.2.0 → dbgraph-0.2.2}/data/northwind-index/corpus.mmindex.json +0 -0
- {dbgraph-0.2.0 → dbgraph-0.2.2}/data/northwind-index/data.csc.index.npy +0 -0
- {dbgraph-0.2.0 → dbgraph-0.2.2}/data/northwind-index/indices.csc.index.npy +0 -0
- {dbgraph-0.2.0 → dbgraph-0.2.2}/data/northwind-index/indptr.csc.index.npy +0 -0
- {dbgraph-0.2.0 → dbgraph-0.2.2}/data/northwind-index/params.index.json +0 -0
- {dbgraph-0.2.0 → dbgraph-0.2.2}/data/northwind-index/vocab.index.json +0 -0
- {dbgraph-0.2.0 → dbgraph-0.2.2}/data/northwind-semantic-v5.json +0 -0
- {dbgraph-0.2.0 → dbgraph-0.2.2}/data/northwind.db +0 -0
- {dbgraph-0.2.0 → dbgraph-0.2.2}/data/time-results.txt +0 -0
- {dbgraph-0.2.0 → dbgraph-0.2.2}/dbgraph/application.py +0 -0
- {dbgraph-0.2.0 → dbgraph-0.2.2}/dbgraph/builder/__init__.py +0 -0
- {dbgraph-0.2.0 → dbgraph-0.2.2}/dbgraph/builder/graph_builder.py +0 -0
- {dbgraph-0.2.0 → dbgraph-0.2.2}/dbgraph/descriptor/__init__.py +0 -0
- {dbgraph-0.2.0 → dbgraph-0.2.2}/dbgraph/descriptor/graph_descriptor.py +0 -0
- {dbgraph-0.2.0 → dbgraph-0.2.2}/dbgraph/descriptor/langchain_graph_descriptor.py +0 -0
- {dbgraph-0.2.0 → dbgraph-0.2.2}/dbgraph/descriptor/prompt_templates.py +0 -0
- {dbgraph-0.2.0 → dbgraph-0.2.2}/dbgraph/entity/__init__.py +0 -0
- {dbgraph-0.2.0 → dbgraph-0.2.2}/dbgraph/entity/asset.py +0 -0
- {dbgraph-0.2.0 → dbgraph-0.2.2}/dbgraph/entity/asset_type.py +0 -0
- {dbgraph-0.2.0 → dbgraph-0.2.2}/dbgraph/entity/link.py +0 -0
- {dbgraph-0.2.0 → dbgraph-0.2.2}/dbgraph/entity/link_type.py +0 -0
- {dbgraph-0.2.0 → dbgraph-0.2.2}/dbgraph/entity/rdbgraph.py +0 -0
- {dbgraph-0.2.0/dbgraph/event → dbgraph-0.2.2/dbgraph/io}/__init__.py +0 -0
- {dbgraph-0.2.0 → dbgraph-0.2.2}/dbgraph/io/graph_loader.py +0 -0
- {dbgraph-0.2.0 → dbgraph-0.2.2}/dbgraph/io/graph_writer.py +0 -0
- {dbgraph-0.2.0 → dbgraph-0.2.2}/dbgraph/io/json_graph_loader.py +0 -0
- {dbgraph-0.2.0 → dbgraph-0.2.2}/dbgraph/io/json_graph_writer.py +0 -0
- {dbgraph-0.2.0/dbgraph/io → dbgraph-0.2.2/dbgraph/persistent}/__init__.py +0 -0
- {dbgraph-0.2.0 → dbgraph-0.2.2}/dbgraph/persistent/graph_persistent.py +0 -0
- {dbgraph-0.2.0/dbgraph/persistent → dbgraph-0.2.2/dbgraph/render}/__init__.py +0 -0
- {dbgraph-0.2.0/dbgraph/render → dbgraph-0.2.2/dbgraph/search}/__init__.py +0 -0
- {dbgraph-0.2.0 → dbgraph-0.2.2}/dbgraph/search/bm25_search_engine.py +0 -0
- {dbgraph-0.2.0 → dbgraph-0.2.2}/dbgraph/search/search_engine.py +0 -0
- {dbgraph-0.2.0/dbgraph/search → dbgraph-0.2.2/dbgraph/utils}/__init__.py +0 -0
- {dbgraph-0.2.0 → dbgraph-0.2.2}/dbgraph/utils/singleton.py +0 -0
- {dbgraph-0.2.0 → dbgraph-0.2.2}/diagrams/entity.png +0 -0
- {dbgraph-0.2.0 → dbgraph-0.2.2}/diagrams/entity.txt +0 -0
- {dbgraph-0.2.0 → dbgraph-0.2.2}/diagrams/usecase.png +0 -0
- {dbgraph-0.2.0 → dbgraph-0.2.2}/diagrams/usecase.txt +0 -0
- {dbgraph-0.2.0 → dbgraph-0.2.2}/docs/index.md +0 -0
- {dbgraph-0.2.0 → dbgraph-0.2.2}/docs/refs/aspect.md +0 -0
- {dbgraph-0.2.0 → dbgraph-0.2.2}/docs/refs/graph.md +0 -0
- {dbgraph-0.2.0 → dbgraph-0.2.2}/main.py +0 -0
- {dbgraph-0.2.0 → dbgraph-0.2.2}/mkdocs.yml +0 -0
- {dbgraph-0.2.0/dbgraph/utils → dbgraph-0.2.2/tests}/__init__.py +0 -0
- {dbgraph-0.2.0 → dbgraph-0.2.2}/tests/test_application.py +0 -0
- {dbgraph-0.2.0 → dbgraph-0.2.2}/tests/test_bm25s_search_engine.py +0 -0
- {dbgraph-0.2.0 → dbgraph-0.2.2}/tests/test_dbgraph.py +0 -0
- {dbgraph-0.2.0 → dbgraph-0.2.2}/tests/test_json_graph_loader.py +0 -0
- {dbgraph-0.2.0 → dbgraph-0.2.2}/tests/test_json_graph_writer.py +0 -0
- {dbgraph-0.2.0 → dbgraph-0.2.2}/tests/test_langchain_graph_descriptor.py +0 -0
- {dbgraph-0.2.0 → dbgraph-0.2.2}/tests/test_rdbgraph.py +0 -0
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<project version="4">
|
|
3
|
+
<component name="AutoImportSettings">
|
|
4
|
+
<option name="autoReloadType" value="SELECTIVE" />
|
|
5
|
+
</component>
|
|
6
|
+
<component name="ChangeListManager">
|
|
7
|
+
<list default="true" id="263a96da-9a82-40fd-89b2-ba71dd2c194d" name="Changes" comment="update renderer">
|
|
8
|
+
<change beforePath="$PROJECT_DIR$/pyproject.toml" beforeDir="false" afterPath="$PROJECT_DIR$/pyproject.toml" afterDir="false" />
|
|
9
|
+
</list>
|
|
10
|
+
<option name="SHOW_DIALOG" value="false" />
|
|
11
|
+
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
|
12
|
+
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
|
13
|
+
<option name="LAST_RESOLUTION" value="IGNORE" />
|
|
14
|
+
</component>
|
|
15
|
+
<component name="FileTemplateManagerImpl">
|
|
16
|
+
<option name="RECENT_TEMPLATES">
|
|
17
|
+
<list>
|
|
18
|
+
<option value="Python Unit Test" />
|
|
19
|
+
<option value="Python Script" />
|
|
20
|
+
</list>
|
|
21
|
+
</option>
|
|
22
|
+
</component>
|
|
23
|
+
<component name="Git.Settings">
|
|
24
|
+
<option name="RECENT_BRANCH_BY_REPOSITORY">
|
|
25
|
+
<map>
|
|
26
|
+
<entry key="$PROJECT_DIR$" value="packaging" />
|
|
27
|
+
</map>
|
|
28
|
+
</option>
|
|
29
|
+
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
|
|
30
|
+
</component>
|
|
31
|
+
<component name="GitHubPullRequestSearchHistory">{
|
|
32
|
+
"lastFilter": {
|
|
33
|
+
"state": "OPEN",
|
|
34
|
+
"assignee": "minhdenthedev"
|
|
35
|
+
}
|
|
36
|
+
}</component>
|
|
37
|
+
<component name="GithubPullRequestsUISettings">{
|
|
38
|
+
"selectedUrlAndAccountId": {
|
|
39
|
+
"url": "https://github.com/minhdenthedev/dbgraph.git",
|
|
40
|
+
"accountId": "6c0b7cdc-aa0d-4999-86e3-e6f0a1d74a10"
|
|
41
|
+
},
|
|
42
|
+
"recentNewPullRequestHead": {
|
|
43
|
+
"server": {
|
|
44
|
+
"useHttp": false,
|
|
45
|
+
"host": "github.com",
|
|
46
|
+
"port": null,
|
|
47
|
+
"suffix": null
|
|
48
|
+
},
|
|
49
|
+
"owner": "minhdenthedev",
|
|
50
|
+
"repository": "dbgraph"
|
|
51
|
+
}
|
|
52
|
+
}</component>
|
|
53
|
+
<component name="ProjectColorInfo">{
|
|
54
|
+
"associatedIndex": 0,
|
|
55
|
+
"fromUser": false
|
|
56
|
+
}</component>
|
|
57
|
+
<component name="ProjectId" id="3IdnkFbc3mGdbjiFJYWIoYOgRXM" />
|
|
58
|
+
<component name="ProjectLevelVcsManager">
|
|
59
|
+
<ConfirmationsSetting value="2" id="Add" />
|
|
60
|
+
</component>
|
|
61
|
+
<component name="ProjectViewState">
|
|
62
|
+
<option name="hideEmptyMiddlePackages" value="true" />
|
|
63
|
+
<option name="showLibraryContents" value="true" />
|
|
64
|
+
</component>
|
|
65
|
+
<component name="PropertiesComponent">{
|
|
66
|
+
"keyToString": {
|
|
67
|
+
"ASKED_SHARE_PROJECT_CONFIGURATION_FILES": "true",
|
|
68
|
+
"ModuleVcsDetector.initialDetectionPerformed": "true",
|
|
69
|
+
"Python tests.Python tests for tests.test_dbgraph.TestDBGraph.executor": "Run",
|
|
70
|
+
"Python tests.Python tests for tests.test_load_graph_sql.TestLoadGraphSQL.test_load.executor": "Run",
|
|
71
|
+
"Python tests.Python tests for tests.test_sql_graph_builder.TestSQLGraphBuilder.executor": "Run",
|
|
72
|
+
"Python tests.Python tests for tests.test_sql_graph_builder.TestSQLGraphBuilder.test__build_links.executor": "Run",
|
|
73
|
+
"Python tests.Python tests for tests.test_sql_graph_builder.TestSQLGraphBuilder.test_build_graph.executor": "Run",
|
|
74
|
+
"Python tests.Python tests for tests.test_sql_graph_persistent.TestSQLGraphPersistent.executor": "Run",
|
|
75
|
+
"Python tests.Python tests for tests.test_sql_graph_persistent.TestSQLGraphPersistent.test_load_graph.executor": "Run",
|
|
76
|
+
"Python tests.Python tests for tests.test_sql_graph_persistent.TestSQLGraphPersistent.test_save_graph.executor": "Run",
|
|
77
|
+
"Python tests.Python tests in test_load_graph_sql.py.executor": "Run",
|
|
78
|
+
"Python tests.Python tests in tests.executor": "Run",
|
|
79
|
+
"RunOnceActivity.ShowReadmeOnStart": "true",
|
|
80
|
+
"RunOnceActivity.git.unshallow": "true",
|
|
81
|
+
"RunOnceActivity.typescript.service.memoryLimit.init": "true",
|
|
82
|
+
"codeWithMe.voiceChat.enabledByDefault": "false",
|
|
83
|
+
"git-widget-placeholder": "main",
|
|
84
|
+
"ignore.virus.scanning.warn.message": "true",
|
|
85
|
+
"nodejs_package_manager_path": "npm",
|
|
86
|
+
"settings.editor.selected.configurable": "editor.preferences.folding"
|
|
87
|
+
}
|
|
88
|
+
}</component>
|
|
89
|
+
<component name="RunManager" selected="Python tests.Python tests in tests">
|
|
90
|
+
<configuration name="Python tests for tests.test_load_graph_sql.TestLoadGraphSQL.test_load" type="tests" factoryName="Autodetect" temporary="true" nameIsGenerated="true">
|
|
91
|
+
<module name="dbgraph" />
|
|
92
|
+
<option name="ENV_FILES" value="" />
|
|
93
|
+
<option name="INTERPRETER_OPTIONS" value="" />
|
|
94
|
+
<option name="PARENT_ENVS" value="true" />
|
|
95
|
+
<option name="SDK_HOME" value="" />
|
|
96
|
+
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
|
97
|
+
<option name="IS_MODULE_SDK" value="true" />
|
|
98
|
+
<option name="ADD_CONTENT_ROOTS" value="true" />
|
|
99
|
+
<option name="ADD_SOURCE_ROOTS" value="true" />
|
|
100
|
+
<option name="DEBUG_JUST_MY_CODE" value="false" />
|
|
101
|
+
<option name="RUN_TOOL" value="" />
|
|
102
|
+
<option name="_new_additionalArguments" value="""" />
|
|
103
|
+
<option name="_new_target" value=""tests.test_load_graph_sql.TestLoadGraphSQL.test_load"" />
|
|
104
|
+
<option name="_new_targetType" value=""PYTHON"" />
|
|
105
|
+
<method v="2" />
|
|
106
|
+
</configuration>
|
|
107
|
+
<configuration name="Python tests for tests.test_sql_graph_builder.TestSQLGraphBuilder" type="tests" factoryName="Autodetect" temporary="true" nameIsGenerated="true">
|
|
108
|
+
<module name="dbgraph" />
|
|
109
|
+
<option name="ENV_FILES" value="" />
|
|
110
|
+
<option name="INTERPRETER_OPTIONS" value="" />
|
|
111
|
+
<option name="PARENT_ENVS" value="true" />
|
|
112
|
+
<option name="SDK_HOME" value="" />
|
|
113
|
+
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
|
114
|
+
<option name="IS_MODULE_SDK" value="true" />
|
|
115
|
+
<option name="ADD_CONTENT_ROOTS" value="true" />
|
|
116
|
+
<option name="ADD_SOURCE_ROOTS" value="true" />
|
|
117
|
+
<option name="DEBUG_JUST_MY_CODE" value="false" />
|
|
118
|
+
<option name="RUN_TOOL" value="" />
|
|
119
|
+
<option name="_new_additionalArguments" value="""" />
|
|
120
|
+
<option name="_new_target" value=""tests.test_sql_graph_builder.TestSQLGraphBuilder"" />
|
|
121
|
+
<option name="_new_targetType" value=""PYTHON"" />
|
|
122
|
+
<method v="2" />
|
|
123
|
+
</configuration>
|
|
124
|
+
<configuration name="Python tests for tests.test_sql_graph_builder.TestSQLGraphBuilder.test__build_links" type="tests" factoryName="Autodetect" temporary="true" nameIsGenerated="true">
|
|
125
|
+
<module name="dbgraph" />
|
|
126
|
+
<option name="ENV_FILES" value="" />
|
|
127
|
+
<option name="INTERPRETER_OPTIONS" value="" />
|
|
128
|
+
<option name="PARENT_ENVS" value="true" />
|
|
129
|
+
<option name="SDK_HOME" value="" />
|
|
130
|
+
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
|
131
|
+
<option name="IS_MODULE_SDK" value="true" />
|
|
132
|
+
<option name="ADD_CONTENT_ROOTS" value="true" />
|
|
133
|
+
<option name="ADD_SOURCE_ROOTS" value="true" />
|
|
134
|
+
<option name="DEBUG_JUST_MY_CODE" value="false" />
|
|
135
|
+
<option name="RUN_TOOL" value="" />
|
|
136
|
+
<option name="_new_additionalArguments" value="""" />
|
|
137
|
+
<option name="_new_target" value=""tests.test_sql_graph_builder.TestSQLGraphBuilder.test__build_links"" />
|
|
138
|
+
<option name="_new_targetType" value=""PYTHON"" />
|
|
139
|
+
<method v="2" />
|
|
140
|
+
</configuration>
|
|
141
|
+
<configuration name="Python tests for tests.test_sql_graph_builder.TestSQLGraphBuilder.test_build_graph" type="tests" factoryName="Autodetect" temporary="true" nameIsGenerated="true">
|
|
142
|
+
<module name="dbgraph" />
|
|
143
|
+
<option name="ENV_FILES" value="" />
|
|
144
|
+
<option name="INTERPRETER_OPTIONS" value="" />
|
|
145
|
+
<option name="PARENT_ENVS" value="true" />
|
|
146
|
+
<option name="SDK_HOME" value="" />
|
|
147
|
+
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
|
148
|
+
<option name="IS_MODULE_SDK" value="true" />
|
|
149
|
+
<option name="ADD_CONTENT_ROOTS" value="true" />
|
|
150
|
+
<option name="ADD_SOURCE_ROOTS" value="true" />
|
|
151
|
+
<option name="DEBUG_JUST_MY_CODE" value="false" />
|
|
152
|
+
<option name="RUN_TOOL" value="" />
|
|
153
|
+
<option name="_new_additionalArguments" value="""" />
|
|
154
|
+
<option name="_new_target" value=""tests.test_sql_graph_builder.TestSQLGraphBuilder.test_build_graph"" />
|
|
155
|
+
<option name="_new_targetType" value=""PYTHON"" />
|
|
156
|
+
<method v="2" />
|
|
157
|
+
</configuration>
|
|
158
|
+
<configuration name="Python tests in tests" type="tests" factoryName="Autodetect" temporary="true" nameIsGenerated="true">
|
|
159
|
+
<module name="dbgraph" />
|
|
160
|
+
<option name="ENV_FILES" value="" />
|
|
161
|
+
<option name="INTERPRETER_OPTIONS" value="" />
|
|
162
|
+
<option name="PARENT_ENVS" value="true" />
|
|
163
|
+
<option name="SDK_HOME" value="" />
|
|
164
|
+
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/tests" />
|
|
165
|
+
<option name="IS_MODULE_SDK" value="true" />
|
|
166
|
+
<option name="ADD_CONTENT_ROOTS" value="true" />
|
|
167
|
+
<option name="ADD_SOURCE_ROOTS" value="true" />
|
|
168
|
+
<option name="DEBUG_JUST_MY_CODE" value="false" />
|
|
169
|
+
<option name="RUN_TOOL" value="" />
|
|
170
|
+
<option name="_new_additionalArguments" value="""" />
|
|
171
|
+
<option name="_new_target" value=""$PROJECT_DIR$/tests"" />
|
|
172
|
+
<option name="_new_targetType" value=""PATH"" />
|
|
173
|
+
<method v="2" />
|
|
174
|
+
</configuration>
|
|
175
|
+
<recent_temporary>
|
|
176
|
+
<list>
|
|
177
|
+
<item itemvalue="Python tests.Python tests in tests" />
|
|
178
|
+
<item itemvalue="Python tests.Python tests for tests.test_sql_graph_builder.TestSQLGraphBuilder" />
|
|
179
|
+
<item itemvalue="Python tests.Python tests for tests.test_sql_graph_builder.TestSQLGraphBuilder.test__build_links" />
|
|
180
|
+
<item itemvalue="Python tests.Python tests for tests.test_sql_graph_builder.TestSQLGraphBuilder.test_build_graph" />
|
|
181
|
+
<item itemvalue="Python tests.Python tests for tests.test_load_graph_sql.TestLoadGraphSQL.test_load" />
|
|
182
|
+
</list>
|
|
183
|
+
</recent_temporary>
|
|
184
|
+
</component>
|
|
185
|
+
<component name="SharedIndexes">
|
|
186
|
+
<attachedChunks>
|
|
187
|
+
<set>
|
|
188
|
+
<option value="bundled-python-sdk-821f704e66d9-5bd6d13a2a75-com.jetbrains.pycharm.pro.sharedIndexes.bundled-PY-262.9437.214" />
|
|
189
|
+
</set>
|
|
190
|
+
</attachedChunks>
|
|
191
|
+
</component>
|
|
192
|
+
<component name="TaskManager">
|
|
193
|
+
<task active="true" id="Default" summary="Default task">
|
|
194
|
+
<changelist id="263a96da-9a82-40fd-89b2-ba71dd2c194d" name="Changes" comment="" />
|
|
195
|
+
<created>1788103453676</created>
|
|
196
|
+
<option name="number" value="Default" />
|
|
197
|
+
<option name="presentableId" value="Default" />
|
|
198
|
+
<updated>1788103453676</updated>
|
|
199
|
+
</task>
|
|
200
|
+
<task id="LOCAL-00001" summary="update packaging">
|
|
201
|
+
<option name="closed" value="true" />
|
|
202
|
+
<created>1788163967330</created>
|
|
203
|
+
<option name="number" value="00001" />
|
|
204
|
+
<option name="presentableId" value="LOCAL-00001" />
|
|
205
|
+
<option name="project" value="LOCAL" />
|
|
206
|
+
<updated>1788163967330</updated>
|
|
207
|
+
</task>
|
|
208
|
+
<task id="LOCAL-00002" summary="update packaging">
|
|
209
|
+
<option name="closed" value="true" />
|
|
210
|
+
<created>1788399865892</created>
|
|
211
|
+
<option name="number" value="00002" />
|
|
212
|
+
<option name="presentableId" value="LOCAL-00002" />
|
|
213
|
+
<option name="project" value="LOCAL" />
|
|
214
|
+
<updated>1788399865892</updated>
|
|
215
|
+
</task>
|
|
216
|
+
<task id="LOCAL-00003" summary="fix bugs in builder">
|
|
217
|
+
<option name="closed" value="true" />
|
|
218
|
+
<created>1788407330419</created>
|
|
219
|
+
<option name="number" value="00003" />
|
|
220
|
+
<option name="presentableId" value="LOCAL-00003" />
|
|
221
|
+
<option name="project" value="LOCAL" />
|
|
222
|
+
<updated>1788407330419</updated>
|
|
223
|
+
</task>
|
|
224
|
+
<task id="LOCAL-00004" summary="format">
|
|
225
|
+
<option name="closed" value="true" />
|
|
226
|
+
<created>1788407896437</created>
|
|
227
|
+
<option name="number" value="00004" />
|
|
228
|
+
<option name="presentableId" value="LOCAL-00004" />
|
|
229
|
+
<option name="project" value="LOCAL" />
|
|
230
|
+
<updated>1788407896437</updated>
|
|
231
|
+
</task>
|
|
232
|
+
<task id="LOCAL-00005" summary="remove events">
|
|
233
|
+
<option name="closed" value="true" />
|
|
234
|
+
<created>1788576856001</created>
|
|
235
|
+
<option name="number" value="00005" />
|
|
236
|
+
<option name="presentableId" value="LOCAL-00005" />
|
|
237
|
+
<option name="project" value="LOCAL" />
|
|
238
|
+
<updated>1788576856001</updated>
|
|
239
|
+
</task>
|
|
240
|
+
<task id="LOCAL-00006" summary="update renderer">
|
|
241
|
+
<option name="closed" value="true" />
|
|
242
|
+
<created>1788922273132</created>
|
|
243
|
+
<option name="number" value="00006" />
|
|
244
|
+
<option name="presentableId" value="LOCAL-00006" />
|
|
245
|
+
<option name="project" value="LOCAL" />
|
|
246
|
+
<updated>1788922273132</updated>
|
|
247
|
+
</task>
|
|
248
|
+
<option name="localTasksCounter" value="7" />
|
|
249
|
+
<servers />
|
|
250
|
+
</component>
|
|
251
|
+
<component name="TypeScriptGeneratedFilesManager">
|
|
252
|
+
<option name="version" value="3" />
|
|
253
|
+
</component>
|
|
254
|
+
<component name="Vcs.Log.Tabs.Properties">
|
|
255
|
+
<option name="TAB_STATES">
|
|
256
|
+
<map>
|
|
257
|
+
<entry key="MAIN">
|
|
258
|
+
<value>
|
|
259
|
+
<State />
|
|
260
|
+
</value>
|
|
261
|
+
</entry>
|
|
262
|
+
</map>
|
|
263
|
+
</option>
|
|
264
|
+
</component>
|
|
265
|
+
<component name="VcsManagerConfiguration">
|
|
266
|
+
<MESSAGE value="update packaging" />
|
|
267
|
+
<MESSAGE value="fix bugs in builder" />
|
|
268
|
+
<MESSAGE value="format" />
|
|
269
|
+
<MESSAGE value="remove events" />
|
|
270
|
+
<MESSAGE value="update renderer" />
|
|
271
|
+
<option name="LAST_COMMIT_MESSAGE" value="update renderer" />
|
|
272
|
+
</component>
|
|
273
|
+
<component name="XDebuggerManager">
|
|
274
|
+
<breakpoint-manager>
|
|
275
|
+
<breakpoints>
|
|
276
|
+
<line-breakpoint enabled="true" suspend="THREAD" type="python-line">
|
|
277
|
+
<url>file://$PROJECT_DIR$/dbgraph/persistent/sql_graph_persistent.py</url>
|
|
278
|
+
<line>330</line>
|
|
279
|
+
<option name="timeStamp" value="4" />
|
|
280
|
+
</line-breakpoint>
|
|
281
|
+
<line-breakpoint enabled="true" suspend="THREAD" type="python-line">
|
|
282
|
+
<url>file://$PROJECT_DIR$/dbgraph/persistent/sql_graph_persistent.py</url>
|
|
283
|
+
<line>351</line>
|
|
284
|
+
<option name="timeStamp" value="5" />
|
|
285
|
+
</line-breakpoint>
|
|
286
|
+
</breakpoints>
|
|
287
|
+
</breakpoint-manager>
|
|
288
|
+
</component>
|
|
289
|
+
</project>
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: dbgraph
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2
|
|
4
4
|
Summary: dbgraph is a database profiling tool which model the database as a graph
|
|
5
5
|
Requires-Python: >=3.11
|
|
6
|
-
Requires-Dist: bm25s
|
|
6
|
+
Requires-Dist: bm25s>=0.3.9
|
|
7
7
|
Requires-Dist: build>=1.6.0
|
|
8
8
|
Requires-Dist: grip>=4.6.2
|
|
9
9
|
Requires-Dist: langchain-openai>=1.6.0
|
|
Binary file
|
|
@@ -13,7 +13,22 @@ from sqlalchemy import (
|
|
|
13
13
|
func,
|
|
14
14
|
inspect,
|
|
15
15
|
select,
|
|
16
|
+
SmallInteger,
|
|
17
|
+
Integer,
|
|
18
|
+
BigInteger,
|
|
19
|
+
Float,
|
|
20
|
+
DECIMAL,
|
|
21
|
+
Text,
|
|
22
|
+
Unicode,
|
|
23
|
+
UnicodeText,
|
|
24
|
+
CHAR,
|
|
25
|
+
NCHAR,
|
|
26
|
+
BLOB,
|
|
27
|
+
DATE,
|
|
28
|
+
DATETIME,
|
|
29
|
+
distinct,
|
|
16
30
|
)
|
|
31
|
+
from sqlalchemy.orm import Session
|
|
17
32
|
|
|
18
33
|
from dbgraph.builder.graph_builder import GraphBuilder
|
|
19
34
|
from dbgraph.entity.aspect import (
|
|
@@ -24,6 +39,7 @@ from dbgraph.entity.aspect import (
|
|
|
24
39
|
RNumericalStatistics,
|
|
25
40
|
RTableSchemaAspect,
|
|
26
41
|
RTableStatisticsAspect,
|
|
42
|
+
RTemporalStatistics,
|
|
27
43
|
)
|
|
28
44
|
from dbgraph.entity.asset import Asset
|
|
29
45
|
from dbgraph.entity.asset_type import AssetType
|
|
@@ -97,21 +113,40 @@ class SQLGraphBuilder(GraphBuilder):
|
|
|
97
113
|
value_counts = {str(row[0]): int(row[1]) for row in rows}
|
|
98
114
|
return RCategoricalStatistics(value_counts)
|
|
99
115
|
|
|
116
|
+
def _get_temp_aspect(self, col: Column) -> RTemporalStatistics:
|
|
117
|
+
min_max_nunique_stmt = select(
|
|
118
|
+
func.min(col), func.max(col), func.count(distinct(col))
|
|
119
|
+
)
|
|
120
|
+
mode_stmt = select(col).group_by(col).order_by(func.count(col).desc()).limit(1)
|
|
121
|
+
with Session(self.engine) as session:
|
|
122
|
+
min_time, max_time, nunique = session.execute(min_max_nunique_stmt).one()
|
|
123
|
+
mode = session.execute(mode_stmt).scalar()
|
|
124
|
+
return RTemporalStatistics(min_time, max_time, mode, nunique)
|
|
125
|
+
|
|
100
126
|
def _get_stats_aspect(self, col: Column) -> RColumnStatisticsAspect:
|
|
101
127
|
non_null_count, null_count = self._get_null_info(col)
|
|
102
|
-
|
|
128
|
+
num_aspect = None
|
|
129
|
+
cat_aspect = None
|
|
130
|
+
temp_aspect = None
|
|
131
|
+
if isinstance(
|
|
132
|
+
col.type, (Numeric, Integer, SmallInteger, BigInteger, Float, DECIMAL)
|
|
133
|
+
):
|
|
103
134
|
num_aspect = self._get_numerical_stats_aspect(col)
|
|
104
|
-
|
|
105
|
-
elif isinstance(col.type, String):
|
|
106
|
-
num_aspect = None
|
|
135
|
+
elif isinstance(col.type, (String, Text, Unicode, UnicodeText, CHAR, NCHAR)):
|
|
107
136
|
cat_aspect = self._get_cat_stats_aspect(col)
|
|
137
|
+
elif isinstance(col.type, (DATE, DATETIME)):
|
|
138
|
+
temp_aspect = self._get_temp_aspect(col)
|
|
139
|
+
elif isinstance(col.type, (BLOB,)):
|
|
140
|
+
pass
|
|
108
141
|
else:
|
|
109
|
-
|
|
110
|
-
|
|
142
|
+
raise NotImplementedError(
|
|
143
|
+
f"Only support Numeric, String, Date, and BLOB. Got {col.type} for {col.name}"
|
|
144
|
+
)
|
|
111
145
|
return RColumnStatisticsAspect(
|
|
112
146
|
name=f"{col.name}_column_stats",
|
|
113
147
|
numerical_stats=num_aspect,
|
|
114
148
|
categorical_stats=cat_aspect,
|
|
149
|
+
temporal_stats=temp_aspect,
|
|
115
150
|
non_null_count=non_null_count,
|
|
116
151
|
null_count=null_count,
|
|
117
152
|
)
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
from dataclasses import dataclass
|
|
2
|
+
from datetime import datetime, timedelta
|
|
2
3
|
from enum import StrEnum
|
|
3
4
|
|
|
4
5
|
|
|
@@ -103,6 +104,16 @@ class RCategoricalStatistics:
|
|
|
103
104
|
value_counts: dict[str, int]
|
|
104
105
|
|
|
105
106
|
|
|
107
|
+
@dataclass
|
|
108
|
+
class RTemporalStatistics:
|
|
109
|
+
"""Statistics for temporal columns"""
|
|
110
|
+
|
|
111
|
+
min_time: datetime | None = None
|
|
112
|
+
max_time: datetime | None = None
|
|
113
|
+
mode_time: datetime | None = None
|
|
114
|
+
num_uniques: int | None = None
|
|
115
|
+
|
|
116
|
+
|
|
106
117
|
@dataclass
|
|
107
118
|
class RColumnStatisticsAspect(Aspect):
|
|
108
119
|
"""Group of properties relevant to RDB's column statistics
|
|
@@ -118,6 +129,7 @@ class RColumnStatisticsAspect(Aspect):
|
|
|
118
129
|
null_count: int
|
|
119
130
|
numerical_stats: RNumericalStatistics | None = None
|
|
120
131
|
categorical_stats: RCategoricalStatistics | None = None
|
|
132
|
+
temporal_stats: RTemporalStatistics | None = None
|
|
121
133
|
|
|
122
134
|
|
|
123
135
|
class FKBehavior(StrEnum):
|
|
@@ -7,6 +7,10 @@ import rustworkx as rx
|
|
|
7
7
|
|
|
8
8
|
from dbgraph.entity.asset import Asset
|
|
9
9
|
from dbgraph.entity.link import Link
|
|
10
|
+
from typing import TYPE_CHECKING
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from dbgraph.entity.rdbgraph import RDatabaseGraph
|
|
10
14
|
|
|
11
15
|
|
|
12
16
|
@dataclass
|
|
@@ -88,7 +92,7 @@ class DatabaseGraph:
|
|
|
88
92
|
|
|
89
93
|
def select_shortest_paths(self, src_id: str, dst_id: str) -> list[DatabaseGraph]:
|
|
90
94
|
"""
|
|
91
|
-
Find shortest paths between two Assets.
|
|
95
|
+
Find the shortest paths between two Assets.
|
|
92
96
|
|
|
93
97
|
Args:
|
|
94
98
|
src_id: ID of the source asset
|
|
@@ -135,7 +139,7 @@ class DatabaseGraph:
|
|
|
135
139
|
return [self._graph.get_node_data(i) for i in asset_indices]
|
|
136
140
|
|
|
137
141
|
def find_shortest_paths(self, src_id: str, dst_id: str) -> list[list[Asset]]:
|
|
138
|
-
"""Find shortest paths between two Assets
|
|
142
|
+
"""Find the shortest paths between two Assets
|
|
139
143
|
|
|
140
144
|
Args:
|
|
141
145
|
src_id: ID of the source asset
|
|
@@ -150,3 +154,7 @@ class DatabaseGraph:
|
|
|
150
154
|
paths = rx.all_shortest_paths(self._graph, src_idx, dst_idx)
|
|
151
155
|
|
|
152
156
|
return [[self._graph.get_node_data(i) for i in path] for path in paths]
|
|
157
|
+
|
|
158
|
+
def to_relational(self) -> "RDatabaseGraph":
|
|
159
|
+
"""Return the RDatabaseGraph"""
|
|
160
|
+
return RDatabaseGraph.from_graph(self)
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import datetime
|
|
2
|
+
import json
|
|
3
|
+
from typing import Any, Callable
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class DateTimeEncoder(json.JSONEncoder):
|
|
7
|
+
"""Custom encoder for datetime"""
|
|
8
|
+
|
|
9
|
+
def default(self, o: Any) -> Any:
|
|
10
|
+
if isinstance(o, (datetime.date, datetime.datetime)):
|
|
11
|
+
return o.isoformat()
|
|
12
|
+
return super().default(o)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def datetime_parser(obj):
|
|
16
|
+
for key, value in obj.items():
|
|
17
|
+
if isinstance(value, str):
|
|
18
|
+
try:
|
|
19
|
+
# try parsing ISO format
|
|
20
|
+
obj[key] = datetime.datetime.fromisoformat(value)
|
|
21
|
+
except ValueError:
|
|
22
|
+
try:
|
|
23
|
+
# if there is only date
|
|
24
|
+
obj[key] = datetime.date.fromisoformat(value)
|
|
25
|
+
except ValueError:
|
|
26
|
+
pass
|
|
27
|
+
return obj
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class DateTimeDecoder(json.JSONDecoder):
|
|
31
|
+
"""Custom decoder for datetime"""
|
|
32
|
+
|
|
33
|
+
def __init__(self, *args, **kwargs):
|
|
34
|
+
super().__init__(object_hook=datetime_parser, *args, **kwargs)
|
|
@@ -181,8 +181,8 @@ class AssetAspectModel(Base):
|
|
|
181
181
|
nullable=False,
|
|
182
182
|
)
|
|
183
183
|
|
|
184
|
-
json_aspect: Mapped[
|
|
185
|
-
|
|
184
|
+
json_aspect: Mapped[str] = mapped_column(
|
|
185
|
+
Text,
|
|
186
186
|
nullable=False,
|
|
187
187
|
)
|
|
188
188
|
|
|
@@ -212,8 +212,8 @@ class LinkAspectModel(Base):
|
|
|
212
212
|
nullable=False,
|
|
213
213
|
)
|
|
214
214
|
|
|
215
|
-
json_aspect: Mapped[
|
|
216
|
-
|
|
215
|
+
json_aspect: Mapped[str] = mapped_column(
|
|
216
|
+
Text,
|
|
217
217
|
nullable=False,
|
|
218
218
|
)
|
|
219
219
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import json
|
|
1
2
|
from dataclasses import asdict, dataclass
|
|
2
3
|
|
|
3
4
|
from sqlalchemy import create_engine, delete, select, update
|
|
@@ -13,6 +14,7 @@ from dbgraph.entity.aspect import (
|
|
|
13
14
|
RTableSchemaAspect,
|
|
14
15
|
RTableStatisticsAspect,
|
|
15
16
|
SemanticAspect,
|
|
17
|
+
RTemporalStatistics,
|
|
16
18
|
)
|
|
17
19
|
from dbgraph.entity.asset import Asset
|
|
18
20
|
from dbgraph.entity.asset_type import AssetType
|
|
@@ -20,6 +22,7 @@ from dbgraph.entity.dbgraph import DatabaseGraph
|
|
|
20
22
|
from dbgraph.entity.link import Link
|
|
21
23
|
from dbgraph.entity.link_type import LinkType
|
|
22
24
|
from dbgraph.persistent.graph_persistent import GraphPersistent
|
|
25
|
+
from dbgraph.persistent.json_utils import DateTimeEncoder, DateTimeDecoder
|
|
23
26
|
from dbgraph.persistent.models import (
|
|
24
27
|
AssetAspectModel,
|
|
25
28
|
AssetModel,
|
|
@@ -69,7 +72,7 @@ class SQLGraphPersistent(GraphPersistent):
|
|
|
69
72
|
asset_id=asset.asset_id,
|
|
70
73
|
name=aspect.name,
|
|
71
74
|
type=aspect_type,
|
|
72
|
-
json_aspect=asdict(aspect),
|
|
75
|
+
json_aspect=json.dumps(asdict(aspect), cls=DateTimeEncoder),
|
|
73
76
|
)
|
|
74
77
|
aspects.append(aspect)
|
|
75
78
|
with Session(self.engine) as session:
|
|
@@ -110,7 +113,7 @@ class SQLGraphPersistent(GraphPersistent):
|
|
|
110
113
|
link_id=link.link_id,
|
|
111
114
|
name=aspect.name,
|
|
112
115
|
type=aspect_type,
|
|
113
|
-
json_aspect=asdict(aspect),
|
|
116
|
+
json_aspect=json.dumps(asdict(aspect), cls=DateTimeEncoder),
|
|
114
117
|
)
|
|
115
118
|
aspects.append(link_aspect)
|
|
116
119
|
with Session(self.engine) as session:
|
|
@@ -201,7 +204,7 @@ class SQLGraphPersistent(GraphPersistent):
|
|
|
201
204
|
name=aspect.name,
|
|
202
205
|
type=aspect_type,
|
|
203
206
|
asset_id=asset_id,
|
|
204
|
-
json_aspect=asdict(aspect),
|
|
207
|
+
json_aspect=json.dumps(asdict(aspect), cls=DateTimeEncoder),
|
|
205
208
|
)
|
|
206
209
|
for aspect_type, aspect in aspects.items()
|
|
207
210
|
]
|
|
@@ -216,7 +219,7 @@ class SQLGraphPersistent(GraphPersistent):
|
|
|
216
219
|
name=aspect.name,
|
|
217
220
|
type=aspect_type,
|
|
218
221
|
link_id=link_id,
|
|
219
|
-
json_aspect=asdict(aspect),
|
|
222
|
+
json_aspect=json.dumps(asdict(aspect), cls=DateTimeEncoder),
|
|
220
223
|
)
|
|
221
224
|
for aspect_type, aspect in aspects.items()
|
|
222
225
|
]
|
|
@@ -228,7 +231,7 @@ class SQLGraphPersistent(GraphPersistent):
|
|
|
228
231
|
self, model: AssetAspectModel, asset_type: AssetType
|
|
229
232
|
) -> Aspect:
|
|
230
233
|
"""Turn SQL Alchemy model to Aspect"""
|
|
231
|
-
json_aspect = model.json_aspect
|
|
234
|
+
json_aspect = json.loads(model.json_aspect, cls=DateTimeDecoder)
|
|
232
235
|
match model.type:
|
|
233
236
|
case "schema_properties":
|
|
234
237
|
if asset_type == AssetType.RTABLE:
|
|
@@ -241,6 +244,7 @@ class SQLGraphPersistent(GraphPersistent):
|
|
|
241
244
|
if asset_type == AssetType.RTABLE:
|
|
242
245
|
aspect = RTableStatisticsAspect(**json_aspect)
|
|
243
246
|
elif asset_type == AssetType.RCOLUMN:
|
|
247
|
+
numerical_aspect = categorical_aspect = temp_aspect = None
|
|
244
248
|
if json_aspect["numerical_stats"] is not None:
|
|
245
249
|
numerical_aspect = RNumericalStatistics(
|
|
246
250
|
**json_aspect["numerical_stats"]
|
|
@@ -251,9 +255,9 @@ class SQLGraphPersistent(GraphPersistent):
|
|
|
251
255
|
**json_aspect["categorical_stats"]
|
|
252
256
|
)
|
|
253
257
|
numerical_aspect = None
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
"
|
|
258
|
+
elif json_aspect["temporal_stats"] is not None:
|
|
259
|
+
temp_aspect = RTemporalStatistics(
|
|
260
|
+
**json_aspect["temporal_stats"]
|
|
257
261
|
)
|
|
258
262
|
aspect = RColumnStatisticsAspect(
|
|
259
263
|
name=json_aspect["name"],
|
|
@@ -261,6 +265,7 @@ class SQLGraphPersistent(GraphPersistent):
|
|
|
261
265
|
null_count=json_aspect["null_count"],
|
|
262
266
|
categorical_stats=categorical_aspect,
|
|
263
267
|
numerical_stats=numerical_aspect,
|
|
268
|
+
temporal_stats=temp_aspect,
|
|
264
269
|
)
|
|
265
270
|
else:
|
|
266
271
|
raise NotImplementedError()
|
|
@@ -289,7 +294,7 @@ class SQLGraphPersistent(GraphPersistent):
|
|
|
289
294
|
|
|
290
295
|
def _parse_link_aspect_model(self, model: LinkAspectModel) -> Aspect:
|
|
291
296
|
"""Turn SQL Alchemy model to Link Aspect"""
|
|
292
|
-
json_aspect = model.json_aspect
|
|
297
|
+
json_aspect = json.loads(model.json_aspect, cls=DateTimeDecoder)
|
|
293
298
|
match model.type:
|
|
294
299
|
case "foreign_key_properties":
|
|
295
300
|
aspect = RForeignKeyAspect(**json_aspect)
|
|
@@ -315,7 +320,7 @@ class SQLGraphPersistent(GraphPersistent):
|
|
|
315
320
|
with Session(self.engine) as session:
|
|
316
321
|
models = session.scalars(
|
|
317
322
|
select(AssetModel).where(AssetModel.graph_id == graph_id)
|
|
318
|
-
)
|
|
323
|
+
).all()
|
|
319
324
|
assets = []
|
|
320
325
|
for model in models:
|
|
321
326
|
aspects = {}
|
|
@@ -336,7 +341,7 @@ class SQLGraphPersistent(GraphPersistent):
|
|
|
336
341
|
with Session(self.engine) as session:
|
|
337
342
|
models = session.scalars(
|
|
338
343
|
select(LinkModel).where(LinkModel.graph_id == graph_id)
|
|
339
|
-
)
|
|
344
|
+
).all()
|
|
340
345
|
links = []
|
|
341
346
|
for model in models:
|
|
342
347
|
aspects = {}
|
|
@@ -7,5 +7,5 @@ class GraphRenderer(ABC):
|
|
|
7
7
|
"""Interface for rendering the graph"""
|
|
8
8
|
|
|
9
9
|
@abstractmethod
|
|
10
|
-
def render(self, graph: DatabaseGraph):
|
|
11
|
-
"""Render the graph
|
|
10
|
+
def render(self, graph: DatabaseGraph) -> str:
|
|
11
|
+
"""Render the graph to text-based format"""
|