gibson-cli 0.6.1__py3-none-any.whl → 0.7.1__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.
Files changed (58) hide show
  1. gibson/api/BaseApi.py +2 -1
  2. gibson/api/Cli.py +9 -2
  3. gibson/command/Build.py +60 -8
  4. gibson/command/Help.py +0 -12
  5. gibson/command/Question.py +4 -7
  6. gibson/command/code/Code.py +42 -12
  7. gibson/command/code/Entity.py +25 -7
  8. gibson/command/code/Model.py +1 -1
  9. gibson/command/code/Schema.py +1 -1
  10. gibson/command/code/Test.py +35 -0
  11. gibson/command/code/Tests.py +12 -21
  12. gibson/command/importer/Import.py +83 -11
  13. gibson/command/importer/OpenApi.py +4 -9
  14. gibson/command/new/Module.py +1 -1
  15. gibson/command/new/New.py +3 -3
  16. gibson/command/new/Project.py +2 -2
  17. gibson/command/rewrite/Rewrite.py +9 -14
  18. gibson/command/tests/test_command_Conf.py +1 -0
  19. gibson/conf/Project.py +1 -0
  20. gibson/core/Configuration.py +21 -58
  21. gibson/core/Conversation.py +25 -7
  22. gibson/data/bash-completion.tmpl +3 -4
  23. gibson/data/postgresql/default-ref-table.tmpl +4 -0
  24. gibson/data/postgresql/default-table.tmpl +5 -0
  25. gibson/db/TableExceptions.py +3 -0
  26. gibson/db/tests/test_db_TableExceptions.py +4 -0
  27. gibson/services/code/context/schema/EntityKeys.py +3 -3
  28. gibson/services/code/context/schema/tests/test_code_context_schema_EntityKeys.py +3 -3
  29. gibson/structure/Entity.py +12 -109
  30. gibson/structure/mysql/Entity.py +117 -0
  31. gibson/structure/{constraints → mysql/constraints}/ReferenceConstraint.py +6 -2
  32. gibson/structure/{keys → mysql/keys}/ForeignKey.py +9 -5
  33. gibson/structure/{keys → mysql/keys}/Index.py +7 -3
  34. gibson/structure/{keys/tests/test_ForeignKey.py → mysql/keys/tests/test_structure_mysql_keys_ForeignKey.py} +16 -8
  35. gibson/structure/{keys/tests/test_Index.py → mysql/keys/tests/test_structure_mysql_keys_Index.py} +7 -3
  36. gibson/structure/{keys/tests/test_IndexAttribute.py → mysql/keys/tests/test_structure_mysql_keys_IndexAttribute.py} +1 -1
  37. gibson/structure/mysql/testing.py +231 -0
  38. gibson/structure/{tests/test_Entity.py → mysql/tests/test_structure_mysql_Entity.py} +34 -20
  39. gibson/structure/postgresql/Entity.py +108 -0
  40. gibson/structure/postgresql/References.py +61 -0
  41. gibson/structure/postgresql/table/ForeignKey.py +28 -0
  42. gibson/structure/postgresql/table/tests/test_structure_postgresql_table_ForeignKey.py +44 -0
  43. gibson/structure/{testing.py → postgresql/testing.py} +45 -82
  44. gibson/structure/postgresql/tests/test_structure_postgresql_Entity.py +82 -0
  45. gibson/structure/tests/test_structure_Entity.py +22 -0
  46. {gibson_cli-0.6.1.dist-info → gibson_cli-0.7.1.dist-info}/METADATA +25 -27
  47. {gibson_cli-0.6.1.dist-info → gibson_cli-0.7.1.dist-info}/RECORD +57 -47
  48. {gibson_cli-0.6.1.dist-info → gibson_cli-0.7.1.dist-info}/WHEEL +1 -1
  49. gibson/command/rewrite/Tests.py +0 -26
  50. /gibson/command/{rewrite → code}/Api.py +0 -0
  51. /gibson/command/{rewrite → code}/Base.py +0 -0
  52. /gibson/command/{rewrite → code}/Models.py +0 -0
  53. /gibson/command/{rewrite → code}/Schemas.py +0 -0
  54. /gibson/data/{default-ref-table.tmpl → mysql/default-ref-table.tmpl} +0 -0
  55. /gibson/data/{default-table.tmpl → mysql/default-table.tmpl} +0 -0
  56. /gibson/structure/{keys → mysql/keys}/IndexAttribute.py +0 -0
  57. {gibson_cli-0.6.1.dist-info → gibson_cli-0.7.1.dist-info}/entry_points.txt +0 -0
  58. {gibson_cli-0.6.1.dist-info → gibson_cli-0.7.1.dist-info}/top_level.txt +0 -0
gibson/api/BaseApi.py CHANGED
@@ -1,4 +1,5 @@
1
1
  import os
2
+ import pprint
2
3
 
3
4
  import requests
4
5
 
@@ -96,7 +97,7 @@ class BaseApi:
96
97
  message = r.json()
97
98
  print("=" * 78)
98
99
  print("Raw Response:\n")
99
- print(message)
100
+ pprint.pprint(message)
100
101
  print("\n" + "=" * 78)
101
102
  except requests.exceptions.JSONDecodeError:
102
103
  pass
gibson/api/Cli.py CHANGED
@@ -66,7 +66,10 @@ class Cli(BaseApi):
66
66
 
67
67
  def headers(self):
68
68
  headers = super().headers()
69
- headers["X-Gibson-API-Key"] = self.configuration.project.api.key
69
+ if self.configuration.project.id:
70
+ headers["X-Gibson-Project-ID"] = self.configuration.project.id
71
+ else:
72
+ headers["X-Gibson-API-Key"] = self.configuration.project.api.key
70
73
  return headers
71
74
 
72
75
  def import_(self):
@@ -157,7 +160,11 @@ class Cli(BaseApi):
157
160
  def modeler_openapi(self, modeler_version, contents):
158
161
  r = self.post(
159
162
  "modeler/openapi",
160
- {"contents": contents, "modeler": {"version": modeler_version}},
163
+ {
164
+ "contents": contents,
165
+ "datastore": {"type": self.configuration.project.datastore.type},
166
+ "modeler": {"version": modeler_version},
167
+ },
161
168
  )
162
169
 
163
170
  return r.json()
gibson/command/Build.py CHANGED
@@ -1,5 +1,6 @@
1
1
  import sys
2
2
 
3
+ import sqlalchemy
3
4
  from sqlalchemy import create_engine
4
5
  from sqlalchemy.orm import sessionmaker
5
6
 
@@ -18,11 +19,19 @@ class Build(BaseCommand):
18
19
 
19
20
  self.conversation.type("Connected to datastore...\n")
20
21
 
22
+ if self.configuration.project.datastore.type == "mysql":
23
+ self.__build_mysql(session)
24
+ elif self.configuration.project.datastore.type == "postgresql":
25
+ self.__build_postgresql(session)
26
+
27
+ self.conversation.newline()
28
+
29
+ def __build_mysql(self, session):
21
30
  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")
31
+ table_exceptions = TableExceptions().mysql()
32
+
33
+ session.execute("set foreign_key_checks = 0")
34
+ self.conversation.type(" foreign key checks have been disabled\n")
26
35
 
27
36
  tables = session.execute("show tables").all()
28
37
  if len(tables) > 0:
@@ -39,11 +48,54 @@ class Build(BaseCommand):
39
48
  self.conversation.type(f" {entity['name']}\n", delay=0.002)
40
49
  session.execute(entity["definition"])
41
50
  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")
51
+ session.execute("set foreign_key_checks = 1")
52
+ self.conversation.type(" foreign key checks have been enabled\n")
53
+
54
+ def __build_postgresql(self, session):
55
+ table_exceptions = TableExceptions().postgresql()
56
+
57
+ schema = list(session.execute("select current_schema()"))[0][0]
58
+ self.conversation.type(f" current schema is {schema}\n")
59
+
60
+ tables = list(
61
+ session.execute(
62
+ """select table_name
63
+ from information_schema.tables
64
+ where table_schema = :table_schema""",
65
+ {"table_schema": schema},
66
+ )
67
+ )
45
68
 
46
- self.conversation.newline()
69
+ if len(tables) > 0:
70
+ self.conversation.type(" dropping existing entities\n")
71
+
72
+ for table in tables:
73
+ self.conversation.type(f" {table[0]}\n", delay=0.002)
74
+ session.execute(f"drop table if exists {schema}.{table[0]} cascade")
75
+ session.commit()
76
+
77
+ self.conversation.type(" building entities\n")
78
+
79
+ tables = {}
80
+ for entity in self.memory.entities:
81
+ tables[entity["name"]] = entity["definition"]
82
+
83
+ while tables != {}:
84
+ remove = []
85
+ for name, definition in tables.items():
86
+
87
+ try:
88
+ session.execute(definition)
89
+ session.commit()
90
+
91
+ self.conversation.type(f' {name.split(".")[-1]}\n', delay=0.002)
92
+
93
+ remove.append(name)
94
+ except sqlalchemy.exc.ProgrammingError:
95
+ session.rollback()
96
+
97
+ for name in remove:
98
+ del tables[name]
47
99
 
48
100
  def execute(self):
49
101
  if len(sys.argv) != 3 or sys.argv[2] != "datastore":
gibson/command/Help.py CHANGED
@@ -48,10 +48,6 @@ class Help(BaseCommand):
48
48
  "description": "move last changes into project",
49
49
  "memory": "last -> stored",
50
50
  },
51
- "model": {
52
- "description": "write the model code for an entity",
53
- "memory": "stored",
54
- },
55
51
  "modify": {
56
52
  "description": "change an entity using natural language",
57
53
  "memory": "last > stored",
@@ -69,15 +65,7 @@ class Help(BaseCommand):
69
65
  "description": "rewrite code",
70
66
  "memory": "stored",
71
67
  },
72
- "schema": {
73
- "description": "write the schema code for an entity",
74
- "memory": "stored",
75
- },
76
68
  "show": {"description": "display an entity", "memory": "last > stored"},
77
- "test": {
78
- "description": "write the unit tests for an entity",
79
- "memory": "stored",
80
- },
81
69
  "tree": {"description": "illustrate the project layout", "memory": None},
82
70
  "q": {"description": "ask Gibson a question", "memory": None},
83
71
  }
@@ -28,7 +28,10 @@ class Question(BaseCommand):
28
28
  with open(path, "r") as f:
29
29
  contents = f.read()
30
30
  except FileNotFoundError:
31
- self.__file_not_found(path)
31
+ self.configuration.display_project()
32
+ self.conversation.file_not_found(path)
33
+ self.conversation.newline()
34
+ exit(1)
32
35
 
33
36
  has_file = True
34
37
  instructions += f"\n\n{contents}\n\n"
@@ -81,12 +84,6 @@ class Question(BaseCommand):
81
84
 
82
85
  self.conversation.newline()
83
86
 
84
- def __file_not_found(self, path):
85
- self.configuration.display_project()
86
- self.conversation.type(f'404, My Friend. Cannot find file "{path}".\n')
87
- self.conversation.newline()
88
- exit(1)
89
-
90
87
  def __python_import_not_found(self, import_):
91
88
  self.configuration.display_project()
92
89
  self.conversation.type(f'That\'s a misfire, "{import_}" does not exist.\n')
@@ -2,41 +2,71 @@ import sys
2
2
 
3
3
  import gibson.core.Colors as Colors
4
4
  from gibson.command.BaseCommand import BaseCommand
5
- from gibson.command.code.Entity import CodeEntity
6
- from gibson.command.code.Model import CodeModel
7
- from gibson.command.code.Schema import CodeSchema
8
- from gibson.command.code.Tests import CodeTests
5
+ from gibson.command.code.Api import Api as CodeApi
6
+ from gibson.command.code.Base import Base as CodeBase
7
+ from gibson.command.code.Entity import Entity as CodeEntity
8
+ from gibson.command.code.Model import Model as CodeModel
9
+ from gibson.command.code.Models import Models as CodeModels
10
+ from gibson.command.code.Schema import Schema as CodeSchema
11
+ from gibson.command.code.Schemas import Schemas as CodeSchemas
12
+ from gibson.command.code.Test import Test as CodeTest
13
+ from gibson.command.code.Tests import Tests as CodeTests
9
14
 
10
15
 
11
16
  class Code(BaseCommand):
12
17
  def execute(self):
13
- if len(sys.argv) == 4 and sys.argv[2] == "entity":
18
+ if len(sys.argv) == 3 and sys.argv[2] == "api":
19
+ CodeApi(self.configuration).execute()
20
+ elif len(sys.argv) == 3 and sys.argv[2] == "base":
21
+ CodeBase(self.configuration).execute()
22
+ elif len(sys.argv) == 4 and sys.argv[2] == "entity":
14
23
  CodeEntity(self.configuration).execute()
15
- elif len(sys.argv) == 4 and sys.argv[2] == "model":
24
+ elif len(sys.argv) == 3 and sys.argv[2] == "models":
25
+ CodeModels(self.configuration).execute()
26
+ elif len(sys.argv) == 4 and sys.argv[2] == "models":
16
27
  CodeModel(self.configuration).execute()
17
- elif len(sys.argv) == 4 and sys.argv[2] == "schema":
28
+ elif len(sys.argv) == 3 and sys.argv[2] == "schemas":
29
+ CodeSchemas(self.configuration).execute()
30
+ elif len(sys.argv) == 4 and sys.argv[2] == "schemas":
18
31
  CodeSchema(self.configuration).execute()
19
- elif len(sys.argv) == 4 and sys.argv[2] == "tests":
32
+ elif len(sys.argv) == 3 and sys.argv[2] == "tests":
20
33
  CodeTests(self.configuration).execute()
34
+ elif len(sys.argv) == 4 and sys.argv[2] == "tests":
35
+ CodeTest(self.configuration).execute()
21
36
  else:
22
37
  self.usage()
23
38
 
24
39
  def usage(self):
25
40
  self.configuration.display_project()
26
41
  self.conversation.type(
27
- f"usage: {Colors.command(self.configuration.command)} {Colors.subcommand('code')} {Colors.arguments(['entity', 'model', 'schema', 'tests'])} {Colors.input('[entity name]')} {Colors.hint('write code')}\n"
42
+ f"usage: {Colors.command(self.configuration.command)} {Colors.subcommand('code')} {Colors.arguments(['api', 'base', 'entity', 'models', 'schemas', 'tests'])} {Colors.input('[entity name]')} {Colors.hint('write code')}\n"
43
+ )
44
+ self.conversation.type(
45
+ f" {Colors.command(self.configuration.command)} {Colors.subcommand('code')} {Colors.argument('api')} {Colors.hint('generate the API code')}\n"
46
+ )
47
+ self.conversation.type(
48
+ f" {Colors.command(self.configuration.command)} {Colors.subcommand('code')} {Colors.argument('base')} {Colors.hint('generate the base code')}\n"
28
49
  )
29
50
  self.conversation.type(
30
51
  f" {Colors.command(self.configuration.command)} {Colors.subcommand('code')} {Colors.argument('entity')} {Colors.input('[entity name]')} {Colors.hint('create or update an entity using the AI pair programmer')}\n"
31
52
  )
32
53
  self.conversation.type(
33
- f" {Colors.command(self.configuration.command)} {Colors.subcommand('code')} {Colors.argument('model')} {Colors.input('[entity name]')} {Colors.hint('generate the model code for an entity')}\n"
54
+ f" {Colors.command(self.configuration.command)} {Colors.subcommand('code')} {Colors.argument('models')} {Colors.hint('generate the models for all entities')}\n"
55
+ )
56
+ self.conversation.type(
57
+ f" {Colors.command(self.configuration.command)} {Colors.subcommand('code')} {Colors.argument('models')} {Colors.input('[entity name]')} {Colors.hint('generate the model(s) for a single entity')}\n"
58
+ )
59
+ self.conversation.type(
60
+ f" {Colors.command(self.configuration.command)} {Colors.subcommand('code')} {Colors.argument('schemas')} {Colors.hint('generate the schemas for all entities')}\n"
61
+ )
62
+ self.conversation.type(
63
+ f" {Colors.command(self.configuration.command)} {Colors.subcommand('code')} {Colors.argument('schemas')} {Colors.input('[entity name]')} {Colors.hint('generate the schema(s) for a single entity')}\n"
34
64
  )
35
65
  self.conversation.type(
36
- f" {Colors.command(self.configuration.command)} {Colors.subcommand('code')} {Colors.argument('schema')} {Colors.input('[entity name]')} {Colors.hint('generate the schema code for an entity')}\n"
66
+ f" {Colors.command(self.configuration.command)} {Colors.subcommand('code')} {Colors.argument('tests')} {Colors.hint('generate the unit tests for all entities')}\n"
37
67
  )
38
68
  self.conversation.type(
39
- f" {Colors.command(self.configuration.command)} {Colors.subcommand('code')} {Colors.argument('tests')} {Colors.input('[entity name]')} {Colors.hint('generate the unit tests for an entity')}\n"
69
+ f" {Colors.command(self.configuration.command)} {Colors.subcommand('code')} {Colors.argument('tests')} {Colors.input('[entity name]')} {Colors.hint('generate the unit tests for a single entity')}\n"
40
70
  )
41
71
  self.conversation.newline()
42
72
  exit(1)
@@ -14,10 +14,10 @@ from gibson.display.WorkspaceHeader import WorkspaceHeader
14
14
  from gibson.services.code.context.schema.Manager import (
15
15
  Manager as CodeContextSchemaManager,
16
16
  )
17
- from gibson.structure.Entity import Entity
17
+ from gibson.structure.Entity import Entity as StructureEntity
18
18
 
19
19
 
20
- class CodeEntity(BaseCommand):
20
+ class Entity(BaseCommand):
21
21
  CODE_WRITER_ENTITY_MODIFIER_NOOP = ""
22
22
 
23
23
  def __init__(self, configuration: Configuration):
@@ -96,7 +96,11 @@ class CodeEntity(BaseCommand):
96
96
  definition,
97
97
  self.CODE_WRITER_ENTITY_MODIFIER_NOOP,
98
98
  )
99
- entity = Entity().import_from_struct(data)
99
+ entity = (
100
+ StructureEntity()
101
+ .instantiate(self.configuration.project.datastore.type)
102
+ .import_from_struct(data)
103
+ )
100
104
 
101
105
  while True:
102
106
  self.__render_workspace(entity, data["code"][0]["definition"])
@@ -147,15 +151,29 @@ class CodeEntity(BaseCommand):
147
151
  entity.create_statement(),
148
152
  input_,
149
153
  )
150
- entity = Entity().import_from_struct(data)
154
+ entity = (
155
+ StructureEntity()
156
+ .instantiate(self.configuration.project.datastore.type)
157
+ .import_from_struct(data)
158
+ )
151
159
 
152
160
  def get_default_ref_table_template_path(self):
153
- return os.path.dirname(__file__) + "/../../data/default-ref-table.tmpl"
161
+ return (
162
+ os.path.dirname(__file__)
163
+ + "/../../data/"
164
+ + self.configuration.project.datastore.type
165
+ + "/default-ref-table.tmpl"
166
+ )
154
167
 
155
168
  def get_default_table_template_path(self):
156
- return os.path.dirname(__file__) + "/../../data/default-table.tmpl"
169
+ return (
170
+ os.path.dirname(__file__)
171
+ + "/../../data/"
172
+ + self.configuration.project.datastore.type
173
+ + "/default-table.tmpl"
174
+ )
157
175
 
158
- def __render_workspace(self, entity: Entity, model):
176
+ def __render_workspace(self, entity: StructureEntity, model):
159
177
  self.configuration.platform.cmd_clear()
160
178
 
161
179
  print("")
@@ -7,7 +7,7 @@ from gibson.core.TimeKeeper import TimeKeeper
7
7
  from gibson.dev.Dev import Dev
8
8
 
9
9
 
10
- class CodeModel(BaseCommand):
10
+ class Model(BaseCommand):
11
11
  def execute(self):
12
12
  self.configuration.require_project()
13
13
  entity = self.memory.recall_stored_entity(sys.argv[3])
@@ -7,7 +7,7 @@ from gibson.core.TimeKeeper import TimeKeeper
7
7
  from gibson.dev.Dev import Dev
8
8
 
9
9
 
10
- class CodeSchema(BaseCommand):
10
+ class Schema(BaseCommand):
11
11
  def execute(self):
12
12
  self.configuration.require_project()
13
13
  entity = self.memory.recall_stored_entity(sys.argv[3])
@@ -0,0 +1,35 @@
1
+ import sys
2
+
3
+ import gibson.core.Colors as Colors
4
+ from gibson.api.Cli import Cli
5
+ from gibson.command.BaseCommand import BaseCommand
6
+ from gibson.core.TimeKeeper import TimeKeeper
7
+ from gibson.dev.Dev import Dev
8
+
9
+
10
+ class Test(BaseCommand):
11
+ def execute(self):
12
+ self.configuration.require_project()
13
+ entity = self.memory.recall_stored_entity(sys.argv[3])
14
+ if entity is None:
15
+ self.conversation.not_sure_no_entity(
16
+ self.configuration.project.name, sys.argv[3]
17
+ )
18
+ exit(1)
19
+
20
+ time_keeper = TimeKeeper()
21
+
22
+ cli = Cli(self.configuration)
23
+ response = cli.code_testing([entity["name"]])
24
+
25
+ Dev(self.configuration).tests(
26
+ response["code"][0]["entity"]["name"], response["code"][0]["definition"]
27
+ )
28
+
29
+ if self.configuration.project.dev.active is True:
30
+ self.conversation.type(
31
+ f"Gibson wrote the following {Colors.argument('tests')} to your project:\n"
32
+ )
33
+
34
+ print(response["code"][0]["definition"])
35
+ time_keeper.display()
@@ -1,35 +1,26 @@
1
- import sys
2
-
3
- import gibson.core.Colors as Colors
4
1
  from gibson.api.Cli import Cli
5
2
  from gibson.command.BaseCommand import BaseCommand
6
3
  from gibson.core.TimeKeeper import TimeKeeper
7
4
  from gibson.dev.Dev import Dev
8
5
 
9
6
 
10
- class CodeTests(BaseCommand):
7
+ class Tests(BaseCommand):
11
8
  def execute(self):
12
- self.configuration.require_project()
13
- entity = self.memory.recall_stored_entity(sys.argv[3])
14
- if entity is None:
15
- self.conversation.not_sure_no_entity(
16
- self.configuration.project.name, sys.argv[3]
17
- )
18
- exit(1)
9
+ entities = []
10
+ if self.memory.entities is not None:
11
+ for entity in self.memory.entities:
12
+ entities.append(entity["name"])
19
13
 
20
14
  time_keeper = TimeKeeper()
21
15
 
22
16
  cli = Cli(self.configuration)
23
- response = cli.code_testing([entity["name"]])
17
+ response = cli.code_testing(entities)
24
18
 
25
- Dev(self.configuration).tests(
26
- response["code"][0]["entity"]["name"], response["code"][0]["definition"]
27
- )
19
+ for entry in response["code"]:
20
+ Dev(self.configuration).tests(entry["entity"]["name"], entry["definition"])
28
21
 
29
- if self.configuration.project.dev.active is True:
30
- self.conversation.type(
31
- f"Gibson wrote the following {Colors.argument('tests')} to your project:\n"
32
- )
22
+ if self.conversation.muted() is False:
23
+ print(entry["definition"])
33
24
 
34
- print(response["code"][0]["definition"])
35
- time_keeper.display()
25
+ if self.conversation.muted() is False:
26
+ time_keeper.display()
@@ -1,3 +1,4 @@
1
+ import re
1
2
  import sys
2
3
 
3
4
  from sqlalchemy import create_engine
@@ -19,8 +20,11 @@ class Import(BaseCommand):
19
20
  if len(sys.argv) == 3 and sys.argv[2] == "api":
20
21
  entities = self.__import_from_api()
21
22
  write_code = self.configuration.project.dev.active
22
- elif len(sys.argv) == 3 and sys.argv[2] == "datastore":
23
- entities = self.__import_from_datastore()
23
+ elif len(sys.argv) == 3 and sys.argv[2] == "mysql":
24
+ entities = self.__import_from_mysql()
25
+ write_code = self.configuration.project.dev.active
26
+ elif len(sys.argv) == 4 and sys.argv[2] == "pg_dump":
27
+ entities = self.__import_from_postgresql()
24
28
  write_code = self.configuration.project.dev.active
25
29
  elif len(sys.argv) == 4 and sys.argv[2] == "openapi":
26
30
  return OpenApi(self.configuration).execute()
@@ -31,7 +35,10 @@ class Import(BaseCommand):
31
35
 
32
36
  word_entities = "entity" if len(entities) == 1 else "entities"
33
37
 
34
- self.conversation.type("\nSummary\n")
38
+ if len(entities) > 0:
39
+ self.conversation.newline()
40
+
41
+ self.conversation.type("Summary\n")
35
42
  self.conversation.type(f" {len(entities)} {word_entities} imported\n")
36
43
  self.conversation.newline()
37
44
 
@@ -53,15 +60,11 @@ class Import(BaseCommand):
53
60
 
54
61
  return response["project"]["entities"]
55
62
 
56
- def __import_from_datastore(self):
57
- self.configuration.display_project()
58
-
63
+ def __import_from_mysql(self):
59
64
  db = create_engine(self.configuration.project.datastore.uri)
60
65
  session = sessionmaker(autocommit=False, autoflush=False, bind=db)()
61
66
 
62
- table_exceptions = TableExceptions().universal()
63
- if self.configuration.project.datastore.type == "mysql":
64
- table_exceptions = TableExceptions().mysql()
67
+ table_exceptions = TableExceptions().mysql()
65
68
 
66
69
  self.conversation.type("Connected to datastore...\n")
67
70
  self.conversation.type("Building schema...\n")
@@ -83,6 +86,72 @@ class Import(BaseCommand):
83
86
 
84
87
  return entities
85
88
 
89
+ def __import_from_postgresql(self):
90
+ self.conversation.type("Reading pg_dump file...\n")
91
+
92
+ try:
93
+ with open(sys.argv[3], "r") as f:
94
+ contents = f.read()
95
+ except FileNotFoundError:
96
+ self.conversation.file_not_found(sys.argv[3])
97
+ self.conversation.newline()
98
+ exit(1)
99
+
100
+ lines = contents.split("\n")
101
+
102
+ tables = {}
103
+ for i in range(len(lines)):
104
+ matches = re.search(
105
+ r"^create table (.*)\s+\(", lines[i].lstrip().rstrip(), re.IGNORECASE
106
+ )
107
+ if matches:
108
+ table_name = matches[1].split(".")[-1]
109
+ definition = []
110
+
111
+ while True:
112
+ i += 1
113
+
114
+ if lines[i].lstrip().rstrip() == ");":
115
+ tables[table_name] = definition
116
+ break
117
+ else:
118
+ definition.append(lines[i].lstrip().rstrip())
119
+ else:
120
+ matches = re.search(
121
+ r"^alter table(?:\s+only)\s+(.*)$",
122
+ lines[i].lstrip().rstrip(),
123
+ re.IGNORECASE,
124
+ )
125
+ if matches:
126
+ table_name = matches[1].split(".")[-1]
127
+
128
+ i += 1
129
+ matches = re.search(
130
+ r"^add (constraint .*?);?$",
131
+ lines[i].lstrip().rstrip(),
132
+ re.IGNORECASE,
133
+ )
134
+ if matches:
135
+ if tables[table_name][-1][-1] != ",":
136
+ tables[table_name][-1] += ","
137
+
138
+ tables[table_name].append(matches[1] + ",")
139
+
140
+ entities = []
141
+ for table_name, definition in tables.items():
142
+ self.conversation.type(f" {table_name}\n", delay=0.002)
143
+
144
+ definition[-1] = definition[-1].rstrip(",")
145
+
146
+ create_table = f"create table if not exists {table_name} (\n"
147
+ for entry in definition:
148
+ create_table += " " * 4 + entry + "\n"
149
+ create_table += ")"
150
+
151
+ entities.append({"definition": create_table, "name": table_name})
152
+
153
+ return entities
154
+
86
155
  def usage(self):
87
156
  self.configuration.display_project()
88
157
  datastore_uri = (
@@ -91,13 +160,16 @@ class Import(BaseCommand):
91
160
  else ""
92
161
  )
93
162
  self.conversation.type(
94
- f"usage: {Colors.command(self.configuration.command)} {Colors.subcommand('import')} {Colors.arguments(['api', 'datastore', 'openapi'])} {Colors.hint('import entities')}\n"
163
+ f"usage: {Colors.command(self.configuration.command)} {Colors.subcommand('import')} {Colors.arguments(['api', 'mysql', 'pg_dump', 'openapi'])} {Colors.hint('import entities')}\n"
95
164
  )
96
165
  self.conversation.type(
97
166
  f" {Colors.command(self.configuration.command)} {Colors.subcommand('import')} {Colors.argument('api')} {Colors.hint(f'import all entities from your project created on {Colors.link(self.configuration.app_domain())}')}\n"
98
167
  )
99
168
  self.conversation.type(
100
- f" {Colors.command(self.configuration.command)} {Colors.subcommand('import')} {Colors.argument('datastore')} {Colors.hint('import all entities from your local datastore')} {Colors.link(datastore_uri)}\n"
169
+ f" {Colors.command(self.configuration.command)} {Colors.subcommand('import')} {Colors.argument('mysql')} {Colors.hint('import all entities from your MySQL database')} ({Colors.link(datastore_uri)})\n"
170
+ )
171
+ self.conversation.type(
172
+ f" {Colors.command(self.configuration.command)} {Colors.subcommand('import')} {Colors.argument('pg_dump')} {Colors.input('path/to/pg_dump.sql')} {Colors.hint('import all entities from a pg_dump file')}\n"
101
173
  )
102
174
  self.conversation.type(
103
175
  f" {Colors.command(self.configuration.command)} {Colors.subcommand('import')} {Colors.argument('openapi')} {Colors.input('path/to/openapi.json')} {Colors.hint('import all entities from an OpenAPI spec file')}\n"
@@ -20,7 +20,10 @@ class OpenApi(BaseCommand):
20
20
  with open(sys.argv[3], "r") as f:
21
21
  contents = json.loads(f.read())
22
22
  except FileNotFoundError:
23
- self.file_not_found()
23
+ self.configuration.display_project()
24
+ self.conversation.file_not_found(sys.argv[3])
25
+ self.conversation.newline()
26
+ exit(1)
24
27
  except json.decoder.JSONDecodeError:
25
28
  self.bad_json()
26
29
 
@@ -112,14 +115,6 @@ class OpenApi(BaseCommand):
112
115
 
113
116
  return True
114
117
 
115
- def file_not_found(self):
116
- self.configuration.display_project()
117
- self.conversation.type(
118
- f'Well that embarrassing. There is no file "{sys.argv[3]}".\n'
119
- )
120
- self.conversation.newline()
121
- exit(1)
122
-
123
118
  def unrecognized_format(self):
124
119
  self.configuration.display_project()
125
120
  self.conversation.type(
@@ -3,7 +3,7 @@ from gibson.api.Cli import Cli
3
3
  from gibson.command.BaseCommand import BaseCommand
4
4
 
5
5
 
6
- class NewModule(BaseCommand):
6
+ class Module(BaseCommand):
7
7
  def execute(self):
8
8
  self.configuration.require_project()
9
9
  module_name = self.conversation.prompt_module()
gibson/command/new/New.py CHANGED
@@ -2,9 +2,9 @@ import sys
2
2
 
3
3
  import gibson.core.Colors as Colors
4
4
  from gibson.command.BaseCommand import BaseCommand
5
- from gibson.command.code.Entity import CodeEntity
6
- from gibson.command.new.Module import NewModule
7
- from gibson.command.new.Project import NewProject
5
+ from gibson.command.code.Entity import Entity as CodeEntity
6
+ from gibson.command.new.Module import Module as NewModule
7
+ from gibson.command.new.Project import Project as NewProject
8
8
 
9
9
 
10
10
  class New(BaseCommand):
@@ -1,7 +1,7 @@
1
1
  from gibson.command.BaseCommand import BaseCommand
2
2
 
3
3
 
4
- class NewProject(BaseCommand):
4
+ class Project(BaseCommand):
5
5
  def execute(self):
6
6
  self.conversation.new_project(self.configuration)
7
7
  project_name = self.conversation.prompt_project()
@@ -9,7 +9,7 @@ class NewProject(BaseCommand):
9
9
  self.conversation.project_already_exists(project_name)
10
10
  exit(1)
11
11
 
12
- project_description = self.conversation.prompt_description(project_name)
12
+ project_description = self.conversation.prompt_project_description(project_name)
13
13
 
14
14
  self.configuration.set_project_env(project_name)
15
15
  self.configuration.append_project_to_conf(project_name, project_description)