Skip to content

Commit ba8fc73

Browse files
committed
Add Storage.update_feed_dict() (for database sync).
1 parent 55f2474 commit ba8fc73

1 file changed

Lines changed: 53 additions & 35 deletions

File tree

src/reader/_storage/_feeds.py

Lines changed: 53 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,12 @@
33
import json
44
import sqlite3
55
from collections.abc import Iterable
6+
from collections.abc import Mapping
67
from datetime import datetime
78
from functools import partial
89
from typing import Any
10+
from typing import cast
11+
from typing import NewType
912
from typing import TYPE_CHECKING
1013

1114
from .._types import FeedFilter
@@ -26,6 +29,7 @@
2629
from ._sqlite_utils import adapt_datetime
2730
from ._sqlite_utils import convert_timestamp
2831
from ._sqlite_utils import rowcount_exactly_one
32+
from ._sqlite_utils import SQLiteValue
2933
from ._tags import feed_tags_filter
3034

3135
if TYPE_CHECKING: # pragma: no cover
@@ -34,6 +38,9 @@
3438
StorageBase = object
3539

3640

41+
FeedDict = NewType('FeedDict', Mapping[str, SQLiteValue])
42+
43+
3744
class FeedsMixin(StorageBase):
3845
@wrap_exceptions()
3946
def add_feed(self, url: str, added: datetime) -> None:
@@ -222,48 +229,21 @@ def set_feed_stale(self, url: str, stale: bool) -> None:
222229
)
223230
rowcount_exactly_one(cursor, lambda: FeedNotFoundError(url))
224231

225-
@wrap_exceptions()
226232
def update_feed(self, intent: FeedUpdateIntent) -> None:
227-
url, _, _, value = intent
228-
229-
context: dict[str, Any] = {
230-
'url': url,
231-
'last_retrieved': adapt_datetime(intent.last_retrieved),
232-
'update_after': adapt_datetime(intent.update_after),
233-
}
234-
235-
if isinstance(value, FeedToUpdate):
236-
assert url == value.feed.url, "updating feed URL not supported"
237-
238-
context.update(
239-
value._asdict(),
240-
caching_info=(
241-
json.dumps(value.caching_info) if value.caching_info else None
242-
),
243-
)
244-
feed = context.pop('feed')
245-
context.update(
246-
feed._asdict(),
247-
updated=adapt_datetime(feed.updated) if feed.updated else None,
248-
last_updated=adapt_datetime(value.last_updated),
249-
data_hash=feed.hash,
250-
)
251-
context.pop('hash', None)
233+
return self.update_feed_dict(feed_update_intent_to_dict(intent))
252234

253-
context['stale'] = 0
254-
255-
if isinstance(value, ExceptionInfo):
256-
context['last_exception'] = json.dumps(value._asdict())
257-
else:
258-
assert isinstance(value, FeedToUpdate | None)
259-
context['last_exception'] = None
235+
@wrap_exceptions()
236+
def update_feed_dict(self, intent: FeedDict) -> None:
237+
"""Low level update_feed_dict() used by database sync."""
260238

261-
expressions = [f"{n} = :{n}" for n in context if n != 'url']
239+
expressions = [f"{n} = :{n}" for n in intent if n != 'url']
262240
query = f"UPDATE feeds SET {', '.join(expressions)} WHERE url = :url;"
263241

264242
with self.get_db() as db:
265-
cursor = db.execute(query, context)
243+
cursor = db.execute(query, intent)
266244

245+
url = intent['url']
246+
assert isinstance(url, str)
267247
rowcount_exactly_one(cursor, lambda: FeedNotFoundError(url))
268248

269249

@@ -360,3 +340,41 @@ def feed_filter(query: Query, filter: FeedFilter) -> dict[str, Any]:
360340
context.update(update_after=adapt_datetime(update_after))
361341

362342
return context
343+
344+
345+
def feed_update_intent_to_dict(intent: FeedUpdateIntent) -> FeedDict:
346+
url, _, _, value = intent
347+
348+
context: dict[str, Any] = {
349+
'url': url,
350+
'last_retrieved': adapt_datetime(intent.last_retrieved),
351+
'update_after': adapt_datetime(intent.update_after),
352+
}
353+
354+
if isinstance(value, FeedToUpdate):
355+
assert url == value.feed.url, "updating feed URL not supported"
356+
357+
context.update(
358+
value._asdict(),
359+
caching_info=(
360+
json.dumps(value.caching_info) if value.caching_info else None
361+
),
362+
)
363+
feed = context.pop('feed')
364+
context.update(
365+
feed._asdict(),
366+
updated=adapt_datetime(feed.updated) if feed.updated else None,
367+
last_updated=adapt_datetime(value.last_updated),
368+
data_hash=feed.hash,
369+
)
370+
context.pop('hash', None)
371+
372+
context['stale'] = 0
373+
374+
if isinstance(value, ExceptionInfo):
375+
context['last_exception'] = json.dumps(value._asdict())
376+
else:
377+
assert isinstance(value, FeedToUpdate | None)
378+
context['last_exception'] = None
379+
380+
return cast(FeedDict, context)

0 commit comments

Comments
 (0)