# Path: djangoevents/app.py
# class EventSourcingWithDjango(EventSourcingApplication):
#     def __init__(self, **kwargs):
#         kwargs.setdefault('json_encoder_cls', DjangoJSONEncoder)
#         super().__init__(**kwargs)
#         self.on_init()
# 
#     def on_init(self):
#         """
#         Override at subclass. For example, initialize repositories that this
#         app would use.
#         """
# 
#     def create_stored_event_repo(self, **kwargs):
#         return DjangoStoredEventRepository(**kwargs)
# 
#     def create_transcoder(self, always_encrypt, cipher, json_decoder_cls, json_encoder_cls):
#         return UnifiedTranscoder(json_encoder_cls=json_encoder_cls)
# 
#     def get_repo_for_aggregate(self, aggregate_cls):
#         """
#         Returns EventSourcedRepository class for a given aggregate.
#         """
#         clsname = '%sRepository' % aggregate_cls.__name__
#         repo_cls = type(clsname, (EventSourcedRepository,), {'domain_class': aggregate_cls})
#         return repo_cls(event_store=self.event_store)
# 
#     def get_repo_for_entity(self, entity_cls):
#         """
#         Returns EventSourcedRepository class for given entity.
#         """
#         msg = "`get_repo_for_entity` is depreciated. Please switch to: `get_repo_for_aggregate`"
#         warnings.warn(msg, DeprecationWarning)
#         return self.get_repo_for_aggregate(aggregate_cls=entity_cls)
# 
# Path: djangoevents/models.py
# class Event(models.Model):
#     event_id = models.CharField(max_length=255, db_index=True)
#     event_type = models.CharField(max_length=255)
#     event_version = models.IntegerField(null=True)
#     event_data = models.TextField()
#     aggregate_id = models.CharField(max_length=255, db_index=True)
#     aggregate_type = models.CharField(max_length=255)
#     aggregate_version = models.IntegerField()
#     create_date = models.DateTimeField()
#     metadata = models.TextField()
#     module_name = models.CharField(max_length=255, db_column='_module_name')
#     class_name = models.CharField(max_length=255, db_column='_class_name')
#     stored_entity_id = models.CharField(max_length=255, db_column='_stored_entity_id', db_index=True)
# 
#     class Meta:
#         unique_together = (("aggregate_id", "aggregate_type", "aggregate_version"),)
#         db_table = 'event_journal'
# 
#     def __str__(self):
#         return '%s.%s | %s | %s' % (self.aggregate_type, self.event_type, self.event_id, self.create_date)
# 
# Path: djangoevents/repository.py
# def from_model_instance(event):
#     return UnifiedStoredEvent(
#         event_id=event.event_id,
#         event_type=event.event_type,
#         event_version=event.event_version,
#         event_data=event.event_data,
#         aggregate_id=event.aggregate_id,
#         aggregate_type=event.aggregate_type,
#         aggregate_version=event.aggregate_version,
#         create_date=event.create_date,
#         metadata=event.metadata,
#         module_name=event.module_name,
#         class_name=event.class_name,
#         stored_entity_id=event.stored_entity_id
#     )
# 
# Path: djangoevents/unifiedtranscoder.py
# class UnifiedTranscoder(AbstractTranscoder):
# class ResolveDomainFailed(Exception):
#     def __init__(self, json_encoder_cls=None):
#     def serialize(self, domain_event):
#     def deserialize(self, stored_event):
#     def _get_domain_event_class(module_name, class_name):
#     def _json_encode(self, data):
#     def _json_decode(self, json_str):
# def get_aggregate_type(domain_event):
# def get_event_type(domain_event):
# 
# Path: djangoevents/exceptions.py
# class AlreadyExists(DjangoeventsError):
#     pass


from ..app import EventSourcingWithDjango
from ..models import Event
from ..repository import from_model_instance
from ..unifiedtranscoder import UnifiedStoredEvent
from eventsourcing.domain.model.entity import EventSourcedEntity
from eventsourcing.domain.services.transcoding import EntityVersion
from eventsourcing.utils.time import timestamp_from_uuid
from datetime import datetime
from django.db import transaction
from djangoevents.exceptions import AlreadyExists
import json
import pytest
@pytest.fixture
def repo():
    app = SampleApp()
    return app.stored_event_repo


@pytest.fixture
def stored_events():
    return [new_stored_event(uuids[i], 'Created', {'title': 'test'}, uuids[0], i) for i, uuid in enumerate(uuids)]


@pytest.mark.django_db
def test_repo_append(repo):
    test_stored_event = new_stored_event(uuids[0], 'Created', {'title': 'test'}, uuids[1], 1)

    # test basic save and get
    repo.append(test_stored_event)
    events = Event.objects.filter(stored_entity_id=test_stored_event.stored_entity_id)
    assert len(events) == 1
    assert test_stored_event == from_model_instance(events[0])

    # test unique constraint
    with transaction.atomic():
        test_stored_event2 = new_stored_event(uuids[2], 'Updated', {'title': 'updated test'}, uuids[1], 1)
        with pytest.raises(AlreadyExists):
            repo.append(test_stored_event2)

    # multiple saves
    test_stored_event3 = new_stored_event(uuids[2], 'Updated', {'title': 'updated test'}, uuids[1], 2)
    repo.append(test_stored_event3)

# Path: djangoevents/app.py
# class EventSourcingWithDjango(EventSourcingApplication):
#     def __init__(self, **kwargs):
#         kwargs.setdefault('json_encoder_cls', DjangoJSONEncoder)
#         super().__init__(**kwargs)
#         self.on_init()
# 
#     def on_init(self):
#         """
#         Override at subclass. For example, initialize repositories that this
#         app would use.
#         """
# 
#     def create_stored_event_repo(self, **kwargs):
#         return DjangoStoredEventRepository(**kwargs)
# 
#     def create_transcoder(self, always_encrypt, cipher, json_decoder_cls, json_encoder_cls):
#         return UnifiedTranscoder(json_encoder_cls=json_encoder_cls)
# 
#     def get_repo_for_aggregate(self, aggregate_cls):
#         """
#         Returns EventSourcedRepository class for a given aggregate.
#         """
#         clsname = '%sRepository' % aggregate_cls.__name__
#         repo_cls = type(clsname, (EventSourcedRepository,), {'domain_class': aggregate_cls})
#         return repo_cls(event_store=self.event_store)
# 
#     def get_repo_for_entity(self, entity_cls):
#         """
#         Returns EventSourcedRepository class for given entity.
#         """
#         msg = "`get_repo_for_entity` is depreciated. Please switch to: `get_repo_for_aggregate`"
#         warnings.warn(msg, DeprecationWarning)
#         return self.get_repo_for_aggregate(aggregate_cls=entity_cls)
# 
# Path: djangoevents/models.py
# class Event(models.Model):
#     event_id = models.CharField(max_length=255, db_index=True)
#     event_type = models.CharField(max_length=255)
#     event_version = models.IntegerField(null=True)
#     event_data = models.TextField()
#     aggregate_id = models.CharField(max_length=255, db_index=True)
#     aggregate_type = models.CharField(max_length=255)
#     aggregate_version = models.IntegerField()
#     create_date = models.DateTimeField()
#     metadata = models.TextField()
#     module_name = models.CharField(max_length=255, db_column='_module_name')
#     class_name = models.CharField(max_length=255, db_column='_class_name')
#     stored_entity_id = models.CharField(max_length=255, db_column='_stored_entity_id', db_index=True)
# 
#     class Meta:
#         unique_together = (("aggregate_id", "aggregate_type", "aggregate_version"),)
#         db_table = 'event_journal'
# 
#     def __str__(self):
#         return '%s.%s | %s | %s' % (self.aggregate_type, self.event_type, self.event_id, self.create_date)
# 
# Path: djangoevents/repository.py
# def from_model_instance(event):
#     return UnifiedStoredEvent(
#         event_id=event.event_id,
#         event_type=event.event_type,
#         event_version=event.event_version,
#         event_data=event.event_data,
#         aggregate_id=event.aggregate_id,
#         aggregate_type=event.aggregate_type,
#         aggregate_version=event.aggregate_version,
#         create_date=event.create_date,
#         metadata=event.metadata,
#         module_name=event.module_name,
#         class_name=event.class_name,
#         stored_entity_id=event.stored_entity_id
#     )
# 
# Path: djangoevents/unifiedtranscoder.py
# class UnifiedTranscoder(AbstractTranscoder):
# class ResolveDomainFailed(Exception):
#     def __init__(self, json_encoder_cls=None):
#     def serialize(self, domain_event):
#     def deserialize(self, stored_event):
#     def _get_domain_event_class(module_name, class_name):
#     def _json_encode(self, data):
#     def _json_decode(self, json_str):
# def get_aggregate_type(domain_event):
# def get_event_type(domain_event):
# 
# Path: djangoevents/exceptions.py
# class AlreadyExists(DjangoeventsError):
#     pass


# Path: djangoevents/tests/test_repo.py
from ..app import EventSourcingWithDjango
from ..models import Event
from ..repository import from_model_instance
from ..unifiedtranscoder import UnifiedStoredEvent
from eventsourcing.domain.model.entity import EventSourcedEntity
from eventsourcing.domain.services.transcoding import EntityVersion
from eventsourcing.utils.time import timestamp_from_uuid
from datetime import datetime
from django.db import transaction
from djangoevents.exceptions import AlreadyExists
import json
import pytest

@pytest.fixture
def repo():
    app = SampleApp()
    return app.stored_event_repo


@pytest.fixture
def stored_events():
    return [new_stored_event(uuids[i], 'Created', {'title': 'test'}, uuids[0], i) for i, uuid in enumerate(uuids)]


@pytest.mark.django_db
def test_repo_append(repo):
    test_stored_event = new_stored_event(uuids[0], 'Created', {'title': 'test'}, uuids[1], 1)

    # test basic save and get
    repo.append(test_stored_event)
    events = Event.objects.filter(stored_entity_id=test_stored_event.stored_entity_id)
    assert len(events) == 1
    assert test_stored_event == from_model_instance(events[0])

    # test unique constraint
    with transaction.atomic():
        test_stored_event2 = new_stored_event(uuids[2], 'Updated', {'title': 'updated test'}, uuids[1], 1)
        with pytest.raises(AlreadyExists):
            repo.append(test_stored_event2)

    # multiple saves
    test_stored_event3 = new_stored_event(uuids[2], 'Updated', {'title': 'updated test'}, uuids[1], 2)
    repo.append(test_stored_event3)

    events = Event.objects.filter(stored_entity_id=test_stored_event.stored_entity_id)