From 8858e3b1619698f91b5fb7d9458ffc4a022482f4 Mon Sep 17 00:00:00 2001 From: Lan Date: Wed, 6 Aug 2025 12:57:14 +0300 Subject: [PATCH] Bumped pybdml v0.3.4 -> v1.2.0 - Upgraded ref use in core following [pydbml upgrade docs](https://github.com/Vanderhoof/PyDBML/blob/master/docs/upgrading.md#getting-tables-from-parse-results-by-name). - Fixed mock classes so that tests pass for #4 PR and also the versio bump. --- .gitignore | 3 ++ dbml_sqlite/core.py | 19 ++++++----- pyproject.toml | 4 +-- requirements.txt | 2 +- tests/example.db | Bin 40960 -> 40960 bytes tests/example2.db | Bin 16384 -> 16384 bytes tests/test_dbml_sqlite.py | 70 +++++++++++++++++++++++++------------- 7 files changed, 63 insertions(+), 35 deletions(-) diff --git a/.gitignore b/.gitignore index 351933d..e019647 100644 --- a/.gitignore +++ b/.gitignore @@ -145,3 +145,6 @@ dmypy.json # Cython debug symbols cython_debug/ + +tests/example.db +tests/example2.db diff --git a/dbml_sqlite/core.py b/dbml_sqlite/core.py index 9dd5a83..0161bb7 100644 --- a/dbml_sqlite/core.py +++ b/dbml_sqlite/core.py @@ -2,7 +2,7 @@ import os import uuid from pydbml import PyDBML -from pydbml.classes import Enum +from pydbml.classes import Table, Enum, Reference from pathlib import Path from itertools import chain @@ -43,7 +43,7 @@ def toSQLite(dbml=".", emulation="full", tableExists=True, indexExists=True, joi results = "".join(results) return results -def validDBMLFile(s): +def validDBMLFile(s: str): """ Return a boolean indicating whether passed string has valid `.dbml` file extension. Case-sensitive (i.e. `.DBML` not accepted). @@ -58,7 +58,7 @@ def validDBMLFile(s): else: return False -def processFile(target, emulationMode, tableExists=True, indexExists=True, idxNameFunc=uuid.uuid4, join=True): +def processFile(target: Path, emulationMode: str, tableExists=True, indexExists=True, idxNameFunc=uuid.uuid4, join=True): """ Given a target `.dbml` file, parse and generate a valid SQLite string. @@ -119,7 +119,7 @@ def processIndex(table, index, idxNameFunc=uuid.uuid4, indexExists=True, join=Tr parts = "".join(parts) return parts -def processEnum(enum, tableExists=True, join=True): +def processEnum(enum: Enum, tableExists=True, join=True): """ Take an Enum object generated by the PyDBML library and use it to generate SQLite DDL for creating an enum table for "full" enum emulation mode only. @@ -139,7 +139,7 @@ def processEnum(enum, tableExists=True, join=True): segments = "".join(segments) return segments -def processTable(table, emulationMode, tableExists=True, join=True): +def processTable(table: Table, emulationMode, tableExists=True, join=True): """ Generate SQLite DDL for creating a table. @@ -161,11 +161,11 @@ def processTable(table, emulationMode, tableExists=True, join=True): segments.append(processColumn(col, emulationMode, False)) if i < len(table.columns) - 1: segments.append(',\n') - for j, ref in enumerate(table.refs): + for j, ref in enumerate(table.get_refs()): if j == 0: segments.append(',\n') segments.append(processRef(ref, False)) - if j < len(table.refs) - 1: + if j < len(table.get_refs()) - 1: segments.append(',\n') segments.append('\n);\n') segments = list(chain.from_iterable(segments)) @@ -173,7 +173,7 @@ def processTable(table, emulationMode, tableExists=True, join=True): segments = "".join(segments) return segments -def processRef(ref, join=True): +def processRef(ref: Reference, join=True): """ Convert a Ref object parsed by PyDBML from dbml into SQLite DDL. @@ -186,7 +186,8 @@ def processRef(ref, join=True): """ segments = [] segments.append(' FOREIGN KEY(') - segments.append(f'{ref.col.name}) REFERENCES {ref.ref_table.name}({ref.ref_col.name})') + segments.append(f'{ref.col1[0].name}) REFERENCES {ref.col2[0].table.name}({ref.col2[0].name})') + # segments.append(f'{ref.col.name}) REFERENCES {ref.ref_table.name}({ref.ref_col.name})') if ref.on_update: segments.append(f' ON UPDATE {ref.on_update.upper()}') if ref.on_delete: diff --git a/pyproject.toml b/pyproject.toml index 89c4a85..13ac28d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "DBML_SQLite" -version = "0.3.3" +version = "0.3.4" description = "A package that provides a CLI tool and a functional API for converting dbml files to SQLite DDL." authors = ["Dave VanderWeele "] repository = 'https://github.com/dvanderweele/DBML_SQLite' @@ -11,7 +11,7 @@ readme = 'README.md' [tool.poetry.dependencies] python = "^3.7" -pydbml = "^0.3.4" +pydbml = "^1.2.0" click = "^8.0.0" [tool.poetry.dev-dependencies] diff --git a/requirements.txt b/requirements.txt index d86e17e..6b08b2f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -20,7 +20,7 @@ lessqlite==0.1.3 msgpack==1.0.2 parso==0.8.2 Pillow==8.2.0 -pydbml==0.3.4 +pydbml==1.2.0 Pygments==2.9.0 pynvim==0.4.3 pyparsing==2.4.7 diff --git a/tests/example.db b/tests/example.db index aacda2c92cd3c74c7c50f3d969b545b288042596..f39930ef9c023a9b2fd6b4bc888f08b1b48e4539 100644 GIT binary patch delta 15 WcmZoTz|?SnX+jcHS@*`2Ir9NC?FPyK delta 15 WcmZoTz|?SnX+jc{f9=MUIr9NBy#|#4 diff --git a/tests/example2.db b/tests/example2.db index 9dc504b272f9b5d1688f1e00dfa49fa9950b4223..70e6e959cc0d4b10004c5389c058809efbbc4b7a 100644 GIT binary patch delta 15 WcmZo@U~Fh$oRGv+*1a)hjy(V^HU;Pa delta 15 WcmZo@U~Fh$oRGxiU%N47jy(V@1_iSK diff --git a/tests/test_dbml_sqlite.py b/tests/test_dbml_sqlite.py index 5d57123..2c387df 100644 --- a/tests/test_dbml_sqlite.py +++ b/tests/test_dbml_sqlite.py @@ -16,25 +16,34 @@ class MockItem: def __init__(self, name): self.name = name class MockColumn: - def __init__(self, name, Type, pk, not_null, unique, default): + def __init__(self, name, Type, pk, not_null, unique, default, table, autoinc=False): self.name = name self.type = Type self.pk = pk self.not_null = not_null self.unique = unique self.default = default + self.table = table + self.autoinc = autoinc class MockRef: - def __init__(self, col, ref_table, ref_col, on_update, on_delete): - self.col = col - self.ref_table = ref_table - self.ref_col = ref_col + def __init__(self, database, type, col1, col2, name, comment, on_update, on_delete, _inline): + self.database = database + self.type = type + self.col1 = col1 + self.col2 = col2 + self.name = name + self.comment = comment self.on_update = on_update self.on_delete = on_delete + self._inline = _inline class MockTable: def __init__(self, name, columns, refs): self.name = name self.columns = columns self.refs = refs + + def get_refs(self): + return self.refs class MockIndex: def __init__(self, name, unique, subjects, table): self.name = name @@ -79,15 +88,15 @@ def test_coercion(): def test_process_column(): # name, Type, pk, not_null, unique, default - c1 = MockColumn("c1", 1, None, None, None, None) - c2 = MockColumn("c2", 'INTEGER', True, False, False, None) - c3 = MockColumn("c3", 'REAL', False, True, True, None) - c4 = MockColumn('c4', 'TEXT', False, False, False, 'howdy') + c1 = MockColumn("c1", 1, None, None, None, None, None) + c2 = MockColumn("c2", 'INTEGER', True, False, False, None, None) + c3 = MockColumn("c3", 'REAL', False, True, True, None, None) + c4 = MockColumn('c4', 'TEXT', False, False, False, 'howdy', None) i1 = MockItem('i1') i2 = MockItem('i2') e1 = MockEnum('e1', [i1, i2]) - c5 = MockColumn('c5', e1, False, True, False, None) - c6 = MockColumn('c6', 'REAL', False, True, False, 12.345) + c5 = MockColumn('c5', e1, False, True, False, None, None) + c6 = MockColumn('c6', 'REAL', False, True, False, 12.345, None) with pytest.raises(TypeError): processColumn(c1, 'full') assert processColumn(c2, 'full') == ' c2 INTEGER PRIMARY KEY' @@ -98,10 +107,16 @@ def test_process_column(): assert processColumn(c6, 'full') == ' c6 REAL NOT NULL DEFAULT 12.345' def test_process_ref(): - fc = MockColumn('foreign_key', None, None, None, None, None) + fc = MockColumn('foreign_key', None, None, None, None, None, None) t = MockTable('foreign_table', [fc], []) - lc = MockColumn('local_key', None, None, None, None, None) - r = MockRef(lc, t, fc, 'NO ACTION', 'NO ACTION') + lc = MockColumn('local_key', None, None, None, None, None, None) + fc.table = t + + # def __init__(self, database, type, col1, col2, name, comment, on_update, on_delete, _inline): + # r = MockRef(lc, t, fc, 'NO ACTION', 'NO ACTION') + + r = MockRef(None, None, [lc], [fc], None, None, 'NO ACTION', 'NO ACTION', None) + o = processRef(r) assert o == ' FOREIGN KEY(local_key) REFERENCES foreign_table(foreign_key) ON UPDATE NO ACTION ON DELETE NO ACTION' @@ -111,18 +126,27 @@ def test_process_table(): 1 ) multiple refs 2 ) joined output """ - lc1 = MockColumn('l1', 'INTEGER', None, None, None, None) - lc2 = MockColumn('l2', 'INTEGER', None, None, None, None) - fc1 = MockColumn('f1', 'INTEGER', None, None, None, None) - fc2 = MockColumn('f2', 'INTEGER', None, None, None, None) + lc1 = MockColumn('l1', 'INTEGER', None, None, None, None, None) + lc2 = MockColumn('l2', 'INTEGER', None, None, None, None, None) + fc1 = MockColumn('f1', 'INTEGER', None, None, None, None, None) + fc2 = MockColumn('f2', 'INTEGER', None, None, None, None, None) fortab = MockTable('ft', [fc1, fc2], []) - r1 = MockRef(lc1, fortab, fc1, 'NO ACTION', 'NO ACTION') - r2 = MockRef(lc2, fortab, fc2, 'NO ACTION', 'NO ACTION') + + fc1.table = fortab + fc2.table = fortab + + # def __init__(self, database, type, col1, col2, name, comment, on_update, on_delete, _inline): + # r1 = MockRef(lc1, fortab, fc1, 'NO ACTION', 'NO ACTION') + # r2 = MockRef(lc2, fortab, fc2, 'NO ACTION', 'NO ACTION') + + r1 = MockRef(None, None, [lc1], [fc1], None, None, 'NO ACTION', 'NO ACTION', None) + r2 = MockRef(None, None, [lc2], [fc2], None, None, 'NO ACTION', 'NO ACTION', None) + loctab = MockTable('lt', [lc1, lc2], [r1, r2]) o = processTable(loctab, 'full', False, True) assert o == "CREATE TABLE lt (\n l1 INTEGER,\n l2 INTEGER,\n FOREIGN KEY(l1) REFERENCES ft(f1) ON UPDATE NO ACTION ON DELETE NO ACTION,\n FOREIGN KEY(l2) REFERENCES ft(f2) ON UPDATE NO ACTION ON DELETE NO ACTION\n);\n" -def test_process_enum(): + items = [] items.append(MockItem('Joe')) items.append(MockItem('Bob')) @@ -138,8 +162,8 @@ def test_process_file(): def test_process_index(): mytab = MockTable('mytab', [], []) - col1 = MockColumn('col1', None, None, None, None, None) - col2 = MockColumn('col2', None, None, None, None, None) + col1 = MockColumn('col1', None, None, None, None, None, None) + col2 = MockColumn('col2', None, None, None, None, None, None) idx = MockIndex('myidx', False, [col1, col2], mytab) o = processIndex(mytab, idx, MockNameFunc, False, True) assert o == "CREATE INDEX myidx ON mytab (col1, col2);\n"