From 5542f47b61c6213e2ae12bb7c55dbf12c927f41a Mon Sep 17 00:00:00 2001
From: Kirill Zaitsev <kzaitsev@mirantis.com>
Date: Sat, 4 Apr 2015 01:57:12 +0300
Subject: [PATCH] Add package_count to Category objects

Partially implements blueprint enable-category-management
Change-Id: I8639586d6dad1b398d54ee6f4ac5755cb38ed8b0
---
 doc/source/specification/murano-repository.rst | 12 ++++++++----
 murano/api/v1/catalog.py                       |  1 -
 murano/db/catalog/api.py                       |  3 +++
 murano/db/models.py                            | 11 +++++++++++
 murano/tests/unit/api/v1/test_catalog.py       |  9 ++++++---
 5 files changed, 28 insertions(+), 8 deletions(-)

diff --git a/doc/source/specification/murano-repository.rst b/doc/source/specification/murano-repository.rst
index b5c338ad..cb12e3a6 100644
--- a/doc/source/specification/murano-repository.rst
+++ b/doc/source/specification/murano-repository.rst
@@ -441,13 +441,15 @@ List categories
                 "id": "0420045dce7445fabae7e5e61fff9e2f",
                 "updated": "2014-12-26T13:57:04",
                 "name": "Web",
-                "created": "2014-12-26T13:57:04"
+                "created": "2014-12-26T13:57:04",
+                "package_count": 1
             },
             {
                 "id": "3dd486b1e26f40ac8f35416b63f52042",
                 "updated": "2014-12-26T13:57:04",
-            "name": "Databases",
-            "created": "2014-12-26T13:57:04"
+                "name": "Databases",
+                "created": "2014-12-26T13:57:04",
+                "package_count": 0
             }]
         }
 
@@ -490,7 +492,8 @@ Get category details
             }
         ],
         "name": "Web",
-        "created": "2015-01-28T17:00:19"
+        "created": "2015-01-28T17:00:19",
+        "package_count": 1
     }
 
 +----------------+-----------------------------------------------------------+
@@ -541,6 +544,7 @@ Add new category
         "name": "category_name",
         "created": "2013-11-30T03:23:42Z",
         "updated": "2013-11-30T03:23:44Z",
+        "package_count": 0
     }
 
 
diff --git a/murano/api/v1/catalog.py b/murano/api/v1/catalog.py
index fdb359c3..89edde4f 100644
--- a/murano/api/v1/catalog.py
+++ b/murano/api/v1/catalog.py
@@ -265,7 +265,6 @@ class Controller(object):
     def delete(self, req, package_id):
         target = {'package_id': package_id}
         policy.check("delete_package", req.context, target)
-
         db_api.package_delete(package_id, req.context)
 
     def get_category(self, req, category_id):
diff --git a/murano/db/catalog/api.py b/murano/db/catalog/api.py
index 9bfab04c..82103d4a 100644
--- a/murano/db/catalog/api.py
+++ b/murano/db/catalog/api.py
@@ -416,6 +416,9 @@ def category_add(category_name):
 
     with session.begin():
         category.update({'name': category_name})
+        # NOTE(kzaitsev) update package_count, so we can safely access from
+        # outside the session
+        category.package_count = 0
         category.save(session)
 
     return category
diff --git a/murano/db/models.py b/murano/db/models.py
index 1adbc896..f38163e2 100644
--- a/murano/db/models.py
+++ b/murano/db/models.py
@@ -278,6 +278,17 @@ class Category(Base, TimestampMixin):
                    default=uuidutils.generate_uuid)
     name = sa.Column(sa.String(80), nullable=False, index=True, unique=True)
 
+    package_count = sa_orm.column_property(
+        sa.select([sa.func.count(package_to_category.c.package_id)]).
+        where(package_to_category.c.category_id == id).
+        correlate_except(package_to_category)
+    )
+
+    def to_dict(self):
+        d = super(Category, self).to_dict()
+        d['package_count'] = self.package_count
+        return d
+
 
 class Tag(Base, TimestampMixin):
     """Represents tags in the datastore."""
diff --git a/murano/tests/unit/api/v1/test_catalog.py b/murano/tests/unit/api/v1/test_catalog.py
index 71d2997a..05ff4973 100644
--- a/murano/tests/unit/api/v1/test_catalog.py
+++ b/murano/tests/unit/api/v1/test_catalog.py
@@ -148,9 +148,12 @@ Content-Type: application/json
         fake_now = timeutils.utcnow()
         timeutils.utcnow.override_time = fake_now
 
-        expected = {'name': 'new_category',
-                    'created': timeutils.isotime(fake_now)[:-1],
-                    'updated': timeutils.isotime(fake_now)[:-1]}
+        expected = {
+            'name': 'new_category',
+            'created': timeutils.isotime(fake_now)[:-1],
+            'updated': timeutils.isotime(fake_now)[:-1],
+            'package_count': 0,
+        }
 
         body = {'name': 'new_category'}
         req = self._post('/catalog/categories', json.dumps(body))