sqloader 0.2.8__tar.gz → 0.2.9__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {sqloader-0.2.8/sqloader.egg-info → sqloader-0.2.9}/PKG-INFO +2 -1
- {sqloader-0.2.8 → sqloader-0.2.9}/pyproject.toml +2 -2
- {sqloader-0.2.8 → sqloader-0.2.9}/setup.py +2 -1
- {sqloader-0.2.8 → sqloader-0.2.9}/sqloader/migrator.py +7 -5
- {sqloader-0.2.8 → sqloader-0.2.9/sqloader.egg-info}/PKG-INFO +2 -1
- {sqloader-0.2.8 → sqloader-0.2.9}/sqloader.egg-info/requires.txt +1 -0
- {sqloader-0.2.8 → sqloader-0.2.9}/tests/test_migrator.py +47 -1
- {sqloader-0.2.8 → sqloader-0.2.9}/LICENSE +0 -0
- {sqloader-0.2.8 → sqloader-0.2.9}/README.md +0 -0
- {sqloader-0.2.8 → sqloader-0.2.9}/setup.cfg +0 -0
- {sqloader-0.2.8 → sqloader-0.2.9}/sqloader/__init__.py +0 -0
- {sqloader-0.2.8 → sqloader-0.2.9}/sqloader/__main__.py +0 -0
- {sqloader-0.2.8 → sqloader-0.2.9}/sqloader/_async_prototype.py +0 -0
- {sqloader-0.2.8 → sqloader-0.2.9}/sqloader/_prototype.py +0 -0
- {sqloader-0.2.8 → sqloader-0.2.9}/sqloader/init.py +0 -0
- {sqloader-0.2.8 → sqloader-0.2.9}/sqloader/mysql.py +0 -0
- {sqloader-0.2.8 → sqloader-0.2.9}/sqloader/mysql_async.py +0 -0
- {sqloader-0.2.8 → sqloader-0.2.9}/sqloader/postgresql.py +0 -0
- {sqloader-0.2.8 → sqloader-0.2.9}/sqloader/postgresql_async.py +0 -0
- {sqloader-0.2.8 → sqloader-0.2.9}/sqloader/sqlite3.py +0 -0
- {sqloader-0.2.8 → sqloader-0.2.9}/sqloader/sqlite3_async.py +0 -0
- {sqloader-0.2.8 → sqloader-0.2.9}/sqloader/sqloader.py +0 -0
- {sqloader-0.2.8 → sqloader-0.2.9}/sqloader.egg-info/SOURCES.txt +0 -0
- {sqloader-0.2.8 → sqloader-0.2.9}/sqloader.egg-info/dependency_links.txt +0 -0
- {sqloader-0.2.8 → sqloader-0.2.9}/sqloader.egg-info/top_level.txt +0 -0
- {sqloader-0.2.8 → sqloader-0.2.9}/tests/test_fetch_aliases.py +0 -0
- {sqloader-0.2.8 → sqloader-0.2.9}/tests/test_mysql.py +0 -0
- {sqloader-0.2.8 → sqloader-0.2.9}/tests/test_postgresql.py +0 -0
- {sqloader-0.2.8 → sqloader-0.2.9}/tests/test_sqlite.py +0 -0
- {sqloader-0.2.8 → sqloader-0.2.9}/tests/test_sqloader.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sqloader
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.9
|
|
4
4
|
Summary: A simple and extensible SQL migration and loader utility for Python.
|
|
5
5
|
Home-page: https://github.com/horrible-gh/py_sqloader.git
|
|
6
6
|
Author: horrible-gh
|
|
@@ -16,6 +16,7 @@ Description-Content-Type: text/markdown
|
|
|
16
16
|
License-File: LICENSE
|
|
17
17
|
Requires-Dist: LogAssist
|
|
18
18
|
Requires-Dist: pymysql>=1.1.1
|
|
19
|
+
Requires-Dist: sqlparse>=0.4.0
|
|
19
20
|
Provides-Extra: postgresql
|
|
20
21
|
Requires-Dist: psycopg2-binary>=2.9.0; extra == "postgresql"
|
|
21
22
|
Provides-Extra: async-mysql
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "sqloader"
|
|
7
|
-
version = "0.2.
|
|
7
|
+
version = "0.2.9"
|
|
8
8
|
authors = [
|
|
9
9
|
{ name="horrible", email="shinjpn1@gmail.com" },
|
|
10
10
|
]
|
|
@@ -21,7 +21,7 @@ keywords = [
|
|
|
21
21
|
"MySQL", "SQLite", "SQL migration", "schema management",
|
|
22
22
|
"json sql loader"
|
|
23
23
|
]
|
|
24
|
-
dependencies=['LogAssist', 'pymysql>=1.1.1']
|
|
24
|
+
dependencies=['LogAssist', 'pymysql>=1.1.1', 'sqlparse>=0.4.0']
|
|
25
25
|
|
|
26
26
|
[project.optional-dependencies]
|
|
27
27
|
postgresql = ["psycopg2-binary>=2.9.0"]
|
|
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
|
|
|
2
2
|
|
|
3
3
|
setup(
|
|
4
4
|
name='sqloader',
|
|
5
|
-
version='0.2.
|
|
5
|
+
version='0.2.9',
|
|
6
6
|
description='py_sqloader package',
|
|
7
7
|
author='horrible-gh',
|
|
8
8
|
author_email='shinjpn1@gmail.com',
|
|
@@ -23,6 +23,7 @@ setup(
|
|
|
23
23
|
python_requires='>=3.6',
|
|
24
24
|
install_requires=[
|
|
25
25
|
"pymysql>=1.1.1", # MySQL sync is always included
|
|
26
|
+
"sqlparse>=0.4.0",
|
|
26
27
|
],
|
|
27
28
|
extras_require={
|
|
28
29
|
"postgresql": ["psycopg2-binary>=2.9.0"],
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import os
|
|
2
|
+
import re
|
|
2
3
|
import glob
|
|
4
|
+
import sqlparse
|
|
3
5
|
from ._prototype import DatabasePrototype, MYSQL, SQLITE, POSTGRESQL
|
|
4
6
|
|
|
5
7
|
class DatabaseMigrator:
|
|
@@ -53,15 +55,15 @@ class DatabaseMigrator:
|
|
|
53
55
|
full_path = os.path.join(self.migrations_path, migration)
|
|
54
56
|
|
|
55
57
|
with open(full_path, 'r', encoding='utf-8') as f:
|
|
56
|
-
sql_commands = f.read().
|
|
58
|
+
sql_commands = [s.strip() for s in sqlparse.split(f.read()) if s.strip()]
|
|
57
59
|
|
|
58
60
|
try:
|
|
59
61
|
# Execute all statements in a single transaction
|
|
60
62
|
with self.db.begin_transaction() as txn:
|
|
61
63
|
for command in sql_commands:
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
64
|
+
if not re.sub(r'--[^\n]*', '', command).strip():
|
|
65
|
+
continue
|
|
66
|
+
txn.execute(command)
|
|
65
67
|
# Auto-commit on exit, auto-rollback on exception
|
|
66
68
|
|
|
67
69
|
if self.db.db_type == SQLITE:
|
|
@@ -97,4 +99,4 @@ class DatabaseMigrator:
|
|
|
97
99
|
Filenames match the relative paths inserted by apply_migration().
|
|
98
100
|
"""
|
|
99
101
|
rows = self.db.fetch_all("SELECT filename FROM migrations")
|
|
100
|
-
return {row['filename'] for row in rows}
|
|
102
|
+
return {row['filename'] for row in rows}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sqloader
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.9
|
|
4
4
|
Summary: A simple and extensible SQL migration and loader utility for Python.
|
|
5
5
|
Home-page: https://github.com/horrible-gh/py_sqloader.git
|
|
6
6
|
Author: horrible-gh
|
|
@@ -16,6 +16,7 @@ Description-Content-Type: text/markdown
|
|
|
16
16
|
License-File: LICENSE
|
|
17
17
|
Requires-Dist: LogAssist
|
|
18
18
|
Requires-Dist: pymysql>=1.1.1
|
|
19
|
+
Requires-Dist: sqlparse>=0.4.0
|
|
19
20
|
Provides-Extra: postgresql
|
|
20
21
|
Requires-Dist: psycopg2-binary>=2.9.0; extra == "postgresql"
|
|
21
22
|
Provides-Extra: async-mysql
|
|
@@ -128,4 +128,50 @@ class TestAutoRun:
|
|
|
128
128
|
def test_auto_run_false_does_not_apply(self, db, migration_dir):
|
|
129
129
|
m = DatabaseMigrator(db, migration_dir, auto_run=False)
|
|
130
130
|
applied = m.get_applied_migrations()
|
|
131
|
-
assert len(applied) == 0
|
|
131
|
+
assert len(applied) == 0
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
# ---------------------------------------------------------------------------
|
|
135
|
+
# comment-only chunk (문제 1)
|
|
136
|
+
# ---------------------------------------------------------------------------
|
|
137
|
+
|
|
138
|
+
class TestCommentOnlyChunk:
|
|
139
|
+
def test_comment_only_file_does_not_raise(self, db):
|
|
140
|
+
"""주석과 공백만 있는 청크는 실행 없이 건너뛰어야 한다."""
|
|
141
|
+
with tempfile.TemporaryDirectory() as tmpdir:
|
|
142
|
+
with open(os.path.join(tmpdir, "001_comments.sql"), "w") as f:
|
|
143
|
+
f.write(
|
|
144
|
+
"-- this is a comment\n"
|
|
145
|
+
"CREATE TABLE comment_test (id INTEGER PRIMARY KEY);\n"
|
|
146
|
+
"-- trailing comment\n"
|
|
147
|
+
)
|
|
148
|
+
m = DatabaseMigrator(db, tmpdir, auto_run=True)
|
|
149
|
+
applied = m.get_applied_migrations()
|
|
150
|
+
assert "001_comments.sql" in applied
|
|
151
|
+
|
|
152
|
+
rows = db.fetch_all(
|
|
153
|
+
"SELECT name FROM sqlite_master WHERE type='table' AND name='comment_test'"
|
|
154
|
+
)
|
|
155
|
+
assert len(list(rows)) == 1
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
# ---------------------------------------------------------------------------
|
|
159
|
+
# multi-statement SQL file (문제 2 — split 경계 검증)
|
|
160
|
+
# ---------------------------------------------------------------------------
|
|
161
|
+
|
|
162
|
+
class TestMultiStatementFile:
|
|
163
|
+
def test_multiple_statements_in_one_file(self, db):
|
|
164
|
+
"""세미콜론으로 구분된 여러 구문이 모두 올바르게 실행되어야 한다."""
|
|
165
|
+
with tempfile.TemporaryDirectory() as tmpdir:
|
|
166
|
+
with open(os.path.join(tmpdir, "001_multi.sql"), "w") as f:
|
|
167
|
+
f.write(
|
|
168
|
+
"CREATE TABLE multi_a (id INTEGER PRIMARY KEY);\n"
|
|
169
|
+
"CREATE TABLE multi_b (id INTEGER PRIMARY KEY);\n"
|
|
170
|
+
)
|
|
171
|
+
DatabaseMigrator(db, tmpdir, auto_run=True)
|
|
172
|
+
|
|
173
|
+
for table in ("multi_a", "multi_b"):
|
|
174
|
+
rows = db.fetch_all(
|
|
175
|
+
f"SELECT name FROM sqlite_master WHERE type='table' AND name='{table}'"
|
|
176
|
+
)
|
|
177
|
+
assert len(list(rows)) == 1, f"Table {table} was not created"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|