Database migration (#45)
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
Closes #16 Co-authored-by: mitsuha_s <stmiroslavsckaya@yandex.ru> Reviewed-on: #45 Reviewed-by: Alexey Skobkin <skobkin-ru@ya.ru>
This commit is contained in:
parent
90a26dd1c8
commit
31c112a4fa
33
database.py
33
database.py
|
@ -2,6 +2,7 @@ from logging import Logger
|
||||||
import psycopg2
|
import psycopg2
|
||||||
from psycopg2.extensions import connection
|
from psycopg2.extensions import connection
|
||||||
from psycopg2.extras import DictCursor, DictRow
|
from psycopg2.extras import DictCursor, DictRow
|
||||||
|
from yoyo import get_backend, read_migrations
|
||||||
from exceptions import DisplayableException
|
from exceptions import DisplayableException
|
||||||
from rss import FeedItem
|
from rss import FeedItem
|
||||||
|
|
||||||
|
@ -10,12 +11,12 @@ class Database:
|
||||||
"""Implement interaction with the database."""
|
"""Implement interaction with the database."""
|
||||||
|
|
||||||
def __init__(self, dsn: str, log: Logger) -> None:
|
def __init__(self, dsn: str, log: Logger) -> None:
|
||||||
"""Create a database file if not exists."""
|
"""Initialize the database"""
|
||||||
self.log: Logger = log
|
self.log: Logger = log
|
||||||
self.log.debug('Database.__init__(DSN=\'%s\')', dsn)
|
self.log.debug('Database.__init__(DSN=\'%s\')', dsn)
|
||||||
self.conn: connection = psycopg2.connect(dsn)
|
self.conn: connection = psycopg2.connect(dsn)
|
||||||
self.cur: DictCursor = self.conn.cursor(cursor_factory=DictCursor)
|
self.cur: DictCursor = self.conn.cursor(cursor_factory=DictCursor)
|
||||||
self.__init_schema()
|
self.__migrate(dsn)
|
||||||
|
|
||||||
def add_user(self, telegram_id: int) -> int:
|
def add_user(self, telegram_id: int) -> int:
|
||||||
"""Add a user's telegram id to the database and return its database id."""
|
"""Add a user's telegram id to the database and return its database id."""
|
||||||
|
@ -156,26 +157,14 @@ class Database:
|
||||||
'INSERT INTO feeds_last_items (feed_id, url, guid) VALUES (%s, %s, %s)', new_items)
|
'INSERT INTO feeds_last_items (feed_id, url, guid) VALUES (%s, %s, %s)', new_items)
|
||||||
self.conn.commit()
|
self.conn.commit()
|
||||||
|
|
||||||
def __init_schema(self) -> None:
|
def __migrate(self, dsn: str) -> None:
|
||||||
self.log.debug('__init_schema()')
|
"""Migrate or initialize the database schema"""
|
||||||
self.cur.execute(
|
self.log.debug(f'Database.__migrate(dsn={dsn})')
|
||||||
'CREATE TABLE IF NOT EXISTS users (id SERIAL PRIMARY KEY, telegram_id INTEGER NOT NULL UNIQUE)'
|
backend = get_backend(dsn)
|
||||||
)
|
migrations = read_migrations('./migrations')
|
||||||
self.cur.execute('CREATE TABLE IF NOT EXISTS feeds (id SERIAL PRIMARY KEY, url TEXT NOT NULL UNIQUE)')
|
|
||||||
self.cur.execute(
|
with backend.lock():
|
||||||
'CREATE TABLE IF NOT EXISTS subscriptions ('
|
backend.apply_migrations(backend.to_apply(migrations))
|
||||||
' user_id INTEGER REFERENCES users,'
|
|
||||||
' feed_id INTEGER REFERENCES feeds,'
|
|
||||||
' UNIQUE (user_id, feed_id)'
|
|
||||||
')'
|
|
||||||
)
|
|
||||||
self.cur.execute(
|
|
||||||
'CREATE TABLE IF NOT EXISTS feeds_last_items ('
|
|
||||||
' feed_id INTEGER REFERENCES feeds ON DELETE CASCADE,'
|
|
||||||
' url TEXT NOT NULL,'
|
|
||||||
' guid TEXT'
|
|
||||||
')'
|
|
||||||
)
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def __dictrow_to_dict_list(rows: list[DictRow]) -> list[dict]:
|
def __dictrow_to_dict_list(rows: list[DictRow]) -> list[dict]:
|
||||||
|
|
30
migrations/0000.initial_schema.py
Normal file
30
migrations/0000.initial_schema.py
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
from yoyo import step
|
||||||
|
|
||||||
|
steps = [
|
||||||
|
step(
|
||||||
|
'CREATE TABLE users ('
|
||||||
|
' id SERIAL PRIMARY KEY,'
|
||||||
|
' telegram_id INTEGER NOT NULL UNIQUE'
|
||||||
|
')'
|
||||||
|
),
|
||||||
|
step(
|
||||||
|
'CREATE TABLE feeds ('
|
||||||
|
' id SERIAL PRIMARY KEY,'
|
||||||
|
' url TEXT NOT NULL UNIQUE'
|
||||||
|
')'
|
||||||
|
),
|
||||||
|
step(
|
||||||
|
'CREATE TABLE subscriptions ('
|
||||||
|
' user_id INTEGER REFERENCES users,'
|
||||||
|
' feed_id INTEGER REFERENCES feeds,'
|
||||||
|
' UNIQUE (user_id, feed_id)'
|
||||||
|
')'
|
||||||
|
),
|
||||||
|
step(
|
||||||
|
'CREATE TABLE feeds_last_items ('
|
||||||
|
' feed_id INTEGER REFERENCES feeds ON DELETE CASCADE,'
|
||||||
|
' url TEXT NOT NULL,'
|
||||||
|
' guid TEXT'
|
||||||
|
')'
|
||||||
|
)
|
||||||
|
]
|
|
@ -13,3 +13,4 @@ six==1.16.0
|
||||||
urllib3==1.26.9
|
urllib3==1.26.9
|
||||||
validators==0.19.0
|
validators==0.19.0
|
||||||
webencodings==0.5.1
|
webencodings==0.5.1
|
||||||
|
yoyo-migrations==7.3.2
|
||||||
|
|
Loading…
Reference in a new issue