Skip to content

Feature/add table support #63

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions sqlalchemy_seed/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
import os

import yaml
from sqlalchemy import MetaData

try:
from yaml import CLoader as Loader
except ImportError:
Expand Down Expand Up @@ -90,6 +92,22 @@ def _create_model_instance(fixture):
return instances


def _create_table_object_data(fixture, session):
Copy link
Owner

@heavenshell heavenshell Jun 24, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add session to docstring param 😉

"""Create a Table object entry.

:param fixture: Fixtures
"""
for data in fixture:
if 'table' in data:
module_name, class_name = data['table'].rsplit('.', 1)
importlib.import_module(module_name)
metadata = MetaData()
metadata.reflect(bind=session.get_bind())
table = metadata.tables[class_name]
insert = table.insert()
session.execute(insert.values(**data['fields']))
Copy link
Owner

@heavenshell heavenshell Jun 24, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not familier with Table so, if I say something wrong with this review, please point out 😉
What happen if insert failed. Does DB rollback?

What about do something like followings?
Is this satisfy your requirements? 😄
I want controll session flush, commit, rollback at same place.
IMO it's readable 😉

def _create_table_object_data(fixture, session):
    """Create a Table object entry.

    :param fixture: Fixtures
    :param session: Session
    """
    table_values = []
    for data in fixture:
        if 'table' in data:
            module_name, class_name = data['table'].rsplit('.', 1)
            importlib.import_module(module_name)
            metadata = MetaData()
            metadata.reflect(bind=session.get_bind())
            table = metadata.tables[class_name]
            insert = table.insert()
            insert.values(**data['fields'])
            table_values.append(insert)

    return table_values

def load_fixtures(session, fixtures):
    """Load fixture.

    :param base: `sqlalchemy.ext.declarative`
    :param fixtures: Fixture files
    """
    instances = []
    tables = []
    for fixture in fixtures:
        _instances = _create_model_instance(fixture)
        for instance in _instances:
            instances.append(instance)
        _tables = _create_table_object_data(fixture, session)
        for table in _tables:
            tables.append(table)

    try:
        for instance in instances:
            session.merge(instance)

        for table in tables:
            session.execute(table)
        session.flush()
        session.commit()
    except Exception:
        session.rollback()
        raise

Copy link
Owner

@heavenshell heavenshell Jun 24, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nn- I think I wrote something strange? 🤔



def load_fixtures(session, fixtures):
"""Load fixture.

Expand All @@ -99,6 +117,7 @@ def load_fixtures(session, fixtures):
instances = []
for fixture in fixtures:
_instances = _create_model_instance(fixture)
_create_table_object_data(fixture, session)
for instance in _instances:
instances.append(instance)

Expand Down
9 changes: 9 additions & 0 deletions tests/fixtures/picture_categories.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
- model: tests.test_sqlalchey_seed.PictureCategory
id: 1
fields:
name: Category1
- model: tests.test_sqlalchey_seed.PictureCategory
id: 2
fields:
name: Category2

12 changes: 12 additions & 0 deletions tests/fixtures/picture_category_picture.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
- table: tests.test_sqlalchey_seed.picture_category_picture
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🙆‍♂

id: 1
fields:
picture_id: 1
picture_category_id: 1

- table: tests.test_sqlalchey_seed.picture_category_picture
id: 2
fields:
picture_id: 1
picture_category_id: 2

30 changes: 28 additions & 2 deletions tests/test_sqlalchey_seed.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import os
from unittest import TestCase

from sqlalchemy import Column, create_engine, ForeignKey, Integer, String
from sqlalchemy import Column, create_engine, ForeignKey, Integer, String, Table
from sqlalchemy.exc import OperationalError
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship, scoped_session, sessionmaker
Expand Down Expand Up @@ -75,6 +75,28 @@ def __repr__(self):
)


class PictureCategory(Base):
__tablename__ = 'picture_category'

id = Column(Integer, primary_key=True)
name = Column(String(120))

def __repr__(self):
"""Repr."""
return 'PictureCategory(id={0}, name={1})'.format(
self.id,
self.name,
)


picture_category_picture = Table(
'picture_category_picture',
Base.metadata,
Column('picture_id', Integer, ForeignKey('pictures.id')),
Column('picture_category_id', Integer, ForeignKey('picture_category.id')),
)


class TestFixtures(TestCase):
path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'fixtures')

Expand Down Expand Up @@ -105,13 +127,17 @@ def test_load_fixture(self):
def test_load_fixtures(self):
create_table(Base)
fixtures = load_fixture_files(
self.path, ['accounts.yaml', 'pictures.yaml'],
self.path, ['accounts.yaml', 'pictures.yaml', 'picture_categories.yaml', 'picture_category_picture.yaml'],
Copy link
Owner

@heavenshell heavenshell Jun 24, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add new test case, such as test_load_table_fixtures.
I want test_load_fixtures assure not BCBreak 😌

)
load_fixtures(session, fixtures)
accounts = session.query(Account).all()
self.assertEqual(len(accounts), 2)
pictures = session.query(Picture).all()
self.assertEqual(len(pictures), 4)
picture_categories = session.query(PictureCategory).all()
self.assertEqual(len(picture_categories), 2)
category_rels = session.query(picture_category_picture).all()
self.assertEqual(len(category_rels), 2)

drop_table(Base, session)

Expand Down