# Path: blitzdb/backends/sql/relations.py
# class ManyToManyProxy(object):
# 
#     """
#     The ManyToManyProxy transparently handles n:m relationships among different object types.
#     It automatically retrieves related documents from the database and initializes them.
# 
#     From the outside, the behavior corresponds to that of a normal Python list to which we
#     can append
# 
#     Open questions:
# 
#     * What happens if we copy a ManyToManyProxy to another object?
#       Answer:
#         The objects should be updated accordingly when the object gets saved to the database.
# 
#     :param        obj:
#     :param field_name:
#     :param     params:
# 
#     example::
# 
#         foo = bar
# 
#     """
# 
#     def __init__(self,obj,field_name,params,objects = None):
#         """
#         - Get the related class
#         - Create a query that will retrieve related objects according to our criteria
#           (either all elements of filtered by some key)
#         - When requesting objects, use a QuerySet to retrieve it from the database.
#         - When inserting/deleting objects, perform an INSERT against the database and
#           invalidate the QuerySet object that we use to retrieve objects.
#         """
#         self.obj = obj
#         self.collection = self.obj.backend.get_collection_for_obj(self.obj)
#         self.field_name = field_name
#         self.params = params
#         self._objects = objects
#         self._queryset = None
# 
#     def __call__(self,*args,**kwargs):
#         self.get_queryset(*args,**kwargs)
#         return self
# 
#     def __getitem__(self,i):
#         if not isinstance(i,(slice,int)):
#             raise TypeError("Index must be an integer or slice object")
#         queryset = self.get_queryset()
#         return queryset[i]
# 
#     def __setitem__(self,i,value):
#         #there is (IMHO) no reasonable and non-ambiguous way to implement this in SQL...
#         raise NotImplementedError
# 
#     def __contains__(self,item):
#         queryset = self.get_queryset()
#         return item in queryset
# 
#     def __delitem__(self,i):
#         obj = self[i]
#         self.remove(obj)
# 
#     def get_queryset(self,*args,**kwargs):
#         if self._queryset is None:
#             relationship_table = self.params['relationship_table']
#             foreign_table = self.obj.backend.get_collection_table(self.params['collection'])
#             condition = relationship_table.c[self.params['pk_field_name']] \
#                 == expression.cast(self.obj.pk,self.params['type'])
#             self._queryset = QuerySet(backend = self.obj.backend,
#                                       table = foreign_table,
#                                       cls = self.params['class'],
#                                       joins = [(relationship_table,)],
#                                       condition = condition,
#                                       objects = self._objects,
#                                       *args,
#                                       **kwargs)
#         return self._queryset
# 
#     def append(self,obj):
#         with self.obj.backend.transaction(implicit = True):
# 
#             #if the object is not yet in a DB, we save it first.
# 
#             if obj.pk is None:
#                 self.obj.backend.save(obj)
# 
#             relationship_table = self.params['relationship_table']
#             condition = and_(relationship_table.c[self.params['related_pk_field_name']] == obj.pk,
#                              relationship_table.c[self.params['pk_field_name']] == self.obj.pk)
#             s = select([func.count(text('*'))]).where(condition)
#             result = self.obj.backend.connection.execute(s)
#             cnt = result.first()[0]
#             if cnt:
#                 return #the object is already inside
#             values = {
#                 self.params['pk_field_name'] : self.obj.pk,
#                 self.params['related_pk_field_name'] : obj.pk
#             }
#             insert = relationship_table.insert().values(**values)
#             self.obj.backend.connection.execute(insert)
#             self._queryset = None
# 
#     def extend(self,objects):
#         for obj in objects:
#             self.append(obj)
# 
#     def insert(self,i,obj):
#         raise NotImplementedError
# 
#     def delete(self):
#         relationship_table = self.params['relationship_table']
#         with self.obj.backend.transaction(implicit = True):
#             condition = relationship_table.c[self.params['pk_field_name']] == self.obj.pk
#             self.obj.backend.connection.execute(delete(relationship_table).where(condition))
# 
#     def remove(self,obj):
#         """
#         Remove an object from the relation
#         """
#         relationship_table = self.params['relationship_table']
#         with self.obj.backend.transaction(implicit = True):
#             condition = and_(relationship_table.c[self.params['related_pk_field_name']] == obj.pk,
#                              relationship_table.c[self.params['pk_field_name']] == self.obj.pk)
#             self.obj.backend.connection.execute(delete(relationship_table).where(condition))
#             self._queryset = None
# 
#     def pop(self,i = None):
#         queryset = self.get_queryset()
#         return queryset.pop(i)
# 
#     def __len__(self):
#         queryset = self.get_queryset()
#         return len(queryset)
# 
# Path: tests/helpers/movie_data.py
# class Movie(Document):
#     class Meta(Document.Meta):
# class Actor(Document):
# class Food(Document):
# class Director(Document):
# class Role(Document):
# def generate_test_data(request, backend, n):


from blitzdb.backends.sql.relations import ManyToManyProxy
from ..helpers.movie_data import Actor, Director, Document, Movie
    from blitzdb.fields import ManyToManyField



def test_basics(backend):

    backend.init_schema()
    backend.create_schema()

    francis_coppola = Director({'name' : 'Francis Coppola'})
    stanley_kubrick = Director({'name' : 'Stanley Kubrick'})

# Path: blitzdb/backends/sql/relations.py
# class ManyToManyProxy(object):
# 
#     """
#     The ManyToManyProxy transparently handles n:m relationships among different object types.
#     It automatically retrieves related documents from the database and initializes them.
# 
#     From the outside, the behavior corresponds to that of a normal Python list to which we
#     can append
# 
#     Open questions:
# 
#     * What happens if we copy a ManyToManyProxy to another object?
#       Answer:
#         The objects should be updated accordingly when the object gets saved to the database.
# 
#     :param        obj:
#     :param field_name:
#     :param     params:
# 
#     example::
# 
#         foo = bar
# 
#     """
# 
#     def __init__(self,obj,field_name,params,objects = None):
#         """
#         - Get the related class
#         - Create a query that will retrieve related objects according to our criteria
#           (either all elements of filtered by some key)
#         - When requesting objects, use a QuerySet to retrieve it from the database.
#         - When inserting/deleting objects, perform an INSERT against the database and
#           invalidate the QuerySet object that we use to retrieve objects.
#         """
#         self.obj = obj
#         self.collection = self.obj.backend.get_collection_for_obj(self.obj)
#         self.field_name = field_name
#         self.params = params
#         self._objects = objects
#         self._queryset = None
# 
#     def __call__(self,*args,**kwargs):
#         self.get_queryset(*args,**kwargs)
#         return self
# 
#     def __getitem__(self,i):
#         if not isinstance(i,(slice,int)):
#             raise TypeError("Index must be an integer or slice object")
#         queryset = self.get_queryset()
#         return queryset[i]
# 
#     def __setitem__(self,i,value):
#         #there is (IMHO) no reasonable and non-ambiguous way to implement this in SQL...
#         raise NotImplementedError
# 
#     def __contains__(self,item):
#         queryset = self.get_queryset()
#         return item in queryset
# 
#     def __delitem__(self,i):
#         obj = self[i]
#         self.remove(obj)
# 
#     def get_queryset(self,*args,**kwargs):
#         if self._queryset is None:
#             relationship_table = self.params['relationship_table']
#             foreign_table = self.obj.backend.get_collection_table(self.params['collection'])
#             condition = relationship_table.c[self.params['pk_field_name']] \
#                 == expression.cast(self.obj.pk,self.params['type'])
#             self._queryset = QuerySet(backend = self.obj.backend,
#                                       table = foreign_table,
#                                       cls = self.params['class'],
#                                       joins = [(relationship_table,)],
#                                       condition = condition,
#                                       objects = self._objects,
#                                       *args,
#                                       **kwargs)
#         return self._queryset
# 
#     def append(self,obj):
#         with self.obj.backend.transaction(implicit = True):
# 
#             #if the object is not yet in a DB, we save it first.
# 
#             if obj.pk is None:
#                 self.obj.backend.save(obj)
# 
#             relationship_table = self.params['relationship_table']
#             condition = and_(relationship_table.c[self.params['related_pk_field_name']] == obj.pk,
#                              relationship_table.c[self.params['pk_field_name']] == self.obj.pk)
#             s = select([func.count(text('*'))]).where(condition)
#             result = self.obj.backend.connection.execute(s)
#             cnt = result.first()[0]
#             if cnt:
#                 return #the object is already inside
#             values = {
#                 self.params['pk_field_name'] : self.obj.pk,
#                 self.params['related_pk_field_name'] : obj.pk
#             }
#             insert = relationship_table.insert().values(**values)
#             self.obj.backend.connection.execute(insert)
#             self._queryset = None
# 
#     def extend(self,objects):
#         for obj in objects:
#             self.append(obj)
# 
#     def insert(self,i,obj):
#         raise NotImplementedError
# 
#     def delete(self):
#         relationship_table = self.params['relationship_table']
#         with self.obj.backend.transaction(implicit = True):
#             condition = relationship_table.c[self.params['pk_field_name']] == self.obj.pk
#             self.obj.backend.connection.execute(delete(relationship_table).where(condition))
# 
#     def remove(self,obj):
#         """
#         Remove an object from the relation
#         """
#         relationship_table = self.params['relationship_table']
#         with self.obj.backend.transaction(implicit = True):
#             condition = and_(relationship_table.c[self.params['related_pk_field_name']] == obj.pk,
#                              relationship_table.c[self.params['pk_field_name']] == self.obj.pk)
#             self.obj.backend.connection.execute(delete(relationship_table).where(condition))
#             self._queryset = None
# 
#     def pop(self,i = None):
#         queryset = self.get_queryset()
#         return queryset.pop(i)
# 
#     def __len__(self):
#         queryset = self.get_queryset()
#         return len(queryset)
# 
# Path: tests/helpers/movie_data.py
# class Movie(Document):
#     class Meta(Document.Meta):
# class Actor(Document):
# class Food(Document):
# class Director(Document):
# class Role(Document):
# def generate_test_data(request, backend, n):


# Path: tests/sql/test_many_to_many.py
from blitzdb.backends.sql.relations import ManyToManyProxy
from ..helpers.movie_data import Actor, Director, Document, Movie
    from blitzdb.fields import ManyToManyField




def test_basics(backend):

    backend.init_schema()
    backend.create_schema()

    francis_coppola = Director({'name' : 'Francis Coppola'})
    stanley_kubrick = Director({'name' : 'Stanley Kubrick'})

    robert_de_niro = Actor({'name' : 'Robert de Niro','movies' : []})