gibson-cli 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.
- api/BaseApi.py +45 -0
- api/Cli.py +248 -0
- bin/gibson.py +16 -0
- command/Api.py +31 -0
- command/Base.py +28 -0
- command/BaseCommand.py +26 -0
- command/Build.py +69 -0
- command/Code.py +198 -0
- command/Conf.py +74 -0
- command/Count.py +35 -0
- command/Dev.py +121 -0
- command/Forget.py +34 -0
- command/Import.py +109 -0
- command/List.py +61 -0
- command/Merge.py +35 -0
- command/Model.py +42 -0
- command/Models.py +31 -0
- command/Modify.py +43 -0
- command/Module.py +42 -0
- command/New.py +38 -0
- command/OpenApi.py +141 -0
- command/Question.py +105 -0
- command/Remove.py +80 -0
- command/Rename.py +71 -0
- command/Rewrite.py +107 -0
- command/Schema.py +42 -0
- command/Schemas.py +31 -0
- command/Show.py +37 -0
- command/Test.py +42 -0
- command/Tests.py +31 -0
- command/Tree.py +92 -0
- command/WarGames.py +35 -0
- command/auth/Auth.py +25 -0
- command/auth/Login.py +17 -0
- command/auth/Logout.py +7 -0
- command/tests/test_command_BaseCommand.py +10 -0
- command/tests/test_command_Conf.py +19 -0
- conf/Api.py +3 -0
- conf/Code.py +9 -0
- conf/Custom.py +4 -0
- conf/Datastore.py +4 -0
- conf/Dependencies.py +24 -0
- conf/Dev.py +15 -0
- conf/Frameworks.py +7 -0
- conf/Modeler.py +3 -0
- conf/Paths.py +10 -0
- conf/Platform.py +16 -0
- conf/Project.py +18 -0
- conf/Version.py +2 -0
- conf/dev/Api.py +5 -0
- conf/dev/Base.py +3 -0
- conf/dev/Model.py +3 -0
- conf/dev/Schema.py +3 -0
- conf/tests/test_conf_Dependencies.py +5 -0
- conf/tests/test_conf_Platform.py +7 -0
- core/CommandRouter.py +249 -0
- core/Configuration.py +418 -0
- core/Conversation.py +270 -0
- core/Env.py +12 -0
- core/Memory.py +148 -0
- core/TimeKeeper.py +12 -0
- core/utils.py +19 -0
- data/default-ref-table.tmpl +4 -0
- data/default-table.tmpl +6 -0
- db/TableExceptions.py +6 -0
- db/tests/test_db_TableExceptions.py +9 -0
- dev/Dev.py +92 -0
- display/Header.py +6 -0
- display/WorkspaceFooter.py +10 -0
- display/WorkspaceHeader.py +8 -0
- display/tests/test_display_Header.py +9 -0
- display/tests/test_display_WorkspaceFooter.py +9 -0
- display/tests/test_display_WorkspaceHeader.py +8 -0
- gibson_cli-0.1.0.dist-info/METADATA +306 -0
- gibson_cli-0.1.0.dist-info/RECORD +102 -0
- gibson_cli-0.1.0.dist-info/WHEEL +5 -0
- gibson_cli-0.1.0.dist-info/entry_points.txt +2 -0
- gibson_cli-0.1.0.dist-info/top_level.txt +12 -0
- lang/Python.py +57 -0
- lang/tests/test_lang_Python.py +70 -0
- services/auth/Server.py +75 -0
- services/code/context/schema/DataDictionary.py +12 -0
- services/code/context/schema/EntityKeys.py +49 -0
- services/code/context/schema/Manager.py +28 -0
- services/code/context/schema/tests/test_code_context_schema_DataDictionary.py +8 -0
- services/code/context/schema/tests/test_code_context_schema_EntityKeys.py +52 -0
- services/code/context/schema/tests/test_code_context_schema_Manager.py +34 -0
- services/code/customization/Authenticator.py +51 -0
- services/code/customization/BaseCustomization.py +12 -0
- services/code/customization/CustomizationManager.py +20 -0
- services/code/customization/tests/test_code_customization_Authenticator.py +53 -0
- services/code/customization/tests/test_code_customization_BaseCustomization.py +14 -0
- structure/Entity.py +115 -0
- structure/constraints/ReferenceConstraint.py +36 -0
- structure/keys/ForeignKey.py +41 -0
- structure/keys/Index.py +64 -0
- structure/keys/IndexAttribute.py +14 -0
- structure/keys/tests/test_ForeignKey.py +80 -0
- structure/keys/tests/test_Index.py +98 -0
- structure/keys/tests/test_IndexAttribute.py +17 -0
- structure/testing.py +194 -0
- structure/tests/test_Entity.py +107 -0
api/BaseApi.py
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
import requests
|
2
|
+
|
3
|
+
|
4
|
+
class BaseApi:
|
5
|
+
def get_headers(self):
|
6
|
+
raise NotImplementedError
|
7
|
+
|
8
|
+
def _get(self, end_point):
|
9
|
+
r = requests.get(self.get_url(end_point), headers=self.get_headers())
|
10
|
+
|
11
|
+
self.__raise_for_status(r)
|
12
|
+
|
13
|
+
return r.json()
|
14
|
+
|
15
|
+
def _post(self, end_point, json: dict):
|
16
|
+
r = requests.post(
|
17
|
+
self.get_url(end_point), headers=self.get_headers(), json=json
|
18
|
+
)
|
19
|
+
|
20
|
+
self.__raise_for_status(r)
|
21
|
+
|
22
|
+
return r
|
23
|
+
|
24
|
+
def _put(self, end_point, json: dict):
|
25
|
+
r = requests.put(self.get_url(end_point), headers=self.get_headers(), json=json)
|
26
|
+
|
27
|
+
self.__raise_for_status(r)
|
28
|
+
|
29
|
+
return r
|
30
|
+
|
31
|
+
def __raise_for_status(self, r):
|
32
|
+
try:
|
33
|
+
r.raise_for_status()
|
34
|
+
except:
|
35
|
+
try:
|
36
|
+
message = r.json()
|
37
|
+
|
38
|
+
print("=" * 78)
|
39
|
+
print("Raw Response:\n")
|
40
|
+
print(message)
|
41
|
+
print("\n" + "=" * 78)
|
42
|
+
except requests.exceptions.JSONDecodeError:
|
43
|
+
pass
|
44
|
+
|
45
|
+
raise
|
api/Cli.py
ADDED
@@ -0,0 +1,248 @@
|
|
1
|
+
import os
|
2
|
+
import requests
|
3
|
+
|
4
|
+
from services.auth.Server import Server as AuthServer
|
5
|
+
from core.Configuration import Configuration
|
6
|
+
from lang.Python import Python
|
7
|
+
from core.Memory import Memory
|
8
|
+
|
9
|
+
from .BaseApi import BaseApi
|
10
|
+
|
11
|
+
|
12
|
+
class Cli(BaseApi):
|
13
|
+
API_ENV = os.environ.get("GIBSONAI_API_ENV", "staging")
|
14
|
+
PREFIX = "cli"
|
15
|
+
VERSION = "v1"
|
16
|
+
|
17
|
+
def __init__(self, configuration: Configuration):
|
18
|
+
super().__init__()
|
19
|
+
self.configuration = configuration
|
20
|
+
|
21
|
+
def code_api(self):
|
22
|
+
return self._post(
|
23
|
+
"code/api",
|
24
|
+
self.__structure_context_payload(self.configuration, with_stored=True),
|
25
|
+
).json()
|
26
|
+
|
27
|
+
def code_base(self):
|
28
|
+
return self._post(
|
29
|
+
"code/base",
|
30
|
+
self.__structure_context_payload(self.configuration, with_stored=True),
|
31
|
+
).json()
|
32
|
+
|
33
|
+
def code_model_attributes(self, model_name, instructions):
|
34
|
+
payload = self.__structure_context_payload(self.configuration)
|
35
|
+
payload["model"] = {"name": model_name}
|
36
|
+
payload["q"] = instructions
|
37
|
+
|
38
|
+
return self._post("code/model/attributes", payload).json()
|
39
|
+
|
40
|
+
def code_models(self, entities: list):
|
41
|
+
payload = self.__structure_context_payload(self.configuration, with_stored=True)
|
42
|
+
payload["entities"] = entities
|
43
|
+
|
44
|
+
return self._post("code/models", payload).json()
|
45
|
+
|
46
|
+
def code_schemas(self, entities: list):
|
47
|
+
payload = self.__structure_context_payload(self.configuration, with_stored=True)
|
48
|
+
payload["entities"] = entities
|
49
|
+
|
50
|
+
return self._post("code/schemas", payload).json()
|
51
|
+
|
52
|
+
def code_testing(self, entities: list):
|
53
|
+
payload = self.__structure_context_payload(self.configuration, with_stored=True)
|
54
|
+
payload["entities"] = entities
|
55
|
+
|
56
|
+
return self._post("code/testing", payload).json()
|
57
|
+
|
58
|
+
def code_writer_entity_modifier(self, context, name, definition, instructions):
|
59
|
+
payload = self.__structure_context_payload(self.configuration)
|
60
|
+
payload["context"] = context
|
61
|
+
payload["entity"] = {"definition": definition, "name": name}
|
62
|
+
payload["q"] = instructions
|
63
|
+
|
64
|
+
return self._post("code/writer/entity/modifier", payload).json()
|
65
|
+
|
66
|
+
def code_writer_schema_context(self):
|
67
|
+
return self._post(
|
68
|
+
"code/writer/schema/context",
|
69
|
+
self.__structure_context_payload(self.configuration, with_stored=True),
|
70
|
+
).json()
|
71
|
+
|
72
|
+
def get_client_id(self):
|
73
|
+
return {
|
74
|
+
"local": "9b0cbebd-3eb4-47be-89ac-4aa589316ff4",
|
75
|
+
"staging": "02459e16-f356-4c01-b689-59847ed04b0a",
|
76
|
+
"production": "da287371-240b-4b53-bfde-4b1581cca62a",
|
77
|
+
}[self.API_ENV]
|
78
|
+
|
79
|
+
def get_api_domain(self):
|
80
|
+
return {
|
81
|
+
"local": "http://localhost:8000",
|
82
|
+
"staging": "https://staging-api.gibsonai.com",
|
83
|
+
"production": "https://api.gibsonai.com",
|
84
|
+
}[self.API_ENV]
|
85
|
+
|
86
|
+
def get_app_domain(self):
|
87
|
+
return {
|
88
|
+
"local": "http://localhost:5173",
|
89
|
+
"staging": "https://staging-app.gibsonai.com",
|
90
|
+
"production": "https://app.gibsonai.com",
|
91
|
+
}[self.API_ENV]
|
92
|
+
|
93
|
+
def get_headers(self):
|
94
|
+
headers = {
|
95
|
+
"X-Gibson-Client-ID": self.get_client_id(),
|
96
|
+
"X-Gibson-API-Key": self.configuration.project.api.key,
|
97
|
+
}
|
98
|
+
|
99
|
+
token = self.configuration.get_access_token()
|
100
|
+
if token is not None:
|
101
|
+
headers["Authorization"] = f"Bearer {token}"
|
102
|
+
|
103
|
+
return headers
|
104
|
+
|
105
|
+
def get_url(self, end_point):
|
106
|
+
return f"{self.get_api_domain()}/{self.VERSION}/{self.PREFIX}/{end_point}"
|
107
|
+
|
108
|
+
def import_(self):
|
109
|
+
return self._get("import")
|
110
|
+
|
111
|
+
def llm_query(self, instructions, has_file, has_python, has_sql):
|
112
|
+
project_config = self.configuration.project
|
113
|
+
r = self._post(
|
114
|
+
"llm/query",
|
115
|
+
{
|
116
|
+
"content": {
|
117
|
+
"meta": {
|
118
|
+
"file": int(has_file),
|
119
|
+
"python": int(has_python),
|
120
|
+
"sql": int(has_sql),
|
121
|
+
}
|
122
|
+
},
|
123
|
+
"frameworks": {
|
124
|
+
"api": project_config.code.frameworks.api,
|
125
|
+
"model": project_config.code.frameworks.model,
|
126
|
+
"revision": project_config.code.frameworks.revision,
|
127
|
+
"schema_": project_config.code.frameworks.schema,
|
128
|
+
"test": project_config.code.frameworks.test,
|
129
|
+
},
|
130
|
+
"q": instructions,
|
131
|
+
},
|
132
|
+
)
|
133
|
+
|
134
|
+
return r.json()
|
135
|
+
|
136
|
+
def login(self):
|
137
|
+
token = AuthServer(self.get_app_domain()).get_token()
|
138
|
+
return token
|
139
|
+
|
140
|
+
def modeler_entity_modify(
|
141
|
+
self, modeler_version, project_description, entity: dict, modifications: str
|
142
|
+
):
|
143
|
+
r = self._put(
|
144
|
+
"modeler/entity/modify",
|
145
|
+
{
|
146
|
+
"entity": entity,
|
147
|
+
"modeler": {"version": modeler_version},
|
148
|
+
"modifications": modifications,
|
149
|
+
"project": {"description": project_description},
|
150
|
+
},
|
151
|
+
)
|
152
|
+
|
153
|
+
return r.json()
|
154
|
+
|
155
|
+
def modeler_entity_remove(self, modeler_version, entities: list, entity_name):
|
156
|
+
r = self._put(
|
157
|
+
"modeler/entity/remove",
|
158
|
+
{
|
159
|
+
"entity": {"name": entity_name},
|
160
|
+
"modeler": {"version": modeler_version},
|
161
|
+
"schema_": entities,
|
162
|
+
},
|
163
|
+
)
|
164
|
+
|
165
|
+
return r.json()
|
166
|
+
|
167
|
+
def modeler_entity_rename(self, modeler_version, entities: list, current, new):
|
168
|
+
r = self._put(
|
169
|
+
"modeler/entity/rename",
|
170
|
+
{
|
171
|
+
"entity": {"current": current, "new": new},
|
172
|
+
"modeler": {"version": modeler_version},
|
173
|
+
"schema_": entities,
|
174
|
+
},
|
175
|
+
)
|
176
|
+
|
177
|
+
return r.json()
|
178
|
+
|
179
|
+
def modeler_module(self, modeler_version, project_description, module):
|
180
|
+
r = self._post(
|
181
|
+
"modeler/module",
|
182
|
+
{
|
183
|
+
"modeler": {"version": modeler_version},
|
184
|
+
"module": module,
|
185
|
+
"project": {"description": project_description},
|
186
|
+
},
|
187
|
+
)
|
188
|
+
|
189
|
+
return r.json()
|
190
|
+
|
191
|
+
def modeler_openapi(self, modeler_version, contents):
|
192
|
+
r = self._post(
|
193
|
+
"modeler/openapi",
|
194
|
+
{"contents": contents, "modeler": {"version": modeler_version}},
|
195
|
+
)
|
196
|
+
|
197
|
+
return r.json()
|
198
|
+
|
199
|
+
def modeler_reconcile(self, modeler_version, entities: list):
|
200
|
+
r = self._post(
|
201
|
+
"modeler/reconcile",
|
202
|
+
{"modeler": {"version": modeler_version}, "schema_": entities},
|
203
|
+
)
|
204
|
+
|
205
|
+
return r.json()
|
206
|
+
|
207
|
+
def __structure_context_payload(
|
208
|
+
self,
|
209
|
+
with_last=False,
|
210
|
+
with_merged=False,
|
211
|
+
with_stored=False,
|
212
|
+
):
|
213
|
+
project_config = self.configuration.project
|
214
|
+
payload = {
|
215
|
+
"api": {
|
216
|
+
"prefix": project_config.dev.api.prefix,
|
217
|
+
"version": project_config.dev.api.version,
|
218
|
+
},
|
219
|
+
"frameworks": {
|
220
|
+
"api": project_config.code.frameworks.api,
|
221
|
+
"model": project_config.code.frameworks.model,
|
222
|
+
"revision": project_config.code.frameworks.revision,
|
223
|
+
"schema_": project_config.code.frameworks.schema,
|
224
|
+
"test": project_config.code.frameworks.test,
|
225
|
+
},
|
226
|
+
"language": project_config.code.language,
|
227
|
+
"path": {
|
228
|
+
"api": Python().make_import_path(project_config.dev.api.path),
|
229
|
+
"base": Python().make_import_path(project_config.dev.base.path),
|
230
|
+
"custom": {
|
231
|
+
"model": {
|
232
|
+
"class_": project_config.code.custom.model_class,
|
233
|
+
"path": project_config.code.custom.model_path,
|
234
|
+
}
|
235
|
+
},
|
236
|
+
"model": Python().make_import_path(project_config.dev.model.path),
|
237
|
+
"schema_": Python().make_import_path(project_config.dev.schema.path),
|
238
|
+
},
|
239
|
+
}
|
240
|
+
|
241
|
+
if with_last is True:
|
242
|
+
payload["schema_"] = Memory(self.configuration).recall_last()["entities"]
|
243
|
+
elif with_merged is True:
|
244
|
+
payload["schema_"] = Memory(self.configuration).recall_merged()
|
245
|
+
elif with_stored is True:
|
246
|
+
payload["schema_"] = Memory(self.configuration).recall_entities()
|
247
|
+
|
248
|
+
return payload
|
bin/gibson.py
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/usr/bin/env python3
|
2
|
+
|
3
|
+
from core.CommandRouter import CommandRouter
|
4
|
+
from core.Configuration import Configuration
|
5
|
+
|
6
|
+
|
7
|
+
def main():
|
8
|
+
configuration = Configuration()
|
9
|
+
if configuration.settings is None:
|
10
|
+
configuration.initialize()
|
11
|
+
else:
|
12
|
+
router = CommandRouter(configuration).run()
|
13
|
+
|
14
|
+
|
15
|
+
if __name__ == "__main__":
|
16
|
+
main()
|
command/Api.py
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
from api.Cli import Cli
|
2
|
+
from dev.Dev import Dev
|
3
|
+
from services.code.customization.Authenticator import Authenticator
|
4
|
+
from core.TimeKeeper import TimeKeeper
|
5
|
+
|
6
|
+
from .BaseCommand import BaseCommand
|
7
|
+
|
8
|
+
|
9
|
+
class Api(BaseCommand):
|
10
|
+
def execute(self):
|
11
|
+
time_keeper = TimeKeeper()
|
12
|
+
dev = Dev(self.configuration)
|
13
|
+
|
14
|
+
cli = Cli(self.configuration)
|
15
|
+
response = cli.code_api()
|
16
|
+
|
17
|
+
if self.customization_management_is_enabled() is True:
|
18
|
+
authenticator = Authenticator(self.configuration).preserve()
|
19
|
+
|
20
|
+
try:
|
21
|
+
for entry in response["code"]:
|
22
|
+
dev.api_component(entry["name"], entry["definition"])
|
23
|
+
|
24
|
+
if self.conversation.muted() is False:
|
25
|
+
print(entry["definition"])
|
26
|
+
finally:
|
27
|
+
if self.customization_management_is_enabled() is True:
|
28
|
+
authenticator.restore()
|
29
|
+
|
30
|
+
if self.conversation.muted() is False:
|
31
|
+
time_keeper.display()
|
command/Base.py
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
from api.Cli import Cli
|
2
|
+
from dev.Dev import Dev
|
3
|
+
from core.TimeKeeper import TimeKeeper
|
4
|
+
|
5
|
+
from .BaseCommand import BaseCommand
|
6
|
+
|
7
|
+
|
8
|
+
class Base(BaseCommand):
|
9
|
+
def execute(self):
|
10
|
+
entities = self.memory.recall_merged()
|
11
|
+
if len(entities) == 0:
|
12
|
+
self.conversation.cant_no_entities(self.configuration.project.name)
|
13
|
+
exit(1)
|
14
|
+
|
15
|
+
time_keeper = TimeKeeper()
|
16
|
+
dev = Dev(self.configuration)
|
17
|
+
|
18
|
+
cli = Cli(self.configuration)
|
19
|
+
response = cli.code_base()
|
20
|
+
|
21
|
+
for entry in response["code"]:
|
22
|
+
dev.base_component(entry["name"], entry["definition"])
|
23
|
+
|
24
|
+
if self.conversation.muted() is False:
|
25
|
+
print(entry["definition"])
|
26
|
+
|
27
|
+
if self.conversation.muted() is False:
|
28
|
+
time_keeper.display()
|
command/BaseCommand.py
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
from core.Configuration import Configuration
|
2
|
+
from core.Memory import Memory
|
3
|
+
|
4
|
+
|
5
|
+
class BaseCommand:
|
6
|
+
def __init__(self, configuration: Configuration):
|
7
|
+
self.__enable_customization_management = True
|
8
|
+
self.configuration = configuration
|
9
|
+
self.conversation = self.configuration.conversation
|
10
|
+
self.memory = Memory(self.configuration)
|
11
|
+
|
12
|
+
def customization_management_is_enabled(self):
|
13
|
+
return self.__enable_customization_management == True
|
14
|
+
|
15
|
+
def disable_customization_management(self):
|
16
|
+
self.__enable_customization_management = False
|
17
|
+
return self
|
18
|
+
|
19
|
+
def execute(self):
|
20
|
+
raise NotImplementedError
|
21
|
+
|
22
|
+
def num_required_args(self):
|
23
|
+
raise NotImplementedError
|
24
|
+
|
25
|
+
def usage(self):
|
26
|
+
return self
|
command/Build.py
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
import sys
|
2
|
+
|
3
|
+
from sqlalchemy import create_engine
|
4
|
+
from sqlalchemy.orm import sessionmaker
|
5
|
+
|
6
|
+
from db.TableExceptions import TableExceptions
|
7
|
+
|
8
|
+
from .BaseCommand import BaseCommand
|
9
|
+
|
10
|
+
|
11
|
+
class Build(BaseCommand):
|
12
|
+
def __build_datastore(self):
|
13
|
+
self.conversation.display_project(self.configuration.project.name)
|
14
|
+
|
15
|
+
db = create_engine(self.configuration.project.datastore.uri)
|
16
|
+
session = sessionmaker(autocommit=False, autoflush=False, bind=db)()
|
17
|
+
table_exceptions = TableExceptions().universal()
|
18
|
+
|
19
|
+
self.conversation.type("Connected to datastore...\n")
|
20
|
+
|
21
|
+
try:
|
22
|
+
if self.configuration.project.datastore.type == "mysql":
|
23
|
+
table_exceptions = TableExceptions().mysql()
|
24
|
+
session.execute("set foreign_key_checks = 0")
|
25
|
+
self.conversation.type(" foreign key checks have been disabled\n")
|
26
|
+
|
27
|
+
tables = session.execute("show tables").all()
|
28
|
+
if len(tables) > 0:
|
29
|
+
self.conversation.type(" dropping existing entities\n")
|
30
|
+
|
31
|
+
for table in tables:
|
32
|
+
if table not in table_exceptions:
|
33
|
+
self.conversation.type(f" {table[0]}\n", delay=0.002)
|
34
|
+
session.execute(f"drop table if exists {table[0]}")
|
35
|
+
|
36
|
+
self.conversation.type(" building entities\n")
|
37
|
+
|
38
|
+
for entity in self.memory.entities:
|
39
|
+
self.conversation.type(f" {entity['name']}\n", delay=0.002)
|
40
|
+
session.execute(entity["definition"])
|
41
|
+
finally:
|
42
|
+
if self.configuration.project.datastore.type == "mysql":
|
43
|
+
session.execute("set foreign_key_checks = 1")
|
44
|
+
self.conversation.type(" foreign key checks have been enabled\n")
|
45
|
+
|
46
|
+
self.conversation.newline()
|
47
|
+
|
48
|
+
def execute(self):
|
49
|
+
if len(sys.argv) != 3 or sys.argv[2] != "datastore":
|
50
|
+
self.usage()
|
51
|
+
|
52
|
+
if self.memory.entities is None or len(self.memory.entities) == 0:
|
53
|
+
self.no_entities()
|
54
|
+
|
55
|
+
self.__build_datastore()
|
56
|
+
|
57
|
+
def no_entities(self):
|
58
|
+
self.conversation.display_project(self.configuration.project.name)
|
59
|
+
self.conversation.type(
|
60
|
+
"Ahhh man. I would love to but there aren't any entities.\n"
|
61
|
+
)
|
62
|
+
self.conversation.newline()
|
63
|
+
exit(1)
|
64
|
+
|
65
|
+
def usage(self):
|
66
|
+
self.conversation.display_project(self.configuration.project.name)
|
67
|
+
self.conversation.type(f"usage: {self.configuration.command} build datastore\n")
|
68
|
+
self.conversation.newline()
|
69
|
+
exit(1)
|
command/Code.py
ADDED
@@ -0,0 +1,198 @@
|
|
1
|
+
import os
|
2
|
+
import re
|
3
|
+
import sys
|
4
|
+
from string import Template
|
5
|
+
|
6
|
+
from api.Cli import Cli
|
7
|
+
from core.Configuration import Configuration
|
8
|
+
from display.Header import Header
|
9
|
+
from display.WorkspaceFooter import WorkspaceFooter
|
10
|
+
from display.WorkspaceHeader import WorkspaceHeader
|
11
|
+
from services.code.context.schema.Manager import Manager as CodeContextSchemaManager
|
12
|
+
from structure.Entity import Entity
|
13
|
+
|
14
|
+
from .BaseCommand import BaseCommand
|
15
|
+
from .Merge import Merge
|
16
|
+
from .Rewrite import Rewrite
|
17
|
+
|
18
|
+
|
19
|
+
class Code(BaseCommand):
|
20
|
+
CODE_WRITER_ENTITY_MODIFIER_NOOP = ""
|
21
|
+
|
22
|
+
def __init__(self, configuration: Configuration):
|
23
|
+
super().__init__(configuration)
|
24
|
+
self.__context = None
|
25
|
+
|
26
|
+
def __add_foreign_key(self, entity, entity_name):
|
27
|
+
entity_keys = self.__context.get_entity_keys(entity_name)
|
28
|
+
if entity_keys is None:
|
29
|
+
self.conversation.type(
|
30
|
+
f'\nThe entity you referenced, "{entity_name}", does not exist.\n'
|
31
|
+
)
|
32
|
+
self.conversation.wait()
|
33
|
+
return False
|
34
|
+
|
35
|
+
best_sql_foreign_key = entity_keys.best_sql_foreign_key()
|
36
|
+
if best_sql_foreign_key is None:
|
37
|
+
self.conversation.type(
|
38
|
+
f'\nYou cannot make a foreign key to "{entity_name}".\n'
|
39
|
+
+ "It does not have primary or unique keys.\n"
|
40
|
+
)
|
41
|
+
self.conversation.wait()
|
42
|
+
return False
|
43
|
+
|
44
|
+
foreign_key, index, data_types = best_sql_foreign_key
|
45
|
+
|
46
|
+
for i in range(len(foreign_key.attributes)):
|
47
|
+
entity.add_attribute(
|
48
|
+
foreign_key.attributes[i],
|
49
|
+
data_types[i],
|
50
|
+
after="uuid",
|
51
|
+
before="date_created",
|
52
|
+
)
|
53
|
+
|
54
|
+
entity.add_foreign_key(foreign_key)
|
55
|
+
entity.add_index(index)
|
56
|
+
|
57
|
+
return True
|
58
|
+
|
59
|
+
def configure_definition(self):
|
60
|
+
existing_entity = self.memory.recall_entity(sys.argv[3])
|
61
|
+
if existing_entity is not None:
|
62
|
+
return existing_entity["definition"]
|
63
|
+
|
64
|
+
parts = sys.argv[3].split("_")
|
65
|
+
if len(parts) > 1 and parts[1] == "ref":
|
66
|
+
# This is a reference table implementation. We will handle this here.
|
67
|
+
with open(self.get_default_ref_table_template_path()) as f:
|
68
|
+
definition = Template(f.read()).substitute({"entity_name": sys.argv[3]})
|
69
|
+
|
70
|
+
self.memory.append_last({"definition": definition, "name": sys.argv[3]})
|
71
|
+
|
72
|
+
self.conversation.type(
|
73
|
+
"Reference table created and stored in last memory. What's next?\n"
|
74
|
+
)
|
75
|
+
self.conversation.newline()
|
76
|
+
|
77
|
+
exit(1)
|
78
|
+
|
79
|
+
with open(self.get_default_table_template_path()) as f:
|
80
|
+
return Template(f.read()).substitute({"entity_name": sys.argv[3]})
|
81
|
+
|
82
|
+
def execute(self):
|
83
|
+
if len(sys.argv) != 4 or sys.argv[2] not in ["entity"]:
|
84
|
+
self.usage()
|
85
|
+
|
86
|
+
cli = Cli(self.configuration)
|
87
|
+
|
88
|
+
self.conversation.display_project(self.configuration.project.name)
|
89
|
+
definition = self.configure_definition()
|
90
|
+
|
91
|
+
self.conversation.c64_boot_search()
|
92
|
+
|
93
|
+
self.__context = CodeContextSchemaManager().from_code_writer_schema_context(
|
94
|
+
cli.code_writer_schema_context()
|
95
|
+
)
|
96
|
+
|
97
|
+
self.conversation.c64_boot_loading()
|
98
|
+
|
99
|
+
data = cli.code_writer_entity_modifier(
|
100
|
+
self.__context.json,
|
101
|
+
sys.argv[3],
|
102
|
+
definition,
|
103
|
+
self.CODE_WRITER_ENTITY_MODIFIER_NOOP,
|
104
|
+
)
|
105
|
+
entity = Entity().import_from_struct(data)
|
106
|
+
|
107
|
+
self.conversation.c64_ready_run()
|
108
|
+
|
109
|
+
while True:
|
110
|
+
self.__render_workspace(entity, data["code"][0]["definition"])
|
111
|
+
|
112
|
+
input_ = input("> ")
|
113
|
+
if input_ in [".", ":q", ":w"]:
|
114
|
+
self.conversation.newline()
|
115
|
+
|
116
|
+
if input_ == ":q":
|
117
|
+
exit(1)
|
118
|
+
|
119
|
+
self.memory.remember_last({"entities": [data["entity"]]})
|
120
|
+
|
121
|
+
if input_ == ".":
|
122
|
+
self.conversation.type(
|
123
|
+
"Damn we write good code. I stored this in last memory. "
|
124
|
+
+ "Your move.\n"
|
125
|
+
)
|
126
|
+
else:
|
127
|
+
self.conversation.mute()
|
128
|
+
Merge(self.configuration).execute()
|
129
|
+
self.conversation.unmute()
|
130
|
+
|
131
|
+
Rewrite(self.configuration, wipe=False).execute()
|
132
|
+
|
133
|
+
self.conversation.newline()
|
134
|
+
|
135
|
+
exit(1)
|
136
|
+
elif input_ == "":
|
137
|
+
continue
|
138
|
+
|
139
|
+
talk_to_gibsonai = True
|
140
|
+
|
141
|
+
parts = input_.split(" ")
|
142
|
+
if parts[0] == "fk":
|
143
|
+
input_ = self.CODE_WRITER_ENTITY_MODIFIER_NOOP
|
144
|
+
if not self.__add_foreign_key(entity, parts[1]):
|
145
|
+
# If the entity was not modified, likely because the table
|
146
|
+
# referenced does not exist or does not contain indexes which
|
147
|
+
# can be used for a foreign key, do not waste the network call
|
148
|
+
# to GibsonAI since there is nothing to do.
|
149
|
+
talk_to_gibsonai = False
|
150
|
+
|
151
|
+
if talk_to_gibsonai is True:
|
152
|
+
data = cli.code_writer_entity_modifier(
|
153
|
+
self.__context.json,
|
154
|
+
data["entity"]["name"],
|
155
|
+
entity.create_statement(),
|
156
|
+
input_,
|
157
|
+
)
|
158
|
+
entity = Entity().import_from_struct(data)
|
159
|
+
|
160
|
+
def get_default_ref_table_template_path(self):
|
161
|
+
return os.path.dirname(__file__) + "/../data/default-ref-table.tmpl"
|
162
|
+
|
163
|
+
def get_default_table_template_path(self):
|
164
|
+
return os.path.dirname(__file__) + "/../data/default-table.tmpl"
|
165
|
+
|
166
|
+
def __render_workspace(self, entity: Entity, model):
|
167
|
+
self.configuration.platform.cmd_clear()
|
168
|
+
|
169
|
+
print("")
|
170
|
+
print(WorkspaceHeader().render(self.configuration.project.name))
|
171
|
+
|
172
|
+
print("")
|
173
|
+
print(Header().render("SQL"))
|
174
|
+
print("")
|
175
|
+
print(entity.create_statement())
|
176
|
+
|
177
|
+
print("")
|
178
|
+
print(Header().render("Model"))
|
179
|
+
print("")
|
180
|
+
print(model)
|
181
|
+
|
182
|
+
print("")
|
183
|
+
print(WorkspaceFooter().render())
|
184
|
+
|
185
|
+
def usage(self):
|
186
|
+
self.conversation.display_project(self.configuration.project.name)
|
187
|
+
self.conversation.type(
|
188
|
+
f"usage: {self.configuration.command} code [thing] [name]\n"
|
189
|
+
+ ' where [thing] can only be "entity", for now\n'
|
190
|
+
+ " and [name] is what you want [thing] to be called\n"
|
191
|
+
)
|
192
|
+
self.conversation.newline()
|
193
|
+
self.conversation.type(
|
194
|
+
' To create a new entity called "user":\n'
|
195
|
+
" gibson code entity user\n"
|
196
|
+
)
|
197
|
+
self.conversation.newline()
|
198
|
+
exit(1)
|