py.lib

Yohn Y. 2021-06-06 Parent:10227cc154fa Child:26a5160d6b6b

18:a8460893606a Go to Latest

py.lib/db/migrator.py

. Наведение порядка с PostgreSQL

History
1 # coding: utf-8
2 """\
3 Инструмент миграции схемы БД.
5 DOC: https://ws.a0fs.net/w/ncc.ws/devel/python/modules/db_migrator/
6 """
8 from os.path import exists, join as p_join, isdir
9 from os import listdir
12 class MigrateError(Exception): pass
15 class MigrateManager(object):
16 def __init__(self, control_table: str, migrate_env: str):
17 self.control_table = control_table
19 if not exists(migrate_env):
20 raise MigrateError('Migrate enviroment not found')
22 self.schema = p_join(migrate_env, 'schema.sql')
23 if not exists(self.schema):
24 raise MigrateError('Schema file not found: %s' % self.schema)
26 self.patch_dir = p_join(migrate_env, 'patch')
27 if not isdir(self.patch_dir):
28 raise MigrateError('Patch dir not found or not directory: %s' % self.patch_dir)
30 def get_patch_files(self, ver: int):
31 res = {}
32 for f in listdir(self.patch_dir):
33 if not f.lower().endswith('.sql'):
34 continue
36 _f = f.strip().split('.')
38 try:
39 _ver = int(_f[0])
41 except (TypeError, ValueError) as e:
42 raise MigrateError('Error on parse version "%(ver)s" of file "%(f)s": %(e)s' % {
43 'ver': _f[0],
44 'f': f,
45 'e': e,
46 })
48 except IndexError:
49 raise MigrateError('Error on get version from filename: %s' % f)
51 if _ver in res:
52 raise MigrateError('Version duplicates on parse file: %s' % f)
54 res[_ver] = p_join(self.patch_dir, f)
56 for i in sorted(res.keys()):
57 if i > ver:
58 yield i, res[i]
60 @staticmethod
61 def get_commands(file):
62 buf = []
63 with open(file) as IN:
64 for l in IN:
65 if l.lstrip().startswith('--'):
66 if buf:
67 yield '\n'.join(buf)
68 buf[:] = []
70 else:
71 buf.append(l)
73 if buf:
74 yield '\n'.join(buf)
76 def init_db(self, db):
77 cursor = db.cursor()
78 for c in self.get_commands(self.schema):
79 cursor.execute(c)
80 db.commit()
82 db.commit()
84 def check(self, db):
85 cursor = db.cursor()
86 cursor.execute("SELECT version FROM %s" % self.control_table)
87 q = cursor.fetchone()
88 del cursor
90 if q is None:
91 ver = -1
92 else:
93 ver = int(q[0])
95 new_ver = ver
96 cursor = db.cursor()
97 for up_ver, patch_file in self.get_patch_files(ver):
98 new_ver = up_ver
99 for cmd in self.get_commands(patch_file):
100 cursor.execute(cmd)
101 db.commit()
103 cursor.execute("DELETE FROM %s" % self.control_table)
105 cursor.execute("""
106 INSERT INTO %s (version)
107 VALUES (%s)
108 """ % (self.control_table, new_ver))
109 db.commit()