diff --git a/doc/dev/debug.md b/doc/dev/debug.md new file mode 100644 index 00000000..f6cb73e6 --- /dev/null +++ b/doc/dev/debug.md @@ -0,0 +1,6 @@ +# Debugging + +## Show SQL commands + +If you set the `YOKADI_SQL_DEBUG` environment variable to a value different +from "0", all SQL commands will be printed to stdout. diff --git a/yokadi/core/db.py b/yokadi/core/db.py index a72aa7a8..da7d324a 100644 --- a/yokadi/core/db.py +++ b/yokadi/core/db.py @@ -64,8 +64,12 @@ def merge(self, session, other): """Merge other into us""" if self is other: raise YokadiException("Cannot merge a project into itself") - for task in other.tasks: - task.project = self + # Do a bulk-update: it's faster than updating each task individually + session.query(Task).filter_by(projectId=other.id).update({Task.projectId: self.id}) + + # Tell SQLAlchemy to forget everything it knows about `other`, + # otherwise it will delete the tasks which were once attached to it + session.expire(other) session.delete(other) @@ -289,7 +293,8 @@ def __init__(self, dbFileName, createIfNeeded=True, memoryDatabase=False, update if memoryDatabase: connectionString = "sqlite:///:memory:" - self.engine = create_engine(connectionString) + echo = os.environ.get("YOKADI_SQL_DEBUG", "0") != "0" + self.engine = create_engine(connectionString, echo=echo) Session = sessionmaker(bind=self.engine) self.session = Session() diff --git a/yokadi/tests/projecttestcase.py b/yokadi/tests/projecttestcase.py index 1dd9fce0..e79f5134 100644 --- a/yokadi/tests/projecttestcase.py +++ b/yokadi/tests/projecttestcase.py @@ -78,20 +78,24 @@ def testStatus(self): self.assertEqual(project.active, True) def testMerge(self): - # Create project p1 with one associated task - dbutils.addTask("p1", "t1", interactive=False) - - # Create project p2 with one associated task - dbutils.addTask("p2", "t2", interactive=False) + COUNT = 4 + for x in range(COUNT): + dbutils.addTask('p1', 'p1-t{}'.format(x), interactive=False) + dbutils.addTask('p2', 'p2-t{}'.format(x), interactive=False) # Merge p1 into p2 tui.addInputAnswers("y") self.cmd.do_p_merge("p1 p2") - # p2 should have two tasks now + # p2 should have both its tasks and all p1 tasks now project = self.session.query(Project).filter_by(name="p2").one() tasks = set([x.title for x in project.tasks]) - self.assertEquals(tasks, {"t1", "t2"}) + + expected = set() + for x in range(COUNT): + expected.add('p1-t{}'.format(x)) + expected.add('p2-t{}'.format(x)) + self.assertEqual(tasks, expected) # p1 should be gone testutils.assertQueryEmpty(self, self.session.query(Project).filter_by(name="p1")) diff --git a/yokadi/ycli/projectcmd.py b/yokadi/ycli/projectcmd.py index 872ef343..2863958f 100644 --- a/yokadi/ycli/projectcmd.py +++ b/yokadi/ycli/projectcmd.py @@ -139,7 +139,6 @@ def parser_p_merge(self): return parser def do_p_merge(self, line): - raise Exception("Broken for now, going to fix it") session = db.getSession() parser = self.parser_p_merge() args = parser.parse_args(line)