Skip to content

Commit

Permalink
Bump version to 1.0.3
Browse files Browse the repository at this point in the history
- Update readme description
- update validator
- refactor tests
  • Loading branch information
jedymatt committed Sep 6, 2021
1 parent 8448e5b commit 2aa56ae
Show file tree
Hide file tree
Showing 6 changed files with 53 additions and 57 deletions.
28 changes: 15 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ from db import session
entities = load_entities_from_json('tests/test_data.json')

# Initializing Seeder
seeder = Seeder() # or Seeder(session)
seeder = Seeder() # or Seeder(session),

# Seeding
seeder.session = session # assign session if no session assigned before seeding
Expand All @@ -62,12 +62,11 @@ session.commit() # or seeder.session.commit()

## Seeder vs. HybridSeeder

| Features & Options | Seeder | HybridSeeder |
| :--------------------------------------------------------------------- | :----------------- | :----------------- |
| Support `model` and `data` keys | :heavy_check_mark: | :heavy_check_mark: |
| Support `model` and `filter` keys | :x: | :heavy_check_mark: |
| Optional argument `add_to_session=False` in the `seed` method | :heavy_check_mark: | :x: |
| Assign existing objects from session or db to a relationship attribute | :x: | :heavy_check_mark: |
| Features & Options | Seeder | HybridSeeder |
| :------------------------------------------------------------ | :----------------- | :----------------- |
| Support `model` and `data` keys | :heavy_check_mark: | :heavy_check_mark: |
| Support `model` and `filter` keys | :x: | :heavy_check_mark: |
| Optional argument `add_to_session=False` in the `seed` method | :heavy_check_mark: | :x: |

## When to use HybridSeeder and 'filter' key field?

Expand All @@ -81,7 +80,7 @@ from db import session
data = {
"model": "models.Parent",
"data": {
"!child": {
"!child": { # '!' is the reference prefix
"model": "models.Child",
"filter": {
"age": 5
Expand All @@ -91,15 +90,17 @@ data = {
}

# When seeding instances that has 'filter' key, then use HybridSeeder, otherwise use Seeder.
seeder = HybridSeeder(session)
# ref_prefix can be changed according to your needs, defaults to '!'
seeder = HybridSeeder(session, ref_prefix='!')
seeder.seed(data)

session.commit() # or seeder.sesssion.commit()
```

## Relationships

In adding a relationship attribute, add prefix **!** to the key in order to identify it.
In adding a reference attribute, add prefix **!** or to the key in order to identify it.
If you want '@' as prefix, you can just specify it to what seeder you use by adding ref_prefix='@' in the argument when instantiating the seeder in order for the seeder to identify the referencing attributes

### Referencing relationship object or a foreign key

Expand All @@ -122,7 +123,7 @@ instance = [
'name': 'John Smith',
# foreign key attribute
'!company_id': {
'model': 'tests.models.Company',
'model': 'tests.models.Company', # models can be removed if it is a referencing attribute
'filter': {
'name': 'MyCompany'
}
Expand All @@ -132,7 +133,7 @@ instance = [
'name': 'Juan Dela Cruz',
# relationship attribute
'!company': {
'model': 'tests.models.Company',
'model': 'tests.models.Company', # models can be removed if it is a referencing attribute
'filter': {
'name': 'MyCompany'
}
Expand All @@ -143,6 +144,7 @@ instance = [

seeder = HybridSeeder(session)
seeder.seed(instance)
seeder.session.commit() # or session.commit()
```

### No Relationship
Expand Down Expand Up @@ -267,7 +269,7 @@ seeder.seed(instance)
}
```

## Examples
## File Input Examples

### JSON

Expand Down
6 changes: 3 additions & 3 deletions TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@
overridden by providing a model data instead as it saves performance time
- [x] Add test case for overriding default reference prefix
- [ ] Update README description
- [ ] add docstrings
- [ ] Add docstrings
- [ ] Refactor test instances and test cases

## Tentative Plans

- load entities from excel support
- add docs
- Support load entities from excel
- Add docs
2 changes: 1 addition & 1 deletion src/sqlalchemyseed/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
from .loader import load_entities_from_csv


__version__ = "1.0.2"
__version__ = "1.0.3"

if __name__ == '__main__':
pass
21 changes: 8 additions & 13 deletions src/sqlalchemyseed/validator.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
SOFTWARE.
"""

import abc
from . import errors, util


Expand Down Expand Up @@ -106,18 +105,13 @@ def check_data_type(item, source_key: Key):
f"Invalid type_, '{source_key.name}' should be '{source_key.type_}'")


class SchemaValidator(abc.ABC):
class SchemaValidator:

def __init__(self, source_keys, ref_prefix):
self._source_keys = source_keys
self._ref_prefix = ref_prefix

@classmethod
def validate(cls, entities, source_keys, ref_prefix='!'):
self = cls(source_keys, ref_prefix)
self._source_keys = source_keys
self._ref_prefix = ref_prefix

def validate(self, entities):
self._pre_validate(entities, entity_is_parent=True)

def _pre_validate(self, entities: dict, entity_is_parent=True):
Expand Down Expand Up @@ -158,11 +152,12 @@ def check_attributes(self, source_data: dict):


def validate(entities, ref_prefix='!'):
SchemaValidator.validate(
entities, ref_prefix=ref_prefix, source_keys=[Key.data()])

SchemaValidator(source_keys=[Key.data()], ref_prefix=ref_prefix) \
.validate(entities=entities)


def hybrid_validate(entities, ref_prefix='!'):
SchemaValidator.validate(entities,
ref_prefix=ref_prefix,
source_keys=[Key.data(), Key.filter()])

SchemaValidator(source_keys=[Key.data(), Key.filter()], ref_prefix=ref_prefix) \
.validate(entities=entities)
8 changes: 8 additions & 0 deletions tests/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,14 @@ class GrandChild(Base):
parent_id = Column(Integer, ForeignKey('children.id'))



class Person(Base):
__tablename__ = 'persons'

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


not_class = 'this is not a class'


Expand Down
45 changes: 18 additions & 27 deletions tests/test_validator.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from sqlalchemyseed import validator

from src.sqlalchemyseed import errors
from src.sqlalchemyseed.validator import SchemaValidator, Key
from src.sqlalchemyseed.validator import SchemaValidator, Key, hybrid_validate
from tests import instances as ins


Expand All @@ -11,72 +11,63 @@ def setUp(self) -> None:
self.source_keys = [Key.data()]

def test_parent(self):
self.assertIsNone(SchemaValidator.validate(
ins.PARENT, source_keys=self.source_keys))
self.assertIsNone(hybrid_validate(ins.PARENT))

def test_parent_invalid(self):
self.assertRaises(errors.InvalidTypeError,
lambda: SchemaValidator.validate(ins.PARENT_INVALID, source_keys=self.source_keys))
lambda: hybrid_validate(ins.PARENT_INVALID))

def test_parent_empty(self):
self.assertIsNone(SchemaValidator.validate(
ins.PARENT_EMPTY, source_keys=self.source_keys))
self.assertIsNone(hybrid_validate(ins.PARENT_EMPTY))

def test_parent_empty_data_list_invalid(self):
self.assertRaises(errors.EmptyDataError,
lambda: SchemaValidator.validate(ins.PARENT_EMPTY_DATA_LIST_INVALID, source_keys=self.source_keys))
lambda: hybrid_validate(ins.PARENT_EMPTY_DATA_LIST_INVALID))

def test_parent_missing_model_invalid(self):
self.assertRaises(errors.MissingKeyError,
lambda: SchemaValidator.validate(ins.PARENT_MISSING_MODEL_INVALID, source_keys=self.source_keys))
lambda: hybrid_validate(ins.PARENT_MISSING_MODEL_INVALID))

def test_parent_invalid_model_invalid(self):
self.assertRaises(errors.InvalidTypeError,
lambda: SchemaValidator.validate(ins.PARENT_INVALID_MODEL_INVALID, source_keys=self.source_keys))
lambda: hybrid_validate(ins.PARENT_INVALID_MODEL_INVALID))

def test_parent_with_extra_length_invalid(self):
self.assertRaises(errors.MaxLengthExceededError,
lambda: SchemaValidator.validate(ins.PARENT_WITH_EXTRA_LENGTH_INVALID, source_keys=self.source_keys))
lambda: hybrid_validate(ins.PARENT_WITH_EXTRA_LENGTH_INVALID))

def test_parent_with_empty_data(self):
self.assertIsNone(SchemaValidator.validate(
ins.PARENT_WITH_EMPTY_DATA, source_keys=self.source_keys))
self.assertIsNone(hybrid_validate(ins.PARENT_WITH_EMPTY_DATA))

def test_parent_with_multi_data(self):
self.assertIsNone(SchemaValidator.validate(
ins.PARENT_WITH_MULTI_DATA, source_keys=self.source_keys))
self.assertIsNone(hybrid_validate(ins.PARENT_WITH_MULTI_DATA))

def test_parent_without_data_invalid(self):
self.assertRaises(errors.MissingKeyError,
lambda: SchemaValidator.validate(ins.PARENT_WITHOUT_DATA_INVALID, source_keys=self.source_keys))
lambda: hybrid_validate(ins.PARENT_WITHOUT_DATA_INVALID))

def test_parent_with_data_and_invalid_data_invalid(self):
self.assertRaises(errors.InvalidTypeError,
lambda: SchemaValidator.validate(ins.PARENT_WITH_DATA_AND_INVALID_DATA_INVALID, source_keys=self.source_keys))
lambda: hybrid_validate(ins.PARENT_WITH_DATA_AND_INVALID_DATA_INVALID))

def test_parent_with_invalid_data_invalid(self):
self.assertRaises(errors.InvalidTypeError,
lambda: SchemaValidator.validate(ins.PARENT_WITH_INVALID_DATA_INVALID, source_keys=self.source_keys))
lambda: hybrid_validate(ins.PARENT_WITH_INVALID_DATA_INVALID))

def test_parent_to_child(self):
self.assertIsNone(SchemaValidator.validate(
ins.PARENT_TO_CHILD, source_keys=self.source_keys))
self.assertIsNone(hybrid_validate(ins.PARENT_TO_CHILD))

def test_parent_to_children(self):
self.assertIsNone(SchemaValidator.validate(
ins.PARENT_TO_CHILDREN, source_keys=self.source_keys))
self.assertIsNone(hybrid_validate(ins.PARENT_TO_CHILDREN))

def test_parent_to_children_without_model(self):
self.assertIsNone(SchemaValidator.validate(
ins.PARENT_TO_CHILDREN_WITHOUT_MODEL, source_keys=self.source_keys))
self.assertIsNone(hybrid_validate(ins.PARENT_TO_CHILDREN_WITHOUT_MODEL))

def test_parent_to_children_with_multi_data(self):
self.assertIsNone(SchemaValidator.validate(
ins.PARENT_TO_CHILDREN_WITH_MULTI_DATA, source_keys=self.source_keys))
self.assertIsNone(hybrid_validate(ins.PARENT_TO_CHILDREN_WITH_MULTI_DATA))

def test_parent_to_children_with_multi_data_without_model(self):
self.assertIsNone(SchemaValidator.validate(
ins.PARENT_TO_CHILDREN_WITH_MULTI_DATA_WITHOUT_MODEL, source_keys=self.source_keys))
self.assertIsNone(hybrid_validate(ins.PARENT_TO_CHILDREN_WITH_MULTI_DATA_WITHOUT_MODEL))


class TestKey(unittest.TestCase):
Expand Down

0 comments on commit 2aa56ae

Please sign in to comment.