From 8766e36aa6f4c3cadf5b751219790380e32642c7 Mon Sep 17 00:00:00 2001 From: mitsuha_s Date: Sun, 21 Aug 2022 16:03:00 +0300 Subject: [PATCH 1/8] add database migrations --- database.py | 30 +++++++++--------------------- migrations/0000.initial-schema.py | 18 ++++++++++++++++++ requirements.txt | 1 + 3 files changed, 28 insertions(+), 21 deletions(-) create mode 100644 migrations/0000.initial-schema.py diff --git a/database.py b/database.py index 4ea6a67..9034de3 100644 --- a/database.py +++ b/database.py @@ -4,6 +4,8 @@ from psycopg2.extensions import connection from psycopg2.extras import DictCursor, DictRow from exceptions import DisplayableException from rss import FeedItem +from yoyo import read_migrations +from yoyo import get_backend class Database: @@ -15,7 +17,7 @@ class Database: self.log.debug('Database.__init__(DSN=\'%s\')', dsn) self.conn: connection = psycopg2.connect(dsn) self.cur: DictCursor = self.conn.cursor(cursor_factory=DictCursor) - self.__init_schema() + self.__migration(dsn) def add_user(self, telegram_id: int) -> int: """Add a user's telegram id to the database and return its database id.""" @@ -156,26 +158,12 @@ class Database: 'INSERT INTO feeds_last_items (feed_id, url, guid) VALUES (%s, %s, %s)', new_items) self.conn.commit() - def __init_schema(self) -> None: - self.log.debug('__init_schema()') - self.cur.execute( - 'CREATE TABLE IF NOT EXISTS users (id SERIAL PRIMARY KEY, telegram_id INTEGER NOT NULL UNIQUE)' - ) - self.cur.execute('CREATE TABLE IF NOT EXISTS feeds (id SERIAL PRIMARY KEY, url TEXT NOT NULL UNIQUE)') - self.cur.execute( - 'CREATE TABLE IF NOT EXISTS subscriptions (' - ' 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' - ')' - ) + def __migration(self, dsn: str) -> None: + backend = get_backend(dsn) + migrations = read_migrations('./migrations') + + with backend.lock(): + backend.apply_migrations(backend.to_apply(migrations)) @staticmethod def __dictrow_to_dict_list(rows: list[DictRow]) -> list[dict]: diff --git a/migrations/0000.initial-schema.py b/migrations/0000.initial-schema.py new file mode 100644 index 0000000..1553418 --- /dev/null +++ b/migrations/0000.initial-schema.py @@ -0,0 +1,18 @@ +from yoyo import step + +steps = [ + step('CREATE TABLE IF NOT EXISTS users (id SERIAL PRIMARY KEY, telegram_id INTEGER NOT NULL UNIQUE)'), + step('CREATE TABLE IF NOT EXISTS feeds (id SERIAL PRIMARY KEY, url TEXT NOT NULL UNIQUE)'), + step('CREATE TABLE IF NOT EXISTS subscriptions (' + ' user_id INTEGER REFERENCES users,' + ' feed_id INTEGER REFERENCES feeds,' + ' UNIQUE (user_id, feed_id)' + ')' + ), + step('CREATE TABLE IF NOT EXISTS feeds_last_items (' + ' feed_id INTEGER REFERENCES feeds ON DELETE CASCADE,' + ' url TEXT NOT NULL,' + ' guid TEXT' + ')' + ) +] diff --git a/requirements.txt b/requirements.txt index cc5e556..fd8e157 100644 --- a/requirements.txt +++ b/requirements.txt @@ -13,3 +13,4 @@ six==1.16.0 urllib3==1.26.9 validators==0.19.0 webencodings==0.5.1 +yoyo-migrations==7.3.2 -- 2.43.5 From 8d4aa91d6f649ce5deb22ba1e13d1b2107d53708 Mon Sep 17 00:00:00 2001 From: mitsuha_s Date: Sun, 21 Aug 2022 19:17:44 +0300 Subject: [PATCH 2/8] code style changes --- database.py | 8 +++----- migrations/0000.initial-schema.py | 18 ------------------ migrations/0000.initial_schema.py | 20 ++++++++++++++++++++ 3 files changed, 23 insertions(+), 23 deletions(-) delete mode 100644 migrations/0000.initial-schema.py create mode 100644 migrations/0000.initial_schema.py diff --git a/database.py b/database.py index 9034de3..2dfe1ba 100644 --- a/database.py +++ b/database.py @@ -3,10 +3,8 @@ import psycopg2 from psycopg2.extensions import connection from psycopg2.extras import DictCursor, DictRow from exceptions import DisplayableException +from yoyo import read_migrations, get_backend from rss import FeedItem -from yoyo import read_migrations -from yoyo import get_backend - class Database: """Implement interaction with the database.""" @@ -17,7 +15,7 @@ class Database: self.log.debug('Database.__init__(DSN=\'%s\')', dsn) self.conn: connection = psycopg2.connect(dsn) self.cur: DictCursor = self.conn.cursor(cursor_factory=DictCursor) - self.__migration(dsn) + self.__migrate(dsn) def add_user(self, telegram_id: int) -> int: """Add a user's telegram id to the database and return its database id.""" @@ -158,7 +156,7 @@ class Database: 'INSERT INTO feeds_last_items (feed_id, url, guid) VALUES (%s, %s, %s)', new_items) self.conn.commit() - def __migration(self, dsn: str) -> None: + def __migrate(self, dsn: str) -> None: backend = get_backend(dsn) migrations = read_migrations('./migrations') diff --git a/migrations/0000.initial-schema.py b/migrations/0000.initial-schema.py deleted file mode 100644 index 1553418..0000000 --- a/migrations/0000.initial-schema.py +++ /dev/null @@ -1,18 +0,0 @@ -from yoyo import step - -steps = [ - step('CREATE TABLE IF NOT EXISTS users (id SERIAL PRIMARY KEY, telegram_id INTEGER NOT NULL UNIQUE)'), - step('CREATE TABLE IF NOT EXISTS feeds (id SERIAL PRIMARY KEY, url TEXT NOT NULL UNIQUE)'), - step('CREATE TABLE IF NOT EXISTS subscriptions (' - ' user_id INTEGER REFERENCES users,' - ' feed_id INTEGER REFERENCES feeds,' - ' UNIQUE (user_id, feed_id)' - ')' - ), - step('CREATE TABLE IF NOT EXISTS feeds_last_items (' - ' feed_id INTEGER REFERENCES feeds ON DELETE CASCADE,' - ' url TEXT NOT NULL,' - ' guid TEXT' - ')' - ) -] diff --git a/migrations/0000.initial_schema.py b/migrations/0000.initial_schema.py new file mode 100644 index 0000000..b81c429 --- /dev/null +++ b/migrations/0000.initial_schema.py @@ -0,0 +1,20 @@ +from yoyo import step + +steps = [ + step('CREATE TABLE IF NOT EXISTS users (id SERIAL PRIMARY KEY, telegram_id INTEGER NOT NULL UNIQUE)'), + step('CREATE TABLE IF NOT EXISTS feeds (id SERIAL PRIMARY KEY, url TEXT NOT NULL UNIQUE)'), + step( + 'CREATE TABLE IF NOT EXISTS subscriptions (' + ' user_id INTEGER REFERENCES users,' + ' feed_id INTEGER REFERENCES feeds,' + ' UNIQUE (user_id, feed_id)' + ')' + ), + step( + 'CREATE TABLE IF NOT EXISTS feeds_last_items (' + ' feed_id INTEGER REFERENCES feeds ON DELETE CASCADE,' + ' url TEXT NOT NULL,' + ' guid TEXT' + ')' + ) +] -- 2.43.5 From dfa0a137baab8d75d0b06dd66f61257558f1806f Mon Sep 17 00:00:00 2001 From: mitsuha_s Date: Sun, 21 Aug 2022 19:20:32 +0300 Subject: [PATCH 3/8] little code style changes --- database.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/database.py b/database.py index 2dfe1ba..4c1472d 100644 --- a/database.py +++ b/database.py @@ -2,10 +2,11 @@ from logging import Logger import psycopg2 from psycopg2.extensions import connection from psycopg2.extras import DictCursor, DictRow -from exceptions import DisplayableException from yoyo import read_migrations, get_backend +from exceptions import DisplayableException from rss import FeedItem + class Database: """Implement interaction with the database.""" -- 2.43.5 From 5aa544cc9cff5b1d46e3146a32b86e26c0727cb5 Mon Sep 17 00:00:00 2001 From: mitsuha_s Date: Sun, 21 Aug 2022 19:28:38 +0300 Subject: [PATCH 4/8] delete IF NOT EXISTS in create table sql queries --- migrations/0000.initial_schema.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/migrations/0000.initial_schema.py b/migrations/0000.initial_schema.py index b81c429..e06b35a 100644 --- a/migrations/0000.initial_schema.py +++ b/migrations/0000.initial_schema.py @@ -1,17 +1,17 @@ from yoyo import step steps = [ - step('CREATE TABLE IF NOT EXISTS users (id SERIAL PRIMARY KEY, telegram_id INTEGER NOT NULL UNIQUE)'), - step('CREATE TABLE IF NOT EXISTS feeds (id SERIAL PRIMARY KEY, url TEXT NOT NULL UNIQUE)'), + 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 IF NOT EXISTS subscriptions (' + 'CREATE TABLE subscriptions (' ' user_id INTEGER REFERENCES users,' ' feed_id INTEGER REFERENCES feeds,' ' UNIQUE (user_id, feed_id)' ')' ), step( - 'CREATE TABLE IF NOT EXISTS feeds_last_items (' + 'CREATE TABLE feeds_last_items (' ' feed_id INTEGER REFERENCES feeds ON DELETE CASCADE,' ' url TEXT NOT NULL,' ' guid TEXT' -- 2.43.5 From 90c93528ec0951555be055f13cca304705e11719 Mon Sep 17 00:00:00 2001 From: mitsuha_s Date: Sun, 21 Aug 2022 23:03:43 +0300 Subject: [PATCH 5/8] add indentation in sql queries --- database.py | 2 +- migrations/0000.initial_schema.py | 13 +++++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/database.py b/database.py index 4c1472d..0b18a19 100644 --- a/database.py +++ b/database.py @@ -2,7 +2,7 @@ from logging import Logger import psycopg2 from psycopg2.extensions import connection from psycopg2.extras import DictCursor, DictRow -from yoyo import read_migrations, get_backend +from yoyo import get_backend, read_migrations from exceptions import DisplayableException from rss import FeedItem diff --git a/migrations/0000.initial_schema.py b/migrations/0000.initial_schema.py index e06b35a..5f4b2a5 100644 --- a/migrations/0000.initial_schema.py +++ b/migrations/0000.initial_schema.py @@ -1,8 +1,17 @@ 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 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,' -- 2.43.5 From d3d33bb718ef3711c09b547c2fa163cbeca38862 Mon Sep 17 00:00:00 2001 From: mitsuha_s Date: Sun, 21 Aug 2022 23:14:56 +0300 Subject: [PATCH 6/8] add docstring and logging to Database.__migrate method --- database.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/database.py b/database.py index 0b18a19..12b82cf 100644 --- a/database.py +++ b/database.py @@ -11,7 +11,7 @@ class Database: """Implement interaction with the database.""" def __init__(self, dsn: str, log: Logger) -> None: - """Create a database file if not exists.""" + """Create a database if not exists.""" self.log: Logger = log self.log.debug('Database.__init__(DSN=\'%s\')', dsn) self.conn: connection = psycopg2.connect(dsn) @@ -158,6 +158,8 @@ class Database: self.conn.commit() def __migrate(self, dsn: str) -> None: + """Migrate or initialize database shema""" + self.log.debug(f'Database.__migrate(dsn={dsn})') backend = get_backend(dsn) migrations = read_migrations('./migrations') -- 2.43.5 From 52023fcd1a148b8995844a7e1475c9d7d3072c99 Mon Sep 17 00:00:00 2001 From: mitsuha_s Date: Sun, 21 Aug 2022 23:25:10 +0300 Subject: [PATCH 7/8] correct docstrings in database.py --- database.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/database.py b/database.py index 12b82cf..c584eb1 100644 --- a/database.py +++ b/database.py @@ -11,7 +11,7 @@ class Database: """Implement interaction with the database.""" def __init__(self, dsn: str, log: Logger) -> None: - """Create a database if not exists.""" + """Initialize the database""" self.log: Logger = log self.log.debug('Database.__init__(DSN=\'%s\')', dsn) self.conn: connection = psycopg2.connect(dsn) @@ -158,7 +158,7 @@ class Database: self.conn.commit() def __migrate(self, dsn: str) -> None: - """Migrate or initialize database shema""" + """Migrate or initialize the database schema""" self.log.debug(f'Database.__migrate(dsn={dsn})') backend = get_backend(dsn) migrations = read_migrations('./migrations') -- 2.43.5 From fe2a9cc515cfdc222720469aa2c014e63b46be76 Mon Sep 17 00:00:00 2001 From: mitsuha_s Date: Sun, 21 Aug 2022 23:39:02 +0300 Subject: [PATCH 8/8] code style changes --- migrations/0000.initial_schema.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/migrations/0000.initial_schema.py b/migrations/0000.initial_schema.py index 5f4b2a5..be7fa0a 100644 --- a/migrations/0000.initial_schema.py +++ b/migrations/0000.initial_schema.py @@ -3,11 +3,12 @@ from yoyo import step steps = [ step( 'CREATE TABLE users (' - ' id SERIAL PRIMARY KEY,' + ' id SERIAL PRIMARY KEY,' ' telegram_id INTEGER NOT NULL UNIQUE' ')' ), - step('CREATE TABLE feeds (' + step( + 'CREATE TABLE feeds (' ' id SERIAL PRIMARY KEY,' ' url TEXT NOT NULL UNIQUE' ')' -- 2.43.5