py.lib

Yohn Y. 2022-08-13 Parent:1668cc57225b

32:eb41cc498ddb Go to Latest

py.lib/db/migrator.py

+ Поддержали наборы объектов концигурации в библиотеке помощника разбора конфигурации + Позволяем в помощнике получить секции конфигурации.

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):
13 pass
16 class MigrateManager(object):
17 def __init__(self, control_table: str, migrate_env: str):
18 self.control_table = control_table
20 if not exists(migrate_env):
21 raise MigrateError('Migrate enviroment not found')
23 self.schema = p_join(migrate_env, 'schema.sql')
24 if not exists(self.schema):
25 raise MigrateError(f'Schema file not found: {self.schema}')
27 self.patch_dir = p_join(migrate_env, 'patch')
28 if not isdir(self.patch_dir):
29 raise MigrateError(f'Patch dir not found or not directory: {self.patch_dir}')
31 def get_patch_files(self, ver: int):
32 res = {}
33 for f in listdir(self.patch_dir):
34 if not f.lower().endswith('.sql'):
35 continue
37 _f = f.strip().split('.')
39 try:
40 _ver = int(_f[0])
42 except (TypeError, ValueError) as e:
43 raise MigrateError(f'Error on parse version "{_f[0]}" of file "{f}": {e}')
45 except IndexError:
46 raise MigrateError(f'Error on get version from filename: {f}')
48 if _ver in res:
49 raise MigrateError(f'Version duplicates on parse file: {f}')
51 res[_ver] = p_join(self.patch_dir, f)
53 for i in sorted(res.keys()):
54 if i > ver:
55 yield i, res[i]
57 @staticmethod
58 def get_commands(file):
59 buf = []
60 with open(file) as IN:
61 for l in IN:
62 if l.lstrip().startswith('--'):
63 if buf:
64 yield '\n'.join(buf)
65 buf[:] = []
67 else:
68 buf.append(l)
70 if buf:
71 yield '\n'.join(buf)
73 def init_db(self, db):
74 cursor = db.cursor()
75 for c in self.get_commands(self.schema):
76 cursor.execute(c)
77 db.commit()
79 db.commit()
81 def check(self, db):
82 cursor = db.cursor()
83 cursor.execute(f"SELECT version FROM {self.control_table}")
84 q = cursor.fetchone()
85 del cursor
87 if q is None:
88 ver = -1
89 else:
90 ver = int(q[0])
92 new_ver = ver
93 cursor = db.cursor()
94 for up_ver, patch_file in self.get_patch_files(ver):
95 new_ver = up_ver
96 for cmd in self.get_commands(patch_file):
97 cursor.execute(cmd)
98 db.commit()
100 cursor.execute(f"DELETE FROM {self.control_table}")
102 cursor.execute(f"""
103 INSERT INTO {self.control_table} (version)
104 VALUES ({new_ver})
105 """)
106 db.commit()
108 @staticmethod
109 def get_conn_from_my_obj(obj: object):
110 """\
111 Получиение объекта соединения из обёрток, которые я сам себе пишу для работы с DB-API
113 :param obj:
114 :return:
115 """
116 if hasattr(obj, '_conn'):
117 return obj._conn
118 elif hasattr(obj, '_con'):
119 return obj._con
120 else:
121 raise TypeError('No known connection object in given database object found')