Skip to content

Commit

Permalink
added support for ddl generation from py-models-parser output
Browse files Browse the repository at this point in the history
  • Loading branch information
xnuinside committed Jan 7, 2022
1 parent 7e2bb21 commit ad98961
Show file tree
Hide file tree
Showing 11 changed files with 322 additions and 13 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
**v0.2.0**

1. Updated parser version in tests.
2. Added support for EXTERNAL & IF NOT EXISTS statetements.
3. Added support for using py-models-parser output as input and added sample in README.md:

DDL Generation from Pydantic, SQLAlchemy and other python models.

**v0.1.0**

Base Generator Functionality with several test cases.
62 changes: 62 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@ Simple DDL Generator generate SQL DDL from 3 different inputs. Idea of the gener

Simple DDL Generator generate SQL DDL from 3 input formats - 1st from output Simple DDL Parser (https://github.com/xnuinside/simple-ddl-parser), 2nd from py-models-parser - https://github.com/xnuinside/py-models-parser. Or you can directly pass TableMeta classes (https://github.com/xnuinside/table-meta) to generator

### Generate DDL from Django, SQLAlchemy, Dataclasses, Pydantic models and other

Generator can generate DDL from all models that supported & parsed by https://github.com/xnuinside/py-models-parser.

If you need DDL generation from another Python Model types - open issue request to add support for this models in parser.


## How to use

As usually - more samples in tests/
Expand All @@ -18,6 +25,10 @@ As usually - more samples in tests/

```

### Generate / Modify using existed DDL with Simple-DDL-Parser


Sample how you can modify your DDL using Simple DDL Parser & Simple DDL Parser

```python

Expand Down Expand Up @@ -65,8 +76,59 @@ As usually - more samples in tests/

```

### Generate DDL from various Python Models with py-models-parser

```python

from simple_ddl_generator import DDLGenerator
from py_models_parser import parse

# you can also read them from file
model_from = """
class Material(BaseModel):
id: int
title: str
description: Optional[str]
link: str = 'http://'
type: Optional[MaterialType]
additional_properties: Optional[Json]
created_at: Optional[datetime.datetime] = datetime.datetime.now()
updated_at: Optional[datetime.datetime]
"""
# get data with parser
result = parse(model_from)

# pass data to DDL Generator
g = DDLGenerator(result)
g.generate()
print(g.result)

# resul will be

"""CREATE TABLE "Material" (
id INTEGER,
title VARCHAR,
description VARCHAR,
link VARCHAR DEFAULT 'http://',
type MaterialType,
additional_properties JSON,
created_at DATETIME DEFAULT now(),
updated_at DATETIME);
"""

```


## Changelog
**v0.2.0**

1. Updated parser version in tests.
2. Added support for EXTERNAL & IF NOT EXISTS statetements.
3. Added support for using py-models-parser output as input and added sample in README.md:

DDL Generation from Pydantic, SQLAlchemy and other python models.

**v0.1.0**

Base Generator Functionality with several test cases.
64 changes: 64 additions & 0 deletions docs/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,13 @@ Simple DDL Generator generate SQL DDL from 3 different inputs. Idea of the gener

Simple DDL Generator generate SQL DDL from 3 input formats - 1st from output Simple DDL Parser (https://github.com/xnuinside/simple-ddl-parser), 2nd from py-models-parser - https://github.com/xnuinside/py-models-parser. Or you can directly pass TableMeta classes (https://github.com/xnuinside/table-meta) to generator

Generate DDL from Django, SQLAlchemy, Dataclasses, Pydantic models and other
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Generator can generate DDL from all models that supported & parsed by https://github.com/xnuinside/py-models-parser.

If you need DDL generation from another Python Model types - open issue request to add support for this models in parser.

How to use
----------

Expand All @@ -37,6 +44,11 @@ As usually - more samples in tests/
pip install simple-ddl-generator
Generate / Modify using existed DDL with Simple-DDL-Parser
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Sample how you can modify your DDL using Simple DDL Parser & Simple DDL Parser

.. code-block:: python
Expand Down Expand Up @@ -82,9 +94,61 @@ As usually - more samples in tests/
PARTITIONED BY (batch_id int);
"""
Generate DDL from various Python Models with py-models-parser
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

.. code-block:: python
from simple_ddl_generator import DDLGenerator
from py_models_parser import parse
# you can also read them from file
model_from = """
class Material(BaseModel):
id: int
title: str
description: Optional[str]
link: str = 'http://'
type: Optional[MaterialType]
additional_properties: Optional[Json]
created_at: Optional[datetime.datetime] = datetime.datetime.now()
updated_at: Optional[datetime.datetime]
"""
# get data with parser
result = parse(model_from)
# pass data to DDL Generator
g = DDLGenerator(result)
g.generate()
print(g.result)
# resul will be
"""CREATE TABLE "Material" (
id INTEGER,
title VARCHAR,
description VARCHAR,
link VARCHAR DEFAULT 'http://',
type MaterialType,
additional_properties JSON,
created_at DATETIME DEFAULT now(),
updated_at DATETIME);
"""
Changelog
---------

**v0.2.0**


#. Updated parser version in tests.
#. Added support for EXTERNAL & IF NOT EXISTS statetements.
#. Added support for using py-models-parser output as input and added sample in README.md:

DDL Generation from Pydantic, SQLAlchemy and other python models.

**v0.1.0**

Base Generator Functionality with several test cases.
31 changes: 30 additions & 1 deletion poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "simple-ddl-generator"
version = "0.1.0"
version = "0.2.0"
description = "Library to generate DDL for different dialects"
authors = ["Iuliia Volkova <xnuinside@gmail.com>"]
readme = "docs/README.rst"
Expand All @@ -22,6 +22,7 @@ simple-ddl-parser = "^0.24.1"
m2r2 = "^0.3.2"
twine = "^3.7.1"
pre-commit = "^2.16.0"
py-models-parser = "^0.6.0"

[build-system]
requires = ["poetry>=0.12"]
Expand Down
25 changes: 19 additions & 6 deletions simple_ddl_generator/core.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,32 @@
from table_meta import ddl_to_meta
from table_meta import ddl_to_meta, models_to_meta, TableMeta
from typing import Dict
from simple_ddl_generator.generator import Generator

from simple_ddl_generator.models_data import prepare_models_data

class DDLGenerator:

def __init__(self, data: Dict, dialect: str = 'sql') -> None:
self.data = data
self.ddl_output = None
self.dialect = dialect

def generate(self) -> str:
self.tables = ddl_to_meta(self.data)

def convert_to_table_meta(self):
print(self.data, 'DATAAA')
if not isinstance(self.data, dict) or not isinstance(self.data['tables'][0], TableMeta):
if isinstance(self.data, dict) and not "attrs" in self.data['tables'][0]:
self.prepared_data = ddl_to_meta(self.data)
else:
self.prepare_models_data()
else:
self.prepared_data = self.data

def prepare_models_data(self):
self.prepared_data = prepare_models_data(models_to_meta(self.data))

def generate(self) -> str:
self.convert_to_table_meta()
self.generate_ddl()

return self.ddl_output

def to_file(self, file_name) -> None:
Expand All @@ -23,5 +36,5 @@ def to_file(self, file_name) -> None:
target_file.write(self.ddl_output)

def generate_ddl(self) -> str:
self.result = Generator(self.tables, self.dialect).render_template()
self.result = Generator(self.prepared_data, self.dialect).render_template()
return self.result
8 changes: 4 additions & 4 deletions simple_ddl_generator/generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@

class Generator:

def __init__(self, tables: TableMeta, dialect: str) -> None:
self.tables = tables
def __init__(self, data: TableMeta, dialect: str) -> None:
self.data = data
self.dialect = dialect

def render_template(self) -> str:
template = jinja2_env.get_template('common.jinja2')
print(self.tables)

return template.render(
properties_as_is=hql_table_properties,
**self.tables)
**self.data)
17 changes: 17 additions & 0 deletions simple_ddl_generator/models_data.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from typing import Dict
from simple_ddl_generator.type_converter import prepare_type


def default_cleaner(default_value: str):
if default_value:
if 'datetime.' in default_value:
default_value = default_value.split('datetime.')[-1]
return default_value


def prepare_models_data(data: Dict):
for table in data["tables"]:
for column in table.columns:
column.type = prepare_type(column.type)
column.default = default_cleaner(column.default)
return data
2 changes: 1 addition & 1 deletion simple_ddl_generator/templates/column.jinja2
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{% include "column_base.jinja2" %}{{" NOT NULL" if not column.nullable else ""}}{{" PRIMARY KEY" if column.primary_key else ""}}{{" UNIQUE" if column.unique else ""}}{{ columnn.references if column.references}}{{ columnn.default if column.default}}
{% include "column_base.jinja2" %}{{" NOT NULL" if not column.nullable else ""}}{{" PRIMARY KEY" if column.primary_key else ""}}{{" UNIQUE" if column.unique else ""}}{{ column.references if column.references}}{{ " DEFAULT " + column.default if column.default}}
Loading

0 comments on commit ad98961

Please sign in to comment.