Repository: CartoDB/cartoframes
Pull request #1531 (2020-02-07 10:52:49)

Adapt Catalog to DO-Metadata API
Catalog using the DO Metadata API instead of DB queries.

**Do not merge**:

- So far it works only with carto-staging users.
- There is a `API_BASE_PATH` config value in the file `data/observatory/catalog/repository/repo_client.py`, that may not be the final API base path.


Patch:
diff --git a/.gitignore b/.gitignore
index 44917192..e6292e79 100644
--- a/.gitignore
+++ b/.gitignore
@@ -22,6 +22,7 @@ _build
 # Distribution / packaging
 .Python
 env/
+.venv/
 build/
 develop-eggs/
 dist/
@@ -50,7 +51,7 @@ SITEKEY.txt
 secret.json
 examples/scratch/*
 
-# JavaScript 
+# JavaScript
 node_modules
 
 # Tests
diff --git a/cartoframes/data/observatory/catalog/repository/category_repo.py b/cartoframes/data/observatory/catalog/repository/category_repo.py
index 3392f360..624f97a5 100644
--- a/cartoframes/data/observatory/catalog/repository/category_repo.py
+++ b/cartoframes/data/observatory/catalog/repository/category_repo.py
@@ -21,9 +21,6 @@ class CategoryRepository(EntityRepository):
         return Category
 
     def _get_rows(self, filters=None):
-        if filters is not None and COUNTRY_FILTER in filters.keys():
-            return self.client.get_categories_joined_datasets(filters)
-
         return self.client.get_categories(filters)
 
     def _map_row(self, row):
diff --git a/cartoframes/data/observatory/catalog/repository/constants.py b/cartoframes/data/observatory/catalog/repository/constants.py
index 72bdec46..3cd42d32 100644
--- a/cartoframes/data/observatory/catalog/repository/constants.py
+++ b/cartoframes/data/observatory/catalog/repository/constants.py
@@ -1,7 +1,7 @@
-CATEGORY_FILTER = 'category_id'
-COUNTRY_FILTER = 'country_id'
-DATASET_FILTER = 'dataset_id'
-GEOGRAPHY_FILTER = 'geography_id'
-PROVIDER_FILTER = 'provider_id'
-VARIABLE_FILTER = 'variable_id'
-VARIABLE_GROUP_FILTER = 'variable_group_id'
+CATEGORY_FILTER = 'category'
+COUNTRY_FILTER = 'country'
+DATASET_FILTER = 'dataset'
+GEOGRAPHY_FILTER = 'geography'
+PROVIDER_FILTER = 'provider'
+VARIABLE_FILTER = 'variable'
+VARIABLE_GROUP_FILTER = 'variable_group'
diff --git a/cartoframes/data/observatory/catalog/repository/country_repo.py b/cartoframes/data/observatory/catalog/repository/country_repo.py
index 293901eb..d4eb4f94 100644
--- a/cartoframes/data/observatory/catalog/repository/country_repo.py
+++ b/cartoframes/data/observatory/catalog/repository/country_repo.py
@@ -2,7 +2,7 @@ from .constants import CATEGORY_FILTER
 from .entity_repo import EntityRepository
 
 
-_COUNTRY_ID_FIELD = 'country_id'
+_COUNTRY_ID_FIELD = 'id'
 _ALLOWED_FILTERS = [CATEGORY_FILTER]
 
 
diff --git a/cartoframes/data/observatory/catalog/repository/dataset_repo.py b/cartoframes/data/observatory/catalog/repository/dataset_repo.py
index f4c0deb1..0776312a 100644
--- a/cartoframes/data/observatory/catalog/repository/dataset_repo.py
+++ b/cartoframes/data/observatory/catalog/repository/dataset_repo.py
@@ -1,11 +1,11 @@
-from .constants import CATEGORY_FILTER, COUNTRY_FILTER, GEOGRAPHY_FILTER, PROVIDER_FILTER, VARIABLE_FILTER
+from .constants import CATEGORY_FILTER, COUNTRY_FILTER, GEOGRAPHY_FILTER, PROVIDER_FILTER
+from ..subscriptions import get_subscription_ids
 from .entity_repo import EntityRepository
-from ..entity import CatalogList
 
 
 _DATASET_ID_FIELD = 'id'
 _DATASET_SLUG_FIELD = 'slug'
-_ALLOWED_FILTERS = [CATEGORY_FILTER, COUNTRY_FILTER, GEOGRAPHY_FILTER, PROVIDER_FILTER, VARIABLE_FILTER]
+_ALLOWED_FILTERS = [CATEGORY_FILTER, COUNTRY_FILTER, GEOGRAPHY_FILTER, PROVIDER_FILTER]
 
 
 def get_dataset_repo():
@@ -18,10 +18,16 @@ class DatasetRepository(EntityRepository):
         super(DatasetRepository, self).__init__(_DATASET_ID_FIELD, _ALLOWED_FILTERS, _DATASET_SLUG_FIELD)
 
     def get_all(self, filters=None, credentials=None):
-        self.client.set_user_credentials(credentials)
-        response = self._get_filtered_entities(filters)
-        self.client.set_user_credentials(None)
-        return response
+        # If credentials are provided, then we only want the user's subscriptions:
+        if credentials is not None:
+            ids = get_subscription_ids(credentials)
+            if len(ids) == 0:
+                return []
+            elif len(ids) > 0:
+                filters = filters or {}
+                filters['id'] = ids
+
+        return self._get_filtered_entities(filters)
 
     @classmethod
     def _get_entity_class(cls):
@@ -56,10 +62,5 @@ class DatasetRepository(EntityRepository):
             'available_in': self._normalize_field(row, 'available_in')
         }
 
-    def get_datasets_for_geographies(self, geographies):
-        rows = self.client.get_datasets_for_geographies(geographies)
-        normalized_data = [self._get_entity_class()(self._map_row(row)) for row in rows]
-        return CatalogList(normalized_data)
-
 
 _REPO = DatasetRepository()
diff --git a/cartoframes/data/observatory/catalog/repository/entity_repo.py b/cartoframes/data/observatory/catalog/repository/entity_repo.py
index 7293030e..a008b511 100644
--- a/cartoframes/data/observatory/catalog/repository/entity_repo.py
+++ b/cartoframes/data/observatory/catalog/repository/entity_repo.py
@@ -97,10 +97,7 @@ class EntityRepository(ABC):
 
     @classmethod
     def _normalize_field(cls, row, field):
-        if field in row:
-            return row[field]
-
-        return None
+        return row.get(field, None)
 
     @classmethod
     @abstractmethod
diff --git a/cartoframes/data/observatory/catalog/repository/geography_repo.py b/cartoframes/data/observatory/catalog/repository/geography_repo.py
index d48ccdf6..d7823153 100644
--- a/cartoframes/data/observatory/catalog/repository/geography_repo.py
+++ b/cartoframes/data/observatory/catalog/repository/geography_repo.py
@@ -1,17 +1,15 @@
-from cartoframes.auth import Credentials
+from pandas import DataFrame
+from geopandas import GeoDataFrame
 
+from .....utils.geom_utils import set_geometry
+from ..subscriptions import get_subscription_ids
 from .constants import COUNTRY_FILTER, CATEGORY_FILTER, PROVIDER_FILTER
 from .entity_repo import EntityRepository
 
-from .....io.carto import read_carto
-
-
 _GEOGRAPHY_ID_FIELD = 'id'
 _GEOGRAPHY_SLUG_FIELD = 'slug'
 _ALLOWED_FILTERS = [COUNTRY_FILTER, CATEGORY_FILTER, PROVIDER_FILTER]
 
-_DO_CREDENTIALS = Credentials('do-metadata', 'default_public')
-
 
 def get_geography_repo():
     return _REPO
@@ -23,10 +21,16 @@ class GeographyRepository(EntityRepository):
         super(GeographyRepository, self).__init__(_GEOGRAPHY_ID_FIELD, _ALLOWED_FILTERS, _GEOGRAPHY_SLUG_FIELD)
 
     def get_all(self, filters=None, credentials=None):
-        self.client.set_user_credentials(credentials)
-        response = self._get_filtered_entities(filters)
-        self.client.set_user_credentials(None)
-        return response
+        # If credentials are provided, then we only want the user's subscriptions:
+        if credentials is not None:
+            ids = get_subscription_ids(credentials)
+            if len(ids) == 0:
+                return []
+            elif len(ids) > 0:
+                filters = filters or {}
+                filters['id'] = ids
+
+        return self._get_filtered_entities(filters)
 
     @classmethod
     def _get_entity_class(cls):
@@ -34,9 +38,6 @@ class GeographyRepository(EntityRepository):
         return Geography
 
     def _get_rows(self, filters=None):
-        if filters is not None and (COUNTRY_FILTER in filters.keys() or CATEGORY_FILTER in filters.keys()):
-            return self.client.get_geographies_joined_datasets(filters)
-
         return self.client.get_geographies(filters)
 
     def _map_row(self, row):
@@ -59,8 +60,12 @@ class GeographyRepository(EntityRepository):
         }
 
     def get_geographies_gdf(self):
-        query = 'select id, geom_coverage as the_geom from geographies_public where geom_coverage is not null'
-        return read_carto(query, _DO_CREDENTIALS)
+        data = self.client.get_geographies({'get_geoms_coverage': True})
+        df = DataFrame(data)
+        gdf = GeoDataFrame(df, crs='epsg:4326')
+
+        set_geometry(gdf, col='geom_coverage', inplace=True)
+        return gdf
 
 
 _REPO = GeographyRepository()
diff --git a/cartoframes/data/observatory/catalog/repository/repo_client.py b/cartoframes/data/observatory/catalog/repository/repo_client.py
index 4a346ecc..77194926 100644
--- a/cartoframes/data/observatory/catalog/repository/repo_client.py
+++ b/cartoframes/data/observatory/catalog/repository/repo_client.py
@@ -1,6 +1,11 @@
-from ..subscriptions import get_subscription_ids
-from .....auth import Credentials
-from .....io.managers.context_manager import ContextManager
+import os
+import requests
+from urllib.parse import urlsplit, urlunsplit, SplitResult
+from .....auth import Credentials, get_default_credentials
+
+DEFAULT_USER = 'do-metadata'
+API_BASE_PATH = 'api/v4/do/dev'
+REQUEST_VERIFY_SSL = True
 
 
 class RepoClient:
@@ -9,92 +14,112 @@ class RepoClient:
 
     def __init__(self):
         self._user_credentials = None
-        self._do_credentials = Credentials('do-metadata', 'default_public')
-        self._context_manager = ContextManager(self._do_credentials)
 
     def set_user_credentials(self, credentials):
         self._user_credentials = credentials
 
     def get_countries(self, filters=None):
-        query = 'SELECT DISTINCT t.country_id AS id FROM datasets_public t'
-        return self._run_query(query, filters)
+        filters = filters or {}
+        api_path = 'metadata/countries'
+        id_filter = filters.get('id')
+        if id_filter:
+            return self._get_entities_by_id(api_path, id_filter)
+        else:
+            return self._make_request(api_path, filters)
 
     def get_categories(self, filters=None):
-        query = 'SELECT t.* FROM categories_public t'
-        return self._run_query(query, filters)
-
-    def get_categories_joined_datasets(self, filters=None):
-        query = 'SELECT DISTINCT c.* FROM categories_public c, datasets_public t'
-        return self._run_query(query, filters, ['c.id = t.category_id'])
+        filters = filters or {}
+        api_path = 'metadata/categories'
+        id_filter = filters.get('id')
+        if id_filter:
+            return self._get_entities_by_id(api_path, id_filter)
+        else:
+            return self._make_request(api_path, filters)
 
     def get_providers(self, filters=None):
-        query = 'SELECT t.* FROM providers_public t'
-        return self._run_query(query, filters)
+        filters = filters or {}
+        api_path = 'metadata/providers'
+        provider_id = filters.get('id')
+        if provider_id:
+            return self._get_entities_by_id(api_path, provider_id)
+        else:
+            return self._make_request(api_path, filters)
 
     def get_variables(self, filters=None):
-        query = 'SELECT t.* FROM variables_public t'
-        return self._run_query(query, filters)
+        filters = filters or {}
+        api_path = 'metadata/variables'
+        id_filter = filters.get('id') or filters.get('slug')
+        if id_filter:
+            return self._get_entities_by_id(api_path, id_filter)
+        else:
+            dataset_id = filters.get('dataset')  # Mandatory filter
+            api_path = 'metadata/datasets/{}/variables'.format(dataset_id)
+            return self._make_request(api_path, filters)
 
     def get_variables_groups(self, filters=None):
-        query = 'SELECT t.* FROM variables_groups_public t'
-        return self._run_query(query, filters)
+        filters = filters or {}
+        api_path = 'metadata/variables_groups'
+        id_filter = filters.get('id') or filters.get('slug')
+        if id_filter:
+            api_path = 'metadata/variables_groups'
+            return self._get_entities_by_id(api_path, id_filter)
+        else:
+            dataset_id = filters.get('dataset')  # Mandatory filter
+            api_path = 'metadata/datasets/{}/variables_groups'.format(dataset_id)
+            return self._make_request(api_path, filters)
 
     def get_geographies(self, filters=None):
-        query = 'SELECT t.* FROM geographies_public t'
-
-        extra_condition = []
-        if self._user_credentials is not None:
-            ids = get_subscription_ids(self._user_credentials)
-            if len(ids) == 0:
-                return []
-            elif len(ids) > 0:
-                extra_condition.append('t.id IN ({})'.format(ids))
-
-        return self._run_query(query, filters, extra_condition)
-
-    def get_geographies_joined_datasets(self, filters=None):
-        query = 'SELECT DISTINCT g.* FROM geographies_public g, datasets_public t'
-        return self._run_query(query, filters, ['g.id = t.geography_id'])
+        filters = filters or {}
+        api_path = 'metadata/geographies'
+        id_filter = filters.get('id') or filters.get('slug')
+        if id_filter:
+            return self._get_entities_by_id(api_path, id_filter)
+        else:
+            return self._make_request(api_path, filters)
 
     def get_datasets(self, filters=None):
-        query = 'SELECT t.* FROM datasets_public t'
-
-        extra_condition = []
-        if self._user_credentials is not None:
-            ids = get_subscription_ids(self._user_credentials)
-            if len(ids) == 0:
-                return []
-            elif len(ids) > 0:
-                extra_condition.append('t.id IN ({})'.format(ids))
-
-        return self._run_query(query, filters, extra_condition)
-
-    def _run_query(self, query, filters, extra_conditions=None):
-        conditions = self._compute_conditions(filters, extra_conditions)
-
-        if len(conditions) > 0:
-            where_clause = ' AND '.join(conditions)
-            query += ' WHERE {}'.format(where_clause)
-
-        return self._context_manager.execute_query(query).get('rows')
-
-    def _compute_conditions(self, filters, extra_conditions):
-        conditions = extra_conditions or []
-
-        if filters is not None and len(filters) > 0:
-            conditions.extend([self._generate_condition(key, value) for key, value in sorted(filters.items())])
-
-        return conditions
-
-    @staticmethod
-    def _generate_condition(key, value):
-        if isinstance(value, list):
-            value_list = ','.join(["'" + v + "'" for v in value])
-            return "t.{} IN ({})".format(key, value_list)
-
-        return "t.{} = '{}'".format(key, value)
-
-    def __new__(cls):
-        if not RepoClient.__instance:
-            RepoClient.__instance = object.__new__(cls)
-        return RepoClient.__instance
+        filters = filters or {}
+        api_path = 'metadata/datasets'
+        id_filter = filters.get('id') or filters.get('slug')
+        if id_filter:
+            return self._get_entities_by_id(api_path, id_filter)
+        else:
+            return self._make_request(api_path, filters)
+
+    def _get_entities_by_id(self, api_base_path, ids):
+        # ids can be an ID or a list of them
+        entities = []
+        entity_ids = ids if isinstance(ids, list) else [ids]
+
+        for entity_id in entity_ids:
+            api_path = os.path.join(api_base_path, entity_id)
+            entity = self._make_request(api_path)
+            if entity is not None:
+                entities.append(entity)
+
+        return entities
+
+    def _make_request(self, api_path, filters=None):
+        request_url = self._build_url(api_path, filters)
+        req = requests.get(request_url, verify=REQUEST_VERIFY_SSL)
+        return req.json()
+
+    def _build_url(self, api_path, filters):
+        credentials = self._get_user_credentials()
+        filters = filters or {}
+
+        url_params = ['api_key={}'.format(credentials.api_key)]
+        for key, value in filters.items():
+            url_params.append('{}={}'.format(key, value))
+
+        url = urlsplit(credentials.base_url)
+
+        path = os.path.join(url.path, API_BASE_PATH, api_path)
+        query = '&'.join(url_params)
+
+        return urlunsplit(SplitResult(
+            scheme=url.scheme, netloc=url.netloc, path=path, query=query, fragment=url.fragment
+        ))
+
+    def _get_user_credentials(self):
+        return self._user_credentials or get_default_credentials() or Credentials(DEFAULT_USER)
diff --git a/cartoframes/data/observatory/catalog/subscriptions.py b/cartoframes/data/observatory/catalog/subscriptions.py
index 75dc8b60..c01f6023 100644
--- a/cartoframes/data/observatory/catalog/subscriptions.py
+++ b/cartoframes/data/observatory/catalog/subscriptions.py
@@ -44,7 +44,7 @@ class Subscriptions:
 def get_subscription_ids(credentials):
     subscriptions = fetch_subscriptions(credentials)
     subscriptions_ids = list(map(lambda pd: pd.id, subscriptions))
-    return ','.join(["'" + id + "'" for id in subscriptions_ids])
+    return subscriptions_ids
 
 
 def fetch_subscriptions(credentials):
diff --git a/cartoframes/viz/styles/cluster_size_style.py b/cartoframes/viz/styles/cluster_size_style.py
index a4d0902b..1ab78230 100644
--- a/cartoframes/viz/styles/cluster_size_style.py
+++ b/cartoframes/viz/styles/cluster_size_style.py
@@ -34,8 +34,6 @@ def cluster_size_style(value, operation='count', resolution=32, color=None, opac
 
     data = {
         'point': {
-            '@size_value': 'ramp(linear({0}, viewportMIN({0}), viewportMAX({0})), [{1}])'.format(
-                cluster_operation, breakpoints),
             'width': 'ramp(linear({0}, viewportMIN({0}), viewportMAX({0})), [{1}])'.format(
                 cluster_operation, breakpoints),
             'color': 'opacity({0}, {1})'.format(
diff --git a/examples/data_services/isodistances.ipynb b/examples/data_services/isodistances.ipynb
index 60cb8299..33b836f9 100644
--- a/examples/data_services/isodistances.ipynb
+++ b/examples/data_services/isodistances.ipynb
@@ -2012,10 +2012,10 @@
     }
    ],
    "source": [
-    "from cartoframes.viz import Map, Layer, basic_style\n",
+    "from cartoframes.viz import Map, Layer\n",
     "\n",
     "Map([\n",
-    "    Layer(isodistances_gdf, basic_style(color='green', opacity='0.3')),\n",
+    "    Layer(isodistances_gdf, 'color: opacity(green, 0.3)'),\n",
     "    Layer(gdf, 'width: 3')\n",
     "])"
    ]
@@ -2037,7 +2037,7 @@
    "name": "python",
    "nbconvert_exporter": "python",
    "pygments_lexer": "ipython3",
-   "version": "3.7.4"
+   "version": "3.6.7"
   }
  },
  "nbformat": 4,
diff --git a/examples/styles/cluster_size_style.ipynb b/examples/styles/cluster_size_style.ipynb
index 749af070..b51ab2ee 100644
--- a/examples/styles/cluster_size_style.ipynb
+++ b/examples/styles/cluster_size_style.ipynb
@@ -922,7 +922,7 @@
        "    const camera = null;\n",
        "    const has_legends = 'true' === 'true';\n",
        "    const is_static = 'None' === 'true';\n",
-       "    const layers = [{&quot;credentials&quot;: {&quot;api_key&quot;: &quot;default_public&quot;, &quot;base_url&quot;: &quot;https://cartoframes.carto.com&quot;, &quot;username&quot;: &quot;cartoframes&quot;}, &quot;data&quot;: &quot;SELECT * FROM \\&quot;cartoframes\\&quot;.\\&quot;vancouver_trees\\&quot;&quot;, &quot;has_legend_list&quot;: true, &quot;interactivity&quot;: [{&quot;attrs&quot;: {&quot;name&quot;: &quot;v40e601&quot;, &quot;title&quot;: &quot;clusterCount()&quot;}, &quot;event&quot;: &quot;hover&quot;}], &quot;legends&quot;: [{&quot;description&quot;: &quot;&quot;, &quot;dynamic&quot;: true, &quot;footer&quot;: &quot;&quot;, &quot;prop&quot;: &quot;width&quot;, &quot;title&quot;: &quot;diameter&quot;, &quot;type&quot;: &quot;size-continuous&quot;, &quot;variable&quot;: &quot;size_value&quot;}], &quot;options&quot;: {}, &quot;type&quot;: &quot;Query&quot;, &quot;viz&quot;: &quot;@v40e601: clusterCount()\\ncolor: opacity(#FFB927, 0.8)\\nwidth: ramp(linear(clusterCount(), viewportMIN(clusterCount()), viewportMAX(clusterCount())), [4.0, 16.0, 32])\\nstrokeWidth: ramp(linear(zoom(),0,18),[0,1])\\nstrokeColor: opacity(#222,ramp(linear(zoom(),0,18),[0,0.6]))\\n@size_value: ramp(linear(clusterCount(), viewportMIN(clusterCount()), viewportMAX(clusterCount())), [4.0, 16.0, 32])\\nfilter: 1\\nresolution: 32\\n&quot;, &quot;widgets&quot;: []}];\n",
+       "    const layers = [{&quot;credentials&quot;: {&quot;api_key&quot;: &quot;default_public&quot;, &quot;base_url&quot;: &quot;https://cartoframes.carto.com&quot;, &quot;username&quot;: &quot;cartoframes&quot;}, &quot;data&quot;: &quot;SELECT * FROM \\&quot;cartoframes\\&quot;.\\&quot;vancouver_trees\\&quot;&quot;, &quot;has_legend_list&quot;: true, &quot;interactivity&quot;: [{&quot;attrs&quot;: {&quot;name&quot;: &quot;v40e601&quot;, &quot;title&quot;: &quot;clusterCount()&quot;}, &quot;event&quot;: &quot;hover&quot;}], &quot;legends&quot;: [{&quot;description&quot;: &quot;&quot;, &quot;dynamic&quot;: true, &quot;footer&quot;: &quot;&quot;, &quot;prop&quot;: &quot;width&quot;, &quot;title&quot;: &quot;diameter&quot;, &quot;type&quot;: &quot;size-continuous&quot;, &quot;variable&quot;: &quot;size_value&quot;}], &quot;options&quot;: {}, &quot;type&quot;: &quot;Query&quot;, &quot;viz&quot;: &quot;@v40e601: clusterCount()\\ncolor: opacity(#FFB927, 0.8)\\nwidth: ramp(linear(clusterCount(), viewportMIN(clusterCount()), viewportMAX(clusterCount())), [4.0, 16.0, 32])\\nstrokeWidth: ramp(linear(zoom(),0,18),[0,1])\\nstrokeColor: opacity(#222,ramp(linear(zoom(),0,18),[0,0.6]))\\nfilter: 1\\nresolution: 32\\n&quot;, &quot;widgets&quot;: []}];\n",
        "    const mapboxtoken = '';\n",
        "    const show_info = 'None' === 'true';\n",
        "\n",
@@ -945,7 +945,7 @@
        "</iframe>"
       ],
       "text/plain": [
-       "<cartoframes.viz.layer.Layer at 0x11937d790>"
+       "<cartoframes.viz.layer.Layer at 0x110b525d0>"
       ]
      },
      "execution_count": 2,
@@ -1861,7 +1861,7 @@
        "    const camera = null;\n",
        "    const has_legends = 'true' === 'true';\n",
        "    const is_static = 'None' === 'true';\n",
-       "    const layers = [{&quot;credentials&quot;: {&quot;api_key&quot;: &quot;default_public&quot;, &quot;base_url&quot;: &quot;https://cartoframes.carto.com&quot;, &quot;username&quot;: &quot;cartoframes&quot;}, &quot;data&quot;: &quot;SELECT * FROM \\&quot;cartoframes\\&quot;.\\&quot;vancouver_trees\\&quot;&quot;, &quot;has_legend_list&quot;: true, &quot;interactivity&quot;: [{&quot;attrs&quot;: {&quot;name&quot;: &quot;v84907f&quot;, &quot;title&quot;: &quot;clusterSum($diameter)&quot;}, &quot;event&quot;: &quot;hover&quot;}], &quot;legends&quot;: [{&quot;description&quot;: &quot;&quot;, &quot;dynamic&quot;: true, &quot;footer&quot;: &quot;&quot;, &quot;prop&quot;: &quot;width&quot;, &quot;title&quot;: &quot;diameter&quot;, &quot;type&quot;: &quot;size-continuous&quot;, &quot;variable&quot;: &quot;size_value&quot;}], &quot;options&quot;: {}, &quot;type&quot;: &quot;Query&quot;, &quot;viz&quot;: &quot;@v84907f: clusterSum($diameter)\\ncolor: opacity(#FFB927, 0.8)\\nwidth: ramp(linear(clusterSum($diameter), viewportMIN(clusterSum($diameter)), viewportMAX(clusterSum($diameter))), [8.0, 32.0, 64])\\nstrokeWidth: ramp(linear(zoom(),0,18),[0,1])\\nstrokeColor: opacity(#222,ramp(linear(zoom(),0,18),[0,0.6]))\\n@size_value: ramp(linear(clusterSum($diameter), viewportMIN(clusterSum($diameter)), viewportMAX(clusterSum($diameter))), [8.0, 32.0, 64])\\nfilter: 1\\nresolution: 64\\n&quot;, &quot;widgets&quot;: []}];\n",
+       "    const layers = [{&quot;credentials&quot;: {&quot;api_key&quot;: &quot;default_public&quot;, &quot;base_url&quot;: &quot;https://cartoframes.carto.com&quot;, &quot;username&quot;: &quot;cartoframes&quot;}, &quot;data&quot;: &quot;SELECT * FROM \\&quot;cartoframes\\&quot;.\\&quot;vancouver_trees\\&quot;&quot;, &quot;has_legend_list&quot;: true, &quot;interactivity&quot;: [{&quot;attrs&quot;: {&quot;name&quot;: &quot;v84907f&quot;, &quot;title&quot;: &quot;clusterSum($diameter)&quot;}, &quot;event&quot;: &quot;hover&quot;}], &quot;legends&quot;: [{&quot;description&quot;: &quot;&quot;, &quot;dynamic&quot;: true, &quot;footer&quot;: &quot;&quot;, &quot;prop&quot;: &quot;width&quot;, &quot;title&quot;: &quot;diameter&quot;, &quot;type&quot;: &quot;size-continuous&quot;, &quot;variable&quot;: &quot;size_value&quot;}], &quot;options&quot;: {}, &quot;type&quot;: &quot;Query&quot;, &quot;viz&quot;: &quot;@v84907f: clusterSum($diameter)\\ncolor: opacity(#FFB927, 0.8)\\nwidth: ramp(linear(clusterSum($diameter), viewportMIN(clusterSum($diameter)), viewportMAX(clusterSum($diameter))), [8.0, 32.0, 64])\\nstrokeWidth: ramp(linear(zoom(),0,18),[0,1])\\nstrokeColor: opacity(#222,ramp(linear(zoom(),0,18),[0,0.6]))\\nfilter: 1\\nresolution: 64\\n&quot;, &quot;widgets&quot;: []}];\n",
        "    const mapboxtoken = '';\n",
        "    const show_info = 'None' === 'true';\n",
        "\n",
@@ -1884,7 +1884,7 @@
        "</iframe>"
       ],
       "text/plain": [
-       "<cartoframes.viz.layer.Layer at 0x119550890>"
+       "<cartoframes.viz.layer.Layer at 0x110cd1050>"
       ]
      },
      "execution_count": 3,


Test patch:
diff --git a/tests/unit/data/observatory/catalog/mocks.py b/tests/unit/data/observatory/catalog/mocks.py
index e561086d..385f0d6c 100644
--- a/tests/unit/data/observatory/catalog/mocks.py
+++ b/tests/unit/data/observatory/catalog/mocks.py
@@ -1,3 +1,7 @@
+from urllib.parse import urlsplit, parse_qsl
+from .examples import db_dataset1, db_dataset2
+
+
 class BigQueryClientMock(object):
     def __init__(self, exception=None):
         self.exception = exception
@@ -16,3 +20,32 @@ class BigQueryClientMock(object):
 
     def get_table_column_names(self, _1, _2, _3):
         return True
+
+
+class MockReponse:
+
+    def __init__(self, json_data=None):
+        self.json_data = json_data
+
+    def json(self):
+        return self.json_data
+
+
+def mocked_do_api_requests_get_datasets(request_url, *args, **kwargs):
+    # Just returns original filters dict
+    url = urlsplit(request_url)
+    orig_filters = dict(parse_qsl(url.query))
+
+    if url.path.endswith('/metadata/datasets'):
+        # Case for test filters:
+        return MockReponse(json_data=orig_filters)
+    else:
+        # Testing requests by id/slug
+        # The last part of the url path should be the dataset_id
+        dataset_id = url.path.split('/')[-1]
+        if dataset_id in [db_dataset1['id'], db_dataset1['slug']]:
+            return MockReponse(json_data=db_dataset1)
+        elif dataset_id in [db_dataset2['id'], db_dataset2['slug']]:
+            return MockReponse(json_data=db_dataset2)
+        else:
+            return MockReponse()
diff --git a/tests/unit/data/observatory/catalog/repository/test_category_repo.py b/tests/unit/data/observatory/catalog/repository/test_category_repo.py
index 12502688..99e22d4c 100644
--- a/tests/unit/data/observatory/catalog/repository/test_category_repo.py
+++ b/tests/unit/data/observatory/catalog/repository/test_category_repo.py
@@ -7,6 +7,10 @@ from cartoframes.data.observatory.catalog.category import Category
 from cartoframes.data.observatory.catalog.entity import CatalogList
 from cartoframes.data.observatory.catalog.repository.category_repo import CategoryRepository
 from cartoframes.data.observatory.catalog.repository.repo_client import RepoClient
+from cartoframes.data.observatory.catalog.repository.constants import (
+    COUNTRY_FILTER, DATASET_FILTER, GEOGRAPHY_FILTER, PROVIDER_FILTER, VARIABLE_FILTER,
+    VARIABLE_GROUP_FILTER
+)
 from ..examples import test_category1, test_categories, db_category1, db_category2
 
 
@@ -39,18 +43,18 @@ class TestCategoryRepo(object):
         mocked_repo.assert_called_once_with(None)
         assert categories is None
 
-    @patch.object(RepoClient, 'get_categories_joined_datasets')
+    @patch.object(RepoClient, 'get_categories')
     def test_get_all_only_uses_allowed_filters(self, mocked_repo):
         # Given
         mocked_repo.return_value = [db_category1, db_category2]
         repo = CategoryRepository()
         filters = {
-            'country_id': 'usa',
-            'dataset_id': 'carto-do.project.census2011',
-            'variable_id': 'population',
-            'geography_id': 'census-geo',
-            'variable_group_id': 'var-group',
-            'provider_id': 'open_data',
+            COUNTRY_FILTER: 'usa',
+            DATASET_FILTER: 'carto-do.project.census2011',
+            VARIABLE_FILTER: 'population',
+            GEOGRAPHY_FILTER: 'census-geo',
+            VARIABLE_GROUP_FILTER: 'var-group',
+            PROVIDER_FILTER: 'open_data',
             'fake_field_id': 'fake_value'
         }
 
@@ -59,7 +63,7 @@ class TestCategoryRepo(object):
 
         # Then
         mocked_repo.assert_called_once_with({
-            'country_id': 'usa'
+            COUNTRY_FILTER: 'usa'
         })
         assert categories == test_categories
 
@@ -102,7 +106,7 @@ class TestCategoryRepo(object):
         assert isinstance(categories, CatalogList)
         assert categories == test_categories
 
-    @patch.object(RepoClient, '_run_query')
+    @patch.object(RepoClient, 'get_categories')
     def test_get_by_country(self, mocked_repo):
         # Given
         mocked_repo.return_value = [db_category1, db_category2]
@@ -110,11 +114,10 @@ class TestCategoryRepo(object):
         repo = CategoryRepository()
 
         # When
-        categories = repo.get_all({'country_id': country_code})
+        categories = repo.get_all({COUNTRY_FILTER: country_code})
 
         # Then
-        query = 'SELECT DISTINCT c.* FROM categories_public c, datasets_public t'
-        mocked_repo.assert_called_once_with(query, {'country_id': country_code}, ['c.id = t.category_id'])
+        mocked_repo.assert_called_once_with({COUNTRY_FILTER: country_code})
         assert isinstance(categories, CatalogList)
         assert categories == test_categories
 
diff --git a/tests/unit/data/observatory/catalog/repository/test_country_repo.py b/tests/unit/data/observatory/catalog/repository/test_country_repo.py
index f2b60680..baf99d80 100644
--- a/tests/unit/data/observatory/catalog/repository/test_country_repo.py
+++ b/tests/unit/data/observatory/catalog/repository/test_country_repo.py
@@ -7,6 +7,10 @@ from cartoframes.data.observatory.catalog.entity import CatalogList
 from cartoframes.data.observatory.catalog.country import Country
 from cartoframes.data.observatory.catalog.repository.country_repo import CountryRepository
 from cartoframes.data.observatory.catalog.repository.repo_client import RepoClient
+from cartoframes.data.observatory.catalog.repository.constants import (
+    CATEGORY_FILTER, DATASET_FILTER, GEOGRAPHY_FILTER, PROVIDER_FILTER, VARIABLE_FILTER,
+    VARIABLE_GROUP_FILTER
+)
 from ..examples import test_countries, test_country1, db_country1, db_country2
 
 
@@ -44,12 +48,12 @@ class TestCountryRepo(object):
         mocked_repo.return_value = [db_country1, db_country2]
         repo = CountryRepository()
         filters = {
-            'dataset_id': 'carto-do.project.census2011',
-            'category_id': 'demographics',
-            'variable_id': 'population',
-            'geography_id': 'census-geo',
-            'variable_group_id': 'var-group',
-            'provider_id': 'open_data',
+            DATASET_FILTER: 'carto-do.project.census2011',
+            CATEGORY_FILTER: 'demographics',
+            VARIABLE_FILTER: 'population',
+            GEOGRAPHY_FILTER: 'census-geo',
+            VARIABLE_GROUP_FILTER: 'var-group',
+            PROVIDER_FILTER: 'open_data',
             'fake_field_id': 'fake_value'
         }
 
@@ -58,7 +62,7 @@ class TestCountryRepo(object):
 
         # Then
         mocked_repo.assert_called_once_with({
-            'category_id': 'demographics'
+            CATEGORY_FILTER: 'demographics'
         })
         assert countries == test_countries
 
@@ -73,7 +77,7 @@ class TestCountryRepo(object):
         country = repo.get_by_id(requested_iso_code)
 
         # Then
-        mocked_repo.assert_called_once_with({'country_id': requested_iso_code})
+        mocked_repo.assert_called_once_with({'id': requested_iso_code})
         assert isinstance(country, Country)
         assert country == test_country1
 
@@ -98,7 +102,7 @@ class TestCountryRepo(object):
         countries = repo.get_by_id_list([db_country1['id'], db_country2['id']])
 
         # Then
-        mocked_repo.assert_called_once_with({'country_id': [db_country1['id'], db_country2['id']]})
+        mocked_repo.assert_called_once_with({'id': [db_country1['id'], db_country2['id']]})
         assert isinstance(countries, CatalogList)
         assert countries == test_countries
 
diff --git a/tests/unit/data/observatory/catalog/repository/test_dataset_repo.py b/tests/unit/data/observatory/catalog/repository/test_dataset_repo.py
index a8487081..8875e496 100644
--- a/tests/unit/data/observatory/catalog/repository/test_dataset_repo.py
+++ b/tests/unit/data/observatory/catalog/repository/test_dataset_repo.py
@@ -1,6 +1,6 @@
 import pytest
 
-from unittest.mock import patch, call
+from unittest.mock import patch
 
 from cartoframes.auth import Credentials
 from cartoframes.exceptions import CatalogError
@@ -8,6 +8,10 @@ from cartoframes.data.observatory.catalog.entity import CatalogList
 from cartoframes.data.observatory.catalog.dataset import Dataset
 from cartoframes.data.observatory.catalog.repository.dataset_repo import DatasetRepository
 from cartoframes.data.observatory.catalog.repository.repo_client import RepoClient
+from cartoframes.data.observatory.catalog.repository.constants import (
+    CATEGORY_FILTER, COUNTRY_FILTER, GEOGRAPHY_FILTER, PROVIDER_FILTER, VARIABLE_FILTER,
+    VARIABLE_GROUP_FILTER
+)
 from ..examples import test_dataset1, test_datasets, db_dataset1, db_dataset2
 
 
@@ -28,9 +32,10 @@ class TestDatasetRepo(object):
         assert datasets == test_datasets
 
     @patch.object(RepoClient, 'get_datasets')
-    @patch.object(RepoClient, 'set_user_credentials')
-    def test_get_all_credentials(self, mocked_set_user_credentials, mocked_get_datasets):
+    @patch('cartoframes.data.observatory.catalog.repository.dataset_repo.get_subscription_ids')
+    def test_get_all_credentials(self, mocked_get_subscription_ids, mocked_get_datasets):
         # Given
+        mocked_get_subscription_ids.return_value = [db_dataset1['id'], db_dataset2['id']]
         mocked_get_datasets.return_value = [db_dataset1, db_dataset2]
         credentials = Credentials('user', '1234')
         repo = DatasetRepository()
@@ -39,8 +44,7 @@ class TestDatasetRepo(object):
         datasets = repo.get_all(credentials=credentials)
 
         # Then
-        mocked_set_user_credentials.assert_has_calls([call(credentials), call(None)])
-        mocked_get_datasets.assert_called_once_with(None)
+        mocked_get_datasets.assert_called_once_with({'id': [db_dataset1['id'], db_dataset2['id']]})
         assert isinstance(datasets, CatalogList)
         assert datasets == test_datasets
 
@@ -63,12 +67,12 @@ class TestDatasetRepo(object):
         mocked_repo.return_value = [db_dataset1, db_dataset2]
         repo = DatasetRepository()
         filters = {
-            'country_id': 'usa',
-            'category_id': 'demographics',
-            'variable_id': 'population',
-            'geography_id': 'census-geo',
-            'variable_group_id': 'var-group',
-            'provider_id': 'open_data',
+            COUNTRY_FILTER: 'usa',
+            CATEGORY_FILTER: 'demographics',
+            VARIABLE_FILTER: 'population',
+            GEOGRAPHY_FILTER: 'census-geo',
+            VARIABLE_GROUP_FILTER: 'var-group',
+            PROVIDER_FILTER: 'open_data',
             'fake_field_id': 'fake_value'
         }
 
@@ -77,11 +81,11 @@ class TestDatasetRepo(object):
 
         # Then
         mocked_repo.assert_called_once_with({
-            'country_id': 'usa',
-            'category_id': 'demographics',
-            'variable_id': 'population',
-            'geography_id': 'census-geo',
-            'provider_id': 'open_data'
+            COUNTRY_FILTER: 'usa',
+            CATEGORY_FILTER: 'demographics',
+            # VARIABLE_FILTER: 'population',
+            GEOGRAPHY_FILTER: 'census-geo',
+            PROVIDER_FILTER: 'open_data'
         })
         assert datasets == test_datasets
 
diff --git a/tests/unit/data/observatory/catalog/repository/test_geography_repo.py b/tests/unit/data/observatory/catalog/repository/test_geography_repo.py
index 6c912913..4570351f 100644
--- a/tests/unit/data/observatory/catalog/repository/test_geography_repo.py
+++ b/tests/unit/data/observatory/catalog/repository/test_geography_repo.py
@@ -1,6 +1,6 @@
 import pytest
 
-from unittest.mock import patch, call
+from unittest.mock import patch
 
 from cartoframes.auth import Credentials
 from cartoframes.exceptions import CatalogError
@@ -8,6 +8,10 @@ from cartoframes.data.observatory.catalog.entity import CatalogList
 from cartoframes.data.observatory.catalog.geography import Geography
 from cartoframes.data.observatory.catalog.repository.geography_repo import GeographyRepository
 from cartoframes.data.observatory.catalog.repository.repo_client import RepoClient
+from cartoframes.data.observatory.catalog.repository.constants import (
+    CATEGORY_FILTER, COUNTRY_FILTER, DATASET_FILTER, GEOGRAPHY_FILTER, PROVIDER_FILTER, VARIABLE_FILTER,
+    VARIABLE_GROUP_FILTER
+)
 from ..examples import test_geography1, test_geographies, db_geography1, db_geography2
 
 
@@ -28,9 +32,10 @@ class TestGeographyRepo(object):
         assert geographies == test_geographies
 
     @patch.object(RepoClient, 'get_geographies')
-    @patch.object(RepoClient, 'set_user_credentials')
-    def test_get_all_credentials(self, mocked_set_user_credentials, mocked_get_geographies):
+    @patch('cartoframes.data.observatory.catalog.repository.geography_repo.get_subscription_ids')
+    def test_get_all_credentials(self, mocked_get_subscription_ids, mocked_get_geographies):
         # Given
+        mocked_get_subscription_ids.return_value = [db_geography1['id'], db_geography2['id']]
         mocked_get_geographies.return_value = [db_geography1, db_geography2]
         credentials = Credentials('user', '1234')
         repo = GeographyRepository()
@@ -39,8 +44,7 @@ class TestGeographyRepo(object):
         geographies = repo.get_all(credentials=credentials)
 
         # Then
-        mocked_set_user_credentials.assert_has_calls([call(credentials), call(None)])
-        mocked_get_geographies.assert_called_once_with(None)
+        mocked_get_geographies.assert_called_once_with({'id': [db_geography1['id'], db_geography2['id']]})
         assert isinstance(geographies, CatalogList)
         assert geographies == test_geographies
 
@@ -57,19 +61,19 @@ class TestGeographyRepo(object):
         mocked_repo.assert_called_once_with(None)
         assert geographies is None
 
-    @patch.object(RepoClient, 'get_geographies_joined_datasets')
+    @patch.object(RepoClient, 'get_geographies')
     def test_get_all_only_uses_allowed_filters(self, mocked_repo):
         # Given
         mocked_repo.return_value = [db_geography1, db_geography2]
         repo = GeographyRepository()
         filters = {
-            'country_id': 'usa',
-            'dataset_id': 'carto-do.project.census2011',
-            'category_id': 'demographics',
-            'variable_id': 'population',
-            'geography_id': 'census-geo',
-            'variable_group_id': 'var-group',
-            'provider_id': 'open_data',
+            COUNTRY_FILTER: 'usa',
+            DATASET_FILTER: 'carto-do.project.census2011',
+            CATEGORY_FILTER: 'demographics',
+            VARIABLE_FILTER: 'population',
+            GEOGRAPHY_FILTER: 'census-geo',
+            VARIABLE_GROUP_FILTER: 'var-group',
+            PROVIDER_FILTER: 'open_data',
             'fake_field_id': 'fake_value'
         }
 
@@ -78,9 +82,9 @@ class TestGeographyRepo(object):
 
         # Then
         mocked_repo.assert_called_once_with({
-            'country_id': 'usa',
-            'category_id': 'demographics',
-            'provider_id': 'open_data'
+            COUNTRY_FILTER: 'usa',
+            CATEGORY_FILTER: 'demographics',
+            PROVIDER_FILTER: 'open_data'
         })
         assert geographies == test_geographies
 
@@ -166,17 +170,17 @@ class TestGeographyRepo(object):
         assert isinstance(geographies, CatalogList)
         assert geographies == test_geographies
 
-    @patch.object(RepoClient, 'get_geographies_joined_datasets')
+    @patch.object(RepoClient, 'get_geographies')
     def test_get_all_with_join_filters(self, mocked_repo):
         # Given
         mocked_repo.return_value = [db_geography1, db_geography2]
         repo = GeographyRepository()
 
         # When
-        geographies = repo.get_all({'category_id': 'demographics'})
+        geographies = repo.get_all({CATEGORY_FILTER: 'demographics'})
 
         # Then
-        mocked_repo.assert_called_once_with({'category_id': 'demographics'})
+        mocked_repo.assert_called_once_with({CATEGORY_FILTER: 'demographics'})
         assert isinstance(geographies, CatalogList)
         assert geographies == test_geographies
 
diff --git a/tests/unit/data/observatory/catalog/repository/test_repo_client.py b/tests/unit/data/observatory/catalog/repository/test_repo_client.py
index 3e4cfdc2..ea588c0c 100644
--- a/tests/unit/data/observatory/catalog/repository/test_repo_client.py
+++ b/tests/unit/data/observatory/catalog/repository/test_repo_client.py
@@ -1,65 +1,50 @@
-from unittest.mock import patch
-
-from cartoframes.io.managers.context_manager import ContextManager
+from unittest import mock
+from cartoframes.data.observatory.catalog.repository.constants import CATEGORY_FILTER, COUNTRY_FILTER
 from cartoframes.data.observatory.catalog.repository.repo_client import RepoClient
-
+from ..mocks import mocked_do_api_requests_get_datasets
 from ..examples import db_dataset1, db_dataset2
 
 
 class TestRepoClient(object):
 
-    @patch.object(ContextManager, 'execute_query')
-    def test_run_query_with_one_filter(self, mocked_client):
-        # Given
-        mocked_client.return_value = {'rows': [db_dataset1, db_dataset2]}
+    @mock.patch(
+        'cartoframes.data.observatory.catalog.repository.repo_client.requests.get',
+        side_effect=mocked_do_api_requests_get_datasets
+    )
+    def test_run_query_with_one_filter(self, mocket_get):
         repo = RepoClient()
-        query = 'SELECT t.* FROM datasets t'
-        filters = {'category_id': 'demographics'}
-        expected_query = "SELECT t.* FROM datasets t WHERE t.category_id = 'demographics'"
-
-        # When
-        categories = repo._run_query(query, filters)
+        filters = {CATEGORY_FILTER: 'demographics'}
+        # Mocked request should return URL filters as a dict:
+        result_filters = repo.get_datasets(filters)
 
-        # Then
-        mocked_client.assert_called_once_with(expected_query)
-        assert categories == [db_dataset1, db_dataset2]
+        assert result_filters[CATEGORY_FILTER] == 'demographics'
 
-    @patch.object(ContextManager, 'execute_query')
-    def test_run_query_with_multiple_filter(self, mocked_client):
-        # Given
-        mocked_client.return_value = {'rows': [db_dataset1, db_dataset2]}
+    @mock.patch(
+        'cartoframes.data.observatory.catalog.repository.repo_client.requests.get',
+        side_effect=mocked_do_api_requests_get_datasets
+    )
+    def test_run_query_with_multiple_filter(self, mocket_get):
         repo = RepoClient()
-        query = 'SELECT t.* FROM datasets t'
         filters = {
-            'category_id': 'demographics',
-            'country_id': 'usa'}
-        expected_select = 'SELECT t.* FROM datasets t WHERE'
-        expected_filter_category = "t.category_id = 'demographics'"
-        expected_filter_country = "t.country_id = 'usa'"
-
-        # When
-        datasets = repo._run_query(query, filters)
-
-        # Then
-        actual_query = str(mocked_client.call_args_list)
-        assert expected_select in actual_query
-        assert expected_filter_category in actual_query
-        assert expected_filter_country in actual_query
-        assert datasets == [db_dataset1, db_dataset2]
-
-    @patch.object(ContextManager, 'execute_query')
-    def test_run_query_with_id_list(self, mocked_client):
-        # Given
-        mocked_client.return_value = {'rows': [db_dataset1, db_dataset2]}
+            CATEGORY_FILTER: 'demographics',
+            COUNTRY_FILTER: 'usa'
+        }
+        # Mocked request should return URL filters as a dict:
+        result_filters = repo.get_datasets(filters)
+
+        assert result_filters[CATEGORY_FILTER] == 'demographics'
+        assert result_filters[COUNTRY_FILTER] == 'usa'
+
+    @mock.patch(
+        'cartoframes.data.observatory.catalog.repository.repo_client.requests.get',
+        side_effect=mocked_do_api_requests_get_datasets
+    )
+    def test_run_query_with_id_list(self, mocket_get):
         repo = RepoClient()
-        query = 'SELECT t.* FROM datasets t'
-        filters = {'id': ['carto-do.dataset.census', 'carto-do.dataset.municipalities']}
-        expected_query = "SELECT t.* FROM datasets t " \
-                         "WHERE t.id IN ('carto-do.dataset.census','carto-do.dataset.municipalities')"
-
-        # When
-        datasets = repo._run_query(query, filters)
+        filters = {
+            'id': ['basicstats_census_1234567a', 'basicstats_municipalities_2345678b']
+        }
+        # Mocked request should return both datasets in this case:
+        datasets = repo.get_datasets(filters)
 
-        # Then
-        mocked_client.assert_called_once_with(expected_query)
         assert datasets == [db_dataset1, db_dataset2]
diff --git a/tests/unit/data/observatory/catalog/repository/test_variable_group_repo.py b/tests/unit/data/observatory/catalog/repository/test_variable_group_repo.py
index 3e9bbc48..6ef8b8d1 100644
--- a/tests/unit/data/observatory/catalog/repository/test_variable_group_repo.py
+++ b/tests/unit/data/observatory/catalog/repository/test_variable_group_repo.py
@@ -7,6 +7,10 @@ from cartoframes.data.observatory.catalog.entity import CatalogList
 from cartoframes.data.observatory.catalog.variable_group import VariableGroup
 from cartoframes.data.observatory.catalog.repository.variable_group_repo import VariableGroupRepository
 from cartoframes.data.observatory.catalog.repository.repo_client import RepoClient
+from cartoframes.data.observatory.catalog.repository.constants import (
+    CATEGORY_FILTER, COUNTRY_FILTER, DATASET_FILTER, GEOGRAPHY_FILTER, PROVIDER_FILTER, VARIABLE_FILTER,
+    VARIABLE_GROUP_FILTER
+)
 from ..examples import test_variable_group1, test_variables_groups, db_variable_group1, db_variable_group2
 
 
@@ -45,13 +49,13 @@ class TestVariableGroupRepo(object):
         mocked_repo.return_value = [db_variable_group1, db_variable_group2]
         repo = VariableGroupRepository()
         filters = {
-            'country_id': 'usa',
-            'dataset_id': 'carto-do.project.census2011',
-            'category_id': 'demographics',
-            'variable_id': 'population',
-            'geography_id': 'census-geo',
-            'variable_group_id': 'var-group',
-            'provider_id': 'open_data',
+            COUNTRY_FILTER: 'usa',
+            DATASET_FILTER: 'carto-do.project.census2011',
+            CATEGORY_FILTER: 'demographics',
+            VARIABLE_FILTER: 'population',
+            GEOGRAPHY_FILTER: 'census-geo',
+            VARIABLE_GROUP_FILTER: 'var-group',
+            PROVIDER_FILTER: 'open_data',
             'fake_field_id': 'fake_value'
         }
 
@@ -60,7 +64,7 @@ class TestVariableGroupRepo(object):
 
         # Then
         mocked_repo.assert_called_once_with({
-            'dataset_id': 'carto-do.project.census2011'
+            DATASET_FILTER: 'carto-do.project.census2011'
         })
         assert variables_groups == test_variables_groups
 
diff --git a/tests/unit/data/observatory/catalog/repository/test_variable_repo.py b/tests/unit/data/observatory/catalog/repository/test_variable_repo.py
index f74925c2..a18e7413 100644
--- a/tests/unit/data/observatory/catalog/repository/test_variable_repo.py
+++ b/tests/unit/data/observatory/catalog/repository/test_variable_repo.py
@@ -7,6 +7,10 @@ from cartoframes.data.observatory.catalog.entity import CatalogList
 from cartoframes.data.observatory.catalog.variable import Variable
 from cartoframes.data.observatory.catalog.repository.variable_repo import VariableRepository
 from cartoframes.data.observatory.catalog.repository.repo_client import RepoClient
+from cartoframes.data.observatory.catalog.repository.constants import (
+    CATEGORY_FILTER, COUNTRY_FILTER, DATASET_FILTER, GEOGRAPHY_FILTER, PROVIDER_FILTER, VARIABLE_FILTER,
+    VARIABLE_GROUP_FILTER
+)
 from ..examples import test_variable1, test_variables, db_variable1, db_variable2
 
 
@@ -45,13 +49,13 @@ class TestVariableRepo(object):
         mocked_repo.return_value = [db_variable1, db_variable2]
         repo = VariableRepository()
         filters = {
-            'country_id': 'usa',
-            'dataset_id': 'carto-do.project.census2011',
-            'category_id': 'demographics',
-            'variable_id': 'population',
-            'geography_id': 'census-geo',
-            'variable_group_id': 'var-group',
-            'provider_id': 'open_data',
+            COUNTRY_FILTER: 'usa',
+            DATASET_FILTER: 'carto-do.project.census2011',
+            CATEGORY_FILTER: 'demographics',
+            VARIABLE_FILTER: 'population',
+            GEOGRAPHY_FILTER: 'census-geo',
+            VARIABLE_GROUP_FILTER: 'var-group',
+            PROVIDER_FILTER: 'open_data',
             'fake_field_id': 'fake_value'
         }
 
@@ -60,8 +64,8 @@ class TestVariableRepo(object):
 
         # Then
         mocked_repo.assert_called_once_with({
-            'dataset_id': 'carto-do.project.census2011',
-            'variable_group_id': 'var-group'
+            DATASET_FILTER: 'carto-do.project.census2011',
+            VARIABLE_GROUP_FILTER: 'var-group'
         })
         assert variables == test_variables
 
diff --git a/tests/unit/data/observatory/catalog/test_catalog.py b/tests/unit/data/observatory/catalog/test_catalog.py
index 2513689e..306354f0 100644
--- a/tests/unit/data/observatory/catalog/test_catalog.py
+++ b/tests/unit/data/observatory/catalog/test_catalog.py
@@ -10,8 +10,13 @@ from cartoframes.data.observatory.catalog.category import Category
 from cartoframes.data.observatory.catalog.catalog import Catalog
 from cartoframes.data.observatory.catalog.subscriptions import Subscriptions
 from cartoframes.data.observatory.catalog.repository.geography_repo import GeographyRepository
-from .examples import test_country2, test_country1, test_category1, test_category2, test_dataset1, test_dataset2, \
+from cartoframes.data.observatory.catalog.repository.constants import (
+    CATEGORY_FILTER, COUNTRY_FILTER, GEOGRAPHY_FILTER
+)
+from .examples import (
+    test_country2, test_country1, test_category1, test_category2, test_dataset1, test_dataset2,
     test_geographies, test_datasets, test_categories, test_countries, test_geography1, test_geography2
+)
 
 
 class TestCatalog(object):
@@ -65,7 +70,7 @@ class TestCatalog(object):
         countries = catalog.category('demographics').countries
 
         # Then
-        mocked_countries.called_once_with({'category_id': 'demographics'})
+        mocked_countries.called_once_with({CATEGORY_FILTER: 'demographics'})
         assert countries == test_countries
 
     @patch.object(Category, 'get_all')
@@ -78,7 +83,7 @@ class TestCatalog(object):
         categories = catalog.country('usa').categories
 
         # Then
-        mocked_categories.called_once_with({'country_id': 'usa'})
+        mocked_categories.called_once_with({COUNTRY_FILTER: 'usa'})
         assert categories == test_categories
 
     @patch.object(Dataset, 'get_all')
@@ -91,7 +96,7 @@ class TestCatalog(object):
         datasets = catalog.country('usa').category('demographics').datasets
 
         # Then
-        mocked_datasets.called_once_with({'country_id': 'usa', 'category_id': 'demographics'})
+        mocked_datasets.called_once_with({COUNTRY_FILTER: 'usa', CATEGORY_FILTER: 'demographics'})
         assert datasets == test_datasets
 
     @patch.object(Geography, 'get_all')
@@ -104,7 +109,7 @@ class TestCatalog(object):
         geographies = catalog.country('usa').category('demographics').geographies
 
         # Then
-        mocked_geographies.called_once_with({'country_id': 'usa', 'category_id': 'demographics'})
+        mocked_geographies.called_once_with({COUNTRY_FILTER: 'usa', CATEGORY_FILTER: 'demographics'})
         assert geographies == test_geographies
 
     @patch.object(Dataset, 'get_all')
@@ -119,9 +124,9 @@ class TestCatalog(object):
 
         # Then
         mocked_datasets.called_once_with({
-            'country_id': 'usa',
-            'category_id': 'demographics',
-            'geography_id': 'carto-do-public-data.tiger.geography_esp_census_2019'})
+            COUNTRY_FILTER: 'usa',
+            CATEGORY_FILTER: 'demographics',
+            GEOGRAPHY_FILTER: 'carto-do-public-data.tiger.geography_esp_census_2019'})
 
         assert datasets == test_datasets
 
@@ -139,7 +144,7 @@ class TestCatalog(object):
 
         # Then
         mocked_repo.assert_called_once_with(slug)
-        mocked_datasets.assert_called_once_with({'geography_id': test_geography1.id})
+        mocked_datasets.assert_called_once_with({GEOGRAPHY_FILTER: test_geography1.id})
         assert datasets == test_datasets
 
     @patch.object(Dataset, 'get_all')
diff --git a/tests/unit/data/observatory/catalog/test_category.py b/tests/unit/data/observatory/catalog/test_category.py
index 4ea8d986..f6c5e9f0 100644
--- a/tests/unit/data/observatory/catalog/test_category.py
+++ b/tests/unit/data/observatory/catalog/test_category.py
@@ -7,8 +7,11 @@ from cartoframes.data.observatory.catalog.repository.dataset_repo import Dataset
 from cartoframes.data.observatory.catalog.repository.category_repo import CategoryRepository
 from cartoframes.data.observatory.catalog.repository.geography_repo import GeographyRepository
 from cartoframes.data.observatory.catalog.entity import CatalogList
-from .examples import test_category1, test_datasets, test_categories, db_category1, test_category2, db_category2, \
+from cartoframes.data.observatory.catalog.repository.constants import CATEGORY_FILTER
+from .examples import (
+    test_category1, test_datasets, test_categories, db_category1, test_category2, db_category2,
     test_geographies
+)
 
 
 class TestCategory(object):
@@ -35,7 +38,7 @@ class TestCategory(object):
         datasets = test_category1.datasets
 
         # Then
-        mocked_repo.assert_called_once_with({'category_id': test_category1.id})
+        mocked_repo.assert_called_once_with({CATEGORY_FILTER: test_category1.id})
         assert isinstance(datasets, list)
         assert isinstance(datasets, CatalogList)
         assert datasets == test_datasets
@@ -49,7 +52,7 @@ class TestCategory(object):
         geographies = test_category1.geographies
 
         # Then
-        mocked_repo.assert_called_once_with({'category_id': test_category1.id})
+        mocked_repo.assert_called_once_with({CATEGORY_FILTER: test_category1.id})
         assert isinstance(geographies, list)
         assert isinstance(geographies, CatalogList)
         assert geographies == test_geographies
diff --git a/tests/unit/data/observatory/catalog/test_country.py b/tests/unit/data/observatory/catalog/test_country.py
index 801940ff..8ae32785 100644
--- a/tests/unit/data/observatory/catalog/test_country.py
+++ b/tests/unit/data/observatory/catalog/test_country.py
@@ -8,8 +8,11 @@ from cartoframes.data.observatory.catalog.repository.country_repo import Country
 from cartoframes.data.observatory.catalog.repository.dataset_repo import DatasetRepository
 from cartoframes.data.observatory.catalog.repository.category_repo import CategoryRepository
 from cartoframes.data.observatory.catalog.repository.geography_repo import GeographyRepository
-from .examples import test_country1, test_datasets, test_countries, test_geographies, db_country1, test_country2, \
+from cartoframes.data.observatory.catalog.repository.constants import COUNTRY_FILTER
+from .examples import (
+    test_country1, test_datasets, test_countries, test_geographies, db_country1, test_country2,
     db_country2, test_categories
+)
 
 
 class TestCountry(object):
@@ -36,7 +39,7 @@ class TestCountry(object):
         datasets = test_country1.datasets
 
         # Then
-        mocked_repo.assert_called_once_with({'country_id': test_country1.id})
+        mocked_repo.assert_called_once_with({COUNTRY_FILTER: test_country1.id})
         assert isinstance(datasets, list)
         assert isinstance(datasets, CatalogList)
         assert datasets == test_datasets
@@ -50,7 +53,7 @@ class TestCountry(object):
         geographies = test_country1.geographies
 
         # Then
-        mocked_repo.assert_called_once_with({'country_id': test_country1.id})
+        mocked_repo.assert_called_once_with({COUNTRY_FILTER: test_country1.id})
         assert isinstance(geographies, list)
         assert isinstance(geographies, CatalogList)
         assert geographies == test_geographies
@@ -64,7 +67,7 @@ class TestCountry(object):
         categories = test_country1.categories
 
         # Then
-        mocked_repo.assert_called_once_with({'country_id': test_country1.id})
+        mocked_repo.assert_called_once_with({COUNTRY_FILTER: test_country1.id})
         assert isinstance(categories, list)
         assert isinstance(categories, CatalogList)
         assert categories == test_categories
diff --git a/tests/unit/data/observatory/catalog/test_dataset.py b/tests/unit/data/observatory/catalog/test_dataset.py
index 8ff5b0ca..4050e411 100644
--- a/tests/unit/data/observatory/catalog/test_dataset.py
+++ b/tests/unit/data/observatory/catalog/test_dataset.py
@@ -11,8 +11,11 @@ from cartoframes.data.observatory.catalog.repository.variable_repo import Variab
 from cartoframes.data.observatory.catalog.repository.variable_group_repo import VariableGroupRepository
 from cartoframes.data.observatory.catalog.repository.dataset_repo import DatasetRepository
 from cartoframes.data.observatory.catalog.subscription_info import SubscriptionInfo
-from .examples import test_dataset1, test_datasets, test_variables, test_variables_groups, db_dataset1, test_dataset2, \
+from cartoframes.data.observatory.catalog.repository.constants import DATASET_FILTER
+from .examples import (
+    test_dataset1, test_datasets, test_variables, test_variables_groups, db_dataset1, test_dataset2,
     db_dataset2, test_subscription_info
+)
 from .mocks import BigQueryClientMock
 
 
@@ -40,7 +43,7 @@ class TestDataset(object):
         variables = test_dataset1.variables
 
         # Then
-        mocked_repo.assert_called_once_with({'dataset_id': test_dataset1.id})
+        mocked_repo.assert_called_once_with({DATASET_FILTER: test_dataset1.id})
         assert isinstance(variables, list)
         assert isinstance(variables, CatalogList)
         assert variables == test_variables
@@ -54,7 +57,7 @@ class TestDataset(object):
         variables_groups = test_dataset1.variables_groups
 
         # Then
-        mocked_repo.assert_called_once_with({'dataset_id': test_dataset1.id})
+        mocked_repo.assert_called_once_with({DATASET_FILTER: test_dataset1.id})
         assert isinstance(variables_groups, list)
         assert isinstance(variables_groups, CatalogList)
         assert variables_groups == test_variables_groups
diff --git a/tests/unit/data/observatory/catalog/test_geography.py b/tests/unit/data/observatory/catalog/test_geography.py
index 7e08bd6c..c91c8604 100644
--- a/tests/unit/data/observatory/catalog/test_geography.py
+++ b/tests/unit/data/observatory/catalog/test_geography.py
@@ -10,8 +10,11 @@ from cartoframes.data.observatory.catalog.geography import Geography
 from cartoframes.data.observatory.catalog.repository.geography_repo import GeographyRepository
 from cartoframes.data.observatory.catalog.repository.dataset_repo import DatasetRepository
 from cartoframes.data.observatory.catalog.subscription_info import SubscriptionInfo
-from .examples import test_geography1, test_geographies, test_datasets, db_geography1, \
+from cartoframes.data.observatory.catalog.repository.constants import GEOGRAPHY_FILTER
+from .examples import (
+    test_geography1, test_geographies, test_datasets, db_geography1,
     test_geography2, db_geography2, test_subscription_info
+)
 from .mocks import BigQueryClientMock
 
 
@@ -39,7 +42,7 @@ class TestGeography(object):
         datasets = test_geography1.datasets
 
         # Then
-        mocked_repo.assert_called_once_with({'geography_id': test_geography1.id})
+        mocked_repo.assert_called_once_with({GEOGRAPHY_FILTER: test_geography1.id})
         assert isinstance(datasets, list)
         assert isinstance(datasets, CatalogList)
         assert datasets == test_datasets
diff --git a/tests/unit/data/observatory/catalog/test_provider.py b/tests/unit/data/observatory/catalog/test_provider.py
index 911231fa..e2a5f345 100644
--- a/tests/unit/data/observatory/catalog/test_provider.py
+++ b/tests/unit/data/observatory/catalog/test_provider.py
@@ -6,6 +6,7 @@ from cartoframes.data.observatory.catalog.entity import CatalogList
 from cartoframes.data.observatory.catalog.provider import Provider
 from cartoframes.data.observatory.catalog.repository.provider_repo import ProviderRepository
 from cartoframes.data.observatory.catalog.repository.dataset_repo import DatasetRepository
+from cartoframes.data.observatory.catalog.repository.constants import PROVIDER_FILTER
 from .examples import test_datasets, test_provider1, test_providers, db_provider1, test_provider2, db_provider2
 
 
@@ -33,7 +34,7 @@ class TestProvider(object):
         datasets = test_provider1.datasets
 
         # Then
-        mocked_repo.assert_called_once_with({'provider_id': test_provider1.id})
+        mocked_repo.assert_called_once_with({PROVIDER_FILTER: test_provider1.id})
         assert isinstance(datasets, list)
         assert isinstance(datasets, CatalogList)
         assert datasets == test_datasets
diff --git a/tests/unit/data/observatory/catalog/test_variable.py b/tests/unit/data/observatory/catalog/test_variable.py
index b250ef4b..12196332 100644
--- a/tests/unit/data/observatory/catalog/test_variable.py
+++ b/tests/unit/data/observatory/catalog/test_variable.py
@@ -6,6 +6,7 @@ from cartoframes.data.observatory.catalog.entity import CatalogList
 from cartoframes.data.observatory.catalog.variable import Variable
 from cartoframes.data.observatory.catalog.repository.variable_repo import VariableRepository
 from cartoframes.data.observatory.catalog.repository.dataset_repo import DatasetRepository
+from cartoframes.data.observatory.catalog.repository.constants import VARIABLE_FILTER
 from .examples import test_datasets, test_variable1, test_variables, db_variable1, test_variable2, db_variable2
 
 
@@ -33,7 +34,7 @@ class TestVariable(object):
         datasets = test_variable1.datasets
 
         # Then
-        mocked_repo.assert_called_once_with({'variable_id': test_variable1.id})
+        mocked_repo.assert_called_once_with({VARIABLE_FILTER: test_variable1.id})
         assert isinstance(datasets, list)
         assert isinstance(datasets, CatalogList)
         assert datasets == test_datasets
diff --git a/tests/unit/data/observatory/catalog/test_variable_group.py b/tests/unit/data/observatory/catalog/test_variable_group.py
index 743dd404..774fee1a 100644
--- a/tests/unit/data/observatory/catalog/test_variable_group.py
+++ b/tests/unit/data/observatory/catalog/test_variable_group.py
@@ -6,8 +6,11 @@ from cartoframes.data.observatory.catalog.entity import CatalogList
 from cartoframes.data.observatory.catalog.variable_group import VariableGroup
 from cartoframes.data.observatory.catalog.repository.variable_repo import VariableRepository
 from cartoframes.data.observatory.catalog.repository.variable_group_repo import VariableGroupRepository
-from .examples import test_variables_groups, test_variable_group1, test_variables, db_variable_group1, \
+from cartoframes.data.observatory.catalog.repository.constants import VARIABLE_GROUP_FILTER
+from .examples import (
+    test_variables_groups, test_variable_group1, test_variables, db_variable_group1,
     test_variable_group2, db_variable_group2
+)
 
 
 class TestVariableGroup(object):
@@ -34,7 +37,7 @@ class TestVariableGroup(object):
         variables = test_variable_group1.variables
 
         # Then
-        mocked_repo.assert_called_once_with({'variable_group_id': test_variable_group1.id})
+        mocked_repo.assert_called_once_with({VARIABLE_GROUP_FILTER: test_variable_group1.id})
         assert isinstance(variables, list)
         assert isinstance(variables, CatalogList)
         assert variables == test_variables