Skip to content

Commit 66d3a1d

Browse files
Fix Hasura Cloud, source field, printing help messages on HasuraError (#215)
* Fix printing help messages on `HasuraError` * Lint * Preserve sources * Changelog
1 parent a0e6fcd commit 66d3a1d

File tree

4 files changed

+39
-24
lines changed

4 files changed

+39
-24
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,18 @@ Please use [this](https://docs.gitlab.com/ee/development/changelog.html) documen
88

99
* cli: Fixed stacktraces missing on exception.
1010
* cli: Fixed wrapping `OSError` with `ConfigurationError` during config loading.
11+
* hasura: Fixed printing help messages on `HasuraError`.
12+
* hasura: Preserve list of sources in Hasura Cloud environments.
13+
* hasura: Fixed `HasuraConfig.source` config option.
1114

1215
### Changed
1316

1417
* cli: Unknown exceptions are no longer wrapped with `DipDupError`.
1518

19+
### Performance
20+
21+
* hasura: Removed some useless requests.
22+
1623
## 4.1.0 - 2022-01-24
1724

1825
### Added

src/dipdup/config.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -872,11 +872,6 @@ def valid_url(cls, v):
872872
raise ConfigurationError(f'`{v}` is not a valid Hasura URL')
873873
return v.rstrip('/')
874874

875-
@validator('source', allow_reuse=True)
876-
def valid_source(cls, v):
877-
if v != 'default':
878-
raise NotImplementedError('Multiple Hasura sources are not supported at the moment')
879-
880875
@cached_property
881876
def headers(self) -> Dict[str, str]:
882877
if self.admin_secret:

src/dipdup/exceptions.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,7 @@ def _help(self) -> str:
306306
"""
307307

308308

309+
# TODO: Drop in next major version
309310
@dataclass(frozen=True, repr=False)
310311
class DeprecatedHandlerError(DipDupError):
311312
"""Default handlers need to be converted to hooks"""
@@ -323,3 +324,17 @@ def _help(self) -> str:
323324
1. If you have any custom logic implemented in default handlers move it to corresponding hooks from the table above.
324325
2. Remove default handlers from project.
325326
"""
327+
328+
329+
@dataclass(frozen=True, repr=False)
330+
class HasuraError(DipDupError):
331+
"""Failed to configure Hasura instance"""
332+
333+
msg: str
334+
335+
def _help(self) -> str:
336+
return f"""
337+
Failed to configure Hasura: {self.msg}
338+
339+
GraphQL integration docs: https://docs.dipdup.net/graphql/
340+
"""

src/dipdup/hasura.py

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
from dipdup.config import HTTPConfig
3030
from dipdup.config import PostgresDatabaseConfig
3131
from dipdup.exceptions import ConfigurationError
32+
from dipdup.exceptions import HasuraError
3233
from dipdup.http import HTTPGateway
3334
from dipdup.models import Schema
3435
from dipdup.utils import iter_files
@@ -77,10 +78,6 @@ def root(self) -> str:
7778
return humps.decamelize(self.name)
7879

7980

80-
class HasuraError(RuntimeError):
81-
...
82-
83-
8481
class HasuraGateway(HTTPGateway):
8582
_default_http_config = HTTPConfig(
8683
cache=False,
@@ -120,21 +117,21 @@ async def configure(self, force: bool = False) -> None:
120117
self._logger.info('Metadata is up to date, no action required')
121118
return
122119

123-
await self._reset_metadata()
124-
metadata = await self._fetch_metadata()
125-
126-
# NOTE: Hasura metadata updated in three steps.
127-
# NOTE: Order matters because queries must be generated after applying table customization to be valid.
128-
# NOTE: 1. Generate and apply tables metadata.
129-
source_tables_metadata = await self._generate_source_tables_metadata()
130-
metadata['sources'][0]['tables'] = source_tables_metadata
120+
# NOTE: Find chosen source and overwrite its tables
121+
source_name = self._hasura_config.source
122+
for source in metadata['sources']:
123+
if source['name'] == source_name:
124+
source['tables'] = await self._generate_source_tables_metadata()
125+
break
126+
else:
127+
raise HasuraError(f'Source `{source_name}` not found in metadata')
131128
await self._replace_metadata(metadata)
132129

133-
# NOTE: 2. Apply table customization and refresh metadata
130+
# NOTE: Apply table customizations before generating queries
134131
await self._apply_table_customization()
135132
metadata = await self._fetch_metadata()
136133

137-
# NOTE: 3. Generate and apply queries and rest endpoints
134+
# NOTE: Generate and apply queries and REST endpoints
138135
query_collections_metadata = await self._generate_query_collections_metadata()
139136
self._logger.info('Adding %s generated and user-defined queries', len(query_collections_metadata))
140137
metadata['query_collections'] = [
@@ -152,6 +149,7 @@ async def configure(self, force: bool = False) -> None:
152149

153150
await self._replace_metadata(metadata)
154151

152+
# NOTE: Fetch metadata once again (to do: find out why is it necessary) and save its hash for future comparisons
155153
metadata = await self._fetch_metadata()
156154
metadata_hash = self._hash_metadata(metadata)
157155
hasura_schema.hash = metadata_hash # type: ignore
@@ -170,7 +168,7 @@ async def _hasura_request(self, endpoint: str, json: Dict[str, Any]) -> Dict[str
170168
)
171169
self._logger.debug('Response: %s', result)
172170
if 'error' in result or 'errors' in result:
173-
raise HasuraError('Can\'t configure Hasura instance', result)
171+
raise HasuraError(result)
174172
return result
175173

176174
async def _healthcheck(self) -> None:
@@ -183,7 +181,7 @@ async def _healthcheck(self) -> None:
183181
break
184182
await asyncio.sleep(1)
185183
else:
186-
raise HasuraError(f'Hasura instance not responding for {timeout} seconds')
184+
raise HasuraError(f'Not responding for {timeout} seconds')
187185

188186
version_json = await (
189187
await self._http._session.get(
@@ -192,7 +190,7 @@ async def _healthcheck(self) -> None:
192190
).json()
193191
version = version_json['version']
194192
if version.startswith('v1'):
195-
raise HasuraError('Hasura v1 is not supported.')
193+
raise HasuraError('v1 is not supported, upgrade to the latest stable version.')
196194

197195
self._logger.info('Connected to Hasura %s', version)
198196

@@ -273,7 +271,7 @@ async def _generate_source_tables_metadata(self) -> List[Dict[str, Any]]:
273271
for field in model._meta.fields_map.values():
274272
if isinstance(field, fields.relational.ForeignKeyFieldInstance):
275273
if not isinstance(field.related_name, str):
276-
raise HasuraError(f'`related_name` of `{field}` must be set')
274+
raise HasuraError(f'`related_name` of `{field}` field must be set')
277275

278276
related_table_name = model_tables[field.model_name]
279277
field_name = field.model_field_name
@@ -293,7 +291,7 @@ async def _generate_source_tables_metadata(self) -> List[Dict[str, Any]]:
293291

294292
elif isinstance(field, fields.relational.ManyToManyFieldInstance):
295293
if not isinstance(field.related_name, str):
296-
raise HasuraError(f'`related_name` of `{field}` must be set')
294+
raise HasuraError(f'`related_name` of `{field}` field must be set')
297295

298296
related_table_name = model_tables[field.model_name]
299297
junction_table_name = field.through

0 commit comments

Comments
 (0)