From ae3af76f1257f33cfaac192bc3d3b8afe780b939 Mon Sep 17 00:00:00 2001 From: Charles Leifer Date: Sat, 4 Mar 2017 21:21:32 -0600 Subject: [PATCH] Revert "Merge pull request #1203 from Necoro/closure" This reverts commit 54ca88c0dace0c2c9584870285012323ae6bd66e, reversing changes made to 113ef55e795999e5b423f04111287f36794ffe22. --- docs/peewee/playhouse.rst | 23 ++--------------------- playhouse/sqlite_ext.py | 38 ++++++++------------------------------ 2 files changed, 10 insertions(+), 51 deletions(-) diff --git a/docs/peewee/playhouse.rst b/docs/peewee/playhouse.rst index aab0ef604..b0fff57e0 100644 --- a/docs/peewee/playhouse.rst +++ b/docs/peewee/playhouse.rst @@ -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 `_ 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. @@ -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 @@ -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 @@ -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. diff --git a/playhouse/sqlite_ext.py b/playhouse/sqlite_ext.py index 8cc7910de..0ad0735a6 100644 --- a/playhouse/sqlite_ext.py +++ b/playhouse/sqlite_ext.py @@ -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: @@ -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() @@ -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