Skip to content

Commit

Permalink
Revert "Merge pull request #1203 from Necoro/closure"
Browse files Browse the repository at this point in the history
This reverts commit 54ca88c, reversing
changes made to 113ef55.
  • Loading branch information
coleifer committed Mar 5, 2017
1 parent 54ca88c commit ae3af76
Show file tree
Hide file tree
Showing 2 changed files with 10 additions and 51 deletions.
23 changes: 2 additions & 21 deletions docs/peewee/playhouse.rst
Expand Up @@ -716,7 +716,7 @@ sqlite_ext API notes
.. _sqlite_closure:
.. py:function:: ClosureTable(model_class[, foreign_key=None[, referencing_class=None, id_column=None]])
.. py:function:: ClosureTable(model_class[, foreign_key=None])
Factory function for creating a model class suitable for working with a `transitive closure <http://www.sqlite.org/cgi/src/artifact/636024302cde41b2bf0c542f81c40c624cfb7012>`_ table. Closure tables are :py:class:`VirtualModel` subclasses that work with the transitive closure SQLite extension. These special tables are designed to make it easy to efficiently query heirarchical data. The SQLite extension manages an AVL tree behind-the-scenes, transparently updating the tree when your table changes and making it easy to perform common queries on heirarchical data.
Expand All @@ -735,7 +735,7 @@ sqlite_ext API notes
$ gcc -g -fPIC -shared closure.c -o closure.so
3. Create a model for your hierarchical data. The only requirement here is that the model has an integer primary key and a self-referential foreign key. Any additional fields are fine.
3. Create a model for your heirarchical data. The only requirement here is that the model have an integer primary key and a self-referential foreign key. Any additional fields are fine.
.. code-block:: python
Expand All @@ -747,23 +747,6 @@ sqlite_ext API notes
# Generate a model for the closure virtual table.
CategoryClosure = ClosureTable(Category)
The self-referentiality can also be achieved via an intermediate table (for a many-to-many relation).
.. code-block:: python
class User(Model):
name = CharField()
class UserRelations(Model):
user = ForeignKeyField(User)
knows = ForeignKeyField(User, related_name='_known_by')
class Meta:
primary_key = CompositeKey('user', 'knows') # Alternatively, a unique index on both columns.
# Generate a model for the closure virtual table, specifying the UserRelations as the referencing table
UserClosure = ClosureTable(User, referencing_class=UserRelations, foreign_key=UserRelations.knows, id_column=UserRelations.user)
4. In your application code, make sure you load the extension when you instantiate your :py:class:`Database` object. This is done by passing the path to the shared library to the :py:meth:`~SqliteExtDatabase.load_extension` method.
.. code-block:: python
Expand All @@ -773,8 +756,6 @@ sqlite_ext API notes
:param model_class: The model class containing the nodes in the tree.
:param foreign_key: The self-referential parent-node field on the model class. If not provided, peewee will introspect the model to find a suitable key.
:param referencing_class: The intermediate table for a many-to-many relationship.
:param id_column: For a many-to-many relationship: the originating side of the relation.
:return: Returns a :py:class:`VirtualModel` for working with a closure table.
.. warning:: There are two caveats you should be aware of when using the ``transitive_closure`` extension. First, it requires that your *source model* have an integer primary key. Second, it is strongly recommended that you create an index on the self-referential foreign key.
Expand Down
38 changes: 8 additions & 30 deletions playhouse/sqlite_ext.py
Expand Up @@ -667,11 +667,8 @@ class Meta:
return getattr(cls, attr)


def ClosureTable(model_class, foreign_key=None, referencing_class=None, id_column=None):
def ClosureTable(model_class, foreign_key=None):
"""Model factory for the transitive closure extension."""
if referencing_class is None:
referencing_class = model_class

if foreign_key is None:
for field_obj in model_class._meta.rel.values():
if field_obj.rel_model is model_class:
Expand All @@ -682,14 +679,11 @@ def ClosureTable(model_class, foreign_key=None, referencing_class=None, id_colum

primary_key = model_class._meta.primary_key

if id_column is None:
id_column = primary_key

class BaseClosureTable(VirtualModel):
depth = VirtualIntegerField()
id = VirtualIntegerField()
idcolumn = VirtualCharField()
parentcolumn = VirtualCharField()
idcolumn = VirtualIntegerField()
parentcolumn = VirtualIntegerField()
root = VirtualIntegerField()
tablename = VirtualCharField()

Expand Down Expand Up @@ -724,33 +718,17 @@ def ancestors(cls, node, depth=None, include_node=False):

@classmethod
def siblings(cls, node, include_node=False):
if referencing_class is model_class:
# self-join
fk_value = node._data.get(foreign_key.name)
query = model_class.select().where(foreign_key == fk_value)
else:
# siblings as given in reference_class
siblings = (referencing_class
.select(id_column)
.join(cls, on=(foreign_key == cls.root))
.where((cls.id == node) & (cls.depth == 1)))

# the according models
query = (model_class
.select()
.where(primary_key << siblings)
.naive())

fk_value = node._data.get(foreign_key.name)
query = model_class.select().where(foreign_key == fk_value)
if not include_node:
query = query.where(primary_key != node)

return query

class Meta:
database = referencing_class._meta.database
database = model_class._meta.database
extension_options = {
'tablename': referencing_class._meta.db_table,
'idcolumn': id_column.db_column,
'tablename': model_class._meta.db_table,
'idcolumn': model_class._meta.primary_key.db_column,
'parentcolumn': foreign_key.db_column}
primary_key = False

Expand Down

0 comments on commit ae3af76

Please sign in to comment.